[pypy-svn] r70084 - in pypy/branch/virtual-forcing/pypy: jit/metainterp jit/metainterp/test rlib
arigo at codespeak.net
arigo at codespeak.net
Sun Dec 13 17:02:46 CET 2009
Author: arigo
Date: Sun Dec 13 17:02:46 2009
New Revision: 70084
Modified:
pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
pypy/branch/virtual-forcing/pypy/rlib/jit.py
Log:
Kill the virtual_ref_check() operation and simplify again the semantics
of virtualrefs. Now it will no longer cause tracing to abort. It might
simplify things quite a lot, and give hopefully good results.
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py Sun Dec 13 17:02:46 2009
@@ -1170,9 +1170,6 @@
def handle_jit_marker__can_enter_jit(self, op):
self.emit('can_enter_jit')
- def handle_jit_marker__virtual_ref_check(self, op):
- self.emit('virtual_ref_check')
-
def serialize_op_direct_call(self, op):
kind = self.codewriter.guess_call_kind(op)
return getattr(self, 'handle_%s_call' % kind)(op)
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/optimizeopt.py Sun Dec 13 17:02:46 2009
@@ -737,9 +737,6 @@
self._optimize_oois_ooisnot(op, False)
def optimize_VIRTUAL_REF(self, op):
- value = self.getvalue(op.args[0])
- if not value.is_virtual(): # virtual_ref(non-virtual) gives bad
- raise compile.GiveUp # results, so don't bother compiling it
indexbox = op.args[1]
#
# get some constants (these calls are all 'memo')
@@ -760,10 +757,6 @@
vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
def optimize_VIRTUAL_REF_FINISH(self, op):
- value = self.getvalue(op.args[1])
- if not value.is_virtual(): # virtual_ref(non-virtual) means it
- raise compile.GiveUp # escaped already, which is bad
- #
# Set the 'forced' field of the virtual_ref.
# In good cases, this is all virtual, so has no effect.
# Otherwise, this forces the real object -- but only now, as
@@ -780,6 +773,12 @@
op1 = ResOperation(rop.SETFIELD_GC, args, None,
descr = virtualref.get_descr_virtual_token(self.cpu))
self.optimize_SETFIELD_GC(op1)
+ # Note that in some cases the virtual in op.args[1] has been forced
+ # already. This is fine. In that case, and *if* a residual
+ # CALL_MAY_FORCE suddenly turns out to access it, then it will
+ # trigger a ResumeGuardForcedDescr.handle_async_forcing() which
+ # will work too (but just be a little pointless, as the structure
+ # was already forced).
def optimize_GETFIELD_GC(self, op):
value = self.getvalue(op.args[0])
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py Sun Dec 13 17:02:46 2009
@@ -508,13 +508,6 @@
@arguments("box", "descr", "box")
def opimpl_setfield_gc(self, box, fielddesc, valuebox):
self.execute_with_descr(rop.SETFIELD_GC, fielddesc, box, valuebox)
- # <hack> XXX
- metainterp = self.metainterp
- if (len(metainterp.virtualref_boxes) >= 2 and
- metainterp.virtualref_boxes[-2] == valuebox and
- virtualref.is_virtual_ref(metainterp.virtualref_boxes[-1].getref_base())):
- metainterp.stop_tracking_virtualref(-2)
- # </hack>
@arguments("box", "descr")
def opimpl_getfield_raw(self, box, fielddesc):
@@ -843,7 +836,6 @@
except GiveUp:
self.metainterp.staticdata.profiler.count(ABORT_BRIDGE)
self.metainterp.switch_to_blackhole()
- self.metainterp.virtual_ref_check()
if self.metainterp.is_blackholing():
self.blackhole_reached_merge_point(self.env)
return True
@@ -907,11 +899,6 @@
# in the vref), then we replace the vref in the list with
# ConstPtr(NULL).
#
- # * at the next virtual_ref_check() or jit_merge_point(), any such
- # NULL causes tracing to abort. So escaping is fine if there
- # is no virtual_ref_check()/jit_merge_point() before the final
- # call to virtual_ref_finish().
- #
metainterp = self.metainterp
if metainterp.is_blackholing():
resbox = box # good enough when blackholing
@@ -946,10 +933,6 @@
metainterp.history.record(rop.VIRTUAL_REF_FINISH,
[vrefbox, lastbox], None)
- @arguments()
- def opimpl_virtual_ref_check(self):
- self.metainterp.virtual_ref_check()
-
# ------------------------------
def setup_call(self, argboxes):
@@ -1058,7 +1041,7 @@
# xxx do something about code duplication
resbox = self.metainterp.execute_and_record_varargs(
rop.CALL_MAY_FORCE, argboxes, descr=descr)
- self.metainterp.vable_and_vrefs_after_residual_call(argboxes)
+ self.metainterp.vable_and_vrefs_after_residual_call()
if resbox is not None:
self.make_result_box(resbox)
self.generate_guard(self.pc, rop.GUARD_NOT_FORCED, None, [])
@@ -1813,7 +1796,7 @@
force_token_box],
None, descr=vinfo.vable_token_descr)
- def vable_and_vrefs_after_residual_call(self, argboxes):
+ def vable_and_vrefs_after_residual_call(self):
if self.is_blackholing():
escapes = True
else:
@@ -1823,8 +1806,7 @@
virtualbox = self.virtualref_boxes[i]
vrefbox = self.virtualref_boxes[i+1]
vref = vrefbox.getref_base()
- if (virtualref.tracing_after_residual_call(vref) or
- virtualbox in argboxes): # <-- XXX hack
+ if virtualref.tracing_after_residual_call(vref):
# this vref was really a virtual_ref, but it escaped
# during this CALL_MAY_FORCE. Mark this fact by
# generating a VIRTUAL_REF_FINISH on it and replacing
@@ -1848,25 +1830,15 @@
def stop_tracking_virtualref(self, i):
virtualbox = self.virtualref_boxes[i]
vrefbox = self.virtualref_boxes[i+1]
- # record VIRTUAL_REF_FINISH just before the current op
- current_op = self.history.operations.pop()
+ # record VIRTUAL_REF_FINISH just before the current CALL_MAY_FORCE
+ call_may_force_op = self.history.operations.pop()
+ assert call_may_force_op.opnum == rop.CALL_MAY_FORCE
self.history.record(rop.VIRTUAL_REF_FINISH,
[vrefbox, virtualbox], None)
- self.history.operations.append(current_op)
+ self.history.operations.append(call_may_force_op)
# mark by replacing it with ConstPtr(NULL)
self.virtualref_boxes[i+1] = self.cpu.ts.CONST_NULL
- def virtual_ref_check(self):
- if self.is_blackholing():
- return
- # abort tracing if we reach this point with an escaped virtual
- for i in range(1, len(self.virtualref_boxes), 2):
- vrefbox = self.virtualref_boxes[i]
- vref = vrefbox.getref_base()
- if not virtualref.is_virtual_ref(vref):
- self.switch_to_blackhole()
- break
-
def handle_exception(self):
etype = self.cpu.get_exception()
evalue = self.cpu.get_exc_value()
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualref.py Sun Dec 13 17:02:46 2009
@@ -1,7 +1,7 @@
import py
from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
-from pypy.rlib.jit import virtual_ref, virtual_ref_check, virtual_ref_finish
+from pypy.rlib.jit import virtual_ref, virtual_ref_finish
from pypy.rlib.objectmodel import compute_unique_id
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.resoperation import rop
@@ -22,7 +22,6 @@
def f():
x = X()
exctx.topframeref = virtual_ref(x)
- virtual_ref_check()
exctx.topframeref = vref_None
virtual_ref_finish(x)
return 1
@@ -54,7 +53,6 @@
exctx.topframeref = virtual_ref(x)
def leave():
exctx.topframeref = vref_None
- virtual_ref_check()
virtual_ref_finish(exctx._frame)
def f(n):
enter(n)
@@ -107,10 +105,9 @@
# here, 'x' should be virtual. (This is ensured because
# we call virtual_ref(x).)
exctx.topframeref = vref_None
- virtual_ref_check()
virtual_ref_finish(x)
- # 'x' is allowed to escape, and even be forced, even after
- # the call to finish().
+ # 'x' and 'vref' can randomly escape after the call to
+ # finish().
g(vref)
n -= 1
return 1
@@ -119,104 +116,10 @@
self.check_loops(new_with_vtable=2) # the vref, and later the X
self.check_aborted_count(0)
- def test_make_vref_and_force_nocheck_1(self):
- jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
- #
- class X:
- pass
- class ExCtx:
- pass
- exctx = ExCtx()
- #
- @dont_look_inside
- def force_me():
- return exctx.topframeref().n
- #
- def f(n):
- total = 0
- while total < 300:
- jitdriver.can_enter_jit(total=total, n=n)
- jitdriver.jit_merge_point(total=total, n=n)
- x = X()
- x.n = n + 123
- exctx.topframeref = virtual_ref(x)
- # --- no virtual_ref_check() here ---
- total += force_me() - 100
- virtual_ref_finish(x)
- exctx.topframeref = vref_None
- return total
- #
- res = self.meta_interp(f, [-4])
- assert res == 16 * 19
- self.check_aborted_count(0)
-
- def test_make_vref_and_force_nocheck_2(self):
- jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
- #
- class X:
- pass
- class ExCtx:
- pass
- exctx = ExCtx()
- #
- @dont_look_inside
- def force_me():
- return exctx.topframeref().n
- #
- def f(n):
- total = 0
- while total < 300:
- jitdriver.can_enter_jit(total=total, n=n)
- jitdriver.jit_merge_point(total=total, n=n)
- x = X()
- x.n = n + 123
- exctx.topframeref = virtual_ref(x)
- virtual_ref_check()
- total += force_me() - 100
- # --- but no virtual_ref_check() there ---
- virtual_ref_finish(x)
- exctx.topframeref = vref_None
- return total
- #
- res = self.meta_interp(f, [-4])
- assert res == 16 * 19
- self.check_aborted_count(0)
-
- def test_make_vref_and_force_check(self):
- jitdriver = JitDriver(greens = [], reds = ['total', 'n'])
- #
- class X:
- pass
- class ExCtx:
- pass
- exctx = ExCtx()
- #
- @dont_look_inside
- def force_me():
- return exctx.topframeref().n
- #
- def f(n):
- total = 0
- while total < 300:
- jitdriver.can_enter_jit(total=total, n=n)
- jitdriver.jit_merge_point(total=total, n=n)
- x = X()
- x.n = n + 123
- exctx.topframeref = virtual_ref(x)
- total += force_me() - 100
- virtual_ref_check()
- virtual_ref_finish(x)
- exctx.topframeref = vref_None
- return total
- #
- res = self.meta_interp(f, [-4])
- assert res == 16 * 19
- self.check_loops({}) # because we aborted tracing
- self.check_aborted_count_at_least(1)
-
def test_simple_no_access(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
+ A = lltype.GcArray(lltype.Signed)
class XY:
pass
class ExCtx:
@@ -234,26 +137,26 @@
myjitdriver.can_enter_jit(n=n)
myjitdriver.jit_merge_point(n=n)
xy = XY()
- xy.next1 = XY()
- xy.next2 = XY()
- xy.next3 = XY()
+ xy.next1 = lltype.malloc(A, 0)
+ xy.next2 = lltype.malloc(A, 0)
+ xy.next3 = lltype.malloc(A, 0)
exctx.topframeref = virtual_ref(xy)
n -= externalfn(n)
exctx.topframeref = vref_None
- xy.next1 = None
- xy.next2 = None
- xy.next3 = None
- virtual_ref_check()
+ xy.next1 = lltype.nullptr(A)
+ xy.next2 = lltype.nullptr(A)
+ xy.next3 = lltype.nullptr(A)
virtual_ref_finish(xy)
#
self.meta_interp(f, [15])
- self.check_loops(new_with_vtable=2) # the vref, and xy so far,
- # but not xy.next1/2/3
+ self.check_loops(new_with_vtable=2, # the vref, and xy so far,
+ new_array=0) # but not xy.next1/2/3
self.check_aborted_count(0)
def test_simple_force_always(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
+ A = lltype.GcArray(lltype.Signed)
class XY:
pass
class ExCtx:
@@ -271,20 +174,27 @@
myjitdriver.can_enter_jit(n=n)
myjitdriver.jit_merge_point(n=n)
xy = XY()
+ xy.next1 = lltype.malloc(A, 0)
+ xy.next2 = lltype.malloc(A, 0)
+ xy.next3 = lltype.malloc(A, 0)
xy.n = n
exctx.topframeref = virtual_ref(xy)
n -= externalfn(n)
- virtual_ref_check()
+ xy.next1 = lltype.nullptr(A)
+ xy.next2 = lltype.nullptr(A)
+ xy.next3 = lltype.nullptr(A)
virtual_ref_finish(xy)
exctx.topframeref = vref_None
#
self.meta_interp(f, [15])
- self.check_loops({}) # because we aborted tracing
- self.check_aborted_count_at_least(1)
+ self.check_loops(new_with_vtable=2, # XY(), the vref
+ new_array=3) # next1/2/3
+ self.check_aborted_count(0)
def test_simple_force_sometimes(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
+ A = lltype.GcArray(lltype.Signed)
class XY:
pass
class ExCtx:
@@ -302,22 +212,30 @@
myjitdriver.can_enter_jit(n=n)
myjitdriver.jit_merge_point(n=n)
xy = XY()
+ xy.next1 = lltype.malloc(A, 0)
+ xy.next2 = lltype.malloc(A, 0)
+ xy.next3 = lltype.malloc(A, 0)
xy.n = n
exctx.topframeref = virtual_ref(xy)
n -= externalfn(n)
- virtual_ref_check()
+ xy.next1 = lltype.nullptr(A)
+ xy.next2 = lltype.nullptr(A)
+ xy.next3 = lltype.nullptr(A)
virtual_ref_finish(xy)
exctx.topframeref = vref_None
return exctx.m
#
res = self.meta_interp(f, [30])
assert res == 13
+ self.check_loops(new_with_vtable=2, # the vref, XY() at the end
+ new_array=0) # but not next1/2/3
self.check_loop_count(1)
self.check_aborted_count(0)
def test_blackhole_forces(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
+ A = lltype.GcArray(lltype.Signed)
class XY:
pass
class ExCtx:
@@ -334,24 +252,32 @@
myjitdriver.can_enter_jit(n=n)
myjitdriver.jit_merge_point(n=n)
xy = XY()
+ xy.next1 = lltype.malloc(A, 0)
+ xy.next2 = lltype.malloc(A, 0)
+ xy.next3 = lltype.malloc(A, 0)
xy.n = n
exctx.topframeref = virtual_ref(xy)
if n == 13:
externalfn(n)
n -= 1
exctx.topframeref = vref_None
- virtual_ref_check()
+ xy.next1 = lltype.nullptr(A)
+ xy.next2 = lltype.nullptr(A)
+ xy.next3 = lltype.nullptr(A)
virtual_ref_finish(xy)
return exctx.m
#
res = self.meta_interp(f, [30])
assert res == 13
+ self.check_loops(new_with_vtable=2, # the vref, XY() at the end
+ new_array=0) # but not next1/2/3
self.check_loop_count(1)
self.check_aborted_count(0)
def test_bridge_forces(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
+ A = lltype.GcArray(lltype.Signed)
class XY:
pass
class ExCtx:
@@ -368,20 +294,34 @@
myjitdriver.can_enter_jit(n=n)
myjitdriver.jit_merge_point(n=n)
xy = XY()
+ xy.next1 = lltype.malloc(A, 0)
+ xy.next2 = lltype.malloc(A, 0)
+ xy.next3 = lltype.malloc(A, 0)
+ xy.next4 = lltype.malloc(A, 0)
+ xy.next5 = lltype.malloc(A, 0)
xy.n = n
exctx.topframeref = virtual_ref(xy)
if n % 6 == 0:
+ xy.next1 = lltype.nullptr(A)
+ xy.next2 = lltype.nullptr(A)
+ xy.next3 = lltype.nullptr(A)
externalfn(n)
n -= 1
exctx.topframeref = vref_None
- virtual_ref_check()
+ xy.next1 = lltype.nullptr(A)
+ xy.next2 = lltype.nullptr(A)
+ xy.next3 = lltype.nullptr(A)
+ xy.next4 = lltype.nullptr(A)
+ xy.next5 = lltype.nullptr(A)
virtual_ref_finish(xy)
return exctx.m
#
res = self.meta_interp(f, [72])
assert res == 6
- self.check_loop_count(1) # the bridge should not be compiled
- self.check_aborted_count_at_least(1)
+ self.check_loop_count(2) # the loop and the bridge
+ self.check_loops(new_with_vtable=3, # loop: vref, xy; bridge: xy
+ new_array=2) # bridge: next4, next5
+ self.check_aborted_count(0)
def test_access_vref_later(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -406,7 +346,6 @@
exctx.later = exctx.topframeref
n -= 1
exctx.topframeref = vref_None
- virtual_ref_check()
virtual_ref_finish(xy)
return g()
#
@@ -417,6 +356,7 @@
def test_jit_force_virtual_seen(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
#
+ A = lltype.GcArray(lltype.Signed)
class XY:
pass
class ExCtx:
@@ -430,16 +370,18 @@
xy = XY()
xy.n = n
exctx.topframeref = virtual_ref(xy)
+ xy.next1 = lltype.malloc(A, 0)
n = exctx.topframeref().n - 1
+ xy.next1 = lltype.nullptr(A)
exctx.topframeref = vref_None
- virtual_ref_check()
virtual_ref_finish(xy)
return 1
#
res = self.meta_interp(f, [15])
assert res == 1
- self.check_loops({}) # because we aborted tracing
- self.check_aborted_count_at_least(1)
+ self.check_loops(new_with_vtable=2, # vref, xy
+ new_array=1) # next1
+ self.check_aborted_count(0)
def test_recursive_call_1(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'frame', 'rec'])
Modified: pypy/branch/virtual-forcing/pypy/rlib/jit.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/rlib/jit.py (original)
+++ pypy/branch/virtual-forcing/pypy/rlib/jit.py Sun Dec 13 17:02:46 2009
@@ -103,27 +103,17 @@
# VRefs
def virtual_ref(x):
+
"""Creates a 'vref' object that contains a reference to 'x'. Calls
to virtual_ref/virtual_ref_finish must be properly nested. The idea
- is that the object 'x' is supposed to be JITted as a virtual (the
- JIT will abort if it is not), at least between the calls to
- virtual_ref and virtual_ref_finish. The point is that the 'vref'
- returned by virtual_ref may escape early. If at runtime it is
- dereferenced (by the call syntax 'vref()') before the
- virtual_ref_finish, then we get out of the assembler. If it is not
- dereferenced at all, or only after the virtual_ref_finish, then
- nothing special occurs. Note that the checks for 'being virtual'
- only occurs when virtual_ref_check() is called (mostly for testing),
- or when jit_merge_point is called by JITted code in a recursive call.
- """
+ is that the object 'x' is supposed to be JITted as a virtual between
+ the calls to virtual_ref and virtual_ref_finish, but the 'vref'
+ object can escape at any point in time. If at runtime it is
+ dereferenced (by the call syntax 'vref()'), it returns 'x', which is
+ then forced."""
return DirectJitVRef(x)
virtual_ref.oopspec = 'virtual_ref(x)'
-def virtual_ref_check():
- from pypy.rpython.lltypesystem import lltype, lloperation
- lloperation.llop.jit_marker(lltype.Void,
- lloperation.void('virtual_ref_check'))
-
def virtual_ref_finish(x):
"""See docstring in virtual_ref(x). Note that virtual_ref_finish
takes as argument the real object, not the vref."""
More information about the Pypy-commit
mailing list