Skip to content
Next Next commit
Split CHECK_FUNCTION_VERSION into two guards
  • Loading branch information
Sacul0457 committed Feb 25, 2026
commit ebcc04386aaf4a71b7d8bdba6e3a10ab3d38a211
8 changes: 4 additions & 4 deletions Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions Include/internal/pycore_uop_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions Lib/test/test_capi/test_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1473,6 +1473,24 @@ def testfunc(n):
# Removed guard
self.assertNotIn("_CHECK_FUNCTION_EXACT_ARGS", uops)

def test_guard_func_callable_removed(self):
def testfunc(n):

def func(a):
return a + 1
x = 0
for i in range(n):
x = func(i) # guarded
x = func(i) # unguarded

return x
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD)
uops = get_opnames(ex)

self.assertIn("_CHECK_FUNCTION_VERSION", uops)
self.assertEqual(count_ops(ex, "_GUARD_CALLABLE_FUNCTION"), 1)

def test_method_guards_removed_or_reduced(self):
def testfunc(n):
result = 0
Expand Down
24 changes: 18 additions & 6 deletions Modules/_testinternalcapi/test_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3919,9 +3919,13 @@ dummy_func(
new_frame = PyStackRef_Wrap(temp);
}

op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
op(_GUARD_CALLABLE_FUNCTION, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
EXIT_IF(!PyFunction_Check(callable_o));
}

op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
Comment thread
Fidget-Spinner marked this conversation as resolved.
PyFunctionObject *func = (PyFunctionObject *)callable_o;
EXIT_IF(func->func_version != func_version);
}
Expand All @@ -3936,6 +3940,7 @@ dummy_func(
_RECORD_CALLABLE +
unused/1 + // Skip over the counter
_CHECK_PEP_523 +
_GUARD_CALLABLE_FUNCTION +
_CHECK_FUNCTION_VERSION +
_CHECK_RECURSION_REMAINING +
_PY_FRAME_GENERAL +
Expand Down Expand Up @@ -4084,6 +4089,7 @@ dummy_func(
_CHECK_CALL_BOUND_METHOD_EXACT_ARGS +
_INIT_CALL_BOUND_METHOD_EXACT_ARGS +
flush + // In case the following deopt
_GUARD_CALLABLE_FUNCTION +
_CHECK_FUNCTION_VERSION +
_CHECK_FUNCTION_EXACT_ARGS +
_CHECK_STACK_SPACE +
Expand All @@ -4096,6 +4102,7 @@ dummy_func(
_RECORD_CALLABLE +
unused/1 + // Skip over the counter
_CHECK_PEP_523 +
_GUARD_CALLABLE_FUNCTION +
_CHECK_FUNCTION_VERSION +
_CHECK_FUNCTION_EXACT_ARGS +
_CHECK_STACK_SPACE +
Expand Down
16 changes: 14 additions & 2 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 18 additions & 6 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Python/optimizer_bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,13 +847,19 @@ dummy_func(void) {
self_or_null = sym_new_not_null(ctx);
}

op(_GUARD_CALLABLE_FUNCTION, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
if (sym_matches_type(callable, &PyFunction_Type)) {
ADD_OP(_NOP, 0, 0);
}
sym_set_type(callable, &PyFunction_Type);
}

op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
Comment thread
Fidget-Spinner marked this conversation as resolved.
Outdated
assert(PyFunction_Check(sym_get_const(ctx, callable)));
ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
uop_buffer_last(&ctx->out_buffer)->operand1 = (uintptr_t)sym_get_const(ctx, callable);
}
sym_set_type(callable, &PyFunction_Type);
}

op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) {
Expand Down
11 changes: 10 additions & 1 deletion Python/optimizer_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.