[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