[pypy-svn] r69812 - in pypy/trunk/pypy/jit: backend backend/llgraph backend/test backend/x86 backend/x86/test metainterp metainterp/test
arigo at codespeak.net
arigo at codespeak.net
Tue Dec 1 17:51:15 CET 2009
Author: arigo
Date: Tue Dec 1 17:51:14 2009
New Revision: 69812
Modified:
pypy/trunk/pypy/jit/backend/llgraph/runner.py
pypy/trunk/pypy/jit/backend/model.py
pypy/trunk/pypy/jit/backend/test/runner_test.py
pypy/trunk/pypy/jit/backend/x86/assembler.py
pypy/trunk/pypy/jit/backend/x86/runner.py
pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py
pypy/trunk/pypy/jit/metainterp/compile.py
pypy/trunk/pypy/jit/metainterp/pyjitpl.py
pypy/trunk/pypy/jit/metainterp/test/test_pyjitpl.py
Log:
(cfbolz, arigo)
Kill ResumeDescr.fail_arg_types, because it can be reconstructed
from information that the backend needs to save anyway. Add the
cpu.make_boxes_from_latest_value() interface to do that. Saves
a byte per fail_arg on every guard.
Small renamings in the corresponding logic in x86/assembler.py.
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 Dec 1 17:51:14 2009
@@ -166,6 +166,13 @@
if op.is_guard():
faildescr = op.descr
assert isinstance(faildescr, history.AbstractFailDescr)
+ faildescr._fail_args_types = []
+ for box in op.fail_args:
+ if box is None:
+ type = history.HOLE
+ else:
+ type = box.type
+ faildescr._fail_args_types.append(type)
fail_index = self.get_fail_descr_number(faildescr)
index = llimpl.compile_add_fail(c, fail_index)
faildescr._compiled_fail = c, index
@@ -235,6 +242,23 @@
token = llimpl.get_frame_forced_token(self.latest_frame)
return self.cast_adr_to_int(token)
+ def make_boxes_from_latest_values(self, faildescr):
+ inputargs_and_holes = []
+ for i in range(len(faildescr._fail_args_types)):
+ boxtype = faildescr._fail_args_types[i]
+ if boxtype == history.INT:
+ box = history.BoxInt(self.get_latest_value_int(i))
+ elif boxtype == history.REF:
+ box = self.ts.BoxRef(self.get_latest_value_ref(i))
+ elif boxtype == history.FLOAT:
+ box = history.BoxFloat(self.get_latest_value_float(i))
+ elif boxtype == history.HOLE:
+ box = None
+ else:
+ assert False, "bad box type: num=%d" % ord(boxtype)
+ inputargs_and_holes.append(box)
+ return inputargs_and_holes
+
# ----------
def get_exception(self):
Modified: pypy/trunk/pypy/jit/backend/model.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/model.py (original)
+++ pypy/trunk/pypy/jit/backend/model.py Tue Dec 1 17:51:14 2009
@@ -83,6 +83,12 @@
same FORCE_TOKEN result as the one in the just-failed loop."""
raise NotImplementedError
+ def make_boxes_from_latest_value(self, faildescr):
+ """Build a list of Boxes (and None for holes) that contains
+ the current values, as would be returned by calls to
+ get_latest_value_xxx()."""
+ raise NotImplementedError
+
def get_exception(self):
raise NotImplementedError
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 Dec 1 17:51:14 2009
@@ -238,6 +238,32 @@
res = self.cpu.get_latest_value_int(0)
assert res == 20
+ def test_make_boxes_from_latest_values(self):
+ i0 = BoxInt()
+ i1 = BoxInt()
+ i2 = BoxInt()
+ faildescr1 = BasicFailDescr(1)
+ 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)
+
+ self.cpu.set_future_value_int(0, 2)
+ fail = self.cpu.execute_token(looptoken)
+ assert fail is faildescr1
+ boxes = self.cpu.make_boxes_from_latest_values(faildescr1)
+ assert len(boxes) == 3
+ assert boxes[0] is None
+ assert isinstance(boxes[1], BoxInt)
+ assert boxes[1].value == 10
+ assert boxes[2] is None
+
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 Dec 1 17:51:14 2009
@@ -1,8 +1,8 @@
import sys, os
import ctypes
from pypy.jit.backend.llsupport import symbolic
-from pypy.jit.metainterp.history import Const, Box, BoxPtr, INT, REF, FLOAT
-from pypy.jit.metainterp.history import AbstractFailDescr
+from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
+from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT
from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory
from pypy.rpython.lltypesystem.rclass import OBJECT
from pypy.rpython.lltypesystem.lloperation import llop
@@ -798,9 +798,9 @@
DESCR_INT = 0x01
DESCR_FLOAT = 0x02
DESCR_SPECIAL = 0x03
- DESCR_FROMSTACK = 8
- DESCR_STOP = 0 | DESCR_SPECIAL
- DESCR_HOLE = 4 | DESCR_SPECIAL
+ CODE_FROMSTACK = 4*8
+ CODE_STOP = 0 | DESCR_SPECIAL
+ CODE_HOLE = 4 | DESCR_SPECIAL
def write_failure_recovery_description(self, mc, failargs, locs):
for i in range(len(failargs)):
@@ -816,7 +816,7 @@
raise AssertionError("bogus kind")
loc = locs[i]
if isinstance(loc, MODRM):
- n = self.DESCR_FROMSTACK + loc.position
+ n = self.CODE_FROMSTACK//4 + loc.position
else:
assert isinstance(loc, REG)
n = loc.op
@@ -825,9 +825,9 @@
mc.writechr((n & 0x7F) | 0x80)
n >>= 7
else:
- n = self.DESCR_HOLE
+ n = self.CODE_HOLE
mc.writechr(n)
- mc.writechr(self.DESCR_STOP)
+ mc.writechr(self.CODE_STOP)
# preallocate the fail_boxes
i = len(failargs) - 1
if i >= 0:
@@ -844,7 +844,7 @@
# decode the next instruction from the bytecode
code = rffi.cast(lltype.Signed, bytecode[0])
bytecode = rffi.ptradd(bytecode, 1)
- if code >= 4*self.DESCR_FROMSTACK:
+ if code >= self.CODE_FROMSTACK:
# 'code' identifies a stack location
if code > 0x7F:
shift = 7
@@ -857,15 +857,15 @@
if nextcode <= 0x7F:
break
kind = code & 3
- code = (code >> 2) - self.DESCR_FROMSTACK
+ code = (code - self.CODE_FROMSTACK) >> 2
if kind == self.DESCR_FLOAT:
size = 2
else:
size = 1
loc = X86StackManager.stack_pos(code, size)
- elif code == self.DESCR_STOP:
+ elif code == self.CODE_STOP:
break
- elif code == self.DESCR_HOLE:
+ elif code == self.CODE_HOLE:
continue
else:
# 'code' identifies a register
@@ -878,6 +878,39 @@
arglocs.append(loc)
return arglocs[:]
+ def make_boxes_from_latest_values(self, bytecode):
+ bytecode = rffi.cast(rffi.UCHARP, bytecode)
+ boxes = []
+ while 1:
+ # decode the next instruction from the bytecode
+ code = rffi.cast(lltype.Signed, bytecode[0])
+ bytecode = rffi.ptradd(bytecode, 1)
+ kind = code & 3
+ while code > 0x7F:
+ code = rffi.cast(lltype.Signed, bytecode[0])
+ bytecode = rffi.ptradd(bytecode, 1)
+ index = len(boxes)
+ if kind == self.DESCR_INT:
+ box = BoxInt(self.fail_boxes_int.getitem(index))
+ elif kind == self.DESCR_REF:
+ box = BoxPtr(self.fail_boxes_ptr.getitem(index))
+ # clear after reading (xxx duplicates
+ # get_latest_value_ref())
+ self.fail_boxes_ptr.setitem(index, lltype.nullptr(
+ llmemory.GCREF.TO))
+ elif kind == self.DESCR_FLOAT:
+ box = BoxFloat(self.fail_boxes_float.getitem(index))
+ else:
+ assert kind == self.DESCR_SPECIAL
+ if code == self.CODE_STOP:
+ break
+ elif code == self.CODE_HOLE:
+ box = None
+ else:
+ assert 0, "bad code"
+ boxes.append(box)
+ return boxes
+
def grab_frame_values(self, bytecode, frame_addr, allregisters):
# no malloc allowed here!!
self.fail_ebp = allregisters[16 + ebp.op]
@@ -887,7 +920,7 @@
# decode the next instruction from the bytecode
code = rffi.cast(lltype.Signed, bytecode[0])
bytecode = rffi.ptradd(bytecode, 1)
- if code >= 4*self.DESCR_FROMSTACK:
+ if code >= self.CODE_FROMSTACK:
if code > 0x7F:
shift = 7
code &= 0x7F
@@ -900,7 +933,7 @@
break
# load the value from the stack
kind = code & 3
- code = (code >> 2) - self.DESCR_FROMSTACK
+ code = (code - self.CODE_FROMSTACK) >> 2
stackloc = frame_addr + get_ebp_ofs(code)
value = rffi.cast(rffi.LONGP, stackloc)[0]
if kind == self.DESCR_FLOAT:
@@ -910,10 +943,10 @@
# 'code' identifies a register: load its value
kind = code & 3
if kind == self.DESCR_SPECIAL:
- if code == self.DESCR_HOLE:
+ if code == self.CODE_HOLE:
num += 1
continue
- assert code == self.DESCR_STOP
+ assert code == self.CODE_STOP
break
code >>= 2
if kind == self.DESCR_FLOAT:
Modified: pypy/trunk/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/runner.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/runner.py Tue Dec 1 17:51:14 2009
@@ -62,6 +62,10 @@
def get_latest_force_token(self):
return self.assembler.fail_ebp + FORCE_INDEX_OFS
+ def make_boxes_from_latest_values(self, faildescr):
+ return self.assembler.make_boxes_from_latest_values(
+ faildescr._x86_failure_recovery_bytecode)
+
def execute_token(self, executable_token):
addr = executable_token._x86_bootstrap_code
func = rffi.cast(lltype.Ptr(self.BOOTSTRAP_TP), addr)
Modified: pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py (original)
+++ pypy/trunk/pypy/jit/backend/x86/test/test_assembler.py Tue Dec 1 17:51:14 2009
@@ -42,8 +42,8 @@
Assembler386.DESCR_INT + 4*(8+100),
Assembler386.DESCR_REF + 4*(8+101),
Assembler386.DESCR_FLOAT + 4*(8+110),
- Assembler386.DESCR_HOLE,
- Assembler386.DESCR_HOLE,
+ Assembler386.CODE_HOLE,
+ Assembler386.CODE_HOLE,
Assembler386.DESCR_INT + 4*ebx.op,
Assembler386.DESCR_REF + 4*esi.op,
Assembler386.DESCR_FLOAT + 4*xmm2.op]
@@ -52,7 +52,7 @@
double_byte_nums.append((num & 0x7F) | 0x80)
double_byte_nums.append(num >> 7)
assert mc.content == (nums[:3] + double_byte_nums + nums[6:] +
- [assembler.DESCR_STOP])
+ [assembler.CODE_STOP])
# also test rebuild_faillocs_from_descr(), which should not
# reproduce the holes at all
@@ -65,6 +65,35 @@
assert ([loc.assembler() for loc in newlocs] ==
[loc.assembler() for loc in locs if loc is not None])
+ # finally, test make_boxes_from_latest_values(), which should
+ # reproduce the holes
+ expected_classes = [BoxInt, BoxPtr, BoxFloat,
+ BoxInt, BoxPtr, BoxFloat,
+ type(None), type(None),
+ BoxInt, BoxPtr, BoxFloat]
+ ptrvalues = {}
+ S = lltype.GcStruct('S')
+ for i, cls in enumerate(expected_classes):
+ if cls == BoxInt:
+ assembler.fail_boxes_int.setitem(i, 1000 + i)
+ elif cls == BoxPtr:
+ s = lltype.malloc(S)
+ s_ref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
+ ptrvalues[i] = s_ref
+ assembler.fail_boxes_ptr.setitem(i, s_ref)
+ elif cls == BoxFloat:
+ assembler.fail_boxes_float.setitem(i, 42.5 + i)
+ boxes = assembler.make_boxes_from_latest_values(bytecode_addr)
+ assert len(boxes) == len(locs) == len(expected_classes)
+ for i, (box, expected_class) in enumerate(zip(boxes, expected_classes)):
+ assert type(box) is expected_class
+ if expected_class == BoxInt:
+ assert box.value == 1000 + i
+ elif expected_class == BoxPtr:
+ assert box.value == ptrvalues[i]
+ elif expected_class == BoxFloat:
+ assert box.value == 42.5 + i
+
# ____________________________________________________________
def test_failure_recovery_func_no_floats():
@@ -136,7 +165,7 @@
descr_bytecode = []
for i, (kind, loc) in enumerate(content):
if kind == 'hole':
- num = Assembler386.DESCR_HOLE
+ num = Assembler386.CODE_HOLE
else:
if kind == 'float':
value, lo, hi = get_random_float()
@@ -174,7 +203,7 @@
num >>= 7
descr_bytecode.append(num)
- descr_bytecode.append(Assembler386.DESCR_STOP)
+ descr_bytecode.append(Assembler386.CODE_STOP)
descr_bytecode.append(0xC3) # fail_index = 0x1C3
descr_bytecode.append(0x01)
descr_bytecode.append(0x00)
Modified: pypy/trunk/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/compile.py (original)
+++ pypy/trunk/pypy/jit/metainterp/compile.py Tue Dec 1 17:51:14 2009
@@ -215,13 +215,6 @@
def store_final_boxes(self, guard_op, boxes):
guard_op.fail_args = boxes
self.guard_opnum = guard_op.opnum
- 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
- # XXX ^^^ kill this attribute
def handle_fail(self, metainterp_sd):
from pypy.jit.metainterp.pyjitpl import MetaInterp
@@ -253,7 +246,7 @@
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)
+ liveboxes = metainterp.cpu.make_boxes_from_latest_values(self)
virtualizable_boxes, data = force_from_resumedata(metainterp,
liveboxes, self)
vinfo.write_boxes(virtualizable, virtualizable_boxes)
Modified: pypy/trunk/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/trunk/pypy/jit/metainterp/pyjitpl.py Tue Dec 1 17:51:14 2009
@@ -1692,7 +1692,7 @@
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_and_holes = self.load_values_from_failure(resumedescr)
+ inputargs_and_holes = self.cpu.make_boxes_from_latest_values(resumedescr)
if must_compile:
self.history = history.History(self.cpu)
self.history.inputargs = [box for box in inputargs_and_holes if box]
@@ -1702,25 +1702,6 @@
self.history = None # this means that is_blackholing() is true
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_and_holes = []
- for i in range(len(fail_arg_types)):
- boxtype = fail_arg_types[i]
- if boxtype == history.INT:
- box = history.BoxInt(cpu.get_latest_value_int(i))
- elif boxtype == history.REF:
- 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_and_holes.append(box)
- return inputargs_and_holes
-
def initialize_virtualizable(self, original_boxes):
vinfo = self.staticdata.virtualizable_info
if vinfo is not None:
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 Dec 1 17:51:14 2009
@@ -134,8 +134,8 @@
class FakeCPU:
ts = llhelper
- def get_latest_value_int(self, index):
- return index
+ def make_boxes_from_latest_values(self, faildescr):
+ return [BoxInt(0), None, BoxInt(2), None, BoxInt(4)]
class FakeStaticData:
cpu = FakeCPU()
@@ -150,10 +150,6 @@
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
More information about the Pypy-commit
mailing list