[pypy-commit] pypy default: Before constant-folding pure GC heap operations, check in detail that it
arigo
noreply at buildbot.pypy.org
Mon Nov 9 03:35:41 EST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r80606:ebe258311483
Date: 2015-11-09 09:23 +0100
http://bitbucket.org/pypy/pypy/changeset/ebe258311483/
Log: Before constant-folding pure GC heap operations, check in detail
that it is valid (not a wrong-typed or out-of-bound access). We can
only do it exactly if supports_guard_gc_type, but that's the only
case in which we should get examples that fail the check (even if
rarely): when optimizing the unrolled loop.
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
@@ -7,6 +7,7 @@
from rpython.jit.metainterp.history import INT, REF, FLOAT, VOID
from rpython.jit.metainterp.resoperation import rop
from rpython.jit.metainterp.optimizeopt import intbounds
+from rpython.jit.metainterp.optimize import SpeculativeError
from rpython.jit.codewriter import longlong, heaptracker
from rpython.jit.codewriter.effectinfo import EffectInfo
@@ -197,6 +198,7 @@
return intbounds.get_integer_max(
not _is_signed_kind(self.FIELD), rffi.sizeof(self.FIELD))
+
def _is_signed_kind(TYPE):
return (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
rffi.cast(TYPE, -1) == -1)
@@ -949,6 +951,35 @@
def store_fail_descr(self, deadframe, descr):
pass # I *think*
+ def protect_speculative_field(self, p, fielddescr):
+ if not p:
+ raise SpeculativeError
+ p = p._obj.container._as_ptr()
+ try:
+ lltype.cast_pointer(lltype.Ptr(fielddescr.S), p)
+ except lltype.InvalidCast:
+ raise SpeculativeError
+
+ def protect_speculative_array(self, p, arraydescr):
+ if not p:
+ raise SpeculativeError
+ p = p._obj.container
+ if lltype.typeOf(p) != arraydescr.A:
+ raise SpeculativeError
+
+ def protect_speculative_string(self, p):
+ if not p:
+ raise SpeculativeError
+ p = p._obj.container
+ if lltype.typeOf(p) != rstr.STR:
+ raise SpeculativeError
+
+ def protect_speculative_unicode(self, p):
+ if not p:
+ raise SpeculativeError
+ p = p._obj.container
+ if lltype.typeOf(p) != rstr.UNICODE:
+ raise SpeculativeError
class LLDeadFrame(object):
diff --git a/rpython/jit/backend/llsupport/descr.py b/rpython/jit/backend/llsupport/descr.py
--- a/rpython/jit/backend/llsupport/descr.py
+++ b/rpython/jit/backend/llsupport/descr.py
@@ -57,6 +57,16 @@
def is_object(self):
return bool(self.vtable)
+ def is_valid_class_for(self, struct):
+ objptr = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
+ cls = llmemory.cast_adr_to_ptr(
+ heaptracker.int2adr(self.get_vtable()),
+ lltype.Ptr(rclass.OBJECT_VTABLE))
+ # this first comparison is necessary, since we want to make sure
+ # that vtable for JitVirtualRef is the same without actually reading
+ # fields
+ return objptr.typeptr == cls or rclass.ll_isinstance(objptr, cls)
+
def is_immutable(self):
return self.immutable_flag
@@ -129,18 +139,11 @@
def __repr__(self):
return 'FieldDescr<%s>' % (self.name,)
- def check_correct_type(self, struct):
+ def assert_correct_type(self, struct):
+ # similar to cpu.protect_speculative_field(), but works also
+ # if supports_guard_gc_type is false (and is allowed to crash).
if self.parent_descr.is_object():
- cls = llmemory.cast_adr_to_ptr(
- heaptracker.int2adr(self.parent_descr.get_vtable()),
- lltype.Ptr(rclass.OBJECT_VTABLE))
- tpptr = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct).typeptr
- # this comparison is necessary, since we want to make sure
- # that vtable for JitVirtualRef is the same without actually reading
- # fields
- if tpptr != cls:
- assert rclass.ll_isinstance(lltype.cast_opaque_ptr(
- rclass.OBJECTPTR, struct), cls)
+ assert self.parent_descr.is_valid_class_for(struct)
else:
pass
diff --git a/rpython/jit/backend/llsupport/gc.py b/rpython/jit/backend/llsupport/gc.py
--- a/rpython/jit/backend/llsupport/gc.py
+++ b/rpython/jit/backend/llsupport/gc.py
@@ -729,7 +729,8 @@
return (infobits_offset, self._T_IS_RPYTHON_INSTANCE_BYTE)
def get_actual_typeid(self, gcptr):
- # Read the whole GC header word. The typeid is the lower half-word.
+ # Read the whole GC header word. Return the typeid from the
+ # lower half-word.
hdr = rffi.cast(self.HDRPTR, gcptr)
type_id = llop.extract_ushort(llgroup.HALFWORD, hdr.tid)
return llop.combine_ushort(lltype.Signed, type_id, 0)
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
@@ -6,6 +6,7 @@
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.rlib.objectmodel import we_are_translated, specialize
from rpython.jit.metainterp import history, compile
+from rpython.jit.metainterp.optimize import SpeculativeError
from rpython.jit.codewriter import heaptracker, longlong
from rpython.jit.backend.model import AbstractCPU
from rpython.jit.backend.llsupport import symbolic, jitframe
@@ -529,6 +530,34 @@
assert self.supports_guard_gc_type
return self.gc_ll_descr.get_actual_typeid(gcptr)
+ def protect_speculative_field(self, gcptr, fielddescr):
+ if not gcptr:
+ raise SpeculativeError
+ if self.supports_guard_gc_type:
+ assert isinstance(fielddescr, FieldDescr)
+ sizedescr = fielddescr.parent_descr
+ if sizedescr.is_object():
+ if (not self.check_is_object(gcptr) or
+ not sizedescr.is_valid_class_for(gcptr)):
+ raise SpeculativeError
+ else:
+ if self.get_actual_typeid(gcptr) != sizedescr.tid:
+ raise SpeculativeError
+
+ def protect_speculative_array(self, gcptr, arraydescr):
+ if not gcptr:
+ raise SpeculativeError
+ if self.supports_guard_gc_type:
+ assert isinstance(arraydescr, ArrayDescr)
+ if self.get_actual_typeid(gcptr) != arraydescr.tid:
+ raise SpeculativeError
+
+ def protect_speculative_string(self, gcptr):
+ self.protect_speculative_array(gcptr, self.gc_ll_descr.str_descr)
+
+ def protect_speculative_unicode(self, gcptr):
+ self.protect_speculative_array(gcptr, self.gc_ll_descr.unicode_descr)
+
# ____________________________________________________________
def bh_arraylen_gc(self, array, arraydescr):
@@ -633,21 +662,21 @@
def bh_getfield_gc_i(self, struct, fielddescr):
ofs, size, sign = self.unpack_fielddescr_size(fielddescr)
if isinstance(lltype.typeOf(struct), lltype.Ptr):
- fielddescr.check_correct_type(struct)
+ fielddescr.assert_correct_type(struct)
return self.read_int_at_mem(struct, ofs, size, sign)
@specialize.argtype(1)
def bh_getfield_gc_r(self, struct, fielddescr):
ofs = self.unpack_fielddescr(fielddescr)
if isinstance(lltype.typeOf(struct), lltype.Ptr):
- fielddescr.check_correct_type(struct)
+ fielddescr.assert_correct_type(struct)
return self.read_ref_at_mem(struct, ofs)
@specialize.argtype(1)
def bh_getfield_gc_f(self, struct, fielddescr):
ofs = self.unpack_fielddescr(fielddescr)
if isinstance(lltype.typeOf(struct), lltype.Ptr):
- fielddescr.check_correct_type(struct)
+ fielddescr.assert_correct_type(struct)
return self.read_float_at_mem(struct, ofs)
bh_getfield_raw_i = bh_getfield_gc_i
@@ -658,20 +687,20 @@
def bh_setfield_gc_i(self, struct, newvalue, fielddescr):
ofs, size, _ = self.unpack_fielddescr_size(fielddescr)
if isinstance(lltype.typeOf(struct), lltype.Ptr):
- fielddescr.check_correct_type(struct)
+ fielddescr.assert_correct_type(struct)
self.write_int_at_mem(struct, ofs, size, newvalue)
def bh_setfield_gc_r(self, struct, newvalue, fielddescr):
ofs = self.unpack_fielddescr(fielddescr)
if isinstance(lltype.typeOf(struct), lltype.Ptr):
- fielddescr.check_correct_type(struct)
+ fielddescr.assert_correct_type(struct)
self.write_ref_at_mem(struct, ofs, newvalue)
@specialize.argtype(1)
def bh_setfield_gc_f(self, struct, newvalue, fielddescr):
ofs = self.unpack_fielddescr(fielddescr)
if isinstance(lltype.typeOf(struct), lltype.Ptr):
- fielddescr.check_correct_type(struct)
+ fielddescr.assert_correct_type(struct)
self.write_float_at_mem(struct, ofs, newvalue)
bh_setfield_raw_i = bh_setfield_gc_i
diff --git a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
--- a/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
+++ b/rpython/jit/backend/llsupport/test/test_zrpy_gc_direct.py
@@ -3,6 +3,7 @@
from rpython.jit.metainterp.history import JitCellToken, NoStats
from rpython.jit.metainterp.history import BasicFinalDescr, BasicFailDescr
from rpython.jit.metainterp.gc import get_description
+from rpython.jit.metainterp.optimize import SpeculativeError
from rpython.annotator.listdef import s_list_of_strings
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.rclass import getclassrepr, getinstancerepr
@@ -19,7 +20,7 @@
class C(B):
pass
def main(argv):
- A(); B(); C()
+ A(); B().foo = len(argv); C()
return 0
t = TranslationContext()
@@ -48,6 +49,14 @@
descr_B = cpu.sizeof(LLB, ptr_vtable_B)
typeid_B = descr_B.get_type_id()
+ fielddescr_B = cpu.fielddescrof(LLB, 'inst_foo')
+
+ LLD = lltype.GcStruct('D', ('dd', lltype.Signed))
+ descr_D = cpu.sizeof(LLD)
+ fielddescr_D = cpu.fielddescrof(LLD, 'dd')
+
+ ARRAY = lltype.GcArray(lltype.Signed)
+ arraydescr = cpu.arraydescrof(ARRAY)
loop1 = parse("""
[p0]
@@ -123,6 +132,38 @@
if token is token3: # guard_is_object
print int(cpu.check_is_object(p0))
+ for p0 in [lltype.nullptr(llmemory.GCREF.TO),
+ rffi.cast(llmemory.GCREF, A()),
+ rffi.cast(llmemory.GCREF, B()),
+ rffi.cast(llmemory.GCREF, C()),
+ rffi.cast(llmemory.GCREF, lltype.malloc(LLD)),
+ rffi.cast(llmemory.GCREF, lltype.malloc(ARRAY, 5)),
+ rffi.cast(llmemory.GCREF, "foobar"),
+ rffi.cast(llmemory.GCREF, u"foobaz")]:
+ results = ['B', 'D', 'A', 'S', 'U']
+ try:
+ cpu.protect_speculative_field(p0, fielddescr_B)
+ except SpeculativeError:
+ results[0] = '-'
+ try:
+ cpu.protect_speculative_field(p0, fielddescr_D)
+ except SpeculativeError:
+ results[1] = '-'
+ try:
+ cpu.protect_speculative_array(p0, arraydescr)
+ except SpeculativeError:
+ results[2] = '-'
+ try:
+ cpu.protect_speculative_string(p0)
+ except SpeculativeError:
+ results[3] = '-'
+ try:
+ cpu.protect_speculative_unicode(p0)
+ except SpeculativeError:
+ results[4] = '-'
+ print ''.join(results)
+
+
call_initial_function(t, g)
cbuilder = genc.CStandaloneBuilder(t, main, t.config)
@@ -145,7 +186,17 @@
'fail\n'
'match\n'
- 'match\n')
+ 'match\n'
+
+ '-----\n' # null
+ '-----\n' # instance of A
+ 'B----\n' # instance of B
+ 'B----\n' # instance of C
+ '-D---\n'
+ '--A--\n'
+ '---S-\n'
+ '----U\n'
+ )
def test_guards_translated_with_gctypeptr():
diff --git a/rpython/jit/metainterp/optimize.py b/rpython/jit/metainterp/optimize.py
--- a/rpython/jit/metainterp/optimize.py
+++ b/rpython/jit/metainterp/optimize.py
@@ -12,3 +12,7 @@
debug_print(msg)
debug_stop("jit-abort")
self.msg = msg
+
+class SpeculativeError(JitException):
+ """Raised when speculative heap access would be ill-typed,
+ which should only occur when optimizing the unrolled loop."""
diff --git a/rpython/jit/metainterp/optimizeopt/pure.py b/rpython/jit/metainterp/optimizeopt/pure.py
--- a/rpython/jit/metainterp/optimizeopt/pure.py
+++ b/rpython/jit/metainterp/optimizeopt/pure.py
@@ -3,6 +3,7 @@
ResOperation
from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method
from rpython.jit.metainterp.optimizeopt.shortpreamble import PreambleOp
+from rpython.jit.metainterp.optimize import SpeculativeError
class RecentPureOps(object):
@@ -93,6 +94,7 @@
break
else:
# all constant arguments: constant-fold away
+ self.protect_speculative_operation(op)
resbox = self.optimizer.constant_fold(op)
# note that INT_xxx_OVF is not done from here, and the
# overflows in the INT_xxx operations are ignored
@@ -117,6 +119,59 @@
if nextop:
self.emit_operation(nextop)
+ def protect_speculative_operation(self, op):
+ """When constant-folding a pure operation that reads memory from
+ a gcref, make sure that the gcref is non-null and of a valid type.
+ Otherwise, raise SpeculativeError. This should only occur when
+ unrolling and optimizing the unrolled loop. Note that if
+ cpu.supports_guard_gc_type is false, we can't really do this
+ check at all, but then we don't unroll in that case.
+ """
+ opnum = op.getopnum()
+ cpu = self.optimizer.cpu
+
+ if (opnum == rop.GETFIELD_GC_PURE_I or
+ opnum == rop.GETFIELD_GC_PURE_R or
+ opnum == rop.GETFIELD_GC_PURE_F):
+ fielddescr = op.getdescr()
+ ref = self.get_constant_box(op.getarg(0)).getref_base()
+ cpu.protect_speculative_field(ref, fielddescr)
+ return
+
+ elif (opnum == rop.GETARRAYITEM_GC_PURE_I or
+ opnum == rop.GETARRAYITEM_GC_PURE_R or
+ opnum == rop.GETARRAYITEM_GC_PURE_F or
+ opnum == rop.ARRAYLEN_GC):
+ arraydescr = op.getdescr()
+ array = self.get_constant_box(op.getarg(0)).getref_base()
+ cpu.protect_speculative_array(array, arraydescr)
+ if opnum == rop.ARRAYLEN_GC:
+ return
+ arraylength = cpu.bh_arraylen_gc(array, arraydescr)
+
+ elif (opnum == rop.STRGETITEM or
+ opnum == rop.STRLEN):
+ string = self.get_constant_box(op.getarg(0)).getref_base()
+ cpu.protect_speculative_string(string)
+ if opnum == rop.STRLEN:
+ return
+ arraylength = cpu.bh_strlen(string)
+
+ elif (opnum == rop.UNICODEGETITEM or
+ opnum == rop.UNICODELEN):
+ unicode = self.get_constant_box(op.getarg(0)).getref_base()
+ cpu.protect_speculative_unicode(unicode)
+ if opnum == rop.UNICODELEN:
+ return
+ arraylength = cpu.bh_unicodelen(unicode)
+
+ else:
+ return
+
+ index = self.get_constant_box(op.getarg(1)).getint()
+ if not (0 <= index < arraylength):
+ raise SpeculativeError
+
def getrecentops(self, opnum):
if rop._OVF_FIRST <= opnum <= rop._OVF_LAST:
opnum = opnum - rop._OVF_FIRST
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
@@ -9028,7 +9028,6 @@
self.optimize_loop(ops, expected)
def test_unroll_pure_on_bogus_object_1(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
@@ -9037,22 +9036,20 @@
i3 = int_sub(i1, 1)
jump(NULL, i3)
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_2(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
guard_true(i2) []
getfield_gc_pure_i(p0, descr=valuedescr)
i3 = int_sub(i1, 1)
- jump(ConstPtr(myptr3), i3)
- """
- self.optimize_loop(ops, ops)
+ jump(ConstPtr(myptr4), i3)
+ """
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_3(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
@@ -9061,10 +9058,9 @@
i3 = int_sub(i1, 1)
jump(NULL, i3)
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_4(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
@@ -9073,10 +9069,9 @@
i3 = int_sub(i1, 1)
jump(ConstPtr(myptr3), i3)
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_5(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
@@ -9085,10 +9080,9 @@
i3 = int_sub(i1, 1)
jump(ConstPtr(arrayref), i3) # too short, length < 126!
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_6(self):
- py.test.skip("FIXME")
ops = """
[i0, i1]
i2 = int_gt(i1, 0)
@@ -9097,10 +9091,9 @@
i3 = int_sub(i1, 1)
jump(125, i3) # arrayref is too short, length < 126!
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_7(self):
- py.test.skip("FIXME")
ops = """
[i0, i1]
i2 = int_gt(i1, 0)
@@ -9109,10 +9102,9 @@
i3 = int_sub(i1, 1)
jump(-1, i3) # cannot access array item -1!
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_8(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
@@ -9121,10 +9113,9 @@
i3 = int_sub(i1, 1)
jump(NULL, i3)
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_9(self):
- py.test.skip("FIXME")
ops = """
[p0, i1]
i2 = int_gt(i1, 0)
@@ -9133,10 +9124,20 @@
i3 = int_sub(i1, 1)
jump(ConstPtr(myptr), i3) # not a string at all
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+
+ def test_unroll_pure_on_bogus_object_9_unicode(self):
+ ops = """
+ [p0, i1]
+ i2 = int_gt(i1, 0)
+ guard_true(i2) []
+ i4 = unicodegetitem(p0, 125)
+ i3 = int_sub(i1, 1)
+ jump(ConstPtr(myptr), i3) # not a unicode at all
+ """
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_10(self):
- py.test.skip("FIXME")
ops = """
[i0, i1]
i2 = int_gt(i1, 0)
@@ -9145,10 +9146,9 @@
i3 = int_sub(i1, 1)
jump(125, i3) # string is too short!
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
def test_unroll_pure_on_bogus_object_11(self):
- py.test.skip("FIXME")
ops = """
[i0, i1]
i2 = int_gt(i1, 0)
@@ -9157,7 +9157,7 @@
i3 = int_sub(i1, 1)
jump(-1, i3) # cannot access character -1!
"""
- self.optimize_loop(ops, ops)
+ py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
class TestLLtype(OptimizeOptTest, LLtypeMixin):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -139,7 +139,10 @@
myptr2 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode2)
mynode3 = lltype.malloc(NODE2)
mynode3.parent.parent.typeptr = node_vtable2
- myptr3 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode3)
+ myptr3 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode3) # a NODE2
+ mynode4 = lltype.malloc(NODE3)
+ mynode4.parent.typeptr = node_vtable3
+ myptr4 = lltype.cast_opaque_ptr(llmemory.GCREF, mynode4) # a NODE3
nullptr = lltype.nullptr(llmemory.GCREF.TO)
#nodebox2 = InputArgRef(lltype.cast_opaque_ptr(llmemory.GCREF, node2))
nodesize = cpu.sizeof(NODE, node_vtable)
diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py
--- a/rpython/jit/metainterp/optimizeopt/unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/unroll.py
@@ -4,7 +4,7 @@
from rpython.jit.metainterp.optimizeopt.shortpreamble import ShortBoxes,\
ShortPreambleBuilder, ExtendedShortPreambleBuilder, PreambleOp
from rpython.jit.metainterp.optimizeopt import info, intutils
-from rpython.jit.metainterp.optimize import InvalidLoop
+from rpython.jit.metainterp.optimize import InvalidLoop, SpeculativeError
from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer,\
Optimization, LoopInfo, MININT, MAXINT, BasicLoopInfo
from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo
@@ -144,9 +144,12 @@
raise InvalidLoop("Cannot import state, virtual states don't match")
self.potential_extra_ops = {}
self.optimizer.init_inparg_dict_from(label_args)
- info, _ = self.optimizer.propagate_all_forward(
- start_label.getarglist()[:], ops, call_pure_results, False,
- flush=False)
+ try:
+ info, _ = self.optimizer.propagate_all_forward(
+ start_label.getarglist()[:], ops, call_pure_results, False,
+ flush=False)
+ except SpeculativeError:
+ raise InvalidLoop("Speculative heap access would be ill-typed")
label_op = ResOperation(rop.LABEL, label_args, start_label.getdescr())
for a in end_jump.getarglist():
self.optimizer.force_box_for_end_of_preamble(
More information about the pypy-commit
mailing list