[pypy-commit] pypy default: Merge share-guard-info
fijal
noreply at buildbot.pypy.org
Sat Oct 3 11:03:28 CEST 2015
Author: fijal
Branch:
Changeset: r79945:054840779e3e
Date: 2015-10-03 11:03 +0200
http://bitbucket.org/pypy/pypy/changeset/054840779e3e/
Log: Merge share-guard-info
This branch shares guard resume descr wherever possible during the
backend. Saves quite a bit of memory and also time when tracing
diff too long, truncating to 2000 out of 2705 lines
diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -39,7 +39,10 @@
def product_check(s):
i = 1
for x in s:
- i = ovfcheck(i * x)
+ try:
+ i = ovfcheck(i * x)
+ except OverflowError:
+ raise
return i
def check_and_adjust_index(space, index, size, axis):
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -249,11 +249,17 @@
ix = 1
while iw > 0:
if iw & 1:
- ix = ovfcheck(ix * temp)
+ try:
+ ix = ovfcheck(ix * temp)
+ except OverflowError:
+ raise
iw >>= 1 # Shift exponent down by 1 bit
if iw == 0:
break
- temp = ovfcheck(temp * temp) # Square the value of temp
+ try:
+ temp = ovfcheck(temp * temp) # Square the value of temp
+ except OverflowError:
+ raise
if iz:
# If we did a multiplication, perform a modulo
ix %= iz
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -671,6 +671,8 @@
a0, a1 = boxes
imm_a1 = check_imm_box(a1)
l0 = self.make_sure_var_in_reg(a0, boxes)
+ op.getdescr().make_a_counter_per_value(op,
+ self.cpu.all_reg_indexes[l0.value])
if not imm_a1:
l1 = self.make_sure_var_in_reg(a1, boxes)
else:
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -40,6 +40,10 @@
self.inputargs = map(mapping, inputargs)
self.operations = []
for op in operations:
+ if op.getopnum() == rop.GUARD_VALUE:
+ # we don't care about the value 13 here, because we gonna
+ # fish it from the extra slot on frame anyway
+ op.getdescr().make_a_counter_per_value(op, 13)
if op.getdescr() is not None:
if op.is_guard() or op.getopnum() == rop.FINISH:
newdescr = op.getdescr()
@@ -372,6 +376,18 @@
except ExecutionFinished, e:
return e.deadframe
+ def get_value_direct(self, deadframe, tp, index):
+ v = deadframe._extra_value
+ if tp == 'i':
+ assert lltype.typeOf(v) == lltype.Signed
+ elif tp == 'r':
+ assert lltype.typeOf(v) == llmemory.GCREF
+ elif tp == 'f':
+ assert lltype.typeOf(v) == longlong.FLOATSTORAGE
+ else:
+ assert False
+ return v
+
def get_int_value(self, deadframe, index):
v = deadframe._values[index]
assert lltype.typeOf(v) == lltype.Signed
@@ -775,11 +791,13 @@
_TYPE = llmemory.GCREF
def __init__(self, latest_descr, values,
- last_exception=None, saved_data=None):
+ last_exception=None, saved_data=None,
+ extra_value=None):
self._latest_descr = latest_descr
self._values = values
self._last_exception = last_exception
self._saved_data = saved_data
+ self._extra_value = extra_value
class LLFrame(object):
@@ -872,7 +890,7 @@
# -----------------------------------------------------
- def fail_guard(self, descr, saved_data=None):
+ def fail_guard(self, descr, saved_data=None, extra_value=None):
values = []
for box in self.current_op.getfailargs():
if box is not None:
@@ -887,7 +905,7 @@
else:
raise ExecutionFinished(LLDeadFrame(descr, values,
self.last_exception,
- saved_data))
+ saved_data, extra_value))
def execute_force_spill(self, _, arg):
pass
@@ -909,7 +927,7 @@
def execute_guard_value(self, descr, arg1, arg2):
if arg1 != arg2:
- self.fail_guard(descr)
+ self.fail_guard(descr, extra_value=arg1)
def execute_guard_nonnull(self, descr, arg):
if not arg:
@@ -1028,7 +1046,6 @@
def execute_guard_overflow(self, descr):
if not self.overflow_flag:
self.fail_guard(descr)
- return lltype.nullptr(llmemory.GCREF.TO) # I think it's fine....
def execute_jump(self, descr, *args):
raise Jump(descr._llgraph_target, args)
diff --git a/rpython/jit/backend/llsupport/llmodel.py b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -389,20 +389,40 @@
descr = self.get_latest_descr(deadframe)
return rffi.cast(lltype.Signed, descr.rd_locs[index]) * WORD
+ @specialize.arg(2)
+ def get_value_direct(self, deadframe, tp, index):
+ if tp == 'i':
+ return self.get_int_value_direct(deadframe, index * WORD)
+ elif tp == 'r':
+ return self.get_ref_value_direct(deadframe, index * WORD)
+ elif tp == 'f':
+ return self.get_float_value_direct(deadframe, index * WORD)
+ else:
+ assert False
+
def get_int_value(self, deadframe, index):
pos = self._decode_pos(deadframe, index)
+ return self.get_int_value_direct(deadframe, pos)
+
+ def get_int_value_direct(self, deadframe, pos):
descr = self.gc_ll_descr.getframedescrs(self).arraydescr
ofs = self.unpack_arraydescr(descr)
return self.read_int_at_mem(deadframe, pos + ofs, WORD, 1)
def get_ref_value(self, deadframe, index):
pos = self._decode_pos(deadframe, index)
+ return self.get_ref_value_direct(deadframe, pos)
+
+ def get_ref_value_direct(self, deadframe, pos):
descr = self.gc_ll_descr.getframedescrs(self).arraydescr
ofs = self.unpack_arraydescr(descr)
return self.read_ref_at_mem(deadframe, pos + ofs)
def get_float_value(self, deadframe, index):
pos = self._decode_pos(deadframe, index)
+ return self.get_float_value_direct(deadframe, pos)
+
+ def get_float_value_direct(self, deadframe, pos):
descr = self.gc_ll_descr.getframedescrs(self).arraydescr
ofs = self.unpack_arraydescr(descr)
return self.read_float_at_mem(deadframe, pos + ofs)
diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py
--- a/rpython/jit/backend/test/test_random.py
+++ b/rpython/jit/backend/test/test_random.py
@@ -22,6 +22,8 @@
self.operations = subops
class FakeMetaInterp(object):
+ ovf_flag = False
+
def execute_raised(self, exc, constant=False):
self._got_exc = exc
@@ -365,9 +367,9 @@
def produce_into(self, builder, r):
fail_subset = builder.subset_of_intvars(r)
original_intvars = builder.intvars[:]
+ builder.fakemetainterp.ovf_flag = False
super(AbstractOvfOperation, self).produce_into(builder, r)
- if builder.fakemetainterp._got_exc: # overflow detected
- assert isinstance(builder.fakemetainterp._got_exc, OverflowError)
+ if builder.fakemetainterp.ovf_flag: # overflow detected
op = ResOperation(rop.GUARD_OVERFLOW, [])
# the overflowed result should not be used any more, but can
# be used on the failure path: recompute fail_subset including
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -424,6 +424,8 @@
def consider_guard_value(self, op):
x = self.make_sure_var_in_reg(op.getarg(0))
+ loc = self.assembler.cpu.all_reg_indexes[x.value]
+ op.getdescr().make_a_counter_per_value(op, loc)
y = self.loc(op.getarg(1))
self.perform_guard(op, [x, y], None)
diff --git a/rpython/jit/codewriter/codewriter.py b/rpython/jit/codewriter/codewriter.py
--- a/rpython/jit/codewriter/codewriter.py
+++ b/rpython/jit/codewriter/codewriter.py
@@ -48,7 +48,7 @@
# which means mostly producing a linear list of operations and
# inserting jumps or conditional jumps. This is a list of tuples
# of the shape ("opname", arg1, ..., argN) or (Label(...),).
- ssarepr = flatten_graph(graph, regallocs)
+ ssarepr = flatten_graph(graph, regallocs, cpu=self.callcontrol.cpu)
#
# step 3b: compute the liveness around certain operations
compute_liveness(ssarepr)
diff --git a/rpython/jit/codewriter/flatten.py b/rpython/jit/codewriter/flatten.py
--- a/rpython/jit/codewriter/flatten.py
+++ b/rpython/jit/codewriter/flatten.py
@@ -1,4 +1,4 @@
-from rpython.flowspace.model import Variable, Constant
+from rpython.flowspace.model import Variable, Constant, c_last_exception
from rpython.jit.metainterp.history import AbstractDescr, getkind
from rpython.rtyper.lltypesystem import lltype
@@ -60,10 +60,11 @@
# ____________________________________________________________
-def flatten_graph(graph, regallocs, _include_all_exc_links=False):
+def flatten_graph(graph, regallocs, _include_all_exc_links=False,
+ cpu=None):
"""Flatten the graph into an SSARepr, with already-computed register
allocations. 'regallocs' in a dict {kind: RegAlloc}."""
- flattener = GraphFlattener(graph, regallocs, _include_all_exc_links)
+ flattener = GraphFlattener(graph, regallocs, _include_all_exc_links, cpu)
flattener.enforce_input_args()
flattener.generate_ssa_form()
return flattener.ssarepr
@@ -71,9 +72,11 @@
class GraphFlattener(object):
- def __init__(self, graph, regallocs, _include_all_exc_links=False):
+ def __init__(self, graph, regallocs, _include_all_exc_links=False,
+ cpu=None):
self.graph = graph
self.regallocs = regallocs
+ self.cpu = cpu
self._include_all_exc_links = _include_all_exc_links
self.registers = {}
if graph:
@@ -100,7 +103,7 @@
self.seen_blocks = {}
self.make_bytecode_block(self.graph.startblock)
- def make_bytecode_block(self, block):
+ def make_bytecode_block(self, block, handling_ovf=False):
if block.exits == ():
self.make_return(block.inputargs)
return
@@ -114,9 +117,15 @@
#
operations = block.operations
for i, op in enumerate(operations):
+ if '_ovf' in op.opname:
+ if (len(block.exits) not in (2, 3) or
+ block.exitswitch is not c_last_exception):
+ raise Exception("detected a block containing ovfcheck()"
+ " but no OverflowError is caught, this"
+ " is not legal in jitted blocks")
self.serialize_op(op)
#
- self.insert_exits(block)
+ self.insert_exits(block, handling_ovf)
def make_return(self, args):
if len(args) == 1:
@@ -136,16 +145,16 @@
raise Exception("?")
self.emitline("---")
- def make_link(self, link):
+ def make_link(self, link, handling_ovf):
if (link.target.exits == ()
and link.last_exception not in link.args
and link.last_exc_value not in link.args):
self.make_return(link.args) # optimization only
return
self.insert_renamings(link)
- self.make_bytecode_block(link.target)
+ self.make_bytecode_block(link.target, handling_ovf)
- def make_exception_link(self, link):
+ def make_exception_link(self, link, handling_ovf):
# Like make_link(), but also introduces the 'last_exception' and
# 'last_exc_value' as variables if needed. Also check if the link
# is jumping directly to the re-raising exception block.
@@ -153,54 +162,74 @@
assert link.last_exc_value is not None
if link.target.operations == () and link.args == [link.last_exception,
link.last_exc_value]:
- self.emitline("reraise")
+ if handling_ovf:
+ exc_data = self.cpu.rtyper.exceptiondata
+ ll_ovf = exc_data.get_standard_ll_exc_instance_by_class(
+ OverflowError)
+ c = Constant(ll_ovf, concretetype=lltype.typeOf(ll_ovf))
+ self.emitline("raise", c)
+ else:
+ self.emitline("reraise")
self.emitline("---")
return # done
- self.make_link(link)
+ self.make_link(link, handling_ovf)
- def insert_exits(self, block):
+ def insert_exits(self, block, handling_ovf=False):
if len(block.exits) == 1:
# A single link, fall-through
link = block.exits[0]
assert link.exitcase in (None, False, True)
# the cases False or True should not really occur, but can show
# up in the manually hacked graphs for generators...
- self.make_link(link)
+ self.make_link(link, handling_ovf)
#
elif block.canraise:
# An exception block. See test_exc_exitswitch in test_flatten.py
# for an example of what kind of code this makes.
index = -1
- while True:
- lastopname = block.operations[index].opname
- if lastopname != '-live-':
- break
- index -= 1
+ opname = block.operations[index].opname
+ if '_ovf' in opname:
+ # ovf checking operation as a lat thing, -live- should be
+ # one before it
+ line = self.popline()
+ self.emitline(opname[:7] + '_jump_if_ovf',
+ TLabel(block.exits[1]), *line[1:])
+ assert len(block.exits) in (2, 3)
+ self.make_link(block.exits[0], False)
+ self.emitline(Label(block.exits[1]))
+ self.make_exception_link(block.exits[1], True)
+ if len(block.exits) == 3:
+ assert block.exits[2].exitcase is Exception
+ self.make_exception_link(block.exits[2], False)
+ return
+ else:
+ while True:
+ lastopname = block.operations[index].opname
+ if lastopname != '-live-':
+ break
+ index -= 1
assert block.exits[0].exitcase is None # is this always True?
#
if not self._include_all_exc_links:
if index == -1:
# cannot raise: the last instruction is not
# actually a '-live-'
- self.make_link(block.exits[0])
+ self.make_link(block.exits[0], False)
return
#
self.emitline('catch_exception', TLabel(block.exits[0]))
- self.make_link(block.exits[0])
+ self.make_link(block.exits[0], False)
self.emitline(Label(block.exits[0]))
for link in block.exits[1:]:
- if (link.exitcase is Exception or
- (link.exitcase is OverflowError and
- lastopname.startswith('int_') and
- lastopname.endswith('_ovf'))):
+ if link.exitcase is Exception:
# this link captures all exceptions
- self.make_exception_link(link)
+ self.make_exception_link(link, False)
break
self.emitline('goto_if_exception_mismatch',
Constant(link.llexitcase,
lltype.typeOf(link.llexitcase)),
TLabel(link))
- self.make_exception_link(link)
+ self.make_exception_link(link, False)
self.emitline(Label(link))
else:
# no link captures all exceptions, so we have to put a reraise
@@ -216,29 +245,26 @@
if linkfalse.llexitcase == True:
linkfalse, linktrue = linktrue, linkfalse
opname = 'goto_if_not'
- livebefore = False
if isinstance(block.exitswitch, tuple):
# special case produced by jtransform.optimize_goto_if_not()
opname = 'goto_if_not_' + block.exitswitch[0]
opargs = block.exitswitch[1:]
if opargs[-1] == '-live-before':
- livebefore = True
opargs = opargs[:-1]
else:
assert block.exitswitch.concretetype == lltype.Bool
opargs = [block.exitswitch]
#
lst = self.flatten_list(opargs) + [TLabel(linkfalse)]
- if livebefore:
- self.emitline('-live-')
+ self.emitline('-live-')
self.emitline(opname, *lst)
- if not livebefore:
- self.emitline('-live-', TLabel(linkfalse))
+ #if not livebefore:
+ # self.emitline('-live-', TLabel(linkfalse))
# true path:
- self.make_link(linktrue)
+ self.make_link(linktrue, handling_ovf)
# false path:
self.emitline(Label(linkfalse))
- self.make_link(linkfalse)
+ self.make_link(linkfalse, handling_ovf)
#
else:
# A switch.
@@ -261,7 +287,7 @@
switchdict)
# emit the default path
if block.exits[-1].exitcase == 'default':
- self.make_link(block.exits[-1])
+ self.make_link(block.exits[-1], handling_ovf)
else:
self.emitline("unreachable")
self.emitline("---")
@@ -275,7 +301,7 @@
# if the switched value doesn't match any case.
self.emitline(Label(switch))
self.emitline('-live-')
- self.make_link(switch)
+ self.make_link(switch, handling_ovf)
def insert_renamings(self, link):
renamings = {}
@@ -323,6 +349,9 @@
def emitline(self, *line):
self.ssarepr.insns.append(line)
+ def popline(self):
+ return self.ssarepr.insns.pop()
+
def flatten_list(self, arglist):
args = []
for v in arglist:
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -8,7 +8,8 @@
from rpython.jit.metainterp.history import getkind
from rpython.jit.metainterp.typesystem import deref, arrayItem
from rpython.jit.metainterp.blackhole import BlackholeInterpreter
-from rpython.flowspace.model import SpaceOperation, Variable, Constant
+from rpython.flowspace.model import SpaceOperation, Variable, Constant,\
+ c_last_exception
from rpython.rlib import objectmodel
from rpython.rlib.jit import _we_are_jitted
from rpython.rlib.rgc import lltype_is_gc
@@ -211,8 +212,8 @@
# ok! optimize this case
block.operations.remove(op)
block.exitswitch = (op.opname,) + tuple(op.args)
- if op.opname in ('ptr_iszero', 'ptr_nonzero'):
- block.exitswitch += ('-live-before',)
+ #if op.opname in ('ptr_iszero', 'ptr_nonzero'):
+ block.exitswitch += ('-live-before',)
# if the variable escape to the next block along a link,
# replace it with a constant, because we know its value
for link in block.exits:
@@ -333,13 +334,13 @@
def rewrite_op_int_add_ovf(self, op):
op0 = self._rewrite_symmetric(op)
op1 = SpaceOperation('-live-', [], None)
- return [op0, op1]
+ return [op1, op0]
rewrite_op_int_mul_ovf = rewrite_op_int_add_ovf
def rewrite_op_int_sub_ovf(self, op):
op1 = SpaceOperation('-live-', [], None)
- return [op, op1]
+ return [op1, op]
def _noop_rewrite(self, op):
return op
diff --git a/rpython/jit/codewriter/test/test_codewriter.py b/rpython/jit/codewriter/test/test_codewriter.py
--- a/rpython/jit/codewriter/test/test_codewriter.py
+++ b/rpython/jit/codewriter/test/test_codewriter.py
@@ -76,11 +76,11 @@
assert jitcode.num_regs_i() == 2
assert jitcode.num_regs_r() == 0
assert jitcode.num_regs_f() == 0
- assert jitcode._live_vars(5) == '%i0 %i1'
+ assert jitcode._live_vars(0) == '%i0 %i1'
#
from rpython.jit.codewriter.jitcode import MissingLiveness
for i in range(len(jitcode.code)+1):
- if i != 5:
+ if i != 0:
py.test.raises(MissingLiveness, jitcode._live_vars, i)
def test_call():
diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -140,6 +140,7 @@
def encoding_test(self, func, args, expected,
transform=False, liveness=False, cc=None, jd=None):
+
graphs = self.make_graphs(func, args)
#graphs[0].show()
if transform:
@@ -147,7 +148,8 @@
cc = cc or FakeCallControl()
transform_graph(graphs[0], FakeCPU(self.rtyper), cc, jd)
ssarepr = flatten_graph(graphs[0], fake_regallocs(),
- _include_all_exc_links=not transform)
+ _include_all_exc_links=not transform,
+ cpu=FakeCPU(self.rtyper))
if liveness:
from rpython.jit.codewriter.liveness import compute_liveness
compute_liveness(ssarepr)
@@ -169,8 +171,8 @@
return n + 1
self.encoding_test(f, [10], """
int_gt %i0, $0 -> %i1
+ -live-
goto_if_not %i1, L1
- -live- L1
int_copy %i0 -> %i2
int_sub %i2, $3 -> %i3
int_copy %i3 -> %i4
@@ -194,8 +196,8 @@
int_copy %i1 -> %i3
L1:
int_gt %i2, $0 -> %i4
+ -live-
goto_if_not %i4, L2
- -live- L2
int_copy %i2 -> %i5
int_copy %i3 -> %i6
int_add %i6, %i5 -> %i7
@@ -218,8 +220,8 @@
int_copy %i0 -> %i2
int_copy %i1 -> %i3
L1:
+ -live-
goto_if_not_int_gt %i2, $0, L2
- -live- L2
int_copy %i2 -> %i4
int_copy %i3 -> %i5
int_add %i5, %i4 -> %i6
@@ -457,8 +459,8 @@
# note that 'goto_if_not_int_is_true' is not the same thing
# as just 'goto_if_not', because the last one expects a boolean
self.encoding_test(f, [7], """
+ -live-
goto_if_not_int_is_true %i0, L1
- -live- L1
int_return $False
---
L1:
@@ -523,8 +525,8 @@
else:
return m2
self.encoding_test(f, [4, 5, 6], """
+ -live- %i0, %i1, %i2
goto_if_not_int_is_true %i0, L1
- -live- %i1, %i2, L1
int_return %i1
---
L1:
@@ -538,15 +540,59 @@
except OverflowError:
return 42
self.encoding_test(f, [7, 2], """
- int_add_ovf %i0, %i1 -> %i2
- -live- %i2
- catch_exception L1
+ -live- %i0, %i1
+ int_add_jump_if_ovf L1, %i0, %i1 -> %i2
int_return %i2
---
L1:
int_return $42
""", transform=True, liveness=True)
+ def test_multiple_int_add_ovf(self):
+ def f(i, j):
+ try:
+ ovfcheck(j + i)
+ return ovfcheck(i + j)
+ except OverflowError:
+ return 42
+ self.encoding_test(f, [7, 2], """
+ -live- %i0, %i1
+ int_add_jump_if_ovf L1, %i1, %i0 -> %i2
+ int_copy %i1 -> %i3
+ int_copy %i0 -> %i4
+ -live- %i3, %i4
+ int_add_jump_if_ovf L2, %i4, %i3 -> %i5
+ int_return %i5
+ ---
+ L2:
+ int_return $42
+ ---
+ L1:
+ int_return $42
+ """, transform=True, liveness=True)
+
+ def test_ovfcheck_no_catch(self):
+ def f(i, j):
+ return ovfcheck(i + j)
+ err = py.test.raises(Exception, "self.encoding_test(f, [7, 2], '',"
+ "transform=True, liveness=True)")
+ assert "ovfcheck()" in str(err)
+
+ def test_ovfcheck_reraise(self):
+ def f(i, j):
+ try:
+ ovfcheck(j + i)
+ except OverflowError:
+ raise
+ self.encoding_test(f, [7, 2], """
+ -live- %i0, %i1
+ int_add_jump_if_ovf L1, %i1, %i0 -> %i2
+ void_return
+ ---
+ L1:
+ raise $<* struct object>
+ """, transform=True, liveness=True)
+
def test_residual_call_raising(self):
@dont_look_inside
def g(i, j):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -15,7 +15,7 @@
for prod in result:
yield tuple(prod)
-from rpython.flowspace.model import FunctionGraph, Block, Link
+from rpython.flowspace.model import FunctionGraph, Block, Link, c_last_exception
from rpython.flowspace.model import SpaceOperation, Variable, Constant
from rpython.rtyper.lltypesystem import lltype, llmemory, rstr, rffi
from rpython.rtyper import rclass
@@ -187,7 +187,7 @@
res = Transformer().optimize_goto_if_not(block)
assert res == True
assert block.operations == [sp1, sp2]
- assert block.exitswitch == ('int_gt', v1, v2)
+ assert block.exitswitch == ('int_gt', v1, v2, '-live-before')
assert block.exits == exits
def test_optimize_goto_if_not__incoming():
@@ -211,7 +211,7 @@
res = Transformer().optimize_goto_if_not(block)
assert res == True
assert block.operations == []
- assert block.exitswitch == ('int_gt', v1, v2)
+ assert block.exitswitch == ('int_gt', v1, v2, '-live-before')
assert block.exits == exits
assert exits[1].args == [const(True)]
@@ -235,7 +235,7 @@
res = Transformer().optimize_goto_if_not(block)
assert res == True
assert block.operations == []
- assert block.exitswitch == (opname, v1, v2)
+ assert block.exitswitch == (opname, v1, v2, '-live-before')
assert block.exits == exits
def test_optimize_goto_if_not__ptr_iszero():
@@ -287,7 +287,7 @@
for v2 in [varoftype(lltype.Signed), const(43)]:
op = SpaceOperation('int_add_nonneg_ovf', [v1, v2], v3)
oplist = Transformer(FakeCPU()).rewrite_operation(op)
- op0, op1 = oplist
+ op1, op0 = oplist
assert op0.opname == 'int_add_ovf'
if isinstance(v1, Constant) and isinstance(v2, Variable):
assert op0.args == [v2, v1]
diff --git a/rpython/jit/codewriter/test/test_regalloc.py b/rpython/jit/codewriter/test/test_regalloc.py
--- a/rpython/jit/codewriter/test/test_regalloc.py
+++ b/rpython/jit/codewriter/test/test_regalloc.py
@@ -63,8 +63,8 @@
self.check_assembler(graph, """
L1:
int_gt %i0, $0 -> %i2
+ -live-
goto_if_not %i2, L2
- -live- L2
int_add %i1, %i0 -> %i1
int_sub %i0, $1 -> %i0
goto L1
@@ -82,8 +82,8 @@
self.check_assembler(graph, """
L1:
int_gt %i0, $0 -> %i2
+ -live-
goto_if_not %i2, L2
- -live- L2
int_push %i1
int_copy %i0 -> %i1
int_pop -> %i0
@@ -102,8 +102,8 @@
self.check_assembler(graph, """
L1:
int_gt %i0, $0 -> %i0
+ -live-
goto_if_not %i0, L2
- -live- L2
int_copy %i1 -> %i0
int_copy $2 -> %i1
goto L1
@@ -121,8 +121,8 @@
self.check_assembler(graph, """
L1:
int_gt %i0, $0 -> %i3
+ -live-
goto_if_not %i3, L2
- -live- L2
int_push %i1
int_copy %i2 -> %i1
int_copy %i0 -> %i2
@@ -142,8 +142,8 @@
self.check_assembler(graph, """
L1:
int_gt %i0, $0 -> %i3
+ -live-
goto_if_not %i3, L2
- -live- L2
int_copy %i2 -> %i1
goto L1
---
@@ -236,8 +236,8 @@
self.check_assembler(graph, """
int_lshift %i0, %i1 -> %i2
int_rshift %i2, %i1 -> %i1
+ -live-
goto_if_not_int_ne %i1, %i0, L1
- -live- L1
raise $<* struct object>
---
L1:
diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -212,6 +212,20 @@
assert lltype.typeOf(result) is longlong.FLOATSTORAGE
self.registers_f[ord(code[position])] = result
position += 1
+ elif resulttype == "iL":
+ result, new_position = result
+ if new_position != -1:
+ position = new_position
+ next_argcode = next_argcode + 2
+ else:
+ assert argcodes[next_argcode] == '>'
+ assert argcodes[next_argcode + 1] == 'i'
+ next_argcode = next_argcode + 2
+ if lltype.typeOf(result) is lltype.Bool:
+ result = int(result)
+ assert lltype.typeOf(result) is lltype.Signed
+ self.registers_i[ord(code[position])] = result
+ position += 1
elif resulttype == 'L':
assert result >= 0
position = result
@@ -394,17 +408,26 @@
def bhimpl_int_mul(a, b):
return intmask(a * b)
- @arguments("i", "i", returns="i")
- def bhimpl_int_add_ovf(a, b):
- return ovfcheck(a + b)
+ @arguments("L", "i", "i", returns="iL")
+ def bhimpl_int_add_jump_if_ovf(label, a, b):
+ try:
+ return ovfcheck(a + b), -1
+ except OverflowError:
+ return 0, label
- @arguments("i", "i", returns="i")
- def bhimpl_int_sub_ovf(a, b):
- return ovfcheck(a - b)
+ @arguments("L", "i", "i", returns="iL")
+ def bhimpl_int_sub_jump_if_ovf(label, a, b):
+ try:
+ return ovfcheck(a - b), -1
+ except OverflowError:
+ return 0, label
- @arguments("i", "i", returns="i")
- def bhimpl_int_mul_ovf(a, b):
- return ovfcheck(a * b)
+ @arguments("L", "i", "i", returns="iL")
+ def bhimpl_int_mul_jump_if_ovf(label, a, b):
+ try:
+ return ovfcheck(a * b), -1
+ except OverflowError:
+ return 0, label
@arguments("i", "i", returns="i")
def bhimpl_int_floordiv(a, b):
@@ -1465,57 +1488,9 @@
assert kind == 'v'
return lltype.nullptr(rclass.OBJECTPTR.TO)
- def _prepare_resume_from_failure(self, opnum, deadframe):
- from rpython.jit.metainterp.resoperation import rop
- #
- if opnum == rop.GUARD_FUTURE_CONDITION:
- pass
- elif opnum == rop.GUARD_TRUE:
- # Produced directly by some goto_if_not_xxx() opcode that did not
- # jump, but which must now jump. The pc is just after the opcode.
- self.position = self.jitcode.follow_jump(self.position)
- #
- elif opnum == rop.GUARD_FALSE:
- # Produced directly by some goto_if_not_xxx() opcode that jumped,
- # but which must no longer jump. The pc is just after the opcode.
- pass
- #
- elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS:
- # Produced by guard_class(), xxx_guard_value(), or a few other
- # opcodes like switch(). The pc is at the start of the opcode
- # (so it will be redone).
- pass
- #
- elif (opnum == rop.GUARD_NONNULL or
- opnum == rop.GUARD_ISNULL or
- opnum == rop.GUARD_NONNULL_CLASS):
- # Produced by goto_if_not_ptr_{non,is}zero(). The pc is at the
- # start of the opcode (so it will be redone); this is needed
- # because of GUARD_NONNULL_CLASS.
- pass
- #
- elif (opnum == rop.GUARD_NO_EXCEPTION or
- opnum == rop.GUARD_EXCEPTION or
- opnum == rop.GUARD_NOT_FORCED):
- return lltype.cast_opaque_ptr(rclass.OBJECTPTR,
- self.cpu.grab_exc_value(deadframe))
- #
- elif opnum == rop.GUARD_NO_OVERFLOW:
- # Produced by int_xxx_ovf(). The pc is just after the opcode.
- # We get here because it did not used to overflow, but now it does.
- return get_llexception(self.cpu, OverflowError())
- #
- elif opnum == rop.GUARD_OVERFLOW:
- # Produced by int_xxx_ovf(). The pc is just after the opcode.
- # We get here because it used to overflow, but now it no longer
- # does.
- pass
- elif opnum == rop.GUARD_NOT_INVALIDATED:
- pass
- else:
- from rpython.jit.metainterp.resoperation import opname
- raise NotImplementedError(opname[opnum])
- return lltype.nullptr(rclass.OBJECTPTR.TO)
+ def _prepare_resume_from_failure(self, deadframe):
+ return lltype.cast_opaque_ptr(rclass.OBJECTPTR,
+ self.cpu.grab_exc_value(deadframe))
# connect the return of values from the called frame to the
# 'xxx_call_yyy' instructions from the caller frame
@@ -1641,8 +1616,7 @@
deadframe,
all_virtuals)
- current_exc = blackholeinterp._prepare_resume_from_failure(
- resumedescr.guard_opnum, deadframe)
+ current_exc = blackholeinterp._prepare_resume_from_failure(deadframe)
_run_forever(blackholeinterp, current_exc)
resume_in_blackhole._dont_inline_ = True
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -767,12 +767,15 @@
# fetch the actual value of the guard_value, possibly turning
# it to an integer
if typetag == self.TY_INT:
- intval = metainterp_sd.cpu.get_int_value(deadframe, index)
+ intval = metainterp_sd.cpu.get_value_direct(deadframe, 'i',
+ index)
elif typetag == self.TY_REF:
- refval = metainterp_sd.cpu.get_ref_value(deadframe, index)
+ refval = metainterp_sd.cpu.get_value_direct(deadframe, 'r',
+ index)
intval = lltype.cast_ptr_to_int(refval)
elif typetag == self.TY_FLOAT:
- floatval = metainterp_sd.cpu.get_float_value(deadframe, index)
+ floatval = metainterp_sd.cpu.get_value_direct(deadframe, 'f',
+ index)
intval = longlong.gethash_fast(floatval)
else:
assert 0, typetag
@@ -788,11 +791,6 @@
increment = jitdriver_sd.warmstate.increment_trace_eagerness
return jitcounter.tick(hash, increment)
- def get_index_of_guard_value(self):
- if (self.status & self.ST_TYPE_MASK) == 0:
- return -1
- return intmask(self.status >> self.ST_SHIFT)
-
def start_compiling(self):
# start tracing and compiling from this guard.
self.status |= self.ST_BUSY_FLAG
@@ -819,62 +817,24 @@
new_loop.original_jitcell_token,
metainterp.box_names_memo)
- def make_a_counter_per_value(self, guard_value_op):
+ def make_a_counter_per_value(self, guard_value_op, index):
assert guard_value_op.getopnum() == rop.GUARD_VALUE
box = guard_value_op.getarg(0)
- try:
- i = guard_value_op.getfailargs().index(box)
- except ValueError:
- return # xxx probably very rare
+ if box.type == history.INT:
+ ty = self.TY_INT
+ elif box.type == history.REF:
+ ty = self.TY_REF
+ elif box.type == history.FLOAT:
+ ty = self.TY_FLOAT
else:
- if box.type == history.INT:
- ty = self.TY_INT
- elif box.type == history.REF:
- ty = self.TY_REF
- elif box.type == history.FLOAT:
- ty = self.TY_FLOAT
- else:
- assert 0, box.type
- self.status = ty | (r_uint(i) << self.ST_SHIFT)
+ assert 0, box.type
+ self.status = ty | (r_uint(index) << self.ST_SHIFT)
-class ResumeGuardNonnullDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_NONNULL
-
-class ResumeGuardIsnullDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_ISNULL
-
-class ResumeGuardClassDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_CLASS
-
-class ResumeGuardTrueDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_TRUE
-
-class ResumeGuardFalseDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_FALSE
-
-class ResumeGuardNonnullClassDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_NONNULL_CLASS
-
-class ResumeGuardExceptionDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_EXCEPTION
-
-class ResumeGuardNoExceptionDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_NO_EXCEPTION
-
-class ResumeGuardOverflowDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_OVERFLOW
-
-class ResumeGuardNoOverflowDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_NO_OVERFLOW
-
-class ResumeGuardValueDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_VALUE
-
-class ResumeGuardNotInvalidated(ResumeGuardDescr):
- guard_opnum = rop.GUARD_NOT_INVALIDATED
+class ResumeGuardExcDescr(ResumeGuardDescr):
+ pass
class ResumeAtPositionDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_FUTURE_CONDITION
+ pass
class AllVirtuals:
llopaque = True
@@ -895,8 +855,6 @@
class ResumeGuardForcedDescr(ResumeGuardDescr):
- guard_opnum = rop.GUARD_NOT_FORCED
-
def _init(self, metainterp_sd, jitdriver_sd):
# to please the annotator
self.metainterp_sd = metainterp_sd
@@ -959,37 +917,13 @@
if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2:
resumedescr = ResumeGuardForcedDescr()
resumedescr._init(optimizer.metainterp_sd, optimizer.jitdriver_sd)
- elif opnum == rop.GUARD_NOT_INVALIDATED:
- resumedescr = ResumeGuardNotInvalidated()
- elif opnum == rop.GUARD_FUTURE_CONDITION:
- resumedescr = ResumeAtPositionDescr()
- elif opnum == rop.GUARD_VALUE:
- resumedescr = ResumeGuardValueDescr()
- elif opnum == rop.GUARD_NONNULL:
- resumedescr = ResumeGuardNonnullDescr()
- elif opnum == rop.GUARD_ISNULL:
- resumedescr = ResumeGuardIsnullDescr()
- elif opnum == rop.GUARD_NONNULL_CLASS:
- resumedescr = ResumeGuardNonnullClassDescr()
- elif opnum == rop.GUARD_CLASS:
- resumedescr = ResumeGuardClassDescr()
- elif opnum == rop.GUARD_TRUE:
- resumedescr = ResumeGuardTrueDescr()
- elif opnum == rop.GUARD_FALSE:
- resumedescr = ResumeGuardFalseDescr()
- elif opnum == rop.GUARD_EXCEPTION:
- resumedescr = ResumeGuardExceptionDescr()
- elif opnum == rop.GUARD_NO_EXCEPTION:
- resumedescr = ResumeGuardNoExceptionDescr()
- elif opnum == rop.GUARD_OVERFLOW:
- resumedescr = ResumeGuardOverflowDescr()
- elif opnum == rop.GUARD_NO_OVERFLOW:
- resumedescr = ResumeGuardNoOverflowDescr()
elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE):
# note - this only happens in tests
resumedescr = ResumeAtPositionDescr()
+ elif opnum in (rop.GUARD_EXCEPTION, rop.GUARD_NO_EXCEPTION):
+ resumedescr = ResumeGuardExcDescr()
else:
- assert False
+ resumedescr = ResumeGuardDescr()
return resumedescr
class ResumeFromInterpDescr(ResumeDescr):
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -253,7 +253,7 @@
z = ovfcheck(a + b)
except OverflowError:
assert metainterp is not None
- metainterp.execute_raised(OverflowError(), constant=True)
+ metainterp.ovf_flag = True
z = 0
return z
@@ -264,7 +264,7 @@
z = ovfcheck(a - b)
except OverflowError:
assert metainterp is not None
- metainterp.execute_raised(OverflowError(), constant=True)
+ metainterp.ovf_flag = True
z = 0
return z
@@ -275,7 +275,7 @@
z = ovfcheck(a * b)
except OverflowError:
assert metainterp is not None
- metainterp.execute_raised(OverflowError(), constant=True)
+ metainterp.ovf_flag = True
z = 0
return z
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -157,6 +157,9 @@
def __init__(self, identifier=None):
self.identifier = identifier # for testing
+ def make_a_counter_per_value(self, op, index):
+ pass # for testing
+
@specialize.argtype(0)
def newconst(value):
@@ -540,6 +543,9 @@
def check_consistency_of_branch(operations, seen, check_descr=True):
"NOT_RPYTHON"
for num, op in enumerate(operations):
+ if op.is_ovf():
+ assert operations[num + 1].getopnum() in (rop.GUARD_NO_OVERFLOW,
+ rop.GUARD_OVERFLOW)
for i in range(op.numargs()):
box = op.getarg(i)
if not isinstance(box, Const):
@@ -750,7 +756,6 @@
return tokens
def check_history(self, expected=None, **check):
- return
insns = {}
for op in self.operations:
opname = op.getopname()
diff --git a/rpython/jit/metainterp/jitprof.py b/rpython/jit/metainterp/jitprof.py
--- a/rpython/jit/metainterp/jitprof.py
+++ b/rpython/jit/metainterp/jitprof.py
@@ -143,6 +143,7 @@
self._print_intline("guards", cnt[Counters.GUARDS])
self._print_intline("opt ops", cnt[Counters.OPT_OPS])
self._print_intline("opt guards", cnt[Counters.OPT_GUARDS])
+ self._print_intline("opt guards shared", cnt[Counters.OPT_GUARDS_SHARED])
self._print_intline("forcings", cnt[Counters.OPT_FORCINGS])
self._print_intline("abort: trace too long",
cnt[Counters.ABORT_TOO_LONG])
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -11,7 +11,7 @@
from rpython.jit.metainterp.optimizeopt.shortpreamble import PreambleOp
from rpython.jit.metainterp.optimize import InvalidLoop
from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\
- AbstractResOp
+ AbstractResOp, GuardResOp
from rpython.rlib.objectmodel import we_are_translated
from rpython.jit.metainterp.optimizeopt import info
@@ -288,7 +288,7 @@
cf = submap[index] = ArrayCachedField(index)
return cf
- def emit_operation(self, op):
+ def emit_operation(self, op):
self.emitting_operation(op)
self.emit_postponed_op()
if (op.is_comparison() or op.is_call_may_force()
diff --git a/rpython/jit/metainterp/optimizeopt/info.py b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -104,6 +104,11 @@
self.last_guard_pos = -1
def mark_last_guard(self, optimizer):
+ if (optimizer.getlastop() is None or
+ not optimizer.getlastop().is_guard()):
+ # there can be a really emitted operation that's not a guard
+ # e.g. a setfield, ignore those
+ return
self.last_guard_pos = len(optimizer._newoperations) - 1
assert self.get_last_guard(optimizer).is_guard()
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -1,7 +1,6 @@
from rpython.jit.metainterp import jitprof, resume, compile
from rpython.jit.metainterp.executor import execute_nonspec_const
-from rpython.jit.metainterp.logger import LogOperations
-from rpython.jit.metainterp.history import Const, ConstInt, REF, ConstPtr
+from rpython.jit.metainterp.history import Const, ConstInt, ConstPtr
from rpython.jit.metainterp.optimizeopt.intutils import IntBound,\
ConstIntBound, MININT, MAXINT, IntUnbounded
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
@@ -10,6 +9,7 @@
from rpython.jit.metainterp.optimizeopt import info
from rpython.jit.metainterp.typesystem import llhelper
from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.debug import debug_print
@@ -260,6 +260,8 @@
self.optearlyforce = None
self.optunroll = None
+ self._last_guard_op = None
+
self.set_optimizations(optimizations)
self.setup()
@@ -526,6 +528,7 @@
if extra_jump:
self.first_optimization.propagate_forward(ops[-1])
self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
+
return (BasicLoopInfo(newargs, self.quasi_immutable_deps),
self._newoperations)
@@ -566,6 +569,7 @@
op.setarg(i, arg)
self.metainterp_sd.profiler.count(jitprof.Counters.OPT_OPS)
if op.is_guard():
+ assert isinstance(op, GuardResOp)
self.metainterp_sd.profiler.count(jitprof.Counters.OPT_GUARDS)
pendingfields = self.pendingfields
self.pendingfields = None
@@ -574,20 +578,85 @@
del self.replaces_guard[orig_op]
return
else:
- guard_op = self.replace_op_with(op, op.getopnum())
- op = self.store_final_boxes_in_guard(guard_op, pendingfields)
- # for unrolling
- for farg in op.getfailargs():
- if farg:
- self.force_box(farg)
+ op = self.emit_guard_operation(op, pendingfields)
elif op.can_raise():
self.exception_might_have_happened = True
+ if ((op.has_no_side_effect() or op.is_guard() or op.is_jit_debug() or
+ op.is_ovf()) and not self.is_call_pure_pure_canraise(op)):
+ pass
+ else:
+ self._last_guard_op = None
self._really_emitted_operation = op
self._newoperations.append(op)
+ def emit_guard_operation(self, op, pendingfields):
+ guard_op = self.replace_op_with(op, op.getopnum())
+ opnum = guard_op.getopnum()
+ if (self._last_guard_op and guard_op.getdescr() is None):
+ self.metainterp_sd.profiler.count_ops(opnum,
+ jitprof.Counters.OPT_GUARDS_SHARED)
+ op = self._copy_resume_data_from(guard_op,
+ self._last_guard_op)
+ else:
+ op = self.store_final_boxes_in_guard(guard_op, pendingfields)
+ self._last_guard_op = op
+ # for unrolling
+ for farg in op.getfailargs():
+ if farg:
+ self.force_box(farg)
+ if op.getopnum() == rop.GUARD_EXCEPTION:
+ self._last_guard_op = None
+ return op
+
+ def potentially_change_ovf_op_to_no_ovf(self, op):
+ # if last emitted operations was int_xxx_ovf and we are not emitting
+ # a guard_no_overflow change to int_add
+ if op.getopnum() != rop.GUARD_NO_OVERFLOW:
+ return
+ if not self._newoperations:
+ # got optimized otherwise
+ return
+ op = self._newoperations[-1]
+ if not op.is_ovf():
+ return
+ newop = self.replace_op_with_no_ovf(op)
+ self._newoperations[-1] = newop
+
+ def replace_op_with_no_ovf(self, op):
+ if op.getopnum() == rop.INT_MUL_OVF:
+ return self.replace_op_with(op, rop.INT_MUL)
+ elif op.getopnum() == rop.INT_ADD_OVF:
+ return self.replace_op_with(op, rop.INT_ADD)
+ elif op.getopnum() == rop.INT_SUB_OVF:
+ return self.replace_op_with(op, rop.INT_SUB)
+ else:
+ assert False
+
+
+ def _copy_resume_data_from(self, guard_op, last_guard_op):
+ if guard_op.getopnum() in (rop.GUARD_NO_EXCEPTION, rop.GUARD_EXCEPTION):
+ assert last_guard_op.getopnum() == rop.GUARD_NOT_FORCED
+ descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self)
+ descr.copy_all_attributes_from(last_guard_op.getdescr())
+ guard_op.setdescr(descr)
+ descr.store_final_boxes(guard_op, last_guard_op.getfailargs(),
+ self.metainterp_sd)
+ assert isinstance(guard_op, GuardResOp)
+ if guard_op.getopnum() == rop.GUARD_VALUE:
+ guard_op = self._maybe_replace_guard_value(guard_op, descr)
+ return guard_op
+
def getlastop(self):
return self._really_emitted_operation
+ def is_call_pure_pure_canraise(self, op):
+ if not op.is_call_pure():
+ return False
+ effectinfo = op.getdescr().get_extra_info()
+ if effectinfo.check_can_raise(ignore_memoryerror=True):
+ return True
+ return False
+
def replace_guard_op(self, old_op_pos, new_op):
old_op = self._newoperations[old_op_pos]
assert old_op.is_guard()
@@ -625,24 +694,26 @@
descr.store_final_boxes(op, newboxes, self.metainterp_sd)
#
if op.getopnum() == rop.GUARD_VALUE:
- if op.getarg(0).type == 'i':
- b = self.getintbound(op.getarg(0))
- if b.is_bool():
- # Hack: turn guard_value(bool) into guard_true/guard_false.
- # This is done after the operation is emitted to let
- # store_final_boxes_in_guard set the guard_opnum field of
- # the descr to the original rop.GUARD_VALUE.
- constvalue = op.getarg(1).getint()
- if constvalue == 0:
- opnum = rop.GUARD_FALSE
- elif constvalue == 1:
- opnum = rop.GUARD_TRUE
- else:
- raise AssertionError("uh?")
- newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr)
- return newop
- # a real GUARD_VALUE. Make it use one counter per value.
- descr.make_a_counter_per_value(op)
+ op = self._maybe_replace_guard_value(op, descr)
+ return op
+
+ def _maybe_replace_guard_value(self, op, descr):
+ if op.getarg(0).type == 'i':
+ b = self.getintbound(op.getarg(0))
+ if b.is_bool():
+ # Hack: turn guard_value(bool) into guard_true/guard_false.
+ # This is done after the operation is emitted to let
+ # store_final_boxes_in_guard set the guard_opnum field of
+ # the descr to the original rop.GUARD_VALUE.
+ constvalue = op.getarg(1).getint()
+ if constvalue == 0:
+ opnum = rop.GUARD_FALSE
+ elif constvalue == 1:
+ opnum = rop.GUARD_TRUE
+ else:
+ raise AssertionError("uh?")
+ newop = self.replace_op_with(op, opnum, [op.getarg(0)], descr)
+ return newop
return op
def optimize_default(self, op):
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -401,7 +401,7 @@
r = self.optimizer.metainterp_sd.logger_ops.repr_of_resop(op)
raise InvalidLoop('A GUARD_VALUE (%s) was proven to '
'always fail' % r)
- descr = compile.ResumeGuardValueDescr()
+ descr = compile.ResumeGuardDescr()
op = old_guard_op.copy_and_change(rop.GUARD_VALUE,
args = [old_guard_op.getarg(0), op.getarg(1)],
descr = descr)
@@ -411,7 +411,6 @@
# not put in short preambles guard_xxx and guard_value
# on the same box.
self.optimizer.replace_guard(op, info)
- descr.make_a_counter_per_value(op)
# to be safe
info.reset_last_guard_pos()
return op
@@ -453,7 +452,7 @@
if old_guard_op.getopnum() == rop.GUARD_NONNULL:
# it was a guard_nonnull, which we replace with a
# guard_nonnull_class.
- descr = compile.ResumeGuardNonnullClassDescr()
+ descr = compile.ResumeGuardDescr()
op = old_guard_op.copy_and_change (rop.GUARD_NONNULL_CLASS,
args = [old_guard_op.getarg(0), op.getarg(1)],
descr=descr)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -2022,6 +2022,7 @@
None)
def test_merge_guard_class_guard_value(self):
+ py.test.skip("disabled")
ops = """
[p1, i0, i1, i2, p2]
guard_class(p1, ConstClass(node_vtable)) [i0]
@@ -2055,6 +2056,7 @@
self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
def test_merge_guard_nonnull_guard_value(self):
+ py.test.skip("disabled")
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1) [i0]
@@ -2072,6 +2074,7 @@
self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
def test_merge_guard_nonnull_guard_class_guard_value(self):
+ py.test.skip("disabled")
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1) [i0]
@@ -2502,7 +2505,6 @@
if values is not None:
fail_args = values
fdescr = guard_op.getdescr()
- assert fdescr.guard_opnum == guard_opnum
reader = ResumeDataFakeReader(fdescr, fail_args,
MyMetaInterp(self.cpu))
boxes = reader.consume_boxes()
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -2967,6 +2967,7 @@
assert "promote of a virtual" in exc.msg
def test_merge_guard_class_guard_value(self):
+ py.test.skip("disabled")
ops = """
[p1, i0, i1, i2, p2]
guard_class(p1, ConstClass(node_vtable)) [i0]
@@ -3012,6 +3013,7 @@
#self.check_expanded_fail_descr("i0", rop.GUARD_NONNULL_CLASS)
def test_merge_guard_nonnull_guard_value(self):
+ py.test.skip("disabled")
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1) [i0]
@@ -3035,6 +3037,7 @@
#self.check_expanded_fail_descr("i0", rop.GUARD_VALUE)
def test_merge_guard_nonnull_guard_class_guard_value(self):
+ py.test.skip("disabled")
ops = """
[p1, i0, i1, i2, p2]
guard_nonnull(p1) [i0]
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -21,6 +21,7 @@
from rpython.rlib.unroll import unrolling_iterable
from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
from rpython.rtyper import rclass
+from rpython.rlib.objectmodel import compute_unique_id
@@ -228,17 +229,23 @@
''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper())
).compile()
- for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']:
+ for (_opimpl, resop) in [
+ ('int_add_jump_if_ovf', 'INT_ADD_OVF'),
+ ('int_sub_jump_if_ovf', 'INT_SUB_OVF'),
+ ('int_mul_jump_if_ovf', 'INT_MUL_OVF')]:
exec py.code.Source('''
- @arguments("box", "box")
- def opimpl_%s(self, b1, b2):
- self.metainterp.clear_exception()
+ @arguments("label", "box", "box", "orgpc")
+ def opimpl_%s(self, lbl, b1, b2, orgpc):
+ self.metainterp.ovf_flag = False
resbox = self.execute(rop.%s, b1, b2)
- self.make_result_of_lastop(resbox) # same as execute_varargs()
if not isinstance(resbox, Const):
- self.metainterp.handle_possible_overflow_error()
+ return self.handle_possible_overflow_error(lbl, orgpc,
+ resbox)
+ elif self.metainterp.ovf_flag:
+ self.pc = lbl
+ return None # but don't emit GUARD_OVERFLOW
return resbox
- ''' % (_opimpl, _opimpl.upper())).compile()
+ ''' % (_opimpl, resop)).compile()
for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert',
'cast_float_to_int', 'cast_int_to_float',
@@ -329,37 +336,37 @@
def opimpl_goto(self, target):
self.pc = target
- @arguments("box", "label")
- def opimpl_goto_if_not(self, box, target):
+ @arguments("box", "label", "orgpc")
+ def opimpl_goto_if_not(self, box, target, orgpc):
switchcase = box.getint()
if switchcase:
opnum = rop.GUARD_TRUE
else:
opnum = rop.GUARD_FALSE
- self.metainterp.generate_guard(opnum, box)
+ self.metainterp.generate_guard(opnum, box, resumepc=orgpc)
if not switchcase:
self.pc = target
- @arguments("box", "label")
- def opimpl_goto_if_not_int_is_true(self, box, target):
+ @arguments("box", "label", "orgpc")
+ def opimpl_goto_if_not_int_is_true(self, box, target, orgpc):
condbox = self.execute(rop.INT_IS_TRUE, box)
- self.opimpl_goto_if_not(condbox, target)
+ self.opimpl_goto_if_not(condbox, target, orgpc)
- @arguments("box", "label")
- def opimpl_goto_if_not_int_is_zero(self, box, target):
+ @arguments("box", "label", "orgpc")
+ def opimpl_goto_if_not_int_is_zero(self, box, target, orgpc):
condbox = self.execute(rop.INT_IS_ZERO, box)
- self.opimpl_goto_if_not(condbox, target)
+ self.opimpl_goto_if_not(condbox, target, orgpc)
for _opimpl in ['int_lt', 'int_le', 'int_eq', 'int_ne', 'int_gt', 'int_ge',
'ptr_eq', 'ptr_ne']:
exec py.code.Source('''
- @arguments("box", "box", "label")
- def opimpl_goto_if_not_%s(self, b1, b2, target):
+ @arguments("box", "box", "label", "orgpc")
+ def opimpl_goto_if_not_%s(self, b1, b2, target, orgpc):
if b1 is b2:
condbox = %s
else:
condbox = self.execute(rop.%s, b1, b2)
- self.opimpl_goto_if_not(condbox, target)
+ self.opimpl_goto_if_not(condbox, target, orgpc)
''' % (_opimpl, FASTPATHS_SAME_BOXES[_opimpl.split("_")[-1]], _opimpl.upper())
).compile()
@@ -418,7 +425,7 @@
assert box.getint() == 0
target = switchdict.dict[const1.getint()]
self.metainterp.generate_guard(rop.GUARD_FALSE, box,
- resumepc=target)
+ resumepc=orgpc)
else:
# found one of the cases
self.implement_guard_value(valuebox, orgpc)
@@ -1457,6 +1464,17 @@
def setup_resume_at_op(self, pc):
self.pc = pc
+ def handle_possible_overflow_error(self, label, orgpc, resbox):
+ if self.metainterp.ovf_flag:
+ self.metainterp.generate_guard(rop.GUARD_OVERFLOW, None,
+ resumepc=orgpc)
+ self.pc = label
+ return None
+ else:
+ self.metainterp.generate_guard(rop.GUARD_NO_OVERFLOW, None,
+ resumepc=orgpc)
+ return resbox
+
def run_one_step(self):
# Execute the frame forward. This method contains a loop that leaves
# whenever the 'opcode_implementations' (which is one of the 'opimpl_'
@@ -2022,7 +2040,7 @@
moreargs = [box] + extraargs
else:
moreargs = list(extraargs)
- if opnum == rop.GUARD_EXCEPTION or opnum == rop.GUARD_OVERFLOW:
+ if opnum == rop.GUARD_EXCEPTION:
guard_op = self.history.record(opnum, moreargs,
lltype.nullptr(llmemory.GCREF.TO))
else:
@@ -2309,7 +2327,7 @@
if isinstance(key, compile.ResumeAtPositionDescr):
self.seen_loop_header_for_jdindex = self.jitdriver_sd.index
try:
- self.prepare_resume_from_failure(key.guard_opnum, deadframe)
+ self.prepare_resume_from_failure(deadframe, key)
if self.resumekey_original_loop_token is None: # very rare case
raise SwitchToBlackhole(Counters.ABORT_BRIDGE)
self.interpret()
@@ -2452,22 +2470,9 @@
else: assert 0
self.jitdriver_sd.warmstate.execute_assembler(loop_token, *args)
- def prepare_resume_from_failure(self, opnum, deadframe):
- frame = self.framestack[-1]
- if opnum == rop.GUARD_FUTURE_CONDITION:
- pass
- elif opnum == rop.GUARD_TRUE: # a goto_if_not that jumps only now
- frame.pc = frame.jitcode.follow_jump(frame.pc)
- elif opnum == rop.GUARD_FALSE: # a goto_if_not that stops jumping;
- pass # or a switch that was in its "default" case
- elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS:
- pass # the pc is already set to the *start* of the opcode
- elif (opnum == rop.GUARD_NONNULL or
- opnum == rop.GUARD_ISNULL or
- opnum == rop.GUARD_NONNULL_CLASS):
- pass # the pc is already set to the *start* of the opcode
- elif opnum == rop.GUARD_NO_EXCEPTION or opnum == rop.GUARD_EXCEPTION:
- exception = self.cpu.grab_exc_value(deadframe)
+ def prepare_resume_from_failure(self, deadframe, resumedescr):
+ exception = self.cpu.grab_exc_value(deadframe)
+ if isinstance(resumedescr, compile.ResumeGuardExcDescr):
if exception:
self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR,
exception))
@@ -2477,20 +2482,8 @@
self.handle_possible_exception()
except ChangeFrame:
pass
- elif opnum == rop.GUARD_NOT_INVALIDATED:
- pass # XXX we want to do something special in resume descr,
- # but not now
- elif opnum == rop.GUARD_NO_OVERFLOW: # an overflow now detected
- self.execute_raised(OverflowError(), constant=True)
- try:
- self.finishframe_exception()
- except ChangeFrame:
- pass
- elif opnum == rop.GUARD_OVERFLOW: # no longer overflowing
- self.clear_exception()
else:
- from rpython.jit.metainterp.resoperation import opname
- raise NotImplementedError(opname[opnum])
+ assert not exception
def get_procedure_token(self, greenkey, with_compiled_targets=False):
JitCell = self.jitdriver_sd.warmstate.JitCell
@@ -2773,18 +2766,6 @@
else:
self.generate_guard(rop.GUARD_NO_EXCEPTION, None, [])
- def handle_possible_overflow_error(self):
- if self.last_exc_value:
- op = self.generate_guard(rop.GUARD_OVERFLOW, None)
- op.setref_base(lltype.cast_opaque_ptr(llmemory.GCREF,
- self.last_exc_value))
- assert self.class_of_last_exc_is_const
- self.last_exc_box = ConstPtr(
- lltype.cast_opaque_ptr(llmemory.GCREF, self.last_exc_value))
- self.finishframe_exception()
- else:
- self.generate_guard(rop.GUARD_NO_OVERFLOW, None)
-
def assert_no_exception(self):
assert not self.last_exc_value
@@ -3250,16 +3231,17 @@
print '-> %r' % (resultbox,)
assert argcodes[next_argcode] == '>'
result_argcode = argcodes[next_argcode + 1]
- assert resultbox.type == {'i': history.INT,
- 'r': history.REF,
- 'f': history.FLOAT}[result_argcode]
+ if 'ovf' not in name:
+ assert resultbox.type == {'i': history.INT,
+ 'r': history.REF,
+ 'f': history.FLOAT}[result_argcode]
else:
resultbox = unboundmethod(self, *args)
#
if resultbox is not None:
self.make_result_of_lastop(resultbox)
elif not we_are_translated():
- assert self._result_argcode in 'v?'
+ assert self._result_argcode in 'v?' or 'ovf' in name
#
unboundmethod = getattr(MIFrame, 'opimpl_' + name).im_func
argtypes = unrolling_iterable(unboundmethod.argtypes)
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -236,6 +236,9 @@
return (self.getopnum() == rop.GUARD_OVERFLOW or
self.getopnum() == rop.GUARD_NO_OVERFLOW)
+ def is_jit_debug(self):
+ return rop._JIT_DEBUG_FIRST <= self.getopnum() <= rop._JIT_DEBUG_LAST
+
def is_always_pure(self):
return rop._ALWAYS_PURE_FIRST <= self.getopnum() <= rop._ALWAYS_PURE_LAST
@@ -375,6 +378,7 @@
newop.rd_frame_info_list = self.rd_frame_info_list
return newop
+
# ===========
# type mixins
# ===========
@@ -689,7 +693,7 @@
'GUARD_NO_EXCEPTION/0d/n', # may be called with an exception currently set
'GUARD_EXCEPTION/1d/r', # may be called with an exception currently set
'GUARD_NO_OVERFLOW/0d/n',
- 'GUARD_OVERFLOW/0d/r',
+ 'GUARD_OVERFLOW/0d/n',
'GUARD_NOT_FORCED/0d/n', # may be called with an exception currently set
'GUARD_NOT_FORCED_2/0d/n', # same as GUARD_NOT_FORCED, but for finish()
'GUARD_NOT_INVALIDATED/0d/n',
@@ -806,10 +810,12 @@
'UNICODESETITEM/3/n',
'COND_CALL_GC_WB/1d/n', # [objptr] (for the write barrier)
'COND_CALL_GC_WB_ARRAY/2d/n', # [objptr, arrayindex] (write barr. for array)
+ '_JIT_DEBUG_FIRST',
'DEBUG_MERGE_POINT/*/n', # debugging only
'ENTER_PORTAL_FRAME/2/n', # debugging only
'LEAVE_PORTAL_FRAME/1/n', # debugging only
'JIT_DEBUG/*/n', # debugging only
+ '_JIT_DEBUG_LAST',
'VIRTUAL_REF_FINISH/2/n', # removed before it's passed to the backend
'COPYSTRCONTENT/5/n', # src, dst, srcstart, dststart, length
'COPYUNICODECONTENT/5/n',
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -115,10 +115,13 @@
while y > 0:
myjitdriver.can_enter_jit(x=x, y=y, res=res)
myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += ovfcheck(x * x)
- x += 1
- res += ovfcheck(x * x)
- y -= 1
+ try:
+ res += ovfcheck(x * x)
+ x += 1
+ res += ovfcheck(x * x)
+ y -= 1
+ except OverflowError:
+ assert 0
return res
res = self.meta_interp(f, [6, 7])
assert res == 1323
@@ -151,7 +154,10 @@
myjitdriver.can_enter_jit(x=x, y=y, res=res)
myjitdriver.jit_merge_point(x=x, y=y, res=res)
b = y * 2
- res += ovfcheck(x * x) + b
+ try:
+ res += ovfcheck(x * x) + b
+ except OverflowError:
+ assert 0
y -= 1
return res
res = self.meta_interp(f, [6, 7])
@@ -230,8 +236,8 @@
res = self.meta_interp(f, [6, 32, 16])
assert res == 1692
self.check_trace_count(3)
- self.check_resops({'int_lt': 2, 'int_gt': 4, 'guard_false': 2,
- 'guard_true': 4, 'int_sub': 4, 'jump': 3,
+ self.check_resops({'int_lt': 4, 'int_gt': 4, 'guard_false': 2,
+ 'guard_true': 6, 'int_sub': 4, 'jump': 3,
'int_mul': 3, 'int_add': 4})
def test_loop_invariant_mul_ovf2(self):
@@ -400,7 +406,7 @@
return externfn(n, n+1)
res = self.interp_operations(f, [6])
assert res == 42
- self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0)
+ self.check_operations_history(int_add=1, int_mul=0, call_i=1, guard_no_exception=0)
def test_residual_call_elidable(self):
def externfn(x, y):
@@ -413,7 +419,7 @@
assert res == 42
# CALL_PURE is not recorded in the history if all-constant args
self.check_operations_history(int_add=0, int_mul=0,
- call=0, call_pure_i=0)
+ call_i=0, call_pure_i=0)
def test_residual_call_elidable_1(self):
@elidable
@@ -425,7 +431,7 @@
assert res == 42
# CALL_PURE is recorded in the history if not-all-constant args
self.check_operations_history(int_add=1, int_mul=0,
- call=0, call_pure_i=1)
+ call_i=0, call_pure_i=1)
def test_residual_call_elidable_2(self):
myjitdriver = JitDriver(greens = [], reds = ['n'])
@@ -653,11 +659,11 @@
#
res = self.meta_interp(f, [3, 6], repeat=7, function_threshold=0)
assert res == 6 - 4 - 5
- self.check_history(call=0) # because the trace starts in the middle
+ self.check_history(call_n=0) # because the trace starts in the middle
#
res = self.meta_interp(f, [60, 84], repeat=7)
assert res == 84 - 61 - 62
- self.check_history(call=1) # because the trace starts immediately
+ self.check_history(call_n=1) # because the trace starts immediately
def test_unroll_one_loop_iteration(self):
def unroll(code):
@@ -679,11 +685,11 @@
res = self.meta_interp(f, [1, 4, 1], enable_opts="", inline=True)
assert res == f(1, 4, 1)
- self.check_history(call_assembler=0)
+ self.check_history(call_assembler_i=0)
res = self.meta_interp(f, [1, 4, 2], enable_opts="", inline=True)
assert res == f(1, 4, 2)
- self.check_history(call_assembler=1)
+ self.check_history(call_assembler_i=1)
def test_format(self):
def f(n):
@@ -723,6 +729,7 @@
elif n == 7: a = 3
else: a = 2
x = intmask(x * 10 + a)
+ #print "XXXXXXXXXXXXXXXX", x
i += 1
return x
res = self.meta_interp(f, [0], backendopt=True)
@@ -834,7 +841,7 @@
return a.foo * x
res = self.interp_operations(f, [42])
assert res == 210
- self.check_operations_history(getfield_gc=1)
+ self.check_operations_history(getfield_gc_i=1)
def test_getfield_immutable(self):
class A:
@@ -851,7 +858,7 @@
return a.foo * x
res = self.interp_operations(f, [42])
assert res == 210
- self.check_operations_history(getfield_gc=0)
+ self.check_operations_history(getfield_gc_i=0)
def test_setfield_bool(self):
class A:
@@ -882,6 +889,24 @@
res = self.interp_operations(f, [1, sys.maxint])
assert res == -42
+ def test_ovf_raise(self):
+ def g(x, y):
+ try:
+ return ovfcheck(x * y)
+ except OverflowError:
+ raise
+
+ def f(x, y):
+ try:
+ return g(x, y)
+ except OverflowError:
+ return 3
+
+ res = self.interp_operations(f, [sys.maxint, 2])
+ assert res == 3
+ res = self.interp_operations(f, [3, 2])
+ assert res == 6
+
def test_int_sub_ovf(self):
def f(x, y):
try:
@@ -1356,7 +1381,7 @@
return g(a, b)
res = self.interp_operations(f, [3, 5])
assert res == 8
- self.check_operations_history(int_add=0, call=1)
+ self.check_operations_history(int_add=0, call_i=1)
def test_listcomp(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'lst'])
@@ -1380,7 +1405,7 @@
return tup[1]
res = self.interp_operations(f, [3, 5])
assert res == 5
- self.check_operations_history(setfield_gc=2, getfield_gc_pure=0)
+ self.check_operations_history(setfield_gc=2, getfield_gc_pure_i=0)
def test_oosend_look_inside_only_one(self):
class A:
@@ -1455,16 +1480,6 @@
res = self.meta_interp(f, [299], listops=True)
assert res == f(299)
self.check_resops(guard_class=0, guard_value=6)
- #
- # The original 'guard_class' is rewritten to be directly 'guard_value'.
- # Check that this rewrite does not interfere with the descr, which
- # should be a full-fledged multivalued 'guard_value' descr.
- if self.basic:
- for loop in get_stats().get_all_loops():
- for op in loop.get_operations():
- if op.getopname() == "guard_value":
- descr = op.getdescr()
- assert descr.get_index_of_guard_value() >= 0
def test_merge_guardnonnull_guardclass(self):
myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
@@ -1866,7 +1881,8 @@
res = self.meta_interp(g, [6, 20])
assert res == g(6, 20)
self.check_trace_count(8)
- self.check_resops(getarrayitem_gc_i=10)
+ # 6 extra from sharing guard data
+ self.check_resops(getarrayitem_gc_i=10 + 6)
def test_multiple_specialied_versions_bridge(self):
myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
@@ -2055,8 +2071,8 @@
res = self.meta_interp(g, [3, 23])
assert res == 7068153
self.check_trace_count(6)
- self.check_resops(guard_true=6, guard_class=2, int_mul=3,
- int_add=3, guard_false=3)
+ self.check_resops(guard_true=8, guard_class=2, int_mul=3,
+ int_add=3, guard_false=4)
def test_dont_trace_every_iteration(self):
myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
@@ -2079,7 +2095,7 @@
self.check_enter_count(2)
def test_current_trace_length(self):
- myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
+ myjitdriver = JitDriver(greens = ['g'], reds = ['x', 'l'])
@dont_look_inside
def residual():
print "hi there"
@@ -2090,14 +2106,15 @@
residual()
y += 1
def f(x, g):
+ l = []
n = 0
while x > 0:
- myjitdriver.can_enter_jit(x=x, g=g)
- myjitdriver.jit_merge_point(x=x, g=g)
+ myjitdriver.can_enter_jit(x=x, g=g, l=l)
+ myjitdriver.jit_merge_point(x=x, g=g, l=l)
loop(g)
x -= 1
- n = current_trace_length()
- return n
+ l.append(current_trace_length())
+ return l[-2] # not the blackholed version
res = self.meta_interp(f, [5, 8])
assert 14 < res < 42
res = self.meta_interp(f, [5, 2])
@@ -2619,7 +2636,10 @@
node2.val = 7
if a >= 100:
sa += 1
- sa += ovfcheck(i + i)
+ try:
+ sa += ovfcheck(i + i)
+ except OverflowError:
+ assert 0
node1 = A(i)
i += 1
assert self.meta_interp(f, [20, 7]) == f(20, 7)
@@ -2638,7 +2658,7 @@
i += 1
return sa
assert self.meta_interp(f, [20]) == f(20)
- self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=2)
+ self.check_resops(int_lt=4, int_le=0, int_ge=0, int_gt=4)
def test_intbounds_not_generalized1(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa'])
@@ -2655,7 +2675,7 @@
i += 1
return sa
assert self.meta_interp(f, [20]) == f(20)
- self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=3)
+ self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=5)
def test_intbounds_not_generalized2(self):
@@ -2676,7 +2696,7 @@
i += 1
return sa
assert self.meta_interp(f, [20]) == f(20)
- self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=2)
+ self.check_resops(int_lt=4, int_le=3, int_ge=3, int_gt=4)
def test_retrace_limit1(self):
myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
@@ -3876,6 +3896,7 @@
class TestLLtype(BaseLLtypeTests, LLJitMixin):
def test_tagged(self):
+ py.test.skip("tagged unsupported")
from rpython.rlib.objectmodel import UnboxedValue
class Base(object):
__slots__ = ()
@@ -3887,8 +3908,10 @@
return self.a > 0
def dec(self):
- return Int(self.a - 1)
-
+ try:
+ return Int(self.a - 1)
+ except OverflowError:
+ raise
class Float(Base):
def __init__(self, a):
@@ -3997,7 +4020,7 @@
More information about the pypy-commit
mailing list