[pypy-svn] r75289 - in pypy/trunk/pypy/jit: backend backend/x86 metainterp metainterp/test
arigo at codespeak.net
arigo at codespeak.net
Fri Jun 11 21:44:19 CEST 2010
Author: arigo
Date: Fri Jun 11 21:44:17 2010
New Revision: 75289
Modified:
pypy/trunk/pypy/jit/backend/model.py
pypy/trunk/pypy/jit/backend/x86/assembler.py
pypy/trunk/pypy/jit/backend/x86/regalloc.py
pypy/trunk/pypy/jit/metainterp/pyjitpl.py
pypy/trunk/pypy/jit/metainterp/test/test_recursive.py
pypy/trunk/pypy/jit/metainterp/virtualizable.py
pypy/trunk/pypy/jit/metainterp/warmspot.py
Log:
Merge branch/jit-call-assembler: finish the handling of the fast path
in CALL_ASSEMBLER. Also tests and fixes a bug: in the fast path, we
have to clear the vable_token of the virtualizable.
Modified: pypy/trunk/pypy/jit/backend/model.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/model.py (original)
+++ pypy/trunk/pypy/jit/backend/model.py Fri Jun 11 21:44:17 2010
@@ -7,7 +7,10 @@
# assembler_helper_ptr - a pointer to helper to call after a direct
# assembler call
portal_calldescr = None
+ done_with_this_frame_void_v = -1
done_with_this_frame_int_v = -1
+ done_with_this_frame_ref_v = -1
+ done_with_this_frame_float_v = -1
def __init__(self):
self.fail_descr_list = []
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 Fri Jun 11 21:44:17 2010
@@ -1364,28 +1364,79 @@
descr = op.descr
assert isinstance(descr, LoopToken)
assert len(arglocs) - 2 == len(descr._x86_arglocs[0])
+ #
+ # Write a call to the direct_bootstrap_code of the target assembler
self._emit_call(rel32(descr._x86_direct_bootstrap_code), arglocs, 2,
tmp=eax)
mc = self._start_block()
- mc.CMP(eax, imm(self.cpu.done_with_this_frame_int_v))
- mc.JE(rel8_patched_later)
+ if op.result is None:
+ assert result_loc is None
+ value = self.cpu.done_with_this_frame_void_v
+ else:
+ kind = op.result.type
+ if kind == INT:
+ assert result_loc is eax
+ value = self.cpu.done_with_this_frame_int_v
+ elif kind == REF:
+ assert result_loc is eax
+ value = self.cpu.done_with_this_frame_ref_v
+ elif kind == FLOAT:
+ value = self.cpu.done_with_this_frame_float_v
+ else:
+ raise AssertionError(kind)
+ mc.CMP(eax, imm(value))
+ mc.JE(rel8_patched_later) # goto B if we get 'done_with_this_frame'
je_location = mc.get_relative_pos()
+ #
+ # Path A: use assembler_helper_adr
self._emit_call(rel32(self.assembler_helper_adr), [eax, arglocs[1]], 0,
tmp=ecx, force_mc=True, mc=mc)
- mc.JMP(rel8_patched_later)
+ if isinstance(result_loc, MODRM64):
+ mc.FSTP(result_loc)
+ #else: result_loc is already either eax or None, checked below
+ mc.JMP(rel8_patched_later) # done
jmp_location = mc.get_relative_pos()
+ #
+ # Path B: fast path. Must load the return value, and reset the token
offset = jmp_location - je_location
assert 0 < offset <= 127
mc.overwrite(je_location - 1, [chr(offset)])
- mc.MOV(eax, heap(self.fail_boxes_int.get_addr_for_num(0)))
+ #
+ # Reset the vable token --- XXX really too much special logic here:-(
+ if self.cpu.index_of_virtualizable >= 0:
+ from pypy.jit.backend.llsupport.descr import BaseFieldDescr
+ fielddescr = self.cpu.vable_token_descr
+ assert isinstance(fielddescr, BaseFieldDescr)
+ ofs = fielddescr.offset
+ mc.MOV(eax, arglocs[1])
+ mc.MOV(addr_add(eax, imm(ofs)), imm(0))
+ # in the line above, TOKEN_NONE = 0
+ #
+ if op.result is not None:
+ # load the return value from fail_boxes_xxx[0]
+ kind = op.result.type
+ if kind == FLOAT:
+ xmmtmp = X86XMMRegisterManager.all_regs[0]
+ adr = self.fail_boxes_float.get_addr_for_num(0)
+ mc.MOVSD(xmmtmp, heap64(adr))
+ mc.MOVSD(result_loc, xmmtmp)
+ else:
+ assert result_loc is eax
+ if kind == INT:
+ adr = self.fail_boxes_int.get_addr_for_num(0)
+ mc.MOV(eax, heap(adr))
+ elif kind == REF:
+ adr = self.fail_boxes_ptr.get_addr_for_num(0)
+ mc.XOR(eax, eax)
+ mc.XCHG(eax, heap(adr))
+ else:
+ raise AssertionError(kind)
+ #
+ # Here we join Path A and Path B again
offset = mc.get_relative_pos() - jmp_location
- assert 0 < offset <= 127
+ assert 0 <= offset <= 127
mc.overwrite(jmp_location - 1, [chr(offset)])
self._stop_block()
- if isinstance(result_loc, MODRM64):
- self.mc.FSTP(result_loc)
- else:
- assert result_loc is eax or result_loc is None
self.mc.CMP(mem(ebp, FORCE_INDEX_OFS), imm(0))
return self.implement_guard(addr, self.mc.JL)
Modified: pypy/trunk/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/regalloc.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/regalloc.py Fri Jun 11 21:44:17 2010
@@ -640,7 +640,7 @@
portal_calldescr = self.assembler.cpu.portal_calldescr
size = portal_calldescr.get_result_size(self.translate_support_code)
vable_index = self.assembler.cpu.index_of_virtualizable
- if vable_index != -1:
+ if vable_index >= 0:
self.rm._sync_var(op.args[vable_index])
vable = self.fm.loc(op.args[vable_index], 1)
else:
Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Fri Jun 11 21:44:17 2010
@@ -1102,9 +1102,6 @@
self._addr2name_values = []
self.__dict__.update(compile.make_done_loop_tokens())
- # store this information for fastpath of call_assembler
- d = self.loop_tokens_done_with_this_frame_int[0].finishdescr
- self.cpu.done_with_this_frame_int_v = self.cpu.get_fail_descr_number(d)
def _freeze_(self):
return True
@@ -1147,6 +1144,12 @@
RESULT = codewriter.portal_graph.getreturnvar().concretetype
self.result_type = history.getkind(RESULT)
#
+ # store this information for fastpath of call_assembler
+ name = self.result_type
+ tokens = getattr(self, 'loop_tokens_done_with_this_frame_%s' % name)
+ num = self.cpu.get_fail_descr_number(tokens[0].finishdescr)
+ setattr(self.cpu, 'done_with_this_frame_%s_v' % name, num)
+ #
warmrunnerdesc = self.warmrunnerdesc
if warmrunnerdesc is not None:
self.num_green_args = warmrunnerdesc.num_green_args
Modified: pypy/trunk/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_recursive.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_recursive.py Fri Jun 11 21:44:17 2010
@@ -1,6 +1,7 @@
import py
from pypy.rlib.jit import JitDriver, we_are_jitted, OPTIMIZER_SIMPLE, hint
-from pypy.rlib.jit import unroll_safe
+from pypy.rlib.jit import unroll_safe, dont_look_inside
+from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rpython.annlowlevel import hlstr
@@ -750,6 +751,60 @@
res = self.meta_interp(main, [0], inline=True)
assert res == main(0)
+ def test_directly_call_assembler_virtualizable_reset_token(self):
+ from pypy.rpython.lltypesystem import lltype
+ from pypy.rlib.debug import llinterpcall
+
+ class Thing(object):
+ def __init__(self, val):
+ self.val = val
+
+ class Frame(object):
+ _virtualizable2_ = ['thing']
+
+ driver = JitDriver(greens = ['codeno'], reds = ['i', 'frame'],
+ virtualizables = ['frame'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ @dont_look_inside
+ def check_frame(subframe):
+ if we_are_translated():
+ llinterpcall(lltype.Void, check_ll_frame, subframe)
+ def check_ll_frame(ll_subframe):
+ # This is called with the low-level Struct that is the frame.
+ # Check that the vable_token was correctly reset to zero.
+ # Note that in order for that test to catch failures, it needs
+ # three levels of recursion: the vable_token of the subframe
+ # at the level 2 is set to a non-zero value when doing the
+ # call to the level 3 only. This used to fail when the test
+ # is run via pypy.jit.backend.x86.test.test_recursive.
+ assert ll_subframe.vable_token == 0
+
+ def main(codeno):
+ frame = Frame()
+ frame.thing = Thing(0)
+ portal(codeno, frame)
+ return frame.thing.val
+
+ def portal(codeno, frame):
+ i = 0
+ while i < 5:
+ driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
+ driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
+ nextval = frame.thing.val
+ if codeno < 2:
+ subframe = Frame()
+ subframe.thing = Thing(nextval)
+ nextval = portal(codeno + 1, subframe)
+ check_frame(subframe)
+ frame.thing = Thing(nextval + 1)
+ i += 1
+ return frame.thing.val
+
+ res = self.meta_interp(main, [0], inline=True)
+ assert res == main(0)
+
def test_directly_call_assembler_virtualizable_force(self):
class Thing(object):
def __init__(self, val):
Modified: pypy/trunk/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/virtualizable.py (original)
+++ pypy/trunk/pypy/jit/metainterp/virtualizable.py Fri Jun 11 21:44:17 2010
@@ -11,7 +11,7 @@
class VirtualizableInfo:
- TOKEN_NONE = 0
+ TOKEN_NONE = 0 # must be 0 -- see also x86.call_assembler
TOKEN_TRACING_RESCALL = -1
def __init__(self, warmrunnerdesc):
Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/warmspot.py (original)
+++ pypy/trunk/pypy/jit/metainterp/warmspot.py Fri Jun 11 21:44:17 2010
@@ -604,8 +604,10 @@
if vinfo is not None:
self.cpu.index_of_virtualizable = (vinfo.index_of_virtualizable -
self.num_green_args)
+ self.cpu.vable_token_descr = vinfo.vable_token_descr
else:
self.cpu.index_of_virtualizable = -1
+ self.cpu.vable_token_descr = None
# ____________________________________________________________
# Now mutate origportalgraph to end with a call to portal_runner_ptr
More information about the Pypy-commit
mailing list