[pypy-svn] r12881 - in pypy/dist/pypy/translator/c: . test

arigo at codespeak.net arigo at codespeak.net
Mon May 30 14:04:58 CEST 2005


Author: arigo
Date: Mon May 30 14:04:58 2005
New Revision: 12881

Modified:
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/funcgen.py
   pypy/dist/pypy/translator/c/ll_include.h
   pypy/dist/pypy/translator/c/node.py
   pypy/dist/pypy/translator/c/test/test_database.py
Log:
Reference counting and deallocators.


Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Mon May 30 14:04:58 2005
@@ -102,6 +102,28 @@
             else:
                 raise Exception("don't know about %r" % (obj,))
 
+    def cincrefstmt(self, expr, T):
+        if isinstance(T, _PtrType) and 'gc' in T.flags:
+            if T.TO == PyObject:
+                return 'Py_INCREF(%s);' % expr
+            else:
+                defnode = self.gettypedefnode(T.TO)
+                if defnode.refcount is not None:
+                    return '%s->%s++;' % (expr, defnode.refcount)
+        return ''
+
+    def cdecrefstmt(self, expr, T):
+        if isinstance(T, _PtrType) and 'gc' in T.flags:
+            if T.TO == PyObject:
+                return 'Py_DECREF(%s);' % expr
+            else:
+                defnode = self.gettypedefnode(T.TO)
+                if defnode.refcount is not None:
+                    return 'if (!--%s->%s) %s(%s);' % (expr, defnode.refcount,
+                                               defnode.deallocator or 'OP_FREE',
+                                                       expr)
+        return ''
+
     def complete(self):
         i = 0
         while True:

Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py	(original)
+++ pypy/dist/pypy/translator/c/funcgen.py	Mon May 30 14:04:58 2005
@@ -3,7 +3,7 @@
 from pypy.translator.c.support import llvalue_from_constant
 from pypy.objspace.flow.model import Variable, Constant, Block
 from pypy.objspace.flow.model import traverse, uniqueitems, last_exception
-from pypy.rpython.lltype import GcPtr, NonGcPtr, PyObject, Void, Primitive
+from pypy.rpython.lltype import GcPtr, NonGcPtr, PyObject, Void
 from pypy.rpython.lltype import pyobjectptr, Struct, Array
 
 
@@ -292,32 +292,49 @@
                 r, args[0], ', '.join(args[1:]), err)
 
     # low-level operations
-    def OP_GETFIELD(self, op, err):
+    def OP_GETFIELD(self, op, err, ampersand=''):
         assert isinstance(op.args[1], Constant)
         STRUCT = self.lltypemap[op.args[0]].TO
         structdef = self.db.gettypedefnode(STRUCT)
         fieldname = structdef.c_struct_field_name(op.args[1].value)
-        return '%s = %s->%s;' % (self.expr(op.result),
-                                 self.expr(op.args[0]),
-                                 fieldname)
+        newvalue = self.expr(op.result)
+        result = ['%s = %s%s->%s;' % (newvalue,
+                                      ampersand,
+                                      self.expr(op.args[0]),
+                                      fieldname)]
+        # need to adjust the refcount of the result
+        T = self.lltypemap[op.result]
+        increfstmt = self.db.cincrefstmt(newvalue, T)
+        if increfstmt:
+            result.append(increfstmt)
+        return '\t'.join(result)
 
     def OP_SETFIELD(self, op, err):
         assert isinstance(op.args[1], Constant)
         STRUCT = self.lltypemap[op.args[0]].TO
         structdef = self.db.gettypedefnode(STRUCT)
         fieldname = structdef.c_struct_field_name(op.args[1].value)
