Skip to content

Commit ebcc043

Browse files
committed
Split CHECK_FUNCTION_VERSION into two guards
1 parent f8ce51a commit ebcc043

File tree

9 files changed

+112
-21
lines changed

9 files changed

+112
-21
lines changed

Include/internal/pycore_opcode_metadata.h

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

Include/internal/pycore_uop_metadata.h

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

Lib/test/test_capi/test_opt.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,24 @@ def testfunc(n):
14731473
# Removed guard
14741474
self.assertNotIn("_CHECK_FUNCTION_EXACT_ARGS", uops)
14751475

1476+
def test_guard_func_callable_removed(self):
1477+
def testfunc(n):
1478+
1479+
def func(a):
1480+
return a + 1
1481+
x = 0
1482+
for i in range(n):
1483+
x = func(i) # guarded
1484+
x = func(i) # unguarded
1485+
1486+
return x
1487+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
1488+
self.assertEqual(res, TIER2_THRESHOLD)
1489+
uops = get_opnames(ex)
1490+
1491+
self.assertIn("_CHECK_FUNCTION_VERSION", uops)
1492+
self.assertEqual(count_ops(ex, "_GUARD_CALLABLE_FUNCTION"), 1)
1493+
14761494
def test_method_guards_removed_or_reduced(self):
14771495
def testfunc(n):
14781496
result = 0

Modules/_testinternalcapi/test_cases.c.h

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

Python/bytecodes.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3919,9 +3919,13 @@ dummy_func(
39193919
new_frame = PyStackRef_Wrap(temp);
39203920
}
39213921

3922-
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
3922+
op(_GUARD_CALLABLE_FUNCTION, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
39233923
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
39243924
EXIT_IF(!PyFunction_Check(callable_o));
3925+
}
3926+
3927+
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
3928+
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
39253929
PyFunctionObject *func = (PyFunctionObject *)callable_o;
39263930
EXIT_IF(func->func_version != func_version);
39273931
}
@@ -3936,6 +3940,7 @@ dummy_func(
39363940
_RECORD_CALLABLE +
39373941
unused/1 + // Skip over the counter
39383942
_CHECK_PEP_523 +
3943+
_GUARD_CALLABLE_FUNCTION +
39393944
_CHECK_FUNCTION_VERSION +
39403945
_CHECK_RECURSION_REMAINING +
39413946
_PY_FRAME_GENERAL +
@@ -4084,6 +4089,7 @@ dummy_func(
40844089
_CHECK_CALL_BOUND_METHOD_EXACT_ARGS +
40854090
_INIT_CALL_BOUND_METHOD_EXACT_ARGS +
40864091
flush + // In case the following deopt
4092+
_GUARD_CALLABLE_FUNCTION +
40874093
_CHECK_FUNCTION_VERSION +
40884094
_CHECK_FUNCTION_EXACT_ARGS +
40894095
_CHECK_STACK_SPACE +
@@ -4096,6 +4102,7 @@ dummy_func(
40964102
_RECORD_CALLABLE +
40974103
unused/1 + // Skip over the counter
40984104
_CHECK_PEP_523 +
4105+
_GUARD_CALLABLE_FUNCTION +
40994106
_CHECK_FUNCTION_VERSION +
41004107
_CHECK_FUNCTION_EXACT_ARGS +
41014108
_CHECK_STACK_SPACE +

Python/executor_cases.c.h

Lines changed: 14 additions & 2 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: 18 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_bytecodes.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,13 +847,19 @@ dummy_func(void) {
847847
self_or_null = sym_new_not_null(ctx);
848848
}
849849

850+
op(_GUARD_CALLABLE_FUNCTION, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
851+
if (sym_matches_type(callable, &PyFunction_Type)) {
852+
ADD_OP(_NOP, 0, 0);
853+
}
854+
sym_set_type(callable, &PyFunction_Type);
855+
}
856+
850857
op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) {
851858
if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) {
852859
assert(PyFunction_Check(sym_get_const(ctx, callable)));
853860
ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version);
854861
uop_buffer_last(&ctx->out_buffer)->operand1 = (uintptr_t)sym_get_const(ctx, callable);
855862
}
856-
sym_set_type(callable, &PyFunction_Type);
857863
}
858864

859865
op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) {

Python/optimizer_cases.c.h

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

0 commit comments

Comments
 (0)