[pypy-commit] pypy default: make the JIT aware of the downcasts that are present in rtyped-flowgraphs. This
cfbolz
noreply at buildbot.pypy.org
Thu Dec 1 14:06:45 CET 2011
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch:
Changeset: r50034:93a45b7c9431
Date: 2011-12-01 14:06 +0100
http://bitbucket.org/pypy/pypy/changeset/93a45b7c9431/
Log: make the JIT aware of the downcasts that are present in rtyped-
flowgraphs. This allows the JIT to sometimes find out the class of a
variable without having to produce a guard_class.
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -207,7 +207,19 @@
if op.args[0] in self.vable_array_vars:
self.vable_array_vars[op.result]= self.vable_array_vars[op.args[0]]
- rewrite_op_cast_pointer = rewrite_op_same_as
+ def rewrite_op_cast_pointer(self, op):
+ newop = self.rewrite_op_same_as(op)
+ assert newop is None
+ if (self._is_rclass_instance(op.args[0]) and
+ self._is_rclass_instance(op.result)):
+ FROM = op.args[0].concretetype.TO
+ TO = op.result.concretetype.TO
+ if lltype._castdepth(TO, FROM) > 0:
+ vtable = heaptracker.get_vtable_for_gcstruct(self.cpu, TO)
+ const_vtable = Constant(vtable, lltype.typeOf(vtable))
+ return [None, # hack, do the right renaming from op.args[0] to op.result
+ SpaceOperation("record_known_class", [op.args[0], const_vtable], None)]
+
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/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -518,6 +518,9 @@
@arguments("r")
def bhimpl_mark_opaque_ptr(a):
pass
+ @arguments("r", "i")
+ def bhimpl_record_known_class(a, b):
+ pass
@arguments("i", returns="i")
def bhimpl_int_copy(a):
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -260,6 +260,16 @@
def optimize_GUARD_FALSE(self, op):
self.optimize_guard(op, CONST_0)
+ def optimize_RECORD_KNOWN_CLASS(self, op):
+ value = self.getvalue(op.getarg(0))
+ expectedclassbox = op.getarg(1)
+ assert isinstance(expectedclassbox, Const)
+ realclassbox = value.get_constant_class(self.optimizer.cpu)
+ if realclassbox is not None:
+ assert realclassbox.same_constant(expectedclassbox)
+ return
+ value.make_constant_class(expectedclassbox, None)
+
def optimize_GUARD_CLASS(self, op):
value = self.getvalue(op.getarg(0))
expectedclassbox = op.getarg(1)
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -28,6 +28,9 @@
def optimize_MARK_OPAQUE_PTR(self, op):
pass
+ def optimize_RECORD_KNOWN_CLASS(self, op):
+ pass
+
dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
default=OptSimplify.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -6482,6 +6482,21 @@
# not obvious, because of the exception UnicodeDecodeError that
# can be raised by ll_str2unicode()
+ def test_record_known_class(self):
+ ops = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ record_known_class(p1, ConstClass(node_vtable))
+ guard_class(p1, ConstClass(node_vtable)) []
+ jump(p1)
+ """
+ expected = """
+ [p0]
+ p1 = getfield_gc(p0, descr=nextdescr)
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected)
+
def test_quasi_immut(self):
ops = """
[p0, p1, i0]
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -243,6 +243,18 @@
def opimpl_mark_opaque_ptr(self, box):
return self.execute(rop.MARK_OPAQUE_PTR, box)
+ @arguments("box", "box")
+ def opimpl_record_known_class(self, box, clsbox):
+ from pypy.rpython.lltypesystem import llmemory
+ if self.metainterp.heapcache.is_class_known(box):
+ return
+ adr = clsbox.getaddr()
+ bounding_class = llmemory.cast_adr_to_ptr(adr, rclass.CLASSTYPE)
+ if bounding_class.subclassrange_max - bounding_class.subclassrange_min == 1:
+ # precise class knowledge, this can be used
+ self.execute(rop.RECORD_KNOWN_CLASS, box, clsbox)
+ self.metainterp.heapcache.class_now_known(box)
+
@arguments("box")
def _opimpl_any_return(self, box):
self.metainterp.finishframe(box)
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -494,6 +494,7 @@
'COPYSTRCONTENT/5', # src, dst, srcstart, dststart, length
'COPYUNICODECONTENT/5',
'QUASIIMMUT_FIELD/1d', # [objptr], descr=SlowMutateDescr
+ 'RECORD_KNOWN_CLASS/2', # [objptr, clsptr]
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
'_CALL_FIRST',
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3585,6 +3585,67 @@
self.interp_operations(f, [5], translationoptions=translationoptions)
+ def test_annotation_gives_knowledge_to_tracer(self):
+ class Base(object):
+ pass
+ class A(Base):
+ def f(self):
+ return self.a
+ def g(self):
+ return self.a + 1
+ class B(Base):
+ def f(self):
+ return self.b
+ def g(self):
+ return self.b + 1
+ class C(B):
+ def f(self):
+ self.c += 1
+ return self.c
+ def g(self):
+ return self.c + 1
+ @dont_look_inside
+ def make(x):
+ if x > 0:
+ a = A()
+ a.a = x + 1
+ elif x < 0:
+ a = B()
+ a.b = -x
+ else:
+ a = C()
+ a.c = 10
+ return a
+ def f(x):
+ a = make(x)
+ if x > 0:
+ assert isinstance(a, A)
+ z = a.f()
+ elif x < 0:
+ assert isinstance(a, B)
+ z = a.f()
+ else:
+ assert isinstance(a, C)
+ z = a.f()
+ return z + a.g()
+ res1 = f(6)
+ res2 = self.interp_operations(f, [6])
+ assert res1 == res2
+ self.check_operations_history(guard_class=0, record_known_class=1)
+
+ res1 = f(-6)
+ res2 = self.interp_operations(f, [-6])
+ assert res1 == res2
+ # cannot use record_known_class here, because B has a subclass
+ self.check_operations_history(guard_class=1)
+
+ res1 = f(0)
+ res2 = self.interp_operations(f, [0])
+ assert res1 == res2
+ # here it works again
+ self.check_operations_history(guard_class=0, record_known_class=1)
+
+
class TestLLtype(BaseLLtypeTests, LLJitMixin):
def test_tagged(self):
from pypy.rlib.objectmodel import UnboxedValue
More information about the pypy-commit
mailing list