diff -r 64afd5cab40a Doc/library/dis.rst --- a/Doc/library/dis.rst Tue Dec 13 19:03:51 2016 -0500 +++ b/Doc/library/dis.rst Wed Dec 14 18:46:40 2016 +0900 @@ -957,6 +957,34 @@ All of the following opcodes use their a value. +.. opcode:: LOAD_METHOD (namei) + + Load *method* named ``co_names[namei]`` from ``TOS`` instance. + + When interpreter can skip creating temporary bound method, *method* will be + unbound method. TOS is replaced by the *method* and pushed again to be used + as first positional argument. + + When interpreter can't optimize, *method* is bound method. TOS is replaced + by NULL and *method* is pushed on top of the stack. + + .. versionadded:: 3.7 + + +.. opcode:: CALL_METHOD (argc) + + Calls method or function. *argc* is number of positional paramters. + 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, *obj* and *method* + on the stack. When *method* is NULL, *obj* is called with positional arguments. + When *method* is not NULL, it is called and *obj* is prepended to positional + arguments. + + .. versionadded:: 3.7 + + .. opcode:: MAKE_FUNCTION (argc) Pushes a new function object on the stack. From bottom to top, the consumed diff -r 64afd5cab40a Doc/whatsnew/3.7.rst --- a/Doc/whatsnew/3.7.rst Tue Dec 13 19:03:51 2016 -0500 +++ b/Doc/whatsnew/3.7.rst Wed Dec 14 18:46:40 2016 +0900 @@ -135,3 +135,8 @@ This section lists previously described that may require changes to your code. +CPython bytecode changes +------------------------ + +* The new :opcode:`LOAD_METHOD` and :opcode:`CALL_METHOD` are added to optimize + method call. (Contributed by Serhiy Storchaka in :issue:`26110`.) diff -r 64afd5cab40a Python/ceval.c --- a/Python/ceval.c Tue Dec 13 19:03:51 2016 -0500 +++ b/Python/ceval.c Wed Dec 14 18:46:40 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 - CALL_METHOD that it's not a method call. + /* meth is not an unbound method (but a regular attr, or + something was returned by a descriptor protocol). Push + NULL to the second of the stack, 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;