8000 gh-100712: make it possible to disable specialization (for debugging)… · python/cpython@e9ccfe4 · GitHub
[go: up one dir, main page]

Skip to content

Commit e9ccfe4

Browse files
authored
gh-100712: make it possible to disable specialization (for debugging) (#100713)
1 parent a1e051a commit e9ccfe4

File tree

11 files changed

+87
-3
lines changed

11 files changed

+87
-3
lines changed

Include/opcode.h

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

Lib/opcode.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
hasfree = []
3434
hasexc = []
3535

36+
37+
ENABLE_SPECIALIZATION = True
38+
3639
def is_pseudo(op):
3740
return op >= MIN_PSEUDO_OPCODE and op <= MAX_PSEUDO_OPCODE
3841

Lib/test/support/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import < ED4F span class=pl-s1>contextlib
77
import functools
88
import getpass
9+
import opcode
910
import os
1011
import re
1112
import stat
@@ -46,7 +47,7 @@
4647
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
4748
"check__all__", "skip_if_buggy_ucrt_strfptime",
4849
"check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
49-
"requires_limited_api",
50+
"requires_limited_api", "requires_specialization",
5051
# sys
5152
"is_jython", "is_android", "is_emscripten", "is_wasi",
5253
"check_impl_detail", "unix_shell", "setswitchinterval",
@@ -1077,6 +1078,8 @@ def requires_limited_api(test):
10771078
return unittest.skipUnless(
10781079
_testcapi.LIMITED_API_AVAILABLE, 'needs Limited API support')(test)
10791080

1081+
def requires_specialization(test):
1082+
return unittest.skipUnless(opcode.ENABLE_SPECIALIZATION, "requires specialization")
10801083

10811084
def _filter_suite(suite, pred):
10821085
"""Recursively filter test cases in a suite based on a predicate."""

Lib/test/test_compile.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
import textwrap
1111
import warnings
1212
from test import support
13-
from test.support import script_helper, requires_debug_ranges
13+
from test.support import (script_helper, requires_debug_ranges,
14+
requires_specialization)
1415
from test.support.os_helper import FakePath
1516

1617

@@ -1251,6 +1252,7 @@ def test_multiline_expression(self):
12511252
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL',
12521253
line=1, end_line=3, column=0, end_column=1)
12531254

1255+
@requires_specialization
12541256
def test_multiline_boolean_expression(self):
12551257
snippet = """\
12561258
if (a or

Lib/test/test_dis.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import sys
88
import types
99
import unittest
10-
from test.support import captured_stdout, requires_debug_ranges, cpython_only
10+
from test.support import (captured_stdout, requires_debug_ranges,
11+
requires_specialization, cpython_only)
1112
from test.support.bytecode_helper import BytecodeTestCase
1213

1314
import opcode
@@ -1086,12 +1087,14 @@ def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY):
10861087
f()
10871088

10881089
@cpython_only
1090+
@requires_specialization
10891091
def test_super_instructions(self):
10901092
self.code_quicken(lambda: load_test(0, 0))
10911093
got = self.get_disassembly(load_test, adaptive=True)
10921094
self.do_disassembly_compare(got, dis_load_test_quickened_code, True)
10931095

10941096
@cpython_only
1097+
@requires_specialization
10951098
def test_binary_specialize(self):
10961099
binary_op_quicken = """\
10971100
0 0 RESUME 0
@@ -1130,6 +1133,7 @@ def test_binary_specialize(self):
11301133
self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_DICT", True)
11311134

11321135
@cpython_only
1136+
@requires_specialization
11331137
def test_load_attr_specialize(self):
11341138
load_attr_quicken = """\
11351139
0 0 RESUME 0
@@ -1144,6 +1148,7 @@ def test_load_attr_specialize(self):
11441148
self.do_disassembly_compare(got, load_attr_quicken, True)
11451149

11461150
@cpython_only
1151+
@requires_specialization
11471152
def test_call_specialize(self):
11481153
call_quicken = """\
11491154
0 RESUME 0
@@ -1160,6 +1165,7 @@ def test_call_specialize(self):
11601165
self.do_disassembly_compare(got, call_quicken)
11611166

