[pypy-svn] r73307 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include test

xoraxax at codespeak.net xoraxax at codespeak.net
Fri Apr 2 21:15:04 CEST 2010


Author: xoraxax
Date: Fri Apr  2 21:14:47 2010
New Revision: 73307

Added:
   pypy/branch/cpython-extension/pypy/module/cpyext/include/unicodeobject.h   (contents, props changed)
Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/api.py
   pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
   pypy/branch/cpython-extension/pypy/module/cpyext/object.py
   pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Reworked complete object model, added PyUnicodeType to globals, extended foo.c to contain a subtype of the unicode type, began to implement slot functions. The new object model requires a word on every W_Root object but I fear that is not avoidable.

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py	Fri Apr  2 21:14:47 2010
@@ -49,7 +49,7 @@
 constant_names = """
 Py_TPFLAGS_READY Py_TPFLAGS_READYING
 METH_COEXIST METH_STATIC METH_CLASS METH_NOARGS
-Py_TPFLAGS_HEAPTYPE
+Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
 """.split()
 for name in constant_names:
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
@@ -238,6 +238,7 @@
         "Dict": "space.w_dict",
         "Tuple": "space.w_tuple",
         "List": "space.w_list",
+        "Unicode": "space.w_unicode",
         }.items():
     GLOBALS['Py%s_Type#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h	Fri Apr  2 21:14:47 2010
@@ -63,6 +63,7 @@
 #include "tupleobject.h"
 #include "dictobject.h"
 #include "intobject.h"
+#include "unicodeobject.h"
 #include "eval.h"
 
 // XXX This shouldn't be included here

Added: pypy/branch/cpython-extension/pypy/module/cpyext/include/unicodeobject.h
==============================================================================
--- (empty file)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/unicodeobject.h	Fri Apr  2 21:14:47 2010
@@ -0,0 +1,3 @@
+typedef struct {
+    PyObject_HEAD
+} PyUnicodeObject;

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/object.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/object.py	Fri Apr  2 21:14:47 2010
@@ -3,22 +3,16 @@
 from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
 from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef
 from pypy.module.cpyext.state import State
-from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject,\
-        W_PyCObjectDual
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject
 from pypy.objspace.std.objectobject import W_ObjectObject
+from pypy.objspace.std.typeobject import W_TypeObject
 import pypy.module.__builtin__.operation as operation
 
 @cpython_api([PyObject], PyObject)
 def _PyObject_New(space, w_type):
     if isinstance(w_type, W_PyCTypeObject):
-        w_pycobj = space.allocate_instance(W_PyCObject, w_type)
-        w_pycobj.__init__(space)
-        w_pycobjd = space.allocate_instance(W_PyCObjectDual, w_type)
-        w_pycobjd.__init__(space)
-        w_pycobjd.set_pycobject(w_pycobj)
-        w_pycobj.set_dual(w_pycobjd)
-        Py_IncRef(space, w_pycobj)
-        return w_pycobj
+        w_obj = space.allocate_instance(W_ObjectObject, w_type)
+        return w_obj
     assert False, "Please add more cases in get_cls_for_type_object!"
 
 @cpython_api([rffi.VOIDP_real], lltype.Void)

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/pyobject.py	Fri Apr  2 21:14:47 2010
@@ -2,7 +2,8 @@
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, PyObject, PyStringObject, ADDR
+from pypy.module.cpyext.api import cpython_api, PyObject, PyStringObject, ADDR,\
+        Py_TPFLAGS_HEAPTYPE
 from pypy.module.cpyext.state import State
 from pypy.objspace.std.stringobject import W_StringObject
 from pypy.rlib.objectmodel import we_are_translated
@@ -30,32 +31,40 @@
 
 def make_ref(space, w_obj, borrowed=False, steal=False):
     from pypy.module.cpyext.typeobject import allocate_type_obj,\
-            W_PyCTypeObject, W_PyCObject, W_PyCObjectDual
+            W_PyCTypeObject, PyOLifeline
+    from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr
     if w_obj is None:
         return lltype.nullptr(PyObject.TO)
     assert isinstance(w_obj, W_Root)
     state = space.fromcache(State)
-    if isinstance(w_obj, W_PyCObject):
-        w_obj = w_obj.w_dual
     py_obj = state.py_objects_w2r.get(w_obj, lltype.nullptr(PyObject.TO))
     if not py_obj:
+        assert not steal
         w_type = space.type(w_obj)
-        if space.is_w(w_type, space.w_type):
+        if space.is_w(w_type, space.w_type) or space.is_w(w_type,
+                space.gettypeobject(W_PyCTypeObject.typedef)):
             pto = allocate_type_obj(space, w_obj)
             py_obj = rffi.cast(PyObject, pto)
             # c_ob_type and c_ob_refcnt are set by allocate_type_obj
-        elif isinstance(w_obj, W_PyCObject):
-            w_type = space.type(w_obj)
-            assert isinstance(w_type, W_PyCTypeObject)
-            pto = w_type.pto
-            # Don't increase refcount for non-heaptypes
-            # Py_IncRef(space, pto)
-            basicsize = pto.c_tp_basicsize
-            py_obj_pad = lltype.malloc(rffi.VOIDP.TO, basicsize,
-                    flavor="raw", zero=True)
-            py_obj = rffi.cast(PyObject, py_obj_pad)
-            py_obj.c_ob_refcnt = 1
-            py_obj.c_ob_type = rffi.cast(PyObject, pto)
+        elif isinstance(w_type, W_PyCTypeObject):
+            lifeline = w_obj.get_pyolifeline()
+            if lifeline is not None: # make old PyObject ready for use in C code
+                py_obj = lifeline.pyo
+                assert py_obj.c_ob_refcnt == 0
+                Py_IncRef(space, py_obj)
+            else:
+                w_type_pyo = make_ref(space, w_type)
+                pto = rffi.cast(PyTypeObjectPtr, w_type_pyo)
+                # Don't increase refcount for non-heaptypes
+                if not rffi.cast(lltype.Signed, pto.c_tp_flags) & Py_TPFLAGS_HEAPTYPE:
+                    Py_DecRef(space, pto)
+                basicsize = pto.c_tp_basicsize
+                py_obj_pad = lltype.malloc(rffi.VOIDP.TO, basicsize,
+                        flavor="raw", zero=True)
+                py_obj = rffi.cast(PyObject, py_obj_pad)
+                py_obj.c_ob_refcnt = 1
+                py_obj.c_ob_type = rffi.cast(PyObject, pto)
+                w_obj.set_pyolifeline(PyOLifeline(space, py_obj))
         elif isinstance(w_obj, W_StringObject):
             py_obj_str = lltype.malloc(PyStringObject.TO, flavor='raw', zero=True)
             py_obj_str.c_size = len(space.str_w(w_obj))
@@ -99,7 +108,6 @@
 
 
 def from_ref(space, ref):
-    from pypy.module.cpyext.typeobject import W_PyCObjectDual, W_PyCObject
     assert lltype.typeOf(ref) == PyObject
     if not ref:
         return None
@@ -107,19 +115,6 @@
     ptr = rffi.cast(ADDR, ref)
     try:
         w_obj = state.py_objects_r2w[ptr]
-        if isinstance(w_obj, W_PyCObjectDual):
-            w_obj_wr = w_obj.w_pycobject
-            w_obj_or_None = w_obj_wr()
-            if w_obj_or_None is None:
-                # resurrect new PyCObject
-                Py_IncRef(space, ref)
-                w_obj_new = space.allocate_instance(W_PyCObject, space.type(w_obj))
-                w_obj_new.__init__(space)
-                w_obj_new.set_dual(w_obj)
-                w_obj.set_pycobject(w_obj_new)
-                w_obj = w_obj_new
-            else:
-                w_obj = w_obj_or_None
     except KeyError:
         ref_type = ref.c_ob_type
         if ref != ref_type and space.is_w(from_ref(space, ref_type), space.w_str):
@@ -138,7 +133,7 @@
     if not obj:
         return
 
-    from pypy.module.cpyext.typeobject import string_dealloc
+    from pypy.module.cpyext.typeobject import string_dealloc, W_PyCTypeObject
     obj.c_ob_refcnt -= 1
     if DEBUG_REFCOUNT:
         debug_refcount("DECREF", obj, obj.c_ob_refcnt, frame_stackdepth=3)
@@ -153,9 +148,12 @@
         else:
             w_obj = state.py_objects_r2w[ptr]
             del state.py_objects_r2w[ptr]
-            _Py_Dealloc(space, obj)
+            w_type = space.type(w_obj)
+            w_typetype = space.type(w_type)
+            if not space.is_w(w_typetype, space.gettypeobject(W_PyCTypeObject.typedef)):
+                _Py_Dealloc(space, obj)
             del state.py_objects_w2r[w_obj]
-        if ptr in state.borrow_mapping:
+        if ptr in state.borrow_mapping: # move to lifeline __del__
             for containee in state.borrow_mapping[ptr]:
                 w_containee = state.py_objects_r2w.get(containee, None)
                 if w_containee is not None:
@@ -188,7 +186,7 @@
     from pypy.module.cpyext.api import generic_cpy_call_dont_decref
     pto = obj.c_ob_type
     pto = rffi.cast(PyTypeObjectPtr, pto)
-    #print >>sys.stderr, "Calling dealloc slot of", obj, \
+    #print >>sys.stderr, "Calling dealloc slot", pto.c_tp_dealloc, "of", obj, \
     #      "'s type which is", rffi.charp2str(pto.c_tp_name)
     generic_cpy_call_dont_decref(space, pto.c_tp_dealloc, obj)
 

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/slotdefs.py	Fri Apr  2 21:14:47 2010
@@ -4,7 +4,8 @@
 from pypy.module.cpyext.api import generic_cpy_call, cpython_api, \
         PyObject
 from pypy.module.cpyext.typeobjectdefs import unaryfunc, wrapperfunc,\
-        ternaryfunc
+        ternaryfunc, PyTypeObjectPtr
+from pypy.module.cpyext.pyobject import from_ref
 from pypy.module.cpyext.state import State
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rlib.unroll import unrolling_iterable
@@ -32,12 +33,25 @@
     func_target = rffi.cast(ternaryfunc, func)
     return generic_cpy_call(space, func_target, w_self, w_args, w_kwds)
 
+ at cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=True)
+def slot_tp_new(space, type, w_args, w_kwds):
+    from pypy.module.cpyext.tupleobject import PyTuple_Check
+    pyo = rffi.cast(PyObject, type)
+    w_type = from_ref(space, pyo)
+    w_func = space.getattr(w_type, space.wrap("__new__"))
+    assert PyTuple_Check(space, w_args)
+    args_w = space.listview(w_args)[:]
+    args_w.insert(0, w_type)
+    w_args_new = space.newtuple(args_w)
+    return space.call(w_func, w_args_new, w_kwds)
+
 
 PyWrapperFlag_KEYWORDS = 1
 
 # adopted from typeobject.c
 def FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS):
     wrapper = globals().get(WRAPPER, None)
