Skip to content

Commit b4978ff

Browse files
authored
GH-88691: Shrink the CALL caches (GH-103230)
1 parent aa5a9b5 commit b4978ff

File tree

12 files changed

+285
-281
lines changed

12 files changed

+285
-281
lines changed

Doc/library/dis.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ the following command can be used to display the disassembly of
5959
3 2 LOAD_GLOBAL 1 (NULL + len)
6060
12 LOAD_FAST 0 (alist)
6161
14 CALL 1
62-
24 RETURN_VALUE
62+
22 RETURN_VALUE
6363

6464
(The "2" is a line number).
6565

Include/internal/pycore_code.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ typedef struct {
7373
typedef struct {
7474
uint16_t counter;
7575
uint16_t func_version[2];
76-
uint16_t min_args;
7776
} _PyCallCache;
7877

7978
#define INLINE_CACHE_ENTRIES_CALL CACHE_ENTRIES(_PyCallCache)

Include/internal/pycore_opcode.h

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

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ def _write_atomic(path, data, mode=0o666):
438438
# Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP)
439439
# Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP)
440440
# Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches)
441+
# Python 3.12b1 3525 (Shrink the CALL caches)
441442

442443
# Python 3.13 will start with 3550
443444

@@ -454,7 +455,7 @@ def _write_atomic(path, data, mode=0o666):
454455
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
455456
# in PC/launcher.c must also be updated.
456457

457-
MAGIC_NUMBER = (3524).to_bytes(2, 'little') + b'\r\n'
458+
MAGIC_NUMBER = (3525).to_bytes(2, 'little') + b'\r\n'
458459

459460
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
460461

Lib/opcode.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,6 @@ def pseudo_op(name, op, real_ops):
410410
"CALL": {
411411
"counter": 1,
412412
"func_version": 2,
413-
"min_args": 1,
414413
},
415414
"STORE_SUBSCR": {
416415
"counter": 1,

Lib/test/test_dis.py

Lines changed: 129 additions & 129 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reduce the number of inline :opcode:`CACHE` entries for :opcode:`CALL`.

Programs/test_frozenmain.h

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

Python/bytecodes.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2318,7 +2318,7 @@ dummy_func(
23182318
kwnames = GETITEM(frame->f_code->co_consts, oparg);
23192319
}
23202320

2321-
// Cache layout: counter/1, func_version/2, min_args/1
2321+
// Cache layout: counter/1, func_version/2
23222322
// Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members!
23232323
family(call, INLINE_CACHE_ENTRIES_CALL) = {
23242324
CALL,
@@ -2348,7 +2348,7 @@ dummy_func(
23482348
// (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.)
23492349
// On exit, the stack is [result].
23502350
// When calling Python, inline the call using DISPATCH_INLINED().
2351-
inst(CALL, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2351+
inst(CALL, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
23522352
int is_meth = method != NULL;
23532353
int total_args = oparg;
23542354
if (is_meth) {
@@ -2426,7 +2426,7 @@ dummy_func(
24262426
// Start out with [NULL, bound_method, arg1, arg2, ...]
24272427
// Transform to [callable, self, arg1, arg2, ...]
24282428
// Then fall through to CALL_PY_EXACT_ARGS
2429-
inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, unused/1, method, callable, unused[oparg] -- unused)) {
2429+
inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, method, callable, unused[oparg] -- unused)) {
24302430
DEOPT_IF(method != NULL, CALL);
24312431
DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
24322432
STAT_INC(CALL, hit);
@@ -2438,7 +2438,7 @@ dummy_func(
24382438
GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
24392439
}
24402440

2441-
inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, unused/1, method, callable, args[oparg] -- unused)) {
2441+
inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
24422442
assert(kwnames == NULL);
24432443
DEOPT_IF(tstate->interp->eval_frame, CALL);
24442444
int is_meth = method != NULL;
@@ -2465,7 +2465,7 @@ dummy_func(
24652465
DISPATCH_INLINED(new_frame);
24662466
}
24672467

2468-
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, min_args/1, method, callable, args[oparg] -- unused)) {
2468+
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
24692469
assert(kwnames == NULL);
24702470
DEOPT_IF(tstate->interp->eval_frame, CALL);
24712471
int is_meth = method != NULL;
@@ -2479,6 +2479,11 @@ dummy_func(
24792479
PyFunctionObject *func = (PyFunctionObject *)callable;
24802480
DEOPT_IF(func->func_version != func_version, CALL);
24812481
PyCodeObject *code = (PyCodeObject *)func->func_code;
2482+
assert(func->func_defaults);
2483+
assert(PyTuple_CheckExact(func->func_defaults));
2484+
int defcount = (int)PyTuple_GET_SIZE(func->func_defaults);
2485+
assert(defcount <= code->co_argcount);
2486+
int min_args = code->co_argcount - defcount;
24822487
DEOPT_IF(argcount > code->co_argcount, CALL);
24832488
DEOPT_IF(argcount < min_args, CALL);
24842489
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL);
@@ -2497,7 +2502,7 @@ dummy_func(
24972502
DISPATCH_INLINED(new_frame);
24982503
}
24992504

2500-
inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, unused/1, null, callable, args[oparg] -- res)) {
2505+
inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
25012506
assert(kwnames == NULL);
25022507
assert(cframe.use_tracing == 0);
25032508
assert(oparg == 1);
@@ -2510,7 +2515,7 @@ dummy_func(
25102515
Py_DECREF(&PyType_Type); // I.e., callable
25112516
}
25122517

2513-
inst(CALL_NO_KW_STR_1, (unused/1, unused/2, unused/1, null, callable, args[oparg] -- res)) {
2518+
inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
25142519
assert(kwnames == NULL);
25152520
assert(cframe.use_tracing == 0);
25162521
assert(oparg == 1);
@@ -2525,7 +2530,7 @@ dummy_func(
25252530
CHECK_EVAL_BREAKER();
25262531
}
25272532

2528-
inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, unused/1, null, callable, args[oparg] -- res)) {
2533+
inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
25292534
assert(kwnames == NULL);
25302535
assert(oparg == 1);
25312536
DEOPT_IF(null != NULL, CALL);
@@ -2539,7 +2544,7 @@ dummy_func(
25392544
CHECK_EVAL_BREAKER();
25402545
}
25412546

2542-
inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2547+
inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
25432548
int is_meth = method != NULL;
25442549
int total_args = oparg;
25452550
if (is_meth) {
@@ -2564,7 +2569,7 @@ dummy_func(
25642569
CHECK_EVAL_BREAKER();
25652570
}
25662571

2567-
inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2572+
inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
25682573
assert(cframe.use_tracing == 0);
25692574
/* Builtin METH_O functions */
25702575
assert(kwnames == NULL);
@@ -2596,7 +2601,7 @@ dummy_func(
25962601
CHECK_EVAL_BREAKER();
25972602
}
25982603

2599-
inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2604+
inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
26002605
assert(cframe.use_tracing == 0);
26012606
/* Builtin METH_FASTCALL functions, without keywords */
26022607
assert(kwnames == NULL);
@@ -2632,7 +2637,7 @@ dummy_func(
26322637
CHECK_EVAL_BREAKER();
26332638
}
26342639

2635-
inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2640+
inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
26362641
assert(cframe.use_tracing == 0);
26372642
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
26382643
int is_meth = method != NULL;
@@ -2668,7 +2673,7 @@ dummy_func(
26682673
CHECK_EVAL_BREAKER();
26692674
}
26702675

2671-
inst(CALL_NO_KW_LEN, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2676+
inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
26722677
assert(cframe.use_tracing == 0);
26732678
assert(kwnames == NULL);
26742679
/* len(o) */
@@ -2696,7 +2701,7 @@ dummy_func(
26962701
ERROR_IF(res == NULL, error);
26972702
}
26982703

2699-
inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, unused/1, method, callable, args[oparg] -- res)) {
2704+
inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
27002705
assert(cframe.use_tracing == 0);
27012706
assert(kwnames == NULL);
27022707
/* isinstance(o, o2) */
@@ -2727,7 +2732,7 @@ dummy_func(
27272732
}
27282733

27292734
// This is secretly a super-instruction
2730-
inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, unused/1, method, self, args[oparg] -- unused)) {
2735+
inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) {
27312736
assert(cframe.use_tracing == 0);
27322737
assert(kwnames == NULL);
27332738
assert(oparg == 1);
@@ -2748,7 +2753,7 @@ dummy_func(
27482753
DISPATCH();
27492754
}
27502755

2751-
inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) {
2756+
inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
27522757
assert(kwnames == NULL);
27532758
int is_meth = method != NULL;
27542759
int total_args = oparg;
@@ -2782,7 +2787,7 @@ dummy_func(
27822787
CHECK_EVAL_BREAKER();
27832788
}
27842789

2785-
inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) {
2790+
inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
27862791
int is_meth = method != NULL;
27872792
int total_args = oparg;
27882793
if (is_meth) {
@@ -2814,7 +2819,7 @@ dummy_func(
28142819
CHECK_EVAL_BREAKER();
28152820
}
28162821

2817-
inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) {
2822+
inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
28182823
assert(kwnames == NULL);
28192824
assert(oparg == 0 || oparg == 1);
28202825
int is_meth = method != NULL;
@@ -2846,7 +2851,7 @@ dummy_func(
28462851
CHECK_EVAL_BREAKER();
28472852
}
28482853

2849-
inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, unused/1, method, unused, args[oparg] -- res)) {
2854+
inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
28502855
assert(kwnames == NULL);
28512856
int is_meth = method != NULL;
28522857
int total_args = oparg;

0 commit comments

Comments
 (0)