11621167
@cpython_only
1168+
@requires_specialization
11631169
def test_loop_quicken(self):
11641170
# Loop can trigger a quicken where the loop is located
11651171
self.code_quicken(loop_test, 1)

Lib/test/test_embed.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from test import support
33
from test.support import import_helper
44
from test.support import os_helper
5+
from test.support import requires_specialization
56
import unittest
67

78
from collections import namedtuple
@@ -346,6 +347,7 @@ def test_simple_initialization_api(self):
346347
out, err = self.run_embedded_interpreter("test_repeated_simple_init")
347348
self.assertEqual(out, 'Finalized\n' * INIT_LOOPS)
348349

350+
@requires_specialization
349351
def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self):
350352
# https://github.com/python/cpython/issues/92031
351353

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added option to build cpython with specialization disabled, by setting ``ENABLE_SPECIALIZATION=False`` in :mod:`opcode`, followed by ``make regen-all``.

Python/bytecodes.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ dummy_func(
304304
};
305305

306306
inst(BINARY_SUBSCR, (unused/4, container, sub -- res)) {
307+
#if ENABLE_SPECIALIZATION
307308
_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
308309
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
309310
assert(cframe.use_tracing == 0);
@@ -313,6 +314,7 @@ dummy_func(
313314
}
314315
STAT_INC(BINARY_SUBSCR, deferred);
315316
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
317+
#endif /* ENABLE_SPECIALIZATION */
316318
res = PyObject_GetItem(container, sub);
317319
DECREF_INPUTS();
318320
ERROR_IF(res == NULL, error);
@@ -441,6 +443,7 @@ dummy_func(
441443
};
442444

443445
inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) {
446+
#if ENABLE_SPECIALIZATION
444447
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
445448
assert(cframe.use_tracing == 0);
446449
next_instr--;
@@ -450,6 +453,9 @@ dummy_func(
450453
STAT_INC(STORE_SUBSCR, deferred);
451454
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
452455
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
456+
#else
457+
(void)counter; // Unused.
458+
#endif /* ENABLE_SPECIALIZATION */
453459
/* container[sub] = v */
454460
int err = PyObject_SetItem(container, sub, v);
455461
DECREF_INPUTS();
@@ -872,6 +878,7 @@ dummy_func(
872878

873879
// stack effect: (__0 -- __array[oparg])
874880
inst(UNPACK_SEQUENCE) {
881+
#if ENABLE_SPECIALIZATION
875882
_PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
876883
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
877884
assert(cframe.use_tracing == 0);
@@ -882,6 +889,7 @@ dummy_func(
882889
}
883890
STAT_INC(UNPACK_SEQUENCE, deferred);
884891
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
892+
#endif /* ENABLE_SPECIALIZATION */
885893
PyObject *seq = POP();
886894
PyObject **top = stack_pointer + oparg;
887895
if (!unpack_iterable(tstate, seq, oparg, -1, top)) {
@@ -956,6 +964,7 @@ dummy_func(
956964
};
957965

958966
inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) {
967+
#if ENABLE_SPECIALIZATION
959968
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
960969
assert(cframe.use_tracing == 0);
961970
PyObject *name = GETITEM(names, oparg);
@@ -966,6 +975,9 @@ dummy_func(
966975
STAT_INC(STORE_ATTR, deferred);
967976
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
968977
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
978+
#else
979+
(void)counter; // Unused.
980+
#endif /* ENABLE_SPECIALIZATION */
969981
PyObject *name = GETITEM(names, oparg);
970982
int err = PyObject_SetAttr(owner, name, v);
971983
Py_DECREF(v);
@@ -1064,6 +1076,7 @@ dummy_func(
10641076

10651077
// error: LOAD_GLOBAL has irregular stack effect
10661078
inst(LOAD_GLOBAL) {
1079+
#if ENABLE_SPECIALIZATION
10671080
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
10681081
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
10691082
assert(cframe.use_tracing == 0);
@@ -1074,6 +1087,7 @@ dummy_func(
10741087
}
10751088
STAT_INC(LOAD_GLOBAL, deferred);
10761089
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
1090+
#endif /* ENABLE_SPECIALIZATION */
10771091
int push_null = oparg & 1;
10781092
PEEK(0) = NULL;
10791093
PyObject *name = GETITEM(names, oparg>>1);
@@ -1430,6 +1444,7 @@ dummy_func(
14301444

14311445
// error: LOAD_ATTR has irregular stack effect
14321446
inst(LOAD_ATTR) {
1447+
#if ENABLE_SPECIALIZATION
14331448
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
14341449
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
14351450
assert(cframe.use_tracing == 0);
@@ -1441,6 +1456,7 @@ dummy_func(
14411456
}
14421457
STAT_INC(LOAD_ATTR, deferred);
14431458
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
1459+
#endif /* ENABLE_SPECIALIZATION */
14441460
PyObject *name = GETITEM(names, oparg >> 1);
14451461
PyObject *owner = TOP();
14461462
if (oparg & 1) {
@@ -1778,6 +1794,7 @@ dummy_func(
17781794
};
17791795

17801796
inst(COMPARE_AND_BRANCH, (unused/2, left, right -- )) {
1797+
#if ENABLE_SPECIALIZATION
17811798
_PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
17821799
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
17831800
assert(cframe.use_tracing == 0);
@@ -1787,6 +1804,7 @@ dummy_func(
17871804
}
17881805
STAT_INC(COMPARE_AND_BRANCH, deferred);
17891806
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
1807+
#endif /* ENABLE_SPECIALIZATION */
17901808
assert((oparg >> 4) <= Py_GE);
17911809
PyObject *cond = PyObject_RichCompare(left, right, oparg>>4);
17921810
Py_DECREF(left);
@@ -2194,6 +2212,7 @@ dummy_func(
21942212

21952213
// stack effect: ( -- __0)
21962214
inst(FOR_ITER) {
2215+
#if ENABLE_SPECIALIZATION
21972216
_PyForIterCache *cache = (_PyForIterCache *)next_instr;
21982217
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
21992218
assert(cframe.use_tracing == 0);
@@ -2203,6 +2222,7 @@ dummy_func(
22032222
}
22042223
STAT_INC(FOR_ITER, deferred);
22052224
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
2225+
#endif /* ENABLE_SPECIALIZATION */
22062226
/* before: [iter]; after: [iter, iter()] *or* [] */
22072227
PyObject *iter = TOP();
22082228
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
@@ -2518,6 +2538,7 @@ dummy_func(
25182538

25192539
// stack effect: (__0, __array[oparg] -- )
25202540
inst(CALL) {
2541+
#if ENABLE_SPECIALIZATION
25212542
_PyCallCache *cache = (_PyCallCache *)next_instr;
25222543
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
25232544
assert(cframe.use_tracing == 0);
@@ -2530,6 +2551,7 @@ dummy_func(
25302551
}
25312552
STAT_INC(CALL, deferred);
25322553
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
2554+
#endif /* ENABLE_SPECIALIZATION */
25332555
int total_args, is_meth;
25342556
is_meth = is_method(stack_pointer, oparg);
25352557
PyObject *function = PEEK(oparg + 1);
@@ -3262,6 +3284,7 @@ dummy_func(
32623284
}
32633285

32643286
inst(BINARY_OP, (unused/1, lhs, rhs -- res)) {
3287+
#if ENABLE_SPECIALIZATION
32653288
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
32663289
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
32673290
assert(cframe.use_tracing == 0);
@@ -3271,6 +3294,7 @@ dummy_func(
32713294
}
32723295
STAT_INC(BINARY_OP, deferred);
32733296
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
3297+
#endif /* ENABLE_SPECIALIZATION */
32743298
assert(0 <= oparg);
32753299
assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops));
32763300
assert(binary_ops[oparg]);

0 commit comments

Comments
 (0)
0