[Python-checkins] r86742 - in python/branches/dmalcolm-ast-optimization-branch: Doc/library/dis.rst Lib/test/test_optimize.py Python/Python-ast.c Python/ceval.c

david.malcolm python-checkins at python.org
Thu Nov 25 00:58:09 CET 2010


Author: david.malcolm
Date: Thu Nov 25 00:58:08 2010
New Revision: 86742

Log:
Further work towards method-call inlining


Modified:
   python/branches/dmalcolm-ast-optimization-branch/Doc/library/dis.rst
   python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py
   python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c
   python/branches/dmalcolm-ast-optimization-branch/Python/ceval.c

Modified: python/branches/dmalcolm-ast-optimization-branch/Doc/library/dis.rst
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Doc/library/dis.rst	(original)
+++ python/branches/dmalcolm-ast-optimization-branch/Doc/library/dis.rst	Thu Nov 25 00:58:08 2010
@@ -808,10 +808,25 @@
    element on the stack contains the keyword arguments dictionary, followed by the
    variable-arguments tuple, followed by explicit keyword and positional arguments.
 
-
 .. opcode:: HAVE_ARGUMENT
 
    This is not really an opcode.  It identifies the dividing line between opcodes
    which don't take arguments ``< HAVE_ARGUMENT`` and those which do ``>=
    HAVE_ARGUMENT``.
 
+** Optimization Instructions **
+.. opcode:: JUMP_IF_SPECIALIZABLE (target)
+
+   Inserted by the optimizer, potentially branching to an optimized version of the code.
+
+   Compares values on the top of the stack, to determine if the assumptions held by the optimized branch are valid.
+
+   Inputs:
+   * TOP: A: code object we inlined for (via a LOAD_CONST, injected by the inliner)
+   * SECOND: B: dynamically queried object, located by usual runtime lookup
+     (LOAD_GLOBAL, or e.g. LOAD_LOCAL "self"; GET_ATTR "do_something")
+
+   If B is A, we can specialize, setting bytecode counter to *target* and popping both TOP and SECOND from the stack.
+
+   Otherwise the assumption is not true, and we fall through to the generic implementation, popping TOP, leaving SECOND on top of the stack.
+

Modified: python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py	(original)
+++ python/branches/dmalcolm-ast-optimization-branch/Lib/test/test_optimize.py	Thu Nov 25 00:58:08 2010
@@ -404,30 +404,84 @@
         src = '''
 class Foo:
     def simple_method(self, a):
-         return self.bar + a + self.baz
+         return 'I am Foo.simple_method' + self.bar + a + self.baz
 
     def user_of_method(self):
          return self.simple_method(10)
+
+    def overridable_method(self, a):
+         return 'I am Foo.overridable_method'
+
+class Bar(Foo):
+    def user_of_base_class_method(self):
+         return self.simple_method(10)
+
+    def overridable_method(self, a):
+         return 'I am Bar.overridable_method'
+
+    def user_of_overridden_method(self, a):
+         return self.overridable_method(a)
 '''
 
-        # "Foo.simple_method" should be inlinable
+        # Various methods should be inlinable:
+        self.assertIsInlinable(src, fnname='Foo.simple_method')
+        self.assertIsInlinable(src, fnname='Foo.overridable_method')
+        self.assertIsInlinable(src, fnname='Bar.overridable_method')
+
+        saved_foo_simple_method = '(__internal__.saved.Foo.simple_method)'
+        saved_foo_overridable_method = '(__internal__.saved.Foo.overridable_method)'
+        saved_bar_overridable_method = '(__internal__.saved.Bar.overridable_method)'
+
 
-        # Ensure that we're saving the inlinable function as a global for use
+        # Ensure that we're saving the inlinable functions as global for use
         # by JUMP_IF_SPECIALIZABLE at callsites:
         fn = self.compile_to_code(src, 'Foo')
         asm = disassemble(fn)
-        self.assertHasLineWith(asm,
-            ('STORE_GLOBAL', '(__internal__.saved.Foo.simple_method)'))
-        #print(asm)
+        self.assertHasLineWith(asm, ('STORE_GLOBAL', saved_foo_simple_method))
+        self.assertHasLineWith(asm, ('STORE_GLOBAL', saved_foo_overridable_method))
+        if 0:
+            print('\nFoo')
+            print(asm)
 
