[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