[pypy-svn] r47559 - in pypy/dist/pypy/rpython/memory: gc gctransform gctransform/test
arigo at codespeak.net
arigo at codespeak.net
Thu Oct 18 19:40:50 CEST 2007
Author: arigo
Date: Thu Oct 18 19:40:49 2007
New Revision: 47559
Modified:
pypy/dist/pypy/rpython/memory/gc/base.py
pypy/dist/pypy/rpython/memory/gc/generation.py
pypy/dist/pypy/rpython/memory/gctransform/framework.py
pypy/dist/pypy/rpython/memory/gctransform/refcounting.py
pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py
pypy/dist/pypy/rpython/memory/gctransform/transform.py
Log:
(arigato, cfbolz before he ran for his train):
* gctransformer support for write_barrier
* fix and expand the write_barrier_support test
* clean up the interface of push_alive() and pop_alive()
* fix tests that depends on choose_gc_from_config() picking
a default GC if none is specified.
Modified: pypy/dist/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/base.py (original)
+++ pypy/dist/pypy/rpython/memory/gc/base.py Thu Oct 18 19:40:49 2007
@@ -4,6 +4,7 @@
class GCBase(object):
_alloc_flavor_ = "raw"
moving_gc = False
+ needs_write_barrier = False
def set_query_functions(self, is_varsize, getfinalizer,
offsets_to_gc_pointers,
@@ -175,7 +176,8 @@
def choose_gc_from_config(config):
"""Return a (GCClass, GC_PARAMS) from the given config object.
"""
- assert config.translation.gctransformer == "framework"
+ if config.translation.gctransformer != "framework": # for tests
+ config.translation.gc = "marksweep" # crash if inconsistent
if config.translation.gc == "marksweep":
GC_PARAMS = {'start_heap_size': 8*1024*1024} # XXX adjust
from pypy.rpython.memory.gc.marksweep import MarkSweepGC
@@ -194,5 +196,5 @@
from pypy.rpython.memory.gc.generation import GenerationGC
return GenerationGC, GC_PARAMS
else:
- raise ValueError("unknown value for frameworkgc: %r" % (
- config.translation.frameworkgc,))
+ raise ValueError("unknown value for translation.gc: %r" % (
+ config.translation.gc,))
Modified: pypy/dist/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gc/generation.py (original)
+++ pypy/dist/pypy/rpython/memory/gc/generation.py Thu Oct 18 19:40:49 2007
@@ -15,6 +15,7 @@
list, chained to each other via their 'forw' header field.
"""
inline_simple_malloc = True
+ needs_write_barrier = True
def __init__(self, AddressLinkedList,
nursery_size=128,
Modified: pypy/dist/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform/framework.py Thu Oct 18 19:40:49 2007
@@ -9,6 +9,7 @@
from pypy.rlib.rarithmetic import ovfcheck
from pypy.rlib.objectmodel import debug_assert
from pypy.translator.backendopt import graphanalyze
+from pypy.translator.backendopt.support import var_needsgc
from pypy.annotation import model as annmodel
from pypy.rpython import annlowlevel
from pypy.rpython.rbuiltin import gen_cast
@@ -248,6 +249,15 @@
else:
self.id_ptr = None
+ if GCClass.needs_write_barrier:
+ self.write_barrier_ptr = getfn(GCClass.write_barrier.im_func,
+ [s_gc, annmodel.SomeAddress(),
+ annmodel.SomeAddress(),
+ annmodel.SomeAddress()],
+ annmodel.s_None,
+ inline=True)
+ else:
+ self.write_barrier_ptr = None
self.statistics_ptr = getfn(GCClass.statistics.im_func,
[s_gc, annmodel.SomeInteger()],
annmodel.SomeInteger())
@@ -561,6 +571,60 @@
else:
hop.rename('cast_ptr_to_int') # works nicely for non-moving GCs
+ def transform_generic_set(self, hop):
+ if self.write_barrier_ptr is None:
+ super(FrameworkGCTransformer, self).transform_generic_set(hop)
+ else:
+ v_struct = hop.spaceop.args[0]
+ v_newvalue = hop.spaceop.args[-1]
+ assert isinstance(v_newvalue.concretetype, lltype.Ptr)
+ opname = hop.spaceop.opname
+ assert opname in ('setfield', 'setarrayitem', 'setinteriorfield')
+ offsets = hop.spaceop.args[1:-1]
+ CURTYPE = v_struct.concretetype.TO
+ v_currentofs = None
+ for ofs in offsets:
+ if ofs.concretetype is lltype.Void:
+ # a field in a structure
+ fieldname = ofs.value
+ fieldofs = llmemory.offsetof(CURTYPE, fieldname)
+ v_offset = rmodel.inputconst(lltype.Signed, fieldofs)
+ CURTYPE = getattr(CURTYPE, fieldname)
+ else:
+ # an index in an array
+ assert ofs.concretetype is lltype.Signed
+ firstitem = llmemory.ArrayItemsOffset(CURTYPE)
+ itemsize = llmemory.sizeof(CURTYPE.OF)
+ c_firstitem = rmodel.inputconst(lltype.Signed, firstitem)
+ c_itemsize = rmodel.inputconst(lltype.Signed, itemsize)
+ v_index = hop.spaceop.args[1]
+ v_offset = hop.genop("int_mul", [c_itemsize, v_index],
+ resulttype = lltype.Signed)
+ v_offset = hop.genop("int_add", [c_firstitem, v_offset],
+ resulttype = lltype.Signed)
+ CURTYPE = CURTYPE.OF
+ if v_currentofs is None:
+ v_currentofs = v_offset
+ else:
+ v_currentofs = hop.genop("int_add",
+ [v_currentofs, v_offset],
+ resulttype = lltype.Signed)
+ # XXX for some GCs we could skip the write_barrier if v_newvalue
+ # is a constant
+ v_newvalue = hop.genop("cast_ptr_to_adr", [v_newvalue],
+ resulttype = llmemory.Address)
+ v_structaddr = hop.genop("cast_ptr_to_adr", [v_struct],
+ resulttype = llmemory.Address)
+ v_fieldaddr = hop.genop("adr_add", [v_structaddr, v_currentofs],
+ resulttype = llmemory.Address)
+ hop.genop("direct_call", [self.write_barrier_ptr,
+ v_newvalue,
+ v_fieldaddr,
+ v_structaddr])
+
+ def var_needs_set_transform(self, var):
+ return var_needsgc(var)
+
def push_alive_nopyobj(self, var, llops):
pass
@@ -573,10 +637,10 @@
if self.gcdata.gc.moving_gc:
# moving GCs don't borrow, so the caller does not need to keep
# the arguments alive
- livevars = [var for var in self.livevars_after_op
+ livevars = [var for var in hop.livevars_after_op()
if not var_ispyobj(var)]
else:
- livevars = self.livevars_after_op + self.current_op_keeps_alive
+ livevars = hop.livevars_after_op() + hop.current_op_keeps_alive()
livevars = [var for var in livevars if not var_ispyobj(var)]
self.num_pushs += len(livevars)
if not livevars:
Modified: pypy/dist/pypy/rpython/memory/gctransform/refcounting.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/refcounting.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform/refcounting.py Thu Oct 18 19:40:49 2007
@@ -154,11 +154,11 @@
def gct_gc_protect(self, hop):
""" protect this object from gc (make it immortal) """
- self.push_alive(hop.spaceop.args[0])
+ self.push_alive(hop.spaceop.args[0], hop.llops)
def gct_gc_unprotect(self, hop):
""" get this object back into gc control """
- self.pop_alive(hop.spaceop.args[0])
+ self.pop_alive(hop.spaceop.args[0], hop.llops)
def gct_fv_gc_malloc(self, hop, flags, TYPE, c_size):
v_raw = hop.genop("direct_call", [self.malloc_fixedsize_ptr, c_size],
Modified: pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform/test/test_framework.py Thu Oct 18 19:40:49 2007
@@ -1,6 +1,6 @@
from pypy.objspace.flow.model import Constant, SpaceOperation
from pypy.annotation.model import SomeInteger
-from pypy.rpython.memory.gc.base import GCBase
+from pypy.rpython.memory.gc.marksweep import MarkSweepGC
from pypy.rpython.memory.gctransform.test.test_transform import rtype
from pypy.rpython.memory.gctransform.transform import GcHighLevelOp
from pypy.rpython.memory.gctransform.framework import FrameworkGCTransformer, CollectAnalyzer
@@ -63,27 +63,49 @@
class WriteBarrierTransformer(FrameworkGCTransformer):
GC_PARAMS = {}
- class GC_CLASS(GCBase):
- def write_barrier(self, addr, addr_to, addr_struct):
- addr_to.address[0] = addr
+ class GCClass(MarkSweepGC):
+ needs_write_barrier = True
-def test_write_barrier_support():
- py.test.skip("no write barrier support yet!")
+def write_barrier_check(spaceop):
t = TranslationContext()
t.buildannotator().build_types(lambda x:x, [SomeInteger()])
t.buildrtyper().specialize()
- llops = LowLevelOpList()
- PTR_TYPE = lltype.Ptr(lltype.GcStruct('S', ('x', lltype.Signed)))
- spaceop = SpaceOperation(
- "setfield",
- [varoftype(PTR_TYPE), Constant('x', lltype.Void)],
- varoftype(lltype.Void))
transformer = WriteBarrierTransformer(t)
+ llops = LowLevelOpList()
hop = GcHighLevelOp(transformer, spaceop, 0, llops)
hop.dispatch()
found = False
+ print spaceop, '======>'
for op in llops:
+ print '\t', op
if op.opname == 'direct_call':
found = True
- break
assert found
+
+def test_write_barrier_support_setfield():
+ PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
+ PTR_TYPE = lltype.Ptr(lltype.GcStruct('S', ('x', PTR_TYPE2)))
+ write_barrier_check(SpaceOperation(
+ "setfield",
+ [varoftype(PTR_TYPE), Constant('x', lltype.Void),
+ varoftype(PTR_TYPE2)],
+ varoftype(lltype.Void)))
+
+def test_write_barrier_support_setarrayitem():
+ PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
+ ARRAYPTR = lltype.Ptr(lltype.GcArray(PTR_TYPE2))
+ write_barrier_check(SpaceOperation(
+ "setarrayitem",
+ [varoftype(ARRAYPTR), varoftype(lltype.Signed),
+ varoftype(PTR_TYPE2)],
+ varoftype(lltype.Void)))
+
+def test_write_barrier_support_setinteriorfield():
+ PTR_TYPE2 = lltype.Ptr(lltype.GcStruct('T', ('y', lltype.Signed)))
+ ARRAYPTR2 = lltype.Ptr(lltype.GcArray(('a', lltype.Signed),
+ ('b', PTR_TYPE2)))
+ write_barrier_check(SpaceOperation(
+ "setinteriorfield",
+ [varoftype(ARRAYPTR2), varoftype(lltype.Signed),
+ Constant('b', lltype.Void), varoftype(PTR_TYPE2)],
+ varoftype(lltype.Void)))
Modified: pypy/dist/pypy/rpython/memory/gctransform/transform.py
==============================================================================
--- pypy/dist/pypy/rpython/memory/gctransform/transform.py (original)
+++ pypy/dist/pypy/rpython/memory/gctransform/transform.py Thu Oct 18 19:40:49 2007
@@ -38,10 +38,16 @@
self.spaceop = op
self.index = index
self.llops = llops
- gct.livevars_after_op = [
+
+ def livevars_after_op(self):
+ gct = self.gctransformer
+ return [
var for var in gct.livevars
if gct.var_last_needed_in[var] > self.index]
- gct.current_op_keeps_alive = [
+
+ def current_op_keeps_alive(self):
+ gct = self.gctransformer
+ return [
var for var in self.spaceop.args
if gct.var_last_needed_in.get(var) == self.index]
@@ -60,9 +66,9 @@
'cast_pointer', 'getsubstruct',
'getinteriorfield'):
# XXX more operations?
- gct.push_alive(v_result)
+ gct.push_alive(v_result, self.llops)
elif opname not in ('direct_call', 'indirect_call'):
- gct.push_alive(v_result)
+ gct.push_alive(v_result, self.llops)
@@ -157,7 +163,7 @@
return is_borrowed
def transform_block(self, block, is_borrowed):
- self.llops = LowLevelOpList()
+ llops = LowLevelOpList()
#self.curr_block = block
self.livevars = [var for var in block.inputargs
if var_needsgc(var) and not is_borrowed(var)]
@@ -175,7 +181,7 @@
self.var_last_needed_in[var] = len(block.operations) + 1
for i, op in enumerate(block.operations):
- hop = GcHighLevelOp(self, op, i, self.llops)
+ hop = GcHighLevelOp(self, op, i, llops)
hop.dispatch()
if len(block.exits) != 0: # i.e not the return block
@@ -186,7 +192,7 @@
deadinallexits.difference_update(sets.Set(link.args))
for var in deadinallexits:
- self.pop_alive(var)
+ self.pop_alive(var, llops)
for link in block.exits:
livecounts = dict.fromkeys(sets.Set(self.livevars) - deadinallexits, 1)
@@ -201,8 +207,7 @@
livecounts[v] = -1
self.links_to_split[link] = livecounts
- block.operations[:] = self.llops
- self.llops = None
+ block.operations[:] = llops
self.livevars = None
self.var_last_needed_in = None
@@ -294,22 +299,18 @@
v_old = hop.genop('g' + opname[1:],
hop.inputargs()[:-1],
resulttype=v_new.concretetype)
- self.push_alive(v_new)
+ self.push_alive(v_new, hop.llops)
hop.rename('bare_' + opname)
- self.pop_alive(v_old)
+ self.pop_alive(v_old, hop.llops)
- def push_alive(self, var, llops=None):
- if llops is None:
- llops = self.llops
+ def push_alive(self, var, llops):
if var_ispyobj(var):
self.push_alive_pyobj(var, llops)
else:
self.push_alive_nopyobj(var, llops)
- def pop_alive(self, var, llops=None):
- if llops is None:
- llops = self.llops
+ def pop_alive(self, var, llops):
if var_ispyobj(var):
self.pop_alive_pyobj(var, llops)
else:
@@ -358,10 +359,10 @@
BaseGCTransformer.__init__(self, parenttransformer.translator)
self.parenttransformer = parenttransformer
- def push_alive(self, var, llops=None):
+ def push_alive(self, var, llops):
pass
- def pop_alive(self, var, llops=None):
+ def pop_alive(self, var, llops):
pass
def gct_malloc(self, hop):
More information about the Pypy-commit
mailing list