diff -r 5c48fbe12cb8 Doc/library/dis.rst --- a/Doc/library/dis.rst Sat Jan 14 21:04:40 2017 +0900 +++ b/Doc/library/dis.rst Mon Jan 16 12:03:41 2017 +0900 @@ -954,12 +954,34 @@ parameters are on the stack, with the right-most parameter on top. Below the parameters, the function object to call is on the stack. Pops all function arguments, and the function itself off the stack, and pushes the return 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 stack must consist of values if the argument carries a specified flag value * ``0x01`` a tuple of default argument objects in positional order diff -r 5c48fbe12cb8 Doc/whatsnew/3.7.rst --- a/Doc/whatsnew/3.7.rst Sat Jan 14 21:04:40 2017 +0900 +++ b/Doc/whatsnew/3.7.rst Mon Jan 16 12:03:41 2017 +0900 @@ -167,6 +167,13 @@ :attr:`~http.cookies.Morsel.value` and :attr:`~http.cookies.Morsel.coded_value` of class :class:`http.cookies.Morsel` are now read-only. 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 -r 5c48fbe12cb8 Python/ceval.c --- a/Python/ceval.c Sat Jan 14 21:04:40 2017 +0900 +++ b/Python/ceval.c Mon Jan 16 12:03:41 2017 +0900 @@ -3233,87 +3233,79 @@ PyObject *name = GETITEM(names, oparg); PyObject *obj = TOP(); PyObject *meth = NULL; 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; } PUSH(res);