Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 015bce6

Browse files
committed
Issue #26110: Add document for LOAD_METHOD and CALL_METHOD opcode.
Changed stack layout bit for "easy to explain."
1 parent 510df6f commit 015bce6

3 files changed

Lines changed: 61 additions & 40 deletions

File tree

Doc/library/dis.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,28 @@ All of the following opcodes use their arguments.
957957
value.
958958

959959

960+
.. opcode:: LOAD_METHOD (namei)
961+
962+
Loads a method named ``co_names[namei]`` from TOS object. TOS is popped and
963+
method and TOS are pushed when interpreter can call unbound method directly.
964+
TOS will be uesd as the first argument (``self``) by :opcode:`CALL_METHOD`.
965+
Otherwise, ``NULL`` and method is pushed (method is bound method or
966+
something else).
967+
968+
.. versionadded:: 3.7
969+
970+
971+
.. opcode:: CALL_METHOD (argc)
972+
973+
Calls a method. *argc* is number of positional arguments.
974+
Keyword arguments are not supported. This opcode is designed to be used
975+
with :opcode:`LOAD_METHOD`. Positional arguments are on top of the stack.
976+
Below them, two items described in :opcode:`LOAD_METHOD` on the stack.
977+
All of them are popped and return value is pushed.
978+
979+
.. versionadded:: 3.7
980+
981+
960982
.. opcode:: MAKE_FUNCTION (argc)
961983

962984
Pushes a new function object on the stack. From bottom to top, the consumed

Doc/whatsnew/3.7.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,10 @@ Changes in the Python API
170170
Assigning to them was deprecated in Python 3.5.
171171
Use the :meth:`~http.cookies.Morsel.set` method for setting them.
172172
(Contributed by Serhiy Storchaka in :issue:`29192`.)
173+
174+
175+
CPython bytecode changes
176+
------------------------
177+
178+
* Added two new opcodes: :opcode:`LOAD_METHOD`` and :opcode:`CALL_METHOD`.
179+
(Contributed by Yury Selivanov and INADA Naoki in :issue:`26110`.)

Python/ceval.c

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3236,81 +3236,73 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
32363236

32373237
int meth_found = _PyObject_GetMethod(obj, name, &meth);
32383238

3239-
SET_TOP(meth); /* Replace `obj` on top; OK if NULL. */
32403239
if (meth == NULL) {
32413240
/* Most likely attribute wasn't found. */
3242-
Py_DECREF(obj);
32433241
goto error;
32443242
}
32453243

32463244
if (meth_found) {
3247-
/* The method object is now on top of the stack.
3248-
Push `obj` back to the stack, so that the stack
3249-
layout would be:
3250-
3251-
method | obj | arg1 | ... | argN
3252-
*/
3253-
PUSH(obj);
3245+
/* We can bypass temporary bound method object.
3246+
meth is unbound method and obj is self.
3247+
3248+
meth | self | arg1 | ... | argN
3249+
*/
3250+
SET_TOP(meth);
3251+
PUSH(obj); // self
32543252
}
32553253
else {
3256-
/* Not a method (but a regular attr, or something
3257-
was returned by a descriptor protocol). Push
3258-
NULL to the top of the stack, to signal
3254+
/* meth is not an unbound method (but a regular attr, or
3255+
something was returned by a descriptor protocol). Set
3256+
the second element of the stack to NULL, to signal
32593257
CALL_METHOD that it's not a method call.
3258+
3259+
NULL | meth | arg1 | ... | argN
32603260
*/
3261+
SET_TOP(NULL);
32613262
Py_DECREF(obj);
3262-
PUSH(NULL);
3263+
PUSH(meth);
32633264
}
32643265
DISPATCH();
32653266
}
32663267

32673268
TARGET(CALL_METHOD) {
32683269
/* Designed to work in tamdem with LOAD_METHOD. */
3269-
PyObject **sp, *res, *obj;
3270+
PyObject **sp, *res, *meth;
32703271

32713272
sp = stack_pointer;
32723273

3273-
obj = PEEK(oparg + 1);
3274-
if (obj == NULL) {
3275-
/* `obj` is NULL when LOAD_METHOD thinks that it's not
3276-
a method call. Swap the NULL and callable.
3274+
meth = PEEK(oparg + 2);
3275+
if (meth == NULL) {
3276+
/* `meth` is NULL when LOAD_METHOD thinks that it's not
3277+
a method call.
32773278
32783279
Stack layout:
32793280
3280-
... | callable | NULL | arg1 | ... | argN
3281-
^- TOP()
3282-
^- (-oparg)
3283-
^- (-oparg-1)
3284-
^- (-oparg-2)
3285-
3286-
after the next line it will be:
3287-
3288-
... | callable | callable | arg1 | ... | argN
3289-
^- TOP()
3290-
^- (-oparg)
3291-
^- (-oparg-1)
3292-
^- (-oparg-2)
3281+
... | NULL | callable | arg1 | ... | argN
3282+
^- TOP()
3283+
^- (-oparg)
3284+
^- (-oparg-1)
3285+
^- (-oparg-2)
32933286
3294-
Right side `callable` will be POPed by call_funtion.
3295-
Left side `callable` will be POPed manually later
3296-
(one of "callbale" refs on the stack is borrowed.)
3287+
`callable` will be POPed by call_funtion.
3288+
NULL will will be POPed manually later.
32973289
*/
3298-
SET_VALUE(oparg + 1, PEEK(oparg + 2));
32993290
res = call_function(&sp, oparg, NULL);
33003291
stack_pointer = sp;
3301-
(void)POP(); /* POP the left side callable. */
3292+
(void)POP(); /* POP the NULL. */
33023293
}
33033294
else {
33043295
/* This is a method call. Stack layout:
33053296
3306-
... | method | obj | arg1 | ... | argN
3297+
... | method | self | arg1 | ... | argN
33073298
^- TOP()
33083299
^- (-oparg)
3309-
^- (-oparg-1)
3300+
^- (-oparg-1)
3301+
^- (-oparg-2)
33103302
3311-
`obj` and `method` will be POPed by call_function.
3303+
`self` and `method` will be POPed by call_function.
33123304
We'll be passing `oparg + 1` to call_function, to
3313-
make it accept the `obj` as a first argument.
3305+
make it accept the `self` as a first argument.
33143306
*/
33153307
res = call_function(&sp, oparg + 1, NULL);
33163308
stack_pointer = sp;

0 commit comments

Comments
 (0)