[pypy-svn] r16229 - pypy/dist/pypy/translator/c

pedronis at codespeak.net pedronis at codespeak.net
Mon Aug 22 20:01:59 CEST 2005


Author: pedronis
Date: Mon Aug 22 20:01:57 2005
New Revision: 16229

Added:
   pypy/dist/pypy/translator/c/gc.py   (contents, props changed)
Modified:
   pypy/dist/pypy/translator/c/database.py
   pypy/dist/pypy/translator/c/funcgen.py
Log:
started factoring out refcounting logic as a pluggable gc policy.

still to-do: factor out malloc impls and the gc-related logic in node.py .

(cfbolz, pedronis)



Modified: pypy/dist/pypy/translator/c/database.py
==============================================================================
--- pypy/dist/pypy/translator/c/database.py	(original)
+++ pypy/dist/pypy/translator/c/database.py	Mon Aug 22 20:01:57 2005
@@ -8,12 +8,13 @@
 from pypy.translator.c.node import ContainerNodeClass, ExtTypeOpaqueDefNode
 from pypy.translator.c.support import cdecl, CNameManager, ErrorValue
 from pypy.translator.c.pyobj import PyObjMaker
+from pypy.translator.c import gc
 
 # ____________________________________________________________
 
 class LowLevelDatabase:
 
-    def __init__(self, translator=None, standalone=False):
+    def __init__(self, translator=None, standalone=False, gcpolicy=gc.RefcountingGcPolicy):
         self.translator = translator
         self.standalone = standalone
         self.structdefnodes = {}
@@ -23,6 +24,7 @@
         self.namespace = CNameManager()
         if not standalone:
             self.pyobjmaker = PyObjMaker(self.namespace, self.get, translator)
+        self.gcpolicy = gcpolicy(self)
 
     def gettypedefnode(self, T, varlength=1):
         if varlength <= 1:

Modified: pypy/dist/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/dist/pypy/translator/c/funcgen.py	(original)
+++ pypy/dist/pypy/translator/c/funcgen.py	Mon Aug 22 20:01:57 2005
@@ -124,7 +124,7 @@
             yield '{'
             yield '\t%s;' % cdecl(exc_value_typename, 'vanishing_exc_value')
             yield '\tRPyConvertExceptionToCPython(vanishing_exc_value);'
-            yield '\t%s' % self.db.cdecrefstmt('vanishing_exc_value', lltype_of_exception_value)
+            yield '\t%s' % self.pop_alive_expr('vanishing_exc_value', lltype_of_exception_value)
             yield '}'
         yield 'return %s; ' % self.error_return_value()
 
@@ -156,21 +156,21 @@
         blocknum = {}
         allblocks = []
 
-        # generate an incref for each input argument
+        # match the subsequent pop_alive for each input argument
         for a in self.graph.getargs():
-            line = self.cincref(a)
+            line = self.push_alive(a)
             if line:
                 yield line
 
         def gen_link(link, linklocalvars=None):
             "Generate the code to jump across the given Link."
-            has_ref = {}
+            is_alive = {}
             linklocalvars = linklocalvars or {}
             for v in to_release:
                 linklocalvars[v] = self.expr(v)
-            has_ref = linklocalvars.copy()
+            is_alive = linklocalvars.copy()
             assignments = []
-            increfs = []
+            stay_alive = []
             for a1, a2 in zip(link.args, link.target.inputargs):
                 if self.lltypemap(a2) == Void:
                     continue
@@ -180,23 +180,23 @@
                     src = self.expr(a1)
                 dest = self.expr(a2)
                 assignments.append((self.lltypename(a2), dest, src))
-                if a1 in has_ref:
-                    del has_ref[a1]
+                if a1 in is_alive:
+                    del is_alive[a1]
                 else:
                     assert self.lltypemap(a1) == self.lltypemap(a2)
-                    increfs.append(a2)
+                    stay_alive.append(a2)
             # warning, the order below is delicate to get right:
-            # 1. decref the old variables that are not passed over
-            for v in has_ref:
-                line = self.cdecref(v, linklocalvars[v])
+            # 1. forget the old variables that are not passed over
+            for v in is_alive:
+                line = self.pop_alive(v, linklocalvars[v])
                 if line:
                     yield line
             # 2. perform the assignments with collision-avoidance
             for line in gen_assignments(assignments):
                 yield line
