summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorINADA Naoki <songofacandy@gmail.com>2017-01-16 08:23:30 (GMT)
committerINADA Naoki <songofacandy@gmail.com>2017-01-16 08:23:30 (GMT)
commit015bce64b35fb9de199f41eb5a3e5b7d9d20e3c1 (patch)
tree374e77e17b8325e6db020a4ed21ceeae1bb6de71 /Python
parent510df6f2721bd6ed69716938c45cea03b2b84c99 (diff)
downloadcpython-015bce64b35fb9de199f41eb5a3e5b7d9d20e3c1.zip
cpython-015bce64b35fb9de199f41eb5a3e5b7d9d20e3c1.tar.gz
cpython-015bce64b35fb9de199f41eb5a3e5b7d9d20e3c1.tar.bz2
Issue #26110: Add document for LOAD_METHOD and CALL_METHOD opcode.
Changed stack layout bit for "easy to explain."
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c72
1 files changed, 32 insertions, 40 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index b970ece..1b8cdfc 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3236,81 +3236,73 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
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)
+ ... | NULL | 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.)
+ `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)
+ ^- (-oparg-1)
+ ^- (-oparg-2)
- `obj` and `method` will be POPed by call_function.
+ `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;