-        self.assertIsInlinable(src, fnname='Foo.simple_method')
+        fn = self.compile_to_code(src, 'Bar')
+        asm = disassemble(fn)
+        self.assertHasLineWith(asm, ('STORE_GLOBAL', saved_bar_overridable_method))
+        if 0:
+            print('\nBar')
+            print(asm)
+
+        # Ensure that the various callsites use these globals:
         fn = self.compile_to_code(src, 'Foo.user_of_method')
         asm = disassemble(fn)
-        #print(asm)
-        self.assertHasLineWith(asm,
-                               ('LOAD_GLOBAL', '(__internal__.saved.Foo.simple_method)'))
+        if 0:
+            print('\nFoo.user_of_method')
+            print(asm)
+        self.assertHasLineWith(asm, ('LOAD_GLOBAL', saved_foo_simple_method))
+        self.assertIn('JUMP_IF_SPECIALIZABLE', asm)
+        self.assertHasLineWith(asm, ('LOAD_CONST', "('I am Foo.simple_method')"))
+
+        # Verify a subclass method that inlines a call to a base class method:
+        fn = self.compile_to_code(src, 'Bar.user_of_base_class_method')
+        asm = disassemble(fn)
+        if 0:
+            print('\nBar.user_of_base_class_method')
+            print(asm)
+        if 0:
+            # FIXME: doesn't inline these yet:
+            self.assertHasLineWith(asm, ('LOAD_GLOBAL', saved_foo_simple_method))
+            self.assertIn('JUMP_IF_SPECIALIZABLE', asm)
+
+        # Verify a subclass method that inlines a call to an overridden base class method:
+        fn = self.compile_to_code(src, 'Bar.user_of_overridden_method')
+        asm = disassemble(fn)
+        if 0:
+            print('\nBar.user_of_overridden_method')
+            print(asm)
+        self.assertHasLineWith(asm, ('LOAD_GLOBAL', saved_bar_overridable_method))
         self.assertIn('JUMP_IF_SPECIALIZABLE', asm)
+        self.assertHasLineWith(asm, ('LOAD_CONST', "('I am Bar.overridable_method')"))
 
+        # FIXME: execute it, verify both paths
 
 
 

Modified: python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c	(original)
+++ python/branches/dmalcolm-ast-optimization-branch/Python/Python-ast.c	Thu Nov 25 00:58:08 2010
@@ -2,7 +2,7 @@
 
 
 /*
-   __version__ 82163.
+   __version__ 86724.
 
    This module must be committed separately after each AST grammar change;
    The __version__ number is set to the revision number of the commit
@@ -7039,7 +7039,7 @@
             NULL;
         if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
                 return NULL;
-        if (PyModule_AddStringConstant(m, "__version__", "82163") < 0)
+        if (PyModule_AddStringConstant(m, "__version__", "86724") < 0)
                 return NULL;
         if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return
             NULL;

Modified: python/branches/dmalcolm-ast-optimization-branch/Python/ceval.c
==============================================================================
--- python/branches/dmalcolm-ast-optimization-branch/Python/ceval.c	(original)
+++ python/branches/dmalcolm-ast-optimization-branch/Python/ceval.c	Thu Nov 25 00:58:08 2010
@@ -748,10 +748,25 @@
         return 0;
 #endif
 
-    /* If they're the same object, we have a match: */
-    if (dynamic == expected)
-        return 1;
-    
+    /*FIXME PyMethodObject */
+
+    if (PyMethod_Check(dynamic)) {
+        if (PyMethod_GET_FUNCTION(dynamic) == expected) {
+            /* FIXME: need to check that "self" is as expected */
+            return 1;
+        }
+    }
+
+/* FIXME: 
+   if (PyInstanceMethod_Check(op)) {
+   }
+*/
+
+    if (PyFunction_Check(dynamic)) {
+        /* If they're the same object, we have a match: */
+        return (dynamic == expected);
+    }
+
     return 0; // FIXME!
 }
 


More information about the Python-checkins mailing list