Author: Amaury Forgeot d'Arc <amaur...@gmail.com> Branch: Changeset: r47643:2017ff82bfd2 Date: 2011-09-21 00:19 +0200 http://bitbucket.org/pypy/pypy/changeset/2017ff82bfd2/
Log: Support PyHeapTypeObject in cpyext; Most pypy types now use this structure as well. diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -57,6 +57,9 @@ compile_extra=['-DPy_BUILD_CORE'], ) +class CConfig2: + _compilation_info_ = CConfig._compilation_info_ + class CConfig_constants: _compilation_info_ = CConfig._compilation_info_ @@ -300,9 +303,13 @@ return unwrapper_raise # used in 'normal' RPython code. return decorate -def cpython_struct(name, fields, forward=None): +def cpython_struct(name, fields, forward=None, level=1): configname = name.replace(' ', '__') - setattr(CConfig, configname, rffi_platform.Struct(name, fields)) + if level == 1: + config = CConfig + else: + config = CConfig2 + setattr(config, configname, rffi_platform.Struct(name, fields)) if forward is None: forward = lltype.ForwardReference() TYPES[configname] = forward @@ -445,9 +452,10 @@ # 'int*': rffi.INTP} def configure_types(): - for name, TYPE in rffi_platform.configure(CConfig).iteritems(): - if name in TYPES: - TYPES[name].become(TYPE) + for config in (CConfig, CConfig2): + for name, TYPE in rffi_platform.configure(config).iteritems(): + if name in TYPES: + TYPES[name].become(TYPE) def build_type_checkers(type_name, cls=None): """ diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h --- a/pypy/module/cpyext/include/object.h +++ b/pypy/module/cpyext/include/object.h @@ -321,6 +321,15 @@ } PyTypeObject; +typedef struct { + PyTypeObject ht_type; + PyNumberMethods as_number; + PyMappingMethods as_mapping; + PySequenceMethods as_sequence; + PyBufferProcs as_buffer; + PyObject *ht_name, *ht_slots; +} PyHeapTypeObject; + /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -19,13 +19,42 @@ basestruct = PyObject.TO def get_dealloc(self, space): - raise NotImplementedError + from pypy.module.cpyext.typeobject import subtype_dealloc + return llhelper( + subtype_dealloc.api_func.functype, + subtype_dealloc.api_func.get_wrapper(space)) + def allocate(self, space, w_type, itemcount=0): - raise NotImplementedError + # similar to PyType_GenericAlloc? + # except that it's not related to any pypy object. + + pytype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type)) + # Don't increase refcount for non-heaptypes + if pytype: + flags = rffi.cast(lltype.Signed, pytype.c_tp_flags) + if not flags & Py_TPFLAGS_HEAPTYPE: + Py_DecRef(space, w_type) + + if pytype: + size = pytype.c_tp_basicsize + else: + size = rffi.sizeof(self.basestruct) + if itemcount: + size += itemcount * pytype.c_tp_itemsize + buf = lltype.malloc(rffi.VOIDP.TO, size, + flavor='raw', zero=True) + pyobj = rffi.cast(PyObject, buf) + pyobj.c_ob_refcnt = 1 + pyobj.c_ob_type = pytype + return pyobj + def attach(self, space, pyobj, w_obj): - raise NotImplementedError + pass + def realize(self, space, ref): - raise NotImplementedError + # For most types, a reference cannot exist without + # a real interpreter object + raise InvalidPointerException(str(ref)) typedescr_cache = {} @@ -40,6 +69,7 @@ """ tp_basestruct = kw.pop('basestruct', PyObject.TO) + tp_alloc = kw.pop('alloc', None) tp_attach = kw.pop('attach', None) tp_realize = kw.pop('realize', None) tp_dealloc = kw.pop('dealloc', None) @@ -49,58 +79,24 @@ class CpyTypedescr(BaseCpyTypedescr): basestruct = tp_basestruct - realize = tp_realize - def get_dealloc(self, space): - if tp_dealloc: + if tp_alloc: + def allocate(self, space, w_type, itemcount=0): + return tp_alloc(space, w_type) + + if tp_dealloc: + def get_dealloc(self, space): return llhelper( tp_dealloc.api_func.functype, tp_dealloc.api_func.get_wrapper(space)) - else: - from pypy.module.cpyext.typeobject import subtype_dealloc - return llhelper( - subtype_dealloc.api_func.functype, - subtype_dealloc.api_func.get_wrapper(space)) - - def allocate(self, space, w_type, itemcount=0): - # similar to PyType_GenericAlloc? - # except that it's not related to any pypy object. - - pytype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_type)) - # Don't increase refcount for non-heaptypes - if pytype: - flags = rffi.cast(lltype.Signed, pytype.c_tp_flags) - if not flags & Py_TPFLAGS_HEAPTYPE: - Py_DecRef(space, w_type) - - if pytype: - size = pytype.c_tp_basicsize - else: - size = rffi.sizeof(tp_basestruct) - if itemcount: - size += itemcount * pytype.c_tp_itemsize - buf = lltype.malloc(rffi.VOIDP.TO, size, - flavor='raw', zero=True) - pyobj = rffi.cast(PyObject, buf) - pyobj.c_ob_refcnt = 1 - pyobj.c_ob_type = pytype - return pyobj if tp_attach: def attach(self, space, pyobj, w_obj): tp_attach(space, pyobj, w_obj) - else: - def attach(self, space, pyobj, w_obj): - pass if tp_realize: def realize(self, space, ref): return tp_realize(space, ref) - else: - def realize(self, space, ref): - # For most types, a reference cannot exist without - # a real interpreter object - raise InvalidPointerException(str(ref)) if typedef: CpyTypedescr.__name__ = "CpyTypedescr_%s" % (typedef.name,) diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py --- a/pypy/module/cpyext/test/test_typeobject.py +++ b/pypy/module/cpyext/test/test_typeobject.py @@ -268,6 +268,21 @@ assert type(obj) is foo.Custom assert type(foo.Custom) is foo.MetaType + def test_heaptype(self): + module = self.import_extension('foo', [ + ("name_by_heaptype", "METH_O", + ''' + PyHeapTypeObject *heaptype = (PyHeapTypeObject *)args; + Py_INCREF(heaptype->ht_name); + return heaptype->ht_name; + ''' + ) + ]) + class C(object): + pass + assert module.name_by_heaptype(C) == "C" + + class TestTypes(BaseApiTest): def test_type_attributes(self, space, api): w_class = space.appexec([], """(): diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -11,7 +11,7 @@ generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL, Py_TPFLAGS_HAVE_GETCHARBUFFER, - build_type_checkers) + build_type_checkers, PyObjectFields) from pypy.module.cpyext.pyobject import ( PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr, track_reference, RefcountState, borrow_from) @@ -25,7 +25,7 @@ from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne from pypy.module.cpyext.typeobjectdefs import ( PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc, - PyNumberMethods, PySequenceMethods, PyBufferProcs) + PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs) from pypy.module.cpyext.slotdefs import ( slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function) from pypy.interpreter.error import OperationError @@ -39,6 +39,19 @@ PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type") +PyHeapTypeObjectStruct = lltype.ForwardReference() +PyHeapTypeObject = lltype.Ptr(PyHeapTypeObjectStruct) +PyHeapTypeObjectFields = ( + ("ht_type", PyTypeObject), + ("ht_name", PyObject), + ("as_number", PyNumberMethods), + ("as_mapping", PyMappingMethods), + ("as_sequence", PySequenceMethods), + ("as_buffer", PyBufferProcs), + ) +cpython_struct("PyHeapTypeObject", PyHeapTypeObjectFields, PyHeapTypeObjectStruct, + level=2) + class W_GetSetPropertyEx(GetSetProperty): def __init__(self, getset, w_type): self.getset = getset @@ -136,6 +149,8 @@ assert len(slot_names) == 2 struct = getattr(pto, slot_names[0]) if not struct: + assert not space.config.translating + assert not pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE if slot_names[0] == 'c_tp_as_number': STRUCT_TYPE = PyNumberMethods elif slot_names[0] == 'c_tp_as_sequence': @@ -301,6 +316,7 @@ make_typedescr(space.w_type.instancetypedef, basestruct=PyTypeObject, + alloc=type_alloc, attach=type_attach, realize=type_realize, dealloc=type_dealloc) @@ -319,11 +335,13 @@ track_reference(space, lltype.nullptr(PyObject.TO), space.w_type) track_reference(space, lltype.nullptr(PyObject.TO), space.w_object) track_reference(space, lltype.nullptr(PyObject.TO), space.w_tuple) + track_reference(space, lltype.nullptr(PyObject.TO), space.w_str) # create the objects py_type = create_ref(space, space.w_type) py_object = create_ref(space, space.w_object) py_tuple = create_ref(space, space.w_tuple) + py_str = create_ref(space, space.w_str) # form cycles pto_type = rffi.cast(PyTypeObjectPtr, py_type) @@ -340,10 +358,15 @@ pto_object.c_tp_bases.c_ob_type = pto_tuple pto_tuple.c_tp_bases.c_ob_type = pto_tuple + for typ in (py_type, py_object, py_tuple, py_str): + heaptype = rffi.cast(PyHeapTypeObject, typ) + heaptype.c_ht_name.c_ob_type = pto_type + # Restore the mapping track_reference(space, py_type, space.w_type, replace=True) track_reference(space, py_object, space.w_object, replace=True) track_reference(space, py_tuple, space.w_tuple, replace=True) + track_reference(space, py_str, space.w_str, replace=True) @cpython_api([PyObject], lltype.Void, external=False) @@ -416,17 +439,34 @@ Py_DecRef(space, obj_pto.c_tp_cache) # let's do it like cpython Py_DecRef(space, obj_pto.c_tp_dict) if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE: - if obj_pto.c_tp_as_buffer: - lltype.free(obj_pto.c_tp_as_buffer, flavor='raw') - if obj_pto.c_tp_as_number: - lltype.free(obj_pto.c_tp_as_number, flavor='raw') - if obj_pto.c_tp_as_sequence: - lltype.free(obj_pto.c_tp_as_sequence, flavor='raw') + heaptype = rffi.cast(PyHeapTypeObject, obj) + Py_DecRef(space, heaptype.c_ht_name) Py_DecRef(space, base_pyo) - rffi.free_charp(obj_pto.c_tp_name) PyObject_dealloc(space, obj) +def type_alloc(space, w_metatype): + size = rffi.sizeof(PyHeapTypeObject) + metatype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_metatype)) + # Don't increase refcount for non-heaptypes + if metatype: + flags = rffi.cast(lltype.Signed, metatype.c_tp_flags) + if not flags & Py_TPFLAGS_HEAPTYPE: + Py_DecRef(space, w_metatype) + + heaptype = lltype.malloc(PyHeapTypeObject.TO, + flavor='raw', zero=True) + pto = heaptype.c_ht_type + pto.c_ob_refcnt = 1 + pto.c_ob_type = metatype + pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE + pto.c_tp_as_number = heaptype.c_as_number + pto.c_tp_as_sequence = heaptype.c_as_sequence + pto.c_tp_as_mapping = heaptype.c_as_mapping + pto.c_tp_as_buffer = heaptype.c_as_buffer + + return rffi.cast(PyObject, heaptype) + def type_attach(space, py_obj, w_type): """ Fills a newly allocated PyTypeObject from an existing type. @@ -445,12 +485,18 @@ if space.is_w(w_type, space.w_str): setup_string_buffer_procs(space, pto) - pto.c_tp_flags |= Py_TPFLAGS_HEAPTYPE pto.c_tp_free = llhelper(PyObject_Del.api_func.functype, PyObject_Del.api_func.get_wrapper(space)) pto.c_tp_alloc = llhelper(PyType_GenericAlloc.api_func.functype, PyType_GenericAlloc.api_func.get_wrapper(space)) - pto.c_tp_name = rffi.str2charp(w_type.getname(space)) + if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE: + 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.stringobject import PyString_AsString + pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) + else: + pto.c_tp_name = rffi.str2charp(w_type.getname(space)) pto.c_tp_basicsize = -1 # hopefully this makes malloc bail out pto.c_tp_itemsize = 0 # uninitialized fields: _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit