[pypy-svn] r28591 - in pypy/dist/pypy/rpython: . lltypesystem lltypesystem/test

arigo at codespeak.net arigo at codespeak.net
Fri Jun 9 17:05:44 CEST 2006


Author: arigo
Date: Fri Jun  9 17:05:43 2006
New Revision: 28591

Modified:
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
   pypy/dist/pypy/rpython/rcpy.py
Log:
Correctly initialize the instance when the type is called from CPython.


Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Fri Jun  9 17:05:43 2006
@@ -481,7 +481,7 @@
                 raise MissingRTypeAttribute(attr)
             self.rbase.setfield(vinst, attr, vvalue, llops, force_cast=True, opname=opname)
 
-    def new_instance(self, llops, classcallhop=None):
+    def new_instance(self, llops, classcallhop=None, v_cpytype=None):
         """Build a new instance, without calling __init__."""
         mallocop = 'malloc'
         ctype = inputconst(Void, self.object_type)
@@ -492,15 +492,16 @@
                 mallocop = 'flavored_malloc'
                 vlist.insert(0, inputconst(Void, flavor))
                 if flavor == 'cpy':
-                    cache = self.rtyper.classdef_to_pytypeobject
-                    try:
-                        pytype = cache[self.classdef]
-                    except KeyError:
-                        from pypy.rpython import rcpy
-                        pytype = rcpy.build_pytypeobject(self)
-                        cache[self.classdef] = pytype
-                    c = inputconst(Ptr(PyObject), pytype)
-                    vlist.append(c)
+                    if v_cpytype is None:
+                        cache = self.rtyper.classdef_to_pytypeobject
+                        try:
+                            cpytype = cache[self.classdef]
+                        except KeyError:
+                            from pypy.rpython import rcpy
+                            cpytype = rcpy.build_pytypeobject(self)
+                            cache[self.classdef] = cpytype
+                        v_cpytype = inputconst(Ptr(PyObject), cpytype)
+                    vlist.append(v_cpytype)
         vptr = llops.genop(mallocop, vlist,
                            resulttype = Ptr(self.object_type))
         ctypeptr = inputconst(CLASSTYPE, self.rclass.getvtable())

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py	Fri Jun  9 17:05:43 2006
@@ -3,6 +3,7 @@
 
 
 class W_MyTest(object):
+    x = 600
 
     def __init__(self, x):
         self.x = x
@@ -67,7 +68,7 @@
     assert res == 4
 
 
-def test_subclass_from_cpython():
+def test_manipulate_more():
     class mytest(object):
         pass
 
@@ -95,3 +96,62 @@
     assert total == 15
     obj, total = fn(obj, expected_extra_mallocs=4)
     assert total == 21
+
+
+def test_instantiate_from_cpython():
+    class mytest(object):
+        pass
+
+    def f(input):
+        if input:
+            w = cpy_import(W_MyTest, input)
+        else:
+            w = W_MyTest(21)
+        w.x += 1
+        return cpy_export(mytest, w), w.x
+
+    fn = compile(f, [object])
+    obj, x = fn(None, expected_extra_mallocs=1) # 1 W_MyTest
+    assert x == 22
+
+    obj2 = type(obj)()
+    del obj
+    obj, x = fn(obj2, expected_extra_mallocs=1) # 1 W_MyTest (obj2)
+    assert obj is obj2
+    assert x == 601     # 600 is the class default of W_MyTest.x
+
+
+def test_subclass_from_cpython():
+    import py; py.test.skip("not implemented (see comments in rcpy.py)")
+    class mytest(object):
+        pass
+
+    def f(input):
+        current = total = 10
+        if input:
+            w = cpy_import(W_MyTest, input)
+            current, total = w.stuff
+        w = W_MyTest(21)
+        current += 1
+        total += current
+        w.stuff = current, total
+        return cpy_export(mytest, w), total
+
+    fn = compile(f, [object])
+    obj, total = fn(None, expected_extra_mallocs=2) # 1 W_MyTest (with 1 tuple)
+    assert total == 21
+    T = type(obj)
+    class U(T):
+        pass
+    obj2 = U()
+    obj2.bla = 123
+    assert obj2.bla == 123
+    del obj
+
+    objlist = [U() for i in range(100)]
+    obj, total = fn(obj2, expected_extra_mallocs=204) # 102 W_MyTests alive
+    assert total == 1
+
+    del objlist
+    obj, total = fn(obj, expected_extra_mallocs=6) # 3 W_MyTests alive
+    assert total == 3

Modified: pypy/dist/pypy/rpython/rcpy.py
==============================================================================
--- pypy/dist/pypy/rpython/rcpy.py	(original)
+++ pypy/dist/pypy/rpython/rcpy.py	Fri Jun  9 17:05:43 2006
@@ -2,7 +2,8 @@
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rpython.objectmodel import CDefinedIntSymbolic
-from pypy.objspace.flow.model import Constant
+from pypy.objspace.flow.model import Constant, Variable
+from pypy.objspace.flow.model import FunctionGraph, Block, Link
 
 
 def cpy_export(cpytype, obj):
@@ -122,9 +123,6 @@
     hints={'c_name': '_typeobject', 'external': True, 'inline_head': True}))
 # XXX should be PyTypeObject but genc inserts 'struct' :-(
 
-def ll_tp_new(tp, args, kwds):
-    return lltype.malloc(lltype.PyObject, flavor='cpy', extra_args=(tp,))
-
 def ll_tp_dealloc(p):
     addr = llmemory.cast_ptr_to_adr(p)
     # Warning: this relies on an optimization in gctransformer, which will
@@ -134,7 +132,24 @@
     llop.gc_deallocate(lltype.Void, CPYOBJECT, addr)
 
 def build_pytypeobject(r_inst):
+    from pypy.rpython.lltypesystem.rclass import CPYOBJECTPTR
+    from pypy.rpython.rtyper import LowLevelOpList
     typetype = lltype.pyobjectptr(type)
+
+    # make the graph of tp_new manually    
+    v1 = Variable('tp');   v1.concretetype = lltype.Ptr(PY_TYPE_OBJECT)
+    v2 = Variable('args'); v2.concretetype = PyObjPtr
+    v3 = Variable('kwds'); v3.concretetype = PyObjPtr
+    block = Block([v1, v2, v3])
+    llops = LowLevelOpList(None)
+    v4 = r_inst.new_instance(llops, v_cpytype = v1)
+    v5 = llops.genop('cast_pointer', [v4], resulttype = PyObjPtr)
+    block.operations = list(llops)
+    tp_new_graph = FunctionGraph('ll_tp_new', block)
+    block.closeblock(Link([v5], tp_new_graph.returnblock))
+    tp_new_graph.getreturnvar().concretetype = v5.concretetype
+
+    # build the PyTypeObject structure
     pytypeobj = lltype.malloc(PY_TYPE_OBJECT, flavor='cpy',
                               extra_args=(typetype,))
     name = r_inst.classdef._cpy_exported_type_.__name__
@@ -146,10 +161,14 @@
     pytypeobj.c_tp_name = lltype.direct_arrayitems(p)
     pytypeobj.c_tp_basicsize = llmemory.sizeof(r_inst.lowleveltype.TO)
     pytypeobj.c_tp_flags = CDefinedIntSymbolic('Py_TPFLAGS_DEFAULT')
-    pytypeobj.c_tp_new = r_inst.rtyper.annotate_helper_fn(
-        ll_tp_new,
-        [lltype.Ptr(PY_TYPE_OBJECT), PyObjPtr, PyObjPtr])
+    pytypeobj.c_tp_new = r_inst.rtyper.type_system.getcallable(tp_new_graph)
     pytypeobj.c_tp_dealloc = r_inst.rtyper.annotate_helper_fn(
         ll_tp_dealloc,
         [PyObjPtr])
     return lltype.cast_pointer(PyObjPtr, pytypeobj)
+
+# To make this a Py_TPFLAGS_BASETYPE, we need to have a tp_new that does
+# something different for subclasses: it needs to allocate a bit more
+# for CPython's GC (see PyObject_GC_Malloc); it needs to Py_INCREF the
+# type if it's a heap type; and it needs to PyObject_GC_Track() the object.
+# Also, tp_dealloc needs to untrack the object.



More information about the Pypy-commit mailing list