[pypy-commit] pypy default: merge heads
arigo
pypy.commits at gmail.com
Fri Jul 6 13:00:47 EDT 2018
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r94815:b717d811eb2b
Date: 2018-07-06 16:26 +0200
http://bitbucket.org/pypy/pypy/changeset/b717d811eb2b/
Log: merge heads
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -82,10 +82,9 @@
class TypeConverter(object):
- _immutable_fields_ = ['cffi_name', 'uses_local', 'name']
+ _immutable_fields_ = ['cffi_name', 'name']
cffi_name = None
- uses_local = False
name = ""
def __init__(self, space, extra):
@@ -108,10 +107,10 @@
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
self._is_abstract(space)
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible
@@ -125,10 +124,10 @@
def to_memory(self, space, w_obj, w_value, offset):
self._is_abstract(space)
- def finalize_call(self, space, w_obj, call_local):
+ def finalize_call(self, space, w_obj):
pass
- def free_argument(self, space, arg, call_local):
+ def free_argument(self, space, arg):
pass
@@ -172,7 +171,7 @@
state = space.fromcache(ffitypes.State)
return state.c_voidp
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
w_tc = space.findattr(w_obj, space.newtext('typecode'))
if w_tc is not None and space.text_w(w_tc) != self.typecode:
raise oefmt(space.w_TypeError,
@@ -208,7 +207,7 @@
class NumericTypeConverterMixin(object):
_mixin_ = True
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
x = rffi.cast(self.c_ptrtype, address)
x[0] = self._unwrap_object(space, w_obj)
@@ -228,26 +227,23 @@
class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
_mixin_ = True
- _immutable_fields_ = ['uses_local']
-
- uses_local = True
def cffi_type(self, space):
state = space.fromcache(ffitypes.State)
return state.c_voidp
- def convert_argument_libffi(self, space, w_obj, address, call_local):
- assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP) # see interp_cppyy.py
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
obj = self._unwrap_object(space, w_obj)
- typed_buf = rffi.cast(self.c_ptrtype, call_local)
+ typed_buf = rffi.cast(self.c_ptrtype, scratch)
typed_buf[0] = obj
x = rffi.cast(rffi.VOIDPP, address)
- x[0] = call_local
+ x[0] = scratch
+
class IntTypeConverterMixin(NumericTypeConverterMixin):
_mixin_ = True
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(self.c_ptrtype, address)
x[0] = self._unwrap_object(space, w_obj)
ba = rffi.cast(rffi.CCHARP, address)
@@ -256,7 +252,7 @@
class FloatTypeConverterMixin(NumericTypeConverterMixin):
_mixin_ = True
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(self.c_ptrtype, address)
x[0] = self._unwrap_object(space, w_obj)
ba = rffi.cast(rffi.CCHARP, address)
@@ -273,18 +269,18 @@
state = space.fromcache(ffitypes.State)
return state.c_void
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
self._is_abstract(space)
class BoolConverter(ffitypes.typeid(bool), TypeConverter):
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.LONGP, address)
x[0] = self._unwrap_object(space, w_obj)
ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = 'b'
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
x = rffi.cast(rffi.LONGP, address)
x[0] = self._unwrap_object(space, w_obj)
@@ -303,13 +299,13 @@
address[0] = '\x00'
class CharConverter(ffitypes.typeid(rffi.CHAR), TypeConverter):
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.CCHARP, address)
x[0] = self._unwrap_object(space, w_obj)
ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = 'b'
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
x = rffi.cast(self.c_ptrtype, address)
x[0] = self._unwrap_object(space, w_obj)
@@ -348,7 +344,7 @@
state = space.fromcache(ffitypes.State)
return state.c_voidp
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible
@@ -381,7 +377,7 @@
class CStringConverter(TypeConverter):
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.LONGP, address)
arg = space.text_w(w_obj)
x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
@@ -393,7 +389,7 @@
charpptr = rffi.cast(rffi.CCHARPP, address)
return space.newtext(rffi.charp2str(charpptr[0]))
- def free_argument(self, space, arg, call_local):
+ def free_argument(self, space, arg):
lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
class CStringConverterWithSize(CStringConverter):
@@ -423,13 +419,13 @@
state = space.fromcache(ffitypes.State)
return state.c_voidp
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.VOIDPP, address)
x[0] = self._unwrap_object(space, w_obj)
ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = 'o'
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
x = rffi.cast(rffi.VOIDPP, address)
x[0] = self._unwrap_object(space, w_obj)
@@ -452,37 +448,39 @@
address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
class VoidPtrPtrConverter(TypeConverter):
- _immutable_fields_ = ['uses_local', 'typecode']
+ typecode = 'p'
- uses_local = True
- typecode = 'a'
+ def __init__(self, space, extra):
+ self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.VOIDPP, address)
- ba = rffi.cast(rffi.CCHARP, address)
try:
x[0] = get_rawbuffer(space, w_obj)
except TypeError:
- r = rffi.cast(rffi.VOIDPP, call_local)
- r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
- x[0] = rffi.cast(rffi.VOIDP, call_local)
+ ptr = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+ self.ref_buffer = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw')
+ self.ref_buffer[0] = ptr
+ x[0] = self.ref_buffer
+ ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = self.typecode
- def finalize_call(self, space, w_obj, call_local):
- r = rffi.cast(rffi.VOIDPP, call_local)
- try:
- set_rawobject(space, w_obj, r[0])
- except OperationError:
- pass # no set on buffer/array/None
+ def finalize_call(self, space, w_obj):
+ if self.ref_buffer:
+ set_rawobject(space, w_obj, self.ref_buffer[0])
+
+ def free_argument(self, space, arg):
+ if self.ref_buffer:
+ lltype.free(self.ref_buffer, flavor='raw')
+ self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
class VoidPtrRefConverter(VoidPtrPtrConverter):
- _immutable_fields_ = ['uses_local', 'typecode']
- uses_local = True
+ _immutable_fields_ = ['typecode']
typecode = 'V'
class InstanceRefConverter(TypeConverter):
_immutable_fields_ = ['typecode', 'clsdecl']
- typecode = 'V'
+ typecode = 'V'
def __init__(self, space, clsdecl):
from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
@@ -508,14 +506,14 @@
state = space.fromcache(ffitypes.State)
return state.c_voidp
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.VOIDPP, address)
x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
address = rffi.cast(capi.C_OBJECT, address)
ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = self.typecode
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
x = rffi.cast(rffi.VOIDPP, address)
x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
@@ -539,7 +537,7 @@
class InstanceConverter(InstanceRefConverter):
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible # TODO: by-value is a jit_libffi special case
@@ -551,9 +549,8 @@
def to_memory(self, space, w_obj, w_value, offset):
self._is_abstract(space)
-
class InstancePtrConverter(InstanceRefConverter):
- typecode = 'o'
+ typecode = 'o'
def _unwrap_object(self, space, w_obj):
try:
@@ -574,36 +571,41 @@
address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
class InstancePtrPtrConverter(InstancePtrConverter):
- _immutable_fields_ = ['uses_local']
+ typecode = 'o'
- uses_local = True
+ def __init__(self, space, extra):
+ InstancePtrConverter.__init__(self, space, extra)
+ self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
- def convert_argument(self, space, w_obj, address, call_local):
- r = rffi.cast(rffi.VOIDPP, call_local)
- r[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.VOIDPP, address)
- x[0] = rffi.cast(rffi.VOIDP, call_local)
- address = rffi.cast(capi.C_OBJECT, address)
+ ptr = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+ self.ref_buffer = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw')
+ self.ref_buffer[0] = ptr
+ x[0] = self.ref_buffer
ba = rffi.cast(rffi.CCHARP, address)
- ba[capi.c_function_arg_typeoffset(space)] = 'o'
+ ba[capi.c_function_arg_typeoffset(space)] = self.typecode
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
# TODO: finalize_call not yet called for fast call (see interp_cppyy.py)
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible
- def finalize_call(self, space, w_obj, call_local):
- from pypy.module._cppyy.interp_cppyy import W_CPPInstance
- assert isinstance(w_obj, W_CPPInstance)
- r = rffi.cast(rffi.VOIDPP, call_local)
- w_obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
-
def from_memory(self, space, w_obj, w_pycppclass, offset):
address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
from pypy.module._cppyy import interp_cppyy
return interp_cppyy.wrap_cppinstance(
space, address, self.clsdecl, do_cast=False, is_ref=True)
+ def finalize_call(self, space, w_obj):
+ if self.ref_buffer:
+ set_rawobject(space, w_obj, self.ref_buffer[0])
+
+ def free_argument(self, space, arg):
+ if self.ref_buffer:
+ lltype.free(self.ref_buffer, flavor='raw')
+ self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
+
class StdStringConverter(InstanceConverter):
def __init__(self, space, extra):
@@ -628,7 +630,7 @@
except Exception:
InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
- def free_argument(self, space, arg, call_local):
+ def free_argument(self, space, arg):
capi.c_destruct(space, self.clsdecl, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
class StdStringRefConverter(InstancePtrConverter):
@@ -646,7 +648,7 @@
state = space.fromcache(ffitypes.State)
return state.c_voidp
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
if hasattr(space, "fake"):
raise NotImplementedError
space.getbuiltinmodule("cpyext")
@@ -657,7 +659,7 @@
ba = rffi.cast(rffi.CCHARP, address)
ba[capi.c_function_arg_typeoffset(space)] = 'a'
- def convert_argument_libffi(self, space, w_obj, address, call_local):
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
# TODO: free_argument not yet called for fast call (see interp_cppyy.py)
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible
@@ -671,7 +673,7 @@
x = rffi.cast(rffi.VOIDPP, address)
x[0] = rffi.cast(rffi.VOIDP, ref)"""
- def free_argument(self, space, arg, call_local):
+ def free_argument(self, space, arg):
if hasattr(space, "fake"):
raise NotImplementedError
space.getbuiltinmodule("cpyext")
@@ -685,7 +687,7 @@
def __init__(self, space, signature):
self.signature = signature
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
# TODO: atm, does not actually get an overload, but a staticmethod
from pypy.module._cppyy.interp_cppyy import W_CPPOverload
cppol = space.interp_w(W_CPPOverload, w_obj)
@@ -740,7 +742,7 @@
raise oefmt(space.w_TypeError,
"cannot pass %T instance as %s", w_obj, self.rawdecl.name)
- def convert_argument(self, space, w_obj, address, call_local):
+ def convert_argument(self, space, w_obj, address):
x = rffi.cast(rffi.VOIDPP, address)
x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
address = rffi.cast(capi.C_OBJECT, address)
diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -1,6 +1,9 @@
import pypy.module._cppyy.capi as capi
from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.function import Method
+from pypy.interpreter.argument import Arguments
+from pypy.interpreter.typedef import interp_attrproperty_w, descr_generic_ne, make_weakref_descr
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
from pypy.interpreter.baseobjspace import W_Root
@@ -166,11 +169,13 @@
# W_CPPConstructorOverload: constructors
# W_CPPStaticOverload: free and static functions
# W_CPPTemplateOverload: templated methods
-# W_CPPTemplateStaticOveload: templated free and static functions
+# W_CPPTemplateStaticOverload: templated free and static functions
#
# CPPMethod: a single function or method (base class)
# CPPSetItem: specialization for Python's __setitem__
#
+# MethodWithProps: python instancemethod that forwards properties
+#
# All methods/functions derive from CPPMethod and are collected as overload
# candidates in user-facing overload classes. Templated methods are a two-step
# process, where first the template is instantiated (or selected if already
@@ -183,13 +188,13 @@
the memory_regulator."""
_attrs_ = ['space', 'scope', 'cppmethod', 'arg_defs', 'args_required',
- 'converters', 'executor', '_funcaddr', 'cif_descr', 'uses_local']
+ 'converters', 'executor', '_funcaddr', 'cif_descr']
_immutable_fields_ = ['scope', 'cppmethod', 'arg_defs', 'args_required',
- 'converters', 'executor', 'uses_local']
+ 'converters', 'executor', '_funcaddr', 'cif_descr']
- def __init__(self, space, declaring_scope, cppmethod, arg_defs, args_required):
+ def __init__(self, space, decl_scope, cppmethod, arg_defs, args_required):
self.space = space
- self.scope = declaring_scope
+ self.scope = decl_scope
self.cppmethod = cppmethod
self.arg_defs = arg_defs
self.args_required = args_required
@@ -200,14 +205,6 @@
self.executor = None
self.cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
self._funcaddr = lltype.nullptr(capi.C_FUNC_PTR.TO)
- self.uses_local = False
-
- def _address_from_local_buffer(self, call_local, idx):
- if not call_local:
- return call_local
- stride = 2*rffi.sizeof(rffi.VOIDP)
- loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
- return rffi.cast(rffi.VOIDP, loc_idx)
@jit.unroll_safe
def call(self, cppthis, args_w, useffi):
@@ -233,61 +230,55 @@
except Exception:
pass
- # some calls, e.g. for ptr-ptr or reference need a local array to store data for
- # the duration of the call
- if self.uses_local:
- call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
- else:
- call_local = lltype.nullptr(rffi.VOIDP.TO)
+ # attempt to call directly through ffi chain
+ if useffi and self._funcaddr:
+ try:
+ return self.do_fast_call(cppthis, args_w)
+ except FastCallNotPossible:
+ pass # can happen if converters or executor does not implement ffi
+ # ffi chain must have failed; using stub functions instead
+ args, stat = self.prepare_arguments(args_w)
try:
- # attempt to call directly through ffi chain
- if useffi and self._funcaddr:
- try:
- return self.do_fast_call(cppthis, args_w, call_local)
- except FastCallNotPossible:
- pass # can happen if converters or executor does not implement ffi
-
- # ffi chain must have failed; using stub functions instead
- args, stat = self.prepare_arguments(args_w, call_local)
- try:
- result = self.executor.execute(
- self.space, self.cppmethod, cppthis, len(args_w), args)
- if stat[0] != rffi.cast(rffi.ULONG, 0):
- what = rffi.cast(rffi.CCHARP, stat[1])
- pywhat = rffi.charp2str(what)
- capi.c_free(self.space, rffi.cast(rffi.VOIDP, what))
- raise OperationError(self.space.w_Exception, self.space.newtext(pywhat))
- return result
- finally:
- self.finalize_call(args, args_w, call_local)
+ result = self.executor.execute(
+ self.space, self.cppmethod, cppthis, len(args_w), args)
+ if stat[0] != rffi.cast(rffi.ULONG, 0):
+ what = rffi.cast(rffi.CCHARP, stat[1])
+ pywhat = rffi.charp2str(what)
+ capi.c_free(self.space, rffi.cast(rffi.VOIDP, what))
+ raise OperationError(self.space.w_Exception, self.space.newtext(pywhat))
+ return result
finally:
- if call_local:
- lltype.free(call_local, flavor='raw')
+ self.finalize_call(args, args_w)
@jit.unroll_safe
- def do_fast_call(self, cppthis, args_w, call_local):
+ def do_fast_call(self, cppthis, args_w):
if self.cif_descr == lltype.nullptr(jit_libffi.CIF_DESCRIPTION):
raise FastCallNotPossible
jit.promote(self)
cif_descr = self.cif_descr
- buffer = lltype.malloc(rffi.CCHARP.TO, cif_descr.exchange_size, flavor='raw')
+ # add extra space for const-ref support (see converter.py)
+ buffer = lltype.malloc(rffi.CCHARP.TO, cif_descr.exchange_size+len(self.arg_defs)*rffi.sizeof(rffi.DOUBLE), flavor='raw')
+ thisoff = 0
try:
- # this pointer
- data = rffi.ptradd(buffer, cif_descr.exchange_args[0])
- x = rffi.cast(rffi.LONGP, data) # LONGP needed for test_zjit.py
- x[0] = rffi.cast(rffi.LONG, cppthis)
+ if cppthis:
+ # this pointer
+ data = rffi.ptradd(buffer, cif_descr.exchange_args[0])
+ x = rffi.cast(rffi.LONGP, data) # LONGP needed for test_zjit.py
+ x[0] = rffi.cast(rffi.LONG, cppthis)
+ thisoff = 1
- # other arguments and defaults
- i = len(self.arg_defs) + 1
+ # actual provided arguments
+ i = -1 # needed if all arguments are defaults
for i in range(len(args_w)):
conv = self.converters[i]
- w_arg = args_w[i]
- data = rffi.ptradd(buffer, cif_descr.exchange_args[i+1])
- conv.convert_argument_libffi(self.space, w_arg, data, call_local)
+ data = rffi.ptradd(buffer, cif_descr.exchange_args[i+thisoff])
+ scratch = rffi.ptradd(buffer, cif_descr.exchange_size+i*rffi.sizeof(rffi.DOUBLE))
+ conv.convert_argument_libffi(self.space, args_w[i], data, scratch)
+ # drop in defaults for the rest
for j in range(i+1, len(self.arg_defs)):
conv = self.converters[j]
- data = rffi.ptradd(buffer, cif_descr.exchange_args[j+1])
+ data = rffi.ptradd(buffer, cif_descr.exchange_args[j+thisoff])
conv.default_argument_libffi(self.space, data)
assert self._funcaddr
@@ -346,22 +337,17 @@
self.executor = executor.get_executor(
self.space, capi.c_method_result_type(self.space, self.cppmethod))
- for conv in self.converters:
- if conv.uses_local:
- self.uses_local = True
- break
-
# Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
# has been offset to the matching class. Hence, the libffi pointer is
# uniquely defined and needs to be setup only once.
funcaddr = capi.c_function_address(self.space, self.cppmethod)
- if funcaddr and cppthis: # TODO: methods only for now
+ if funcaddr:
state = self.space.fromcache(ffitypes.State)
- # argument type specification (incl. cppthis)
+ # argument type specification (incl. cppthis if applicable)
fargs = []
try:
- fargs.append(state.c_voidp)
+ if cppthis: fargs.append(state.c_voidp)
for i, conv in enumerate(self.converters):
fargs.append(conv.cffi_type(self.space))
fresult = self.executor.cffi_type(self.space)
@@ -386,7 +372,7 @@
self._funcaddr = funcaddr
@jit.unroll_safe
- def prepare_arguments(self, args_w, call_local):
+ def prepare_arguments(self, args_w):
args = capi.c_allocate_function_args(self.space, len(args_w))
stride = capi.c_function_arg_sizeof(self.space)
for i in range(len(args_w)):
@@ -394,15 +380,13 @@
w_arg = args_w[i]
try:
arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
- loc_i = self._address_from_local_buffer(call_local, i)
- conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+ conv.convert_argument(self.space, w_arg, rffi.cast(capi.C_OBJECT, arg_i))
except:
# fun :-(
for j in range(i):
conv = self.converters[j]
arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), j*stride)
- loc_j = self._address_from_local_buffer(call_local, j)
- conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j))
capi.c_deallocate_function_args(self.space, args)
raise
stat = rffi.cast(rffi.ULONGP,
@@ -411,14 +395,13 @@
return args, stat
@jit.unroll_safe
- def finalize_call(self, args, args_w, call_local):
+ def finalize_call(self, args, args_w):
stride = capi.c_function_arg_sizeof(self.space)
for i in range(len(args_w)):
conv = self.converters[i]
arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
- loc_i = self._address_from_local_buffer(call_local, i)
- conv.finalize_call(self.space, args_w[i], loc_i)
- conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+ conv.finalize_call(self.space, args_w[i])
+ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i))
capi.c_deallocate_function_args(self.space, args)
def signature(self, show_formalargs=True):
@@ -466,42 +449,81 @@
CPPMethod.call(self, cppthis, args_w, useffi)
+# CPPOverloads have settable flags that control memory and ffi behavior. These flags
+# need forwarding, which the normal instancemethod does not provide, hence this
+# derived class.
+class MethodWithProps(Method):
+ # allow user to determine ffi use rules per overload
+ def fget_useffi(self, space):
+ f = space.interp_w(W_CPPOverload, self.w_function)
+ return f.fget_useffi(space)
+
+ @unwrap_spec(value=bool)
+ def fset_useffi(self, space, value):
+ f = space.interp_w(W_CPPOverload, self.w_function)
+ f.fset_useffi(space, value)
+
+MethodWithProps.typedef = TypeDef(
+ "cpp_instancemethod",
+ __doc__ = """cpp_instancemethod(function, instance, class)
+
+Create an instance method object.""",
+ __new__ = interp2app(MethodWithProps.descr_method__new__.im_func),
+ __call__ = interp2app(MethodWithProps.descr_method_call),
+ __get__ = interp2app(MethodWithProps.descr_method_get),
+ im_func = interp_attrproperty_w('w_function', cls=MethodWithProps),
+ __func__ = interp_attrproperty_w('w_function', cls=MethodWithProps),
+ im_self = interp_attrproperty_w('w_instance', cls=MethodWithProps),
+ __self__ = interp_attrproperty_w('w_instance', cls=MethodWithProps),
+ im_class = interp_attrproperty_w('w_class', cls=MethodWithProps),
+ __getattribute__ = interp2app(MethodWithProps.descr_method_getattribute),
+ __eq__ = interp2app(MethodWithProps.descr_method_eq),
+ __ne__ = descr_generic_ne,
+ __hash__ = interp2app(MethodWithProps.descr_method_hash),
+ __repr__ = interp2app(MethodWithProps.descr_method_repr),
+ __reduce__ = interp2app(MethodWithProps.descr_method__reduce__),
+ __weakref__ = make_weakref_descr(MethodWithProps),
+ __useffi__ = GetSetProperty(MethodWithProps.fget_useffi, MethodWithProps.fset_useffi),
+ )
+MethodWithProps.typedef.acceptable_as_base_class = False
+
+
class W_CPPOverload(W_Root):
"""App-level dispatcher: controls a collection of (potentially) overloaded methods
or functions. Calls these in order and deals with error handling and reporting."""
- _attrs_ = ['space', 'scope', 'functions', 'flags', 'w_this']
+ _attrs_ = ['space', 'scope', 'functions', 'flags']
_immutable_fields_ = ['scope', 'functions[*]']
- def __init__(self, space, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
+ def __init__(self, space, decl_scope, funcs, flags = OVERLOAD_FLAGS_USE_FFI):
self.space = space
- self.scope = declaring_scope
+ self.scope = decl_scope
from rpython.rlib import debug
- self.functions = debug.make_sure_not_resized(functions)
+ self.functions = debug.make_sure_not_resized(funcs)
self.flags = flags
- self.w_this = self.space.w_None
+
+ def descr_get(self, w_obj, w_cls=None):
+ """functionobject.__get__(obj[, type]) -> method"""
+ # TODO: check validity of w_cls if given
+ space = self.space
+ asking_for_bound = (space.is_none(w_cls) or
+ not space.is_w(w_obj, space.w_None) or
+ space.is_w(w_cls, space.type(space.w_None)))
+ if asking_for_bound:
+ return MethodWithProps(space, self, w_obj, w_cls)
+ else:
+ return MethodWithProps(space, self, None, w_cls)
@unwrap_spec(args_w='args_w')
- def descr_get(self, w_cppinstance, args_w):
- if self.space.is_w(w_cppinstance, self.space.w_None):
- return self # unbound, so no new instance needed
- cppol = W_CPPOverload(self.space, self.scope, self.functions, self.flags)
- cppol.w_this = w_cppinstance
- return cppol # bound
-
- @unwrap_spec(args_w='args_w')
- def call(self, args_w):
- if self.space.is_w(self.w_this, self.space.w_None) and len(args_w):
- w_this = args_w[0]
- args_w = args_w[1:]
- else:
- w_this = self.w_this
+ def call_args(self, args_w):
+ jit.promote(self)
+ w_this = args_w[0]
cppinstance = self.space.interp_w(W_CPPInstance, w_this)
cppinstance._nullcheck()
if not capi.c_is_subtype(self.space, cppinstance.clsdecl, self.scope):
raise oefmt(self.space.w_TypeError,
"cannot pass %T instance as %s", w_this, self.scope.name)
- return self.call_impl(cppinstance.get_cppthis(self.scope), args_w)
+ return self.call_impl(cppinstance.get_cppthis(self.scope), args_w[1:])
@jit.unroll_safe
def call_impl(self, cppthis, args_w):
@@ -576,13 +598,17 @@
def fget_doc(self, space):
return self.prototype()
+ def getname(self, space):
+ # for the benefit of Method/instancemethod
+ return capi.c_method_name(space, self.functions[0].cppmethod)
+
def __repr__(self):
return "W_CPPOverload(%s)" % [f.prototype() for f in self.functions]
W_CPPOverload.typedef = TypeDef(
'CPPOverload',
__get__ = interp2app(W_CPPOverload.descr_get),
- __call__ = interp2app(W_CPPOverload.call),
+ __call__ = interp2app(W_CPPOverload.call_args),
__useffi__ = GetSetProperty(W_CPPOverload.fget_useffi, W_CPPOverload.fset_useffi),
__doc__ = GetSetProperty(W_CPPOverload.fget_doc)
)
@@ -593,27 +619,24 @@
class W_CPPStaticOverload(W_CPPOverload):
_attrs_ = []
- @unwrap_spec(args_w='args_w')
- def descr_get(self, w_cppinstance, args_w):
- if isinstance(w_cppinstance, W_CPPInstance):
+ def descr_get(self, w_obj, w_cls=None):
+ if isinstance(w_obj, W_CPPInstance):
# two possibilities: this is a static function called on an
# instance and w_this must not be set, or a free function rebound
# onto a class and w_this should be set
- cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance)
+ cppinstance = self.space.interp_w(W_CPPInstance, w_obj)
if cppinstance.clsdecl.handle != self.scope.handle:
- cppol = W_CPPStaticOverload(self.space, self.scope, self.functions, self.flags)
- cppol.w_this = w_cppinstance
- return cppol # bound
+ return MethodWithProps(self.space, self, w_obj, w_cls) # bound
return self # unbound
@unwrap_spec(args_w='args_w')
- def call(self, args_w):
- if not self.space.is_w(self.w_this, self.space.w_None):
- # free function used as bound method, put self back into args_w
- cppinstance = self.space.interp_w(W_CPPInstance, self.w_this)
- cppinstance._nullcheck()
- args_w = [self.w_this] + args_w
+ def call_args(self, args_w):
+ jit.promote(self)
+ #if isinstance(args_w[0], W_CPPInstance):
+ # free function used as bound method, leave in place
return self.call_impl(capi.C_NULL_OBJECT, args_w)
+ # free functions are implemented as methods of 'namespace' classes, remove 'instance'
+ #return self.call_impl(capi.C_NULL_OBJECT, args_w[1:])
def __repr__(self):
return "W_CPPStaticOverload(%s)" % [f.prototype() for f in self.functions]
@@ -621,7 +644,7 @@
W_CPPStaticOverload.typedef = TypeDef(
'CPPStaticOverload',
__get__ = interp2app(W_CPPStaticOverload.descr_get),
- __call__ = interp2app(W_CPPStaticOverload.call),
+ __call__ = interp2app(W_CPPStaticOverload.call_args),
__useffi__ = GetSetProperty(W_CPPStaticOverload.fget_useffi, W_CPPStaticOverload.fset_useffi),
__doc__ = GetSetProperty(W_CPPStaticOverload.fget_doc)
)
@@ -630,27 +653,20 @@
class W_CPPConstructorOverload(W_CPPOverload):
_attrs_ = []
- @unwrap_spec(args_w='args_w')
- def descr_get(self, w_cppinstance, args_w):
- if self.space.is_w(w_cppinstance, self.space.w_None):
- return self # unbound (TODO: probably useless)
- cppol = W_CPPConstructorOverload(self.space, self.scope, self.functions, self.flags)
- cppol.w_this = w_cppinstance
- return cppol # bound
+ def __init__(self, space, decl_scope, funcs, flags = OVERLOAD_FLAGS_USE_FFI):
+ W_CPPOverload.__init__(self, space, decl_scope, funcs, flags)
+ self.flags &= ~OVERLOAD_FLAGS_USE_FFI
@unwrap_spec(args_w='args_w')
- def call(self, args_w):
+ def call_args(self, args_w):
+ jit.promote(self)
# TODO: factor out the following:
if capi.c_is_abstract(self.space, self.scope.handle):
raise oefmt(self.space.w_TypeError,
"cannot instantiate abstract class '%s'",
self.scope.name)
- if self.space.is_w(self.w_this, self.space.w_None) and len(args_w):
- cppinstance = self.space.interp_w(W_CPPInstance, args_w[0])
- args_w = args_w[1:]
- else:
- cppinstance = self.space.interp_w(W_CPPInstance, self.w_this)
- w_result = self.call_impl(rffi.cast(capi.C_OBJECT, self.scope.handle), args_w)
+ cppinstance = self.space.interp_w(W_CPPInstance, args_w[0])
+ w_result = self.call_impl(rffi.cast(capi.C_OBJECT, self.scope.handle), args_w[1:])
newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
if cppinstance is not None:
cppinstance._rawobject = newthis
@@ -662,7 +678,7 @@
W_CPPConstructorOverload.typedef = TypeDef(
'CPPConstructorOverload',
__get__ = interp2app(W_CPPConstructorOverload.descr_get),
- __call__ = interp2app(W_CPPConstructorOverload.call),
+ __call__ = interp2app(W_CPPConstructorOverload.call_args),
__doc__ = GetSetProperty(W_CPPConstructorOverload.fget_doc)
)
@@ -725,7 +741,9 @@
# try to match with run-time instantiations
for cppol in self.master.overloads.values():
try:
- return cppol.descr_get(self.w_this, []).call(args_w)
+ if not self.space.is_w(self.w_this, self.space.w_None):
+ return self.space.call_obj_args(cppol, self.w_this, Arguments(self.space, args_w))
+ return self.space.call_args(cppol, Arguments(self.space, args_w))
except Exception:
pass # completely ignore for now; have to see whether errors become confusing
@@ -748,7 +766,9 @@
except KeyError:
self.master.overloads[fullname] = method
- return method.descr_get(self.w_this, []).call(args_w)
+ if not self.space.is_w(self.w_this, self.space.w_None):
+ return self.space.call_obj_args(method, self.w_this, Arguments(self.space, args_w))
+ return self.space.call_args(method, Arguments(self.space, args_w))
def getitem_impl(self, name, args_w):
space = self.space
@@ -771,25 +791,25 @@
if c_fullname != fullname:
self.master.overloads[c_fullname] = method
- return method.descr_get(self.w_this, [])
+ return method.descr_get(self.w_this, None)
class W_CPPTemplateOverload(W_CPPOverload, TemplateOverloadMixin):
"""App-level dispatcher to allow both lookup/instantiation of templated methods and
dispatch among overloads between templated and non-templated method."""
- _attrs_ = ['name', 'overloads', 'master']
+ _attrs_ = ['name', 'overloads', 'master', 'w_this']
_immutable_fields_ = ['name']
- def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
- W_CPPOverload.__init__(self, space, declaring_scope, functions, flags)
+ def __init__(self, space, name, decl_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
+ W_CPPOverload.__init__(self, space, decl_scope, functions, flags)
self.name = name
self.overloads = {}
self.master = self
+ self.w_this = space.w_None
- @unwrap_spec(args_w='args_w')
- def descr_get(self, w_cppinstance, args_w):
- # like W_CPPOverload, but returns W_CPPTemplateOverload
+ def descr_get(self, w_cppinstance, w_cls=None):
+ # TODO: don't return copy, but bind in an external object (like W_CPPOverload)
if self.space.is_w(w_cppinstance, self.space.w_None):
return self # unbound, so no new instance needed
cppol = W_CPPTemplateOverload(self.space, self.name, self.scope, self.functions, self.flags)
@@ -798,13 +818,13 @@
return cppol # bound
@unwrap_spec(args_w='args_w')
- def call(self, args_w):
+ def call_args(self, args_w):
# direct call: either pick non-templated overload or attempt to deduce
# the template instantiation from the argument types
# try existing overloads or compile-time instantiations
try:
- return W_CPPOverload.call(self, args_w)
+ return W_CPPOverload.call_args(self, args_w)
except Exception:
pass
@@ -814,6 +834,9 @@
def getitem(self, args_w):
return self.getitem_impl(self.name, args_w)
+ def getname(self, space):
+ return self.name
+
def __repr__(self):
return "W_CPPTemplateOverload(%s)" % [f.prototype() for f in self.functions]
@@ -821,7 +844,7 @@
'CPPTemplateOverload',
__get__ = interp2app(W_CPPTemplateOverload.descr_get),
__getitem__ = interp2app(W_CPPTemplateOverload.getitem),
- __call__ = interp2app(W_CPPTemplateOverload.call),
+ __call__ = interp2app(W_CPPTemplateOverload.call_args),
__useffi__ = GetSetProperty(W_CPPTemplateOverload.fget_useffi, W_CPPTemplateOverload.fset_useffi),
__doc__ = GetSetProperty(W_CPPTemplateOverload.fget_doc)
)
@@ -830,18 +853,18 @@
"""App-level dispatcher to allow both lookup/instantiation of templated methods and
dispatch among overloads between templated and non-templated method."""
- _attrs_ = ['name', 'overloads', 'master']
+ _attrs_ = ['name', 'overloads', 'master', 'w_this']
_immutable_fields_ = ['name']
- def __init__(self, space, name, declaring_scope, functions, flags = OVERLOAD_FLAGS_USE_FFI):
- W_CPPStaticOverload.__init__(self, space, declaring_scope, functions, flags)
+ def __init__(self, space, name, decl_scope, funcs, flags = OVERLOAD_FLAGS_USE_FFI):
+ W_CPPStaticOverload.__init__(self, space, decl_scope, funcs, flags)
self.name = name
self.overloads = {}
self.master = self
+ self.w_this = space.w_None
- @unwrap_spec(args_w='args_w')
- def descr_get(self, w_cppinstance, args_w):
- # like W_CPPStaticOverload, but returns W_CPPTemplateStaticOverload
+ def descr_get(self, w_cppinstance, w_cls=None):
+ # TODO: don't return copy, but bind in an external object (like W_CPPOverload)
if isinstance(w_cppinstance, W_CPPInstance):
cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance)
if cppinstance.clsdecl.handle != self.scope.handle:
@@ -852,13 +875,13 @@
return self # unbound
@unwrap_spec(args_w='args_w')
- def call(self, args_w):
+ def call_args(self, args_w):
# direct call: either pick non-templated overload or attempt to deduce
# the template instantiation from the argument types
# try existing overloads or compile-time instantiations
try:
- return W_CPPStaticOverload.call(self, args_w)
+ return W_CPPStaticOverload.call_args(self, args_w)
except Exception:
pass
@@ -869,6 +892,9 @@
def getitem(self, args_w):
return self.getitem_impl(self.name, args_w)
+ def getname(self, space):
+ return self.name
+
def __repr__(self):
return "W_CPPTemplateStaticOverload(%s)" % [f.prototype() for f in self.functions]
@@ -876,7 +902,7 @@
'CPPTemplateStaticOverload',
__get__ = interp2app(W_CPPTemplateStaticOverload.descr_get),
__getitem__ = interp2app(W_CPPTemplateStaticOverload.getitem),
- __call__ = interp2app(W_CPPTemplateStaticOverload.call),
+ __call__ = interp2app(W_CPPTemplateStaticOverload.call_args),
__useffi__ = GetSetProperty(W_CPPTemplateStaticOverload.fget_useffi, W_CPPTemplateStaticOverload.fset_useffi),
__doc__ = GetSetProperty(W_CPPTemplateStaticOverload.fget_doc)
)
@@ -898,9 +924,9 @@
_attrs_ = ['space', 'scope', 'converter', 'offset']
_immutable_fields = ['scope', 'converter', 'offset']
- def __init__(self, space, declaring_scope, type_name, offset):
+ def __init__(self, space, decl_scope, type_name, offset):
self.space = space
- self.scope = declaring_scope
+ self.scope = decl_scope
self.converter = converter.get_converter(self.space, type_name, '')
self.offset = offset
@@ -1417,7 +1443,7 @@
ol = W_CPPStaticOverload(self.space, nss, funcs[:])
# TODO: cache this operator (not done yet, as the above does not
# select all overloads)
- return ol.call([self, w_other])
+ return ol.call_args([self, w_other])
except OperationError as e:
if not e.match(self.space, self.space.w_TypeError):
raise
diff --git a/pypy/module/_cppyy/test/test_zjit.py b/pypy/module/_cppyy/test/test_zjit.py
--- a/pypy/module/_cppyy/test/test_zjit.py
+++ b/pypy/module/_cppyy/test/test_zjit.py
@@ -205,6 +205,9 @@
def exception_match(self, typ, sub):
return typ is sub
+ def is_none(self, w_obj):
+ return w_obj is None
+
def is_w(self, w_one, w_two):
return w_one is w_two
@@ -268,6 +271,9 @@
def call_function(self, w_func, *args_w):
return None
+ def call_obj_args(self, w_callable, w_obj, args):
+ return w_callable.call_args([w_obj]+args)
+
def _freeze_(self):
return True
@@ -283,19 +289,19 @@
def f():
cls = interp_cppyy.scope_byname(space, "example01")
inst = interp_cppyy._bind_object(space, FakeInt(0), cls, True)
- cls.get_overload("__init__").descr_get(inst, []).call([FakeInt(0)])
+ cls.get_overload("__init__").descr_get(inst, []).call_args([FakeInt(0)])
cppmethod = cls.get_overload(method_name)
assert isinstance(inst, interp_cppyy.W_CPPInstance)
i = 10
while i > 0:
drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)
- cppmethod.descr_get(inst, []).call([FakeInt(i)])
+ cppmethod.descr_get(inst, []).call_args([FakeInt(i)])
i -= 1
return 7
f()
space = FakeSpace()
result = self.meta_interp(f, [], listops=True, backendopt=True, listcomp=True)
- self.check_jitcell_token_count(0) # same for fast and slow path??
+ self.check_jitcell_token_count(1)
# rely on replacement of capi calls to raise exception instead (see FakeSpace.__init__)
@py.test.mark.dont_track_allocations("cppmethod.cif_descr kept 'leaks'")
More information about the pypy-commit
mailing list