-        return '%s->%s = %s;' % (self.expr(op.args[0]),
-                                 fieldname,
-                                 self.expr(op.args[2]))
+        oldvalue = '%s->%s' % (self.expr(op.args[0]),
+                               fieldname)
+        newvalue = self.expr(op.args[2])
+        result = ['%s = %s;' % (oldvalue, newvalue)]
+
+        # need to adjust some refcounts
+        T = structdef.c_struct_field_type(op.args[1].value)
+        decrefstmt = self.db.cdecrefstmt('prev', T)
+        increfstmt = self.db.cincrefstmt(newvalue, T)
+        if increfstmt:
+            result.append(increfstmt)
+        if decrefstmt:
+            result.insert(0, '{ %s = %s;' % (
+                cdecl(self.typemap[op.args[2]], 'prev'),
+                oldvalue))
+            result.append('if (prev) ' + decrefstmt)
+            result.append('}')
+        return '\t'.join(result)
 
     def OP_GETSUBSTRUCT(self, op, err):
-        assert isinstance(op.args[1], Constant)
-        STRUCT = self.lltypemap[op.args[0]].TO
-        structdef = self.db.gettypedefnode(STRUCT)
-        fieldname = structdef.c_struct_field_name(op.args[1].value)
-        return '%s = &%s->%s;' % (self.expr(op.result),
-                                  self.expr(op.args[0]),
-                                  fieldname)
+        return self.OP_GETFIELD(op, err, ampersand='&')
 
     def OP_GETARRAYITEM(self, op, err):
         return '%s = %s->items + %s;' % (self.expr(op.result),
@@ -335,7 +352,9 @@
         result = ['OP_ZERO_MALLOC(sizeof(%s), %s, %s)' % (cdecl(typename, ''),
                                                           eresult,
                                                           err),
-                  self.cincref(op.result)]
+                  '%s->%s = 1;' % (eresult,
+                                   self.db.gettypedefnode(TYPE).refcount),
+                  ]
         return '\t'.join(result)
 
     def OP_MALLOC_VARSIZE(self, op, err):
@@ -355,25 +374,15 @@
                                                   err),
                   '%s->length = %s;' % (eresult,
                                         elength),
-                  self.cincref(op.result)]
+                  '%s->%s = 1;' % (eresult,
+                                   self.db.gettypedefnode(TYPE).refcount),
+                  ]
         return '\t'.join(result)
 
     def cincref(self, v):
         T = self.lltypemap[v]
-        if not isinstance(T, Primitive) and 'gc' in T.flags:
-            if T.TO == PyObject:
-                return 'Py_INCREF(%s);' % v.name
-            else:
-                return '/*XXX INCREF %s*/' % v.name
-        else:
-            return ''
+        return self.db.cincrefstmt(v.name, T)
 
     def cdecref(self, v, expr=None):
         T = self.lltypemap[v]
-        if not isinstance(T, Primitive) and 'gc' in T.flags:
-            if T.TO == PyObject:
-                return 'Py_DECREF(%s);' % v.name
-            else:
-                return '/*XXX DECREF %s*/' % v.name
-        else:
-            return ''
+        return self.db.cdecrefstmt(expr or v.name, T)

Modified: pypy/dist/pypy/translator/c/ll_include.h
==============================================================================
--- pypy/dist/pypy/translator/c/ll_include.h	(original)
+++ pypy/dist/pypy/translator/c/ll_include.h	Mon May 30 14:04:58 2005
@@ -8,3 +8,5 @@
     if (r == NULL) { PyErr_NoMemory(); FAIL(err) }      \
     memset((void*) r, 0, size);                         \
   }
+
+#define OP_FREE(p)	PyObject_Free(p);

Modified: pypy/dist/pypy/translator/c/node.py
==============================================================================
--- pypy/dist/pypy/translator/c/node.py	(original)
+++ pypy/dist/pypy/translator/c/node.py	Mon May 30 14:04:58 2005
@@ -1,7 +1,7 @@
 from __future__ import generators
 from pypy.rpython.lltype import Struct, Array, FuncType, PyObjectType, typeOf
 from pypy.rpython.lltype import GcStruct, GcArray, GC_CONTAINER, ContainerType
-from pypy.rpython.lltype import parentlink
+from pypy.rpython.lltype import parentlink, _PtrType
 from pypy.translator.c.funcgen import FunctionCodeGenerator
 from pypy.translator.c.support import cdecl, somelettersfrom
 
@@ -11,13 +11,16 @@
         return False
     if isinstance(T, GcStruct):
         if T._names and isinstance(T._flds[T._names[0]], GC_CONTAINER):
-            return False   # refcount already in the first first
+            return False   # refcount already in the first field
     return True
 
 
 class StructDefNode:
+    refcount = None
+    deallocator = None
 
     def __init__(self, db, STRUCT, varlength=1):
+        self.db = db
         self.STRUCT = STRUCT
         if varlength == 1:
             basename = STRUCT._name
@@ -29,16 +32,34 @@
         self.fields = []
         self.prefix = somelettersfrom(STRUCT._name) + '_'
         for name in STRUCT._names:
-            T = STRUCT._flds[name]
+            T = self.c_struct_field_type(name)
             if name == STRUCT._arrayfld:
                 typename = db.gettype(T, varlength=varlength, who_asks=self)
             else:
                 typename = db.gettype(T, who_asks=self)
             self.fields.append((self.c_struct_field_name(name), typename))
 
+        # look up the reference counter field
+        if needs_refcount(STRUCT):
+            self.refcount = 'refcount'
+        elif isinstance(STRUCT, GcStruct):
+            # refcount in the first field
+            T = self.c_struct_field_type(STRUCT._names[0])
+            assert isinstance(T, GC_CONTAINER)
+            firstfieldname, firstfieldtype = self.fields[0]
+            firstdefnode = db.gettypedefnode(T)
+            self.refcount = '%s.%s' % (firstfieldname, firstdefnode.refcount)
+
+        # is a specific deallocator needed?
+        if self.refcount and varlength == 1 and list(self.deallocator_lines('')):
+            self.deallocator = db.namespace.uniquename('dealloc_'+self.name)
+
     def c_struct_field_name(self, name):
         return self.prefix + name
 
+    def c_struct_field_type(self, name):
+        return self.STRUCT._flds[name]
+
     def access_expr(self, baseexpr, fldname):
         fldname = self.c_struct_field_name(fldname)
         return '%s.%s' % (baseexpr, fldname)
@@ -50,11 +71,35 @@
         for name, typename in self.fields:
             yield '\t%s;' % cdecl(typename, name)
         yield '};'
+        if self.deallocator:
+            yield 'void %s(struct %s *p) {' % (self.deallocator, self.name)
+            for line in self.deallocator_lines('p->'):
+                yield '\t' + line
+            yield '\tOP_FREE(p);'
+            yield '}'
+
+    def deallocator_lines(self, prefix):
+        STRUCT = self.STRUCT
+        for name in STRUCT._names:
+            FIELD_T = self.c_struct_field_type(name)
+            if isinstance(FIELD_T, _PtrType) and 'gc' in FIELD_T.flags:
+                cname = self.c_struct_field_name(name)
+                line = self.db.cdecrefstmt('%s%s' % (prefix, cname), FIELD_T)
+                if line:
+                    yield line
+            elif isinstance(FIELD_T, ContainerType):
+                defnode = self.db.gettypedefnode(FIELD_T)
+                cname = self.c_struct_field_name(name)
+                for line in defnode.deallocator_lines('%s%s.' %(prefix, cname)):
+                    yield line
 
 
 class ArrayDefNode:
+    refcount = None
+    deallocator = None
 
     def __init__(self, db, ARRAY, varlength=1):
+        self.db = db
         self.ARRAY = ARRAY
         if varlength == 1:
             basename = 'array'
@@ -66,6 +111,14 @@
         self.structname = db.gettype(ARRAY.OF, who_asks=self)
         self.varlength = varlength
 
+        # look up the reference counter field
+        if needs_refcount(ARRAY):
+            self.refcount = 'refcount'
+
+        # is a specific deallocator needed?
+        if self.refcount and varlength == 1 and list(self.deallocator_lines('')):
+            self.deallocator = db.namespace.uniquename('dealloc_'+self.name)
+
     def access_expr(self, baseexpr, index):
         return '%s.items[%d]' % (baseexpr, index)
 
@@ -76,6 +129,33 @@
         yield '\tlong length;'
         yield '\t%s;' % cdecl(self.structname, 'items[%d]' % self.varlength)
         yield '};'
+        if self.deallocator:
+            yield 'void %s(struct %s *a) {' % (self.deallocator, self.name)
+            for line in self.deallocator_lines('a->'):
+                yield '\t' + line
+            yield '\tOP_FREE(a);'
+            yield '}'
+
+    def deallocator_lines(self, prefix):
+        ARRAY = self.ARRAY
+        defnode = self.db.gettypedefnode(ARRAY.OF)
+        varname = 'p%d' % len(prefix)
+        body = list(defnode.deallocator_lines('%s->' % varname))
+        if body:
+            yield '{'
+            yield '\tstruct %s *%s = %sitems;' % (defnode.name,
+                                                  varname,
+                                                  prefix)
+            yield '\tstruct %s *%s_end = %s + %slength;' % (defnode.name,
+                                                            varname,
+                                                            varname,
+                                                            prefix)
+            yield '\twhile (%s != %s_end) {' % (varname, varname)
+            for line in body:
+                yield '\t\t' + line
+            yield '\t\t%s++;' % varname
+            yield '\t}'
+            yield '}'
 
 # ____________________________________________________________
 

Modified: pypy/dist/pypy/translator/c/test/test_database.py
==============================================================================
--- pypy/dist/pypy/translator/c/test/test_database.py	(original)
+++ pypy/dist/pypy/translator/c/test/test_database.py	Mon May 30 14:04:58 2005
@@ -193,3 +193,72 @@
     db.get(pyobjectptr(f))
     db.complete()
     dump_on_stdout(db)
+
+
+def test_malloc():
+    S = GcStruct('testing', ('x', Signed), ('y', Signed))
+    def ll_f(x):
+        p = malloc(S)
+        p.x = x
+        p.y = x+1
+        return p.x * p.y
+    t = Translator(ll_f)
+    a = t.annotate([int])
+    rtyper = RPythonTyper(t.annotator)
+    rtyper.specialize()
+    db = LowLevelDatabase(rtyper)
+    db.get(rtyper.getfunctionptr(ll_f))
+    db.complete()
+    dump_on_stdout(db)
+
+def test_multiple_malloc():
+    S1 = GcStruct('testing1', ('x', Signed), ('y', Signed))
+    S = GcStruct('testing', ('ptr1', GcPtr(S1)),
+                            ('ptr2', GcPtr(S1)),
+                            ('z', Signed))
+    def ll_f(x):
+        ptr1 = malloc(S1)
+        ptr1.x = x
+        ptr2 = malloc(S1)
+        ptr2.x = x+1
+        s = malloc(S)
+        s.ptr1 = ptr1
+        s.ptr2 = ptr2
+        return s.ptr1.x * s.ptr2.x
+    t = Translator(ll_f)
+    a = t.annotate([int])
+    rtyper = RPythonTyper(t.annotator)
+    rtyper.specialize()
+    db = LowLevelDatabase(rtyper)
+    db.get(rtyper.getfunctionptr(ll_f))
+    db.complete()
+    dump_on_stdout(db)
+
+def test_nested_gcstruct():
+    S1 = GcStruct('inlined', ('x', Signed), ('y', GcPtr(PyObject)))
+    S = GcStruct('testing', ('head', S1),
+                            ('ptr2', GcPtr(S1)),
+                            ('z', Signed))
+    def ll_f(x):
+        ptr2 = malloc(S1)
+        ptr2.x = x+1
+        s = malloc(S)
+        s.head.x = x
+        s.ptr2 = ptr2
+        return s.head.x * s.ptr2.x
+    t = Translator(ll_f)
+    a = t.annotate([int])
+    rtyper = RPythonTyper(t.annotator)
+    rtyper.specialize()
+    db = LowLevelDatabase(rtyper)
+    db.get(rtyper.getfunctionptr(ll_f))
+    db.complete()
+    dump_on_stdout(db)
+
+def test_array():
+    A = GcArray(('obj', GcPtr(PyObject)))
+    a = malloc(A, 10)
+    db = LowLevelDatabase()
+    db.get(a)
+    db.complete()
+    dump_on_stdout(db)



More information about the Pypy-commit mailing list