[pypy-svn] r28581 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem/test translator/c translator/c/src translator/c/test

arigo at codespeak.net arigo at codespeak.net
Fri Jun 9 13:30:37 CEST 2006


Author: arigo
Date: Fri Jun  9 13:30:35 2006
New Revision: 28581

Modified:
   pypy/dist/pypy/annotation/builtin.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_rcpyclass.py
   pypy/dist/pypy/rpython/rbuiltin.py
   pypy/dist/pypy/rpython/rcpy.py
   pypy/dist/pypy/translator/c/funcgen.py
   pypy/dist/pypy/translator/c/src/mem.h
   pypy/dist/pypy/translator/c/test/test_genc.py
Log:
(arre, arigo)

Added tp_alloc/tp_free and the corresponding support for lltyping
helpers containing 'malloc(PyObject, flavor='cpy', extra_args=(tp,))'.



Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py	(original)
+++ pypy/dist/pypy/annotation/builtin.py	Fri Jun  9 13:30:35 2006
@@ -384,24 +384,31 @@
 from pypy.annotation.model import SomePtr
 from pypy.rpython.lltypesystem import lltype
 
-def malloc(T, n=None, s_flavor=None):
-    assert n is None or (n.knowntype == int or issubclass(n.knowntype, pypy.rpython.rarithmetic.base_int))
-    assert T.is_constant()
-    if n is not None:
+def malloc(s_T, s_n=None, s_flavor=None, s_extra_args=None):
+    assert (s_n is None or s_n.knowntype == int
+            or issubclass(s_n.knowntype, pypy.rpython.rarithmetic.base_int))
+    assert s_T.is_constant()
+    if s_n is not None:
         n = 1
+    else:
+        n = None
     if s_flavor is None:
-        p = lltype.malloc(T.const, n)
+        p = lltype.malloc(s_T.const, n)
+        r = SomePtr(lltype.typeOf(p))
     else:
         assert s_flavor.is_constant()
-        p = lltype.malloc(T.const, n, s_flavor.const)
-    r = SomePtr(lltype.typeOf(p))
+        # not sure how to call malloc() for the example 'p' in the
+        # presence of s_extraargs
+        r = SomePtr(lltype.Ptr(s_T.const))
     return r
 
 def free(s_p, s_flavor):
     assert s_flavor.is_constant()
-    T = s_p.ll_ptrtype.TO
-    p = lltype.malloc(T, flavor=s_flavor.const)
-    lltype.free(p, flavor=s_flavor.const)
+    # same problem as in malloc(): some flavors are not easy to
+    # malloc-by-example
+    #T = s_p.ll_ptrtype.TO
+    #p = lltype.malloc(T, flavor=s_flavor.const)
+    #lltype.free(p, flavor=s_flavor.const)
 
 def typeOf(s_val):
     lltype = annotation_to_lltype(s_val, info="in typeOf(): ")

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 13:30:35 2006
@@ -19,7 +19,7 @@
         w = W_MyTest(21)
         return cpy_export(mytest, w)
 
-    fn = compile(f, [])
+    fn = compile(f, [], expected_extra_mallocs=1)
     res = fn()
     assert type(res).__name__ == 'mytest'
 
@@ -40,3 +40,29 @@
     fn = compile(g, [])
     res = fn()
     assert res == 42
+
+
+def test_tp_dealloc():
+    import py; py.test.skip("in-progress")
+    class mytest(object):
+        pass
+
+    class A(object):
+        pass
+
+    def f():
+        w = W_MyTest(21)
+        w.a = A()
+        w.a.x = 4
+        return cpy_export(mytest, w)
+
+    def g():
+        obj = f()
+        w = cpy_import(W_MyTest, obj)
+        return w.a.x
+
+    fn = compile(g, [], backendopt=False)
+    res = fn()
+    # the A() should have been deallocated too, otherwise the number
+    # of mallocs doesn't match the number of frees
+    assert res == 4

Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/rbuiltin.py	Fri Jun  9 13:30:35 2006
@@ -160,6 +160,23 @@
             return NotImplemented
         return llops.convertvar(v, r_from.self_repr, r_to.self_repr)
 
