8000 gh-115999: Specialize `CALL_KW` in free-threaded builds (#127713) · python/cpython@c84928e · GitHub
[go: up one dir, main page]

Skip to content

Commit c84928e

Browse files
authored
gh-115999: Specialize CALL_KW in free-threaded builds (#127713)
* Enable specialization of CALL_KW * Fix bug pushing frame in _PY_FRAME_KW `_PY_FRAME_KW` pushes a pointer to the new frame onto the stack for consumption by the next uop. When pushing the frame fails, we do not want to push the result, `NULL`, to the stack because it is not a valid stackref. This works in the default build because `PyStackRef_NULL` and `NULL` are the same value, so the `PyStackRef_XCLOSE()` in the error handler ignores it. In the free-threaded build the values are not the same; `PyStackRef_XCLOSE()` will attempt to decref a null pointer.
1 parent e8f4e27 commit c84928e

File tree

4 files changed

+26
-35
lines changed

4 files changed

+26
-35
lines changed

Python/bytecodes.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4311,17 +4311,18 @@ dummy_func(
43114311
assert(Py_TYPE(callable_o) == &PyFunction_Type);
43124312
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
43134313
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
4314-
new_frame = _PyEvalFramePushAndInit(
4314+
_PyInterpreterFrame *temp = _PyEvalFramePushAndInit(
43154315
tstate, callable[0], locals,
43164316
args, positional_args, kwnames_o, frame
43174317
);
43184318
PyStackRef_CLOSE(kwnames);
43194319
// The frame has stolen all the arguments from the stack,
43204320
// so there is no need to clean them up.
43214321
SYNC_SP();
4322-
if (new_frame == NULL) {
4322+
if (temp == NULL) {
43234323
ERROR_NO_POP();
43244324
}
4325+
new_frame = temp;
43254326
}
43264327

43274328
op(_CHECK_FUNCTION_VERSION_KW, (func_version/2, callable[1], self_or_null[1], unused[oparg], kwnames -- callable[1], self_or_null[1], unused[oparg], kwnames)) {
@@ -4372,15 +4373,15 @@ dummy_func(
43724373
_PUSH_FRAME;
43734374

43744375
specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable[1], self_or_null[1], args[oparg], kwnames -- callable[1], self_or_null[1], args[oparg], kwnames)) {
4375-
#if ENABLE_SPECIALIZATION
4376+
#if ENABLE_SPECIALIZATION_FT
43764377
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
43774378
next_instr = this_instr;
43784379
_Py_Specialize_CallKw(callable[0], next_instr, oparg + !PyStackRef_IsNull(self_or_null[0]));
43794380
DISPATCH_SAME_OPARG();
43804381
}
43814382
OPCODE_DEFERRED_INC(CALL_KW);
43824383
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
4383-
#endif /* ENABLE_SPECIALIZATION */
4384+
#endif /* ENABLE_SPECIALIZATION_FT */
43844385
}
43854386

43864387
macro(CALL_KW) =

Python/executor_cases.c.h

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 10 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,7 +2107,7 @@ specialize_py_call_kw(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
21072107
return -1;
21082108
}
21092109
write_u32(cache->func_version, version);
2110-
instr->op.code = bound_method ? CALL_KW_BOUND_METHOD : CALL_KW_PY;
2110+
specialize(instr, bound_method ? CALL_KW_BOUND_METHOD : CALL_KW_PY);
21112111
return 0;
21122112
}
21132113

@@ -2202,10 +2202,9 @@ _Py_Specialize_CallKw(_PyStackRef callable_st, _Py_CODEUNIT *instr, int nargs)
22022202
{
22032203
PyObject *callable = PyStackRef_AsPyObjectBorrow(callable_st);
22042204

2205-
assert(ENABLE_SPECIALIZATION);
2205+
assert(ENABLE_SPECIALIZATION_FT);
22062206
assert(_PyOpcode_Caches[CALL_KW] == INLINE_CACHE_ENTRIES_CALL_KW);
22072207
assert(_Py_OPCODE(*instr) != INSTRUMENTED_CALL_KW);
2208-
_PyCallCache *cache = (_PyCallCache *)(instr + 1);
22092208
int fail;
22102209
if (PyFunction_Check(callable)) {
22112210
fail = specialize_py_call_kw((PyFunctionObject *)callable, instr, nargs, false);
@@ -2221,19 +2220,11 @@ _Py_Specialize_CallKw(_PyStackRef callable_st, _Py_CODEUNIT *instr, int nargs)
22212220
}
22222221
}
22232222
else {
2224-
instr->op.code = CALL_KW_NON_PY;
2223+
specialize(instr, CALL_KW_NON_PY);
22252224
fail = 0;
22262225
}
22272226
if (fail) {
2228-
STAT_INC(CALL, failure);
2229-
assert(!PyErr_Occurred());
2230-
instr->op.code = CALL_KW;
2231-
cache->counter = adaptive_counter_backoff(cache->counter);
2232-
}
2233-
else {
2234-
STAT_INC(CALL, success);
2235-
assert(!PyErr_Occurred());
2236-
cache->counter = adaptive_counter_cooldown();
2227+
unspecialize(instr);
22372228
}
22382229
}
22392230

0 commit comments

Comments
 (0)
0