cpython: a6241b2073c6 (original) (raw)
Mercurial > cpython
changeset 106165:a6241b2073c6
Issue #26110: Add document for LOAD_METHOD and CALL_METHOD opcode. Changed stack layout bit for "easy to explain." [#26110]
INADA Naoki songofacandy@gmail.com | |
---|---|
date | Mon, 16 Jan 2017 17:23:30 +0900 |
parents | 1add5cb46692 |
children | 27dc9a1c061e |
files | Doc/library/dis.rst Doc/whatsnew/3.7.rst Python/ceval.c |
diffstat | 3 files changed, 63 insertions(+), 42 deletions(-)[+] [-] Doc/library/dis.rst 22 Doc/whatsnew/3.7.rst 7 Python/ceval.c 76 |
line wrap: on
line diff
--- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -957,6 +957,28 @@ All of the following opcodes use their a 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
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -170,3 +170,10 @@ Changes in the Python API
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`.
--- a/Python/ceval.c +++ b/Python/ceval.c @@ -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. */[](#l3.7) if (meth == NULL) {[](#l3.8) /* Most likely attribute wasn't found. */[](#l3.9)
Py_DECREF(obj);[](#l3.10) goto error;[](#l3.11) }[](#l3.12)
/* The method object is now on top of the stack.[](#l3.15)
Push `obj` back to the stack, so that the stack[](#l3.16)
layout would be:[](#l3.17)
method | obj | arg1 | ... | argN[](#l3.19)
*/[](#l3.20)
PUSH(obj);[](#l3.21)
/* We can bypass temporary bound method object.[](#l3.22)
meth is unbound method and obj is self.[](#l3.23)
[](#l3.24)
meth | self | arg1 | ... | argN[](#l3.25)
*/[](#l3.26)
SET_TOP(meth);[](#l3.27)
PUSH(obj); // self[](#l3.28) }[](#l3.29) else {[](#l3.30)
/* Not a method (but a regular attr, or something[](#l3.31)
was returned by a descriptor protocol). Push[](#l3.32)
NULL to the top of the stack, to signal[](#l3.33)
/* meth is not an unbound method (but a regular attr, or[](#l3.34)
something was returned by a descriptor protocol). Set[](#l3.35)
the second element of the stack to NULL, to signal[](#l3.36) CALL_METHOD that it's not a method call.[](#l3.37)
NULL | meth | arg1 | ... | argN[](#l3.39) */[](#l3.40)
SET_TOP(NULL);[](#l3.41) Py_DECREF(obj);[](#l3.42)
PUSH(NULL);[](#l3.43)
PUSH(meth);[](#l3.44) }[](#l3.45) DISPATCH();[](#l3.46) }[](#l3.47)
TARGET(CALL_METHOD) { /* Designed to work in tamdem with LOAD_METHOD. */
PyObject **sp, *res, *obj;[](#l3.51)
PyObject **sp, *res, *meth;[](#l3.52)
obj = PEEK(oparg + 1);[](#l3.56)
if (obj == NULL) {[](#l3.57)
/* `obj` is NULL when LOAD_METHOD thinks that it's not[](#l3.58)
a method call. Swap the NULL and callable.[](#l3.59)
meth = PEEK(oparg + 2);[](#l3.60)
if (meth == NULL) {[](#l3.61)
/* `meth` is NULL when LOAD_METHOD thinks that it's not[](#l3.62)
a method call.[](#l3.63)
... | callable | NULL | arg1 | ... | argN[](#l3.67)
^- TOP()[](#l3.68)
^- (-oparg)[](#l3.69)
^- (-oparg-1)[](#l3.70)
^- (-oparg-2)[](#l3.71)
after the next line it will be:[](#l3.73)
... | callable | callable | arg1 | ... | argN[](#l3.75)
^- TOP()[](#l3.76)
^- (-oparg)[](#l3.77)
^- (-oparg-1)[](#l3.78)
^- (-oparg-2)[](#l3.79)
Right side `callable` will be POPed by call_funtion.[](#l3.81)
Left side `callable` will be POPed manually later[](#l3.82)
(one of "callbale" refs on the stack is borrowed.)[](#l3.83)
... | NULL | callable | arg1 | ... | argN[](#l3.84)
^- TOP()[](#l3.85)
^- (-oparg)[](#l3.86)
^- (-oparg-1)[](#l3.87)
^- (-oparg-2)[](#l3.88)
`callable` will be POPed by call_funtion.[](#l3.90)
NULL will will be POPed manually later.[](#l3.91) */[](#l3.92)
SET_VALUE(oparg + 1, PEEK(oparg + 2));[](#l3.93) res = call_function(&sp, oparg, NULL);[](#l3.94) stack_pointer = sp;[](#l3.95)
(void)POP(); /* POP the left side callable. */[](#l3.96)
(void)POP(); /* POP the NULL. */[](#l3.97) }[](#l3.98) else {[](#l3.99) /* This is a method call. Stack layout:[](#l3.100)
... | method | obj | arg1 | ... | argN[](#l3.102)
... | method | self | arg1 | ... | argN[](#l3.103) ^- TOP()[](#l3.104) ^- (-oparg)[](#l3.105)
^- (-oparg-1)[](#l3.106)
`obj` and `method` will be POPed by call_function.[](#l3.108)
^- (-oparg-1)[](#l3.109)
^- (-oparg-2)[](#l3.110)
`self` and `method` will be POPed by call_function.[](#l3.112) We'll be passing `oparg + 1` to call_function, to[](#l3.113)
make it accept the `obj` as a first argument.[](#l3.114)
make it accept the `self` as a first argument.[](#l3.115) */[](#l3.116) res = call_function(&sp, oparg + 1, NULL);[](#l3.117) stack_pointer = sp;[](#l3.118)