+    function = globals().get(FUNCTION, None)
     slotname = ("c_" + SLOT).split(".")
     assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
     if FLAGS:
@@ -46,7 +60,7 @@
     else:
         wrapper1 = wrapper
         wrapper2 = None
-    return (NAME, slotname, FUNCTION, wrapper1, wrapper2, DOC)
+    return (NAME, slotname, function, wrapper1, wrapper2, DOC)
 
 def TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
     return FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, 0)

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/foo.c	Fri Apr  2 21:14:47 2010
@@ -136,6 +136,81 @@
         foo_getseters,            /*tp_getset*/
 };
 
+typedef struct {
+    PyUnicodeObject HEAD;
+} FuuObject;
+
+static PyObject *
+Fuu_escape(PyTypeObject* type, PyObject *args)
+{
+    Py_RETURN_TRUE;
+}
+
+
+static PyMethodDef Fuu_methods[] = {
+    {"escape", (PyCFunction) Fuu_escape, METH_VARARGS, NULL},
+    {NULL}  /* Sentinel */
+};
+
+PyTypeObject FuuType = {
+    PyObject_HEAD_INIT(NULL)
+    0,
+    "foo.fuu",
+    sizeof(FuuObject),
+    0,
+    0,          /*tp_dealloc*/
+    0,          /*tp_print*/
+    0,          /*tp_getattr*/
+    0,          /*tp_setattr*/
+    0,          /*tp_compare*/
+    0,          /*tp_repr*/
+    0,          /*tp_as_number*/
+    0,          /*tp_as_sequence*/
+    0,          /*tp_as_mapping*/
+    0,          /*tp_hash */
+
+    0,          /*tp_call*/
+    0,          /*tp_str*/
+    0,          /*tp_getattro*/
+    0,          /*tp_setattro*/
+    0,          /*tp_as_buffer*/
+
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    0,          /*tp_doc*/
+
+    0,          /*tp_traverse*/
+    0,          /*tp_clear*/
+
+    0,          /*tp_richcompare*/
+    0,          /*tp_weaklistoffset*/
+
+    0,          /*tp_iter*/
+    0,          /*tp_iternext*/
+
+    /* Attribute descriptor and subclassing stuff */
+
+    Fuu_methods,/*tp_methods*/
+    0,          /*tp_members*/
+    0,          /*tp_getset*/
+    0,          /*tp_base*/
+    0,          /*tp_dict*/
+
+    0,          /*tp_descr_get*/
+    0,          /*tp_descr_set*/
+    0,          /*tp_dictoffset*/
+
+    0,          /*tp_init*/
+    0,          /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
+    0,          /*tp_new*/
+    0,          /*tp_free  Low-level free-memory routine */
+    0,          /*tp_is_gc For PyObject_IS_GC */
+    0,          /*tp_bases*/
+    0,          /*tp_mro method resolution order */
+    0,          /*tp_cache*/
+    0,          /*tp_subclasses*/
+    0           /*tp_weaklist*/
+};
+
 
 /* foo functions */
 
