[pypy-svn] r23075 - in pypy/dist/pypy/rpython/memory: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Mon Feb 6 17:25:48 CET 2006
Author: cfbolz
Date: Mon Feb 6 17:25:46 2006
New Revision: 23075
Modified:
pypy/dist/pypy/rpython/memory/gctransform.py
pypy/dist/pypy/rpython/memory/test/test_gctransform.py
Log:
* fix incref to not crash on NULL pointers
* move the write barriers to the RefcountingGCTransformer, they are not needed
for the general case
* same for the static_deallocator
* write a function that generates the graph for decrefs: so far only for
arrays
Modified: pypy/dist/pypy/rpython/memory/gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform.py Mon Feb 6 17:25:46 2006
@@ -2,7 +2,9 @@
from pypy.objspace.flow.model import SpaceOperation, Variable, Constant, \
c_last_exception, FunctionGraph, Block, Link, checkgraph
from pypy.translator.unsimplify import insert_empty_block
-from pypy.rpython import rmodel
+from pypy.translator.translator import graphof
+from pypy.annotation import model as annmodel
+from pypy.rpython import rmodel, objectmodel
from pypy.rpython.memory import gc
import sets
@@ -44,7 +46,7 @@
return True
-class GCTransformer:
+class GCTransformer(object):
def __init__(self, translator):
self.translator = translator
self.seen_graphs = {}
@@ -140,30 +142,6 @@
else:
return [op]
- def replace_setfield(self, op):
- if not var_needsgc(op.args[2]):
- return [op]
- oldval = Variable()
- oldval.concretetype = op.args[2].concretetype
- getoldvalop = SpaceOperation("getfield", [op.args[0], op.args[1]], oldval)
- result = [getoldvalop]
- result.extend(self.pop_alive(oldval))
- result.extend(self.push_alive(op.args[2]))
- result.append(op)
- return result
-
- def replace_setarrayitem(self, op):
- if not var_needsgc(op.args[2]):
- return [op]
- oldval = Variable()
- oldval.concretetype = op.args[2].concretetype
- getoldvalop = SpaceOperation("getarrayitem",
- [op.args[0], op.args[1]], oldval)
- result = [getoldvalop]
- result.extend(self.pop_alive(oldval))
- result.extend(self.push_alive(op.args[2]))
- result.append(op)
- return result
def push_alive(self, var):
if var_ispyobj(var):
@@ -205,6 +183,59 @@
# ----------------------------------------------------------------
+
+class RefcountingGCTransformer(GCTransformer):
+
+ gc_header_offset = gc.GCHeaderOffset(lltype.Struct("header", ("refcount", lltype.Signed)))
+
+ def __init__(self, translator):
+ super(RefcountingGCTransformer, self).__init__(translator)
+ # create incref graph
+ def incref(adr):
+ if adr:
+ gcheader = adr - RefcountingGCTransformer.gc_header_offset
+ gcheader.signed[0] = gcheader.signed[0] + 1
+ self.increfgraph = self.translator.rtyper.annotate_helper(
+ incref, [annmodel.SomeAddress()])
+ self.translator.rtyper.specialize_more_blocks()
+ self.increfptr = const_funcptr_fromgraph(self.increfgraph)
+ self.seen_graphs[self.increfgraph] = True
+ # cache graphs:
+ self.decref_graphs = {}
+ self.static_deallocator_graphs = {}
+
+ def push_alive_nopyobj(self, var):
+ adr1 = varoftype(llmemory.Address)
+ result = [SpaceOperation("cast_ptr_to_adr", [var], adr1)]
+ result.append(SpaceOperation("direct_call", [self.increfptr, adr1],
+ varoftype(lltype.Void)))
+ return result
+
+ def replace_setfield(self, op):
+ if not var_needsgc(op.args[2]):
+ return [op]
+ oldval = Variable()
+ oldval.concretetype = op.args[2].concretetype
+ getoldvalop = SpaceOperation("getfield", [op.args[0], op.args[1]], oldval)
+ result = [getoldvalop]
+ result.extend(self.pop_alive(oldval))
+ result.extend(self.push_alive(op.args[2]))
+ result.append(op)
+ return result
+
+ def replace_setarrayitem(self, op):
+ if not var_needsgc(op.args[2]):
+ return [op]
+ oldval = Variable()
+ oldval.concretetype = op.args[2].concretetype
+ getoldvalop = SpaceOperation("getarrayitem",
+ [op.args[0], op.args[1]], oldval)
+ result = [getoldvalop]
+ result.extend(self.pop_alive(oldval))
+ result.extend(self.push_alive(op.args[2]))
+ result.append(op)
+ return result
+
def _static_deallocator_body_for_type(self, v, TYPE, depth=1):
if isinstance(TYPE, lltype.Array):
@@ -229,6 +260,8 @@
yield ' '*depth + 'pop_alive(%s)'%v
def static_deallocation_graph_for_type(self, TYPE):
+ if TYPE in self.static_deallocator_graphs:
+ return self.static_deallocator_graphs[TYPE]
def compute_pop_alive_ll_ops(hop):
hop.llops.extend(self.pop_alive(hop.args_v[1]))
return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const)
@@ -276,35 +309,49 @@
for block in g.iterblocks():
opcount += len(block.operations)
if opcount == 0:
+ self.static_deallocator_graphs[TYPE] = None
return None
else:
+ self.static_deallocator_graphs[TYPE] = g
return g
+
-class RefcountingGCTransformer(GCTransformer):
-
- gc_header_offset = gc.GCHeaderOffset(lltype.Struct("header", ("refcount", lltype.Signed)))
-
- def push_alive_nopyobj(self, var):
- adr1 = varoftype(llmemory.Address)
- result = [SpaceOperation("cast_ptr_to_adr", [var], adr1)]
- adr2 = varoftype(llmemory.Address)
- offset = rmodel.inputconst(lltype.Signed, self.gc_header_offset)
- result.append(SpaceOperation("adr_sub", [adr1, offset], adr2))
- zero = rmodel.inputconst(lltype.Signed, 0)
- intconst = rmodel.inputconst(lltype.Void, int)
- refcount = varoftype(lltype.Signed)
- result.append(SpaceOperation("raw_load", [adr2, intconst, zero], refcount))
- newrefcount = varoftype(lltype.Signed)
- result.append(SpaceOperation("int_add",
- [refcount, rmodel.inputconst(lltype.Signed, 1)],
- newrefcount))
- result.append(SpaceOperation("raw_store",
- [adr2, intconst, zero, newrefcount],
- varoftype(lltype.Void)))
- return result
-
+ def decref_graph_for_type(self, TYPE):
+ if TYPE in self.decref_graphs:
+ return self.decref_graphs[TYPE]
+ if isinstance(TYPE, lltype.GcArray):
+ graph = self.static_deallocation_graph_for_type(TYPE)
+ def compute_destructor_ll_ops(hop):
+ assert hop.args_v[1].concretetype.TO == TYPE
+ return hop.genop("direct_call",
+ [const_funcptr_fromgraph(graph), hop.args_v[1]],
+ resulttype=lltype.Void)
+ def destructor(var):
+ pass
+ destructor.compute_ll_ops = compute_destructor_ll_ops
+ destructor.llresult = lltype.Void
+ def decref(array):
+ arrayadr = objectmodel.cast_ptr_to_adr(array)
+ gcheader = arrayadr - RefcountingGCTransformer.gc_header_offset
+ refcount = gcheader.signed[0] - 1
+ gcheader.signed[0] = refcount
+ if refcount == 0:
+ destructor(array)
+ g = self.translator.rtyper.annotate_helper(decref, [lltype.Ptr(TYPE)])
+ self.translator.rtyper.specialize_more_blocks()
+ # the produced deallocator graph does not need to be transformed
+ self.seen_graphs[g] = True
+ self.decref_graphs[TYPE] = g
+ return g
def varoftype(concretetype):
var = Variable()
var.concretetype = concretetype
return var
+
+def const_funcptr_fromgraph(graph):
+ FUNC = lltype.FuncType([v.concretetype for v in graph.startblock.inputargs],
+ graph.returnblock.inputargs[0].concretetype)
+ return rmodel.inputconst(lltype.Ptr(FUNC),
+ lltype.functionptr(FUNC, graph.name, graph=graph))
+
Modified: pypy/dist/pypy/rpython/memory/test/test_gctransform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/test/test_gctransform.py (original)
+++ pypy/dist/pypy/rpython/memory/test/test_gctransform.py Mon Feb 6 17:25:46 2006
@@ -260,7 +260,8 @@
c.x = 1
return c.x
t = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
-
+ ops = getops(graphof(t, f))
+ assert len(ops['direct_call']) == 2
# ______________________________________________________________________
@@ -278,7 +279,7 @@
t.s = s1
t.s = s2
return t
- t = rtype_and_transform(f, [], gctransform.GCTransformer)
+ t = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
graph = graphof(t, f)
ops = getops(graph)
assert len(ops['getfield']) == 2
@@ -295,7 +296,7 @@
a = lltype.malloc(A, 1)
a[0] = s1
a[0] = s2
- t = rtype_and_transform(f, [], gctransform.GCTransformer)
+ t = rtype_and_transform(f, [], gctransform.RefcountingGCTransformer, check=False)
graph = graphof(t, f)
ops = getops(graph)
assert len(ops['getarrayitem']) == 2
@@ -306,14 +307,14 @@
# ----------------------------------------------------------------------
# test deallocators
-def make_deallocator(TYPE):
+def make_deallocator(TYPE, attr="static_deallocation_graph_for_type"):
def f():
pass
t = TranslationContext()
t.buildannotator().build_types(f, [])
t.buildrtyper().specialize(t)
- transformer = gctransform.GCTransformer(t)
- graph = transformer.static_deallocation_graph_for_type(TYPE)
+ transformer = gctransform.RefcountingGCTransformer(t)
+ graph = getattr(transformer, attr)(TYPE)
if conftest.option.view:
t.view()
return graph
@@ -356,6 +357,12 @@
assert len(ops['getarraysubstruct']) == 1
assert len(ops['gc_free']) == 1
+def test_decref_array():
+ TPtr = lltype.Ptr(lltype.GcStruct("T", ('a', lltype.Signed)))
+ GcA = lltype.GcArray(('x', TPtr), ('y', TPtr))
+ dgraph = make_deallocator(GcA, attr="decref_graph_for_type")
+ ops = getops(dgraph)
+
def test_deallocator_with_destructor():
S = lltype.GcStruct("S", ('x', lltype.Signed))
def f(s):
More information about the Pypy-commit
mailing list