[pypy-svn] r68092 - in pypy/trunk/pypy/jit: backend/llgraph metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Thu Oct 1 12:07:16 CEST 2009


Author: arigo
Date: Thu Oct  1 12:07:15 2009
New Revision: 68092

Modified:
   pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
   pypy/trunk/pypy/jit/metainterp/codewriter.py
   pypy/trunk/pypy/jit/metainterp/policy.py
   pypy/trunk/pypy/jit/metainterp/test/test_basic.py
   pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py
   pypy/trunk/pypy/jit/metainterp/test/test_del.py
   pypy/trunk/pypy/jit/metainterp/warmspot.py
Log:
Get rid of the issue that instantiate() turns into
an indirect_call with no graphs to hint what is called.
Done by detecting exactly this situation and guessing
that what is called is any 'instantiate' field of any
vtable.  If this guess is ever wrong it's not bad.


Modified: pypy/trunk/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/trunk/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/trunk/pypy/jit/backend/llgraph/llimpl.py	Thu Oct  1 12:07:15 2009
@@ -110,6 +110,7 @@
     'ooisnot'         : (('ref', 'ref'), 'bool'),
     'instanceof'      : (('ref',), 'bool'),
     'subclassof'      : (('ref', 'ref'), 'bool'),
+    'runtimenew'      : (('ref',), 'ref'),
     'setfield_gc'     : (('ref', 'intorptr'), None),
     'getfield_gc'     : (('ref',), 'intorptr'),
     'getfield_gc_pure': (('ref',), 'intorptr'),
@@ -844,6 +845,11 @@
         if ootype.classof(value) is not expected_class:
             raise GuardFailed
 
+    def op_runtimenew(self, _, cls):
+        cls = ootype.cast_from_object(ootype.Class, cls)
+        res = ootype.runtimenew(cls)
+        return ootype.cast_to_object(res)
+
     def op_instanceof(self, typedescr, obj):
         inst = ootype.cast_from_object(ootype.ROOT, obj)
         return ootype.instanceof(inst, typedescr.TYPE)

Modified: pypy/trunk/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/codewriter.py	Thu Oct  1 12:07:15 2009
@@ -148,7 +148,8 @@
         return (cfnptr, calldescr)
 
     def register_indirect_call_targets(self, op):
-        targets = self.policy.graphs_from(op, self.cpu.supports_floats)
+        targets = self.policy.graphs_from(op, self.rtyper,
+                                          self.cpu.supports_floats)
         assert targets is not None
         for graph in targets:
             if graph in self.all_indirect_call_targets:
@@ -1000,22 +1001,26 @@
 
     def serialize_op_direct_call(self, op):
         kind = self.codewriter.policy.guess_call_kind(op,
+                                           self.codewriter.rtyper,
                                            self.codewriter.cpu.supports_floats)
         return getattr(self, 'handle_%s_call' % kind)(op)
 
     def serialize_op_indirect_call(self, op):
         kind = self.codewriter.policy.guess_call_kind(op,
+                                           self.codewriter.rtyper,
                                            self.codewriter.cpu.supports_floats)
         return getattr(self, 'handle_%s_indirect_call' % kind)(op)
 
     def serialize_op_oosend(self, op):
         kind = self.codewriter.policy.guess_call_kind(op,
+                                           self.codewriter.rtyper,
                                            self.codewriter.cpu.supports_floats)
         return getattr(self, 'handle_%s_oosend' % kind)(op)
 
     def handle_regular_call(self, op, oosend_methdescr=None):
         self.minimize_variables()
         [targetgraph] = self.codewriter.policy.graphs_from(op,
+                                           self.codewriter.rtyper,
                                            self.codewriter.cpu.supports_floats)
         jitbox = self.codewriter.get_jitcode(targetgraph, self.graph,
                                              oosend_methdescr=oosend_methdescr)

Modified: pypy/trunk/pypy/jit/metainterp/policy.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/policy.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/policy.py	Thu Oct  1 12:07:15 2009
@@ -1,6 +1,6 @@
 from pypy.translator.simplify import get_funcobj
 from pypy.jit.metainterp import support, history
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, rclass
 
 class JitPolicy(object):
 
@@ -29,7 +29,7 @@
                 not contains_unsupported_variable_type(graph,
                                                        supports_floats))
 
-    def graphs_from(self, op, supports_floats):
+    def graphs_from(self, op, rtyper, supports_floats):
         if op.opname == 'direct_call':
             funcobj = get_funcobj(op.args[0].value)
             graph = funcobj.graph
@@ -50,10 +50,24 @@
                 if result:
                     return result  # common case: look inside these graphs,
                                    # and ignore the others if there are any
+            else:
+                # special case: handle the indirect call that goes to
+                # the 'instantiate' methods.  This check is a bit imprecise
+                # but it's not too bad if we mistake a random indirect call
+                # for the one to 'instantiate'.
+                CALLTYPE = op.args[0].concretetype
+                if (op.opname == 'indirect_call' and len(op.args) == 2 and
+                    CALLTYPE == rclass.OBJECT_VTABLE.instantiate):
+                    return list(self._graphs_of_all_instantiate(rtyper))
         # residual call case: we don't need to look into any graph
         return None
 
