[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