def prepare_nostruct_fnptr(self, ffi): # tweaked version: instead of returning the ctfuncptr # corresponding exactly to the OP_FUNCTION ... OP_FUNCTION_END # opcodes, this builds in self.nostruct_ctype another one in # which the struct args are replaced with ptr-to- struct, and # a struct return value is replaced with a hidden first arg of # type ptr-to-struct. This is how recompiler.py produces # trampoline functions for PyPy. if self.nostruct_ctype is None: fargs, fret, ellipsis, abi = self._unpack(ffi) # 'locs' will be a string of the same length as the final fargs, # containing 'A' where a struct argument was detected, and 'R' # in first position if a struct return value was detected locs = ['\x00'] * len(fargs) for i in range(len(fargs)): farg = fargs[i] if isinstance(farg, ctypestruct.W_CTypeStructOrUnion): farg = newtype.new_pointer_type(ffi.space, farg) fargs[i] = farg locs[i] = 'A' if isinstance(fret, ctypestruct.W_CTypeStructOrUnion): fret = newtype.new_pointer_type(ffi.space, fret) fargs = [fret] + fargs locs = ['R'] + locs fret = newtype.new_void_type(ffi.space) ctfuncptr = newtype._new_function_type( ffi.space, fargs, fret, ellipsis, abi) if locs == ['\x00'] * len(locs): locs = None else: locs = ''.join(locs) self.nostruct_ctype = ctfuncptr self.nostruct_locs = locs self.nostruct_nargs = len(ctfuncptr.fargs) - (locs is not None and locs[0] == 'R')
def tf1_tf1(space, w_self, args_w): """Pythonized version of TF1 constructor: takes functions and callable objects, and allows a callback into them.""" from pypy.module.cppyy import interp_cppyy tf1_class = interp_cppyy.scope_byname(space, "TF1") # expected signature: # 1. (char* name, pyfunc, double xmin, double xmax, int npar = 0) argc = len(args_w) try: if argc < 4 or 5 < argc: raise TypeError("wrong number of arguments") # first argument must be a name funcname = space.str_w(args_w[0]) # last (optional) argument is number of parameters npar = 0 if argc == 5: npar = space.int_w(args_w[4]) # second argument must be a callable python object w_callable = args_w[1] if not space.is_true(space.callable(w_callable)): raise TypeError("2nd argument is not a valid python callable") # generate a pointer to function from pypy.module._cffi_backend import newtype, ctypefunc, func c_double = newtype.new_primitive_type(space, 'double') c_doublep = newtype.new_pointer_type(space, c_double) # wrap the callable as the signature needs modifying w_ifunc = interp_cppyy.get_interface_func(space, w_callable, npar) w_cfunc = ctypefunc.W_CTypeFunc(space, [c_doublep, c_doublep], c_double, False) w_callback = func.callback(space, w_cfunc, w_ifunc, None) funcaddr = rffi.cast(rffi.ULONG, w_callback.get_closure()) # so far, so good; leaves on issue: CINT is expecting a wrapper, but # we need the overload that takes a function pointer, which is not in # the dictionary, hence this helper: newinst = _create_tf1(space.str_w(args_w[0]), funcaddr, space.float_w(args_w[2]), space.float_w(args_w[3]), npar) # w_self is a null-ptr bound as TF1 from pypy.module.cppyy.interp_cppyy import W_CPPInstance, memory_regulator cppself = space.interp_w(W_CPPInstance, w_self, can_be_None=False) cppself._rawobject = newinst memory_regulator.register(cppself) # tie all the life times to the TF1 instance space.setattr(w_self, space.wrap('_callback'), w_callback) # by definition for __init__ return None except (OperationError, TypeError, IndexError), e: newargs_w = args_w[1:] # drop class
def realize_c_type_or_func(ffi, opcodes, index): op = opcodes[index] from_ffi = (opcodes == ffi.ctxobj.ctx.c_types) if from_ffi and ffi.cached_types[index] is not None: return ffi.cached_types[index] case = getop(op) if case == cffi_opcode.OP_PRIMITIVE: x = get_primitive_type(ffi, getarg(op)) elif case == cffi_opcode.OP_POINTER: y = realize_c_type_or_func(ffi, opcodes, getarg(op)) if isinstance(y, W_CType): x = newtype.new_pointer_type(ffi.space, y) elif isinstance(y, W_RawFuncType): x = y.unwrap_as_fnptr(ffi) else: raise NotImplementedError elif case == cffi_opcode.OP_ARRAY: x = get_array_type(ffi, opcodes, getarg(op), rffi.cast(rffi.SIGNED, opcodes[index + 1])) elif case == cffi_opcode.OP_OPEN_ARRAY: x = get_array_type(ffi, opcodes, getarg(op), -1) elif case == cffi_opcode.OP_STRUCT_UNION: x = _realize_c_struct_or_union(ffi, getarg(op)) elif case == cffi_opcode.OP_ENUM: x = _realize_c_enum(ffi, getarg(op)) elif case == cffi_opcode.OP_FUNCTION: x = W_RawFuncType(opcodes, index) elif case == cffi_opcode.OP_NOOP: x = realize_c_type_or_func(ffi, opcodes, getarg(op)) elif case == cffi_opcode.OP_TYPENAME: # essential: the TYPENAME opcode resolves the type index looked # up in the 'ctx.c_typenames' array, but it does so in 'ctx.c_types' # instead of in 'opcodes'! type_index = rffi.getintfield(ffi.ctxobj.ctx.c_typenames[getarg(op)], 'c_type_index') x = realize_c_type_or_func(ffi, ffi.ctxobj.ctx.c_types, type_index) else: raise oefmt(ffi.space.w_NotImplementedError, "op=%d", case) if from_ffi: assert ffi.cached_types[index] is None or ffi.cached_types[index] is x ffi.cached_types[index] = x return x
def descr_addressof(self, w_arg, args_w): """\ Limited equivalent to the '&' operator in C: 1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a pointer to this struct or union. 2. ffi.addressof(<cdata>, field-or-index...) returns the address of a field or array item inside the given structure or array, recursively in case of nested structures or arrays. 3. ffi.addressof(<library>, "name") returns the address of the named function or global variable.""" # from pypy.module._cffi_backend.lib_obj import W_LibObject space = self.space if isinstance(w_arg, W_LibObject) and len(args_w) == 1: # case 3 in the docstring return w_arg.address_of_func_or_global_var(space.str_w(args_w[0])) # w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA) if len(args_w) == 0: # case 1 in the docstring if not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and not isinstance( w_ctype, ctypearray.W_CTypeArray ): raise oefmt(space.w_TypeError, "expected a cdata struct/union/array object") offset = 0 else: # case 2 in the docstring if ( not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and not isinstance(w_ctype, ctypearray.W_CTypeArray) and not isinstance(w_ctype, ctypeptr.W_CTypePointer) ): raise oefmt(space.w_TypeError, "expected a cdata struct/union/array/pointer object") if len(args_w) == 1: w_ctype, offset = w_ctype.direct_typeoffsetof(args_w[0], False) else: w_ctype, offset = self._more_addressof(args_w, w_ctype) # assert isinstance(w_arg, W_CData) cdata = w_arg.unsafe_escaping_ptr() cdata = rffi.ptradd(cdata, offset) w_ctypeptr = newtype.new_pointer_type(space, w_ctype) return W_CData(space, cdata, w_ctypeptr)
def descr_addressof(self, w_arg, args_w): """\ Limited equivalent to the '&' operator in C: 1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a pointer to this struct or union. 2. ffi.addressof(<cdata>, field-or-index...) returns the address of a field or array item inside the given structure or array, recursively in case of nested structures or arrays. 3. ffi.addressof(<library>, "name") returns the address of the named function or global variable.""" # from pypy.module._cffi_backend.lib_obj import W_LibObject space = self.space if isinstance(w_arg, W_LibObject) and len(args_w) == 1: # case 3 in the docstring return w_arg.address_of_func_or_global_var(space.text_w(args_w[0])) # w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA) if len(args_w) == 0: # case 1 in the docstring if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and not isinstance(w_ctype, ctypearray.W_CTypeArray)): raise oefmt(space.w_TypeError, "expected a cdata struct/union/array object") offset = 0 else: # case 2 in the docstring if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and not isinstance(w_ctype, ctypearray.W_CTypeArray) and not isinstance(w_ctype, ctypeptr.W_CTypePointer)): raise oefmt( space.w_TypeError, "expected a cdata struct/union/array/pointer object") if len(args_w) == 1: w_ctype, offset = w_ctype.direct_typeoffsetof(args_w[0], False) else: w_ctype, offset = self._more_addressof(args_w, w_ctype) # assert isinstance(w_arg, W_CData) cdata = w_arg.unsafe_escaping_ptr() cdata = rffi.ptradd(cdata, offset) w_ctypeptr = newtype.new_pointer_type(space, w_ctype) return W_CData(space, cdata, w_ctypeptr)
def get_array_type(ffi, opcodes, itemindex, length): w_ctitem = realize_c_type(ffi, opcodes, itemindex) w_ctitemptr = newtype.new_pointer_type(ffi.space, w_ctitem) return newtype._new_array_type(ffi.space, w_ctitemptr, length)
def realize_c_type_or_func(ffi, opcodes, index): op = opcodes[index] from_ffi = (opcodes == ffi.ctxobj.ctx.c_types) if from_ffi and ffi.cached_types[index] is not None: return ffi.cached_types[index] case = getop(op) if case == cffi_opcode.OP_PRIMITIVE: x = get_primitive_type(ffi, getarg(op)) elif case == cffi_opcode.OP_POINTER: y = realize_c_type_or_func(ffi, opcodes, getarg(op)) if isinstance(y, W_CType): x = newtype.new_pointer_type(ffi.space, y) elif isinstance(y, W_RawFuncType): x = y.unwrap_as_fnptr(ffi) else: raise NotImplementedError elif case == cffi_opcode.OP_ARRAY: x = get_array_type(ffi, opcodes, getarg(op), rffi.cast(rffi.SIGNED, opcodes[index + 1])) elif case == cffi_opcode.OP_OPEN_ARRAY: x = get_array_type(ffi, opcodes, getarg(op), -1) elif case == cffi_opcode.OP_STRUCT_UNION: x = _realize_c_struct_or_union(ffi, getarg(op))
def __init__(self, space): self.library = None self.capi_calls = {} import pypy.module._cffi_backend.newtype as nt # TODO: the following need to match up with the globally defined C_XYZ low-level # types (see capi/__init__.py), but by using strings here, that isn't guaranteed c_opaque_ptr = nt.new_primitive_type(space, 'unsigned long') c_scope = c_opaque_ptr c_type = c_scope c_object = c_opaque_ptr c_method = c_opaque_ptr c_index = nt.new_primitive_type(space, 'long') c_void = nt.new_void_type(space) c_char = nt.new_primitive_type(space, 'char') c_uchar = nt.new_primitive_type(space, 'unsigned char') c_short = nt.new_primitive_type(space, 'short') c_int = nt.new_primitive_type(space, 'int') c_long = nt.new_primitive_type(space, 'long') c_llong = nt.new_primitive_type(space, 'long long') c_ullong = nt.new_primitive_type(space, 'unsigned long long') c_float = nt.new_primitive_type(space, 'float') c_double = nt.new_primitive_type(space, 'double') c_ccharp = nt.new_pointer_type(space, c_char) c_index_array = nt.new_pointer_type(space, c_void) c_voidp = nt.new_pointer_type(space, c_void) c_size_t = nt.new_primitive_type(space, 'size_t') c_ptrdiff_t = nt.new_primitive_type(space, 'ptrdiff_t') self.capi_call_ifaces = { # name to opaque C++ scope representation 'num_scopes' : ([c_scope], c_int), 'scope_name' : ([c_scope, c_int], c_ccharp), 'resolve_name' : ([c_ccharp], c_ccharp), 'get_scope' : ([c_ccharp], c_scope), 'get_template' : ([c_ccharp], c_type), 'actual_class' : ([c_type, c_object], c_type), # memory management 'allocate' : ([c_type], c_object), 'deallocate' : ([c_type, c_object], c_void), 'destruct' : ([c_type, c_object], c_void), # method/function dispatching 'call_v' : ([c_method, c_object, c_int, c_voidp], c_void), 'call_b' : ([c_method, c_object, c_int, c_voidp], c_uchar), 'call_c' : ([c_method, c_object, c_int, c_voidp], c_char), 'call_h' : ([c_method, c_object, c_int, c_voidp], c_short), 'call_i' : ([c_method, c_object, c_int, c_voidp], c_int), 'call_l' : ([c_method, c_object, c_int, c_voidp], c_long), 'call_ll' : ([c_method, c_object, c_int, c_voidp], c_llong), 'call_f' : ([c_method, c_object, c_int, c_voidp], c_float), 'call_d' : ([c_method, c_object, c_int, c_voidp], c_double), 'call_r' : ([c_method, c_object, c_int, c_voidp], c_voidp), 'call_s' : ([c_method, c_object, c_int, c_voidp], c_ccharp), 'constructor' : ([c_method, c_object, c_int, c_voidp], c_object), 'call_o' : ([c_method, c_object, c_int, c_voidp, c_type], c_object), 'get_methptr_getter' : ([c_scope, c_index], c_voidp), # TODO: verify # handling of function argument buffer 'allocate_function_args' : ([c_int], c_voidp), 'deallocate_function_args' : ([c_voidp], c_void), 'function_arg_sizeof' : ([], c_size_t), 'function_arg_typeoffset' : ([], c_size_t), # scope reflection information 'is_namespace' : ([c_scope], c_int), 'is_enum' : ([c_ccharp], c_int), # type/class reflection information 'final_name' : ([c_type], c_ccharp), 'scoped_final_name' : ([c_type], c_ccharp), 'has_complex_hierarchy' : ([c_type], c_int), 'num_bases' : ([c_type], c_int), 'base_name' : ([c_type, c_int], c_ccharp), 'is_subtype' : ([c_type, c_type], c_int), 'base_offset' : ([c_type, c_type, c_object, c_int], c_ptrdiff_t), # method/function reflection information 'num_methods' : ([c_scope], c_int), 'method_index_at' : ([c_scope, c_int], c_index), 'method_indices_from_name' : ([c_scope, c_ccharp], c_index_array), 'method_name' : ([c_scope, c_index], c_ccharp), 'method_result_type' : ([c_scope, c_index], c_ccharp), 'method_num_args' : ([c_scope, c_index], c_int), 'method_req_args' : ([c_scope, c_index], c_int), 'method_arg_type' : ([c_scope, c_index, c_int], c_ccharp), 'method_arg_default' : ([c_scope, c_index, c_int], c_ccharp), 'method_signature' : ([c_scope, c_index], c_ccharp), 'method_is_template' : ([c_scope, c_index], c_int), 'method_num_template_args' : ([c_scope, c_index], c_int), 'method_template_arg_name' : ([c_scope, c_index, c_index], c_ccharp), 'get_method' : ([c_scope, c_index], c_method), 'get_global_operator' : ([c_scope, c_scope, c_scope, c_ccharp], c_index), # method properties 'is_constructor' : ([c_type, c_index], c_int), 'is_staticmethod' : ([c_type, c_index], c_int), # data member reflection information 'num_datamembers' : ([c_scope], c_int), 'datamember_name' : ([c_scope, c_int], c_ccharp), 'datamember_type' : ([c_scope, c_int], c_ccharp), 'datamember_offset' : ([c_scope, c_int], c_ptrdiff_t), 'datamember_index' : ([c_scope, c_ccharp], c_int), # data member properties 'is_publicdata' : ([c_scope, c_int], c_int), 'is_staticdata' : ([c_scope, c_int], c_int), # misc helpers 'strtoll' : ([c_ccharp], c_llong), 'strtoull' : ([c_ccharp], c_ullong), 'free' : ([c_voidp], c_void), 'charp2stdstring' : ([c_ccharp], c_object), 'stdstring2stdstring' : ([c_object], c_object), } # size/offset are backend-specific but fixed after load self.c_sizeof_farg = 0 self.c_offset_farg = 0
def __init__(self, space): self.library = None self.capi_calls = {} import pypy.module._cffi_backend.newtype as nt # TODO: the following need to match up with the globally defined C_XYZ low-level # types (see capi/__init__.py), but by using strings here, that isn't guaranteed c_opaque_ptr = nt.new_primitive_type(space, 'unsigned long') c_scope = c_opaque_ptr c_type = c_scope c_object = c_opaque_ptr c_method = c_opaque_ptr c_index = nt.new_primitive_type(space, 'long') c_void = nt.new_void_type(space) c_char = nt.new_primitive_type(space, 'char') c_uchar = nt.new_primitive_type(space, 'unsigned char') c_short = nt.new_primitive_type(space, 'short') c_int = nt.new_primitive_type(space, 'int') c_long = nt.new_primitive_type(space, 'long') c_llong = nt.new_primitive_type(space, 'long long') c_ullong = nt.new_primitive_type(space, 'unsigned long long') c_float = nt.new_primitive_type(space, 'float') c_double = nt.new_primitive_type(space, 'double') c_ccharp = nt.new_pointer_type(space, c_char) c_index_array = nt.new_pointer_type(space, c_void) c_voidp = nt.new_pointer_type(space, c_void) c_size_t = nt.new_primitive_type(space, 'size_t') c_ptrdiff_t = nt.new_primitive_type(space, 'ptrdiff_t') self.capi_call_ifaces = { # name to opaque C++ scope representation 'num_scopes': ([c_scope], c_int), 'scope_name': ([c_scope, c_int], c_ccharp), 'resolve_name': ([c_ccharp], c_ccharp), 'get_scope': ([c_ccharp], c_scope), 'get_template': ([c_ccharp], c_type), 'actual_class': ([c_type, c_object], c_type), # memory management 'allocate': ([c_type], c_object), 'deallocate': ([c_type, c_object], c_void), 'destruct': ([c_type, c_object], c_void), # method/function dispatching 'call_v': ([c_method, c_object, c_int, c_voidp], c_void), 'call_b': ([c_method, c_object, c_int, c_voidp], c_uchar), 'call_c': ([c_method, c_object, c_int, c_voidp], c_char), 'call_h': ([c_method, c_object, c_int, c_voidp], c_short), 'call_i': ([c_method, c_object, c_int, c_voidp], c_int), 'call_l': ([c_method, c_object, c_int, c_voidp], c_long), 'call_ll': ([c_method, c_object, c_int, c_voidp], c_llong), 'call_f': ([c_method, c_object, c_int, c_voidp], c_float), 'call_d': ([c_method, c_object, c_int, c_voidp], c_double), 'call_r': ([c_method, c_object, c_int, c_voidp], c_voidp), 'call_s': ([c_method, c_object, c_int, c_voidp], c_ccharp), 'constructor': ([c_method, c_object, c_int, c_voidp], c_object), 'call_o': ([c_method, c_object, c_int, c_voidp, c_type], c_object), 'get_methptr_getter': ([c_scope, c_index], c_voidp), # TODO: verify # handling of function argument buffer 'allocate_function_args': ([c_int], c_voidp), 'deallocate_function_args': ([c_voidp], c_void), 'function_arg_sizeof': ([], c_size_t), 'function_arg_typeoffset': ([], c_size_t), # scope reflection information 'is_namespace': ([c_scope], c_int), 'is_enum': ([c_ccharp], c_int), # type/class reflection information 'final_name': ([c_type], c_ccharp), 'scoped_final_name': ([c_type], c_ccharp), 'has_complex_hierarchy': ([c_type], c_int), 'num_bases': ([c_type], c_int), 'base_name': ([c_type, c_int], c_ccharp), 'is_subtype': ([c_type, c_type], c_int), 'base_offset': ([c_type, c_type, c_object, c_int], c_ptrdiff_t), # method/function reflection information 'num_methods': ([c_scope], c_int), 'method_index_at': ([c_scope, c_int], c_index), 'method_indices_from_name': ([c_scope, c_ccharp], c_index_array), 'method_name': ([c_scope, c_index], c_ccharp), 'method_result_type': ([c_scope, c_index], c_ccharp), 'method_num_args': ([c_scope, c_index], c_int), 'method_req_args': ([c_scope, c_index], c_int), 'method_arg_type': ([c_scope, c_index, c_int], c_ccharp), 'method_arg_default': ([c_scope, c_index, c_int], c_ccharp), 'method_signature': ([c_scope, c_index], c_ccharp), 'method_is_template': ([c_scope, c_index], c_int), 'method_num_template_args': ([c_scope, c_index], c_int), 'method_template_arg_name': ([c_scope, c_index, c_index], c_ccharp), 'get_method': ([c_scope, c_index], c_method), 'get_global_operator': ([c_scope, c_scope, c_scope, c_ccharp], c_index), # method properties 'is_constructor': ([c_type, c_index], c_int), 'is_staticmethod': ([c_type, c_index], c_int), # data member reflection information 'num_datamembers': ([c_scope], c_int), 'datamember_name': ([c_scope, c_int], c_ccharp), 'datamember_type': ([c_scope, c_int], c_ccharp), 'datamember_offset': ([c_scope, c_int], c_ptrdiff_t), 'datamember_index': ([c_scope, c_ccharp], c_int), # data member properties 'is_publicdata': ([c_scope, c_int], c_int), 'is_staticdata': ([c_scope, c_int], c_int), # misc helpers 'strtoll': ([c_ccharp], c_llong), 'strtoull': ([c_ccharp], c_ullong), 'free': ([c_voidp], c_void), 'charp2stdstring': ([c_ccharp], c_object), 'stdstring2stdstring': ([c_object], c_object), } # size/offset are backend-specific but fixed after load self.c_sizeof_farg = 0 self.c_offset_farg = 0
def address(self): w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype) return W_CData(self.space, self.ptr, w_ctypeptr)
def address(self): w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype) return W_CData(self.space, self.fetch_global_var_addr(), w_ctypeptr)