@@ -167,13 +242,23 @@
 	PyObject *m, *d;
 
     Py_TYPE(&footype) = &PyType_Type;
+
+    /* Workaround for quirk in Visual Studio, see
+        <http://www.python.it/faq/faq-3.html#3.24> */
+    FuuType.tp_base = &PyUnicode_Type;
+
     if (PyType_Ready(&footype) < 0)
         return;
+    if (PyType_Ready(&FuuType) < 0)
+        return;
 	m = Py_InitModule("foo", foo_functions);
 	if (m == NULL)
 	    return;
 	d = PyModule_GetDict(m);
-	if (d)
-	    PyDict_SetItemString(d, "fooType", (PyObject *)&footype);
+	if (d) {
+	    if (PyDict_SetItemString(d, "fooType", (PyObject *)&footype) < 0)
+            return;
+        PyDict_SetItemString(d, "FuuType", (PyObject *) &FuuType);
+    }
    	/* No need to check the error here, the caller will do that */
 }

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	Fri Apr  2 21:14:47 2010
@@ -157,6 +157,22 @@
             if delta != 0:
                 leaking = True
                 print >>sys.stderr, "Leaking %r: %i references" % (w_obj, delta)
+                lifeline = w_obj.get_pyolifeline()
+                if lifeline is not None:
+                    refcnt = lifeline.pyo.c_ob_refcnt
+                    if refcnt > 0:
+                        print >>sys.stderr, "\tThe object also held by C code."
+                    else:
+                        referrers_repr = []
+                        for o in gc.get_referrers(w_obj):
+                            try:
+                                repr_str = repr(o)
+                            except TypeError, e:
+                                repr_str = "%s (type of o is %s)" % (str(e), type(o))
+                            referrers_repr.append(repr_str)
+                        referrers = ", ".join(referrers_repr)
+                        print >>sys.stderr, "\tThe object is referenced by these objects:", \
+                                referrers
         for w_obj in lost_objects_w:
             print >>sys.stderr, "Lost object %r" % (w_obj, )
             leaking = True

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_typeobject.py	Fri Apr  2 21:14:47 2010
@@ -36,3 +36,12 @@
         raises(TypeError, "obj.int_member_readonly = 42")
         raises(SystemError, "obj.broken_member")
         raises(SystemError, "obj.broken_member = 42")
