[pypy-svn] r67731 - in pypy/trunk/pypy: jit/backend/llsupport jit/backend/x86 jit/backend/x86/test rpython rpython/lltypesystem rpython/lltypesystem/test rpython/memory/gc rpython/memory/gc/test rpython/memory/gctransform rpython/memory/test translator/c translator/c/test
pedronis at codespeak.net
pedronis at codespeak.net
Thu Sep 17 13:54:43 CEST 2009
Author: pedronis
Date: Thu Sep 17 13:54:41 2009
New Revision: 67731
Modified:
pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
pypy/trunk/pypy/jit/backend/x86/assembler.py
pypy/trunk/pypy/jit/backend/x86/runner.py
pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py
pypy/trunk/pypy/rpython/llinterp.py
pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py
pypy/trunk/pypy/rpython/memory/gc/generation.py
pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py
pypy/trunk/pypy/rpython/memory/gctransform/framework.py
pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
pypy/trunk/pypy/translator/c/gc.py
pypy/trunk/pypy/translator/c/test/test_boehm.py
Log:
(micke, pedronis, armin around a bit yesterday)
fix the issue that the failure code produced by the x86 backend was not marking the array it uses for failure pointer values which is old as pointing potentially to young objects.
this was solved by inventing a new gc operation gc_assume_young_pointers implemented by at least the generation and hybrid gc, and by having the x86 backend produce a call to something that will end up invoking the operation at the end of the failure write backs
Modified: pypy/trunk/pypy/jit/backend/llsupport/llmodel.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llsupport/llmodel.py (original)
+++ pypy/trunk/pypy/jit/backend/llsupport/llmodel.py Thu Sep 17 13:54:41 2009
@@ -44,6 +44,14 @@
else:
self._setup_exception_handling_untranslated()
self.clear_exception()
+ self.setup()
+ if translate_support_code:
+ self._setup_on_leave_jitted_translated()
+ else:
+ self._setup_on_leave_jitted_untranslated()
+
+ def setup(self):
+ pass
def set_class_sizes(self, class_sizes):
self.class_sizes = class_sizes
@@ -131,10 +139,35 @@
self.pos_exc_value = pos_exc_value
self.save_exception = save_exception
- _SAVE_EXCEPTION_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
+ def _setup_on_leave_jitted_untranslated(self):
+ # assume we don't need a backend leave in this case
+ self.on_leave_jitted_save_exc = self.save_exception
+ self.on_leave_jitted_noexc = lambda : None
+
+ def _setup_on_leave_jitted_translated(self):
+ on_leave_jitted_hook = self.get_on_leave_jitted_hook()
+ save_exception = self.save_exception
+
+ def on_leave_jitted_noexc():
+ on_leave_jitted_hook()
+
+ def on_leave_jitted_save_exc():
+ on_leave_jitted_hook()
+ save_exception()
- def get_save_exception_int(self):
- f = llhelper(self._SAVE_EXCEPTION_FUNC, self.save_exception)
+ self.on_leave_jitted_noexc = on_leave_jitted_noexc
+ self.on_leave_jitted_save_exc = on_leave_jitted_save_exc
+
+ def get_on_leave_jitted_hook(self):
+ return lambda : None
+
+ _ON_JIT_LEAVE_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
+
+ def get_on_leave_jitted_int(self, save_exception):
+ if save_exception:
+ f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_save_exc)
+ else:
+ f = llhelper(self._ON_JIT_LEAVE_FUNC, self.on_leave_jitted_noexc)
return rffi.cast(lltype.Signed, f)
def get_exception(self):
Modified: pypy/trunk/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/assembler.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/assembler.py Thu Sep 17 13:54:41 2009
@@ -83,6 +83,11 @@
self.fail_boxes_ptr = lltype.malloc(lltype.GcArray(llmemory.GCREF),
MAX_FAIL_BOXES, zero=True)
+ def leave_jitted_hook(self):
+ fail_boxes_ptr = self.fail_boxes_ptr
+ llop.gc_assume_young_pointers(lltype.Void,
+ llmemory.cast_ptr_to_adr(fail_boxes_ptr))
+
def make_sure_mc_exists(self):
if self.mc is None:
rffi.cast(lltype.Signed, self.fail_boxes_int) # workaround
@@ -653,10 +658,15 @@
mc.MOV(addr_add(imm(self.fail_box_int_addr),
imm(len(locs) * WORD)),
eax)
- if exc:
- # note that we don't have to save and restore eax, ecx and edx here
- addr = self.cpu.get_save_exception_int()
- mc.CALL(rel32(addr))
+
+ # we call a provided function that will
+ # - call our on_leave_jitted_hook which will mark
+ # the fail_boxes_ptr array as pointing to young objects to
+ # avoid unwarranted freeing
+ # - optionally save exception depending on the flag
+ addr = self.cpu.get_on_leave_jitted_int(save_exception=exc)
+ mc.CALL(rel32(addr))
+
# don't break the following code sequence!
mc = mc._mc
mc.LEA(esp, addr_add(imm(0), ebp, (-RET_BP + 2) * WORD))
Modified: pypy/trunk/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/runner.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/runner.py Thu Sep 17 13:54:41 2009
@@ -21,16 +21,17 @@
gcdescr=None):
AbstractLLCPU.__init__(self, rtyper, stats, translate_support_code,
gcdescr)
- TP = lltype.GcArray(llmemory.GCREF)
self._bootstrap_cache = {}
self._guard_list = []
- self.setup()
if rtyper is not None: # for tests
self.lltype2vtable = rtyper.lltype_to_vtable_mapping()
def setup(self):
self.assembler = Assembler386(self, self.translate_support_code)
+ def get_on_leave_jitted_hook(self):
+ return self.assembler.leave_jitted_hook
+
def setup_once(self):
pass
Modified: pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_zrpy_gc.py Thu Sep 17 13:54:41 2009
@@ -54,7 +54,7 @@
return entrypoint
-def compile_and_run(f, gc, **kwds):
+def compile_and_run(f, gc, CPUClass=CPU386, **kwds):
from pypy.annotation.listdef import s_list_of_strings
from pypy.translator.translator import TranslationContext
from pypy.jit.metainterp.warmspot import apply_jit
@@ -68,7 +68,7 @@
t.buildannotator().build_types(f, [s_list_of_strings])
t.buildrtyper().specialize()
if kwds['jit']:
- apply_jit(t, CPUClass=CPU386, optimizer=OPTIMIZER_SIMPLE)
+ apply_jit(t, CPUClass=CPUClass, optimizer=OPTIMIZER_SIMPLE)
cbuilder = genc.CStandaloneBuilder(t, f, t.config)
cbuilder.generate_source()
cbuilder.compile()
@@ -326,6 +326,14 @@
check(l[13].x == 122)
check(l[14].x == 132)
check(l[15].x == 142)
+
+ class CPU386CollectOnLeave(CPU386):
+
+ def execute_operations(self, loop, verbose=False):
+ op = CPU386.execute_operations(self, loop, verbose)
+ rgc.collect(0)
+ return op
+
res = compile_and_run(get_test(main), "hybrid", gcrootfinder="asmgcc",
- jit=True)
+ CPUClass=CPU386CollectOnLeave, jit=True)
assert int(res) == 20
Modified: pypy/trunk/pypy/rpython/llinterp.py
==============================================================================
--- pypy/trunk/pypy/rpython/llinterp.py (original)
+++ pypy/trunk/pypy/rpython/llinterp.py Thu Sep 17 13:54:41 2009
@@ -821,6 +821,9 @@
def op_gc__collect(self, *gen):
self.heap.collect(*gen)
+ def op_gc_assume_young_pointers(self, addr):
+ raise NotImplementedError
+
def op_gc_can_move(self, ptr):
addr = llmemory.cast_ptr_to_adr(ptr)
return self.heap.can_move(addr)
Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py Thu Sep 17 13:54:41 2009
@@ -100,6 +100,28 @@
return True
llop = _LLOP()
+class VoidMarker(object):
+ # marker wrapper for void arguments to llops
+ def __init__(self, value):
+ self.value = value
+ def _freeze_(self):
+ return True
+
+def void(value):
+ return VoidMarker(value)
+
+class Entry(ExtRegistryEntry):
+ _about_ = void
+
+ def compute_result_annotation(self, s_value):
+ assert s_value.is_constant()
+ from pypy.annotation.bookkeeper import getbookkeeper
+ bk = getbookkeeper()
+ return bk.immutablevalue(VoidMarker(s_value.const))
+
+ def specialize_call(self, hop):
+ from pypy.rpython.lltypesystem import lltype
+ return hop.inputconst(lltype.Void, None)
def enum_ops_without_sideeffects(raising_is_ok=False):
"""Enumerate operations that have no side-effects
@@ -127,8 +149,16 @@
return lltype_to_annotation(RESULTTYPE.const)
def specialize_call(self, hop):
+ from pypy.rpython.lltypesystem import lltype
op = self.instance # the LLOp object that was called
- args_v = [hop.inputarg(r, i+1) for i, r in enumerate(hop.args_r[1:])]
+ args_v = []
+ for i, s_arg in enumerate(hop.args_s[1:]):
+ if s_arg.is_constant() and isinstance(s_arg.const, VoidMarker):
+ v_arg = hop.inputconst(lltype.Void, s_arg.const.value)
+ else:
+ v_arg = hop.inputarg(hop.args_r[i+1], i+1)
+ args_v.append(v_arg)
+
if op.canraise:
hop.exception_is_here()
else:
@@ -408,6 +438,7 @@
'gc_thread_prepare' : LLOp(canraise=(MemoryError,)),
'gc_thread_run' : LLOp(),
'gc_thread_die' : LLOp(),
+ 'gc_assume_young_pointers': LLOp(),
# experimental operations in support of thread cloning, only
# implemented by the Mark&Sweep GC
'gc_x_swap_pool': LLOp(canraise=(MemoryError,), canunwindgc=True),
Modified: pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py (original)
+++ pypy/trunk/pypy/rpython/lltypesystem/test/test_lloperation.py Thu Sep 17 13:54:41 2009
@@ -1,5 +1,5 @@
import py
-from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop
+from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS, llop, void
from pypy.rpython.lltypesystem import lltype, opimpl
from pypy.rpython.ootypesystem import ootype, ooopimpl
from pypy.rpython.llinterp import LLFrame
@@ -39,6 +39,19 @@
res = interpret(llf, [5, 7], policy=LowLevelAnnotatorPolicy())
assert res == 12
+def test_llop_with_voids_interp():
+ from pypy.rpython.annlowlevel import LowLevelAnnotatorPolicy
+ S = lltype.GcStruct('S', ('x', lltype.Signed), ('y', lltype.Signed))
+ name_y = void('y')
+ def llf():
+ s = lltype.malloc(S)
+ llop.bare_setfield(lltype.Void, s, void('x'), 3)
+ llop.bare_setfield(lltype.Void, s, name_y, 2)
+ return s.x + s.y
+ res = interpret(llf, [], policy=LowLevelAnnotatorPolicy())
+ assert res == 5
+
+
# ___________________________________________________________________________
# This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync.
Modified: pypy/trunk/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/generation.py (original)
+++ pypy/trunk/pypy/rpython/memory/gc/generation.py Thu Sep 17 13:54:41 2009
@@ -448,6 +448,15 @@
remember_young_pointer._dont_inline_ = True
self.remember_young_pointer = remember_young_pointer
+ def assume_young_pointers(self, addr_struct):
+ objhdr = self.header(addr_struct)
+ if objhdr.tid & GCFLAG_NO_YOUNG_PTRS:
+ self.old_objects_pointing_to_young.append(addr_struct)
+ objhdr.tid &= ~GCFLAG_NO_YOUNG_PTRS
+ if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
+ objhdr.tid &= ~GCFLAG_NO_HEAP_PTRS
+ self.last_generation_root_objects.append(addr_struct)
+
def write_into_last_generation_obj(self, addr_struct, addr):
objhdr = self.header(addr_struct)
if objhdr.tid & GCFLAG_NO_HEAP_PTRS:
Modified: pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py (original)
+++ pypy/trunk/pypy/rpython/memory/gc/test/test_direct.py Thu Sep 17 13:54:41 2009
@@ -299,7 +299,19 @@
gc.collect(9)
assert calls == ['semispace_collect']
- calls = []
+ calls = []
+
+ def test_assume_young_pointers(self):
+ s0 = lltype.malloc(S, immortal=True)
+ self.consider_constant(s0)
+ s = self.malloc(S)
+ s.x = 1
+ s0.next = s
+ self.gc.assume_young_pointers(llmemory.cast_ptr_to_adr(s0))
+
+ self.gc.collect(0)
+
+ assert s0.next.x == 1
class TestHybridGC(TestGenerationGC):
Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py Thu Sep 17 13:54:41 2009
@@ -242,6 +242,13 @@
[s_gc, annmodel.SomeAddress()],
annmodel.SomeBool())
+ if hasattr(GCClass, 'assume_young_pointers'):
+ # xxx should really be a noop for gcs without generations
+ self.assume_young_pointers_ptr = getfn(
+ GCClass.assume_young_pointers.im_func,
+ [s_gc, annmodel.SomeAddress()],
+ annmodel.s_None)
+
# in some GCs we can inline the common case of
# malloc_fixedsize(typeid, size, True, False, False)
if getattr(GCClass, 'inline_simple_malloc', False):
@@ -574,6 +581,12 @@
hop.genop("direct_call", [self.can_move_ptr, self.c_const_gc, v_addr],
resultvar=op.result)
+ def gct_gc_assume_young_pointers(self, hop):
+ op = hop.spaceop
+ v_addr = op.args[0]
+ hop.genop("direct_call", [self.assume_young_pointers_ptr,
+ self.c_const_gc, v_addr])
+
def _can_realloc(self):
return self.gcdata.gc.can_realloc
Modified: pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py (original)
+++ pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py Thu Sep 17 13:54:41 2009
@@ -5,7 +5,7 @@
from pypy.annotation import model as annmodel
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.memory.gctransform import framework
-from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython.lltypesystem.lloperation import llop, void
from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR
from pypy.rlib.objectmodel import compute_unique_id, we_are_translated
from pypy.rlib.debug import ll_assert
@@ -1110,5 +1110,26 @@
res = run([100, 100])
assert res == 200
+ def test_assume_young_pointers(self):
+ from pypy.rlib import rgc
+ S = lltype.GcForwardReference()
+ S.become(lltype.GcStruct('S',
+ ('x', lltype.Signed),
+ ('prev', lltype.Ptr(S)),
+ ('next', lltype.Ptr(S))))
+ s0 = lltype.malloc(S, immortal=True)
+ def f():
+ s = lltype.malloc(S)
+ s.x = 42
+ llop.bare_setfield(lltype.Void, s0, void('next'), s)
+ llop.gc_assume_young_pointers(lltype.Void,
+ llmemory.cast_ptr_to_adr(s0))
+ rgc.collect(0)
+ return s0.next.x
+
+ run = self.runner(f, nbargs=0)
+ res = run([])
+ assert res == 42
+
def test_malloc_nonmovable_fixsize(self):
py.test.skip("not supported")
Modified: pypy/trunk/pypy/translator/c/gc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/gc.py (original)
+++ pypy/trunk/pypy/translator/c/gc.py Thu Sep 17 13:54:41 2009
@@ -83,6 +83,9 @@
def OP_GC_THREAD_DIE(self, funcgen, op):
return ''
+ def OP_GC_ASSUME_YOUNG_POINTERS(self, funcgen, op):
+ return ''
+
class RefcountingInfo:
static_deallocator = None
Modified: pypy/trunk/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_boehm.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_boehm.py Thu Sep 17 13:54:41 2009
@@ -1,6 +1,7 @@
import py
from pypy.translator.translator import TranslationContext
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.memory.test import snippet
from pypy.rpython.tool.rffi_platform import check_boehm
from pypy.translator.c.genc import CExtModuleBuilder
@@ -411,6 +412,17 @@
run = self.getcompiled(f)
assert run() == True
+ def test_assume_young_pointers_nop(self):
+ S = lltype.GcStruct('S', ('x', lltype.Signed))
+ s = lltype.malloc(S)
+ s.x = 0
+ def f():
+ llop.gc_assume_young_pointers(lltype.Void,
+ llmemory.cast_ptr_to_adr(s))
+ return True
+ run = self.getcompiled(f)
+ assert run() == True
+
# reusing some tests from pypy.rpython.memory.test.snippet
large_tests_ok = True
More information about the Pypy-commit
mailing list