Author: Carl Friedrich Bolz <cfb...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit