[pypy-svn] r6297 - pypy/branch/pypy-genc/translator

arigo at codespeak.net arigo at codespeak.net
Mon Sep 6 14:51:17 CEST 2004


Author: arigo
Date: Mon Sep  6 14:51:16 2004
New Revision: 6297

Modified:
   pypy/branch/pypy-genc/translator/genc.h
   pypy/branch/pypy-genc/translator/genc.py
   pypy/branch/pypy-genc/translator/genc_typeset.py
   pypy/branch/pypy-genc/translator/typer.py
Log:
* Reorganization of reference counters code.
* Support for tuples.



Modified: pypy/branch/pypy-genc/translator/genc.h
==============================================================================
--- pypy/branch/pypy-genc/translator/genc.h	(original)
+++ pypy/branch/pypy-genc/translator/genc.h	Mon Sep  6 14:51:16 2004
@@ -81,9 +81,6 @@
 #define return_o(o)             return o;
 #define returnerr_i()           return -1;
 #define returnerr_o()           return NULL;
-#define incref_o(o)             Py_INCREF(o);
-#define decref_o(o)             Py_DECREF(o);
-#define xdecref_o(o)            Py_XDECREF(o);
 
 #define OP_EXCEPTION_ov(x)    /* XXX exceptions not implemented */
 

Modified: pypy/branch/pypy-genc/translator/genc.py
==============================================================================
--- pypy/branch/pypy-genc/translator/genc.py	(original)
+++ pypy/branch/pypy-genc/translator/genc.py	Mon Sep  6 14:51:16 2004
@@ -6,7 +6,7 @@
 import autopath, os
 from pypy.translator.typer import LLFunction, LLOp, LLConst
 from pypy.translator.classtyper import LLClass
-from pypy.translator import genc_typeset
+from pypy.translator.genc_typeset import CTypeSet, consts_used
 
 # ____________________________________________________________
 
@@ -27,7 +27,7 @@
                 pass
         else:
             bindings = {}
-        self.typeset = genc_typeset.CTypeSet(self, bindings)
+        self.typeset = CTypeSet(self, bindings)
         self.initializationcode = []
         self.llclasses = {};   self.classeslist = []
         self.llfunctions = {}; self.functionslist = []
@@ -145,7 +145,7 @@
         to_declare = []
         for line in body:
             if isinstance(line, LLOp):
-                for a in line.args + getattr(line.name, 'known_answer', []):
+                for a in line.args + consts_used(line.name):
                     if isinstance(a, LLConst) and a.to_declare:
                         to_declare.append(a)
                         if a.initexpr:
@@ -181,18 +181,20 @@
         # print the body
         for line in body:
             if isinstance(line, LLOp):
-                args = [a.name for a in line.args]
-                if line.errtarget:
-                    args.append(line.errtarget)
-                # line.name is actually not a string, but a callable that
-                # generates the C code -- unless it is a special low-level-only
-                # operation that comes from typer.py.
-                writer = line.name   
-                if isinstance(writer, str):
-                    writer = self.LL_ONLY_OPERATIONS[writer]
-                code = writer(*args)
-                for codeline in code.split('\n'):
-                    print >> f, '\t' + codeline
+                writer = line.name
+                if isinstance(writer, str):   # special low-level operation
+                    meth = getattr(self, 'lloperation_' + writer)
+                    code = meth(line)
+                else:
+                    # line.name is actually not a string, but a callable that
+                    # generates the C code.
+                    args = [a.name for a in line.args]
+                    if line.errtarget:
+                        args.append(line.errtarget)
+                    code = writer(*args)
+                if code:
+                    for codeline in code.split('\n'):
+                        print >> f, '\t' + codeline
 
             elif line:  # label
                 print >> f, '   %s:' % line
@@ -200,6 +202,46 @@
                 print >> f
         print >> f, '}'
 
+    def lloperation_move(self, line):
+        vx, vy = line.args
+        return '%s = %s;' % (vy.name, vx.name)
+
+    def lloperation_goto(self, line):
+        return 'goto %s;' % line.errtarget
+
+    def lloperation_copy(self, line):
+        ls = []
+        assert len(line.args) % 2 == 0
+        half = len(line.args) // 2
+        for i in range(half):
+            vx = line.args[i]
+            vy = line.args[half+i]
+            ls.append('%s = %s;' % (vy.name, vx.name))
+            if vy.type == 'PyObject*':
+                ls.append('Py_INCREF(%s);' % vy.name)
+        return ' '.join(ls)
+
+    def lloperation_incref(self, line):
+        ls = []
+        for a in line.args:
+            if a.type == 'PyObject*':
+                ls.append('Py_INCREF(%s);' % a.name)
+        return ' '.join(ls)
+
+    def lloperation_decref(self, line):
+        ls = []
+        for a in line.args:
+            if a.type == 'PyObject*':
+                ls.append('Py_DECREF(%s);' % a.name)
+        return ' '.join(ls)
+
+    def lloperation_xdecref(self, line):
+        ls = []
+        for a in line.args:
+            if a.type == 'PyObject*':
+                ls.append('Py_XDECREF(%s);' % a.name)
+        return ' '.join(ls)
+
     def gen_cclass(self, llclass):
         f = self.f
         cls = llclass.cdef.cls
@@ -249,11 +291,6 @@
 
 # ____________________________________________________________
 
-    LL_ONLY_OPERATIONS = {
-        'move': lambda x,y: '%s = %s;' % (y,x),
-        'goto': lambda err: 'goto %s;' % err,
-        }
-
     C_HEADER = open(os.path.join(autopath.this_dir, 'genc.h')).read()
 
     C_SEP = "/************************************************************/"

Modified: pypy/branch/pypy-genc/translator/genc_typeset.py
==============================================================================
--- pypy/branch/pypy-genc/translator/genc_typeset.py	(original)
+++ pypy/branch/pypy-genc/translator/genc_typeset.py	Mon Sep  6 14:51:16 2004
@@ -36,6 +36,7 @@
         self.genc = genc
         self.bindings = bindings
         self.r_constants = {}
+        self.r_tuples = {}
         self.lloperations = {'convert': {}, 'release': {}}
         self.parse_operation_templates()
 
@@ -54,6 +55,9 @@
                 return self.R_INT
             if isinstance(var, annmodel.SomeImpossibleValue):
                 return self.R_VOID
+            if isinstance(var, annmodel.SomeTuple):
+                items_r = [self.gethltype(s_item) for s_item in var.items]
+                return self.tuple_representation(items_r)
             # fall-back
             return self.R_OBJECT
         if isinstance(var, Constant):
@@ -82,6 +86,14 @@
                 return '\n'.join(ls)
             opnewlist[sig] = writer, True
             return True   # retry
+        if opname == 'OP_NEWTUPLE':
+            opnewtuple = self.lloperations.setdefault('OP_NEWTUPLE', {})
+            rt = self.tuple_representation(hltypes[:-1])
+            sig = tuple(hltypes[:-1]) + (rt,)
+            if sig in opnewtuple:
+                return False
+            opnewtuple[sig] = 'copy', False
+            return True   # retry
         if opname == 'OP_SIMPLE_CALL' and hltypes:
             opsimplecall = self.lloperations.setdefault('OP_SIMPLE_CALL', {})
             sig = (self.R_OBJECT,) * len(hltypes)
@@ -109,6 +121,11 @@
         try:
             return self.r_constants[key]
         except KeyError:
+            if isinstance(value, tuple):
+                # tuples have their own representation and
+                # don't need a fully constant representation
+                items_r = [self.constant_representation(x) for x in value]
+                return self.tuple_representation(items_r)
             # a constant doesn't need any C variable to be encoded
             r = self.r_constants[key] = CRepr([])
             r.const = value
@@ -218,6 +235,62 @@
                           to_declare = bool(initexpr))
         writer.known_answer = [llconst]
 
