diff options
author | Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> | 2021-05-15 23:15:23 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-15 16:15:23 +0100 |
commit | f24afda5917ce1710ad08ca34b2509f1f2b16de2 (patch) | |
tree | 72513ebad5e8235d451cffdb27f67182606b686f /Python/ceval.c | |
parent | e4e931a67e49cf3c61263dc94fb0806c34f972cd (diff) | |
download | cpython-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.c | 68 |
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; |