diff --git a/Include/cpython/compile.h b/Include/cpython/compile.h index e6cd39af2ba739..581fcb5128991c 100644 --- a/Include/cpython/compile.h +++ b/Include/cpython/compile.h @@ -76,6 +76,7 @@ PyAPI_FUNC(int) PyUnstable_OpcodeHasJump(int opcode); PyAPI_FUNC(int) PyUnstable_OpcodeHasFree(int opcode); PyAPI_FUNC(int) PyUnstable_OpcodeHasLocal(int opcode); PyAPI_FUNC(int) PyUnstable_OpcodeHasExc(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeIsInstrumented(int opcode); PyAPI_FUNC(PyObject*) _PyUnstable_GetUnaryIntrinsicName(int index); PyAPI_FUNC(PyObject*) _PyUnstable_GetBinaryIntrinsicName(int index); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index d525913f8a7aba..2c005921cc65ba 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -949,7 +949,8 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define IS_VALID_OPCODE(OP) \ (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \ - (_PyOpcode_opcode_metadata[(OP)].valid_entry)) + (_PyOpcode_opcode_metadata[(OP)].valid_entry)) || \ + ((OP) == INSTRUMENTED_LINE) #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) @@ -957,12 +958,14 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define HAS_JUMP_FLAG (8) #define HAS_FREE_FLAG (16) #define HAS_LOCAL_FLAG (32) +#define IS_INSTRUMENTED_FLAG (64) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) #define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_JUMP_FLAG)) #define OPCODE_HAS_FREE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_FREE_FLAG)) #define OPCODE_HAS_LOCAL(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_LOCAL_FLAG)) +#define OPCODE_IS_INSTRUMENTED(OP) (_PyOpcode_opcode_metadata[OP].flags & (IS_INSTRUMENTED_FLAG)) || ((OP) == INSTRUMENTED_LINE) struct opcode_metadata { bool valid_entry; @@ -998,7 +1001,7 @@ extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]; const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [NOP] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, @@ -1012,9 +1015,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [POP_TOP] = { true, INSTR_FMT_IX, 0 }, [PUSH_NULL] = { true, INSTR_FMT_IX, 0 }, [END_FOR] = { true, INSTR_FMT_IB, 0 }, - [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, IS_INSTRUMENTED_FLAG }, [END_SEND] = { true, INSTR_FMT_IX, 0 }, - [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, IS_INSTRUMENTED_FLAG }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, 0 }, [UNARY_NOT] = { true, INSTR_FMT_IX, 0 }, [TO_BOOL] = { true, INSTR_FMT_IXC00, 0 }, @@ -1051,15 +1054,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 }, [RETURN_VALUE] = { true, INSTR_FMT_IX, 0 }, - [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, IS_INSTRUMENTED_FLAG }, [RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG | IS_INSTRUMENTED_FLAG }, [GET_AITER] = { true, INSTR_FMT_IX, 0 }, [GET_ANEXT] = { true, INSTR_FMT_IX, 0 }, [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, - [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [POP_EXCEPT] = { true, INSTR_FMT_IX, 0 }, [RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1103,7 +1106,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [MAP_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, [LOAD_SUPER_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, [LOAD_ZERO_SUPER_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, @@ -1150,7 +1153,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [GET_ITER] = { true, INSTR_FMT_IX, 0 }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, 0 }, [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, @@ -1169,7 +1172,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, [KW_NAMES] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, @@ -1190,7 +1193,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, - [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, IS_INSTRUMENTED_FLAG }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [MAKE_FUNCTION] = { true, INSTR_FMT_IX, 0 }, [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1202,13 +1205,13 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, 0 }, - [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, IS_INSTRUMENTED_FLAG }, + [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, + [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | IS_INSTRUMENTED_FLAG }, [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [CACHE] = { true, INSTR_FMT_IX, 0 }, [RESERVED] = { true, INSTR_FMT_IX, 0 }, diff --git a/Include/opcode.h b/Include/opcode.h index 697520937d9055..84035cc21013ed 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -127,7 +127,6 @@ extern "C" { #define LOAD_FROM_DICT_OR_DEREF 176 #define SET_FUNCTION_ATTRIBUTE 177 #define ENTER_EXECUTOR 230 -#define MIN_INSTRUMENTED_OPCODE 237 #define INSTRUMENTED_LOAD_SUPER_ATTR 237 #define INSTRUMENTED_POP_JUMP_IF_NONE 238 #define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239 diff --git a/Lib/opcode.py b/Lib/opcode.py index 36831d8a122bff..8bef9d85bc66e9 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -192,7 +192,6 @@ def pseudo_op(name, op, real_ops): def_op('ENTER_EXECUTOR', 230) # Instrumented instructions -MIN_INSTRUMENTED_OPCODE = 237 def_op('INSTRUMENTED_LOAD_SUPER_ATTR', 237) def_op('INSTRUMENTED_POP_JUMP_IF_NONE', 238) diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index b3a9bcbe160453..b58d9df6ae6fa6 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -18,6 +18,7 @@ def test_invalid_opcodes(self): self.check_bool_function_result(_opcode.has_free, invalid, False) self.check_bool_function_result(_opcode.has_local, invalid, False) self.check_bool_function_result(_opcode.has_exc, invalid, False) + self.check_bool_function_result(_opcode.is_instrumented, invalid, False) def test_is_valid(self): names = [ @@ -57,7 +58,7 @@ def test_stack_effect(self): # All defined opcodes has_arg = dis.hasarg for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): - if code >= opcode.MIN_INSTRUMENTED_OPCODE: + if _opcode.is_instrumented(code): continue with self.subTest(opname=name): stack_effect(code) @@ -82,7 +83,7 @@ def test_stack_effect_jump(self): has_exc = dis.hasexc has_jump = dis.hasjabs + dis.hasjrel for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): - if code >= opcode.MIN_INSTRUMENTED_OPCODE: + if _opcode.is_instrumented(code): continue with self.subTest(opname=name): if code not in has_arg: diff --git a/Modules/_opcode.c b/Modules/_opcode.c index b8d95a048ec2c6..0fe37b99dac333 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -203,6 +203,24 @@ _opcode_has_exc_impl(PyObject *module, int opcode) PyUnstable_OpcodeHasExc(opcode); } +/*[clinic input] + +_opcode.is_instrumented -> bool + + opcode: int + +Return True if the opcode is instrumented, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_is_instrumented_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=dbfb4dce2bef87c8 input=f4bcce48607a9266]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeIsInstrumented(opcode); +} + + /*[clinic input] _opcode.get_specialization_stats @@ -286,6 +304,7 @@ opcode_functions[] = { _OPCODE_HAS_FREE_METHODDEF _OPCODE_HAS_LOCAL_METHODDEF _OPCODE_HAS_EXC_METHODDEF + _OPCODE_IS_INSTRUMENTED_METHODDEF _OPCODE_GET_SPECIALIZATION_STATS_METHODDEF _OPCODE_GET_INTRINSIC1_DESCS_METHODDEF _OPCODE_GET_INTRINSIC2_DESCS_METHODDEF diff --git a/Modules/clinic/_opcode.c.h b/Modules/clinic/_opcode.c.h index e1fc5ba17f7078..e92fdef53946b3 100644 --- a/Modules/clinic/_opcode.c.h +++ b/Modules/clinic/_opcode.c.h @@ -595,6 +595,69 @@ _opcode_has_exc(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObj return return_value; } +PyDoc_STRVAR(_opcode_is_instrumented__doc__, +"is_instrumented($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode is instrumented, False otherwise."); + +#define _OPCODE_IS_INSTRUMENTED_METHODDEF \ + {"is_instrumented", _PyCFunction_CAST(_opcode_is_instrumented), METH_FASTCALL|METH_KEYWORDS, _opcode_is_instrumented__doc__}, + +static int +_opcode_is_instrumented_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_is_instrumented(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_instrumented", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_is_instrumented_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_opcode_get_specialization_stats__doc__, "get_specialization_stats($module, /)\n" "--\n" @@ -648,4 +711,4 @@ _opcode_get_intrinsic2_descs(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _opcode_get_intrinsic2_descs_impl(module); } -/*[clinic end generated code: output=d85de5f2887b3661 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=eb9c9c199a7ad65d input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index b4e06e7cb14085..422d7269341013 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -915,6 +915,12 @@ PyUnstable_OpcodeHasExc(int opcode) return IS_BLOCK_PUSH_OPCODE(opcode); } +int +PyUnstable_OpcodeIsInstrumented(int opcode) +{ + return OPCODE_IS_INSTRUMENTED(opcode); +} + static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { diff --git a/Python/instrumentation.c b/Python/instrumentation.c index c3515d2c5a3ad9..ddf32b7e924c30 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -3,12 +3,13 @@ #include "pycore_frame.h" #include "pycore_interp.h" #include "pycore_long.h" -#include "pycore_modsupport.h" // _PyModule_CreateInitialized() +#include "pycore_modsupport.h" // _PyModule_CreateInitialized() #include "pycore_namespace.h" #include "pycore_object.h" #include "pycore_opcode.h" +#include "pycore_opcode_metadata.h" // OPCODE_IS_INSTRUMENTED #include "pycore_pyerrors.h" -#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_pystate.h" // _PyInterpreterState_GET() /* Uncomment this to dump debugging output when assertions fail */ // #define INSTRUMENT_DEBUG 1 @@ -130,7 +131,7 @@ is_instrumented(int opcode) { assert(opcode != 0); assert(opcode != RESERVED); - return opcode >= MIN_INSTRUMENTED_OPCODE; + return OPCODE_IS_INSTRUMENTED(opcode); } #ifndef NDEBUG diff --git a/Python/specialize.c b/Python/specialize.c index 1669ce17fc804e..9177e67e6f40a9 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -7,8 +7,9 @@ #include "pycore_long.h" #include "pycore_moduleobject.h" #include "pycore_object.h" -#include "pycore_opcode.h" // _PyOpcode_Caches -#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() +#include "pycore_opcode.h" // _PyOpcode_Caches +#include "pycore_opcode_metadata.h" // OPCODE_IS_INSTRUMENTED +#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include // rand() @@ -279,7 +280,7 @@ _PyCode_Quicken(PyCodeObject *code) _Py_CODEUNIT *instructions = _PyCode_CODE(code); for (int i = 0; i < Py_SIZE(code); i++) { opcode = _Py_GetBaseOpcode(code, i); - assert(opcode < MIN_INSTRUMENTED_OPCODE); + assert(!OPCODE_IS_INSTRUMENTED(opcode)); int caches = _PyOpcode_Caches[opcode]; if (caches) { instructions[i + 1].cache = adaptive_counter_warmup(); diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 179abcf989e9bf..2f5641d90b1872 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -76,7 +76,6 @@ def main(opcode_py, ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"] MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"] MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"] - MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"] NUM_OPCODES = len(opname) used = [ False ] * len(opname) @@ -103,8 +102,6 @@ def main(opcode_py, op = opmap[name] if op == MIN_PSEUDO_OPCODE: fobj.write(DEFINE.format("MIN_PSEUDO_OPCODE", MIN_PSEUDO_OPCODE)) - if op == MIN_INSTRUMENTED_OPCODE: - fobj.write(DEFINE.format("MIN_INSTRUMENTED_OPCODE", MIN_INSTRUMENTED_OPCODE)) fobj.write(DEFINE.format(name, op)) diff --git a/Tools/cases_generator/flags.py b/Tools/cases_generator/flags.py index 78acd93b73ac31..47195462da8f01 100644 --- a/Tools/cases_generator/flags.py +++ b/Tools/cases_generator/flags.py @@ -15,6 +15,7 @@ class InstructionFlags: HAS_JUMP_FLAG: bool HAS_FREE_FLAG: bool HAS_LOCAL_FLAG: bool + IS_INSTRUMENTED_FLAG: bool def __post_init__(self): self.bitmask = {name: (1 << i) for i, name in enumerate(self.names())} @@ -38,11 +39,12 @@ def fromInstruction(instr: parsing.Node): variable_used(instr, "GETLOCAL") or variable_used(instr, "SETLOCAL") ) and not has_free, + IS_INSTRUMENTED_FLAG=instr.name.startswith("INSTRUMENTED_"), ) @staticmethod def newEmpty(): - return InstructionFlags(False, False, False, False, False, False) + return InstructionFlags(False, False, False, False, False, False, False) def add(self, other: "InstructionFlags") -> None: for name, value in dataclasses.asdict(other).items(): @@ -68,9 +70,13 @@ def emit_macros(cls, out: Formatter): out.emit(f"#define {name} ({value})") for name, value in flags.bitmask.items(): + if name == 'IS_INSTRUMENTED_FLAG': + or_special_case = " || ((OP) == INSTRUMENTED_LINE)" + else: + or_special_case = "" out.emit( f"#define OPCODE_{name[:-len('_FLAG')]}(OP) " - f"(_PyOpcode_opcode_metadata[OP].flags & ({name}))" + f"(_PyOpcode_opcode_metadata[OP].flags & ({name})){or_special_case}" ) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 967e1e2f5b63bb..1c5c1463918601 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -283,7 +283,8 @@ def write_metadata(self, metadata_filename: str, pymetadata_filename: str) -> No self.out.emit( "#define IS_VALID_OPCODE(OP) \\\n" " (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \\\n" - " (_PyOpcode_opcode_metadata[(OP)].valid_entry))" + " (_PyOpcode_opcode_metadata[(OP)].valid_entry)) || \\\n" + " ((OP) == INSTRUMENTED_LINE)" # implemented in ceval.c, not bytecodes.c ) self.out.emit("")