+    def tuple_representation(self, items_r):
+        # a tuple is implemented by several C variables or fields
+        # instead of a single struct at the C level.
+        items_r = tuple(items_r)
+        try:
+            return self.r_tuples[items_r]
+        except KeyError:
+            impl = []
+            for r in items_r:
+                impl += r.impl
+            rt = CRepr(impl)
+            if items_r:
+                rt.err_check = items_r[0].err_check
+            self.r_tuples[items_r] = rt
+            # can convert the tuple to a PyTupleObject only if each item can be
+            conv = self.lloperations['convert']
+            also_using = []
+            for r in items_r:
+                if r == self.R_OBJECT:
+                    continue
+                if (r, self.R_OBJECT) not in conv:
+                    break
+                llname, can_fail = conv[r, self.R_OBJECT]
+                also_using.append(llname)
+            else:
+                def writer(*args):
+                    content = args[:-2]
+                    result = args[-2]
+                    err = args[-1]
+                    ls = ['{',
+                          'PyObject* o;',
+                          'if (!(%s = PyTuple_New(%d))) goto %s;' % (
+                                result, len(items_r), err)]
+                    j = 0
+                    for i in range(len(items_r)):
+                        r = items_r[i]
+                        if r == self.R_OBJECT:
+                            o = content[j]
+                            j = j+1
+                            ls.append('Py_INCREF(%s);' % o)
+                        else:
+                            o = 'o'
+                            llname, can_fail = conv[r, self.R_OBJECT]
+                            k = len(r.impl)
+                            args = content[j:j+k] + (o,)
+                            j = j+k
+                            if can_fail:
+                                args += (err,)
+                            ls.append(llname(*args))
+                        ls.append('PyTuple_SET_ITEM(%s, %d, %s);' %
+                                  (result, i, o))
+                    return '\n'.join(ls).replace('\n', '\n\t') + '\n}'
+                writer.also_using = also_using
+                conv[rt, self.R_OBJECT] = writer, True
+            return rt
+
     def parse_operation_templates(self):
         # parse the genc.h header to figure out which macros are implemented
         codes = ''.join(self.REPR_BY_CODE.keys())
@@ -258,3 +331,12 @@
                 c = '_%02x' % ord(c)
         l.append(c)
     return ''.join(l)
+
+def consts_used(writer):
+    "Enumerate the global constants that a writer function uses."
+    result = getattr(writer, 'known_answer', [])
+    if hasattr(writer, 'also_using'):
+        result = list(result)
+        for w in writer.also_using:
+            result += consts_used(w)
+    return result

Modified: pypy/branch/pypy-genc/translator/typer.py
==============================================================================
--- pypy/branch/pypy-genc/translator/typer.py	(original)
+++ pypy/branch/pypy-genc/translator/typer.py	Mon Sep  6 14:51:16 2004
@@ -49,15 +49,17 @@
 #       This dict contains the known signatures of each space operation.
 #       Special opnames:
 #         'convert' x y : convert some x to y
-#         'incref'    z : get a new ref to the object z
-#         'decref'    z : release (or decref) the object z
 #         'caseXXX'   z : fails (i.e. jump to errlabel) if z is not XXX
 #         'return'    z : z is the return value of the function
 #         'returnerr' z : same, but return an error code instead of z's content
 #
 #       Low-level-only operation names:
-#         'goto'        : fails unconditionally (i.e. jump to errlabel)
-#         'move'    x y : raw copy of the LLVar x to the LLVar y
+#         'goto'          : fails unconditionally (i.e. jump to errlabel)
+#         'move'    x y   : raw copy of the LLVar x to the LLVar y
+#         'copy' x1 x2.. y1 y2...: raw copy x1 to y1, x2 to y2, etc. and incref
+#         'incref'  x y...: raw incref of the LLVars x, y, etc.
+#         'decref'  x y...: raw decref of the LLVars x, y, etc.
+#         'xdecref' x y...: raw xdecref of the LLVars x, y, etc.
 #
 #   def typingerror(self, opname, hltypes):
 #       Called when no match is found in lloperations.  This function must
@@ -154,13 +156,7 @@
 
         # generate an incref for each input argument
         for v in self.graph.getargs():
