Author: Remi Meier <[email protected]>
Branch: stmgc-c4
Changeset: r65375:21bde4788254
Date: 2013-07-12 16:47 +0200
http://bitbucket.org/pypy/pypy/changeset/21bde4788254/
Log: progress on stm barriers (without fastpath) and GC without malloc
fastpaths (nursery)
diff --git a/rpython/jit/backend/llsupport/assembler.py
b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -81,27 +81,34 @@
self.memcpy_addr = self.cpu.cast_ptr_to_int(memcpy_fn)
self._build_failure_recovery(False, withfloats=False)
self._build_failure_recovery(True, withfloats=False)
- self._build_wb_slowpath(False)
- self._build_wb_slowpath(True)
- self._build_wb_slowpath(False, for_frame=True)
+ if gc_ll_descr.stm:
+ descrs = [gc_ll_descr.P2Rdescr, gc_ll_descr.P2Wdescr]
+ else:
+ descrs = [gc_ll_descr.write_barrier_descr]
+ for d in descrs:
+ self._build_b_slowpath(d, False)
+ self._build_b_slowpath(d, True)
+ self._build_b_slowpath(d, False, for_frame=True)
# only one of those
self.build_frame_realloc_slowpath()
if self.cpu.supports_floats:
self._build_failure_recovery(False, withfloats=True)
self._build_failure_recovery(True, withfloats=True)
- self._build_wb_slowpath(False, withfloats=True)
- self._build_wb_slowpath(True, withfloats=True)
+ for d in descrs:
+ self._build_b_slowpath(d, False, withfloats=True)
+ self._build_b_slowpath(d, True, withfloats=True)
self._build_propagate_exception_path()
+
if gc_ll_descr.get_malloc_slowpath_addr() is not None:
# generate few slowpaths for various cases
self.malloc_slowpath = self._build_malloc_slowpath(kind='fixed')
self.malloc_slowpath_varsize = self._build_malloc_slowpath(
kind='var')
- if hasattr(gc_ll_descr, 'malloc_str'):
+ if gc_ll_descr.get_malloc_slowpath_addr() is not None and
hasattr(gc_ll_descr, 'malloc_str'):
self.malloc_slowpath_str = self._build_malloc_slowpath(kind='str')
else:
self.malloc_slowpath_str = None
- if hasattr(gc_ll_descr, 'malloc_unicode'):
+ if gc_ll_descr.get_malloc_slowpath_addr() is not None and
hasattr(gc_ll_descr, 'malloc_unicode'):
self.malloc_slowpath_unicode = self._build_malloc_slowpath(
kind='unicode')
else:
diff --git a/rpython/jit/backend/llsupport/gc.py
b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -294,12 +294,42 @@
self.returns_modified_object = False
self.gcheaderbuilder = gc_ll_descr.gcheaderbuilder
self.HDRPTR = gc_ll_descr.HDRPTR
+ self.b_slowpath = [0, 0, 0, 0]
def repr_of_descr(self):
raise NotImplementedError
def __repr(self):
raise NotImplementedError
+
+ def get_b_slowpath(self, num):
+ return self.b_slowpath[num]
+
+ def set_b_slowpath(self, num, addr):
+ self.b_slowpath[num] = addr
+
+ def get_barrier_funcptr(self, returns_modified_object):
+ raise NotImplementedError
+
+ def get_barrier_fn(self, cpu, returns_modified_object):
+ # must pass in 'self.returns_modified_object', to make sure that
+ # the callers are fixed for this case
+ funcptr = self.get_barrier_funcptr(returns_modified_object)
+ funcaddr = llmemory.cast_ptr_to_adr(funcptr)
+ return cpu.cast_adr_to_int(funcaddr)
+
+ def get_barrier_from_array_fn(self, cpu):
+ # returns a function with arguments [array, index, newvalue]
+ llop1 = self.llop1
+ funcptr = llop1.get_write_barrier_from_array_failing_case(
+ self.FUNCPTR)
+ funcaddr = llmemory.cast_ptr_to_adr(funcptr)
+ return cpu.cast_adr_to_int(funcaddr) # this may return 0
+
+ def has_barrier_from_array(self, cpu):
+ return self.get_barrier_from_array_fn(cpu) != 0
+
+
class WriteBarrierDescr(BarrierDescr):
def __init__(self, gc_ll_descr):
@@ -325,8 +355,6 @@
assert self.jit_wb_cards_set_singlebyte == -0x80
else:
self.jit_wb_cards_set = 0
- #
- self.wb_slowpath = [0, 0, 0, 0]
def repr_of_descr(self):
return 'wbdescr'
@@ -351,30 +379,6 @@
FUNCTYPE = self.FUNCPTR
return self.llop1.get_write_barrier_failing_case(FUNCTYPE)
- def get_write_barrier_fn(self, cpu, returns_modified_object):
- # must pass in 'self.returns_modified_object', to make sure that
- # the callers are fixed for this case
- funcptr = self.get_barrier_funcptr(returns_modified_object)
- funcaddr = llmemory.cast_ptr_to_adr(funcptr)
- return cpu.cast_adr_to_int(funcaddr)
-
- def get_write_barrier_from_array_fn(self, cpu):
- # returns a function with arguments [array, index, newvalue]
- llop1 = self.llop1
- funcptr = llop1.get_write_barrier_from_array_failing_case(
- self.FUNCPTR)
- funcaddr = llmemory.cast_ptr_to_adr(funcptr)
- return cpu.cast_adr_to_int(funcaddr) # this may return 0
-
- def has_write_barrier_from_array(self, cpu):
- return self.get_write_barrier_from_array_fn(cpu) != 0
-
- def get_wb_slowpath(self, withcards, withfloats):
- return self.wb_slowpath[withcards + 2 * withfloats]
-
- def set_wb_slowpath(self, withcards, withfloats, addr):
- self.wb_slowpath[withcards + 2 * withfloats] = addr
-
@specialize.arg(2)
def _do_barrier(self, gcref_struct, returns_modified_object):
assert self.returns_modified_object == returns_modified_object
@@ -431,7 +435,7 @@
class STMWriteBarrierDescr(STMBarrierDescr):
def __init__(self, gc_ll_descr, stmcat):
- assert stmcat in ['P2W', 'R2W']
+ assert stmcat in ['P2W']
STMBarrierDescr.__init__(self, gc_ll_descr, stmcat,
'stm_write_barrier')
@@ -465,6 +469,8 @@
if not self.stm:
# XXX: not needed with stm/shadowstack??
self._setup_tid()
+ else:
+ self.fielddescr_tid = None
self._setup_write_barrier()
self._setup_str()
self._make_functions(really_not_translated)
@@ -608,6 +614,7 @@
unicode_itemsize = self.unicode_descr.itemsize
unicode_ofs_length = self.unicode_descr.lendescr.offset
+
def malloc_str(length):
return llop1.do_malloc_varsize_clear(
llmemory.GCREF,
@@ -615,7 +622,7 @@
str_ofs_length)
self.generate_function('malloc_str', malloc_str,
[lltype.Signed])
-
+
def malloc_unicode(length):
return llop1.do_malloc_varsize_clear(
llmemory.GCREF,
@@ -717,7 +724,7 @@
def can_use_nursery_malloc(self, size):
return (self.max_size_of_young_obj is not None and
size < self.max_size_of_young_obj)
-
+
def has_write_barrier_class(self):
return WriteBarrierDescr
diff --git a/rpython/jit/backend/llsupport/rewrite.py
b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -240,7 +240,8 @@
mallocs. (For all I know this latter case never occurs in
practice, but better safe than sorry.)
"""
- if self.gc_ll_descr.fielddescr_tid is not None: # framework GC
+ if self.gc_ll_descr.fielddescr_tid is not None \
+ or self.gc_ll_descr.stm: # framework GC
assert (size & (WORD-1)) == 0, "size not aligned?"
addr = self.gc_ll_descr.get_malloc_fn_addr('malloc_big_fixedsize')
args = [ConstInt(addr), ConstInt(size), ConstInt(typeid)]
@@ -434,7 +435,7 @@
def gen_write_barrier_array(self, v_base, v_index, v_value):
write_barrier_descr = self.gc_ll_descr.write_barrier_descr
- if write_barrier_descr.has_write_barrier_from_array(self.cpu):
+ if write_barrier_descr.has_barrier_from_array(self.cpu):
# If we know statically the length of 'v', and it is not too
# big, then produce a regular write_barrier. If it's unknown or
# too big, produce instead a write_barrier_from_array.
diff --git a/rpython/jit/backend/llsupport/test/test_rewrite.py
b/rpython/jit/backend/llsupport/test/test_rewrite.py
--- a/rpython/jit/backend/llsupport/test/test_rewrite.py
+++ b/rpython/jit/backend/llsupport/test/test_rewrite.py
@@ -281,7 +281,7 @@
gcdescr = get_description(config_)
self.gc_ll_descr = GcLLDescr_framework(gcdescr, None, None, None,
really_not_translated=True)
- self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
+ self.gc_ll_descr.write_barrier_descr.has_barrier_from_array = (
lambda cpu: True)
#
class FakeCPU(BaseFakeCPU):
@@ -573,7 +573,7 @@
""")
def test_write_barrier_before_array_without_from_array(self):
- self.gc_ll_descr.write_barrier_descr.has_write_barrier_from_array = (
+ self.gc_ll_descr.write_barrier_descr.has_barrier_from_array = (
lambda cpu: False)
self.check_rewrite("""
[p1, i2, p3]
diff --git a/rpython/jit/backend/test/runner_test.py
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -4245,11 +4245,11 @@
class WBDescrForTests(AbstractDescr):
returns_modified_object = False
- wb_slowpath = (0, 0, 0, 0)
- def get_wb_slowpath(self, c1, c2):
- return self.wb_slowpath[c1+2*c2]
- def set_wb_slowpath(self, c1, c2, addr):
+ b_slowpath = (0, 0, 0, 0)
+ def get_b_slowpath(self, c1, c2):
+ return self.b_slowpath[c1+2*c2]
+ def set_b_slowpath(self, c1, c2, addr):
i = c1+2*c2
- self.wb_slowpath = (self.wb_slowpath[:i] + (addr,) +
- self.wb_slowpath[i+1:])
+ self.b_slowpath = (self.b_slowpath[:i] + (addr,) +
+ self.b_slowpath[i+1:])
diff --git a/rpython/jit/backend/x86/assembler.py
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -51,7 +51,6 @@
self.float_const_abs_addr = 0
self.malloc_slowpath = 0
self.malloc_slowpath_varsize = 0
- self.wb_slowpath = [0, 0, 0, 0, 0]
self.setup_failure_recovery()
self.datablockwrapper = None
self.stack_check_slowpath = 0
@@ -310,17 +309,21 @@
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
self.stack_check_slowpath = rawstart
- def _build_wb_slowpath(self, withcards, withfloats=False, for_frame=False):
- descr = self.cpu.gc_ll_descr.write_barrier_descr
+ def _build_b_slowpath(self, descr, withcards, withfloats=False,
+ for_frame=False):
+ is_stm = self.cpu.gc_ll_descr.stm
exc0, exc1 = None, None
if descr is None:
return
+
if not withcards:
- func = descr.get_write_barrier_fn(self.cpu)
+ func = descr.get_barrier_fn(self.cpu,
+ returns_modified_object=is_stm)
else:
+ assert not is_stm
if descr.jit_wb_cards_set == 0:
return
- func = descr.get_write_barrier_from_array_fn(self.cpu)
+ func = descr.get_barrier_from_array_fn(self.cpu)
if func == 0:
return
#
@@ -362,11 +365,16 @@
self._store_and_reset_exception(mc, exc0, exc1)
mc.CALL(imm(func))
- #
+
+ if descr.returns_modified_object:
+ # new addr in eax, save in scratch reg
+ mc.PUSH_r(eax.value)
+
if withcards:
# A final TEST8 before the RET, for the caller. Careful to
# not follow this instruction with another one that changes
# the status of the CPU flags!
+ assert not is_stm
if IS_X86_32:
mc.MOV_rs(eax.value, 3*WORD)
else:
@@ -374,12 +382,14 @@
mc.TEST8(addr_add_const(eax, descr.jit_wb_if_flag_byteofs),
imm(-0x80))
#
-
if not for_frame:
if IS_X86_32:
# ADD touches CPU flags
mc.LEA_rs(esp.value, 2 * WORD)
self._pop_all_regs_from_frame(mc, [], withfloats, callee_only=True)
+
+ if descr.returns_modified_object:
+ mc.POP_r(eax.value)
mc.RET16_i(WORD)
else:
if IS_X86_32:
@@ -390,13 +400,16 @@
mc.MOV(exc0, RawEspLoc(WORD * 5, REF))
mc.MOV(exc1, RawEspLoc(WORD * 6, INT))
mc.LEA_rs(esp.value, 7 * WORD)
+
+ if descr.returns_modified_object:
+ mc.POP_r(eax.value)
mc.RET()
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
if for_frame:
- self.wb_slowpath[4] = rawstart
+ descr.set_b_slowpath(4, rawstart)
else:
- self.wb_slowpath[withcards + 2 * withfloats] = rawstart
+ descr.set_b_slowpath(withcards + 2 * withfloats, rawstart)
def assemble_loop(self, loopname, inputargs, operations, looptoken, log):
'''adds the following attributes to looptoken:
@@ -1027,9 +1040,11 @@
if gcrootmap and gcrootmap.is_stm:
wbdescr = self.cpu.gc_ll_descr.P2Wdescr
- else:
- wbdescr = self.cpu.gc_ll_descr.write_barrier_descr
-
+ self._stm_barrier_fastpath(mc, wbdescr, [ebp], is_frame=True,
+ align_stack=align_stack)
+ return
+
+ wbdescr = self.cpu.gc_ll_descr.write_barrier_descr
if gcrootmap and wbdescr:
# frame never uses card marking, so we enforce this is not
# an array
@@ -1980,13 +1995,43 @@
self.mc.overwrite(jmp_location - 1, chr(offset))
# ------------------- END CALL ASSEMBLER -----------------------
+ def _stm_barrier_fastpath(self, mc, descr, arglocs, is_frame=False,
+ align_stack=False):
+ assert self.cpu.gc_ll_descr.stm
+ from rpython.jit.backend.llsupport.gc import STMBarrierDescr
+ assert isinstance(descr, STMBarrierDescr)
+ assert descr.returns_modified_object
+ loc_base = arglocs[0]
+ assert isinstance(loc_base, RegLoc)
+ # Write only a CALL to the helper prepared in advance, passing it as
+ # argument the address of the structure we are writing into
+ # (the first argument to COND_CALL_GC_WB).
+ helper_num = 0
+ if is_frame:
+ helper_num = 4
+ elif self._regalloc is not None and self._regalloc.xrm.reg_bindings:
+ helper_num += 2
+ #
+ if not is_frame:
+ mc.PUSH(loc_base)
+ if is_frame and align_stack:
+ mc.SUB_ri(esp.value, 16 - WORD) # erase the return address
+ func = descr.get_b_slowpath(helper_num)
+ mc.CALL(imm(func))
+ mc.MOV_rr(loc_base.value, eax.value)
+ if is_frame and align_stack:
+ mc.ADD_ri(esp.value, 16 - WORD) # erase the return address
+
+
+
def _write_barrier_fastpath(self, mc, descr, arglocs, array=False,
is_frame=False, align_stack=False):
# Write code equivalent to write_barrier() in the GC: it checks
# a flag in the object at arglocs[0], and if set, it calls a
# helper piece of assembler. The latter saves registers as needed
# and call the function jit_remember_young_pointer() from the GC.
+ assert not self.cpu.gc_ll_descr.stm
if we_are_translated():
cls = self.cpu.gc_ll_descr.has_write_barrier_class()
assert cls is not None and isinstance(descr, cls)
@@ -2029,18 +2074,18 @@
helper_num = 4
elif self._regalloc is not None and self._regalloc.xrm.reg_bindings:
helper_num += 2
- if self.wb_slowpath[helper_num] == 0: # tests only
+ if descr.get_b_slowpath(helper_num) == 0: # tests only
assert not we_are_translated()
self.cpu.gc_ll_descr.write_barrier_descr = descr
- self._build_wb_slowpath(card_marking,
- bool(self._regalloc.xrm.reg_bindings))
- assert self.wb_slowpath[helper_num] != 0
+ self._build_b_slowpath(descr, card_marking,
+ bool(self._regalloc.xrm.reg_bindings))
+ assert descr.get_b_slowpath(helper_num) != 0
#
if not is_frame:
mc.PUSH(loc_base)
if is_frame and align_stack:
mc.SUB_ri(esp.value, 16 - WORD) # erase the return address
- mc.CALL(imm(self.wb_slowpath[helper_num]))
+ mc.CALL(imm(descr.get_b_slowpath(helper_num)))
if is_frame and align_stack:
mc.ADD_ri(esp.value, 16 - WORD) # erase the return address
@@ -2105,6 +2150,9 @@
self._write_barrier_fastpath(self.mc, op.getdescr(), arglocs,
array=True)
+ def genop_discard_cond_call_stm_b(self, op, arglocs):
+ self._stm_barrier_fastpath(self.mc, op.getdescr(), arglocs)
+
def not_implemented_op_discard(self, op, arglocs):
not_implemented("not implemented operation: %s" % op.getopname())
@@ -2129,6 +2177,7 @@
self._check_frame_depth_debug(self.mc)
def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, gcmap):
+ assert not self.cpu.gc_ll_descr.stm
assert size & (WORD-1) == 0 # must be correctly aligned
self.mc.MOV(eax, heap(nursery_free_adr))
self.mc.LEA_rm(edi.value, (eax.value, size))
@@ -2145,6 +2194,7 @@
def malloc_cond_varsize_frame(self, nursery_free_adr, nursery_top_adr,
sizeloc, gcmap):
+ assert not self.cpu.gc_ll_descr.stm
if sizeloc is eax:
self.mc.MOV(edi, sizeloc)
sizeloc = edi
@@ -2167,6 +2217,7 @@
def malloc_cond_varsize(self, kind, nursery_free_adr, nursery_top_adr,
lengthloc, itemsize, maxlength, gcmap,
arraydescr):
+ assert not self.cpu.gc_ll_descr.stm
from rpython.jit.backend.llsupport.descr import ArrayDescr
assert isinstance(arraydescr, ArrayDescr)
diff --git a/rpython/jit/backend/x86/regalloc.py
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -798,6 +798,7 @@
self.perform_discard(op, arglocs)
consider_cond_call_gc_wb_array = consider_cond_call_gc_wb
+ consider_cond_call_stm_b = consider_cond_call_gc_wb
def consider_call_malloc_nursery(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
@@ -823,6 +824,10 @@
size, gcmap)
def consider_call_malloc_nursery_varsize_frame(self, op):
+ gc_ll_descr = self.assembler.cpu.gc_ll_descr
+ assert gc_ll_descr.max_size_of_young_obj is not None
+ # ^^^ if this returns None, don't translate the rest of this function
+ #
size_box = op.getarg(0)
assert isinstance(size_box, BoxInt) # we cannot have a const here!
# sizeloc must be in a register, but we can free it now
@@ -845,6 +850,9 @@
def consider_call_malloc_nursery_varsize(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
+ assert gc_ll_descr.max_size_of_young_obj is not None
+ # ^^^ if this returns None, don't translate the rest of this function
+ #
if not hasattr(gc_ll_descr, 'max_size_of_young_obj'):
raise Exception("unreachable code")
# for boehm, this function should never be called
diff --git a/rpython/memory/gc/stmgc.py b/rpython/memory/gc/stmgc.py
--- a/rpython/memory/gc/stmgc.py
+++ b/rpython/memory/gc/stmgc.py
@@ -96,7 +96,7 @@
@classmethod
def JIT_max_size_of_young_obj(cls):
- return -1 # XXX: should not be used
+ return None
@classmethod
def JIT_minimal_size_in_nursery(cls):
diff --git a/rpython/memory/gctransform/framework.py
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -625,6 +625,7 @@
# 'no_collect' function can trigger collection
import cStringIO
err = cStringIO.StringIO()
+ import sys
prev = sys.stdout
try:
sys.stdout = err
diff --git a/rpython/memory/gctransform/stmframework.py
b/rpython/memory/gctransform/stmframework.py
--- a/rpython/memory/gctransform/stmframework.py
+++ b/rpython/memory/gctransform/stmframework.py
@@ -47,7 +47,7 @@
return self.gcdata.gc.gcheaderbuilder.header_of_object(obj)
def gct_gc_adr_of_root_stack_top(self, hop):
- hop.genop("stm_get_root_stack_top")
+ hop.genop("stm_get_root_stack_top", [], resultvar=hop.spaceop.result)
def _gct_with_roots_pushed(self, hop):
livevars = self.push_roots(hop)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit