[pypy-commit] pypy default: Support PyHeapTypeObject in cpyext;
amauryfa
noreply at buildbot.pypy.org
Tue Sep 27 23:14:34 CEST 2011
Author: Amaury Forgeot d'Arc <amauryfa at 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:
More information about the pypy-commit
mailing list