-            sig = (self.hltypes[v],)
-            try:
-                llname, can_fail = self.lloperations['incref'][sig]
-            except KeyError:
-                continue   # ignore types with no particular incref operation
-            assert not can_fail
-            yield LLOp(llname, self.llreprs[v])
+            yield LLOp('incref', self.llreprs[v])
 
         # generate the body of each block
         for block in allblocks:
@@ -208,13 +204,7 @@
     # __________ Type checking and conversion routines __________
 
     def mark_release(self, v):
-        sig = (self.hltypes[v],)
-        try:
-            llname, can_fail = self.lloperations['decref'][sig]
-        except KeyError:
-            return   # ignore types with no particular decref operation
-        assert not can_fail
-        llop = LLOp(llname, self.llreprs[v])
+        llop = LLOp('decref', self.llreprs[v])
         # make a new node for the release tree
         self.to_release = ReleaseNode(v, llop, self.to_release)
 
@@ -263,6 +253,13 @@
             raise TypingError([opname] + args_t)
         # check if the answer has an existing well-known answer
         if resulttype is not None:  # if we are allowed to patch self.llreprs
+            if llname == 'copy':
+                # patch self.llreprs and we're done
+                llrepr = []
+                for v in args:
+                    llrepr += self.llreprs[v]
+                self.llreprs[result] = llrepr
+                return
             llrepr = self.knownanswer(llname)
             if llrepr is not None:
                 # patch self.llreprs and we're done
@@ -305,38 +302,36 @@
             # copy the data, performing any necessary conversion
             # See also remove_direct_loops() for why we don't worry about
             # the order of the operations
-            escapingreferences = {}
+            current_refcnt = {}
+            needed_refcnt = {}
             for v, w in zip(exit.args, exit.target.inputargs):
                 self.makevar(v)
                 if self.hltypes[v] == self.hltypes[w]:  # fast case
                     for x, y in zip(self.llreprs[v], self.llreprs[w]):
                         self.blockops.append(LLOp('move', [x, y]))
-                    escapingreferences.setdefault(v, 0)
-                    escapingreferences[v] += 1
+                    needed_refcnt.setdefault(v, 0)
+                    needed_refcnt[v] += 1
                 else:
                     self.operation('convert', [v], w)
-                    escapingreferences.setdefault(w, 0)
-                    escapingreferences[w] += 1
-            # then release all the variables that go out of scope minus the
-            # ones that are carried over to the next block
+                    needed_refcnt.setdefault(w, 0)
+                    needed_refcnt[w] += 1
+            # list all variables that go out of scope: as needing by default
+            # no reference
             for node in self.to_release.getbranch():
-                v = node.var
-                escaping = escapingreferences.get(v, 0)
-                if escaping == 0:   # no reference escapes the current scope
-                    self.blockops.append(node.release_operation)
-                else:
-                    # sometimes, a value is duplicated, so that several
-                    # references exit to the next scope.  In this case we need
-                    # to generate increfs.
-                    while escaping > 1:
-                        sig = (self.hltypes[v],)
-                        try:
-                            llname, can_fail = self.lloperations['incref'][sig]
-                        except KeyError:
-                            break   # no incref operation
-                        assert not can_fail
-                        self.blockops.append(LLOp(llname, self.llreprs[v]))
-                        escaping -= 1
+                current_refcnt[node.var] = 1
+                needed_refcnt.setdefault(node.var, 0)
+            # now adjust all reference counters: first increfs, then decrefs
+            # (in case a variable to decref points to the same objects than
+            #  another variable to incref).
+            for v, needed in needed_refcnt.items():
+                current_refcnt.setdefault(v, 0)
+                while current_refcnt[v] < needed:
+                    self.blockops.append(LLOp('incref', self.llreprs[v]))
+                    current_refcnt[v] += 1
+            for v, needed in needed_refcnt.items():
+                while current_refcnt[v] > needed:
+                    self.blockops.append(LLOp('decref', self.llreprs[v]))
+                    current_refcnt[v] -= 1
             # finally jump to the target block
             self.blockops.append(LLOp('goto', [], self.blockname[exit.target]))
         finally:



More information about the Pypy-commit mailing list