summaryrefslogtreecommitdiff
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>2021-05-15 23:15:23 +0800
committerGitHub <noreply@github.com>2021-05-15 16:15:23 +0100
commitf24afda5917ce1710ad08ca34b2509f1f2b16de2 (patch)
tree72513ebad5e8235d451cffdb27f67182606b686f /Python/ceval.c
parente4e931a67e49cf3c61263dc94fb0806c34f972cd (diff)
downloadcpython-git-f24afda5917ce1710ad08ca34b2509f1f2b16de2.tar.gz
bpo-26110: Add ``CALL_METHOD_KW`` opcode to speedup method calls with keywords (GH-26014)
* Add CALL_METHOD_KW * Make CALL_METHOD branchless too since it shares the same code * Place parentheses in STACK_SHRINK
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 2e15eea480..fa7b0b5a05 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1421,7 +1421,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define STACK_SHRINK(n) do { \
assert(n >= 0); \
(void)(lltrace && prtrace(tstate, TOP(), "stackadj")); \
- (void)(BASIC_STACKADJ(-n)); \
+ (void)(BASIC_STACKADJ(-(n))); \
assert(STACK_LEVEL() <= co->co_stacksize); \
} while (0)
#define EXT_POP(STACK_POINTER) ((void)(lltrace && \
@@ -1431,7 +1431,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define PUSH(v) BASIC_PUSH(v)
#define POP() BASIC_POP()
#define STACK_GROW(n) BASIC_STACKADJ(n)
-#define STACK_SHRINK(n) BASIC_STACKADJ(-n)
+#define STACK_SHRINK(n) BASIC_STACKADJ(-(n))
#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER))
#endif
@@ -4164,16 +4164,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
case TARGET(CALL_METHOD): {
/* Designed to work in tamdem with LOAD_METHOD. */
- PyObject **sp, *res, *meth;
+ PyObject **sp, *res;
+ int meth_found;
sp = stack_pointer;
+ /* `meth` is NULL when LOAD_METHOD thinks that it's not
+ a method call.
- meth = PEEK(oparg + 2);
- if (meth == NULL) {
- /* `meth` is NULL when LOAD_METHOD thinks that it's not
- a method call.
-
- Stack layout:
+ Stack layout:
... | NULL | callable | arg1 | ... | argN
^- TOP()
@@ -4181,15 +4179,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
^- (-oparg-1)
^- (-oparg-2)
- `callable` will be POPed by call_function.
- NULL will will be POPed manually later.
- */
- res = call_function(tstate, &trace_info, &sp, oparg, NULL);
- stack_pointer = sp;
- (void)POP(); /* POP the NULL. */
- }
- else {
- /* This is a method call. Stack layout:
+ `callable` will be POPed by call_function.
+ NULL will will be POPed manually later.
+ If `meth` isn't NULL, it's a method call. Stack layout:
... | method | self | arg1 | ... | argN
^- TOP()
@@ -4197,21 +4189,45 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
^- (-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 `self` as a first argument.
- */
- res = call_function(tstate, &trace_info, &sp, oparg + 1, NULL);
- stack_pointer = sp;
- }
+ `self` and `method` will be POPed by call_function.
+ We'll be passing `oparg + 1` to call_function, to
+ make it accept the `self` as a first argument.
+ */
+ meth_found = (PEEK(oparg + 2) != NULL);
+ res = call_function(tstate, &trace_info, &sp, oparg + meth_found, NULL);
+ stack_pointer = sp;
+ STACK_SHRINK(1 - meth_found);
PUSH(res);
- if (res == NULL)
+ if (res == NULL) {
goto error;
+ }
CHECK_EVAL_BREAKER();
DISPATCH();
}
+ case TARGET(CALL_METHOD_KW): {
+ /* Designed to work in tandem with LOAD_METHOD. Same as CALL_METHOD
+ but pops TOS to get a tuple of keyword names. */
+ PyObject **sp, *res;
+ PyObject *names = NULL;
+ int meth_found;
+ names = POP();
+
+ sp = stack_pointer;
+ meth_found = (PEEK(oparg + 2) != NULL);
+ res = call_function(tstate, &trace_info, &sp, oparg + meth_found, names);
+ stack_pointer = sp;
+
+ STACK_SHRINK(1 - meth_found);
+ PUSH(res);
+ Py_DECREF(names);
+ if (res == NULL) {
+ goto error;
+ }
+ CHECK_EVAL_BREAKER();
+ DISPATCH();
+ }
case TARGET(CALL_FUNCTION): {
PREDICTED(CALL_FUNCTION);
PyObject **sp, *res;