+        a = module.fooType
+        assert "cannot create" in raises(TypeError, "a()").value.message
+        skip("In Progress")
+        class bar(module.fooType):
+            pass
+        fuu = module.FuuType
+        fuu_inst = fuu(u"abc")
+        assert "cannot create" in raises(TypeError, "bar()").value.message
+

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	Fri Apr  2 21:14:47 2010
@@ -3,27 +3,31 @@
 from weakref import ref
 
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.tool.pairtype import extendabletype
 from pypy.rpython.annlowlevel import llhelper
-from pypy.interpreter.gateway import ObjSpace, W_Root
+from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.objspace.std.typeobject import W_TypeObject, _CPYTYPE
+from pypy.objspace.std.typeobject import W_TypeObject, _CPYTYPE, call__Type
+from pypy.objspace.std.typetype import _precheck_for_new
 from pypy.objspace.std.objectobject import W_ObjectObject
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.module.cpyext.api import cpython_api, cpython_api_c, cpython_struct, \
     PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, generic_cpy_call, \
-    Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, PyStringObject, ADDR
+    Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, PyStringObject, ADDR, \
+    Py_TPFLAGS_HAVE_CLASS
 from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
 from pypy.interpreter.module import Module
 from pypy.module.cpyext import structmemberdefs
 from pypy.module.cpyext.modsupport import  convert_method_defs
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.methodobject import PyDescr_NewWrapper
-from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef
+from pypy.module.cpyext.pyobject import Py_IncRef, Py_DecRef, _Py_Dealloc
 from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
 from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr, PyTypeObject, \
         PyGetSetDef, PyMemberDef
 from pypy.module.cpyext.slotdefs import slotdefs
