[pypy-commit] pypy default: Propagate debug.ll_assert_not_none() through the JIT, using the same
arigo
pypy.commits at gmail.com
Sat Dec 17 13:48:41 EST 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r89122:5efae655f1ce
Date: 2016-12-17 18:20 +0100
http://bitbucket.org/pypy/pypy/changeset/5efae655f1ce/
Log: Propagate debug.ll_assert_not_none() through the JIT, using the same
technique as jit.record_exact_class(). If we use it a bit inside
PyPy it could remove a good number of guard_nonnull or
guard_nonnull_class.
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
@@ -283,6 +283,12 @@
def rewrite_op_jit_record_exact_class(self, op):
return SpaceOperation("record_exact_class", [op.args[0], op.args[1]], None)
+ def rewrite_op_debug_assert_not_none(self, op):
+ if isinstance(op.args[0], Variable):
+ return SpaceOperation('assert_not_none', [op.args[0]], None)
+ else:
+ return []
+
def rewrite_op_cast_bool_to_int(self, op): pass
def rewrite_op_cast_bool_to_uint(self, op): pass
def rewrite_op_cast_char_to_int(self, op): pass
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
@@ -402,7 +402,7 @@
self.encoding_test(f, [65], """
raise $<* struct object>
- """)
+ """, transform=True)
def test_exc_raise_2(self):
def g(i):
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
@@ -563,6 +563,10 @@
ll_assert((i & 1) == 1, "bhimpl_cast_int_to_ptr: not an odd int")
return lltype.cast_int_to_ptr(llmemory.GCREF, i)
+ @arguments("r")
+ def bhimpl_assert_not_none(a):
+ assert a
+
@arguments("r", "i")
def bhimpl_record_exact_class(a, b):
pass
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
@@ -5,6 +5,7 @@
from rpython.rlib.rarithmetic import ovfcheck, r_longlong, is_valid_int
from rpython.rlib.unroll import unrolling_iterable
from rpython.rlib.objectmodel import specialize
+from rpython.rlib.debug import fatalerror
from rpython.jit.metainterp.history import check_descr
from rpython.jit.metainterp.history import INT, REF, FLOAT, VOID, AbstractDescr
from rpython.jit.metainterp.history import ConstInt, ConstFloat, ConstPtr
@@ -321,6 +322,10 @@
def do_keepalive(cpu, _, x):
pass
+def do_assert_not_none(cpu, _, box):
+ if not box.getref_base():
+ fatalerror("found during JITting: ll_assert_not_none() failed")
+
# ____________________________________________________________
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
@@ -499,6 +499,9 @@
box = self.get_box_replacement(op.getarg(0))
self.make_constant(box, CONST_0)
+ def optimize_ASSERT_NOT_NONE(self, op):
+ self.make_nonnull(op.getarg(0))
+
def optimize_RECORD_EXACT_CLASS(self, op):
opinfo = self.getptrinfo(op.getarg(0))
expectedclassbox = op.getarg(1)
diff --git a/rpython/jit/metainterp/optimizeopt/simplify.py b/rpython/jit/metainterp/optimizeopt/simplify.py
--- a/rpython/jit/metainterp/optimizeopt/simplify.py
+++ b/rpython/jit/metainterp/optimizeopt/simplify.py
@@ -42,6 +42,9 @@
# but it's a bit hard to implement robustly if heap.py is also run
pass
+ def optimize_ASSERT_NOT_NONE(self, op):
+ pass
+
def optimize_RECORD_EXACT_CLASS(self, op):
pass
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
@@ -5595,6 +5595,19 @@
"""
self.optimize_loop(ops, expected)
+ def test_assert_not_none(self):
+ ops = """
+ [p0]
+ assert_not_none(p0)
+ guard_nonnull(p0) []
+ finish()
+ """
+ expected = """
+ [p0]
+ finish()
+ """
+ self.optimize_loop(ops, expected)
+
class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
pass
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
@@ -275,12 +275,18 @@
def opimpl_ptr_iszero(self, box):
return self.execute(rop.PTR_EQ, box, history.CONST_NULL)
+ @arguments("box")
+ def opimpl_assert_not_none(self, box):
+ if self.metainterp.heapcache.is_nullity_known(box):
+ return
+ self.execute(rop.ASSERT_NOT_NONE, box)
+ self.metainterp.heapcache.nullity_now_known(box)
+
@arguments("box", "box")
def opimpl_record_exact_class(self, box, clsbox):
from rpython.rtyper.lltypesystem import llmemory
if self.metainterp.heapcache.is_class_known(box):
return
- adr = clsbox.getaddr()
self.execute(rop.RECORD_EXACT_CLASS, box, clsbox)
self.metainterp.heapcache.class_now_known(box)
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
@@ -1143,6 +1143,7 @@
'COPYSTRCONTENT/5/n', # src, dst, srcstart, dststart, length
'COPYUNICODECONTENT/5/n',
'QUASIIMMUT_FIELD/1d/n', # [objptr], descr=SlowMutateDescr
+ 'ASSERT_NOT_NONE/1/n', # [objptr]
'RECORD_EXACT_CLASS/2/n', # [objptr, clsptr]
'KEEPALIVE/1/n',
'SAVE_EXCEPTION/0/r',
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
@@ -4585,3 +4585,30 @@
assert res == -42
res = self.interp_operations(f, [0, 200])
assert res == 205
+
+ def test_ll_assert_not_none(self):
+ # the presence of ll_assert_not_none(), even in cases where it
+ # doesn't influence the annotation, is a hint for the JIT
+ from rpython.rlib.debug import ll_assert_not_none
+ class X:
+ pass
+ class Y(X):
+ pass
+ def g(x, check):
+ if check:
+ x = ll_assert_not_none(x)
+ return isinstance(x, Y)
+ @dont_look_inside
+ def make(i):
+ if i == 1:
+ return X()
+ if i == 2:
+ return Y()
+ return None
+ def f(a, b, check):
+ return g(make(a), check) + g(make(b), check) * 10
+ res = self.interp_operations(f, [1, 2, 1])
+ assert res == 10
+ self.check_operations_history(guard_nonnull=0, guard_nonnull_class=0,
+ guard_class=2,
+ assert_not_none=2) # before optimization
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -1141,6 +1141,9 @@
"""
Assure the JIT that value is an instance of cls. This is a precise
class check, like a guard_class.
+
+ See also debug.ll_assert_not_none(x), which asserts that x is not None
+ and also assures the JIT that it is the case.
"""
assert type(value) is cls
diff --git a/rpython/rtyper/debug.py b/rpython/rtyper/debug.py
--- a/rpython/rtyper/debug.py
+++ b/rpython/rtyper/debug.py
@@ -22,7 +22,7 @@
def ll_assert_not_none(x):
"""assert x is not None"""
- assert x, "ll_assert_not_none(%r)" % (x,)
+ assert x is not None, "ll_assert_not_none(%r)" % (x,)
return x
class Entry(ExtRegistryEntry):
@@ -33,11 +33,8 @@
def specialize_call(self, hop):
[v0] = hop.inputargs(hop.args_r[0])
- assert isinstance(v0.concretetype, lltype.Ptr)
- v1 = hop.genop('ptr_nonzero', [v0], resulttype=lltype.Bool)
hop.exception_cannot_occur()
- cmsg = hop.inputconst(lltype.Void, "ll_assert_not_none failed")
- hop.genop('debug_assert', [v1, cmsg])
+ hop.genop('debug_assert_not_none', [v0])
return v0
class FatalError(Exception):
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -521,6 +521,10 @@
if not x:
raise LLAssertFailure(msg)
+ def op_debug_assert_not_none(self, x):
+ if not x:
+ raise LLAssertFailure("ll_assert_not_none() failed")
+
def op_debug_fatalerror(self, ll_msg, ll_exc=None):
msg = ''.join(ll_msg.chars)
if ll_exc is None:
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -78,7 +78,8 @@
def is_pure(self, args_v):
if self.canfold: # canfold => pure operation
return True
- if self is llop.debug_assert: # debug_assert is pure enough
+ if (self is llop.debug_assert or # debug_assert is pure enough
+ self is llop.debug_assert_not_none):
return True
# reading from immutable
if self is llop.getfield or self is llop.getarrayitem:
@@ -552,6 +553,7 @@
'debug_offset': LLOp(canrun=True),
'debug_flush': LLOp(canrun=True),
'debug_assert': LLOp(tryfold=True),
+ 'debug_assert_not_none': LLOp(tryfold=True),
'debug_fatalerror': LLOp(canrun=True),
'debug_llinterpcall': LLOp(canraise=(Exception,)),
# Python func call 'res=arg[0](*arg[1:])'
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -812,6 +812,10 @@
return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]),
c_string_constant(op.args[1].value))
+ def OP_DEBUG_ASSERT_NOT_NONE(self, op):
+ return 'RPyAssert(%s != NULL, "ll_assert_not_none() failed");' % (
+ self.expr(op.args[0]),)
+
def OP_DEBUG_FATALERROR(self, op):
# XXX
from rpython.rtyper.lltypesystem.rstr import STR
More information about the pypy-commit
mailing list