[pypy-svn] r69714 - in pypy/branch/virtual-forcing/pypy/jit: backend/llgraph backend/test backend/x86 metainterp metainterp/test
arigo at codespeak.net
arigo at codespeak.net
Fri Nov 27 22:40:47 CET 2009
Author: arigo
Date: Fri Nov 27 22:40:46 2009
New Revision: 69714
Modified:
pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py
pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
pypy/branch/virtual-forcing/pypy/jit/backend/x86/runner.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/codewriter.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/pyjitpl.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/typesystem.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py
pypy/branch/virtual-forcing/pypy/jit/metainterp/warmstate.py
Log:
(pedronis, arigo)
Progress. The tests pass, but the work is not done.
Modified: pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/llgraph/llimpl.py Fri Nov 27 22:40:46 2009
@@ -401,8 +401,10 @@
fail_args = []
if op.fail_args:
for fail_arg in op.fail_args:
- if fail_arg is None or fail_arg is skip:
+ if fail_arg is None:
fail_args.append(None)
+ elif fail_arg is skip:
+ fail_args.append(fail_arg.concretetype._defl())
else:
fail_args.append(self.getenv(fail_arg))
self.fail_args = fail_args
Modified: pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/test/runner_test.py Fri Nov 27 22:40:46 2009
@@ -1225,9 +1225,10 @@
values = []
def maybe_force(token, flag):
if flag:
- self.cpu.force(token)
- values.append(self.cpu.get_latest_value_int(0))
- values.append(self.cpu.get_latest_value_int(1))
+ descr = self.cpu.force(token)
+ values.append(descr)
+ values.append(self.cpu.get_latest_value_int(0))
+ values.append(self.cpu.get_latest_value_int(1))
FUNC = self.FuncType([lltype.Signed, lltype.Signed], lltype.Void)
func_ptr = llhelper(lltype.Ptr(FUNC), maybe_force)
@@ -1261,7 +1262,7 @@
assert fail.identifier == 1
assert self.cpu.get_latest_value_int(0) == 1
assert self.cpu.get_latest_value_int(1) == 10
- assert values == [1, 10]
+ assert values == [faildescr, 1, 10]
def test_force_operations_returning_int(self):
values = []
Modified: pypy/branch/virtual-forcing/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/backend/x86/runner.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/backend/x86/runner.py Fri Nov 27 22:40:46 2009
@@ -106,6 +106,7 @@
self.assembler.leave_jitted_hook()
# end of "no gc operation!" block
assert fail_index == fail_index_2
+ return faildescr
class CPU386_NO_SSE2(CPU386):
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 Fri Nov 27 22:40:46 2009
@@ -1214,6 +1214,7 @@
canraise = True # if we need to look into the delayed ptr that is
# the portal, then it's certainly going to raise
if pure:
+ assert not calldescr.effectinfo.promotes_virtualizables
self.emit('residual_call_pure')
elif canraise:
self.emit('residual_call')
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/compile.py Fri Nov 27 22:40:46 2009
@@ -221,6 +221,7 @@
if box:
fail_arg_types[i] = box.type
self.fail_arg_types = fail_arg_types
+ # XXX ^^^ kill this attribute
def handle_fail(self, metainterp_sd):
from pypy.jit.metainterp.pyjitpl import MetaInterp
@@ -236,6 +237,17 @@
send_bridge_to_backend(metainterp.staticdata, self, inputargs,
new_loop.operations)
+ def force_virtualizable(self, vinfo, virtualizable):
+ from pypy.jit.metainterp.pyjitpl import MetaInterp
+ from pypy.jit.metainterp.resume import force_from_resumedata
+ metainterp = MetaInterp(self.metainterp_sd)
+ metainterp.history = None # blackholing
+ liveboxes = metainterp.load_values_from_failure(self)
+ virtualizable_boxes = force_from_resumedata(metainterp,
+ liveboxes, self)
+ vinfo.write_boxes(virtualizable, virtualizable_boxes)
+
+
class ResumeFromInterpDescr(ResumeDescr):
def __init__(self, original_greenkey, redkey):
ResumeDescr.__init__(self, original_greenkey)
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/effectinfo.py Fri Nov 27 22:40:46 2009
@@ -8,7 +8,7 @@
_cache = {}
def __new__(cls, write_descrs_fields, write_descrs_arrays,
- promotes_virtualizables):
+ promotes_virtualizables=False):
key = (frozenset(write_descrs_fields), frozenset(write_descrs_arrays),
promotes_virtualizables)
if key in cls._cache:
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 Fri Nov 27 22:40:46 2009
@@ -632,6 +632,7 @@
varargs = [jitcode.cfnptr] + varargs
res = self.execute_varargs(rop.CALL, varargs,
descr=jitcode.calldescr, exc=True)
+ self.metainterp.load_fields_from_virtualizable()
else:
# for oosends (ootype only): calldescr is a MethDescr
res = self.execute_varargs(rop.OOSEND, varargs,
@@ -651,7 +652,7 @@
@arguments("descr", "varargs")
def opimpl_residual_call(self, calldescr, varargs):
- return self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=True)
+ return self.do_residual_call(varargs, descr=calldescr, exc=True)
@arguments("varargs")
def opimpl_recursion_leave_prep(self, varargs):
@@ -675,11 +676,11 @@
greenkey = varargs[1:num_green_args + 1]
if warmrunnerstate.can_inline_callable(greenkey):
return self.perform_call(portal_code, varargs[1:], greenkey)
- return self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=True)
+ return self.do_residual_call(varargs, descr=calldescr, exc=True)
@arguments("descr", "varargs")
def opimpl_residual_call_noexception(self, calldescr, varargs):
- self.execute_varargs(rop.CALL, varargs, descr=calldescr, exc=False)
+ self.do_residual_call(varargs, descr=calldescr, exc=False)
@arguments("descr", "varargs")
def opimpl_residual_call_pure(self, calldescr, varargs):
@@ -696,8 +697,8 @@
return self.perform_call(jitcode, varargs)
else:
# but we should not follow calls to that graph
- return self.execute_varargs(rop.CALL, [box] + varargs,
- descr=calldescr, exc=True)
+ return self.do_residual_call([box] + varargs,
+ descr=calldescr, exc=True)
@arguments("orgpc", "methdescr", "varargs")
def opimpl_oosend(self, pc, methdescr, varargs):
@@ -980,6 +981,24 @@
return self.metainterp.handle_exception()
return False
+ def do_residual_call(self, argboxes, descr, exc):
+ effectinfo = descr.get_extra_info()
+ if effectinfo is None or effectinfo.promotes_virtualizables:
+ # residual calls require attention to keep virtualizables in-sync
+ self.metainterp.vable_before_residual_call()
+ # xxx do something about code duplication
+ resbox = self.metainterp.execute_and_record_varargs(
+ rop.CALL_MAY_FORCE, argboxes, descr=descr)
+ self.metainterp.vable_after_residual_call()
+ if resbox is not None:
+ self.make_result_box(resbox)
+ self.generate_guard(self.pc, rop.GUARD_NOT_FORCED, None, [])
+ if exc:
+ return self.metainterp.handle_exception()
+ return False
+ else:
+ return self.execute_varargs(rop.CALL, argboxes, descr, exc)
+
# ____________________________________________________________
class MetaInterpStaticData(object):
@@ -1298,7 +1317,8 @@
@specialize.arg(1)
def execute_and_record(self, opnum, descr, *argboxes):
history.check_descr(descr)
- assert opnum != rop.CALL and opnum != rop.OOSEND
+ assert (opnum != rop.CALL and opnum != rop.CALL_MAY_FORCE
+ and opnum != rop.OOSEND)
# execute the operation
profiler = self.staticdata.profiler
profiler.count_ops(opnum)
@@ -1315,12 +1335,6 @@
@specialize.arg(1)
def execute_and_record_varargs(self, opnum, argboxes, descr=None):
history.check_descr(descr)
- # residual calls require attention to keep virtualizables in-sync.
- # CALL_PURE doesn't need it because so far 'promote_virtualizable'
- # as an operation is enough to make the called function non-pure.
- is_a_call = (opnum == rop.CALL or opnum == rop.OOSEND)
- if is_a_call:
- self.before_residual_call()
# execute the operation
profiler = self.staticdata.profiler
profiler.count_ops(opnum)
@@ -1334,8 +1348,6 @@
resbox = self._record_helper_pure_varargs(opnum, resbox, descr, argboxes)
else:
resbox = self._record_helper_nonpure_varargs(opnum, resbox, descr, argboxes)
- if is_a_call:
- self.after_residual_call()
return resbox
def _record_helper_pure(self, opnum, resbox, descr, *argboxes):
@@ -1719,9 +1731,9 @@
vinfo = self.staticdata.virtualizable_info
virtualizable_box = self.virtualizable_boxes[-1]
virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
- vinfo.clear_vable_rti(virtualizable)
+ vinfo.clear_vable_token(virtualizable)
- def before_residual_call(self):
+ def vable_before_residual_call(self):
if self.is_blackholing():
return
vinfo = self.staticdata.virtualizable_info
@@ -1729,8 +1741,14 @@
virtualizable_box = self.virtualizable_boxes[-1]
virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
vinfo.tracing_before_residual_call(virtualizable)
+ #
+ force_token_box = history.BoxInt()
+ self.history.record(rop.FORCE_TOKEN, [], force_token_box)
+ self.history.record(rop.SETFIELD_GC, [virtualizable_box,
+ force_token_box],
+ None, descr=vinfo.vable_token_descr)
- def after_residual_call(self):
+ def vable_after_residual_call(self):
if self.is_blackholing():
vable_escapes = True
else:
@@ -1787,7 +1805,7 @@
# is and stays NULL.
virtualizable_box = self.virtualizable_boxes[-1]
virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
- assert not virtualizable.vable_rti
+ assert not virtualizable.vable_token
self.synchronize_virtualizable()
def check_synchronized_virtualizable(self):
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/resume.py Fri Nov 27 22:40:46 2009
@@ -455,6 +455,10 @@
metainterp.framestack.reverse()
return virtualizable_boxes
+def force_from_resumedata(metainterp, newboxes, storage):
+ resumereader = ResumeDataReader(storage, newboxes, metainterp)
+ return resumereader.consume_boxes()
+
class ResumeDataReader(object):
virtuals = None
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/test/test_virtualizable.py Fri Nov 27 22:40:46 2009
@@ -7,7 +7,6 @@
from pypy.rlib.jit import OPTIMIZER_SIMPLE, OPTIMIZER_FULL
from pypy.rlib.rarithmetic import intmask
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-from pypy.rpython.lltypesystem.rvirtualizable2 import VABLERTIPTR
from pypy.rpython.rclass import FieldListAccessor
from pypy.jit.metainterp.warmspot import get_stats, get_translator
from pypy.jit.metainterp import history, heaptracker
@@ -41,8 +40,7 @@
XY = lltype.GcStruct(
'XY',
('parent', rclass.OBJECT),
- ('vable_base', llmemory.Address),
- ('vable_rti', VABLERTIPTR),
+ ('vable_token', lltype.Signed),
('inst_x', lltype.Signed),
('inst_node', lltype.Ptr(LLtypeMixin.NODE)),
hints = {'virtualizable2_accessor': FieldListAccessor()})
@@ -57,7 +55,7 @@
def setup(self):
xy = lltype.malloc(self.XY)
- xy.vable_rti = lltype.nullptr(VABLERTIPTR.TO)
+ xy.vable_token = 0
xy.parent.typeptr = self.xy_vtable
return xy
@@ -205,8 +203,7 @@
XY2 = lltype.GcStruct(
'XY2',
('parent', rclass.OBJECT),
- ('vable_base', llmemory.Address),
- ('vable_rti', VABLERTIPTR),
+ ('vable_token', lltype.Signed),
('inst_x', lltype.Signed),
('inst_l1', lltype.Ptr(lltype.GcArray(lltype.Signed))),
('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))),
@@ -219,7 +216,7 @@
def setup2(self):
xy2 = lltype.malloc(self.XY2)
- xy2.vable_rti = lltype.nullptr(VABLERTIPTR.TO)
+ xy2.vable_token = 0
xy2.parent.typeptr = self.xy2_vtable
return xy2
@@ -392,7 +389,7 @@
def setup2sub(self):
xy2 = lltype.malloc(self.XY2SUB)
- xy2.parent.vable_rti = lltype.nullptr(VABLERTIPTR.TO)
+ xy2.parent.vable_token = 0
xy2.parent.parent.typeptr = self.xy2_vtable
return xy2
@@ -619,8 +616,8 @@
self.check_tree_loop_count(0)
def test_external_read_sometimes(self):
- py.test.skip("known bug: access the frame in a residual call but"
- " only sometimes, so that it's not seen during tracing")
+ #py.test.skip("known bug: access the frame in a residual call but"
+ # " only sometimes, so that it's not seen during tracing")
jitdriver = JitDriver(greens = [], reds = ['frame'],
virtualizables = ['frame'])
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/typesystem.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/typesystem.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/typesystem.py Fri Nov 27 22:40:46 2009
@@ -49,10 +49,6 @@
CONST_NULL = history.ConstPtr(history.ConstPtr.value)
CVAL_NULLREF = None # patched by optimizeopt.py
- def get_VABLERTI(self):
- from pypy.rpython.lltypesystem.rvirtualizable2 import VABLERTIPTR
- return VABLERTIPTR
-
def new_ConstRef(self, x):
ptrval = lltype.cast_opaque_ptr(llmemory.GCREF, x)
return history.ConstPtr(ptrval)
@@ -159,10 +155,6 @@
loops_done_with_this_frame_ref = None # patched by compile.py
CONST_NULL = history.ConstObj(history.ConstObj.value)
CVAL_NULLREF = None # patched by optimizeopt.py
-
- def get_VABLERTI(self):
- from pypy.rpython.ootypesystem.rvirtualizable2 import VABLERTI
- return VABLERTI
def new_ConstRef(self, x):
obj = ootype.cast_to_object(x)
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/virtualizable.py Fri Nov 27 22:40:46 2009
@@ -4,19 +4,24 @@
from pypy.rpython import rvirtualizable2
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib.nonconst import NonConstant
from pypy.jit.metainterp.typesystem import deref, fieldType, arrayItem
from pypy.jit.metainterp import history
from pypy.jit.metainterp.warmstate import wrap, unwrap
class VirtualizableInfo:
+ token_none = 0
+ token_tracing = -1
+
def __init__(self, warmrunnerdesc):
self.warmrunnerdesc = warmrunnerdesc
jitdriver = warmrunnerdesc.jitdriver
cpu = warmrunnerdesc.cpu
+ if cpu.ts.name == 'ootype':
+ import py
+ py.test.skip("ootype: fix virtualizables")
self.cpu = cpu
- self.VABLERTI = cpu.ts.get_VABLERTI()
- self.null_vable_rti = cpu.ts.nullptr(deref(self.VABLERTI))
self.BoxArray = cpu.ts.BoxRef
#
assert len(jitdriver.virtualizables) == 1 # for now
@@ -29,6 +34,7 @@
self.VTYPEPTR = VTYPEPTR
self.VTYPE = VTYPE = deref(VTYPEPTR)
self.null_vable = cpu.ts.nullptr(VTYPE)
+ self.vable_token_descr = cpu.fielddescrof(VTYPE, 'vable_token')
#
accessor = VTYPE._hints['virtualizable2_accessor']
all_fields = accessor.fields
@@ -148,7 +154,7 @@
def finish(self):
#
def force_if_necessary(virtualizable):
- if virtualizable.vable_rti:
+ if virtualizable.vable_token:
self.force_now(virtualizable)
force_if_necessary._always_inline_ = True
#
@@ -169,72 +175,55 @@
def is_vtypeptr(self, TYPE):
return rvirtualizable2.match_virtualizable_type(TYPE, self.VTYPEPTR)
- def cast_instance_to_base_ptr(self, vable_rti):
- if we_are_translated():
- return self.cpu.ts.cast_instance_to_base_ref(vable_rti)
- else:
- vable_rti._TYPE = self.VABLERTI # hack for non-translated mode
- return vable_rti
+ def reset_vable_token(self, virtualizable):
+ virtualizable.vable_token = self.token_none
- def clear_vable_rti(self, virtualizable):
- if virtualizable.vable_rti:
+ def clear_vable_token(self, virtualizable):
+ if virtualizable.vable_token:
self.force_now(virtualizable)
- assert not virtualizable.vable_rti
+ assert not virtualizable.vable_token
def tracing_before_residual_call(self, virtualizable):
- assert not virtualizable.vable_rti
- ptr = self.cast_instance_to_base_ptr(tracing_vable_rti)
- virtualizable.vable_rti = ptr
+ assert not virtualizable.vable_token
+ virtualizable.vable_token = self.token_tracing
def tracing_after_residual_call(self, virtualizable):
- if virtualizable.vable_rti:
+ if virtualizable.vable_token:
# not modified by the residual call; assert that it is still
# set to 'tracing_vable_rti' and clear it.
- ptr = self.cast_instance_to_base_ptr(tracing_vable_rti)
- assert virtualizable.vable_rti == ptr
- virtualizable.vable_rti = self.null_vable_rti
+ assert virtualizable.vable_token == self.token_tracing
+ virtualizable.vable_token = self.token_none
return False
else:
# marker "modified during residual call" set.
return True
def force_now(self, virtualizable):
- rti = virtualizable.vable_rti
- virtualizable.vable_rti = self.null_vable_rti
- if we_are_translated():
- rti = cast_base_ptr_to_instance(AbstractVableRti, rti)
- rti.force_now(virtualizable)
+ token = virtualizable.vable_token
+ virtualizable.vable_token = self.token_none
+ if token == self.token_tracing:
+ # The values in the virtualizable are always correct during
+ # tracing. We only need to reset vable_token to token_none
+ # as a marker for the tracing, to tell it that this
+ # virtualizable escapes.
+ pass
+ else:
+ faildescr = self.cpu.force(token)
+ faildescr.force_virtualizable(self, virtualizable)
force_now._dont_inline_ = True
# ____________________________________________________________
#
-# The 'vable_rti' field of a virtualizable is either NULL or points
-# to an instance of the following classes. It is:
+# The 'vable_token' field of a virtualizable is either 0, -1, or points
+# into the CPU stack to a particular field in the current frame. It is:
#
-# 1. NULL if not in the JIT at all, except as described below.
+# 1. 0 (token_none) if not in the JIT at all, except as described below.
#
-# 2. always NULL when tracing is in progress.
+# 2. equal to 0 when tracing is in progress; except:
#
-# 3. 'tracing_vable_rti' during tracing when we do a residual call,
+# 3. equal to -1 (token_tracing) during tracing when we do a residual call,
# calling random unknown other parts of the interpreter; it is
-# reset to NULL as soon as something occurs to the virtualizable.
+# reset to 0 as soon as something occurs to the virtualizable.
#
-# 4. NULL for now when running the machine code with a virtualizable;
-# later it will be a RunningVableRti().
-
-
-class AbstractVableRti(object):
-
- def force_now(self, virtualizable):
- raise NotImplementedError
-
-
-class TracingVableRti(AbstractVableRti):
-
- def force_now(self, virtualizable):
- # The values if the virtualizable are always correct during tracing.
- # We only need to set a marker to tell that forcing occurred.
- # As the caller resets vable_rti to NULL, it plays the role of marker.
- pass
-
-tracing_vable_rti = TracingVableRti()
+# 4. when running the machine code with a virtualizable, it is set
+# to the address in the CPU stack by the FORCE_TOKEN operation.
Modified: pypy/branch/virtual-forcing/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/branch/virtual-forcing/pypy/jit/metainterp/warmstate.py (original)
+++ pypy/branch/virtual-forcing/pypy/jit/metainterp/warmstate.py Fri Nov 27 22:40:46 2009
@@ -213,6 +213,8 @@
virtualizable = vinfo.cast_to_vtype(virtualizable)
assert virtualizable != globaldata.blackhole_virtualizable, (
"reentering same frame via blackhole")
+ else:
+ virtualizable = None
# look for the cell corresponding to the current greenargs
greenargs = args[:num_green_args]
@@ -247,6 +249,8 @@
fail_descr = metainterp_sd.cpu.execute_token(loop_token)
debug_stop("jit-running")
metainterp_sd.profiler.end_running()
+ if vinfo is not None:
+ vinfo.reset_vable_token(virtualizable)
loop_token = fail_descr.handle_fail(metainterp_sd)
maybe_compile_and_run._dont_inline_ = True
More information about the Pypy-commit
mailing list