[pypy-svn] r36654 - in pypy/dist/pypy/translator: . backendopt backendopt/test

antocuni at codespeak.net antocuni at codespeak.net
Sat Jan 13 14:57:21 CET 2007


Author: antocuni
Date: Sat Jan 13 14:57:20 2007
New Revision: 36654

Modified:
   pypy/dist/pypy/translator/backendopt/all.py
   pypy/dist/pypy/translator/backendopt/checkvirtual.py
   pypy/dist/pypy/translator/backendopt/inline.py
   pypy/dist/pypy/translator/backendopt/test/test_all.py
   pypy/dist/pypy/translator/backendopt/test/test_checkvirtual.py
   pypy/dist/pypy/translator/backendopt/test/test_inline.py
   pypy/dist/pypy/translator/backendopt/test/test_malloc.py
   pypy/dist/pypy/translator/driver.py
Log:
Inline oosends we can dispatch at compile-time because they call
non-virtual methods.

Make backend_optimizations() always call check_virtual_methods when
using ootypesystem.

Make ootype.ROOT the default Instance where to start from when
checking virtual methods.



Modified: pypy/dist/pypy/translator/backendopt/all.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/all.py	(original)
+++ pypy/dist/pypy/translator/backendopt/all.py	Sat Jan 13 14:57:20 2007
@@ -10,6 +10,7 @@
 from pypy.translator.backendopt.mallocprediction import clever_inlining_and_malloc_removal
 from pypy.translator.backendopt.removeassert import remove_asserts
 from pypy.translator.backendopt.support import log
+from pypy.translator.backendopt.checkvirtual import check_virtual_methods
 from pypy.objspace.flow.model import checkgraph
 
 def backend_optimizations(translator, graphs=None, secondary=False, **kwds):
@@ -31,6 +32,9 @@
     if config.raisingop2direct_call:
         raisingop2direct_call(translator, graphs)
 
+    if translator.rtyper.type_system.name == 'ootypesystem':
+        check_virtual_methods()
+
     # remove obvious no-ops
     for graph in graphs:
         removenoops.remove_same_as(graph)

