[pypy-svn] r70276 - in pypy/branch/jit-delayed-write/pypy/jit/metainterp: . test
arigo at codespeak.net
arigo at codespeak.net
Sat Dec 26 15:08:03 CET 2009
Author: arigo
Date: Sat Dec 26 15:08:01 2009
New Revision: 70276
Modified:
pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py
pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py
pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py
Log:
In-progress.
Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/optimizeopt.py Sat Dec 26 15:08:01 2009
@@ -63,7 +63,11 @@
def get_args_for_fail(self, modifier):
pass
- def make_virtual_info(self, modifier, fieldnums):
+ def get_backstore(self):
+ return (None, None)
+
+ def make_virtual_info(self, modifier, fieldnums,
+ backstore_num, backstore_descr):
raise NotImplementedError # should not be called on this level
def is_constant(self):
@@ -138,10 +142,12 @@
class AbstractVirtualValue(OptValue):
- _attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo')
+ _attrs_ = ('optimizer', 'keybox', 'source_op', '_cached_vinfo',
+ 'backstore_field')
box = None
level = LEVEL_NONNULL
_cached_vinfo = None
+ backstore_field = None # the fielddescr from lazy_setfields
def __init__(self, optimizer, keybox, source_op=None):
self.optimizer = optimizer
@@ -160,19 +166,40 @@
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):
+ def get_backstore(self):
+ if self.backstore_field is None:
+ return (None, None)
+ heapopt = self.optimizer.heap_op_optimizer
+ try:
+ op = heapopt.lazy_setfields[self.backstore_field]
+ except KeyError:
+ self.backstore_field = None
+ return (None, None)
+ if self.optimizer.getvalue(op.args[1]) is not self:
+ self.backstore_field = None
+ return (None, None)
+ return (op.args[0], self.backstore_field)
+
+ def make_virtual_info(self, modifier, fieldnums,
+ backstore_num, backstore_descr):
+ vinfo = self._cached_vinfo
+ if vinfo is not None and vinfo.equals(fieldnums, backstore_num,
+ backstore_descr):
return vinfo
vinfo = self._make_virtual(modifier)
- vinfo.fieldnums = fieldnums
+ vinfo.set_content(fieldnums, backstore_num, backstore_descr)
self._cached_vinfo = vinfo
return vinfo
def _make_virtual(self, modifier):
raise NotImplementedError("abstract base")
+ def register_virtual_fields(self, modifier, fieldboxes):
+ modifier.register_virtual_fields(self.keybox, fieldboxes)
+ parentbox, parentdescr = self.get_backstore()
+ if parentdescr is not None:
+ modifier.register_box(parentbox)
+
def get_fielddescrlist_cache(cpu):
if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
result = descrlist_dict()
@@ -238,7 +265,7 @@
# 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]
- modifier.register_virtual_fields(self.keybox, fieldboxes)
+ self.register_virtual_fields(modifier, fieldboxes)
for ofs in lst:
fieldvalue = self._fields[ofs]
fieldvalue.get_args_for_fail(modifier)
@@ -306,7 +333,7 @@
itemboxes = []
for itemvalue in self._items:
itemboxes.append(itemvalue.get_key_box())
- modifier.register_virtual_fields(self.keybox, itemboxes)
+ self.register_virtual_fields(modifier, itemboxes)
for itemvalue in self._items:
if itemvalue is not self.constvalue:
itemvalue.get_args_for_fail(modifier)
@@ -535,6 +562,7 @@
self.newoperations.append(op)
def store_final_boxes_in_guard(self, op):
+ self.heap_op_optimizer.force_lazy_setfields_for_guard()
descr = op.descr
assert isinstance(descr, compile.ResumeGuardDescr)
modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
@@ -918,7 +946,6 @@
if op.is_ovf():
return
if op.is_guard():
- self.force_all_lazy_setfields_of_nonvirtuals()
return
opnum = op.opnum
if (opnum == rop.SETFIELD_GC or
@@ -957,6 +984,9 @@
except KeyError:
return
del self.lazy_setfields[descr]
+ fieldvalue = self.optimizer.getvalue(op.args[1])
+ if isinstance(fieldvalue, AbstractVirtualValue):
+ fieldvalue.backstore_field = None
self.optimizer._emit_operation(op)
def force_all_lazy_setfields(self):
@@ -965,15 +995,26 @@
self.force_lazy_setfield(descr)
del self.lazy_setfields_descrs[:]
- def force_all_lazy_setfields_of_nonvirtuals(self):
+ def force_lazy_setfields_for_guard(self):
for descr in self.lazy_setfields_descrs:
try:
op = self.lazy_setfields[descr]
except KeyError:
continue
+ # the only really interesting case that we need to handle in the
+ # guards' resume data is that of a virtual object that is stored
+ # into a field of a non-virtual object. The later object cannot
+ # actually be virtual here (verified by an assert), but the
+ # former object 'fieldvalue' can be.
+ value = self.optimizer.getvalue(op.args[0])
+ assert not value.is_virtual()
fieldvalue = self.optimizer.getvalue(op.args[1])
- if not fieldvalue.is_virtual():
- self.force_lazy_setfield(descr)
+ if fieldvalue.is_virtual():
+ assert isinstance(fieldvalue, AbstractVirtualValue)
+ if fieldvalue.backstore_field is descr:
+ # this is the case that can be handled by resume data
+ continue
+ self.force_lazy_setfield(descr)
def force_lazy_setfield_if_necessary(self, op, value, write=False):
try:
@@ -1003,6 +1044,8 @@
def optimize_SETFIELD_GC(self, op, value, fieldvalue):
self.force_lazy_setfield_if_necessary(op, value, write=True)
self.lazy_setfields[op.descr] = op
+ if isinstance(fieldvalue, AbstractVirtualValue):
+ fieldvalue.backstore_field = op.descr
# remember the result of future reads of the field
self.cache_field_value(op.descr, value, fieldvalue, write=True)
Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py (original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/resume.py Sat Dec 26 15:08:01 2009
@@ -252,8 +252,6 @@
if (isinstance(box, Box) and box not in self.liveboxes_from_env
and box not in self.liveboxes):
self.liveboxes[box] = UNASSIGNED
- return True
- return False
def _register_boxes(self, boxes):
for box in boxes:
@@ -298,6 +296,7 @@
return liveboxes[:]
def _number_virtuals(self, liveboxes, values, num_env_virtuals):
+ # !! 'liveboxes' is a list that is extend()ed in-place !!
memo = self.memo
new_liveboxes = [None] * memo.num_cached_boxes()
count = 0
@@ -339,7 +338,13 @@
value = values[virtualbox]
fieldnums = [self._gettagged(box)
for box in fieldboxes]
- vinfo = value.make_virtual_info(self, fieldnums)
+ backstore_box, backstore_descr = value.get_backstore()
+ if backstore_descr is not None:
+ backstore_num = self._gettagged(backstore_box)
+ else:
+ backstore_num = NULLREF
+ vinfo = value.make_virtual_info(self, fieldnums,
+ backstore_num, backstore_descr)
# 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:
@@ -366,11 +371,47 @@
return self.liveboxes_from_env[box]
return self.liveboxes[box]
+
+class BackstoreRef(object):
+ # Used to say that a virtual object must, after being created because
+ # of a guard failure, be stored back on the given field of the given
+ # non-virtual object. For lazy setfields. Limited to one place per
+ # virtual for now.
+ def __init__(self, parentdescr, parentnum):
+ self.parentdescr = parentdescr
+ self.parentnum = parentnum
+
+ def setfields(self, metainterp, box, fn_decode_box):
+ parentbox = fn_decode_box(self.parentnum)
+ metainterp.execute_and_record(rop.SETFIELD_GC, self.parentdescr,
+ parentbox, box)
+
class AbstractVirtualInfo(object):
+ backstore_ref = None
+
def allocate(self, metainterp):
raise NotImplementedError
+
def setfields(self, metainterp, box, fn_decode_box):
- raise NotImplementedError
+ if self.backstore_ref is not None:
+ self.backstore_ref.setfields(metainterp, box, fn_decode_box)
+
+ def equals(self, fieldnums, backstore_num, backstore_descr):
+ return (tagged_list_eq(self.fieldnums, fieldnums) and
+ self.backstore_equals(backstore_num, backstore_descr))
+
+ def backstore_equals(self, backstore_num, backstore_descr):
+ if backstore_descr is None:
+ return self.backstore_ref is None
+ else:
+ return (self.backstore_ref is not None and
+ self.backstore_ref.parentdescr == backstore_descr and
+ self.backstore_ref.parentnum == backstore_num)
+
+ def set_content(self, fieldnums, backstore_num, backstore_descr):
+ self.fieldnums = fieldnums
+ if backstore_descr is not None:
+ self.backstore_ref = BackstoreRef(backstore_descr, backstore_num)
class AbstractVirtualStructInfo(AbstractVirtualInfo):
@@ -384,6 +425,7 @@
metainterp.execute_and_record(rop.SETFIELD_GC,
self.fielddescrs[i],
box, fieldbox)
+ AbstractVirtualInfo.setfields(self, metainterp, box, fn_decode_box)
def debug_prints(self):
assert len(self.fielddescrs) == len(self.fieldnums)
@@ -434,6 +476,7 @@
metainterp.execute_and_record(rop.SETARRAYITEM_GC,
self.arraydescr,
box, ConstInt(i), itembox)
+ AbstractVirtualInfo.setfields(self, metainterp, box, fn_decode_box)
def debug_prints(self):
debug_print("\tvarrayinfo", self.arraydescr)
Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_optimizeopt.py Sat Dec 26 15:08:01 2009
@@ -87,18 +87,39 @@
def test_reuse_vinfo():
class FakeVInfo(object):
- pass
+ def set_content(self, fieldnums, backstore_num, backstore_descr):
+ self.fieldnums = fieldnums
+ self.backstore_num = backstore_num
+ self.backstore_descr = backstore_descr
+ def equals(self, fieldnums, backstore_num, backstore_descr):
+ return (self.fieldnums == fieldnums and
+ self.backstore_num == backstore_num and
+ self.backstore_descr == backstore_descr)
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])
+ vinfo1 = v1.make_virtual_info(None, [1, 2, 4], None, None)
+ vinfo2 = v1.make_virtual_info(None, [1, 2, 4], None, None)
assert vinfo1 is vinfo2
- vinfo3 = v1.make_virtual_info(None, [1, 2, 6])
+ vinfo3 = v1.make_virtual_info(None, [1, 2, 6], None, None)
assert vinfo3 is not vinfo2
- vinfo4 = v1.make_virtual_info(None, [1, 2, 6])
+ vinfo4 = v1.make_virtual_info(None, [1, 2, 6], None, None)
assert vinfo3 is vinfo4
+ #
+ descr = object()
+ descr2 = object()
+ vinfo1 = v1.make_virtual_info(None, [1, 2, 4], None, None)
+ vinfo2 = v1.make_virtual_info(None, [1, 2, 4], 6, descr)
+ assert vinfo1 is not vinfo2
+ vinfo3 = v1.make_virtual_info(None, [1, 2, 4], 6, descr)
+ assert vinfo3 is vinfo2
+ vinfo4 = v1.make_virtual_info(None, [1, 2, 4], 5, descr)
+ assert vinfo4 is not vinfo3
+ vinfo5 = v1.make_virtual_info(None, [1, 2, 4], 5, descr2)
+ assert vinfo5 is not vinfo4
+ vinfo6 = v1.make_virtual_info(None, [1, 2, 4], 5, descr2)
+ assert vinfo6 is vinfo5
def test_descrlist_dict():
from pypy.jit.metainterp import optimizeutil
@@ -2060,6 +2081,54 @@
where p7v is a node_vtable, valuedescr=iv
''')
+ def test_expand_fail_lazy_setfield_1(self):
+ self.make_fail_descr()
+ ops = """
+ [p1, i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ guard_true(i3, descr=fdescr) [p1]
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ expected = """
+ [p1, i2, i3]
+ guard_true(i3, descr=fdescr) [p1, i2]
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.check_expanded_fail_descr('''p1
+ where p2 is a node_vtable, valuedescr=i2 --> p1.nextdescr
+ ''')
+
+ def test_expand_fail_lazy_setfield_2(self):
+ self.make_fail_descr()
+ ops = """
+ [i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(ConstPtr(myptr), p2, descr=nextdescr)
+ guard_true(i3, descr=fdescr) []
+ i4 = int_neg(i2)
+ setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+ jump(i2, i4)
+ """
+ expected = """
+ [i2, i3]
+ guard_true(i3, descr=fdescr) [i2]
+ i4 = int_neg(i2)
+ setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+ jump(i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+ self.check_expanded_fail_descr('''
+ where p2 is a node_vtable, valuedescr=i2 --> myptr.nextdescr
+ ''')
+
class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
Modified: pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py (original)
+++ pypy/branch/jit-delayed-write/pypy/jit/metainterp/test/test_resume.py Sat Dec 26 15:08:01 2009
@@ -40,6 +40,24 @@
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)])
+def test_vinfo():
+ v1 = AbstractVirtualInfo()
+ v1.set_content([1, 2, 4], -1, None)
+ assert v1.backstore_ref is None
+ assert v1.equals([1, 2, 4], -1, None)
+ assert not v1.equals([1, 2, 6], -1, None)
+ assert not v1.equals([1, 2, 4], 3, object())
+ #
+ v2 = AbstractVirtualInfo()
+ descr = object()
+ v2.set_content([1, 2, 4], 3, descr)
+ assert v2.backstore_ref is not None
+ assert v2.backstore_ref.parentdescr is descr
+ assert v2.backstore_ref.parentnum == 3
+ assert v2.equals([1, 2, 4], 3, descr)
+ assert not v2.equals([1, 2, 4], 2, descr)
+ assert not v2.equals([1, 2, 4], 3, object())
+
class MyMetaInterp:
_already_allocated_resume_virtuals = None
@@ -960,6 +978,73 @@
assert ptr.a == 111
assert ptr.b == lltype.nullptr(LLtypeMixin.NODE)
+
+def test_virtual_adder_make_virtual_backstore():
+ b2s, b4s, b5s = [BoxPtr(), BoxPtr(), BoxPtr()]
+ c1s = ConstInt(111)
+ storage = Storage()
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+ modifier = ResumeDataVirtualAdder(storage, memo)
+ modifier.liveboxes_from_env = {}
+ modifier.liveboxes = {}
+ modifier.vfieldboxes = {}
+
+ class FakeOptimizer(object):
+ class cpu:
+ pass
+ def getvalue(self, box):
+ return {b2s: v2, b4s: v4}[box]
+ fakeoptimizer = FakeOptimizer()
+ class HeapOpOptimizer(object):
+ pass
+ fakeoptimizer.heap_op_optimizer = HeapOpOptimizer()
+ class FakeSetFieldOperation(object):
+ args = [b2s, b4s]
+ fakeoptimizer.heap_op_optimizer.lazy_setfields = {
+ LLtypeMixin.nextdescr: FakeSetFieldOperation()}
+
+ v4 = VirtualValue(fakeoptimizer, ConstAddr(LLtypeMixin.node_vtable_adr2,
+ LLtypeMixin.cpu), b4s)
+ v4.backstore_field = LLtypeMixin.nextdescr
+ v4.setfield(LLtypeMixin.valuedescr, OptValue(c1s))
+ v4.setfield(LLtypeMixin.otherdescr, OptValue(b5s))
+ v4._cached_sorted_fields = [LLtypeMixin.valuedescr, LLtypeMixin.otherdescr]
+
+ v2 = OptValue(b2s)
+
+ v4.register_virtual_fields(modifier, [c1s, b5s])
+ liveboxes = []
+ modifier._number_virtuals(liveboxes, {b4s: v4}, 0)
+ assert liveboxes == [b2s, b5s]
+ storage.rd_consts = memo.consts[:]
+ storage.rd_numb = None
+ # resume
+ demo55.next = lltype.nullptr(LLtypeMixin.NODE)
+ b2t = BoxPtr(demo55o)
+ b5t = BoxPtr(demo66o)
+ newboxes = _resume_remap(liveboxes, [b2s, b5s], b2t, b5t)
+
+ metainterp = MyMetaInterp()
+ reader = ResumeDataReader(storage, newboxes, metainterp)
+ assert len(reader.virtuals) == 1
+ b4t = reader._decode_box(modifier._gettagged(b4s))
+ trace = metainterp.trace
+ b4new = (rop.NEW_WITH_VTABLE, [ConstAddr(LLtypeMixin.node_vtable_adr2,
+ LLtypeMixin.cpu)],
+ b4t, None)
+ b4set1 = (rop.SETFIELD_GC, [b4t, c1s], None, LLtypeMixin.valuedescr)
+ b4set2 = (rop.SETFIELD_GC, [b4t, b5t], None, LLtypeMixin.otherdescr)
+ b2set = (rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.nextdescr)
+ expected = [b4new, b4set1, b4set2, b2set]
+
+ for x, y in zip(expected, trace):
+ assert x == y
+ ptr = demo55.next
+ assert ptr.value == 111
+ ptr = lltype.cast_pointer(lltype.Ptr(LLtypeMixin.NODE2), ptr)
+ assert ptr.other == demo66
+
+
def test_invalidation_needed():
class options:
failargs_limit = 10
More information about the Pypy-commit
mailing list