+def parse_kwds(hop, *argspec_i_r):
+    lst = [i for (i, r) in argspec_i_r if i is not None]
+    lst.sort()
+    if lst != range(hop.nb_args - len(lst), hop.nb_args):
+        raise TyperError("keyword args are expected to be at the end of "
+                         "the 'hop' arg list")
+    result = []
+    for i, r in argspec_i_r:
+        if i is not None:
+            if r is None:
+                r = hop.args_r[i]
+            result.append(hop.inputarg(r, arg=i))
+        else:
+            result.append(None)
+    hop.nb_args -= len(lst)
+    return result
+
 # ____________________________________________________________
 
 def rtype_builtin_bool(hop):
@@ -297,19 +314,28 @@
 BUILTIN_TYPER[object.__init__] = rtype_object__init__
 # annotation of low-level types
 
-def rtype_malloc(hop, i_flavor=None):
+def rtype_malloc(hop, i_flavor=None, i_extra_args=None):
     assert hop.args_s[0].is_constant()
     vlist = [hop.inputarg(lltype.Void, arg=0)]
     opname = 'malloc'
-    positional_args = hop.nb_args
-    if i_flavor is not None:
-        assert i_flavor == hop.nb_args-1
-        positional_args -= 1
-        vlist.insert(0, hop.inputarg(lltype.Void, arg=i_flavor))
+    v_flavor, v_extra_args = parse_kwds(hop, (i_flavor, lltype.Void),
+                                             (i_extra_args, None))
+    if v_flavor is not None:
+        vlist.insert(0, v_flavor)
         opname = 'flavored_' + opname
-    if positional_args == 2:
+    if hop.nb_args == 2:
         vlist.append(hop.inputarg(lltype.Signed, arg=1))
         opname += '_varsize'
+
+    if v_extra_args is not None:
+        # items of the v_extra_args tuple become additional args to the op
+        from pypy.rpython.rtuple import AbstractTupleRepr
+        r_tup = hop.args_r[i_extra_args]
+        assert isinstance(r_tup, AbstractTupleRepr)
+        for n, r in enumerate(r_tup.items_r):
+            v = r_tup.getitem(hop.llops, v_extra_args, n)
+            vlist.append(v)
+
     return hop.genop(opname, vlist, resulttype = hop.r_result.lowleveltype)
 
 def rtype_free(hop, i_flavor):

Modified: pypy/dist/pypy/rpython/rcpy.py
==============================================================================
--- pypy/dist/pypy/rpython/rcpy.py	(original)
+++ pypy/dist/pypy/rpython/rcpy.py	Fri Jun  9 13:30:35 2006
@@ -64,7 +64,8 @@
 
 PyObjPtr = lltype.Ptr(lltype.PyObject)
 
-PY_TYPE_OBJECT = lltype.PyStruct(
+PY_TYPE_OBJECT = lltype.PyForwardReference()
+PY_TYPE_OBJECT.become(lltype.PyStruct(
     'PyTypeObject',
     ('head',           lltype.PyObject),
     ('c_ob_size',      lltype.Signed),
@@ -87,10 +88,41 @@
     ('c_tp_setattro',  lltype.Signed),
     ('c_tp_as_buffer', lltype.Signed),
     ('c_tp_flags',     lltype.Signed),
+    ('c_tp_doc',       lltype.Signed),
+    ('c_tp_traverse',  lltype.Signed),
+    ('c_tp_clear',     lltype.Signed),
+    ('c_tp_richcompare',lltype.Signed),
+    ('c_tp_weaklistoffset',lltype.Signed),
+    ('c_tp_iter',      lltype.Signed),
+    ('c_tp_iternext',  lltype.Signed),
+    ('c_tp_methods',   lltype.Signed),
+    ('c_tp_members',   lltype.Signed),
+    ('c_tp_getset',    lltype.Signed),
+    ('c_tp_base',      lltype.Signed),
+    ('c_tp_dict',      lltype.Signed),
+    ('c_tp_descr_get', lltype.Signed),
+    ('c_tp_descr_set', lltype.Signed),
+    ('c_tp_dictoffset',lltype.Signed),
+    ('c_tp_init',      lltype.Signed),
+    ('c_tp_alloc',     lltype.Ptr(lltype.FuncType([lltype.Ptr(PY_TYPE_OBJECT),
+                                                   lltype.Signed],
+                                                  PyObjPtr))),
+    ('c_tp_new',       lltype.Signed),
+    ('c_tp_free',      lltype.Ptr(lltype.FuncType([llmemory.Address],
+                                                  lltype.Void))),
 
-    hints={'c_name': '_typeobject', 'external': True, 'inline_head': True})
+    hints={'c_name': '_typeobject', 'external': True, 'inline_head': True}))
 # XXX should be PyTypeObject but genc inserts 'struct' :-(
 