Modified: pypy/dist/pypy/translator/backendopt/checkvirtual.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/checkvirtual.py	(original)
+++ pypy/dist/pypy/translator/backendopt/checkvirtual.py	Sat Jan 13 14:57:20 2007
@@ -7,7 +7,9 @@
 non-virtual calls, such as JVM).
 """
 
-def check_virtual_methods(INSTANCE, super_methods = {}):
+from pypy.rpython.ootypesystem import ootype
+
+def check_virtual_methods(INSTANCE=ootype.ROOT, super_methods = {}):
     my_methods = super_methods.copy()
     for name, method in INSTANCE._methods.iteritems():
         method._virtual = False

Modified: pypy/dist/pypy/translator/backendopt/inline.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/inline.py	(original)
+++ pypy/dist/pypy/translator/backendopt/inline.py	Sat Jan 13 14:57:20 2007
@@ -22,6 +22,16 @@
 class CannotInline(Exception):
     pass
 
+def get_meth_from_oosend(op):
+    method_name = op.args[0].value
+    INSTANCE = op.args[1].concretetype
+    _, meth = INSTANCE._lookup(op.args[0].value)
+    virtual = getattr(meth, '_virtual', True)
+    if virtual:
+        return None
+    else:
+        return meth
+
 def collect_called_graphs(graph, translator):
     graphs_or_something = {}
     for block in graph.iterblocks():
@@ -40,15 +50,23 @@
                     for graph in graphs:
                         graphs_or_something[graph] = True
             if op.opname == 'oosend':
-                graphs_or_something[op.args[0]] = True # XXX?
+                meth = get_meth_from_oosend(op)
+                key = getattr(meth, 'graph', op.args[0])
+                graphs_or_something[key] = True
     return graphs_or_something
 
 def iter_callsites(graph, calling_what):
     for block in graph.iterblocks():
         for i, op in enumerate(block.operations):
-            if not op.opname == "direct_call":
+            if op.opname == "direct_call":
+                funcobj = get_funcobj(op.args[0].value)
+            elif op.opname == "oosend":
+                funcobj = get_meth_from_oosend(op)
+                if funcobj is None:
+                    continue # cannot inline virtual methods
+            else:
                 continue
-            funcobj = get_funcobj(op.args[0].value)
+
             graph = getattr(funcobj, 'graph', None)
             # accept a function or a graph as 'inline_func'
             if (graph is calling_what or
@@ -178,11 +196,18 @@
         self.cleanup()
         return count
 
+    def get_graph_from_op(self, op):
+        assert op.opname in ('direct_call', 'oosend')
+        if op.opname == 'direct_call':
+            return get_funcobj(self.op.args[0].value).graph
+        else:
+            return get_meth_from_oosend(op).graph
+
     def inline_once(self, block, index_operation):
         self.varmap = {}
         self._copied_blocks = {}
         self.op = block.operations[index_operation]
-        self.graph_to_inline = get_funcobj(self.op.args[0].value).graph
+        self.graph_to_inline = self.get_graph_from_op(self.op)
         self.exception_guarded = False
         if (block.exitswitch == c_last_exception and
             index_operation == len(block.operations) - 1):
@@ -201,9 +226,14 @@
     def search_for_calls(self, block):
         d = {}
         for i, op in enumerate(block.operations):
-            if not op.opname == "direct_call":
+            if op.opname == "direct_call":
+                funcobj = get_funcobj(op.args[0].value)
+            elif op.opname == "oosend":
+                funcobj = get_meth_from_oosend(op)
+                if funcobj is None:
+                    continue
+            else:
                 continue
-            funcobj = get_funcobj(op.args[0].value)
             graph = getattr(funcobj, 'graph', None)
             # accept a function or a graph as 'inline_func'
             if (graph is self.inline_func or
@@ -565,9 +595,13 @@
                                    'dont_inline', False):
                             continue
                         result.append((parentgraph, graph))
+                if op.opname == "oosend":
+                    meth = get_meth_from_oosend(op)
+                    graph = getattr(meth, 'graph', None)
+                    if graph is not None:
+                        result.append((parentgraph, graph))
     return result
-
-
+    
 def instrument_inline_candidates(graphs, multiplier):
     threshold = BASE_INLINE_THRESHOLD * multiplier
     cache = {None: False}

Modified: pypy/dist/pypy/translator/backendopt/test/test_all.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_all.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_all.py	Sat Jan 13 14:57:20 2007
@@ -217,5 +217,3 @@
     type_system = 'ootype'
     check_malloc_removed = OOTypeMallocRemovalTest.check_malloc_removed
     
-    def test_big(self):
-        py.test.skip('FIXME! It should pass as long as oosend is inlined')

Modified: pypy/dist/pypy/translator/backendopt/test/test_checkvirtual.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_checkvirtual.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_checkvirtual.py	Sat Jan 13 14:57:20 2007
@@ -6,7 +6,7 @@
     A = Instance("A", ROOT)
     addMethods(A, {"foo": meth(Meth([], Void))})
 
-    check_virtual_methods(ROOT)
+    check_virtual_methods()
     assert A._methods["foo"]._virtual == False
 
 def test_checkvirtual_simple():
@@ -18,7 +18,7 @@
     
     addMethods(B, {"foo": meth(Meth([], Void))})
 
-    check_virtual_methods(ROOT)
+    check_virtual_methods()
     assert A._methods["foo"]._virtual == True
     assert A._methods["bar"]._virtual == False
     assert B._methods["foo"]._virtual == False
@@ -33,7 +33,7 @@
     
     addMethods(C, {"foo": meth(Meth([], Void))})
 
-    check_virtual_methods(ROOT)
+    check_virtual_methods()
     assert A._methods["foo"]._virtual == True
     assert A._methods["bar"]._virtual == False
     assert "foo" not in B._methods
@@ -49,7 +49,7 @@
     
     addMethods(B1, {"foo": meth(Meth([], Void))})
 
-    check_virtual_methods(ROOT)
+    check_virtual_methods()
     assert A._methods["foo"]._virtual == True
     assert A._methods["bar"]._virtual == False
     assert B1._methods["foo"]._virtual == False

Modified: pypy/dist/pypy/translator/backendopt/test/test_inline.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_inline.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_inline.py	Sat Jan 13 14:57:20 2007
@@ -9,6 +9,7 @@
 from pypy.translator.backendopt.inline import collect_called_graphs
 from pypy.translator.backendopt.inline import measure_median_execution_cost
 from pypy.translator.backendopt.inline import instrument_inline_candidates
+from pypy.translator.backendopt.checkvirtual import check_virtual_methods
 from pypy.translator.translator import TranslationContext, graphof
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.rpython.test.tool import LLRtypeMixin, OORtypeMixin
@@ -84,8 +85,11 @@
             return interp.eval_graph(graphof(t, entry), args)
         return eval_func
 
-    def check_auto_inlining(self, func, sig, multiplier=None, call_count_check=False):
+    def check_auto_inlining(self, func, sig, multiplier=None, call_count_check=False,
+                            checkvirtual=False):
         t = self.translate(func, sig)
+        if checkvirtual:
+            check_virtual_methods()
         if option.view:
             t.view()
         # inline!
@@ -585,3 +589,50 @@
         expected = fn(0)
         res = eval_func([0])
         assert res == expected
+
+    def test_oosend(self):
+        class A:
+            def foo(self, x):
+                return x
+        def fn(x):
+            a = A()
+            return a.foo(x)
+
+        eval_func, t = self.check_auto_inlining(fn, [int], checkvirtual=True)
+        expected = fn(42)
+        res = eval_func([42])
+        assert res == expected
+
+    def test_not_inline_oosend(self):
+        class A:
+            def foo(self, x):
+                return x
+        class B(A):
+            def foo(self, x):
+                return x+1
+
+        def fn(flag, x):
+            if flag:
+                obj = A()
+            else:
+                obj = B()
+            return obj.foo(x)
+
+        eval_func, t = self.check_auto_inlining(fn, [bool, int], checkvirtual=True)
+        expected = fn(True, 42)
+        res = eval_func([True, 42])
+        assert res == expected
+
+    def test_classattr(self):
+        class A:
+            attr = 666
+        class B(A):
+            attr = 42
+        def fn5():
+            b = B()
+            return b.attr
+
+        eval_func, t = self.check_auto_inlining(fn5, [], checkvirtual=True)
+        res = eval_func([])
+        assert res == 42
+

Modified: pypy/dist/pypy/translator/backendopt/test/test_malloc.py
==============================================================================
--- pypy/dist/pypy/translator/backendopt/test/test_malloc.py	(original)
+++ pypy/dist/pypy/translator/backendopt/test/test_malloc.py	Sat Jan 13 14:57:20 2007
@@ -104,7 +104,6 @@
         self.check(fn4, [int], [42], 42)
 
     def test_fn5(self):
-        self._skip_oo('It will work as soon as trivial oosend are inlined')
         class A:
             attr = 666
         class B(A):
@@ -352,3 +351,9 @@
             return x.foo
         self.check(fn, [], [], 42)
 
+    def test_fn5(self):
+        # don't test this in ootype because the class attribute access
+        # is turned into an oosend which prevents malloc removal to
+        # work unless we inline first. See test_classattr in
+        # test_inline.py
+        pass

Modified: pypy/dist/pypy/translator/driver.py
==============================================================================
--- pypy/dist/pypy/translator/driver.py	(original)
+++ pypy/dist/pypy/translator/driver.py	Sat Jan 13 14:57:20 2007
@@ -355,9 +355,6 @@
             heap2stack=False,
             clever_malloc_removal=False)
         if self.config.translation.backend == 'cli':
-            from pypy.translator.backendopt.checkvirtual import check_virtual_methods
-            from pypy.rpython.ootypesystem import ootype
-            check_virtual_methods(ootype.ROOT)
             opt['merge_if_blocks'] = True
             opt['inline_threshold'] = 1
             opt['mallocs'] = True



More information about the Pypy-commit mailing list