[pypy-svn] r69570 - in pypy/trunk/pypy: . interpreter jit/backend/llgraph jit/backend/llvm/test jit/backend/test jit/backend/x86 jit/backend/x86/test jit/metainterp jit/metainterp/test module/exceptions objspace/std/test translator/c/test
pedronis at codespeak.net
pedronis at codespeak.net
Tue Nov 24 11:08:44 CET 2009
Author: pedronis
Date: Tue Nov 24 11:08:43 2009
New Revision: 69570
Modified:
pypy/trunk/pypy/ (props changed)
pypy/trunk/pypy/interpreter/executioncontext.py
pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
pypy/trunk/pypy/jit/backend/llgraph/runner.py
pypy/trunk/pypy/jit/backend/llvm/test/conftest.py (props changed)
pypy/trunk/pypy/jit/backend/test/runner_test.py
pypy/trunk/pypy/jit/backend/x86/assembler.py
pypy/trunk/pypy/jit/backend/x86/regalloc.py
pypy/trunk/pypy/jit/backend/x86/test/test_gc_integration.py (props changed)
pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py
pypy/trunk/pypy/jit/metainterp/compile.py
pypy/trunk/pypy/jit/metainterp/history.py
pypy/trunk/pypy/jit/metainterp/jitprof.py
pypy/trunk/pypy/jit/metainterp/logger.py (contents, props changed)
pypy/trunk/pypy/jit/metainterp/optimizeopt.py
pypy/trunk/pypy/jit/metainterp/pyjitpl.py
pypy/trunk/pypy/jit/metainterp/resume.py
pypy/trunk/pypy/jit/metainterp/simple_optimize.py
pypy/trunk/pypy/jit/metainterp/test/oparser.py
pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py
pypy/trunk/pypy/jit/metainterp/test/test_logger.py
pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py
pypy/trunk/pypy/jit/metainterp/test/test_resume.py
pypy/trunk/pypy/jit/metainterp/test/test_virtual.py
pypy/trunk/pypy/module/exceptions/ (props changed)
pypy/trunk/pypy/objspace/std/test/test_setobject.py (props changed)
pypy/trunk/pypy/translator/c/test/test_refcount.py (props changed)
Log:
merge compress-virtuals-resumedata(2)
(cfbolz, pedronis)
reuse vinfos by making virtuals and boxes out of them (and not the environment) have more stable numberings
by introducing holes (None) in fail_args
Modified: pypy/trunk/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/trunk/pypy/interpreter/executioncontext.py (original)
+++ pypy/trunk/pypy/interpreter/executioncontext.py Tue Nov 24 11:08:43 2009
@@ -142,6 +142,8 @@
#assert frame is self.gettopframe() --- slowish
if self.some_frame is frame:
self.some_frame = frame.f_back_some
+ if self.some_frame and self.some_frame.f_forward:
+ raise Exception()
else:
f_back = frame.f_back()
if f_back is not None:
Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py (original)
+++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py Tue Nov 24 11:08:43 2009
@@ -364,7 +364,10 @@
op = loop.operations[-1]
if op.fail_args is None:
op.fail_args = []
- op.fail_args.append(_variables[intvar])
+ if intvar == -1:
+ op.fail_args.append(None)
+ else:
+ op.fail_args.append(_variables[intvar])
def compile_redirect_fail(old_loop, old_index, new_loop):
old_loop = _from_opaque(old_loop)
@@ -407,23 +410,27 @@
except GuardFailed:
assert op.is_guard()
_stats.exec_conditional_jumps += 1
- if op.fail_args:
- args = [self.getenv(v) for v in op.fail_args]
- else:
- args = []
if op.jump_target is not None:
# a patched guard, pointing to further code
+ args = [self.getenv(v) for v in op.fail_args if v]
assert len(op.jump_target.inputargs) == len(args)
self.env = dict(zip(op.jump_target.inputargs, args))
operations = op.jump_target.operations
opindex = 0
continue
else:
+ fail_args = []
+ if op.fail_args:
+ for fail_arg in op.fail_args:
+ if fail_arg is None:
+ fail_args.append(None)
+ else:
+ fail_args.append(self.getenv(fail_arg))
# a non-patched guard
if self.verbose:
log.trace('failed: %s' % (
- ', '.join(map(str, args)),))
- self.fail_args = args
+ ', '.join(map(str, fail_args)),))
+ self.fail_args = fail_args
return op.fail_index
#verbose = self.verbose
assert (result is None) == (op.result is None)
Modified: pypy/trunk/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/runner.py (original)
+++ pypy/trunk/pypy/jit/backend/llgraph/runner.py Tue Nov 24 11:08:43 2009
@@ -171,7 +171,10 @@
index = llimpl.compile_add_fail(c, fail_index)
faildescr._compiled_fail = c, index
for box in op.fail_args:
- llimpl.compile_add_fail_arg(c, var2index[box])
+ if box is not None:
+ llimpl.compile_add_fail_arg(c, var2index[box])
+ else:
+ llimpl.compile_add_fail_arg(c, -1)
x = op.result
if x is not None:
if isinstance(x, history.BoxInt):
Modified: pypy/trunk/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/test/runner_test.py (original)
+++ pypy/trunk/pypy/jit/backend/test/runner_test.py Tue Nov 24 11:08:43 2009
@@ -125,6 +125,27 @@
res = self.cpu.get_latest_value_int(0)
assert res == 10
+ def test_compile_with_holes_in_fail_args(self):
+ i0 = BoxInt()
+ i1 = BoxInt()
+ i2 = BoxInt()
+ looptoken = LoopToken()
+ operations = [
+ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
+ ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
+ ResOperation(rop.GUARD_TRUE, [i2], None, descr=BasicFailDescr(2)),
+ ResOperation(rop.JUMP, [i1], None, descr=looptoken),
+ ]
+ inputargs = [i0]
+ operations[2].fail_args = [None, None, i1, None]
+
+ self.cpu.compile_loop(inputargs, operations, looptoken)
+ self.cpu.set_future_value_int(0, 2)
+ fail = self.cpu.execute_token(looptoken)
+ assert fail == 2
+ res = self.cpu.get_latest_value_int(2)
+ assert res == 10
+
def test_backends_dont_keep_loops_alive(self):
import weakref, gc
self.cpu.dont_keepalive_stuff = True
@@ -183,6 +204,40 @@
res = self.cpu.get_latest_value_int(0)
assert res == 20
+ def test_compile_bridge_with_holes(self):
+ i0 = BoxInt()
+ i1 = BoxInt()
+ i2 = BoxInt()
+ faildescr1 = BasicFailDescr(1)
+ faildescr2 = BasicFailDescr(2)
+ looptoken = LoopToken()
+ operations = [
+ ResOperation(rop.INT_ADD, [i0, ConstInt(1)], i1),
+ ResOperation(rop.INT_LE, [i1, ConstInt(9)], i2),
+ ResOperation(rop.GUARD_TRUE, [i2], None, descr=faildescr1),
+ ResOperation(rop.JUMP, [i1], None, descr=looptoken),
+ ]
+ inputargs = [i0]
+ operations[2].fail_args = [None, i1, None]
+ self.cpu.compile_loop(inputargs, operations, looptoken)
+
+ i1b = BoxInt()
+ i3 = BoxInt()
+ bridge = [
+ ResOperation(rop.INT_LE, [i1b, ConstInt(19)], i3),
+ ResOperation(rop.GUARD_TRUE, [i3], None, descr=faildescr2),
+ ResOperation(rop.JUMP, [i1b], None, descr=looptoken),
+ ]
+ bridge[1].fail_args = [i1b]
+
+ self.cpu.compile_bridge(faildescr1, [i1b], bridge)
+
+ self.cpu.set_future_value_int(0, 2)
+ fail = self.cpu.execute_token(looptoken)
+ assert fail == 2
+ res = self.cpu.get_latest_value_int(0)
+ assert res == 20
+
def test_finish(self):
i0 = BoxInt()
class UntouchableFailDescr(AbstractFailDescr):
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 Tue Nov 24 11:08:43 2009
@@ -738,7 +738,7 @@
""" assert that all args are actually Boxes
"""
for arg in args:
- assert isinstance(arg, Box)
+ assert arg is None or isinstance(arg, Box) # hole
def implement_guard_recovery(self, guard_opnum, faildescr, failargs,
fail_locs):
@@ -754,6 +754,8 @@
pos = mc.tell()
for i in range(len(failargs)):
arg = failargs[i]
+ if arg is None: # hole
+ continue
loc = locs[i]
if isinstance(loc, REG):
if arg.type == FLOAT:
@@ -767,6 +769,8 @@
mc.MOV(heap(adr), loc)
for i in range(len(failargs)):
arg = failargs[i]
+ if arg is None: # hole
+ continue
loc = locs[i]
if not isinstance(loc, REG):
if arg.type == FLOAT:
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 Tue Nov 24 11:08:43 2009
@@ -203,7 +203,8 @@
def possibly_free_vars(self, vars):
for var in vars:
- self.possibly_free_var(var)
+ if var is not None: # xxx kludgy
+ self.possibly_free_var(var)
def make_sure_var_in_reg(self, var, forbidden_vars=[],
selected_reg=None, imm_fine=True,
@@ -239,9 +240,12 @@
def _update_bindings(self, locs, inputargs):
# XXX this should probably go to llsupport/regalloc.py
used = {}
- for i in range(len(inputargs)):
+ i = 0
+ for loc in locs:
+ if loc is None: # xxx bit kludgy
+ continue
arg = inputargs[i]
- loc = locs[i]
+ i += 1
if arg.type == FLOAT:
if isinstance(loc, REG):
self.xrm.reg_bindings[arg] = loc
@@ -360,6 +364,8 @@
longevity[arg] = (start_live[arg], i)
if op.is_guard():
for arg in op.fail_args:
+ if arg is None: # hole
+ continue
assert isinstance(arg, Box)
if arg not in start_live:
print "Bogus arg in guard %d at %d" % (op.opnum, i)
@@ -373,6 +379,8 @@
return longevity
def loc(self, v):
+ if v is None: # xxx kludgy
+ return None
if v.type == FLOAT:
return self.xrm.loc(v)
return self.rm.loc(v)
Modified: pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_virtual.py Tue Nov 24 11:08:43 2009
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.test.test_virtual import VirtualTests
+from pypy.jit.metainterp.test.test_virtual import VirtualTests, VirtualMiscTests
from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
class MyClass:
@@ -13,3 +13,8 @@
@staticmethod
def _new():
return MyClass()
+
+class TestsVirtualMisc(Jit386Mixin, VirtualMiscTests):
+ # for the individual tests see
+ # ====> ../../../metainterp/test/test_virtual.py
+ pass
Modified: pypy/trunk/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/compile.py (original)
+++ pypy/trunk/pypy/jit/metainterp/compile.py Tue Nov 24 11:08:43 2009
@@ -233,7 +233,12 @@
def store_final_boxes(self, guard_op, boxes):
guard_op.fail_args = boxes
self.guard_opnum = guard_op.opnum
- self.fail_arg_types = [box.type for box in boxes]
+ fail_arg_types = [history.HOLE] * len(boxes)
+ for i in range(len(boxes)):
+ box = boxes[i]
+ if box:
+ fail_arg_types[i] = box.type
+ self.fail_arg_types = fail_arg_types
def handle_fail(self, metainterp_sd):
from pypy.jit.metainterp.pyjitpl import MetaInterp
Modified: pypy/trunk/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/history.py (original)
+++ pypy/trunk/pypy/jit/metainterp/history.py Tue Nov 24 11:08:43 2009
@@ -15,6 +15,7 @@
INT = 'i'
REF = 'r'
FLOAT = 'f'
+HOLE = '_'
FAILARGS_LIMIT = 1000
@@ -756,8 +757,9 @@
ops = op.descr._debug_suboperations
TreeLoop.check_consistency_of_branch(ops, seen.copy())
for box in op.fail_args or []:
- assert isinstance(box, Box)
- assert box in seen
+ if box is not None:
+ assert isinstance(box, Box)
+ assert box in seen
else:
assert op.fail_args is None
box = op.result
Modified: pypy/trunk/pypy/jit/metainterp/jitprof.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/jitprof.py (original)
+++ pypy/trunk/pypy/jit/metainterp/jitprof.py Tue Nov 24 11:08:43 2009
@@ -20,6 +20,9 @@
OPT_FORCINGS
ABORT_TOO_LONG
ABORT_BRIDGE
+NVIRTUALS
+NVHOLES
+NVREUSED
"""
def _setup():
@@ -175,6 +178,9 @@
self._print_intline("forcings", cnt[OPT_FORCINGS])
self._print_intline("trace too long", cnt[ABORT_TOO_LONG])
self._print_intline("bridge abort", cnt[ABORT_BRIDGE])
+ self._print_intline("nvirtuals", cnt[NVIRTUALS])
+ self._print_intline("nvholes", cnt[NVHOLES])
+ self._print_intline("nvreused", cnt[NVREUSED])
def _print_line_time(self, string, i, tim):
final = "%s:%s\t%d\t%f\n" % (string, " " * max(0, 13-len(string)), i, tim)
Modified: pypy/trunk/pypy/jit/metainterp/logger.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/logger.py (original)
+++ pypy/trunk/pypy/jit/metainterp/logger.py Tue Nov 24 11:08:43 2009
@@ -63,6 +63,8 @@
if not name:
name = 'cls' + str(mv)
return 'ConstClass(' + name + ')'
+ elif arg is None:
+ return 'None'
else:
return '?'
Modified: pypy/trunk/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/trunk/pypy/jit/metainterp/optimizeopt.py Tue Nov 24 11:08:43 2009
@@ -2,7 +2,7 @@
ConstFloat
from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstObj, REF
from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.metainterp.jitprof import OPT_OPS, OPT_GUARDS, OPT_FORCINGS
+from pypy.jit.metainterp import jitprof
from pypy.jit.metainterp.executor import execute_nonspec
from pypy.jit.metainterp.specnode import SpecNode, NotSpecNode, ConstantSpecNode
from pypy.jit.metainterp.specnode import AbstractVirtualStructSpecNode
@@ -62,6 +62,9 @@
def get_args_for_fail(self, modifier):
pass
+ def make_virtual_info(self, modifier, fieldnums):
+ raise NotImplementedError # should not be called on this level
+
def is_constant(self):
return self.level == LEVEL_CONSTANT
@@ -134,9 +137,10 @@
class AbstractVirtualValue(OptValue):
- _attrs_ = ('optimizer', 'keybox', 'source_op')
+ _attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo')
box = None
level = LEVEL_NONNULL
+ _cached_vinfo = None
def __init__(self, optimizer, keybox, source_op=None):
self.optimizer = optimizer
@@ -155,6 +159,19 @@
self._really_force()
return self.box
+ def make_virtual_info(self, modifier, fieldnums):
+ vinfo = self._cached_vinfo
+ if vinfo is not None and resume.tagged_list_eq(
+ vinfo.fieldnums, fieldnums):
+ return vinfo
+ vinfo = self._make_virtual(modifier)
+ vinfo.fieldnums = fieldnums
+ self._cached_vinfo = vinfo
+ return vinfo
+
+ def _make_virtual(self, modifier):
+ raise NotImplementedError("abstract base")
+
class AbstractVirtualStructValue(AbstractVirtualValue):
_attrs_ = ('_fields', '_cached_sorted_fields')
@@ -207,14 +224,11 @@
# we have already seen the very same keybox
lst = self._get_field_descr_list()
fieldboxes = [self._fields[ofs].get_key_box() for ofs in lst]
- self._make_virtual(modifier, lst, fieldboxes)
+ modifier.register_virtual_fields(self.keybox, fieldboxes)
for ofs in lst:
fieldvalue = self._fields[ofs]
fieldvalue.get_args_for_fail(modifier)
- def _make_virtual(self, modifier, fielddescrs, fieldboxes):
- raise NotImplementedError
-
class VirtualValue(AbstractVirtualStructValue):
level = LEVEL_KNOWNCLASS
@@ -224,10 +238,9 @@
assert isinstance(known_class, Const)
self.known_class = known_class
- def _make_virtual(self, modifier, fielddescrs, fieldboxes):
- modifier.make_virtual(self.keybox, self.known_class,
- fielddescrs, fieldboxes)
-
+ def _make_virtual(self, modifier):
+ fielddescrs = self._get_field_descr_list()
+ return modifier.make_virtual(self.known_class, fielddescrs)
class VStructValue(AbstractVirtualStructValue):
@@ -235,10 +248,9 @@
AbstractVirtualStructValue.__init__(self, optimizer, keybox, source_op)
self.structdescr = structdescr
- def _make_virtual(self, modifier, fielddescrs, fieldboxes):
- modifier.make_vstruct(self.keybox, self.structdescr,
- fielddescrs, fieldboxes)
-
+ def _make_virtual(self, modifier):
+ fielddescrs = self._get_field_descr_list()
+ return modifier.make_vstruct(self.structdescr, fielddescrs)
class VArrayValue(AbstractVirtualValue):
@@ -282,11 +294,14 @@
const = self.optimizer.new_const_item(self.arraydescr)
for itemvalue in self._items:
itemboxes.append(itemvalue.get_key_box())
- modifier.make_varray(self.keybox, self.arraydescr, itemboxes)
+ modifier.register_virtual_fields(self.keybox, itemboxes)
for itemvalue in self._items:
if itemvalue is not self.constvalue:
itemvalue.get_args_for_fail(modifier)
+ def _make_virtual(self, modifier):
+ return modifier.make_varray(self.arraydescr)
+
class __extend__(SpecNode):
def setup_virtual_node(self, optimizer, box, newinputargs):
raise NotImplementedError
@@ -354,12 +369,12 @@
self.loop = loop
self.values = {}
self.interned_refs = self.cpu.ts.new_ref_dict()
- self.resumedata_memo = resume.ResumeDataLoopMemo(self.cpu)
+ self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd)
self.heap_op_optimizer = HeapOpOptimizer(self)
self.bool_boxes = {}
def forget_numberings(self, virtualbox):
- self.metainterp_sd.profiler.count(OPT_FORCINGS)
+ self.metainterp_sd.profiler.count(jitprof.OPT_FORCINGS)
self.resumedata_memo.forget_numberings(virtualbox)
def getinterned(self, box):
@@ -480,6 +495,8 @@
else:
self.optimize_default(op)
self.loop.operations = self.newoperations
+ # accumulate counters
+ self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
def emit_operation(self, op, must_clone=True):
self.heap_op_optimizer.emitting_operation(op)
@@ -492,9 +509,9 @@
op = op.clone()
must_clone = False
op.args[i] = box
- self.metainterp_sd.profiler.count(OPT_OPS)
+ self.metainterp_sd.profiler.count(jitprof.OPT_OPS)
if op.is_guard():
- self.metainterp_sd.profiler.count(OPT_GUARDS)
+ self.metainterp_sd.profiler.count(jitprof.OPT_GUARDS)
self.store_final_boxes_in_guard(op)
elif op.can_raise():
self.exception_might_have_happened = True
@@ -507,7 +524,7 @@
assert isinstance(descr, compile.ResumeGuardDescr)
modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
newboxes = modifier.finish(self.values)
- if len(newboxes) > self.metainterp_sd.options.failargs_limit:
+ if len(newboxes) > self.metainterp_sd.options.failargs_limit: # XXX be careful here
raise compile.GiveUp
descr.store_final_boxes(op, newboxes)
#
Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Nov 24 11:08:43 2009
@@ -1683,21 +1683,20 @@
def initialize_state_from_guard_failure(self, resumedescr, must_compile):
# guard failure: rebuild a complete MIFrame stack
self.in_recursion = -1 # always one portal around
- inputargs = self.load_values_from_failure(resumedescr)
- warmrunnerstate = self.staticdata.state
+ inputargs_and_holes = self.load_values_from_failure(resumedescr)
if must_compile:
self.history = history.History(self.cpu)
- self.history.inputargs = inputargs
+ self.history.inputargs = [box for box in inputargs_and_holes if box]
self.staticdata.profiler.start_tracing()
else:
self.staticdata.profiler.start_blackhole()
self.history = None # this means that is_blackholing() is true
- self.rebuild_state_after_failure(resumedescr, inputargs)
+ self.rebuild_state_after_failure(resumedescr, inputargs_and_holes)
def load_values_from_failure(self, resumedescr):
cpu = self.cpu
fail_arg_types = resumedescr.fail_arg_types
- inputargs = []
+ inputargs_and_holes = []
for i in range(len(fail_arg_types)):
boxtype = fail_arg_types[i]
if boxtype == history.INT:
@@ -1706,10 +1705,12 @@
box = cpu.ts.BoxRef(cpu.get_latest_value_ref(i))
elif boxtype == history.FLOAT:
box = history.BoxFloat(cpu.get_latest_value_float(i))
+ elif boxtype == history.HOLE:
+ box = None
else:
assert False, "bad box type: num=%d" % ord(boxtype)
- inputargs.append(box)
- return inputargs
+ inputargs_and_holes.append(box)
+ return inputargs_and_holes
def initialize_virtualizable(self, original_boxes):
vinfo = self.staticdata.virtualizable_info
Modified: pypy/trunk/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/resume.py (original)
+++ pypy/trunk/pypy/jit/metainterp/resume.py Tue Nov 24 11:08:43 2009
@@ -1,6 +1,7 @@
import sys, os
from pypy.jit.metainterp.history import Box, Const, ConstInt, INT, REF
from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp import jitprof
from pypy.rpython.lltypesystem import rffi
from pypy.rlib import rarithmetic
from pypy.rlib.objectmodel import we_are_translated
@@ -84,23 +85,39 @@
# please rpython :(
return rarithmetic.widen(x) == rarithmetic.widen(y)
+def tagged_list_eq(tl1, tl2):
+ if len(tl1) != len(tl2):
+ return False
+ for i in range(len(tl1)):
+ if not tagged_eq(tl1[i], tl2[i]):
+ return False
+ return True
+
TAGCONST = 0
TAGINT = 1
TAGBOX = 2
TAGVIRTUAL = 3
-UNASSIGNED = tag(-1, TAGBOX)
+UNASSIGNED = tag(-2 ** 12 - 1, TAGBOX)
+UNASSIGNEDVIRTUAL = tag(-2 ** 12 - 1, TAGVIRTUAL)
NULLREF = tag(-1, TAGCONST)
class ResumeDataLoopMemo(object):
- def __init__(self, cpu):
- self.cpu = cpu
+ def __init__(self, metainterp_sd):
+ self.metainterp_sd = metainterp_sd
+ self.cpu = metainterp_sd.cpu
self.consts = []
self.large_ints = {}
- self.refs = cpu.ts.new_ref_dict_2()
+ self.refs = self.cpu.ts.new_ref_dict_2()
self.numberings = {}
+ self.cached_boxes = {}
+ self.cached_virtuals = {}
+
+ self.nvirtuals = 0
+ self.nvholes = 0
+ self.nvreused = 0
def getconst(self, const):
if const.type == INT:
@@ -135,6 +152,8 @@
self.consts.append(const)
return result
+ # env numbering
+
def number(self, values, snapshot):
if snapshot is None:
return None, {}, 0
@@ -173,7 +192,41 @@
def forget_numberings(self, virtualbox):
# XXX ideally clear only the affected numberings
self.numberings.clear()
+ self.clear_box_virtual_numbers()
+
+ # caching for virtuals and boxes inside them
+
+ def num_cached_boxes(self):
+ return len(self.cached_boxes)
+
+ def assign_number_to_box(self, box, boxes):
+ if box in self.cached_boxes:
+ num = self.cached_boxes[box]
+ boxes[-num-1] = box
+ else:
+ boxes.append(box)
+ num = -len(boxes)
+ self.cached_boxes[box] = num
+ return num
+
+ def num_cached_virtuals(self):
+ return len(self.cached_virtuals)
+
+ def assign_number_to_virtual(self, box):
+ if box in self.cached_virtuals:
+ num = self.cached_virtuals[box]
+ else:
+ num = self.cached_virtuals[box] = -len(self.cached_virtuals) - 1
+ return num
+ def clear_box_virtual_numbers(self):
+ self.cached_boxes.clear()
+ self.cached_virtuals.clear()
+
+ def update_counters(self, profiler):
+ profiler.count(jitprof.NVIRTUALS, self.nvirtuals)
+ profiler.count(jitprof.NVHOLES, self.nvholes)
+ profiler.count(jitprof.NVREUSED, self.nvreused)
_frame_info_placeholder = (None, 0, 0)
@@ -185,30 +238,19 @@
#self.virtuals = []
#self.vfieldboxes = []
- def make_virtual(self, virtualbox, known_class, fielddescrs, fieldboxes):
- vinfo = VirtualInfo(known_class, fielddescrs)
- self._make_virtual(virtualbox, vinfo, fieldboxes)
-
- def make_vstruct(self, virtualbox, typedescr, fielddescrs, fieldboxes):
- vinfo = VStructInfo(typedescr, fielddescrs)
- self._make_virtual(virtualbox, vinfo, fieldboxes)
-
- def make_varray(self, virtualbox, arraydescr, itemboxes):
- vinfo = VArrayInfo(arraydescr)
- self._make_virtual(virtualbox, vinfo, itemboxes)
-
- def _make_virtual(self, virtualbox, vinfo, fieldboxes):
- if virtualbox in self.liveboxes_from_env:
- tagged = self.liveboxes_from_env[virtualbox]
- i, _ = untag(tagged)
- assert self.virtuals[i] is None
- self.virtuals[i] = vinfo
- self.vfieldboxes[i] = fieldboxes
- else:
- tagged = tag(len(self.virtuals), TAGVIRTUAL)
- self.virtuals.append(vinfo)
- self.vfieldboxes.append(fieldboxes)
+ def make_virtual(self, known_class, fielddescrs):
+ return VirtualInfo(known_class, fielddescrs)
+
+ def make_vstruct(self, typedescr, fielddescrs):
+ return VStructInfo(typedescr, fielddescrs)
+
+ def make_varray(self, arraydescr):
+ return VArrayInfo(arraydescr)
+
+ def register_virtual_fields(self, virtualbox, fieldboxes):
+ tagged = self.liveboxes_from_env.get(virtualbox, UNASSIGNEDVIRTUAL)
self.liveboxes[virtualbox] = tagged
+ self.vfieldboxes[virtualbox] = fieldboxes
self._register_boxes(fieldboxes)
def register_box(self, box):
@@ -234,7 +276,8 @@
def finish(self, values):
# compute the numbering
storage = self.storage
- numb, liveboxes_from_env, v = self.memo.number(values, storage.rd_snapshot)
+ numb, liveboxes_from_env, v = self.memo.number(values,
+ storage.rd_snapshot)
self.liveboxes_from_env = liveboxes_from_env
self.liveboxes = {}
storage.rd_numb = numb
@@ -243,8 +286,7 @@
# collect liveboxes and virtuals
n = len(liveboxes_from_env) - v
liveboxes = [None]*n
- self.virtuals = [None]*v
- self.vfieldboxes = [None]*v
+ self.vfieldboxes = {}
for box, tagged in liveboxes_from_env.iteritems():
i, tagbits = untag(tagged)
if tagbits == TAGBOX:
@@ -254,31 +296,65 @@
value = values[box]
value.get_args_for_fail(self)
- self._number_virtuals(liveboxes)
+ self._number_virtuals(liveboxes, values, v)
storage.rd_consts = self.memo.consts
dump_storage(storage, liveboxes)
return liveboxes[:]
- def _number_virtuals(self, liveboxes):
+ def _number_virtuals(self, liveboxes, values, num_env_virtuals):
+ memo = self.memo
+ new_liveboxes = [None] * memo.num_cached_boxes()
+ count = 0
for box, tagged in self.liveboxes.iteritems():
i, tagbits = untag(tagged)
if tagbits == TAGBOX:
+ assert box not in self.liveboxes_from_env
assert tagged_eq(tagged, UNASSIGNED)
- self.liveboxes[box] = tag(len(liveboxes), TAGBOX)
- liveboxes.append(box)
+ index = memo.assign_number_to_box(box, new_liveboxes)
+ self.liveboxes[box] = tag(index, TAGBOX)
+ count += 1
else:
assert tagbits == TAGVIRTUAL
+ if tagged_eq(tagged, UNASSIGNEDVIRTUAL):
+ assert box not in self.liveboxes_from_env
+ index = memo.assign_number_to_virtual(box)
+ self.liveboxes[box] = tag(index, TAGVIRTUAL)
+ new_liveboxes.reverse()
+ liveboxes.extend(new_liveboxes)
+ nholes = len(new_liveboxes) - count
storage = self.storage
storage.rd_virtuals = None
- if len(self.virtuals) > 0:
- storage.rd_virtuals = self.virtuals[:]
- for i in range(len(storage.rd_virtuals)):
- vinfo = storage.rd_virtuals[i]
- fieldboxes = self.vfieldboxes[i]
- vinfo.fieldnums = [self._gettagged(box)
- for box in fieldboxes]
+ vfieldboxes = self.vfieldboxes
+ if vfieldboxes:
+ length = num_env_virtuals + memo.num_cached_virtuals()
+ virtuals = storage.rd_virtuals = [None] * length
+ memo.nvirtuals += length
+ memo.nvholes += length - len(vfieldboxes)
+ for virtualbox, fieldboxes in vfieldboxes.iteritems():
+ num, _ = untag(self.liveboxes[virtualbox])
+ value = values[virtualbox]
+ fieldnums = [self._gettagged(box)
+ for box in fieldboxes]
+ vinfo = value.make_virtual_info(self, fieldnums)
+ # if a new vinfo instance is made, we get the fieldnums list we
+ # pass in as an attribute. hackish.
+ if vinfo.fieldnums is not fieldnums:
+ memo.nvreused += 1
+ virtuals[num] = vinfo
+
+ if self._invalidation_needed(len(liveboxes), nholes):
+ memo.clear_box_virtual_numbers()
+
+ def _invalidation_needed(self, nliveboxes, nholes):
+ memo = self.memo
+ # xxx heuristic a bit out of thin air
+ failargs_limit = memo.metainterp_sd.options.failargs_limit
+ if nliveboxes > (failargs_limit // 2):
+ if nholes > nliveboxes//3:
+ return True
+ return False
def _gettagged(self, box):
if isinstance(box, Const):
@@ -392,10 +468,15 @@
def _prepare_virtuals(self, metainterp, virtuals):
if virtuals:
- self.virtuals = [vinfo.allocate(metainterp) for vinfo in virtuals]
+ self.virtuals = [None] * len(virtuals)
for i in range(len(virtuals)):
vinfo = virtuals[i]
- vinfo.setfields(metainterp, self.virtuals[i], self._decode_box)
+ if vinfo is not None:
+ self.virtuals[i] = vinfo.allocate(metainterp)
+ for i in range(len(virtuals)):
+ vinfo = virtuals[i]
+ if vinfo is not None:
+ vinfo.setfields(metainterp, self.virtuals[i], self._decode_box)
def consume_boxes(self):
numb = self.cur_numb
@@ -450,8 +531,14 @@
for const in storage.rd_consts:
debug_print('\tconst', const.repr_rpython())
for box in liveboxes:
- debug_print('\tbox', box.repr_rpython())
+ if box is None:
+ debug_print('\tbox', 'None')
+ else:
+ debug_print('\tbox', box.repr_rpython())
if storage.rd_virtuals is not None:
for virtual in storage.rd_virtuals:
- virtual.debug_prints()
+ if virtual is None:
+ debug_print('\t\t', 'None')
+ else:
+ virtual.debug_prints()
debug_stop("jit-resume")
Modified: pypy/trunk/pypy/jit/metainterp/simple_optimize.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/simple_optimize.py (original)
+++ pypy/trunk/pypy/jit/metainterp/simple_optimize.py Tue Nov 24 11:08:43 2009
@@ -16,7 +16,7 @@
# we need it since the backend can modify those lists, which make
# get_guard_op in compile.py invalid
# in fact, x86 modifies this list for moving GCs
- memo = resume.ResumeDataLoopMemo(metainterp_sd.cpu)
+ memo = resume.ResumeDataLoopMemo(metainterp_sd)
newoperations = []
for op in loop.operations:
if op.is_guard():
Modified: pypy/trunk/pypy/jit/metainterp/test/oparser.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/oparser.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/oparser.py Tue Nov 24 11:08:43 2009
@@ -205,10 +205,15 @@
if i < j:
for arg in line[i:j].split(','):
arg = arg.strip()
- try:
- fail_args.append(self.vars[arg])
- except KeyError:
- raise ParseError("Unknown var in fail_args: %s" % arg)
+ if arg == 'None':
+ fail_arg = None
+ else:
+ try:
+ fail_arg = self.vars[arg]
+ except KeyError:
+ raise ParseError(
+ "Unknown var in fail_args: %s" % arg)
+ fail_args.append(fail_arg)
if descr is None and self.invent_fail_descr:
descr = self.invent_fail_descr(fail_args)
if hasattr(descr, '_oparser_uses_descr_of_guard'):
Modified: pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_jitprof.py Tue Nov 24 11:08:43 2009
@@ -63,7 +63,8 @@
]
assert profiler.events == expected
assert profiler.times == [2, 1, 1, 1]
- assert profiler.counters == [1, 1, 1, 1, 4, 3, 1, 1, 7, 1, 0, 0, 0]
+ assert profiler.counters == [1, 1, 1, 1, 4, 3, 1, 1, 7, 1, 0, 0, 0,
+ 0, 0, 0]
def test_simple_loop_with_call(self):
@dont_look_inside
Modified: pypy/trunk/pypy/jit/metainterp/test/test_logger.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_logger.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_logger.py Tue Nov 24 11:08:43 2009
@@ -83,6 +83,15 @@
'''
self.reparse(inp)
+ def test_guard_w_hole(self):
+ inp = '''
+ [i0]
+ i1 = int_add(i0, 1)
+ guard_true(i0) [i0, None, i1]
+ finish(i1)
+ '''
+ self.reparse(inp)
+
def test_debug_merge_point(self):
inp = '''
[]
@@ -112,7 +121,7 @@
assert output.splitlines()[-1] == "jump(i0, descr=<Loop3>)"
pure_parse(output)
- def test_guard(self):
+ def test_guard_descr(self):
namespace = {'fdescr': BasicFailDescr(4)}
inp = '''
[i0]
Modified: pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_optimizeopt.py Tue Nov 24 11:08:43 2009
@@ -74,6 +74,22 @@
lst2 = virt1._get_field_descr_list()
assert lst1 is lst2
+def test_reuse_vinfo():
+ class FakeVInfo(object):
+ pass
+ class FakeVirtualValue(optimizeopt.AbstractVirtualValue):
+ def _make_virtual(self, *args):
+ return FakeVInfo()
+ v1 = FakeVirtualValue(None, None, None)
+ vinfo1 = v1.make_virtual_info(None, [1, 2, 4])
+ vinfo2 = v1.make_virtual_info(None, [1, 2, 4])
+ assert vinfo1 is vinfo2
+ vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+ assert vinfo3 is not vinfo2
+ vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+ assert vinfo3 is vinfo4
+
+
# ____________________________________________________________
def equaloplists(oplist1, oplist2, strict_fail_args=True, remap={}):
Modified: pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py Tue Nov 24 11:08:43 2009
@@ -1,7 +1,8 @@
# some unit tests for the bytecode decoding
-from pypy.jit.metainterp import pyjitpl, codewriter, resoperation
+from pypy.jit.metainterp import pyjitpl, codewriter, resoperation, history
+from pypy.jit.metainterp import jitprof
from pypy.jit.metainterp.history import AbstractFailDescr, BoxInt, ConstInt
from pypy.jit.metainterp.history import History
from pypy.jit.metainterp.resoperation import ResOperation, rop
@@ -154,3 +155,39 @@
assert metainterp_sd.get_name_from_address(123) == 'a'
assert metainterp_sd.get_name_from_address(456) == 'b'
assert metainterp_sd.get_name_from_address(789) == ''
+
+def test_initialize_state_from_guard_failure():
+ from pypy.jit.metainterp.typesystem import llhelper
+ calls = []
+
+ class FakeCPU:
+ ts = llhelper
+
+ def get_latest_value_int(self, index):
+ return index
+
+ class FakeStaticData:
+ cpu = FakeCPU()
+ profiler = jitprof.EmptyProfiler()
+
+ metainterp = pyjitpl.MetaInterp(FakeStaticData())
+
+ def rebuild_state_after_failure(descr, newboxes):
+ calls.append(newboxes)
+ metainterp.rebuild_state_after_failure = rebuild_state_after_failure
+
+ class FakeResumeDescr:
+ pass
+ resumedescr = FakeResumeDescr()
+ resumedescr.fail_arg_types = [history.INT, history.HOLE,
+ history.INT, history.HOLE,
+ history.INT]
+
+ metainterp.initialize_state_from_guard_failure(resumedescr, True)
+
+ inp = metainterp.history.inputargs
+ assert len(inp) == 3
+ assert [box.value for box in inp] == [0, 2, 4]
+ b0, b2, b4 = inp
+ assert len(calls) == 1
+ assert calls[0] == [b0, None, b2, None, b4]
Modified: pypy/trunk/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_resume.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_resume.py Tue Nov 24 11:08:43 2009
@@ -1,6 +1,7 @@
import py
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.jit.metainterp.optimizeopt import VirtualValue, OptValue
+from pypy.jit.metainterp.optimizeopt import VirtualValue, OptValue, VArrayValue
+from pypy.jit.metainterp.optimizeopt import VStructValue
from pypy.jit.metainterp.resume import *
from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, ConstAddr
from pypy.jit.metainterp.history import ConstPtr, ConstFloat
@@ -33,6 +34,12 @@
assert tagged_eq(UNASSIGNED, UNASSIGNED)
assert not tagged_eq(tag(1, TAGBOX), UNASSIGNED)
+def test_tagged_list_eq():
+ assert tagged_list_eq([UNASSIGNED, tag(1, TAGBOX), tag(-2, TAGVIRTUAL)],
+ [UNASSIGNED, tag(1, TAGBOX), tag(-2, TAGVIRTUAL)])
+ assert not tagged_list_eq([tag(1, TAGBOX)], [tag(-2, TAGBOX)])
+ assert not tagged_list_eq([tag(1, TAGBOX), tag(-2, TAGBOX)], [tag(1, TAGBOX)])
+
class MyMetaInterp:
def __init__(self, cpu=None):
if cpu is None:
@@ -105,6 +112,22 @@
lst = reader.consume_boxes()
assert lst == [b1s, b2s, b3s]
+
+def test_prepare_virtuals():
+ class FakeVinfo(object):
+ def allocate(self, metainterp):
+ return "allocated"
+ def setfields(self, metainterp, virtual, func):
+ assert virtual == "allocated"
+ class FakeStorage(object):
+ rd_virtuals = [FakeVinfo(), None]
+ rd_numb = []
+ rd_consts = []
+ class FakeMetainterp(object):
+ cpu = None
+ reader = ResumeDataReader(FakeStorage(), [], FakeMetainterp())
+ assert reader.virtuals == ["allocated", None]
+
# ____________________________________________________________
@@ -238,6 +261,13 @@
assert snapshot.prev is fs[2].parent_resumedata_snapshot
assert snapshot.boxes == fs[2].env
+
+class FakeMetaInterpStaticData:
+ cpu = LLtypeMixin.cpu
+
+ class options:
+ failargs_limit = 100
+
def test_rebuild_from_resumedata():
b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
c1, c2, c3 = [ConstInt(1), ConstInt(2), ConstInt(3)]
@@ -246,7 +276,7 @@
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
capture_resumedata(fs, None, storage)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
metainterp = MyMetaInterp()
@@ -270,7 +300,7 @@
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
capture_resumedata(fs, [b4], storage)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
metainterp = MyMetaInterp()
@@ -298,7 +328,7 @@
fs = fs[:-1] + [FakeFrame("code2", 10, -1, c3, b2, b4)]
capture_resumedata(fs, None, storage2)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
@@ -330,7 +360,7 @@
def virtual_value(keybox, value, next):
vv = VirtualValue(None, ConstAddr(LLtypeMixin.node_vtable_adr,
- LLtypeMixin.cpu), keybox)
+ LLtypeMixin.cpu), keybox)
if not isinstance(next, OptValue):
next = OptValue(next)
vv.setfield(LLtypeMixin.nextdescr, next)
@@ -351,25 +381,26 @@
fs = fs[:-1] + [FakeFrame("code2", 10, -1, c3, b2, b4)]
capture_resumedata(fs, None, storage2)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
values = {b2: virtual_value(b2, b5, c4)}
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish(values)
assert len(storage.rd_virtuals) == 1
- assert storage.rd_virtuals[0].fieldnums == [tag(len(liveboxes)-1, TAGBOX),
+ assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX),
tag(0, TAGCONST)]
b6 = BoxPtr()
v6 = virtual_value(b6, c2, None)
v6.setfield(LLtypeMixin.nextdescr, v6)
values = {b2: virtual_value(b2, b4, v6), b6: v6}
+ memo.clear_box_virtual_numbers()
modifier = ResumeDataVirtualAdder(storage2, memo)
liveboxes2 = modifier.finish(values)
assert len(storage2.rd_virtuals) == 2
assert storage2.rd_virtuals[0].fieldnums == [tag(len(liveboxes2)-1, TAGBOX),
- tag(1, TAGVIRTUAL)]
+ tag(-1, TAGVIRTUAL)]
assert storage2.rd_virtuals[1].fieldnums == [tag(2, TAGINT),
- tag(1, TAGVIRTUAL)]
+ tag(-1, TAGVIRTUAL)]
# now on to resuming
metainterp = MyMetaInterp()
@@ -398,13 +429,40 @@
FakeFrame("code2", 10, -1, c3, b2t, b4t)]
assert metainterp.framestack == fs2
+def test_rebuild_from_resumedata_two_guards_w_shared_virtuals():
+ b1, b2, b3, b4, b5, b6 = [BoxPtr(), BoxPtr(), BoxInt(), BoxPtr(), BoxInt(), BoxInt()]
+ c1, c2, c3, c4 = [ConstInt(1), ConstInt(2), ConstInt(3),
+ LLtypeMixin.nodebox.constbox()]
+ storage = Storage()
+ fs = [FakeFrame("code0", 0, -1, c1, b2, b3)]
+ capture_resumedata(fs, None, storage)
+
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+ values = {b2: virtual_value(b2, b5, c4)}
+ modifier = ResumeDataVirtualAdder(storage, memo)
+ liveboxes = modifier.finish(values)
+ assert len(storage.rd_virtuals) == 1
+ assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX),
+ tag(0, TAGCONST)]
+
+ storage2 = Storage()
+ fs = [FakeFrame("code0", 0, -1, b1, b4, b2)]
+ capture_resumedata(fs, None, storage2)
+ values[b4] = virtual_value(b4, b6, c4)
+ modifier = ResumeDataVirtualAdder(storage2, memo)
+ liveboxes = modifier.finish(values)
+ assert len(storage2.rd_virtuals) == 2
+ assert storage2.rd_virtuals[1].fieldnums == storage.rd_virtuals[0].fieldnums
+ assert storage2.rd_virtuals[1] is storage.rd_virtuals[0]
+
+
def test_resumedata_top_recursive_virtuals():
b1, b2, b3 = [BoxPtr(), BoxPtr(), BoxInt()]
storage = Storage()
fs = [FakeFrame("code0", 0, -1, b1, b2)]
capture_resumedata(fs, None, storage)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
v1 = virtual_value(b1, b3, None)
v2 = virtual_value(b2, b3, v1)
v1.setfield(LLtypeMixin.nextdescr, v2)
@@ -413,9 +471,9 @@
liveboxes = modifier.finish(values)
assert liveboxes == [b3]
assert len(storage.rd_virtuals) == 2
- assert storage.rd_virtuals[0].fieldnums == [tag(0, TAGBOX),
+ assert storage.rd_virtuals[0].fieldnums == [tag(-1, TAGBOX),
tag(1, TAGVIRTUAL)]
- assert storage.rd_virtuals[1].fieldnums == [tag(0, TAGBOX),
+ assert storage.rd_virtuals[1].fieldnums == [tag(-1, TAGBOX),
tag(0, TAGVIRTUAL)]
@@ -423,7 +481,7 @@
def test_ResumeDataLoopMemo_ints():
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
tagged = memo.getconst(ConstInt(44))
assert untag(tagged) == (44, TAGINT)
tagged = memo.getconst(ConstInt(-3))
@@ -445,7 +503,7 @@
def test_ResumeDataLoopMemo_refs():
cpu = LLtypeMixin.cpu
- memo = ResumeDataLoopMemo(cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
const = cpu.ts.ConstRef(demo55o)
tagged = memo.getconst(const)
index, tagbits = untag(tagged)
@@ -463,7 +521,7 @@
assert tagged == NULLREF
def test_ResumeDataLoopMemo_other():
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
const = ConstFloat(-1.0)
tagged = memo.getconst(const)
index, tagbits = untag(tagged)
@@ -481,7 +539,7 @@
env2 = [c3, b3, b1, c3]
snap2 = Snapshot(snap, env2)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
numb, liveboxes, v = memo.number({}, snap1)
assert v == 0
@@ -553,31 +611,76 @@
tag(1, TAGVIRTUAL)]
assert numb5.prev is numb4
+def test_ResumeDataLoopMemo_number_boxes():
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+ b1, b2 = [BoxInt(), BoxInt()]
+ assert memo.num_cached_boxes() == 0
+ boxes = []
+ num = memo.assign_number_to_box(b1, boxes)
+ assert num == -1
+ assert boxes == [b1]
+ assert memo.num_cached_boxes() == 1
+ boxes = [None]
+ num = memo.assign_number_to_box(b1, boxes)
+ assert num == -1
+ assert boxes == [b1]
+ num = memo.assign_number_to_box(b2, boxes)
+ assert num == -2
+ assert boxes == [b1, b2]
+
+ assert memo.num_cached_boxes() == 2
+ boxes = [None, None]
+ num = memo.assign_number_to_box(b2, boxes)
+ assert num == -2
+ assert boxes == [None, b2]
+ num = memo.assign_number_to_box(b1, boxes)
+ assert num == -1
+ assert boxes == [b1, b2]
+
+ memo.clear_box_virtual_numbers()
+ assert memo.num_cached_boxes() == 0
+
+def test_ResumeDataLoopMemo_number_virtuals():
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+ b1, b2 = [BoxInt(), BoxInt()]
+ assert memo.num_cached_virtuals() == 0
+ num = memo.assign_number_to_virtual(b1)
+ assert num == -1
+ assert memo.num_cached_virtuals() == 1
+ num = memo.assign_number_to_virtual(b1)
+ assert num == -1
+ num = memo.assign_number_to_virtual(b2)
+ assert num == -2
+
+ assert memo.num_cached_virtuals() == 2
+ num = memo.assign_number_to_virtual(b2)
+ assert num == -2
+ num = memo.assign_number_to_virtual(b1)
+ assert num == -1
-def test__make_virtual():
+ memo.clear_box_virtual_numbers()
+ assert memo.num_cached_virtuals() == 0
+
+def test_register_virtual_fields():
b1, b2 = BoxInt(), BoxInt()
vbox = BoxPtr()
modifier = ResumeDataVirtualAdder(None, None)
modifier.liveboxes_from_env = {}
modifier.liveboxes = {}
- modifier.virtuals = []
- modifier.vfieldboxes = []
- modifier.make_virtual(vbox, None, ['a', 'b'], [b1, b2])
- assert modifier.liveboxes == {vbox: tag(0, TAGVIRTUAL), b1: UNASSIGNED,
+ modifier.vfieldboxes = {}
+ modifier.register_virtual_fields(vbox, [b1, b2])
+ assert modifier.liveboxes == {vbox: UNASSIGNEDVIRTUAL, b1: UNASSIGNED,
b2: UNASSIGNED}
- assert len(modifier.virtuals) == 1
- assert modifier.vfieldboxes == [[b1, b2]]
+ assert modifier.vfieldboxes == {vbox: [b1, b2]}
modifier = ResumeDataVirtualAdder(None, None)
modifier.liveboxes_from_env = {vbox: tag(0, TAGVIRTUAL)}
modifier.liveboxes = {}
- modifier.virtuals = [None]
- modifier.vfieldboxes = [None]
- modifier.make_virtual(vbox, None, ['a', 'b', 'c'], [b1, b2, vbox])
+ modifier.vfieldboxes = {}
+ modifier.register_virtual_fields(vbox, [b1, b2, vbox])
assert modifier.liveboxes == {b1: UNASSIGNED, b2: UNASSIGNED,
vbox: tag(0, TAGVIRTUAL)}
- assert len(modifier.virtuals) == 1
- assert modifier.vfieldboxes == [[b1, b2, vbox]]
+ assert modifier.vfieldboxes == {vbox: [b1, b2, vbox]}
def _resume_remap(liveboxes, expected, *newvalues):
newboxes = []
@@ -599,7 +702,7 @@
def test_virtual_adder_int_constants():
b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**16), ConstInt(-65)]
storage = make_storage(b1s, b2s, b3s)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
assert storage.rd_snapshot is None
@@ -618,7 +721,7 @@
def test_virtual_adder_memo_const_sharing():
b1s, b2s, b3s = [ConstInt(sys.maxint), ConstInt(2**16), ConstInt(-65)]
storage = make_storage(b1s, b2s, b3s)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
modifier.finish({})
assert len(memo.consts) == 2
@@ -635,7 +738,7 @@
def test_virtual_adder_no_op_renaming():
b1s, b2s, b3s = [BoxInt(1), BoxInt(2), BoxInt(3)]
storage = make_storage(b1s, b2s, b3s)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
b1_2 = BoxInt()
class FakeValue(object):
@@ -667,7 +770,7 @@
b1s, b2s, b3s = [BoxInt(1), BoxPtr(), BoxInt(3)]
b1s = ConstInt(111)
storage = make_storage(b1s, b2s, b3s)
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
b2t, b3t = [BoxPtr(demo55o), BoxInt(33)]
@@ -688,26 +791,30 @@
b2s, b3s, b4s, b5s = [BoxPtr(), BoxInt(3), BoxPtr(), BoxPtr()]
c1s = ConstInt(111)
storage = Storage()
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
modifier.liveboxes_from_env = {}
modifier.liveboxes = {}
- modifier.virtuals = []
- modifier.vfieldboxes = []
- modifier.make_virtual(b2s,
- ConstAddr(LLtypeMixin.node_vtable_adr,
- LLtypeMixin.cpu),
- [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr],
- [b4s, c1s]) # new fields
- modifier.make_virtual(b4s,
- ConstAddr(LLtypeMixin.node_vtable_adr2,
- LLtypeMixin.cpu),
- [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr,
- LLtypeMixin.otherdescr],
- [b2s, b3s, b5s]) # new fields
+ modifier.vfieldboxes = {}
+
+ v2 = VirtualValue(None, ConstAddr(LLtypeMixin.node_vtable_adr,
+ LLtypeMixin.cpu), b2s)
+ v2._fields = {LLtypeMixin.nextdescr: b4s,
+ LLtypeMixin.valuedescr: c1s}
+ v2._cached_sorted_fields = [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr]
+ v4 = VirtualValue(None, ConstAddr(LLtypeMixin.node_vtable_adr2,
+ LLtypeMixin.cpu), b4s)
+ v4._fields = {LLtypeMixin.nextdescr: b2s,
+ LLtypeMixin.valuedescr: b3s,
+ LLtypeMixin.otherdescr: b5s}
+ v4._cached_sorted_fields = [LLtypeMixin.nextdescr, LLtypeMixin.valuedescr,
+ LLtypeMixin.otherdescr]
+ modifier.register_virtual_fields(b2s, [b4s, c1s])
+ modifier.register_virtual_fields(b4s, [b2s, b3s, b5s])
+ values = {b2s: v2, b4s: v4}
liveboxes = []
- modifier._number_virtuals(liveboxes)
+ modifier._number_virtuals(liveboxes, values, 0)
storage.rd_consts = memo.consts[:]
storage.rd_numb = None
# resume
@@ -722,22 +829,25 @@
metainterp = MyMetaInterp()
reader = ResumeDataReader(storage, newboxes, metainterp)
assert len(reader.virtuals) == 2
- b2t = reader._decode_box(tag(0, TAGVIRTUAL))
- b4t = reader._decode_box(tag(1, TAGVIRTUAL))
+ b2t = reader._decode_box(modifier._gettagged(b2s))
+ b4t = reader._decode_box(modifier._gettagged(b4s))
trace = metainterp.trace
- expected = [
- (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr,
+ b2new = (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr,
LLtypeMixin.cpu)],
- b2t, None),
- (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr2,
+ b2t, None)
+ b4new = (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr2,
LLtypeMixin.cpu)],
- b4t, None),
- (rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.nextdescr),
- (rop.SETFIELD_GC, [b2t, c1s], None, LLtypeMixin.valuedescr),
- (rop.SETFIELD_GC, [b4t, b2t], None, LLtypeMixin.nextdescr),
- (rop.SETFIELD_GC, [b4t, b3t], None, LLtypeMixin.valuedescr),
- (rop.SETFIELD_GC, [b4t, b5t], None, LLtypeMixin.otherdescr),
- ]
+ b4t, None)
+ b2set = [(rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.nextdescr),
+ (rop.SETFIELD_GC, [b2t, c1s], None, LLtypeMixin.valuedescr)]
+ b4set = [(rop.SETFIELD_GC, [b4t, b2t], None, LLtypeMixin.nextdescr),
+ (rop.SETFIELD_GC, [b4t, b3t], None, LLtypeMixin.valuedescr),
+ (rop.SETFIELD_GC, [b4t, b5t], None, LLtypeMixin.otherdescr)]
+ if untag(modifier._gettagged(b2s))[0] == -2:
+ expected = [b2new, b4new] + b2set + b4set
+ else:
+ expected = [b4new, b2new] + b4set + b2set
+
for x, y in zip(expected, trace):
assert x == y
ptr = b2t.value._obj.container._as_ptr()
@@ -753,17 +863,21 @@
b2s, b4s = [BoxPtr(), BoxInt(4)]
c1s = ConstInt(111)
storage = Storage()
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
modifier.liveboxes_from_env = {}
modifier.liveboxes = {}
- modifier.virtuals = []
- modifier.vfieldboxes = []
- modifier.make_varray(b2s,
- LLtypeMixin.arraydescr,
- [b4s, c1s]) # new fields
+ modifier.vfieldboxes = {}
+
+ class FakeOptimizer(object):
+ def new_const_item(self, descr):
+ return None
+ v2 = VArrayValue(FakeOptimizer(), LLtypeMixin.arraydescr, 2, b2s)
+ v2._items = [b4s, c1s]
+ modifier.register_virtual_fields(b2s, [b4s, c1s])
liveboxes = []
- modifier._number_virtuals(liveboxes)
+ values = {b2s: v2}
+ modifier._number_virtuals(liveboxes, values, 0)
dump_storage(storage, liveboxes)
storage.rd_consts = memo.consts[:]
storage.rd_numb = None
@@ -799,18 +913,17 @@
b2s, b4s = [BoxPtr(), BoxPtr()]
c1s = ConstInt(111)
storage = Storage()
- memo = ResumeDataLoopMemo(LLtypeMixin.cpu)
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
modifier.liveboxes_from_env = {}
modifier.liveboxes = {}
- modifier.virtuals = []
- modifier.vfieldboxes = []
- modifier.make_vstruct(b2s,
- LLtypeMixin.ssize,
- [LLtypeMixin.adescr, LLtypeMixin.bdescr],
- [c1s, b4s]) # new fields
+ modifier.vfieldboxes = {}
+ v2 = VStructValue(None, LLtypeMixin.ssize, b2s)
+ v2._fields = {LLtypeMixin.adescr: c1s, LLtypeMixin.bdescr: b4s}
+ v2._cached_sorted_fields = [LLtypeMixin.adescr, LLtypeMixin.bdescr]
+ modifier.register_virtual_fields(b2s, [c1s, b4s])
liveboxes = []
- modifier._number_virtuals(liveboxes)
+ modifier._number_virtuals(liveboxes, {b2s: v2}, 0)
dump_storage(storage, liveboxes)
storage.rd_consts = memo.consts[:]
storage.rd_numb = None
@@ -837,3 +950,23 @@
assert lltype.typeOf(ptr) == lltype.Ptr(LLtypeMixin.S)
assert ptr.a == 111
assert ptr.b == lltype.nullptr(LLtypeMixin.NODE)
+
+def test_invalidation_needed():
+ class options:
+ failargs_limit = 10
+
+ metainterp_sd = FakeMetaInterpStaticData()
+ metainterp_sd.options = options
+ memo = ResumeDataLoopMemo(metainterp_sd)
+ modifier = ResumeDataVirtualAdder(None, memo)
+
+ for i in range(5):
+ assert not modifier._invalidation_needed(5, i)
+
+ assert not modifier._invalidation_needed(7, 2)
+ assert modifier._invalidation_needed(7, 3)
+
+ assert not modifier._invalidation_needed(10, 2)
+ assert not modifier._invalidation_needed(10, 3)
+ assert modifier._invalidation_needed(10, 4)
+
Modified: pypy/trunk/pypy/jit/metainterp/test/test_virtual.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_virtual.py (original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_virtual.py Tue Nov 24 11:08:43 2009
@@ -304,6 +304,8 @@
# ENTER - compile the leaving path
self.check_enter_count(4)
+class VirtualMiscTests:
+
def test_guards_around_forcing(self):
class A(object):
def __init__(self, x):
@@ -329,6 +331,29 @@
return 0
self.meta_interp(f, [50])
+ def test_guards_and_holes(self):
+ class A(object):
+ def __init__(self, x):
+ self.x = x
+ mydriver = JitDriver(reds = ['n', 'tot'], greens = [])
+
+ def f(n):
+ tot = 0
+ while n > 0:
+ mydriver.can_enter_jit(n=n, tot=tot)
+ mydriver.jit_merge_point(n=n, tot=tot)
+ a = A(n)
+ b = A(n+1)
+ if n % 9 == 0:
+ tot += (a.x + b.x) % 3
+ c = A(n+1)
+ if n % 10 == 0:
+ tot -= (c.x + a.x) % 3
+ n -= 1
+ return tot
+ r = self.meta_interp(f, [70])
+ expected = f(70)
+ assert r == expected
# ____________________________________________________________
# Run 1: all the tests instantiate a real RPython class
@@ -435,3 +460,11 @@
p = lltype.malloc(NODE2)
p.parent.typeptr = vtable2
return p
+
+# misc
+
+class TestOOTypeMisc(VirtualMiscTests, OOJitMixin):
+ pass
+
+class TestLLTypeMisc(VirtualMiscTests, LLJitMixin):
+ pass
More information about the Pypy-commit
mailing list