+from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rlib.rstring import rsplit
 
 
@@ -35,11 +39,11 @@
         if doc:
             doc = rffi.charp2str(getset.c_doc)
         if getset.c_get:
-            get = W_PyCObject.getter
+            get = GettersAndSetters.getter.im_func
         if getset.c_set:
-            set = W_PyCObject.setter
+            set = GettersAndSetters.setter.im_func
         GetSetProperty.__init__(self, get, set, None, doc,
-                                cls=W_PyCObject, use_closure=True,
+                                cls=None, use_closure=True, # XXX cls?
                                 tag="cpyext_1")
 
 def PyDescr_NewGetSet(space, getset, pto):
@@ -53,11 +57,11 @@
         doc = set = None
         if doc:
             doc = rffi.charp2str(getset.c_doc)
-        get = W_PyCObject.member_getter
+        get = GettersAndSetters.member_getter.im_func
         if not (flags & structmemberdefs.READONLY):
-            set = W_PyCObject.member_setter
+            set = GettersAndSetters.member_setter.im_func
         GetSetProperty.__init__(self, get, set, None, doc,
-                                cls=W_PyCObject, use_closure=True,
+                                cls=None, use_closure=True, # XXX cls?
                                 tag="cpyext_2")
 
 def convert_getset_defs(space, dict_w, getsets, pto):
@@ -88,13 +92,38 @@
             dict_w[name] = w_descr
             i += 1
 
+def update_all_slots(space, w_obj, pto):
+    #  XXX fill slots in pto
+    state = space.fromcache(State)
+    for method_name, slot_name, slot_func, _, _, doc in slotdefs:
+        w_descr = space.lookup(w_obj, method_name)
+        if w_descr is None:
+            # XXX special case iternext
+            continue
+        if slot_func is None:
+            os.write(2, method_name + " defined by the type but no slot function defined!\n")
+            continue
+        if method_name == "__new__" and "bar" in repr(w_obj):
+            import pdb; pdb.set_trace()
+        slot_func_helper = llhelper(slot_func.api_func.functype,
+                slot_func.api_func.get_wrapper(space))
+        # XXX special case wrapper-functions and use a "specific" slot func,
+        # XXX special case tp_new
+        if len(slot_name) == 1:
+            setattr(pto, slot_name[0], slot_func_helper)
+        else:
+            assert len(slot_name) == 2
+            struct = getattr(pto, slot_name[0])
+            if not struct:
+                continue
+            setattr(struct, slot_name[1], slot_func_helper)
+
 def add_operators(space, dict_w, pto):
     # XXX support PyObject_HashNotImplemented
     state = space.fromcache(State)
     for method_name, slot_name, _, wrapper_func, wrapper_func_kwds, doc in slotdefs:
         if method_name in dict_w:
             continue
-        # XXX is this rpython?
         if len(slot_name) == 1:
             func = getattr(pto, slot_name[0])
         else:
@@ -107,16 +136,26 @@
         if not func:
             continue
         if wrapper_func is None and wrapper_func_kwds is None:
-            os.write(2, method_name + " used by the type but no wrapper function defined!")
+            os.write(2, method_name + " used by the type but no wrapper function defined!\n")
             continue
         dict_w[method_name] = PyDescr_NewWrapper(space, pto, method_name, wrapper_func,
                 wrapper_func_kwds, doc, func_voidp)
 
+def inherit_special(space, pto, base_pto):
+    # XXX copy basicsize and flags in a magical way
+    flags = rffi.cast(lltype.Signed, pto.c_tp_flags)
+    if flags & Py_TPFLAGS_HAVE_CLASS:
+        base_object_pyo = make_ref(space, space.w_object, steal=True)
+        base_object_pto = rffi.cast(PyTypeObjectPtr, base_object_pyo)
+        if base_pto != base_object_pto or \
+                flags & Py_TPFLAGS_HEAPTYPE:
+            if not pto.c_tp_new:
+                pto.c_tp_new = base_pto.c_tp_new
+
 
 class W_PyCTypeObject(W_TypeObject):
     def __init__(self, space, pto):
-        self.pto = pto
-        bases_w = []
+        bases_w = [] # XXX fill
         dict_w = {}
 
         add_operators(space, dict_w, pto)
@@ -132,16 +171,28 @@
             bases_w or [space.w_object], dict_w)
         self.__flags__ = _CPYTYPE # mainly disables lookup optimizations
 
-class W_PyCObject(Wrappable):
-    def __init__(self, space):
+class __extend__(W_Root):
+    __metaclass__ = extendabletype
+    __slots__ = ("_pyolifeline", )
+    _pyolifeline = None
+    def set_pyolifeline(self, lifeline):
+        self._pyolifeline = lifeline
+    def get_pyolifeline(self):
+        return self._pyolifeline
+
+class PyOLifeline(object):
+    def __init__(self, space, pyo):
+        self.pyo = pyo
         self.space = space
 
-    def set_dual(self, w_obj):
-        self.w_dual = w_obj
-
     def __del__(self):
-        Py_DecRef(self.space, self)
+        if self.pyo:
+            assert self.pyo.c_ob_refcnt == 0
+            _Py_Dealloc(self.space, self.pyo)
+            self.pyo = lltype.nullptr(PyObject.TO)
+        # XXX handle borrowed objects here
 