-    def guess_call_kind(self, op, supports_floats):
+    def _graphs_of_all_instantiate(self, rtyper):
+        for vtable in rtyper.lltype_to_vtable_mapping().itervalues():
+            if vtable.instantiate:
+                yield vtable.instantiate._obj.graph
+
+    def guess_call_kind(self, op, rtyper, supports_floats):
         if op.opname == 'direct_call':
             funcptr = op.args[0].value
             funcobj = get_funcobj(funcptr)
@@ -69,7 +83,7 @@
             SELFTYPE, methname, opargs = support.decompose_oosend(op)
             if SELFTYPE.oopspec_name is not None:
                 return 'builtin'
-        if self.graphs_from(op, supports_floats) is None:
+        if self.graphs_from(op, rtyper, supports_floats) is None:
             return 'residual'
         return 'regular'
 

Modified: pypy/trunk/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_basic.py	Thu Oct  1 12:07:15 2009
@@ -644,7 +644,6 @@
         res = self.interp_operations(f, [13])
         assert res == 72
 
-    @py.test.mark.xfail
     def test_instantiate_does_not_call(self):
         mydriver = JitDriver(reds = ['n', 'x'], greens = [])
         class Base: pass
@@ -664,7 +663,7 @@
                 x += inst.foo
                 n -= 1
             return x
-        res = self.meta_interp(f, [20])
+        res = self.meta_interp(f, [20], optimizer=OPTIMIZER_SIMPLE)
         assert res == f(20)
         self.check_loops(call=0)
 

Modified: pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_codewriter.py	Thu Oct  1 12:07:15 2009
@@ -101,7 +101,6 @@
         assert dict.fromkeys(names) == {'g': None}
 
     def test_instantiate(self):
-        py.test.skip("in-progress")
         class A1:     id = 651
         class A2(A1): id = 652
         class B1:     id = 661
@@ -119,7 +118,17 @@
         graph2 = self.graphof(ll_instantiate)
         jitcode = cw.make_one_bytecode((graph2, None), False)
         assert 'residual_call' not in jitcode._source
-        xxx
+        names = [jitcode.name for (fnaddress, jitcode)
+                               in self.metainterp_sd.indirectcalls]
+        names = dict.fromkeys(names)
+        assert len(names) >= 4
+        for expected in ['A1', 'A2', 'B1', 'B2']:
+            for name in names:
+                if name.startswith('instantiate_') and name.endswith(expected):
+                    break
+            else:
+                assert 0, "missing instantiate_*_%s in:\n%r" % (expected,
+                                                                names)
 
 
 class ImmutableFieldsTests:

Modified: pypy/trunk/pypy/jit/metainterp/test/test_del.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/test/test_del.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/test/test_del.py	Thu Oct  1 12:07:15 2009
@@ -1,5 +1,5 @@
 import py
-from pypy.rlib.jit import JitDriver
+from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE
 from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
 
 
@@ -54,6 +54,32 @@
         res = self.meta_interp(f, [20])
         assert res == 42
 
+    def test_instantiate_with_or_without_del(self):
+        import gc
+        mydriver = JitDriver(reds = ['n', 'x'], greens = [])
+        class Base: pass
+        class A(Base): foo = 72
+        class B(Base):
+            foo = 8
+            def __del__(self):
+                pass
+        def f(n):
+            x = 0
+            while n > 0:
+                mydriver.can_enter_jit(n=n, x=x)
+                mydriver.jit_merge_point(n=n, x=x)
+                if n % 2 == 0:
+                    cls = A
+                else:
+                    cls = B
+                inst = cls()
+                x += inst.foo
+                n -= 1
+            return 1
+        res = self.meta_interp(f, [20], optimizer=OPTIMIZER_SIMPLE)
+        assert res == 1
+        self.check_loops(call=1)   # for the case B(), but not for the case A()
+
 
 class TestLLtype(DelTests, LLJitMixin):
     def test_signal_action(self):

Modified: pypy/trunk/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/trunk/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/trunk/pypy/jit/metainterp/warmspot.py	Thu Oct  1 12:07:15 2009
@@ -561,6 +561,7 @@
 
 def find_all_graphs(portal, policy, translator, supports_floats):
     from pypy.translator.simplify import get_graph
+    rtyper = translator.rtyper
     all_graphs = [portal]
     seen = set([portal])
     todo = [portal]
@@ -569,10 +570,10 @@
         for _, op in top_graph.iterblockops():
             if op.opname not in ("direct_call", "indirect_call", "oosend"):
                 continue
-            kind = policy.guess_call_kind(op, supports_floats)
+            kind = policy.guess_call_kind(op, rtyper, supports_floats)
             if kind != "regular":
                 continue
-            for graph in policy.graphs_from(op, supports_floats):
+            for graph in policy.graphs_from(op, rtyper, supports_floats):
                 if graph in seen:
                     continue
                 if policy.look_inside_graph(graph, supports_floats):



More information about the Pypy-commit mailing list