From 2e282d6115b1f713c51716a5356a3b20c7aad861 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 3 Jan 2023 14:30:03 +0000 Subject: [PATCH 1/5] gh-100712: make it possible to disable specialization (for debugging) --- Include/opcode.h | 2 ++ Lib/opcode.py | 3 +++ Lib/test/support/__init__.py | 5 ++++- Lib/test/test_dis.py | 8 +++++++- Lib/test/test_embed.py | 2 ++ Python/bytecodes.c | 24 ++++++++++++++++++++++++ Python/generated_cases.c.h | 24 ++++++++++++++++++++++++ Python/specialize.c | 12 ++++++++++++ Tools/build/generate_opcode_h.py | 5 +++++ 9 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 888250ed37e8cb..7c8b28a5d70dc5 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -231,6 +231,8 @@ extern "C" { #define NB_INPLACE_TRUE_DIVIDE 24 #define NB_INPLACE_XOR 25 +/* Defined in Lib/opcode.py */ +#define ENABLE_SPECIALIZATION 1 #define IS_PSEUDO_OPCODE(op) (((op) >= MIN_PSEUDO_OPCODE) && ((op) <= MAX_PSEUDO_OPCODE)) diff --git a/Lib/opcode.py b/Lib/opcode.py index fc57affbac5814..4664992ae97ce5 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -33,6 +33,9 @@ hasfree = [] hasexc = [] + +ENABLE_SPECIALIZATION = True + def is_pseudo(op): return op >= MIN_PSEUDO_OPCODE and op <= MAX_PSEUDO_OPCODE diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ff736f1c2db8e2..37f90cfed2122d 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -6,6 +6,7 @@ import contextlib import functools import getpass +import opcode import os import re import stat @@ -46,7 +47,7 @@ "anticipate_failure", "load_package_tests", "detect_api_mismatch", "check__all__", "skip_if_buggy_ucrt_strfptime", "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", - "requires_limited_api", + "requires_limited_api", "requires_specialization", # sys "is_jython", "is_android", "is_emscripten", "is_wasi", "check_impl_detail", "unix_shell", "setswitchinterval", @@ -1077,6 +1078,8 @@ def requires_limited_api(test): return unittest.skipUnless( _testcapi.LIMITED_API_AVAILABLE, 'needs Limited API support')(test) +def requires_specialization(test): + return unittest.skipUnless(opcode.ENABLE_SPECIALIZATION, "requires specialization") def _filter_suite(suite, pred): """Recursively filter test cases in a suite based on a predicate.""" diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 950af3ceb24fea..13cc9a0bdfd360 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -7,7 +7,8 @@ import sys import types import unittest -from test.support import captured_stdout, requires_debug_ranges, cpython_only +from test.support import (captured_stdout, requires_debug_ranges, + requires_specialization, cpython_only) from test.support.bytecode_helper import BytecodeTestCase import opcode @@ -1086,12 +1087,14 @@ def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY): f() @cpython_only + @requires_specialization def test_super_instructions(self): self.code_quicken(lambda: load_test(0, 0)) got = self.get_disassembly(load_test, adaptive=True) self.do_disassembly_compare(got, dis_load_test_quickened_code, True) @cpython_only + @requires_specialization def test_binary_specialize(self): binary_op_quicken = """\ 0 0 RESUME 0 @@ -1130,6 +1133,7 @@ def test_binary_specialize(self): self.do_disassembly_compare(got, binary_subscr_quicken % "BINARY_SUBSCR_DICT", True) @cpython_only + @requires_specialization def test_load_attr_specialize(self): load_attr_quicken = """\ 0 0 RESUME 0 @@ -1144,6 +1148,7 @@ def test_load_attr_specialize(self): self.do_disassembly_compare(got, load_attr_quicken, True) @cpython_only + @requires_specialization def test_call_specialize(self): call_quicken = """\ 0 RESUME 0 @@ -1160,6 +1165,7 @@ def test_call_specialize(self): self.do_disassembly_compare(got, call_quicken) @cpython_only + @requires_specialization def test_loop_quicken(self): # Loop can trigger a quicken where the loop is located self.code_quicken(loop_test, 1) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 2dda7ccf7bf80c..da398187a43817 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -2,6 +2,7 @@ from test import support from test.support import import_helper from test.support import os_helper +from test.support import requires_specialization import unittest from collections import namedtuple @@ -346,6 +347,7 @@ def test_simple_initialization_api(self): out, err = self.run_embedded_interpreter("test_repeated_simple_init") self.assertEqual(out, 'Finalized\n' * INIT_LOOPS) + @requires_specialization def test_specialized_static_code_gets_unspecialized_at_Py_FINALIZE(self): # https://github.com/python/cpython/issues/92031 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e1c73ab6b32fbf..00d1744ed2ec6a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -343,6 +343,7 @@ dummy_func( }; inst(BINARY_SUBSCR, (unused/4, container, sub -- res)) { + #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -352,6 +353,7 @@ dummy_func( } STAT_INC(BINARY_SUBSCR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); DECREF_INPUTS(); ERROR_IF(res == NULL, error); @@ -487,6 +489,7 @@ dummy_func( }; inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) { + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); next_instr--; @@ -496,6 +499,9 @@ dummy_func( STAT_INC(STORE_SUBSCR, deferred); _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + assert(counter >= 0); /* prevent compiler warning */ + #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); DECREF_INPUTS(); @@ -975,6 +981,7 @@ dummy_func( // stack effect: (__0 -- __array[oparg]) inst(UNPACK_SEQUENCE) { + #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -985,6 +992,7 @@ dummy_func( } STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ PyObject *seq = POP(); PyObject **top = stack_pointer + oparg; if (!unpack_iterable(tstate, seq, oparg, -1, top)) { @@ -1059,6 +1067,7 @@ dummy_func( }; inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) { + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); PyObject *name = GETITEM(names, oparg); @@ -1069,6 +1078,9 @@ dummy_func( STAT_INC(STORE_ATTR, deferred); _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + assert(counter >= 0); /* prevent compiler warning */ + #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(names, oparg); int err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); @@ -1167,6 +1179,7 @@ dummy_func( // error: LOAD_GLOBAL has irregular stack effect inst(LOAD_GLOBAL) { + #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1177,6 +1190,7 @@ dummy_func( } STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int push_null = oparg & 1; PEEK(0) = NULL; PyObject *name = GETITEM(names, oparg>>1); @@ -1572,6 +1586,7 @@ dummy_func( // error: LOAD_ATTR has irregular stack effect inst(LOAD_ATTR) { + #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1583,6 +1598,7 @@ dummy_func( } STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(names, oparg >> 1); PyObject *owner = TOP(); if (oparg & 1) { @@ -1917,6 +1933,7 @@ dummy_func( }; inst(COMPARE_OP, (unused/2, left, right -- res)) { + #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1926,6 +1943,7 @@ dummy_func( } STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ assert(oparg <= Py_GE); res = PyObject_RichCompare(left, right, oparg); Py_DECREF(left); @@ -2347,6 +2365,7 @@ dummy_func( // stack effect: ( -- __0) inst(FOR_ITER) { + #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -2356,6 +2375,7 @@ dummy_func( } STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ /* before: [iter]; after: [iter, iter()] *or* [] */ PyObject *iter = TOP(); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); @@ -2698,6 +2718,7 @@ dummy_func( // stack effect: (__0, __array[oparg] -- ) inst(CALL) { + #if ENABLE_SPECIALIZATION _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -2710,6 +2731,7 @@ dummy_func( } STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int total_args, is_meth; is_meth = is_method(stack_pointer, oparg); PyObject *function = PEEK(oparg + 1); @@ -3448,6 +3470,7 @@ dummy_func( } inst(BINARY_OP, (unused/1, lhs, rhs -- res)) { + #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -3457,6 +3480,7 @@ dummy_func( } STAT_INC(BINARY_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ assert(0 <= oparg); assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1179bdfc696c62..4c20d86cdb938f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -420,6 +420,7 @@ PyObject *sub = PEEK(1); PyObject *container = PEEK(2); PyObject *res; + #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -429,6 +430,7 @@ } STAT_INC(BINARY_SUBSCR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); Py_DECREF(container); Py_DECREF(sub); @@ -611,6 +613,7 @@ PyObject *container = PEEK(2); PyObject *v = PEEK(3); uint16_t counter = read_u16(&next_instr[0].cache); + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); next_instr--; @@ -620,6 +623,9 @@ STAT_INC(STORE_SUBSCR, deferred); _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + assert(counter >= 0); /* prevent compiler warning */ + #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); Py_DECREF(v); @@ -1166,6 +1172,7 @@ TARGET(UNPACK_SEQUENCE) { PREDICTED(UNPACK_SEQUENCE); + #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1176,6 +1183,7 @@ } STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ PyObject *seq = POP(); PyObject **top = stack_pointer + oparg; if (!unpack_iterable(tstate, seq, oparg, -1, top)) { @@ -1248,6 +1256,7 @@ PyObject *owner = PEEK(1); PyObject *v = PEEK(2); uint16_t counter = read_u16(&next_instr[0].cache); + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); PyObject *name = GETITEM(names, oparg); @@ -1258,6 +1267,9 @@ STAT_INC(STORE_ATTR, deferred); _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + assert(counter >= 0); /* prevent compiler warning */ + #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(names, oparg); int err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); @@ -1370,6 +1382,7 @@ TARGET(LOAD_GLOBAL) { PREDICTED(LOAD_GLOBAL); + #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1380,6 +1393,7 @@ } STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int push_null = oparg & 1; PEEK(0) = NULL; PyObject *name = GETITEM(names, oparg>>1); @@ -1812,6 +1826,7 @@ TARGET(LOAD_ATTR) { PREDICTED(LOAD_ATTR); + #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1823,6 +1838,7 @@ } STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(names, oparg >> 1); PyObject *owner = TOP(); if (oparg & 1) { @@ -2174,6 +2190,7 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *res; + #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -2183,6 +2200,7 @@ } STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ assert(oparg <= Py_GE); res = PyObject_RichCompare(left, right, oparg); Py_DECREF(left); @@ -2695,6 +2713,7 @@ TARGET(FOR_ITER) { PREDICTED(FOR_ITER); + #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -2704,6 +2723,7 @@ } STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ /* before: [iter]; after: [iter, iter()] *or* [] */ PyObject *iter = TOP(); PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); @@ -3052,6 +3072,7 @@ TARGET(CALL) { PREDICTED(CALL); + #if ENABLE_SPECIALIZATION _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -3064,6 +3085,7 @@ } STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int total_args, is_meth; is_meth = is_method(stack_pointer, oparg); PyObject *function = PEEK(oparg + 1); @@ -3807,6 +3829,7 @@ PyObject *rhs = PEEK(1); PyObject *lhs = PEEK(2); PyObject *res; + #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -3816,6 +3839,7 @@ } STAT_INC(BINARY_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ assert(0 <= oparg); assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); diff --git a/Python/specialize.c b/Python/specialize.c index d9af7b742d54c2..59626dad048165 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -266,6 +266,7 @@ do { \ void _PyCode_Quicken(PyCodeObject *code) { + #if ENABLE_SPECIALIZATION int previous_opcode = 0; _Py_CODEUNIT *instructions = _PyCode_CODE(code); for (int i = 0; i < Py_SIZE(code); i++) { @@ -296,6 +297,7 @@ _PyCode_Quicken(PyCodeObject *code) } previous_opcode = opcode; } + #endif /* ENABLE_SPECIALIZATION */ } #define SIMPLE_FUNCTION 0 @@ -681,6 +683,7 @@ static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyOb void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR); _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyTypeObject *type = Py_TYPE(owner); @@ -853,6 +856,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR); _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyTypeObject *type = Py_TYPE(owner); @@ -1125,6 +1129,7 @@ _Py_Specialize_LoadGlobal( PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_GLOBAL] == INLINE_CACHE_ENTRIES_LOAD_GLOBAL); /* Use inline cache */ _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)(instr + 1); @@ -1296,6 +1301,7 @@ void _Py_Specialize_BinarySubscr( PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[BINARY_SUBSCR] == INLINE_CACHE_ENTRIES_BINARY_SUBSCR); _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)(instr + 1); @@ -1378,6 +1384,7 @@ _Py_Specialize_BinarySubscr( void _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) { + assert(ENABLE_SPECIALIZATION); _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)(instr + 1); PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { @@ -1757,6 +1764,7 @@ void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL); _PyCallCache *cache = (_PyCallCache *)(instr + 1); int fail; @@ -1875,6 +1883,7 @@ void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg, PyObject **locals) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP); _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1); switch (oparg) { @@ -1996,6 +2005,7 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); int next_opcode = _Py_OPCODE(instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1]); @@ -2071,6 +2081,7 @@ unpack_sequence_fail_kind(PyObject *seq) void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[UNPACK_SEQUENCE] == INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)(instr + 1); @@ -2180,6 +2191,7 @@ int void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) { + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); _PyForIterCache *cache = (_PyForIterCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(iter); diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 174573a3c64b08..9b2112f7f5f31d 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -85,6 +85,7 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna is_pseudo = opcode['is_pseudo'] _pseudo_ops = opcode['_pseudo_ops'] + ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"] HAVE_ARGUMENT = opcode["HAVE_ARGUMENT"] MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"] MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"] @@ -171,6 +172,10 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna for i, (op, _) in enumerate(opcode["_nb_ops"]): fobj.write(DEFINE.format(op, i)) + fobj.write("\n") + fobj.write("/* Defined in Lib/opcode.py */\n") + fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}") + iobj.write("\n") iobj.write("#ifdef Py_DEBUG\n") iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") From fdd0f98907bcdc9d83864d8e68b33cc3cd9019fb Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 14:33:26 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2023-01-03-14-33-23.gh-issue-100712.po6xyB.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-03-14-33-23.gh-issue-100712.po6xyB.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-03-14-33-23.gh-issue-100712.po6xyB.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-14-33-23.gh-issue-100712.po6xyB.rst new file mode 100644 index 00000000000000..3ebee0dd2aa48f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-03-14-33-23.gh-issue-100712.po6xyB.rst @@ -0,0 +1 @@ +Added option to build cpython with specialization disabled, by setting ``ENABLE_SPECIALIZATION=False`` in :mod:`opcode`, followed by ``make regen-all``. From afb1e9bbbed40fdcfd2595e500979f621135320e Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 18 Jan 2023 19:26:49 +0000 Subject: [PATCH 3/5] fix merge error --- Python/bytecodes.c | 2 ++ Python/generated_cases.c.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index be0ba0039e5c18..0e0db419358810 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1794,6 +1794,7 @@ dummy_func( }; inst(COMPARE_AND_BRANCH, (unused/2, left, right -- )) { + #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -1803,6 +1804,7 @@ dummy_func( } STAT_INC(COMPARE_AND_BRANCH, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); Py_DECREF(left); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index cd9cb408975694..53182c016cf905 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2120,6 +2120,7 @@ PREDICTED(COMPARE_AND_BRANCH); PyObject *right = PEEK(1); PyObject *left = PEEK(2); + #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); @@ -2129,6 +2130,7 @@ } STAT_INC(COMPARE_AND_BRANCH, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); Py_DECREF(left); From ee42c4ce7b6c5e5010e363c62773c2be11aa33ad Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Wed, 18 Jan 2023 20:47:53 +0000 Subject: [PATCH 4/5] one more merge error --- Lib/test/test_compile.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 1606c9cfda3239..05a5ed1fa9a637 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -10,7 +10,8 @@ import textwrap import warnings from test import support -from test.support import script_helper, requires_debug_ranges +from test.support import (script_helper, requires_debug_ranges, + requires_specialization) from test.support.os_helper import FakePath @@ -1251,6 +1252,7 @@ def test_multiline_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'CALL', line=1, end_line=3, column=0, end_column=1) + @requires_specialization def test_multiline_boolean_expression(self): snippet = """\ if (a or From 3856b2334a8b78a0854b18b044939fc1e5838cf6 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Thu, 19 Jan 2023 10:09:14 +0000 Subject: [PATCH 5/5] assert(counter >= 0); --> (void)counter; --- Python/bytecodes.c | 4 ++-- Python/generated_cases.c.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0e0db419358810..6088fa45ac64d2 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -454,7 +454,7 @@ dummy_func( _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else - assert(counter >= 0); /* prevent compiler warning */ + (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); @@ -976,7 +976,7 @@ dummy_func( _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else - assert(counter >= 0); /* prevent compiler warning */ + (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(names, oparg); int err = PyObject_SetAttr(owner, name, v); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 53182c016cf905..46d421f98ac7ef 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -611,7 +611,7 @@ _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else - assert(counter >= 0); /* prevent compiler warning */ + (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); @@ -1194,7 +1194,7 @@ _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); #else - assert(counter >= 0); /* prevent compiler warning */ + (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(names, oparg); int err = PyObject_SetAttr(owner, name, v);