[Python-checkins] cpython: Issue #26110: Add document for LOAD_METHOD and CALL_METHOD opcode.

inada.naoki python-checkins at python.org
Mon Jan 16 03:23:38 EST 2017


https://hg.python.org/cpython/rev/a6241b2073c6
changeset:   106165:a6241b2073c6
parent:      106163:1add5cb46692
user:        INADA Naoki <songofacandy at gmail.com>
date:        Mon Jan 16 17:23:30 2017 +0900
summary:
  Issue #26110: Add document for LOAD_METHOD and CALL_METHOD opcode.

Changed stack layout bit for "easy to explain."

files:
  Doc/library/dis.rst  |  22 +++++++++
  Doc/whatsnew/3.7.rst |   7 ++
  Python/ceval.c       |  76 ++++++++++++++-----------------
  3 files changed, 63 insertions(+), 42 deletions(-)


diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -957,6 +957,28 @@
    value.
 
 
+.. opcode:: LOAD_METHOD (namei)
+
+   Loads a method named ``co_names[namei]`` from TOS object. TOS is popped and
+   method and TOS are pushed when interpreter can call unbound method directly.
+   TOS will be uesd as the first argument (``self``) by :opcode:`CALL_METHOD`.
+   Otherwise, ``NULL`` and  method is pushed (method is bound method or
+   something else).
+
+   .. versionadded:: 3.7
+
+
+.. opcode:: CALL_METHOD (argc)
+
+   Calls a method.  *argc* is number of positional arguments.
+   Keyword arguments are not supported.  This opcode is designed to be used
+   with :opcode:`LOAD_METHOD`.  Positional arguments are on top of the stack.
+   Below them, two items described in :opcode:`LOAD_METHOD` on the stack.
+   All of them are popped and return value is pushed.
+
+   .. versionadded:: 3.7
+
+
 .. opcode:: MAKE_FUNCTION (argc)
 
    Pushes a new function object on the stack.  From bottom to top, the consumed
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -170,3 +170,10 @@
   Assigning to them was deprecated in Python 3.5.
   Use the :meth:`~http.cookies.Morsel.set` method for setting them.
   (Contributed by Serhiy Storchaka in :issue:`29192`.)
+
+
+CPython bytecode changes
+------------------------
+
+* Added two new opcodes: :opcode:`LOAD_METHOD`` and :opcode:`CALL_METHOD`.
+  (Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.)
diff --git a/Python/ceval.c b/Python/ceval.c
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3236,81 +3236,73 @@
 
             int meth_found = _PyObject_GetMethod(obj, name, &meth);
 
-            SET_TOP(meth);  /* Replace `obj` on top; OK if NULL. */
             if (meth == NULL) {
                 /* Most likely attribute wasn't found. */
-                Py_DECREF(obj);
                 goto error;
             }
 
             if (meth_found) {
-                /* The method object is now on top of the stack.
-                   Push `obj` back to the stack, so that the stack
-                   layout would be:
-
-                       method | obj | arg1 | ... | argN
-                */
-                PUSH(obj);
+                /* We can bypass temporary bound method object.
+                   meth is unbound method and obj is self.
+                  
+                   meth | self | arg1 | ... | argN
+                 */
+                SET_TOP(meth);
+                PUSH(obj);  // self
             }
             else {
-                /* Not a method (but a regular attr, or something
-                   was returned by a descriptor protocol).  Push
-                   NULL to the top of the stack, to signal
+                /* meth is not an unbound method (but a regular attr, or
+                   something was returned by a descriptor protocol).  Set
+                   the second element of the stack to NULL, to signal
                    CALL_METHOD that it's not a method call.
+
+                   NULL | meth | arg1 | ... | argN
                 */
+                SET_TOP(NULL);
                 Py_DECREF(obj);
-                PUSH(NULL);
+                PUSH(meth);
             }
             DISPATCH();
         }
 
         TARGET(CALL_METHOD) {
             /* Designed to work in tamdem with LOAD_METHOD. */
-            PyObject **sp, *res, *obj;
+            PyObject **sp, *res, *meth;
 
             sp = stack_pointer;
 
-            obj = PEEK(oparg + 1);
-            if (obj == NULL) {
-                /* `obj` is NULL when LOAD_METHOD thinks that it's not
-                   a method call.  Swap the NULL and callable.
+            meth = PEEK(oparg + 2);
+            if (meth == NULL) {
+                /* `meth` is NULL when LOAD_METHOD thinks that it's not
+                   a method call.
 
                    Stack layout:
 
-                       ... | callable | NULL | arg1 | ... | argN
-                                                           ^- TOP()
-                                              ^- (-oparg)
-                                       ^- (-oparg-1)
-                              ^- (-oparg-2)
-
-                   after the next line it will be:
-
-                       ... | callable | callable | arg1 | ... | argN
-                                                                ^- TOP()
-                                                   ^- (-oparg)
-                                        ^- (-oparg-1)
-                              ^- (-oparg-2)
-
-                   Right side `callable` will be POPed by call_funtion.
-                   Left side `callable` will be POPed manually later
-                   (one of "callbale" refs on the stack is borrowed.)
+                       ... | NULL | callable | arg1 | ... | argN
+                                                            ^- TOP()
+                                               ^- (-oparg)
+                                    ^- (-oparg-1)
+                             ^- (-oparg-2)
+
+                   `callable` will be POPed by call_funtion.
+                   NULL will will be POPed manually later.
                 */
-                SET_VALUE(oparg + 1, PEEK(oparg + 2));
                 res = call_function(&sp, oparg, NULL);
                 stack_pointer = sp;
-                (void)POP(); /* POP the left side callable. */
+                (void)POP(); /* POP the NULL. */
             }
             else {
                 /* This is a method call.  Stack layout:
 
-                     ... | method | obj | arg1 | ... | argN
+                     ... | method | self | arg1 | ... | argN
                                                         ^- TOP()
                                            ^- (-oparg)
-                                     ^- (-oparg-1)
-
-                  `obj` and `method` will be POPed by call_function.
+                                    ^- (-oparg-1)
+                           ^- (-oparg-2)
+
+                  `self` and `method` will be POPed by call_function.
                   We'll be passing `oparg + 1` to call_function, to
-                  make it accept the `obj` as a first argument.
+                  make it accept the `self` as a first argument.
                 */
                 res = call_function(&sp, oparg + 1, NULL);
                 stack_pointer = sp;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list