-            # 3. incref the new variables if needed
-            for a2 in increfs:
-                line = self.cincref(a2)
+            # 3. keep alive the new variables if needed
+            for a2 in stay_alive:
+                line = self.push_alive(a2)
                 if line:
                     yield line
             yield 'goto block%d;' % blocknum[link.target]
@@ -228,10 +228,9 @@
                     yield '%s(%s);' % (macro, ', '.join(lst))
                 to_release.append(op.result)
 
-                if op.opname !='direct_call' and self.lltypemap(op.result) != PyObjPtr: # xxx factor out
-                    line = self.cincref(op.result)
-                    if line:
-                        yield line
+                line = self.db.gcpolicy.push_alive_op_result(op.opname, LOCALVAR % op.result.name, self.lltypemap(op.result))
+                if line:
+                    yield line
 
             err_reachable = False
             if len(block.exits) == 0:
@@ -290,11 +289,11 @@
                     if isinstance(link.last_exception, Variable):
                         d[link.last_exception] = 'exc_cls'
                     else:
-                        yield '\t' + self.db.cdecrefstmt('exc_cls', T1)
+                        yield '\t' + self.pop_alive_expr('exc_cls', T1)
                     if isinstance(link.last_exc_value, Variable):
                         d[link.last_exc_value] = 'exc_value'
                     else:
-                        yield '\t' + self.db.cdecrefstmt('exc_value', T2)
+                        yield '\t' + self.pop_alive_expr('exc_value', T2)
                     for op in gen_link(link, d):
                         yield '\t' + op
                     yield '}'
@@ -333,7 +332,7 @@
             while to_release:
                 v = to_release.pop()
                 if err_reachable:
-                    yield self.cdecref(v)
+                    yield self.pop_alive(v)
                 yield 'err%d_%d:' % (blocknum[block], len(to_release))
                 err_reachable = True
             if err_reachable:
@@ -400,10 +399,9 @@
         result = ['%s = %s;' % (newvalue, sourceexpr)]
         # need to adjust the refcount of the result
 
-        if T == PyObjPtr: # xxx factor out
-            increfstmt = self.db.cincrefstmt(newvalue, T)
-            if increfstmt:
-                result.append(increfstmt)
+        line = self.pyobj_incref_expr(newvalue, T)
+        if line:
+            result.append(line)
         result = '\t'.join(result)
         if T == Void:
             result = '/* %s */' % result
@@ -412,18 +410,9 @@
     def generic_set(self, op, targetexpr):
         newvalue = self.expr(op.args[2], special_case_void=False)
         result = ['%s = %s;' % (targetexpr, newvalue)]
-        # need to adjust some refcounts
+        # insert write barrier
         T = self.lltypemap(op.args[2])
-        decrefstmt = self.db.cdecrefstmt('prev', T) # xxx factor out write barrier
-        increfstmt = self.db.cincrefstmt(newvalue, T)
-        if increfstmt:
-            result.append(increfstmt)
-        if decrefstmt:
-            result.insert(0, '{ %s = %s;' % (
-                cdecl(self.lltypename(op.args[2]), 'prev'),
-                targetexpr))
-            result.append(decrefstmt)
-            result.append('}')
+        self.db.gcpolicy.write_barrier(result, newvalue, T, targetexpr)
         result = '\t'.join(result)
         if T == Void:
             result = '/* %s */' % result
@@ -531,10 +520,10 @@
         result.append('%s = (%s)%s;' % (self.expr(op.result),
                                         cdecl(typename, ''),
                                         self.expr(op.args[0])))
-        if TYPE == PyObjPtr: # xxx factor out
-            line = self.cincref(op.result)
-            if line:
-                result.append(line)        
+
+        line = self.pyobj_incref(op.result)
+        if line:
+            result.append(line)        
         return '\t'.join(result)
 
     def OP_SAME_AS(self, op, err):
@@ -544,18 +533,34 @@
         if TYPE != Void:
             result.append('%s = %s;' % (self.expr(op.result),
                                         self.expr(op.args[0])))
