def parse_string_to_type(self, string, consider_fn_as_fnptr): # This cannot be made @elidable because it calls general space # functions (indirectly, e.g. via the new_xxx_type() functions). # The get_string_to_type() function above is elidable, and we # hope that in almost all cases, get_string_to_type() has already # found an answer. try: x = self.types_dict[string] except KeyError: info = self.ctxobj.info index = parse_c_type.parse_c_type(info, string) if index < 0: raise self._ffi_bad_type(string) x = realize_c_type.realize_c_type_or_func( self, self.ctxobj.info.c_output, index) assert x is not None if isinstance(x, realize_c_type.W_RawFuncType): x.unwrap_as_fnptr(self) # force it here self.types_dict[string] = x # if isinstance(x, W_CType): return x else: assert isinstance(x, realize_c_type.W_RawFuncType) if consider_fn_as_fnptr: return x.unwrap_as_fnptr_in_elidable() else: raise x.unexpected_fn_type(self)
def parse_string_to_type(self, string, consider_fn_as_fnptr): # This cannot be made @elidable because it calls general space # functions (indirectly, e.g. via the new_xxx_type() functions). # The get_string_to_type() function above is elidable, and we # hope that in almost all cases, get_string_to_type() has already # found an answer. try: x = self.types_dict[string] except KeyError: info = self.ctxobj.info index = parse_c_type.parse_c_type(info, string) if index < 0: num_spaces = rffi.getintfield(info, 'c_error_location') raise oefmt(self.w_FFIError, "%s\n%s\n%s^", rffi.charp2str(info.c_error_message), string, " " * num_spaces) x = realize_c_type.realize_c_type_or_func( self, self.ctxobj.info.c_output, index) assert x is not None if isinstance(x, realize_c_type.W_RawFuncType): x.unwrap_as_fnptr(self) # force it here self.types_dict[string] = x # if isinstance(x, W_CType): return x else: assert isinstance(x, realize_c_type.W_RawFuncType) if consider_fn_as_fnptr: return x.unwrap_as_fnptr_in_elidable() else: raise x.unexpected_fn_type(self)
def _build_cpython_func(self, g, fnname): # Build a function: in the PyPy version, these are all equivalent # and 'g->address' is a pointer to a function of exactly the # C type specified --- almost: arguments that are structs or # unions are replaced with pointers, and a return value that # would be struct or union is instead handled by passing # inside the function a hidden first pointer argument. rawfunctype = realize_c_type.realize_c_type_or_func( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) assert isinstance(rawfunctype, realize_c_type.W_RawFuncType) # w_ct, locs = rawfunctype.unwrap_as_nostruct_fnptr(self.ffi) # ptr = rffi.cast(rffi.CCHARP, g.c_address) assert ptr return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, w_ct, locs, rawfunctype, fnname)
def _build_cpython_func(self, g, fnname): # Build a function: in the PyPy version, these are all equivalent # and 'g->address' is a pointer to a function of exactly the # C type specified --- almost: arguments that are structs or # unions are replaced with pointers, and a return value that # would be struct or union is instead handled by passing # inside the function a hidden first pointer argument. rawfunctype = realize_c_type.realize_c_type_or_func( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) assert isinstance(rawfunctype, realize_c_type.W_RawFuncType) # rawfunctype.prepare_nostruct_fnptr(self.ffi) # ptr = rffi.cast(rffi.CCHARP, g.c_address) assert ptr return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, rawfunctype, fnname, self.libname)
def _build_attr(self, attr): index = parse_c_type.search_in_globals(self.ctx, attr) if index < 0: for ffi1, lib1 in self.ffi.included_ffis_libs: if lib1 is not None: try: w_result = lib1._get_attr_elidable(attr) break # found, break out of this loop except KeyError: w_result = lib1._build_attr(attr) if w_result is not None: break # found, break out of this loop else: w_result = ffi1.fetch_int_constant(attr) if w_result is not None: break # found, break out of this loop else: return None # not found at all else: space = self.space g = self.ctx.c_globals[index] op = getop(g.c_type_op) if (op == cffi_opcode.OP_CPYTHON_BLTN_V or op == cffi_opcode.OP_CPYTHON_BLTN_N or op == cffi_opcode.OP_CPYTHON_BLTN_O): # A function w_result = self._build_cpython_func(g, attr) # elif op == cffi_opcode.OP_GLOBAL_VAR: # A global variable of the exact type specified here w_ct = realize_c_type.realize_c_type(self.ffi, self.ctx.c_types, getarg(g.c_type_op)) g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn) if g_size != w_ct.size and g_size != 0 and w_ct.size > 0: raise oefmt( self.ffi.w_FFIError, "global variable '%s' should be %d bytes " "according to the cdef, but is actually %d", attr, w_ct.size, g_size) ptr = rffi.cast(rffi.CCHARP, g.c_address) if not ptr: # for dlopen() style ptr = self.cdlopen_fetch(attr) w_result = cglob.W_GlobSupport(space, w_ct, ptr) # elif (op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM): # A constant integer whose value, in an "unsigned long long", # is obtained by calling the function at g->address w_result = realize_c_type.realize_global_int( self.ffi, g, index) # elif (op == cffi_opcode.OP_CONSTANT or op == cffi_opcode.OP_DLOPEN_CONST): # A constant which is not of integer type w_ct = realize_c_type.realize_c_type(self.ffi, self.ctx.c_types, getarg(g.c_type_op)) fetch_funcptr = rffi.cast(realize_c_type.FUNCPTR_FETCH_CHARP, g.c_address) if w_ct.size <= 0: raise oefmt(space.w_SystemError, "constant has no known size") if not fetch_funcptr: # for dlopen() style assert op == cffi_opcode.OP_DLOPEN_CONST ptr = self.cdlopen_fetch(attr) else: assert op == cffi_opcode.OP_CONSTANT ptr = lltype.malloc(rffi.CCHARP.TO, w_ct.size, flavor='raw') self.ffi._finalizer.free_mems.append(ptr) fetch_funcptr(ptr) w_result = w_ct.convert_to_object(ptr) # elif op == cffi_opcode.OP_DLOPEN_FUNC: # For dlopen(): the function of the given 'name'. We use # dlsym() to get the address of something in the dynamic # library, which we interpret as being exactly a function of # the specified type. ptr = self.cdlopen_fetch(attr) w_ct = realize_c_type.realize_c_type_or_func( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) # must have returned a function type: assert isinstance(w_ct, realize_c_type.W_RawFuncType) w_ctfnptr = w_ct.unwrap_as_fnptr(self.ffi) w_result = W_CData(self.space, ptr, w_ctfnptr) # else: raise oefmt(space.w_NotImplementedError, "in lib_build_attr: op=%d", op) assert w_result is not None self.dict_w[attr] = w_result return w_result
def _build_attr(self, attr): index = parse_c_type.search_in_globals(self.ctx, attr) if index < 0: for ffi1, lib1 in self.ffi.included_ffis_libs: if lib1 is not None: try: w_result = lib1._get_attr_elidable(attr) break # found, break out of this loop except KeyError: w_result = lib1._build_attr(attr) if w_result is not None: break # found, break out of this loop else: w_result = ffi1.fetch_int_constant(attr) if w_result is not None: break # found, break out of this loop else: return None # not found at all else: space = self.space g = self.ctx.c_globals[index] op = getop(g.c_type_op) if (op == cffi_opcode.OP_CPYTHON_BLTN_V or op == cffi_opcode.OP_CPYTHON_BLTN_N or op == cffi_opcode.OP_CPYTHON_BLTN_O): # A function w_result = self._build_cpython_func(g, attr) # elif op == cffi_opcode.OP_GLOBAL_VAR: # A global variable of the exact type specified here # (nowadays, only used by the ABI mode or backend # compatibility; see OP_GLOBAL_F for the API mode w_ct = realize_c_type.realize_c_type( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn) if g_size != w_ct.size and g_size != 0 and w_ct.size > 0: raise oefmt(self.ffi.w_FFIError, "global variable '%s' should be %d bytes " "according to the cdef, but is actually %d", attr, w_ct.size, g_size) ptr = rffi.cast(rffi.CCHARP, g.c_address) if not ptr: # for dlopen() style ptr = self.cdlopen_fetch(attr) w_result = cglob.W_GlobSupport(space, attr, w_ct, ptr=ptr) # elif op == cffi_opcode.OP_GLOBAL_VAR_F: w_ct = realize_c_type.realize_c_type( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) w_result = cglob.W_GlobSupport(space, attr, w_ct, fetch_addr=g.c_address) # elif (op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM): # A constant integer whose value, in an "unsigned long long", # is obtained by calling the function at g->address w_result = realize_c_type.realize_global_int(self.ffi, g, index) # elif (op == cffi_opcode.OP_CONSTANT or op == cffi_opcode.OP_DLOPEN_CONST): # A constant which is not of integer type w_ct = realize_c_type.realize_c_type( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) fetch_funcptr = rffi.cast( realize_c_type.FUNCPTR_FETCH_CHARP, g.c_address) if w_ct.size <= 0: raise oefmt(self.ffi.w_FFIError, "constant '%s' is of type '%s', " "whose size is not known", attr, w_ct.name) raise oefmt(space.w_SystemError, "constant has no known size") if not fetch_funcptr: # for dlopen() style assert op == cffi_opcode.OP_DLOPEN_CONST ptr = self.cdlopen_fetch(attr) else: assert op == cffi_opcode.OP_CONSTANT ptr = lltype.malloc(rffi.CCHARP.TO, w_ct.size, flavor='raw') self.ffi._finalizer.free_mems.append(ptr) fetch_funcptr(ptr) w_result = w_ct.convert_to_object(ptr) # elif op == cffi_opcode.OP_DLOPEN_FUNC: # For dlopen(): the function of the given 'name'. We use # dlsym() to get the address of something in the dynamic # library, which we interpret as being exactly a function of # the specified type. ptr = self.cdlopen_fetch(attr) w_ct = realize_c_type.realize_c_type_or_func( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) # must have returned a function type: assert isinstance(w_ct, realize_c_type.W_RawFuncType) w_ctfnptr = w_ct.unwrap_as_fnptr(self.ffi) w_result = W_CData(self.space, ptr, w_ctfnptr) # # elif op == cffi_opcode.OP_EXTERN_PYTHON: # for reading 'lib.bar' where bar is declared # as an extern "Python" w_ct = realize_c_type.realize_c_type( self.ffi, self.ctx.c_types, getarg(g.c_type_op)) ptr = lltype.direct_fieldptr(g, 'c_size_or_direct_fn') w_result = w_ct.convert_to_object(rffi.cast(rffi.CCHARP, ptr)) else: raise oefmt(space.w_NotImplementedError, "in lib_build_attr: op=%d", op) assert w_result is not None self.dict_w[attr] = w_result return w_result