+class GettersAndSetters:
     def getter(self, space, w_self):
         return generic_cpy_call(
             space, self.getset.c_get, w_self,
@@ -158,15 +209,44 @@
     def member_setter(self, space, w_self, w_value):
         PyMember_SetOne(space, w_self, self.member, w_value)
 
-class W_PyCObjectDual(W_PyCObject):
-    def __init__(self, space):
-        self.space = space
+def c_type_descr__call__(space, w_type, __args__):
+    if isinstance(w_type, W_PyCTypeObject):
+        pyo = make_ref(space, w_type)
+        pto = rffi.cast(PyTypeObjectPtr, pyo)
+        tp_new = pto.c_tp_new
+        try:
+            if tp_new:
+                args_w, kw_w = __args__.unpack()
+                w_args = space.newtuple(args_w)
+                w_kw = space.newdict()
+                for key, w_obj in kw_w.items():
+                    space.setitem(w_kw, space.wrap(key), w_obj)
+                return generic_cpy_call(space, tp_new, pto, w_args, w_kw)
+            else:
+                raise operationerrfmt(space.w_TypeError,
+                    "cannot create '%s' instances", w_type.getname(space, '?'))
+        finally:
+            Py_DecRef(space, pyo)
+    else:
+        return call__Type(space, w_type, __args__)
 
-    def set_pycobject(self, w_pycobject):
-        self.w_pycobject = ref(w_pycobject)
+def c_type_descr__new__(space, w_typetype, w_name, w_bases, w_dict):
+    # copied from typetype.descr__new__, XXX missing logic: metaclass resolving
+    w_typetype = _precheck_for_new(space, w_typetype)
+
+    bases_w = space.fixedview(w_bases)
+    name = space.str_w(w_name)
+    dict_w = {}
+    dictkeys_w = space.listview(w_dict)
+    for w_key in dictkeys_w:
+        key = space.str_w(w_key)
+        dict_w[key] = space.getitem(w_dict, w_key)
+    w_type = space.allocate_instance(W_PyCTypeObject, w_typetype)
+    W_TypeObject.__init__(w_type, space, name, bases_w or [space.w_object],
+                          dict_w)
+    w_type.ready()
+    return w_type
 
-    def __del__(self): # ok, subclassing isnt so sensible here
-        pass
 
 @cpython_api([PyObject], lltype.Void, external=False)
 def subtype_dealloc(space, obj):
@@ -202,12 +282,14 @@
 def type_dealloc(space, obj):
     state = space.fromcache(State)
     obj_pto = rffi.cast(PyTypeObjectPtr, obj)
+    if not obj_pto.c_tp_name or "C_type" == rffi.charp2str(obj_pto.c_tp_name):
+        import pdb; pdb.set_trace()
     type_pto = rffi.cast(PyTypeObjectPtr, obj.c_ob_type)
     base_pyo = rffi.cast(PyObject, obj_pto.c_tp_base)
-    Py_DecRef(space, base_pyo)
     Py_DecRef(space, obj_pto.c_tp_bases)
     Py_DecRef(space, obj_pto.c_tp_cache) # lets do it like cpython
     if obj_pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
+        Py_DecRef(space, base_pyo)
         lltype.free(obj_pto.c_tp_name, flavor="raw")
         obj_pto_voidp = rffi.cast(rffi.VOIDP_real, obj_pto)
         generic_cpy_call(space, type_pto.c_tp_free, obj_pto_voidp)
@@ -219,7 +301,6 @@
     """ Allocates a pto from a w_type which must be a PyPy type. """
     state = space.fromcache(State)
     from pypy.module.cpyext.object import PyObject_dealloc, PyObject_Del
-    assert not isinstance(w_type, W_PyCTypeObject)
     assert isinstance(w_type, W_TypeObject)
 
     pto = lltype.malloc(PyTypeObject, flavor="raw", zero=True)
@@ -264,9 +345,16 @@
         PyPyType_Ready(space, pto, w_type)
     else:
         pto.c_ob_type = lltype.nullptr(PyObject.TO)
+    if space.is_w(w_type, space.w_object):
+        pto.c_tp_basicsize = rffi.sizeof(PyObject.TO)
+    elif space.is_w(w_type, space.w_type):
+        pto.c_tp_basicsize = rffi.sizeof(PyTypeObject)
+    elif space.is_w(w_type, space.w_str):
+        pto.c_tp_basicsize = rffi.sizeof(PyStringObject.TO)
+    elif pto.c_tp_base:
+        pto.c_tp_basicsize = pto.c_tp_base.c_tp_basicsize
 
-    #  XXX fill slots in pto
-    #  would look like fixup_slot_dispatchers()
+    update_all_slots(space, w_type, pto)
     return pto
 
 @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
@@ -283,7 +371,7 @@
         base = pto.c_tp_base
         if not base and not (w_obj is not None and
             space.is_w(w_obj, space.w_object)):
-            base_pyo = make_ref(space, space.w_object)
+            base_pyo = make_ref(space, space.w_object, steal=True)
             base = pto.c_tp_base = rffi.cast(PyTypeObjectPtr, base_pyo)
         else:
             base_pyo = rffi.cast(PyObject, base)
@@ -301,7 +389,9 @@
         if w_obj is None:
             PyPyType_Register(space, pto)
         # missing:
-        # inherit_special, inherit_slots, setting __doc__ if not defined and tp_doc defined
+        if base:
+            inherit_special(space, pto, base)
+        # inherit_slots, setting __doc__ if not defined and tp_doc defined
         # inheriting tp_as_* slots
         # unsupported:
         # tp_mro, tp_subclasses
@@ -324,8 +414,8 @@
         w_obj.ready()
     return 1
 
-W_PyCObject.typedef = W_ObjectObject.typedef
-
 W_PyCTypeObject.typedef = TypeDef(
-    'C_type', W_TypeObject.typedef
+    'C_type', W_TypeObject.typedef,
+    __call__ = interp2app(c_type_descr__call__, unwrap_spec=[ObjSpace, W_Root, Arguments]),
+    __new__ = interp2app(c_type_descr__new__),
     )



More information about the Pypy-commit mailing list