-            if TYPE == PyObjPtr: # xxx factor out
-                line = self.cincref(op.result)
-                if line:
-                    result.append(line)        
+            line = self.pyobj_incref(op.result)
+            if line:
+                result.append(line)
         return '\t'.join(result)
 
-    def cincref(self, v):
+    def pyobj_incref(self, v):
         T = self.lltypemap(v)
-        return self.db.cincrefstmt(LOCALVAR % v.name, T)
+        return self.pyobj_incref_expr(LOCALVAR % v.name, T)
 
-    def cdecref(self, v, expr=None):
+    def pyobj_incref_expr(self, expr, T):
+        return self.db.gcpolicy.pyobj_incref(expr, T)
+
+    def pyobj_decref_expr(self, expr, T):
+        return self.db.gcpolicy.pyobj_decref(expr, T)
+            
+    def push_alive(self, v):
+        T = self.lltypemap(v)
+        return self.push_alive_expr(LOCALVAR % v.name, T)
+
+    def pop_alive(self, v, expr=None):
         T = self.lltypemap(v)
-        return self.db.cdecrefstmt(expr or (LOCALVAR % v.name), T)
+        return self.pop_alive_expr(expr or (LOCALVAR % v.name), T)
+
+    def push_alive_expr(self, expr, T):
+        return self.db.gcpolicy.push_alive(expr, T)
+
+    def pop_alive_expr(self, expr, T):
+        return self.db.gcpolicy.pop_alive(expr, T)
+
 
 assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)

Added: pypy/dist/pypy/translator/c/gc.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/c/gc.py	Mon Aug 22 20:01:57 2005
@@ -0,0 +1,70 @@
+from pypy.translator.c.support import cdecl
+from pypy.rpython.lltype import Ptr, PyObject
+
+PyObjPtr = Ptr(PyObject)
+
+class BasicGcPolicy:
+    
+    def __init__(self, db):
+        self.db = db
+
+    def pyobj_incref(self, expr, T):
+        if T == PyObjPtr:
+            return 'Py_XINCREF(%s);' % expr
+        return ''
+
+    def pyobj_decref(self, expr, T):
+        return 'Py_XDECREF(%s);' % expr
+
+    def push_alive(self, expr, T):
+        if isinstance(T, Ptr) and T._needsgc():
+            if expr == 'NULL':    # hum
+                return ''
+            if T.TO == PyObject:
+                return self.pyobj_incref(expr, T)
+            else:
+                return self.push_alive_nopyobj(expr, T)
+        return ''
+
+    def pop_alive(self, expr, T):
+        if isinstance(T, Ptr) and T._needsgc():
+            if T.TO == PyObject:
+                return self.pyobj_decref(expr, T)
+            else:
+                return self.pop_alive_nopyobj(expr, T)
+        return ''
+
+
+class RefcountingGcPolicy(BasicGcPolicy):
+
+    def push_alive_nopyobj(self, expr, T):
+        defnode = self.db.gettypedefnode(T.TO)
+        if defnode.refcount is not None:
+            return 'if (%s) %s->%s++;' % (expr, expr, defnode.refcount)
+
+    def pop_alive_nopyobj(self, expr, T):
+        defnode = self.db.gettypedefnode(T.TO)
+        if defnode.refcount is not None:
+            return 'if (%s && !--%s->%s) %s(%s);' % (expr, expr,
+                                                     defnode.refcount,
+                                                     defnode.deallocator or 'OP_FREE',
+                                                     expr)
+
+    def push_alive_op_result(self, opname, expr, T):
+        if opname !='direct_call' and T != PyObjPtr:
+            return self.push_alive(expr, T)
+        return ''
+
+    def write_barrier(self, result, newvalue, T, targetexpr):  
+        decrefstmt = self.pop_alive('prev', T)
+        increfstmt = self.push_alive(newvalue, T)
+        if increfstmt:
+            result.append(increfstmt)
+        if decrefstmt:
+            result.insert(0, '{ %s = %s;' % (
+                cdecl(self.db.gettype(T), 'prev'),
+                targetexpr))
+            result.append(decrefstmt)
+            result.append('}')
+
+



More information about the Pypy-commit mailing list