def finish_type_2(space, pto, w_obj): """ Sets up other attributes, when the interpreter type has been created. """ pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w)) base = pto.c_tp_base if base: inherit_special(space, pto, w_obj, base) for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)): if isinstance(w_base, W_TypeObject): inherit_slots(space, pto, w_base) #else: # w_base is a W_ClassObject, ignore it if not pto.c_tp_setattro: from pypy.module.cpyext.object import PyObject_GenericSetAttr pto.c_tp_setattro = llslot(space, PyObject_GenericSetAttr) if not pto.c_tp_getattro: from pypy.module.cpyext.object import PyObject_GenericGetAttr pto.c_tp_getattro = llslot(space, PyObject_GenericGetAttr) if w_obj.is_cpytype(): decref(space, pto.c_tp_dict) w_dict = w_obj.getdict(space) # pass in the w_obj to convert any values that are # unbound GetSetProperty into bound PyGetSetDescrObject pto.c_tp_dict = make_ref(space, w_dict, w_obj)
def setup_buffer_procs(space, w_type, pto): bufspec = w_type.layout.typedef.buffer if bufspec is None and not space.is_w(w_type, space.w_unicode): # not a buffer, but let w_unicode be a read buffer return c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True) lltype.render_immortal(c_buf) c_buf.c_bf_getsegcount = llslot(space, bf_segcount) if space.is_w(w_type, space.w_bytes): # Special case: str doesn't support get_raw_address(), so we have a # custom get*buffer that instead gives the address of the char* in the # PyBytesObject*! c_buf.c_bf_getreadbuffer = llslot(space, str_getreadbuffer) c_buf.c_bf_getcharbuffer = llslot(space, str_getcharbuffer) elif space.is_w(w_type, space.w_unicode): # Special case: unicode doesn't support get_raw_address(), so we have a # custom get*buffer that instead gives the address of the char* in the # PyUnicodeObject*! c_buf.c_bf_getreadbuffer = llslot(space, unicode_getreadbuffer) elif space.is_w(w_type, space.w_buffer): # Special case: we store a permanent address on the cpyext wrapper, # so we'll reuse that. # Note: we could instead store a permanent address on the buffer object, # and use get_raw_address() c_buf.c_bf_getreadbuffer = llslot(space, buf_getreadbuffer) c_buf.c_bf_getcharbuffer = llslot(space, buf_getcharbuffer) else: # use get_raw_address() c_buf.c_bf_getreadbuffer = llslot(space, bf_getreadbuffer) c_buf.c_bf_getcharbuffer = llslot(space, bf_getcharbuffer) if bufspec == 'read-write': c_buf.c_bf_getwritebuffer = llslot(space, bf_getwritebuffer) pto.c_tp_as_buffer = c_buf pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER pto.c_tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER
def setup_buffer_procs(space, w_type, pto): bufspec = w_type.layout.typedef.buffer if bufspec is None and not space.is_w(w_type, space.w_unicode): # not a buffer, but let w_unicode be a read buffer return c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True) lltype.render_immortal(c_buf) c_buf.c_bf_getsegcount = llslot(space, bf_segcount) if space.is_w(w_type, space.w_str): # Special case: str doesn't support get_raw_address(), so we have a # custom get*buffer that instead gives the address of the char* in the # PyBytesObject*! c_buf.c_bf_getreadbuffer = llslot(space, str_getreadbuffer) c_buf.c_bf_getcharbuffer = llslot(space, str_getcharbuffer) elif space.is_w(w_type, space.w_unicode): # Special case: unicode doesn't support get_raw_address(), so we have a # custom get*buffer that instead gives the address of the char* in the # PyUnicodeObject*! c_buf.c_bf_getreadbuffer = llslot(space, unicode_getreadbuffer) elif space.is_w(w_type, space.w_buffer): # Special case: we store a permanent address on the cpyext wrapper, # so we'll reuse that. # Note: we could instead store a permanent address on the buffer object, # and use get_raw_address() c_buf.c_bf_getreadbuffer = llslot(space, buf_getreadbuffer) c_buf.c_bf_getcharbuffer = llslot(space, buf_getcharbuffer) else: # use get_raw_address() c_buf.c_bf_getreadbuffer = llslot(space, bf_getreadbuffer) c_buf.c_bf_getcharbuffer = llslot(space, bf_getcharbuffer) if bufspec == 'read-write': c_buf.c_bf_getwritebuffer = llslot(space, bf_getwritebuffer) pto.c_tp_as_buffer = c_buf pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER pto.c_tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER
def subtype_dealloc(space, obj): pto = obj.c_ob_type base = pto this_func_ptr = llslot(space, subtype_dealloc) w_obj = from_ref(space, rffi.cast(PyObject, base)) # This wrapper is created on a specific type, call it w_A. # We wish to call the dealloc function from one of the base classes of w_A, # the first of which is not this function itself. # w_obj is an instance of w_A or one of its subclasses. So climb up the # inheritance chain until base.c_tp_dealloc is exactly this_func, and then # continue on up until they differ. #print 'subtype_dealloc, start from', rffi.charp2str(base.c_tp_name) while base.c_tp_dealloc != this_func_ptr: base = base.c_tp_base assert base #print ' ne move to', rffi.charp2str(base.c_tp_name) w_obj = from_ref(space, rffi.cast(PyObject, base)) while base.c_tp_dealloc == this_func_ptr: base = base.c_tp_base assert base #print ' eq move to', rffi.charp2str(base.c_tp_name) w_obj = from_ref(space, rffi.cast(PyObject, base)) #print ' end with', rffi.charp2str(base.c_tp_name) dealloc = base.c_tp_dealloc # XXX call tp_del if necessary generic_cpy_call(space, dealloc, obj)
def subtype_dealloc(space, obj): pto = obj.c_ob_type base = pto this_func_ptr = llslot(space, subtype_dealloc) while base.c_tp_dealloc == this_func_ptr: base = base.c_tp_base assert base dealloc = base.c_tp_dealloc # XXX call tp_del if necessary generic_cpy_call(space, dealloc, obj)
def finish_type_2(space, pto, w_obj): """ Sets up other attributes, when the interpreter type has been created. """ pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w)) base = pto.c_tp_base if base: inherit_special(space, pto, base) for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)): inherit_slots(space, pto, w_base) if not pto.c_tp_setattro: from pypy.module.cpyext.object import PyObject_GenericSetAttr pto.c_tp_setattro = llslot(space, PyObject_GenericSetAttr) if not pto.c_tp_getattro: from pypy.module.cpyext.object import PyObject_GenericGetAttr pto.c_tp_getattro = llslot(space, PyObject_GenericGetAttr) if w_obj.is_cpytype(): Py_DecRef(space, pto.c_tp_dict) w_dict = w_obj.getdict(space) pto.c_tp_dict = make_ref(space, w_dict)
def add_operators(space, dict_w, pto): from pypy.module.cpyext.object import PyObject_HashNotImplemented hash_not_impl = llslot(space, PyObject_HashNotImplemented) for method_name, slot_names, wrapper_class, doc in slotdefs_for_wrappers: if method_name in dict_w: continue offset = [rffi.offsetof(lltype.typeOf(pto).TO, slot_names[0])] if len(slot_names) == 1: func = getattr(pto, slot_names[0]) if slot_names[0] == 'c_tp_hash': # two special cases where __hash__ is explicitly set to None # (which leads to an unhashable type): # 1) tp_hash == PyObject_HashNotImplemented # 2) tp_hash == NULL and either of tp_compare or tp_richcompare are not NULL if hash_not_impl == func or (not func and (pto.c_tp_compare or pto.c_tp_richcompare)): dict_w[method_name] = space.w_None continue else: assert len(slot_names) == 2 struct = getattr(pto, slot_names[0]) if not struct: continue offset.append( rffi.offsetof(lltype.typeOf(struct).TO, slot_names[1])) func = getattr(struct, slot_names[1]) func_voidp = rffi.cast(rffi.VOIDP, func) if not func: continue if wrapper_class is None: continue assert issubclass(wrapper_class, W_PyCWrapperObject) w_obj = wrapper_class(space, pto, method_name, doc, func_voidp, offset=offset[:]) dict_w[method_name] = w_obj if pto.c_tp_doc: dict_w['__doc__'] = space.newtext( rffi.charp2str(cts.cast('char*', pto.c_tp_doc))) if pto.c_tp_new: add_tp_new_wrapper(space, dict_w, pto)
def subtype_dealloc(space, obj): pto = obj.c_ob_type base = pto this_func_ptr = llslot(space, subtype_dealloc) # This wrapper is created on a specific type, call it w_A. # We wish to call the dealloc function from one of the base classes of w_A, # the first of which is not this function itself. # w_obj is an instance of w_A or one of its subclasses. So climb up the # inheritance chain until base.c_tp_dealloc is exactly this_func, and then # continue on up until they differ. while base.c_tp_dealloc != this_func_ptr: base = base.c_tp_base assert base while base.c_tp_dealloc == this_func_ptr: base = base.c_tp_base assert base dealloc = base.c_tp_dealloc # XXX call tp_del if necessary generic_cpy_call(space, dealloc, obj)
def is_tp_new_wrapper(space, ml): return ml.c_ml_meth == rffi.cast(PyCFunction, llslot(space, tp_new_wrapper))
def setup_new_method_def(space): ptr = get_new_method_def(space) ptr.c_ml_meth = rffi.cast(PyCFunction, llslot(space, tp_new_wrapper))
def type_attach(space, py_obj, w_type, w_userdata=None): """ Fills a newly allocated PyTypeObject from an existing type. """ from pypy.module.cpyext.object import PyObject_Free assert isinstance(w_type, W_TypeObject) pto = rffi.cast(PyTypeObjectPtr, py_obj) typedescr = get_typedescr(w_type.layout.typedef) if space.is_w(w_type, space.w_bytes): pto.c_tp_itemsize = 1 elif space.is_w(w_type, space.w_tuple): pto.c_tp_itemsize = rffi.sizeof(PyObject) # buffer protocol setup_buffer_procs(space, w_type, pto) pto.c_tp_free = llslot(space, PyObject_Free) pto.c_tp_alloc = llslot(space, PyType_GenericAlloc) builder = space.fromcache(State).builder if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0 and builder.cpyext_type_init is None): # this ^^^ is not None only during startup of cpyext. At that # point we might get into troubles by doing make_ref() when # things are not initialized yet. So in this case, simply use # str2charp() and "leak" the string. w_typename = space.getattr(w_type, space.newtext('__name__')) heaptype = cts.cast('PyHeapTypeObject*', pto) heaptype.c_ht_name = make_ref(space, w_typename) from pypy.module.cpyext.bytesobject import PyString_AsString pto.c_tp_name = cts.cast('const char *', PyString_AsString(space, heaptype.c_ht_name)) else: pto.c_tp_name = cts.cast('const char*', rffi.str2charp(w_type.name)) # uninitialized fields: # c_tp_print # XXX implement # c_tp_compare and more? w_base = best_base(space, w_type.bases_w) pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base)) # dealloc if space.gettypeobject(w_type.layout.typedef) is w_type: # only for the exact type, like 'space.w_tuple' or 'space.w_list' pto.c_tp_dealloc = typedescr.get_dealloc(space) else: # for all subtypes, use base's dealloc (requires sorting in attach_all) pto.c_tp_dealloc = pto.c_tp_base.c_tp_dealloc if not pto.c_tp_dealloc: # strange, but happens (ABCMeta) pto.c_tp_dealloc = llslot(space, subtype_dealloc) if builder.cpyext_type_init is not None: builder.cpyext_type_init.append((pto, w_type)) else: finish_type_1(space, pto, w_type.bases_w) finish_type_2(space, pto, w_type) pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct) if pto.c_tp_base: if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize: pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize: pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize if w_type.is_heaptype(): update_all_slots(space, w_type, pto) else: update_all_slots_builtin(space, w_type, pto) if not pto.c_tp_new: base_object_pyo = make_ref(space, space.w_object) base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo) flags = rffi.cast(lltype.Signed, pto.c_tp_flags) if pto.c_tp_base != base_object_pto or flags & Py_TPFLAGS_HEAPTYPE: pto.c_tp_new = pto.c_tp_base.c_tp_new Py_DecRef(space, base_object_pyo) pto.c_tp_flags |= Py_TPFLAGS_READY return pto
def type_attach(space, py_obj, w_type): """ Fills a newly allocated PyTypeObject from an existing type. """ from pypy.module.cpyext.object import PyObject_Free assert isinstance(w_type, W_TypeObject) pto = rffi.cast(PyTypeObjectPtr, py_obj) typedescr = get_typedescr(w_type.layout.typedef) # dealloc if space.gettypeobject(w_type.layout.typedef) is w_type: # only for the exact type, like 'space.w_tuple' or 'space.w_list' pto.c_tp_dealloc = typedescr.get_dealloc().get_llhelper(space) else: # for all subtypes, use subtype_dealloc() pto.c_tp_dealloc = llslot(space, subtype_dealloc) if space.is_w(w_type, space.w_str): pto.c_tp_itemsize = 1 elif space.is_w(w_type, space.w_tuple): pto.c_tp_itemsize = rffi.sizeof(PyObject) # buffer protocol setup_buffer_procs(space, w_type, pto) pto.c_tp_free = llslot(space, PyObject_Free) pto.c_tp_alloc = llslot(space, PyType_GenericAlloc) builder = space.fromcache(StaticObjectBuilder) if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0 and builder.cpyext_type_init is None): # this ^^^ is not None only during startup of cpyext. At that # point we might get into troubles by doing make_ref() when # things are not initialized yet. So in this case, simply use # str2charp() and "leak" the string. w_typename = space.getattr(w_type, space.wrap('__name__')) heaptype = rffi.cast(PyHeapTypeObject, pto) heaptype.c_ht_name = make_ref(space, w_typename) from pypy.module.cpyext.bytesobject import PyString_AsString pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) else: pto.c_tp_name = rffi.str2charp(w_type.name) # uninitialized fields: # c_tp_print # XXX implement # c_tp_compare and more? w_base = best_base(space, w_type.bases_w) pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base)) if builder.cpyext_type_init is not None: builder.cpyext_type_init.append((pto, w_type)) else: finish_type_1(space, pto) finish_type_2(space, pto, w_type) pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct) if pto.c_tp_base: if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize: pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize: pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize # will be filled later on with the correct value # may not be 0 if space.is_w(w_type, space.w_object): pto.c_tp_new = rffi.cast(newfunc, 1) update_all_slots(space, w_type, pto) pto.c_tp_flags |= Py_TPFLAGS_READY return pto
def setup_new_method_def(space): ptr = get_new_method_def(space) ptr.c_ml_meth = rffi.cast( PyCFunction_typedef, llslot(space, tp_new_wrapper))