+def ll_tp_alloc(tp, itemcount):
+    # XXX pass itemcount too
+    return lltype.malloc(lltype.PyObject, flavor='cpy', extra_args=(tp,))
+
+def ll_tp_free(addr):
+    # hack: don't cast addr to PyObjPtr, otherwise there is an incref/decref
+    # added around the free!
+    lltype.free(addr, flavor='cpy')
+
 def build_pytypeobject(r_inst):
     typetype = lltype.pyobjectptr(type)
     pytypeobj = lltype.malloc(PY_TYPE_OBJECT, flavor='cpy',
@@ -104,4 +136,10 @@
     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_alloc = r_inst.rtyper.annotate_helper_fn(
+        ll_tp_alloc,
+        [lltype.Ptr(PY_TYPE_OBJECT), lltype.Signed])
+    pytypeobj.c_tp_free = r_inst.rtyper.annotate_helper_fn(
+        ll_tp_free,
+        [llmemory.Address])
     return lltype.cast_pointer(PyObjPtr, pytypeobj)

Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py	(original)
+++ pypy/dist/pypy/translator/c/funcgen.py	Fri Jun  9 13:30:35 2006
@@ -562,16 +562,16 @@
             return "OP_STACK_MALLOC(%s, %s);" % (esize, eresult)
         elif flavor == "cpy":
             cpytype = self.expr(op.args[2])
-            return "%s = PyObject_New(%s, (PyTypeObject *)%s);" % (
-                eresult, cdecl(typename, ''), cpytype)
+            return "OP_CPY_MALLOC(%s, %s);" % (cpytype, eresult)
         else:
             raise NotImplementedError
 
     def OP_FLAVORED_FREE(self, op):
         flavor = op.args[0].value
         if flavor == "raw":
-            return "OP_RAW_FREE(%s, %s)" % (self.expr(op.args[1]),
-                                            self.expr(op.result))
+            return "OP_RAW_FREE(%s)" % (self.expr(op.args[1]),)
+        elif flavor == "cpy":
+            return "OP_CPY_FREE(%s)" % (self.expr(op.args[1]),)
         else:
             raise NotImplementedError
 

Modified: pypy/dist/pypy/translator/c/src/mem.h
==============================================================================
--- pypy/dist/pypy/translator/c/src/mem.h	(original)
+++ pypy/dist/pypy/translator/c/src/mem.h	Fri Jun  9 13:30:35 2006
@@ -14,7 +14,7 @@
     r = (void*) alloca(size);                                              \
     if (r == NULL) FAIL_EXCEPTION(PyExc_MemoryError, "out of memory");\
  
-#define OP_RAW_FREE(x,r)        OP_FREE(x)
+#define OP_RAW_FREE(x)             OP_FREE(x)
 #define OP_RAW_MEMCOPY(x,y,size,r) memcpy(y,x,size);
 
 /************************************************************/
@@ -119,3 +119,15 @@
 #define PUSH_ALIVE(obj)
 
 #endif /* USING_NO_GC */
+
+/************************************************************/
+/* rcpy support */
+
+#define OP_CPY_MALLOC(cpytype, r)  {                            \
+    /* XXX add tp_itemsize later */                             \
+    OP_RAW_MALLOC(((PyTypeObject *)cpytype)->tp_basicsize, r);  \
+    if (r) {                                                    \
+        PyObject_Init((PyObject *)r, (PyTypeObject *)cpytype);  \
+    }                                                           \
+  }
+#define OP_CPY_FREE(x)   OP_RAW_FREE(x)

Modified: pypy/dist/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_genc.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_genc.py	Fri Jun  9 13:30:35 2006
@@ -31,7 +31,7 @@
     return m
 
 def compile(fn, argtypes, view=False, gcpolicy=None, backendopt=True,
-            annotatorpolicy=None):
+            annotatorpolicy=None, expected_extra_mallocs=0):
     t = TranslationContext()
     a = t.buildannotator(policy=annotatorpolicy)
     a.build_types(fn, argtypes)
@@ -50,7 +50,7 @@
             return compiled_fn(*args, **kwds)
         finally:
             mallocs, frees = module.malloc_counters()
-            assert mallocs == frees
+            assert mallocs - frees == expected_extra_mallocs
     return checking_fn
 
 def test_func_as_pyobject():



More information about the Pypy-commit mailing list