diff -r fcc9f19fcc13 Doc/library/dis.rst --- a/Doc/library/dis.rst Wed Dec 14 11:16:06 2016 +0100 +++ b/Doc/library/dis.rst Wed Dec 14 20:14:28 2016 +0900 @@ -957,6 +957,27 @@ All of the following opcodes use their a value. +.. opcode:: LOAD_METHOD (namei) + + Loads method named ``co_names[namei]`` from TOS object. TOS is popped and + ``method, TOS`` is pushed when interpreter can call unbound method directly. + Otherwise, ``NULL, method`` is pushed (method is bound method or something + else). + + .. versionadded:: 3.7 + + +.. opcode:: CALL_METHOD (argc) + + Calls 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 -r fcc9f19fcc13 Doc/whatsnew/3.7.rst --- a/Doc/whatsnew/3.7.rst Wed Dec 14 11:16:06 2016 +0100 +++ b/Doc/whatsnew/3.7.rst Wed Dec 14 20:14:28 2016 +0900 @@ -135,3 +135,8 @@ This section lists previously described that may require changes to your code. +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 -r fcc9f19fcc13 Python/ceval.c --- a/Python/ceval.c Wed Dec 14 11:16:06 2016 +0100 +++ b/Python/ceval.c Wed Dec 14 20:14:28 2016 +0900 @@ -3236,81 +3236,73 @@ PyObject* _Py_HOT_FUNCTION 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 - */ + /* We can bypass temporary bound method object. + meth is unbound method and obj is self. + + meth | obj | arg1 | ... | argN + */ + SET_TOP(meth); PUSH(obj); } 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;