Issue #26110: Add document for LOAD_METHOD and CALL_METHOD opcode.

Changed stack layout bit for "easy to explain."
This commit is contained in:
INADA Naoki 2017-01-16 17:23:30 +09:00
parent 510df6f272
commit 015bce64b3
3 changed files with 61 additions and 40 deletions

View file

@ -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)
... | NULL | callable | 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.)
`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;