[pypy-svn] r66541 - in pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp: . test
arigo at codespeak.net
arigo at codespeak.net
Thu Jul 23 17:30:03 CEST 2009
Author: arigo
Date: Thu Jul 23 17:30:01 2009
New Revision: 66541
Modified:
pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py
pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py
pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py
pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py
pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py
Log:
Unrevert r66530, and tie virtuals to FAILs in optimizeopt.py.
In-progress.
Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/optimizeopt.py Thu Jul 23 17:30:01 2009
@@ -4,6 +4,7 @@
from pypy.jit.metainterp.specnode import SpecNode
from pypy.jit.metainterp.specnode import VirtualInstanceSpecNode
from pypy.jit.metainterp.optimizeutil import av_newdict, _findall, sort_descrs
+from pypy.jit.metainterp import resume
from pypy.rlib.objectmodel import we_are_translated
@@ -36,11 +37,9 @@
def force_box(self):
return self.box
- def get_args_for_fail(self, list, memo):
- if not self.is_constant():
- if self.box not in memo:
- list.append(self.box)
- memo[self.box] = None
+ def get_args_for_fail(self, srcbox, modifier):
+ if self.is_constant():
+ modifier.make_constant(srcbox, self.box)
def is_constant(self):
return self.level == LEVEL_CONSTANT
@@ -120,10 +119,11 @@
newoperations.append(op)
return self.box
- def get_args_for_fail(self, list, memo):
+ def get_args_for_fail(self, srcbox, modifier):
if self.box is not None:
- InstanceValue.get_args_for_fail(self, list, memo)
+ InstanceValue.get_args_for_fail(self, srcbox, modifier)
else:
+ xxxxx
if self.source_op is not None: #otherwise, no loop detection needed
keybox = self.source_op.result
if keybox in memo:
@@ -258,18 +258,19 @@
op_fail = op1.suboperations[0]
assert op_fail.opnum == rop.FAIL
#
- memo = {}
- newboxes = []
+ if not we_are_translated() and op_fail.descr is None: # for tests
+ op_fail.descr = Storage()
+ resume.ResumeDataBuilder()
+ resume.generate_boxes(op_fail.args)
+ resume.finish(op_fail.descr)
+ modifier = resume.ResumeDataVirtualAdder(op_fail.descr, op_fail.args)
for box in op_fail.args:
- try:
+ if box in self.values:
value = self.values[box]
- except KeyError:
- if box not in memo:
- newboxes.append(box)
- memo[box] = None
- else:
- value.get_args_for_fail(newboxes, memo)
- # NB. we mutate op_fail in-place above. That's bad. Hopefully
+ value.get_args_for_fail(box, modifier)
+ newboxes = modifier.finish()
+ # NB. we mutate op_fail in-place below, as well as op_fail.descr
+ # via the ResumeDataVirtualAdder. That's bad. Hopefully
# it does not really matter because no-one is going to look again
# at its unoptimized version. We cannot really clone it because of
# how the rest works (e.g. it is returned by cpu.execute_operations()).
@@ -405,3 +406,6 @@
optimize_ops = _findall(Optimizer, 'optimize_')
+
+class Storage:
+ "for tests."
Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/pyjitpl.py Thu Jul 23 17:30:01 2009
@@ -1512,7 +1512,7 @@
if not we_are_translated():
self._debug_history.append(['guard_failure', None, None])
vinfo = self.staticdata.virtualizable_info
- resumereader = resume.ResumeDataReader(resumedescr, newboxes)
+ resumereader = resume.ResumeDataReader(resumedescr, newboxes, self)
if vinfo is not None:
self.virtualizable_boxes = resumereader.consume_boxes()
# just jumped away from assembler (case 4 in the comment in
Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py (original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/resume.py Thu Jul 23 17:30:01 2009
@@ -1,10 +1,14 @@
-from pypy.jit.metainterp.history import Box
+import sys
+from pypy.jit.metainterp.history import Box, Const
+from pypy.jit.metainterp.resoperation import rop
# Logic to encode the chain of frames and the state of the boxes at a
-# FAIL operation, and to decode it again.
+# FAIL operation, and to decode it again. This is a bit advanced,
+# because it needs to support optimize.py which encodes virtuals with
+# arbitrary cycles.
# XXX I guess that building the data so that it is compact as possible
-# would be a big win.
+# on the 'storage' object would be a big win.
class ResumeDataBuilder(object):
@@ -39,33 +43,135 @@
storage.rd_frame_infos = self.frame_infos[:]
storage.rd_nums = self.nums[:]
storage.rd_consts = self.consts[:]
+ storage.rd_virtuals = None
return self.liveboxes
+VIRTUAL_FLAG = int((sys.maxint+1) // 2)
+assert not (VIRTUAL_FLAG & (VIRTUAL_FLAG-1)) # a power of two
+
+class ResumeDataVirtualAdder(object):
+
+ def __init__(self, storage, liveboxes):
+ self.storage = storage
+ self.nums = storage.rd_nums[:]
+ self.consts = storage.rd_consts[:]
+ assert storage.rd_virtuals is None
+ self.original_liveboxes = liveboxes
+ self.liveboxes = {}
+ for box in liveboxes:
+ self.liveboxes[box] = 0
+ self.liveboxes_order = liveboxes[:]
+ self.virtuals = []
+ self.vfieldboxes = []
+
+ def make_constant(self, box, const):
+ assert self.liveboxes[box] == 0
+ self.liveboxes[box] = self._getconstindex(const)
+
+ def make_virtual(self, virtualbox, known_class, sizedescr,
+ fielddescrs, fieldboxes):
+ assert self.liveboxes[virtualbox] == 0
+ self.liveboxes[virtualbox] = len(self.virtuals) | VIRTUAL_FLAG
+ vinfo = VirtualInfo(known_class, sizedescr, fielddescrs)
+ self.virtuals.append(vinfo)
+ self.vfieldboxes.append(fieldboxes)
+ for box in fieldboxes:
+ if isinstance(box, Box):
+ self.liveboxes.setdefault(box, 0)
+ self.liveboxes_order.append(box)
+
+ def is_virtual(self, virtualbox):
+ return self.liveboxes[virtualbox] >= VIRTUAL_FLAG
+
+ def finish(self):
+ storage = self.storage
+ liveboxes = []
+ for box in self.liveboxes_order:
+ if self.liveboxes[box] == 0:
+ self.liveboxes[box] = len(liveboxes)
+ liveboxes.append(box)
+ for i in range(len(storage.rd_nums)):
+ num = storage.rd_nums[i]
+ if num >= 0:
+ box = self.original_liveboxes[num]
+ storage.rd_nums[i] = self.liveboxes[box]
+ 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._getboxindex(box) for box in fieldboxes]
+ storage.rd_consts = self.consts[:]
+ return liveboxes
+
+ def _getboxindex(self, box):
+ if isinstance(box, Const):
+ return self._getconstindex(box)
+ else:
+ return self.liveboxes[box]
+
+ def _getconstindex(self, const):
+ result = -2 - len(self.consts)
+ self.consts.append(const)
+ return result
+
+
+class VirtualInfo(object):
+ def __init__(self, known_class, sizedescr, fielddescrs):
+ self.known_class = known_class
+ self.sizedescr = sizedescr
+ self.fielddescrs = fielddescrs
+ #self.fieldnums = ...
+
+ def allocate(self, metainterp):
+ return metainterp.execute_and_record(rop.NEW_WITH_VTABLE,
+ [self.known_class],
+ descr=self.sizedescr)
+
+ def setfields(self, metainterp, box, fn_decode_box):
+ for i in range(len(self.fielddescrs)):
+ fieldbox = fn_decode_box(self.fieldnums[i])
+ metainterp.execute_and_record(rop.SETFIELD_GC,
+ [box, fieldbox],
+ descr=self.fielddescrs[i])
+
+
class ResumeDataReader(object):
i_frame_infos = 0
i_boxes = 0
- def __init__(self, storage, liveboxes):
+ def __init__(self, storage, liveboxes, metainterp=None):
self.frame_infos = storage.rd_frame_infos
self.nums = storage.rd_nums
self.consts = storage.rd_consts
self.liveboxes = liveboxes
+ if storage.rd_virtuals is not None:
+ self._prepare_virtuals(metainterp, storage.rd_virtuals)
+
+ def _prepare_virtuals(self, metainterp, virtuals):
+ self.virtuals = [vinfo.allocate(metainterp) for vinfo in virtuals]
+ for i in range(len(virtuals)):
+ vinfo = virtuals[i]
+ vinfo.setfields(metainterp, self.virtuals[i], self._decode_box)
def consume_boxes(self):
boxes = []
while True:
num = self.nums[self.i_boxes]
self.i_boxes += 1
- if num >= 0:
- box = self.liveboxes[num]
- elif num != -1:
- box = self.consts[-2 - num]
- else:
+ if num == -1:
break
- boxes.append(box)
+ boxes.append(self._decode_box(num))
return boxes
+ def _decode_box(self, num):
+ if num < 0:
+ return self.consts[-2 - num]
+ elif num & VIRTUAL_FLAG:
+ return self.virtuals[num - VIRTUAL_FLAG]
+ else:
+ return self.liveboxes[num]
+
def has_more_frame_infos(self):
return self.i_frame_infos < len(self.frame_infos)
Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py (original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/oparser.py Thu Jul 23 17:30:01 2009
@@ -147,6 +147,8 @@
args.append(self.getvar(arg))
except KeyError:
raise ParseError("Unknown var: %s" % arg)
+ if hasattr(descr, '_oparser_uses_descr'):
+ descr._oparser_uses_descr(self, args)
return opnum, args, descr
def parse_result_op(self, line):
Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_optimizeopt.py Thu Jul 23 17:30:01 2009
@@ -1,8 +1,11 @@
import py
+from pypy.jit.metainterp.test.test_resume import MyMetaInterp
from pypy.jit.metainterp.test.test_optimizefindnode import (LLtypeMixin,
OOtypeMixin,
BaseTest)
from pypy.jit.metainterp.optimizeopt import optimize
+from pypy.jit.metainterp.history import AbstractDescr
+from pypy.jit.metainterp import resume
from pypy.jit.metainterp.resoperation import rop, opname
from pypy.jit.metainterp.test.oparser import parse
@@ -570,28 +573,55 @@
self.optimize_loop(ops, 'Not', expected, i1=5,
boxkinds={'myptr': self.nodebox.value})
- def test_expand_fail_arguments(self):
+ # ----------
+
+ def make_fail_descr(self, boxestext):
+ class FailDescr(AbstractDescr):
+ args_seen = []
+ def _oparser_uses_descr(self, oparse, args):
+ # typically called twice, before and after optimization
+ if len(self.args_seen) == 0:
+ boxes = [oparse.box_for_var(boxtext.strip())
+ for boxtext in boxestext.split(',')]
+ builder = resume.ResumeDataBuilder()
+ builder.generate_boxes(boxes)
+ liveboxes = builder.finish(fdescr)
+ assert liveboxes == args
+ self.args_seen.append((args, oparse))
+ #
+ fdescr = FailDescr()
+ self.fdescr = fdescr
+ self.namespace['fdescr'] = fdescr
+
+ def check_expanded_fail_descr(self, expectedtext):
+ fdescr = self.fdescr
+ args, oparse = fdescr.args_seen[-1]
+ reader = resume.ResumeDataReader(fdescr, args, MyMetaInterp())
+ boxes = reader.consume_boxes()
+ expected = [oparse.getvar(boxtext.strip())
+ for boxtext in expectedtext.split(',')]
+ assert boxes == expected
+
+ def test_expand_fail_1(self):
+ self.make_fail_descr('i2, i3')
ops = """
- [i1, i2, i3, p3]
- p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
- p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
- setfield_gc(p1, 1, descr=valuedescr)
- setfield_gc(p1, p2, descr=nextdescr)
- setfield_gc(p2, i2, descr=valuedescr)
- setfield_gc(p2, p3, descr=nextdescr)
+ [i1, i3]
+ i2 = int_add(10, 5)
guard_true(i1)
- fail(p1, i3)
- jump(i2, i1, i3, p3)
+ fail(i2, i3, descr=fdescr)
+ jump(i1, i3)
"""
expected = """
- [i1, i2, i3, p3]
+ [i1, i3]
guard_true(i1)
- fail(i2, p3, i3)
- jump(i2, 1, i3, p3)
+ fail(i3, descr=fdescr)
+ jump(1, i3)
"""
- self.optimize_loop(ops, 'Not, Not, Not, Not', expected, i1=1)
+ self.optimize_loop(ops, 'Not, Not', expected, i1=1, i2=15)
+ self.check_expanded_fail_descr('15, i3')
- def test_expand_fail_loop(self):
+ def test_expand_fail_2(self):
+ py.test.skip("in-progress")
ops = """
[i1, i2]
p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
@@ -604,12 +634,44 @@
expected = """
[i1, i2]
guard_true(i1)
- fail(i2)
+ p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ setfield_gc(p1, i2, descr=valuedescr)
+ setfield_gc(p1, p1, descr=nextdescr)
+ fail(p1)
jump(1, i2)
"""
self.optimize_loop(ops, 'Not, Not', expected, i1=1)
- def test_expand_fail_duplicate(self):
+ def test_expand_fail_3(self):
+ py.test.skip("in-progress")
+ ops = """
+ [i1, i2, i3, p3]
+ p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ setfield_gc(p1, 1, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p2, p3, descr=nextdescr)
+ guard_true(i1)
+ fail(p1, i3)
+ jump(i2, i1, i3, p3)
+ """
+ expected = """
+ [i1, i2, i3, p3]
+ guard_true(i1)
+ p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ setfield_gc(p1, 1, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p2, p3, descr=nextdescr)
+ fail(p1, i3)
+ jump(i2, 1, i3, p3)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', expected, i1=1)
+
+ def test_expand_fail_4(self):
+ py.test.skip("in-progress")
ops = """
[i1, i2]
p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
@@ -624,17 +686,22 @@
expected = """
[i1, i2]
guard_true(i1)
- fail(i2)
+ p1 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ p2 = new_with_vtable(ConstClass(node_vtable), descr=nodesize)
+ setfield_gc(p1, i2, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ setfield_gc(p2, i2, descr=valuedescr)
+ fail(%s)
jump(1, i2)
"""
- self.optimize_loop(ops % 'p1', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'p1, i2', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'p1, i2, i2', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'i2, p1, i2', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'i2, i2, p1', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'p1, p1', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'p1, p2', 'Not, Not', expected, i1=1)
- self.optimize_loop(ops % 'p2, p1', 'Not, Not', expected, i1=1)
+ self.optimize_loop(ops % 'p1', 'Not, Not',
+ expected % 'p1', i1=1)
+ self.optimize_loop(ops % 'p1, i2', 'Not, Not',
+ expected % 'p1, i2', i1=1)
+ self.optimize_loop(ops % 'i2, p1', 'Not, Not',
+ expected % 'i2, p1', i1=1)
+ self.optimize_loop(ops % 'p1, p2', 'Not, Not',
+ expected % 'p1, p2', i1=1)
class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
Modified: pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py (original)
+++ pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp/test/test_resume.py Thu Jul 23 17:30:01 2009
@@ -60,15 +60,40 @@
def execute_and_record(self, opnum, argboxes, descr=None):
return executor.execute(LLtypeMixin.cpu, opnum, argboxes, descr)
+demo55 = lltype.malloc(LLtypeMixin.NODE)
+demo55o = lltype.cast_opaque_ptr(llmemory.GCREF, demo55)
-def test_virtual_adder():
- py.test.skip("not enabled")
- # see r66529 in pypy/branch/pyjitpl5-optimize4/pypy/jit/metainterp
+
+def test_virtual_adder_no_op():
+ storage = make_demo_storage()
+ b1s, b2s, b3s = [BoxInt(1), BoxPtr(), BoxInt(3)]
+ modifier = ResumeDataVirtualAdder(storage, [b1s, b2s, b3s])
+ assert not modifier.is_virtual(b1s)
+ assert not modifier.is_virtual(b2s)
+ assert not modifier.is_virtual(b3s)
+ # done
+ liveboxes = modifier.finish()
+ assert liveboxes == [b1s, b2s, b3s]
+ #
+ b1t, b2t, b3t = [BoxInt(11), BoxPtr(demo55o), BoxInt(33)]
+ reader = ResumeDataReader(storage, [b1t, b2t, b3t], MyMetaInterp())
+ lst = reader.consume_boxes()
+ assert lst == [b1t, ConstInt(1), b1t, b2t]
+ lst = reader.consume_boxes()
+ assert lst == [ConstInt(2), ConstInt(3)]
+ lst = reader.consume_boxes()
+ assert lst == [b1t, b2t, b3t]
+
+
+def test_virtual_adder_make_virtual():
storage = make_demo_storage()
b1s, b2s, b3s, b4s, b5s = [BoxInt(1), BoxPtr(), BoxInt(3),
BoxPtr(), BoxPtr()]
c1s = ConstInt(111)
modifier = ResumeDataVirtualAdder(storage, [b1s, b2s, b3s])
+ assert not modifier.is_virtual(b1s)
+ assert not modifier.is_virtual(b2s)
+ assert not modifier.is_virtual(b3s)
modifier.make_virtual(b2s,
ConstAddr(LLtypeMixin.node_vtable_adr,
LLtypeMixin.cpu),
@@ -82,24 +107,23 @@
[LLtypeMixin.nextdescr, LLtypeMixin.valuedescr,
LLtypeMixin.otherdescr],
[b2s, b3s, b5s]) # new fields
+ assert not modifier.is_virtual(b1s)
+ assert modifier.is_virtual(b2s)
+ assert not modifier.is_virtual(b3s)
+ assert modifier.is_virtual(b4s)
+ assert not modifier.is_virtual(b5s)
# done
liveboxes = modifier.finish()
- # we get 'liveboxes' in an unspecified order
- sortedliveboxes = liveboxes[:]
- sortedliveboxes.sort(key=lambda box: box.value)
- assert sortedliveboxes == [b1s,
- #b2s -- virtual
- b3s,
- #b4s -- virtual
- #b2s -- again, shared
- #b3s -- again, shared
- b5s]
+ assert liveboxes == [b1s,
+ #b2s -- virtual
+ b3s,
+ #b4s -- virtual
+ #b2s -- again, shared
+ #b3s -- again, shared
+ b5s]
#
- demo55 = lltype.malloc(LLtypeMixin.NODE)
- demo55o = lltype.cast_opaque_ptr(llmemory.GCREF, demo55)
b1t, b3t, b5t = [BoxInt(11), BoxInt(33), BoxPtr(demo55o)]
- newliveboxes = [{b1s:b1t, b3s:b3t, b5s:b5t}[bs] for bs in liveboxes]
- reader = ResumeDataReader(storage, newliveboxes, MyMetaInterp())
+ reader = ResumeDataReader(storage, [b1t, b3t, b5t], MyMetaInterp())
lst = reader.consume_boxes()
b2t = lst[-1]
assert lst == [b1t, ConstInt(1), b1t, b2t]
@@ -116,3 +140,26 @@
assert ptr2.other == demo55
assert ptr2.parent.value == 33
assert ptr2.parent.next == ptr
+
+
+def test_virtual_adder_make_constant():
+ storage = make_demo_storage()
+ b1s, b2s, b3s = [BoxInt(1), BoxPtr(), BoxInt(3)]
+ modifier = ResumeDataVirtualAdder(storage, [b1s, b2s, b3s])
+ modifier.make_constant(b1s, ConstInt(111)) # <-------
+ assert not modifier.is_virtual(b1s)
+ assert not modifier.is_virtual(b2s)
+ assert not modifier.is_virtual(b3s)
+ # done
+ liveboxes = modifier.finish()
+ assert liveboxes == [b2s, b3s]
+ #
+ b2t, b3t = [BoxPtr(demo55o), BoxInt(33)]
+ reader = ResumeDataReader(storage, [b2t, b3t], MyMetaInterp())
+ lst = reader.consume_boxes()
+ c1t = ConstInt(111)
+ assert lst == [c1t, ConstInt(1), c1t, b2t]
+ lst = reader.consume_boxes()
+ assert lst == [ConstInt(2), ConstInt(3)]
+ lst = reader.consume_boxes()
+ assert lst == [c1t, b2t, b3t]
More information about the Pypy-commit
mailing list