def dir1(self, ignore_global_vars=False): space = self.space total = rffi.getintfield(self.ctx, 'c_num_globals') g = self.ctx.c_globals names_w = [] for i in range(total): if ignore_global_vars: op = getop(g[i].c_type_op) if (op == cffi_opcode.OP_GLOBAL_VAR or op == cffi_opcode.OP_GLOBAL_VAR_F): continue names_w.append(space.wrap(rffi.charp2str(g[i].c_name))) return space.newlist(names_w)
def dir1(self, ignore_global_vars=False): space = self.space total = rffi.getintfield(self.ctx, 'c_num_globals') g = self.ctx.c_globals names_w = [] for i in range(total): if ignore_global_vars: op = getop(g[i].c_type_op) if (op == cffi_opcode.OP_GLOBAL_VAR or op == cffi_opcode.OP_GLOBAL_VAR_F): continue names_w.append(space.newtext(rffi.charp2str(g[i].c_name))) return space.newlist(names_w)
def fetch_int_constant(self, name): index = parse_c_type.search_in_globals(self.ctxobj.ctx, name) if index >= 0: g = self.ctxobj.ctx.c_globals[index] op = realize_c_type.getop(g.c_type_op) if (op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM): return realize_c_type.realize_global_int(self, g, index) raise oefmt(self.w_FFIError, "function, global variable or non-integer constant " "'%s' must be fetched from its original 'lib' " "object", name) for ffi1, _ in self.included_ffis_libs: w_result = ffi1.fetch_int_constant(name) if w_result is not None: return w_result return None
def externpy_deco(space, w_ffi, w_python_callable, w_name, w_error, w_onerror): from pypy.module._cffi_backend.ffi_obj import W_FFIObject from pypy.module._cffi_backend.ccallback import W_ExternPython ffi = space.interp_w(W_FFIObject, w_ffi) if space.is_w(w_name, space.w_None): w_name = space.getattr(w_python_callable, space.wrap('__name__')) name = space.str_w(w_name) ctx = ffi.ctxobj.ctx index = parse_c_type.search_in_globals(ctx, name) if index < 0: raise externpy_not_found(ffi, name) g = ctx.c_globals[index] if getop(g.c_type_op) != cffi_opcode.OP_EXTERN_PYTHON: raise externpy_not_found(ffi, name) w_ct = realize_c_type.realize_c_type(ffi, ctx.c_types, getarg(g.c_type_op)) # make a W_ExternPython instance, which is nonmovable; then cast it # to a raw pointer and assign it to the field 'reserved1' of the # externpy object from C. We must make sure to keep it alive forever, # or at least until ffi.def_extern() is used again to change the # binding. Note that the W_ExternPython is never exposed to the user. externpy = rffi.cast(parse_c_type.PEXTERNPY, g.c_address) externpython = instantiate(W_ExternPython, nonmovable=True) cdata = rffi.cast(rffi.CCHARP, externpy) W_ExternPython.__init__(externpython, space, cdata, w_ct, w_python_callable, w_error, w_onerror) key = rffi.cast(lltype.Signed, externpy) space.fromcache(KeepaliveCache).cache_dict[key] = externpython externpy.c_reserved1 = externpython.hide_object() # return the function object unmodified return w_python_callable
def externpy_deco(space, w_ffi, w_python_callable, w_name, w_error, w_onerror): from pypy.module._cffi_backend.ffi_obj import W_FFIObject from pypy.module._cffi_backend.ccallback import W_ExternPython ffi = space.interp_w(W_FFIObject, w_ffi) if space.is_w(w_name, space.w_None): w_name = space.getattr(w_python_callable, space.wrap("__name__")) name = space.str_w(w_name) ctx = ffi.ctxobj.ctx index = parse_c_type.search_in_globals(ctx, name) if index < 0: raise externpy_not_found(ffi, name) g = ctx.c_globals[index] if getop(g.c_type_op) != cffi_opcode.OP_EXTERN_PYTHON: raise externpy_not_found(ffi, name) w_ct = realize_c_type.realize_c_type(ffi, ctx.c_types, getarg(g.c_type_op)) # make a W_ExternPython instance, which is nonmovable; then cast it # to a raw pointer and assign it to the field 'reserved1' of the # externpy object from C. We must make sure to keep it alive forever, # or at least until ffi.def_extern() is used again to change the # binding. Note that the W_ExternPython is never exposed to the user. externpy = rffi.cast(parse_c_type.PEXTERNPY, g.c_address) externpython = instantiate(W_ExternPython, nonmovable=True) cdata = rffi.cast(rffi.CCHARP, externpy) W_ExternPython.__init__(externpython, space, cdata, w_ct, w_python_callable, w_error, w_onerror) key = rffi.cast(lltype.Signed, externpy) space.fromcache(KeepaliveCache).cache_dict[key] = externpython externpy.c_reserved1 = externpython.hide_object() # return the function object unmodified return w_python_callable
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 ffiobj_init(ffi, module_name, version, types, w_globals, w_struct_unions, w_enums, w_typenames, w_includes): space = ffi.space # xxx force ll2ctypes conversion here. This appears to be needed, # otherwise ll2ctypes explodes. I don't want to know :-( rffi.cast(lltype.Signed, ffi.ctxobj) if version == -1 and not types: return if not (cffi1_module.VERSION_MIN <= version <= cffi1_module.VERSION_MAX): raise oefmt(space.w_ImportError, "cffi out-of-line Python module '%s' has unknown version %s", module_name, hex(version)) if types: # unpack a string of 4-byte entries into an array of _cffi_opcode_t n = len(types) // 4 ntypes = allocate_array(ffi, _CFFI_OPCODE_T, n) decoder = StringDecoder(ffi, types) for i in range(n): ntypes[i] = decoder.next_opcode() ffi.ctxobj.ctx.c_types = ntypes rffi.setintfield(ffi.ctxobj.ctx, 'c_num_types', n) ffi.cached_types = [None] * n if w_globals is not None: # unpack a tuple alternating strings and ints, each two together # describing one global_s entry with no specified address or size. # The int is only used with integer constants. globals_w = space.fixedview(w_globals) n = len(globals_w) // 2 size = n * rffi.sizeof(GLOBAL_S) + n * rffi.sizeof(CDL_INTCONST_S) p = allocate(ffi, size) nglobs = rffi.cast(rffi.CArrayPtr(GLOBAL_S), p) p = rffi.ptradd(p, llmemory.raw_malloc_usage(n * rffi.sizeof(GLOBAL_S))) nintconsts = rffi.cast(rffi.CArrayPtr(CDL_INTCONST_S), p) for i in range(n): decoder = StringDecoder(ffi, space.str_w(globals_w[i * 2])) nglobs[i].c_type_op = decoder.next_opcode() nglobs[i].c_name = decoder.next_name() op = getop(nglobs[i].c_type_op) if op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM: w_integer = globals_w[i * 2 + 1] ll_set_cdl_realize_global_int(nglobs[i]) bigint = space.bigint_w(w_integer) ullvalue = bigint.ulonglongmask() rffi.setintfield(nintconsts[i], 'neg', int(bigint.sign <= 0)) rffi.setintfield(nintconsts[i], 'value', ullvalue) ffi.ctxobj.ctx.c_globals = nglobs rffi.setintfield(ffi.ctxobj.ctx, 'c_num_globals', n) if w_struct_unions is not None: # unpack a tuple of struct/unions, each described as a sub-tuple; # the item 0 of each sub-tuple describes the struct/union, and # the items 1..N-1 describe the fields, if any struct_unions_w = space.fixedview(w_struct_unions) n = len(struct_unions_w) nftot = 0 # total number of fields for i in range(n): nftot += space.len_w(struct_unions_w[i]) - 1 nstructs = allocate_array(ffi, STRUCT_UNION_S, n) nfields = allocate_array(ffi, FIELD_S, nftot) nf = 0 for i in range(n): # 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) desc = space.fixedview(struct_unions_w[i]) nf1 = len(desc) - 1 decoder = StringDecoder(ffi, space.str_w(desc[0])) rffi.setintfield(nstructs[i], 'c_type_index', decoder.next_4bytes()) flags = decoder.next_4bytes() rffi.setintfield(nstructs[i], 'c_flags', flags) nstructs[i].c_name = decoder.next_name() if flags & (cffi_opcode.F_OPAQUE | cffi_opcode.F_EXTERNAL): rffi.setintfield(nstructs[i], 'c_size', -1) rffi.setintfield(nstructs[i], 'c_alignment', -1) rffi.setintfield(nstructs[i], 'c_first_field_index', -1) rffi.setintfield(nstructs[i], 'c_num_fields', 0) assert nf1 == 0 else: rffi.setintfield(nstructs[i], 'c_size', -2) rffi.setintfield(nstructs[i], 'c_alignment', -2) rffi.setintfield(nstructs[i], 'c_first_field_index', nf) rffi.setintfield(nstructs[i], 'c_num_fields', nf1) for j in range(nf1): decoder = StringDecoder(ffi, space.str_w(desc[j + 1])) # this 'decoder' is for one of the other strings beyond # the first one, describing one field each type_op = decoder.next_opcode() nfields[nf].c_field_type_op = type_op rffi.setintfield(nfields[nf], 'c_field_offset', -1) if getop(type_op) != cffi_opcode.OP_NOOP: field_size = decoder.next_4bytes() else: field_size = -1 rffi.setintfield(nfields[nf], 'c_field_size', field_size) nfields[nf].c_name = decoder.next_name() nf += 1 assert nf == nftot ffi.ctxobj.ctx.c_struct_unions = nstructs ffi.ctxobj.ctx.c_fields = nfields rffi.setintfield(ffi.ctxobj.ctx, 'c_num_struct_unions', n) if w_enums: # unpack a tuple of strings, each of which describes one enum_s entry enums_w = space.fixedview(w_enums) n = len(enums_w) nenums = allocate_array(ffi, ENUM_S, n) for i in range(n): decoder = StringDecoder(ffi, space.str_w(enums_w[i])) rffi.setintfield(nenums[i], 'c_type_index', decoder.next_4bytes()) rffi.setintfield(nenums[i], 'c_type_prim', decoder.next_4bytes()) nenums[i].c_name = decoder.next_name() nenums[i].c_enumerators = decoder.next_name() ffi.ctxobj.ctx.c_enums = nenums rffi.setintfield(ffi.ctxobj.ctx, 'c_num_enums', n) if w_typenames: # unpack a tuple of strings, each of which describes one typename_s # entry typenames_w = space.fixedview(w_typenames) n = len(typenames_w) ntypenames = allocate_array(ffi, TYPENAME_S, n) for i in range(n): decoder = StringDecoder(ffi, space.str_w(typenames_w[i])) rffi.setintfield(ntypenames[i],'c_type_index',decoder.next_4bytes()) ntypenames[i].c_name = decoder.next_name() ffi.ctxobj.ctx.c_typenames = ntypenames rffi.setintfield(ffi.ctxobj.ctx, 'c_num_typenames', n) if w_includes: from pypy.module._cffi_backend.ffi_obj import W_FFIObject # for w_parent_ffi in space.fixedview(w_includes): parent_ffi = space.interp_w(W_FFIObject, w_parent_ffi) ffi.included_ffis_libs.append((parent_ffi, None))
def ffiobj_init(ffi, module_name, version, types, w_globals, w_struct_unions, w_enums, w_typenames, w_includes): space = ffi.space # xxx force ll2ctypes conversion here. This appears to be needed, # otherwise ll2ctypes explodes. I don't want to know :-( rffi.cast(lltype.Signed, ffi.ctxobj) if version == -1 and not types: return if not (cffi1_module.VERSION_MIN <= version <= cffi1_module.VERSION_MAX): raise oefmt( space.w_ImportError, "cffi out-of-line Python module '%s' has unknown version %s", module_name, hex(version)) if types: # unpack a string of 4-byte entries into an array of _cffi_opcode_t n = len(types) // 4 ntypes = allocate_array(ffi, _CFFI_OPCODE_T, n) decoder = StringDecoder(ffi, types) for i in range(n): ntypes[i] = decoder.next_opcode() ffi.ctxobj.ctx.c_types = ntypes rffi.setintfield(ffi.ctxobj.ctx, 'c_num_types', n) ffi.cached_types = [None] * n if w_globals is not None: # unpack a tuple alternating strings and ints, each two together # describing one global_s entry with no specified address or size. # The int is only used with integer constants. globals_w = space.fixedview(w_globals) n = len(globals_w) // 2 size = n * rffi.sizeof(GLOBAL_S) + n * rffi.sizeof(CDL_INTCONST_S) p = allocate(ffi, size) nglobs = rffi.cast(rffi.CArrayPtr(GLOBAL_S), p) p = rffi.ptradd(p, llmemory.raw_malloc_usage(n * rffi.sizeof(GLOBAL_S))) nintconsts = rffi.cast(rffi.CArrayPtr(CDL_INTCONST_S), p) for i in range(n): decoder = StringDecoder(ffi, space.bytes_w(globals_w[i * 2])) nglobs[i].c_type_op = decoder.next_opcode() nglobs[i].c_name = decoder.next_name() op = getop(nglobs[i].c_type_op) if op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM: w_integer = globals_w[i * 2 + 1] ll_set_cdl_realize_global_int(nglobs[i]) bigint = space.bigint_w(w_integer) ullvalue = bigint.ulonglongmask() rffi.setintfield(nintconsts[i], 'neg', int(bigint.sign <= 0)) rffi.setintfield(nintconsts[i], 'value', ullvalue) ffi.ctxobj.ctx.c_globals = nglobs rffi.setintfield(ffi.ctxobj.ctx, 'c_num_globals', n) if w_struct_unions is not None: # unpack a tuple of struct/unions, each described as a sub-tuple; # the item 0 of each sub-tuple describes the struct/union, and # the items 1..N-1 describe the fields, if any struct_unions_w = space.fixedview(w_struct_unions) n = len(struct_unions_w) nftot = 0 # total number of fields for i in range(n): nftot += space.len_w(struct_unions_w[i]) - 1 nstructs = allocate_array(ffi, STRUCT_UNION_S, n) nfields = allocate_array(ffi, FIELD_S, nftot) nf = 0 for i in range(n): # 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) desc = space.fixedview(struct_unions_w[i]) nf1 = len(desc) - 1 decoder = StringDecoder(ffi, space.bytes_w(desc[0])) rffi.setintfield(nstructs[i], 'c_type_index', decoder.next_4bytes()) flags = decoder.next_4bytes() rffi.setintfield(nstructs[i], 'c_flags', flags) nstructs[i].c_name = decoder.next_name() if flags & (cffi_opcode.F_OPAQUE | cffi_opcode.F_EXTERNAL): rffi.setintfield(nstructs[i], 'c_size', -1) rffi.setintfield(nstructs[i], 'c_alignment', -1) rffi.setintfield(nstructs[i], 'c_first_field_index', -1) rffi.setintfield(nstructs[i], 'c_num_fields', 0) assert nf1 == 0 else: rffi.setintfield(nstructs[i], 'c_size', -2) rffi.setintfield(nstructs[i], 'c_alignment', -2) rffi.setintfield(nstructs[i], 'c_first_field_index', nf) rffi.setintfield(nstructs[i], 'c_num_fields', nf1) for j in range(nf1): decoder = StringDecoder(ffi, space.bytes_w(desc[j + 1])) # this 'decoder' is for one of the other strings beyond # the first one, describing one field each type_op = decoder.next_opcode() nfields[nf].c_field_type_op = type_op rffi.setintfield(nfields[nf], 'c_field_offset', -1) if getop(type_op) != cffi_opcode.OP_NOOP: field_size = decoder.next_4bytes() else: field_size = -1 rffi.setintfield(nfields[nf], 'c_field_size', field_size) nfields[nf].c_name = decoder.next_name() nf += 1 assert nf == nftot ffi.ctxobj.ctx.c_struct_unions = nstructs ffi.ctxobj.ctx.c_fields = nfields rffi.setintfield(ffi.ctxobj.ctx, 'c_num_struct_unions', n) if w_enums: # unpack a tuple of strings, each of which describes one enum_s entry enums_w = space.fixedview(w_enums) n = len(enums_w) nenums = allocate_array(ffi, ENUM_S, n) for i in range(n): decoder = StringDecoder(ffi, space.bytes_w(enums_w[i])) rffi.setintfield(nenums[i], 'c_type_index', decoder.next_4bytes()) rffi.setintfield(nenums[i], 'c_type_prim', decoder.next_4bytes()) nenums[i].c_name = decoder.next_name() nenums[i].c_enumerators = decoder.next_name() ffi.ctxobj.ctx.c_enums = nenums rffi.setintfield(ffi.ctxobj.ctx, 'c_num_enums', n) if w_typenames: # unpack a tuple of strings, each of which describes one typename_s # entry typenames_w = space.fixedview(w_typenames) n = len(typenames_w) ntypenames = allocate_array(ffi, TYPENAME_S, n) for i in range(n): decoder = StringDecoder(ffi, space.bytes_w(typenames_w[i])) rffi.setintfield(ntypenames[i], 'c_type_index', decoder.next_4bytes()) ntypenames[i].c_name = decoder.next_name() ffi.ctxobj.ctx.c_typenames = ntypenames rffi.setintfield(ffi.ctxobj.ctx, 'c_num_typenames', n) if w_includes: from pypy.module._cffi_backend.ffi_obj import W_FFIObject # for w_parent_ffi in space.fixedview(w_includes): parent_ffi = space.interp_w(W_FFIObject, w_parent_ffi) ffi.included_ffis_libs.append((parent_ffi, None))
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