mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Compare commits
1 Commits
2025-09-29
...
2025-10-06
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a6fda4daf |
343
Lib/_opcode_metadata.py
vendored
Normal file
343
Lib/_opcode_metadata.py
vendored
Normal file
@@ -0,0 +1,343 @@
|
||||
# This file is generated by Tools/cases_generator/py_metadata_generator.py
|
||||
# from:
|
||||
# Python/bytecodes.c
|
||||
# Do not edit!
|
||||
_specializations = {
|
||||
"RESUME": [
|
||||
"RESUME_CHECK",
|
||||
],
|
||||
"TO_BOOL": [
|
||||
"TO_BOOL_ALWAYS_TRUE",
|
||||
"TO_BOOL_BOOL",
|
||||
"TO_BOOL_INT",
|
||||
"TO_BOOL_LIST",
|
||||
"TO_BOOL_NONE",
|
||||
"TO_BOOL_STR",
|
||||
],
|
||||
"BINARY_OP": [
|
||||
"BINARY_OP_MULTIPLY_INT",
|
||||
"BINARY_OP_ADD_INT",
|
||||
"BINARY_OP_SUBTRACT_INT",
|
||||
"BINARY_OP_MULTIPLY_FLOAT",
|
||||
"BINARY_OP_ADD_FLOAT",
|
||||
"BINARY_OP_SUBTRACT_FLOAT",
|
||||
"BINARY_OP_ADD_UNICODE",
|
||||
"BINARY_OP_INPLACE_ADD_UNICODE",
|
||||
],
|
||||
"BINARY_SUBSCR": [
|
||||
"BINARY_SUBSCR_DICT",
|
||||
"BINARY_SUBSCR_GETITEM",
|
||||
"BINARY_SUBSCR_LIST_INT",
|
||||
"BINARY_SUBSCR_STR_INT",
|
||||
"BINARY_SUBSCR_TUPLE_INT",
|
||||
],
|
||||
"STORE_SUBSCR": [
|
||||
"STORE_SUBSCR_DICT",
|
||||
"STORE_SUBSCR_LIST_INT",
|
||||
],
|
||||
"SEND": [
|
||||
"SEND_GEN",
|
||||
],
|
||||
"UNPACK_SEQUENCE": [
|
||||
"UNPACK_SEQUENCE_TWO_TUPLE",
|
||||
"UNPACK_SEQUENCE_TUPLE",
|
||||
"UNPACK_SEQUENCE_LIST",
|
||||
],
|
||||
"STORE_ATTR": [
|
||||
"STORE_ATTR_INSTANCE_VALUE",
|
||||
"STORE_ATTR_SLOT",
|
||||
"STORE_ATTR_WITH_HINT",
|
||||
],
|
||||
"LOAD_GLOBAL": [
|
||||
"LOAD_GLOBAL_MODULE",
|
||||
"LOAD_GLOBAL_BUILTIN",
|
||||
],
|
||||
"LOAD_SUPER_ATTR": [
|
||||
"LOAD_SUPER_ATTR_ATTR",
|
||||
"LOAD_SUPER_ATTR_METHOD",
|
||||
],
|
||||
"LOAD_ATTR": [
|
||||
"LOAD_ATTR_INSTANCE_VALUE",
|
||||
"LOAD_ATTR_MODULE",
|
||||
"LOAD_ATTR_WITH_HINT",
|
||||
"LOAD_ATTR_SLOT",
|
||||
"LOAD_ATTR_CLASS",
|
||||
"LOAD_ATTR_PROPERTY",
|
||||
"LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
|
||||
"LOAD_ATTR_METHOD_WITH_VALUES",
|
||||
"LOAD_ATTR_METHOD_NO_DICT",
|
||||
"LOAD_ATTR_METHOD_LAZY_DICT",
|
||||
"LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
|
||||
"LOAD_ATTR_NONDESCRIPTOR_NO_DICT",
|
||||
],
|
||||
"COMPARE_OP": [
|
||||
"COMPARE_OP_FLOAT",
|
||||
"COMPARE_OP_INT",
|
||||
"COMPARE_OP_STR",
|
||||
],
|
||||
"CONTAINS_OP": [
|
||||
"CONTAINS_OP_SET",
|
||||
"CONTAINS_OP_DICT",
|
||||
],
|
||||
"FOR_ITER": [
|
||||
"FOR_ITER_LIST",
|
||||
"FOR_ITER_TUPLE",
|
||||
"FOR_ITER_RANGE",
|
||||
"FOR_ITER_GEN",
|
||||
],
|
||||
"CALL": [
|
||||
"CALL_BOUND_METHOD_EXACT_ARGS",
|
||||
"CALL_PY_EXACT_ARGS",
|
||||
"CALL_TYPE_1",
|
||||
"CALL_STR_1",
|
||||
"CALL_TUPLE_1",
|
||||
"CALL_BUILTIN_CLASS",
|
||||
"CALL_BUILTIN_O",
|
||||
"CALL_BUILTIN_FAST",
|
||||
"CALL_BUILTIN_FAST_WITH_KEYWORDS",
|
||||
"CALL_LEN",
|
||||
"CALL_ISINSTANCE",
|
||||
"CALL_LIST_APPEND",
|
||||
"CALL_METHOD_DESCRIPTOR_O",
|
||||
"CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
|
||||
"CALL_METHOD_DESCRIPTOR_NOARGS",
|
||||
"CALL_METHOD_DESCRIPTOR_FAST",
|
||||
"CALL_ALLOC_AND_ENTER_INIT",
|
||||
"CALL_PY_GENERAL",
|
||||
"CALL_BOUND_METHOD_GENERAL",
|
||||
"CALL_NON_PY_GENERAL",
|
||||
],
|
||||
}
|
||||
|
||||
_specialized_opmap = {
|
||||
'BINARY_OP_ADD_FLOAT': 150,
|
||||
'BINARY_OP_ADD_INT': 151,
|
||||
'BINARY_OP_ADD_UNICODE': 152,
|
||||
'BINARY_OP_INPLACE_ADD_UNICODE': 3,
|
||||
'BINARY_OP_MULTIPLY_FLOAT': 153,
|
||||
'BINARY_OP_MULTIPLY_INT': 154,
|
||||
'BINARY_OP_SUBTRACT_FLOAT': 155,
|
||||
'BINARY_OP_SUBTRACT_INT': 156,
|
||||
'BINARY_SUBSCR_DICT': 157,
|
||||
'BINARY_SUBSCR_GETITEM': 158,
|
||||
'BINARY_SUBSCR_LIST_INT': 159,
|
||||
'BINARY_SUBSCR_STR_INT': 160,
|
||||
'BINARY_SUBSCR_TUPLE_INT': 161,
|
||||
'CALL_ALLOC_AND_ENTER_INIT': 162,
|
||||
'CALL_BOUND_METHOD_EXACT_ARGS': 163,
|
||||
'CALL_BOUND_METHOD_GENERAL': 164,
|
||||
'CALL_BUILTIN_CLASS': 165,
|
||||
'CALL_BUILTIN_FAST': 166,
|
||||
'CALL_BUILTIN_FAST_WITH_KEYWORDS': 167,
|
||||
'CALL_BUILTIN_O': 168,
|
||||
'CALL_ISINSTANCE': 169,
|
||||
'CALL_LEN': 170,
|
||||
'CALL_LIST_APPEND': 171,
|
||||
'CALL_METHOD_DESCRIPTOR_FAST': 172,
|
||||
'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 173,
|
||||
'CALL_METHOD_DESCRIPTOR_NOARGS': 174,
|
||||
'CALL_METHOD_DESCRIPTOR_O': 175,
|
||||
'CALL_NON_PY_GENERAL': 176,
|
||||
'CALL_PY_EXACT_ARGS': 177,
|
||||
'CALL_PY_GENERAL': 178,
|
||||
'CALL_STR_1': 179,
|
||||
'CALL_TUPLE_1': 180,
|
||||
'CALL_TYPE_1': 181,
|
||||
'COMPARE_OP_FLOAT': 182,
|
||||
'COMPARE_OP_INT': 183,
|
||||
'COMPARE_OP_STR': 184,
|
||||
'CONTAINS_OP_DICT': 185,
|
||||
'CONTAINS_OP_SET': 186,
|
||||
'FOR_ITER_GEN': 187,
|
||||
'FOR_ITER_LIST': 188,
|
||||
'FOR_ITER_RANGE': 189,
|
||||
'FOR_ITER_TUPLE': 190,
|
||||
'LOAD_ATTR_CLASS': 191,
|
||||
'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 192,
|
||||
'LOAD_ATTR_INSTANCE_VALUE': 193,
|
||||
'LOAD_ATTR_METHOD_LAZY_DICT': 194,
|
||||
'LOAD_ATTR_METHOD_NO_DICT': 195,
|
||||
'LOAD_ATTR_METHOD_WITH_VALUES': 196,
|
||||
'LOAD_ATTR_MODULE': 197,
|
||||
'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 198,
|
||||
'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 199,
|
||||
'LOAD_ATTR_PROPERTY': 200,
|
||||
'LOAD_ATTR_SLOT': 201,
|
||||
'LOAD_ATTR_WITH_HINT': 202,
|
||||
'LOAD_GLOBAL_BUILTIN': 203,
|
||||
'LOAD_GLOBAL_MODULE': 204,
|
||||
'LOAD_SUPER_ATTR_ATTR': 205,
|
||||
'LOAD_SUPER_ATTR_METHOD': 206,
|
||||
'RESUME_CHECK': 207,
|
||||
'SEND_GEN': 208,
|
||||
'STORE_ATTR_INSTANCE_VALUE': 209,
|
||||
'STORE_ATTR_SLOT': 210,
|
||||
'STORE_ATTR_WITH_HINT': 211,
|
||||
'STORE_SUBSCR_DICT': 212,
|
||||
'STORE_SUBSCR_LIST_INT': 213,
|
||||
'TO_BOOL_ALWAYS_TRUE': 214,
|
||||
'TO_BOOL_BOOL': 215,
|
||||
'TO_BOOL_INT': 216,
|
||||
'TO_BOOL_LIST': 217,
|
||||
'TO_BOOL_NONE': 218,
|
||||
'TO_BOOL_STR': 219,
|
||||
'UNPACK_SEQUENCE_LIST': 220,
|
||||
'UNPACK_SEQUENCE_TUPLE': 221,
|
||||
'UNPACK_SEQUENCE_TWO_TUPLE': 222,
|
||||
}
|
||||
|
||||
opmap = {
|
||||
'CACHE': 0,
|
||||
'RESERVED': 17,
|
||||
'RESUME': 149,
|
||||
'INSTRUMENTED_LINE': 254,
|
||||
'BEFORE_ASYNC_WITH': 1,
|
||||
'BEFORE_WITH': 2,
|
||||
'BINARY_SLICE': 4,
|
||||
'BINARY_SUBSCR': 5,
|
||||
'CHECK_EG_MATCH': 6,
|
||||
'CHECK_EXC_MATCH': 7,
|
||||
'CLEANUP_THROW': 8,
|
||||
'DELETE_SUBSCR': 9,
|
||||
'END_ASYNC_FOR': 10,
|
||||
'END_FOR': 11,
|
||||
'END_SEND': 12,
|
||||
'EXIT_INIT_CHECK': 13,
|
||||
'FORMAT_SIMPLE': 14,
|
||||
'FORMAT_WITH_SPEC': 15,
|
||||
'GET_AITER': 16,
|
||||
'GET_ANEXT': 18,
|
||||
'GET_ITER': 19,
|
||||
'GET_LEN': 20,
|
||||
'GET_YIELD_FROM_ITER': 21,
|
||||
'INTERPRETER_EXIT': 22,
|
||||
'LOAD_ASSERTION_ERROR': 23,
|
||||
'LOAD_BUILD_CLASS': 24,
|
||||
'LOAD_LOCALS': 25,
|
||||
'MAKE_FUNCTION': 26,
|
||||
'MATCH_KEYS': 27,
|
||||
'MATCH_MAPPING': 28,
|
||||
'MATCH_SEQUENCE': 29,
|
||||
'NOP': 30,
|
||||
'POP_EXCEPT': 31,
|
||||
'POP_TOP': 32,
|
||||
'PUSH_EXC_INFO': 33,
|
||||
'PUSH_NULL': 34,
|
||||
'RETURN_GENERATOR': 35,
|
||||
'RETURN_VALUE': 36,
|
||||
'SETUP_ANNOTATIONS': 37,
|
||||
'STORE_SLICE': 38,
|
||||
'STORE_SUBSCR': 39,
|
||||
'TO_BOOL': 40,
|
||||
'UNARY_INVERT': 41,
|
||||
'UNARY_NEGATIVE': 42,
|
||||
'UNARY_NOT': 43,
|
||||
'WITH_EXCEPT_START': 44,
|
||||
'BINARY_OP': 45,
|
||||
'BUILD_CONST_KEY_MAP': 46,
|
||||
'BUILD_LIST': 47,
|
||||
'BUILD_MAP': 48,
|
||||
'BUILD_SET': 49,
|
||||
'BUILD_SLICE': 50,
|
||||
'BUILD_STRING': 51,
|
||||
'BUILD_TUPLE': 52,
|
||||
'CALL': 53,
|
||||
'CALL_FUNCTION_EX': 54,
|
||||
'CALL_INTRINSIC_1': 55,
|
||||
'CALL_INTRINSIC_2': 56,
|
||||
'CALL_KW': 57,
|
||||
'COMPARE_OP': 58,
|
||||
'CONTAINS_OP': 59,
|
||||
'CONVERT_VALUE': 60,
|
||||
'COPY': 61,
|
||||
'COPY_FREE_VARS': 62,
|
||||
'DELETE_ATTR': 63,
|
||||
'DELETE_DEREF': 64,
|
||||
'DELETE_FAST': 65,
|
||||
'DELETE_GLOBAL': 66,
|
||||
'DELETE_NAME': 67,
|
||||
'DICT_MERGE': 68,
|
||||
'DICT_UPDATE': 69,
|
||||
'ENTER_EXECUTOR': 70,
|
||||
'EXTENDED_ARG': 71,
|
||||
'FOR_ITER': 72,
|
||||
'GET_AWAITABLE': 73,
|
||||
'IMPORT_FROM': 74,
|
||||
'IMPORT_NAME': 75,
|
||||
'IS_OP': 76,
|
||||
'JUMP_BACKWARD': 77,
|
||||
'JUMP_BACKWARD_NO_INTERRUPT': 78,
|
||||
'JUMP_FORWARD': 79,
|
||||
'LIST_APPEND': 80,
|
||||
'LIST_EXTEND': 81,
|
||||
'LOAD_ATTR': 82,
|
||||
'LOAD_CONST': 83,
|
||||
'LOAD_DEREF': 84,
|
||||
'LOAD_FAST': 85,
|
||||
'LOAD_FAST_AND_CLEAR': 86,
|
||||
'LOAD_FAST_CHECK': 87,
|
||||
'LOAD_FAST_LOAD_FAST': 88,
|
||||
'LOAD_FROM_DICT_OR_DEREF': 89,
|
||||
'LOAD_FROM_DICT_OR_GLOBALS': 90,
|
||||
'LOAD_GLOBAL': 91,
|
||||
'LOAD_NAME': 92,
|
||||
'LOAD_SUPER_ATTR': 93,
|
||||
'MAKE_CELL': 94,
|
||||
'MAP_ADD': 95,
|
||||
'MATCH_CLASS': 96,
|
||||
'POP_JUMP_IF_FALSE': 97,
|
||||
'POP_JUMP_IF_NONE': 98,
|
||||
'POP_JUMP_IF_NOT_NONE': 99,
|
||||
'POP_JUMP_IF_TRUE': 100,
|
||||
'RAISE_VARARGS': 101,
|
||||
'RERAISE': 102,
|
||||
'RETURN_CONST': 103,
|
||||
'SEND': 104,
|
||||
'SET_ADD': 105,
|
||||
'SET_FUNCTION_ATTRIBUTE': 106,
|
||||
'SET_UPDATE': 107,
|
||||
'STORE_ATTR': 108,
|
||||
'STORE_DEREF': 109,
|
||||
'STORE_FAST': 110,
|
||||
'STORE_FAST_LOAD_FAST': 111,
|
||||
'STORE_FAST_STORE_FAST': 112,
|
||||
'STORE_GLOBAL': 113,
|
||||
'STORE_NAME': 114,
|
||||
'SWAP': 115,
|
||||
'UNPACK_EX': 116,
|
||||
'UNPACK_SEQUENCE': 117,
|
||||
'YIELD_VALUE': 118,
|
||||
'INSTRUMENTED_RESUME': 236,
|
||||
'INSTRUMENTED_END_FOR': 237,
|
||||
'INSTRUMENTED_END_SEND': 238,
|
||||
'INSTRUMENTED_RETURN_VALUE': 239,
|
||||
'INSTRUMENTED_RETURN_CONST': 240,
|
||||
'INSTRUMENTED_YIELD_VALUE': 241,
|
||||
'INSTRUMENTED_LOAD_SUPER_ATTR': 242,
|
||||
'INSTRUMENTED_FOR_ITER': 243,
|
||||
'INSTRUMENTED_CALL': 244,
|
||||
'INSTRUMENTED_CALL_KW': 245,
|
||||
'INSTRUMENTED_CALL_FUNCTION_EX': 246,
|
||||
'INSTRUMENTED_INSTRUCTION': 247,
|
||||
'INSTRUMENTED_JUMP_FORWARD': 248,
|
||||
'INSTRUMENTED_JUMP_BACKWARD': 249,
|
||||
'INSTRUMENTED_POP_JUMP_IF_TRUE': 250,
|
||||
'INSTRUMENTED_POP_JUMP_IF_FALSE': 251,
|
||||
'INSTRUMENTED_POP_JUMP_IF_NONE': 252,
|
||||
'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 253,
|
||||
'JUMP': 256,
|
||||
'JUMP_NO_INTERRUPT': 257,
|
||||
'LOAD_CLOSURE': 258,
|
||||
'LOAD_METHOD': 259,
|
||||
'LOAD_SUPER_METHOD': 260,
|
||||
'LOAD_ZERO_SUPER_ATTR': 261,
|
||||
'LOAD_ZERO_SUPER_METHOD': 262,
|
||||
'POP_BLOCK': 263,
|
||||
'SETUP_CLEANUP': 264,
|
||||
'SETUP_FINALLY': 265,
|
||||
'SETUP_WITH': 266,
|
||||
'STORE_FAST_MAYBE_NULL': 267,
|
||||
}
|
||||
|
||||
HAVE_ARGUMENT = 44
|
||||
MIN_INSTRUMENTED_OPCODE = 236
|
||||
449
Lib/opcode.py
vendored
449
Lib/opcode.py
vendored
@@ -4,404 +4,47 @@ opcode module - potentially shared between dis and other modules which
|
||||
operate on bytecodes (e.g. peephole optimizers).
|
||||
"""
|
||||
|
||||
__all__ = ["cmp_op", "hasarg", "hasconst", "hasname", "hasjrel", "hasjabs",
|
||||
"haslocal", "hascompare", "hasfree", "hasexc", "opname", "opmap",
|
||||
"HAVE_ARGUMENT", "EXTENDED_ARG"]
|
||||
|
||||
# It's a chicken-and-egg I'm afraid:
|
||||
# We're imported before _opcode's made.
|
||||
# With exception unheeded
|
||||
# (stack_effect is not needed)
|
||||
# Both our chickens and eggs are allayed.
|
||||
# --Larry Hastings, 2013/11/23
|
||||
__all__ = ["cmp_op", "stack_effect", "hascompare", "opname", "opmap",
|
||||
"HAVE_ARGUMENT", "EXTENDED_ARG", "hasarg", "hasconst", "hasname",
|
||||
"hasjump", "hasjrel", "hasjabs", "hasfree", "haslocal", "hasexc"]
|
||||
|
||||
try:
|
||||
from _opcode import stack_effect
|
||||
__all__.append('stack_effect')
|
||||
except ImportError:
|
||||
pass
|
||||
import _opcode
|
||||
from _opcode import stack_effect
|
||||
|
||||
cmp_op = ('<', '<=', '==', '!=', '>', '>=')
|
||||
from _opcode_metadata import (_specializations, _specialized_opmap, opmap,
|
||||
HAVE_ARGUMENT, MIN_INSTRUMENTED_OPCODE)
|
||||
EXTENDED_ARG = opmap['EXTENDED_ARG']
|
||||
|
||||
hasarg = []
|
||||
hasconst = []
|
||||
hasname = []
|
||||
hasjrel = []
|
||||
hasjabs = []
|
||||
haslocal = []
|
||||
hascompare = []
|
||||
hasfree = []
|
||||
hasexc = []
|
||||
|
||||
def is_pseudo(op):
|
||||
return op >= MIN_PSEUDO_OPCODE and op <= MAX_PSEUDO_OPCODE
|
||||
|
||||
oplists = [hasarg, hasconst, hasname, hasjrel, hasjabs,
|
||||
haslocal, hascompare, hasfree, hasexc]
|
||||
|
||||
opmap = {}
|
||||
|
||||
## pseudo opcodes (used in the compiler) mapped to the values
|
||||
##Â they can become in the actual code.
|
||||
_pseudo_ops = {}
|
||||
|
||||
def def_op(name, op):
|
||||
opmap[name] = op
|
||||
|
||||
def name_op(name, op):
|
||||
def_op(name, op)
|
||||
hasname.append(op)
|
||||
|
||||
def jrel_op(name, op):
|
||||
def_op(name, op)
|
||||
hasjrel.append(op)
|
||||
|
||||
def jabs_op(name, op):
|
||||
def_op(name, op)
|
||||
hasjabs.append(op)
|
||||
|
||||
def pseudo_op(name, op, real_ops):
|
||||
def_op(name, op)
|
||||
_pseudo_ops[name] = real_ops
|
||||
# add the pseudo opcode to the lists its targets are in
|
||||
for oplist in oplists:
|
||||
res = [opmap[rop] in oplist for rop in real_ops]
|
||||
if any(res):
|
||||
assert all(res)
|
||||
oplist.append(op)
|
||||
|
||||
|
||||
# Instruction opcodes for compiled code
|
||||
# Blank lines correspond to available opcodes
|
||||
|
||||
def_op('CACHE', 0)
|
||||
def_op('POP_TOP', 1)
|
||||
def_op('PUSH_NULL', 2)
|
||||
|
||||
def_op('NOP', 9)
|
||||
def_op('UNARY_POSITIVE', 10)
|
||||
def_op('UNARY_NEGATIVE', 11)
|
||||
def_op('UNARY_NOT', 12)
|
||||
|
||||
def_op('UNARY_INVERT', 15)
|
||||
|
||||
def_op('BINARY_SUBSCR', 25)
|
||||
def_op('BINARY_SLICE', 26)
|
||||
def_op('STORE_SLICE', 27)
|
||||
|
||||
def_op('GET_LEN', 30)
|
||||
def_op('MATCH_MAPPING', 31)
|
||||
def_op('MATCH_SEQUENCE', 32)
|
||||
def_op('MATCH_KEYS', 33)
|
||||
|
||||
def_op('PUSH_EXC_INFO', 35)
|
||||
def_op('CHECK_EXC_MATCH', 36)
|
||||
def_op('CHECK_EG_MATCH', 37)
|
||||
|
||||
def_op('WITH_EXCEPT_START', 49)
|
||||
def_op('GET_AITER', 50)
|
||||
def_op('GET_ANEXT', 51)
|
||||
def_op('BEFORE_ASYNC_WITH', 52)
|
||||
def_op('BEFORE_WITH', 53)
|
||||
def_op('END_ASYNC_FOR', 54)
|
||||
def_op('CLEANUP_THROW', 55)
|
||||
|
||||
def_op('STORE_SUBSCR', 60)
|
||||
def_op('DELETE_SUBSCR', 61)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
# Delete below def_op after updating coroutines.py
|
||||
def_op('YIELD_FROM', 72)
|
||||
|
||||
def_op('GET_ITER', 68)
|
||||
def_op('GET_YIELD_FROM_ITER', 69)
|
||||
def_op('PRINT_EXPR', 70)
|
||||
def_op('LOAD_BUILD_CLASS', 71)
|
||||
|
||||
def_op('LOAD_ASSERTION_ERROR', 74)
|
||||
def_op('RETURN_GENERATOR', 75)
|
||||
|
||||
def_op('LIST_TO_TUPLE', 82)
|
||||
def_op('RETURN_VALUE', 83)
|
||||
def_op('IMPORT_STAR', 84)
|
||||
def_op('SETUP_ANNOTATIONS', 85)
|
||||
|
||||
def_op('ASYNC_GEN_WRAP', 87)
|
||||
def_op('PREP_RERAISE_STAR', 88)
|
||||
def_op('POP_EXCEPT', 89)
|
||||
|
||||
HAVE_ARGUMENT = 90 # real opcodes from here have an argument:
|
||||
|
||||
name_op('STORE_NAME', 90) # Index in name list
|
||||
name_op('DELETE_NAME', 91) # ""
|
||||
def_op('UNPACK_SEQUENCE', 92) # Number of tuple items
|
||||
jrel_op('FOR_ITER', 93)
|
||||
def_op('UNPACK_EX', 94)
|
||||
name_op('STORE_ATTR', 95) # Index in name list
|
||||
name_op('DELETE_ATTR', 96) # ""
|
||||
name_op('STORE_GLOBAL', 97) # ""
|
||||
name_op('DELETE_GLOBAL', 98) # ""
|
||||
def_op('SWAP', 99)
|
||||
def_op('LOAD_CONST', 100) # Index in const list
|
||||
hasconst.append(100)
|
||||
name_op('LOAD_NAME', 101) # Index in name list
|
||||
def_op('BUILD_TUPLE', 102) # Number of tuple items
|
||||
def_op('BUILD_LIST', 103) # Number of list items
|
||||
def_op('BUILD_SET', 104) # Number of set items
|
||||
def_op('BUILD_MAP', 105) # Number of dict entries
|
||||
name_op('LOAD_ATTR', 106) # Index in name list
|
||||
def_op('COMPARE_OP', 107) # Comparison operator
|
||||
hascompare.append(107)
|
||||
name_op('IMPORT_NAME', 108) # Index in name list
|
||||
name_op('IMPORT_FROM', 109) # Index in name list
|
||||
jrel_op('JUMP_FORWARD', 110) # Number of words to skip
|
||||
jrel_op('JUMP_IF_FALSE_OR_POP', 111) # Number of words to skip
|
||||
jrel_op('JUMP_IF_TRUE_OR_POP', 112) # ""
|
||||
jrel_op('POP_JUMP_IF_FALSE', 114)
|
||||
jrel_op('POP_JUMP_IF_TRUE', 115)
|
||||
name_op('LOAD_GLOBAL', 116) # Index in name list
|
||||
def_op('IS_OP', 117)
|
||||
def_op('CONTAINS_OP', 118)
|
||||
def_op('RERAISE', 119)
|
||||
def_op('COPY', 120)
|
||||
def_op('BINARY_OP', 122)
|
||||
jrel_op('SEND', 123) # Number of bytes to skip
|
||||
def_op('LOAD_FAST', 124) # Local variable number, no null check
|
||||
haslocal.append(124)
|
||||
def_op('STORE_FAST', 125) # Local variable number
|
||||
haslocal.append(125)
|
||||
def_op('DELETE_FAST', 126) # Local variable number
|
||||
haslocal.append(126)
|
||||
def_op('LOAD_FAST_CHECK', 127) # Local variable number
|
||||
haslocal.append(127)
|
||||
jrel_op('POP_JUMP_IF_NOT_NONE', 128)
|
||||
jrel_op('POP_JUMP_IF_NONE', 129)
|
||||
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
|
||||
def_op('GET_AWAITABLE', 131)
|
||||
def_op('MAKE_FUNCTION', 132) # Flags
|
||||
def_op('BUILD_SLICE', 133) # Number of items
|
||||
jrel_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards)
|
||||
def_op('MAKE_CELL', 135)
|
||||
hasfree.append(135)
|
||||
def_op('LOAD_CLOSURE', 136)
|
||||
hasfree.append(136)
|
||||
def_op('LOAD_DEREF', 137)
|
||||
hasfree.append(137)
|
||||
def_op('STORE_DEREF', 138)
|
||||
hasfree.append(138)
|
||||
def_op('DELETE_DEREF', 139)
|
||||
hasfree.append(139)
|
||||
jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards)
|
||||
|
||||
def_op('CALL_FUNCTION_EX', 142) # Flags
|
||||
|
||||
def_op('EXTENDED_ARG', 144)
|
||||
EXTENDED_ARG = 144
|
||||
def_op('LIST_APPEND', 145)
|
||||
def_op('SET_ADD', 146)
|
||||
def_op('MAP_ADD', 147)
|
||||
def_op('LOAD_CLASSDEREF', 148)
|
||||
hasfree.append(148)
|
||||
def_op('COPY_FREE_VARS', 149)
|
||||
def_op('YIELD_VALUE', 150)
|
||||
def_op('RESUME', 151) # This must be kept in sync with deepfreeze.py
|
||||
def_op('MATCH_CLASS', 152)
|
||||
|
||||
def_op('FORMAT_VALUE', 155)
|
||||
def_op('BUILD_CONST_KEY_MAP', 156)
|
||||
def_op('BUILD_STRING', 157)
|
||||
|
||||
def_op('LIST_EXTEND', 162)
|
||||
def_op('SET_UPDATE', 163)
|
||||
def_op('DICT_MERGE', 164)
|
||||
def_op('DICT_UPDATE', 165)
|
||||
|
||||
def_op('CALL', 171)
|
||||
def_op('KW_NAMES', 172)
|
||||
hasconst.append(172)
|
||||
|
||||
|
||||
hasarg.extend([op for op in opmap.values() if op >= HAVE_ARGUMENT])
|
||||
|
||||
MIN_PSEUDO_OPCODE = 256
|
||||
|
||||
pseudo_op('SETUP_FINALLY', 256, ['NOP'])
|
||||
hasexc.append(256)
|
||||
pseudo_op('SETUP_CLEANUP', 257, ['NOP'])
|
||||
hasexc.append(257)
|
||||
pseudo_op('SETUP_WITH', 258, ['NOP'])
|
||||
hasexc.append(258)
|
||||
pseudo_op('POP_BLOCK', 259, ['NOP'])
|
||||
|
||||
pseudo_op('JUMP', 260, ['JUMP_FORWARD', 'JUMP_BACKWARD'])
|
||||
pseudo_op('JUMP_NO_INTERRUPT', 261, ['JUMP_FORWARD', 'JUMP_BACKWARD_NO_INTERRUPT'])
|
||||
|
||||
pseudo_op('LOAD_METHOD', 262, ['LOAD_ATTR'])
|
||||
|
||||
MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1
|
||||
|
||||
del def_op, name_op, jrel_op, jabs_op, pseudo_op
|
||||
|
||||
opname = ['<%r>' % (op,) for op in range(MAX_PSEUDO_OPCODE + 1)]
|
||||
opname = ['<%r>' % (op,) for op in range(max(opmap.values()) + 1)]
|
||||
for op, i in opmap.items():
|
||||
opname[i] = op
|
||||
|
||||
cmp_op = ('<', '<=', '==', '!=', '>', '>=')
|
||||
|
||||
_nb_ops = [
|
||||
("NB_ADD", "+"),
|
||||
("NB_AND", "&"),
|
||||
("NB_FLOOR_DIVIDE", "//"),
|
||||
("NB_LSHIFT", "<<"),
|
||||
("NB_MATRIX_MULTIPLY", "@"),
|
||||
("NB_MULTIPLY", "*"),
|
||||
("NB_REMAINDER", "%"),
|
||||
("NB_OR", "|"),
|
||||
("NB_POWER", "**"),
|
||||
("NB_RSHIFT", ">>"),
|
||||
("NB_SUBTRACT", "-"),
|
||||
("NB_TRUE_DIVIDE", "/"),
|
||||
("NB_XOR", "^"),
|
||||
("NB_INPLACE_ADD", "+="),
|
||||
("NB_INPLACE_AND", "&="),
|
||||
("NB_INPLACE_FLOOR_DIVIDE", "//="),
|
||||
("NB_INPLACE_LSHIFT", "<<="),
|
||||
("NB_INPLACE_MATRIX_MULTIPLY", "@="),
|
||||
("NB_INPLACE_MULTIPLY", "*="),
|
||||
("NB_INPLACE_REMAINDER", "%="),
|
||||
("NB_INPLACE_OR", "|="),
|
||||
("NB_INPLACE_POWER", "**="),
|
||||
("NB_INPLACE_RSHIFT", ">>="),
|
||||
("NB_INPLACE_SUBTRACT", "-="),
|
||||
("NB_INPLACE_TRUE_DIVIDE", "/="),
|
||||
("NB_INPLACE_XOR", "^="),
|
||||
]
|
||||
# These lists are documented as part of the dis module's API
|
||||
hasarg = [op for op in opmap.values() if _opcode.has_arg(op)]
|
||||
hasconst = [op for op in opmap.values() if _opcode.has_const(op)]
|
||||
hasname = [op for op in opmap.values() if _opcode.has_name(op)]
|
||||
hasjump = [op for op in opmap.values() if _opcode.has_jump(op)]
|
||||
hasjrel = hasjump # for backward compatibility
|
||||
hasjabs = []
|
||||
hasfree = [op for op in opmap.values() if _opcode.has_free(op)]
|
||||
haslocal = [op for op in opmap.values() if _opcode.has_local(op)]
|
||||
hasexc = [op for op in opmap.values() if _opcode.has_exc(op)]
|
||||
|
||||
_specializations = {
|
||||
"BINARY_OP": [
|
||||
"BINARY_OP_ADAPTIVE",
|
||||
"BINARY_OP_ADD_FLOAT",
|
||||
"BINARY_OP_ADD_INT",
|
||||
"BINARY_OP_ADD_UNICODE",
|
||||
"BINARY_OP_INPLACE_ADD_UNICODE",
|
||||
"BINARY_OP_MULTIPLY_FLOAT",
|
||||
"BINARY_OP_MULTIPLY_INT",
|
||||
"BINARY_OP_SUBTRACT_FLOAT",
|
||||
"BINARY_OP_SUBTRACT_INT",
|
||||
],
|
||||
"BINARY_SUBSCR": [
|
||||
"BINARY_SUBSCR_ADAPTIVE",
|
||||
"BINARY_SUBSCR_DICT",
|
||||
"BINARY_SUBSCR_GETITEM",
|
||||
"BINARY_SUBSCR_LIST_INT",
|
||||
"BINARY_SUBSCR_TUPLE_INT",
|
||||
],
|
||||
"CALL": [
|
||||
"CALL_ADAPTIVE",
|
||||
"CALL_PY_EXACT_ARGS",
|
||||
"CALL_PY_WITH_DEFAULTS",
|
||||
"CALL_BOUND_METHOD_EXACT_ARGS",
|
||||
"CALL_BUILTIN_CLASS",
|
||||
"CALL_BUILTIN_FAST_WITH_KEYWORDS",
|
||||
"CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
|
||||
"CALL_NO_KW_BUILTIN_FAST",
|
||||
"CALL_NO_KW_BUILTIN_O",
|
||||
"CALL_NO_KW_ISINSTANCE",
|
||||
"CALL_NO_KW_LEN",
|
||||
"CALL_NO_KW_LIST_APPEND",
|
||||
"CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
|
||||
"CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS",
|
||||
"CALL_NO_KW_METHOD_DESCRIPTOR_O",
|
||||
"CALL_NO_KW_STR_1",
|
||||
"CALL_NO_KW_TUPLE_1",
|
||||
"CALL_NO_KW_TYPE_1",
|
||||
],
|
||||
"COMPARE_OP": [
|
||||
"COMPARE_OP_ADAPTIVE",
|
||||
"COMPARE_OP_FLOAT_JUMP",
|
||||
"COMPARE_OP_INT_JUMP",
|
||||
"COMPARE_OP_STR_JUMP",
|
||||
],
|
||||
"EXTENDED_ARG": [
|
||||
"EXTENDED_ARG_QUICK",
|
||||
],
|
||||
"FOR_ITER": [
|
||||
"FOR_ITER_ADAPTIVE",
|
||||
"FOR_ITER_LIST",
|
||||
"FOR_ITER_RANGE",
|
||||
],
|
||||
"JUMP_BACKWARD": [
|
||||
"JUMP_BACKWARD_QUICK",
|
||||
],
|
||||
"LOAD_ATTR": [
|
||||
"LOAD_ATTR_ADAPTIVE",
|
||||
# These potentially push [NULL, bound method] onto the stack.
|
||||
"LOAD_ATTR_CLASS",
|
||||
"LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
|
||||
"LOAD_ATTR_INSTANCE_VALUE",
|
||||
"LOAD_ATTR_MODULE",
|
||||
"LOAD_ATTR_PROPERTY",
|
||||
"LOAD_ATTR_SLOT",
|
||||
"LOAD_ATTR_WITH_HINT",
|
||||
# These will always push [unbound method, self] onto the stack.
|
||||
"LOAD_ATTR_METHOD_LAZY_DICT",
|
||||
"LOAD_ATTR_METHOD_NO_DICT",
|
||||
"LOAD_ATTR_METHOD_WITH_DICT",
|
||||
"LOAD_ATTR_METHOD_WITH_VALUES",
|
||||
],
|
||||
"LOAD_CONST": [
|
||||
"LOAD_CONST__LOAD_FAST",
|
||||
],
|
||||
"LOAD_FAST": [
|
||||
"LOAD_FAST__LOAD_CONST",
|
||||
"LOAD_FAST__LOAD_FAST",
|
||||
],
|
||||
"LOAD_GLOBAL": [
|
||||
"LOAD_GLOBAL_ADAPTIVE",
|
||||
"LOAD_GLOBAL_BUILTIN",
|
||||
"LOAD_GLOBAL_MODULE",
|
||||
],
|
||||
"RESUME": [
|
||||
"RESUME_QUICK",
|
||||
],
|
||||
"STORE_ATTR": [
|
||||
"STORE_ATTR_ADAPTIVE",
|
||||
"STORE_ATTR_INSTANCE_VALUE",
|
||||
"STORE_ATTR_SLOT",
|
||||
"STORE_ATTR_WITH_HINT",
|
||||
],
|
||||
"STORE_FAST": [
|
||||
"STORE_FAST__LOAD_FAST",
|
||||
"STORE_FAST__STORE_FAST",
|
||||
],
|
||||
"STORE_SUBSCR": [
|
||||
"STORE_SUBSCR_ADAPTIVE",
|
||||
"STORE_SUBSCR_DICT",
|
||||
"STORE_SUBSCR_LIST_INT",
|
||||
],
|
||||
"UNPACK_SEQUENCE": [
|
||||
"UNPACK_SEQUENCE_ADAPTIVE",
|
||||
"UNPACK_SEQUENCE_LIST",
|
||||
"UNPACK_SEQUENCE_TUPLE",
|
||||
"UNPACK_SEQUENCE_TWO_TUPLE",
|
||||
],
|
||||
}
|
||||
_specialized_instructions = [
|
||||
opcode for family in _specializations.values() for opcode in family
|
||||
]
|
||||
_specialization_stats = [
|
||||
"success",
|
||||
"failure",
|
||||
"hit",
|
||||
"deferred",
|
||||
"miss",
|
||||
"deopt",
|
||||
]
|
||||
|
||||
_intrinsic_1_descs = _opcode.get_intrinsic1_descs()
|
||||
_intrinsic_2_descs = _opcode.get_intrinsic2_descs()
|
||||
_nb_ops = _opcode.get_nb_ops()
|
||||
|
||||
hascompare = [opmap["COMPARE_OP"]]
|
||||
|
||||
_cache_format = {
|
||||
"LOAD_GLOBAL": {
|
||||
"counter": 1,
|
||||
"index": 1,
|
||||
"module_keys_version": 2,
|
||||
"module_keys_version": 1,
|
||||
"builtin_keys_version": 1,
|
||||
},
|
||||
"BINARY_OP": {
|
||||
@@ -412,16 +55,19 @@ _cache_format = {
|
||||
},
|
||||
"COMPARE_OP": {
|
||||
"counter": 1,
|
||||
"mask": 1,
|
||||
},
|
||||
"CONTAINS_OP": {
|
||||
"counter": 1,
|
||||
},
|
||||
"BINARY_SUBSCR": {
|
||||
"counter": 1,
|
||||
"type_version": 2,
|
||||
"func_version": 1,
|
||||
},
|
||||
"FOR_ITER": {
|
||||
"counter": 1,
|
||||
},
|
||||
"LOAD_SUPER_ATTR": {
|
||||
"counter": 1,
|
||||
},
|
||||
"LOAD_ATTR": {
|
||||
"counter": 1,
|
||||
"version": 2,
|
||||
@@ -436,13 +82,34 @@ _cache_format = {
|
||||
"CALL": {
|
||||
"counter": 1,
|
||||
"func_version": 2,
|
||||
"min_args": 1,
|
||||
},
|
||||
"STORE_SUBSCR": {
|
||||
"counter": 1,
|
||||
},
|
||||
"SEND": {
|
||||
"counter": 1,
|
||||
},
|
||||
"JUMP_BACKWARD": {
|
||||
"counter": 1,
|
||||
},
|
||||
"TO_BOOL": {
|
||||
"counter": 1,
|
||||
"version": 2,
|
||||
},
|
||||
"POP_JUMP_IF_TRUE": {
|
||||
"counter": 1,
|
||||
},
|
||||
"POP_JUMP_IF_FALSE": {
|
||||
"counter": 1,
|
||||
},
|
||||
"POP_JUMP_IF_NONE": {
|
||||
"counter": 1,
|
||||
},
|
||||
"POP_JUMP_IF_NOT_NONE": {
|
||||
"counter": 1,
|
||||
},
|
||||
}
|
||||
|
||||
_inline_cache_entries = [
|
||||
sum(_cache_format.get(opname[opcode], {}).values()) for opcode in range(256)
|
||||
]
|
||||
_inline_cache_entries = {
|
||||
name : sum(value.values()) for (name, value) in _cache_format.items()
|
||||
}
|
||||
|
||||
2
Lib/test/support/__init__.py
vendored
2
Lib/test/support/__init__.py
vendored
@@ -7,7 +7,7 @@ import contextlib
|
||||
import dataclasses
|
||||
import functools
|
||||
import logging
|
||||
# import _opcode # TODO: RUSTPYTHON
|
||||
import _opcode
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
|
||||
107
Lib/test/support/bytecode_helper.py
vendored
107
Lib/test/support/bytecode_helper.py
vendored
@@ -3,10 +3,26 @@
|
||||
import unittest
|
||||
import dis
|
||||
import io
|
||||
from _testinternalcapi import compiler_codegen, optimize_cfg, assemble_code_object
|
||||
import opcode
|
||||
try:
|
||||
import _testinternalcapi
|
||||
except ImportError:
|
||||
_testinternalcapi = None
|
||||
|
||||
_UNSPECIFIED = object()
|
||||
|
||||
def instructions_with_positions(instrs, co_positions):
|
||||
# Return (instr, positions) pairs from the instrs list and co_positions
|
||||
# iterator. The latter contains items for cache lines and the former
|
||||
# doesn't, so those need to be skipped.
|
||||
|
||||
co_positions = co_positions or iter(())
|
||||
for instr in instrs:
|
||||
yield instr, next(co_positions, ())
|
||||
for _, size, _ in (instr.cache_info or ()):
|
||||
for i in range(size):
|
||||
next(co_positions, ())
|
||||
|
||||
class BytecodeTestCase(unittest.TestCase):
|
||||
"""Custom assertion methods for inspecting bytecode."""
|
||||
|
||||
@@ -53,16 +69,14 @@ class CompilationStepTestCase(unittest.TestCase):
|
||||
class Label:
|
||||
pass
|
||||
|
||||
def assertInstructionsMatch(self, actual_, expected_):
|
||||
# get two lists where each entry is a label or
|
||||
# an instruction tuple. Normalize the labels to the
|
||||
# instruction count of the target, and compare the lists.
|
||||
def assertInstructionsMatch(self, actual_seq, expected):
|
||||
# get an InstructionSequence and an expected list, where each
|
||||
# entry is a label or an instruction tuple. Construct an expcted
|
||||
# instruction sequence and compare with the one given.
|
||||
|
||||
self.assertIsInstance(actual_, list)
|
||||
self.assertIsInstance(expected_, list)
|
||||
|
||||
actual = self.normalize_insts(actual_)
|
||||
expected = self.normalize_insts(expected_)
|
||||
self.assertIsInstance(expected, list)
|
||||
actual = actual_seq.get_instructions()
|
||||
expected = self.seq_from_insts(expected).get_instructions()
|
||||
self.assertEqual(len(actual), len(expected))
|
||||
|
||||
# compare instructions
|
||||
@@ -72,10 +86,8 @@ class CompilationStepTestCase(unittest.TestCase):
|
||||
continue
|
||||
self.assertIsInstance(exp, tuple)
|
||||
self.assertIsInstance(act, tuple)
|
||||
# crop comparison to the provided expected values
|
||||
if len(act) > len(exp):
|
||||
act = act[:len(exp)]
|
||||
self.assertEqual(exp, act)
|
||||
idx = max([p[0] for p in enumerate(exp) if p[1] != -1])
|
||||
self.assertEqual(exp[:idx], act[:idx])
|
||||
|
||||
def resolveAndRemoveLabels(self, insts):
|
||||
idx = 0
|
||||
@@ -90,54 +102,57 @@ class CompilationStepTestCase(unittest.TestCase):
|
||||
|
||||
return res
|
||||
|
||||
def normalize_insts(self, insts):
|
||||
""" Map labels to instruction index.
|
||||
Map opcodes to opnames.
|
||||
"""
|
||||
insts = self.resolveAndRemoveLabels(insts)
|
||||
res = []
|
||||
def seq_from_insts(self, insts):
|
||||
labels = {item for item in insts if isinstance(item, self.Label)}
|
||||
for i, lbl in enumerate(labels):
|
||||
lbl.value = i
|
||||
|
||||
seq = _testinternalcapi.new_instruction_sequence()
|
||||
for item in insts:
|
||||
assert isinstance(item, tuple)
|
||||
opcode, oparg, *loc = item
|
||||
opcode = dis.opmap.get(opcode, opcode)
|
||||
if isinstance(oparg, self.Label):
|
||||
arg = oparg.value
|
||||
if isinstance(item, self.Label):
|
||||
seq.use_label(item.value)
|
||||
else:
|
||||
arg = oparg if opcode in self.HAS_ARG else None
|
||||
opcode = dis.opname[opcode]
|
||||
res.append((opcode, arg, *loc))
|
||||
return res
|
||||
op = item[0]
|
||||
if isinstance(op, str):
|
||||
op = opcode.opmap[op]
|
||||
arg, *loc = item[1:]
|
||||
if isinstance(arg, self.Label):
|
||||
arg = arg.value
|
||||
loc = loc + [-1] * (4 - len(loc))
|
||||
seq.addop(op, arg or 0, *loc)
|
||||
return seq
|
||||
|
||||
def complete_insts_info(self, insts):
|
||||
# fill in omitted fields in location, and oparg 0 for ops with no arg.
|
||||
res = []
|
||||
for item in insts:
|
||||
assert isinstance(item, tuple)
|
||||
inst = list(item)
|
||||
opcode = dis.opmap[inst[0]]
|
||||
oparg = inst[1]
|
||||
loc = inst[2:] + [-1] * (6 - len(inst))
|
||||
res.append((opcode, oparg, *loc))
|
||||
return res
|
||||
def check_instructions(self, insts):
|
||||
for inst in insts:
|
||||
if isinstance(inst, self.Label):
|
||||
continue
|
||||
op, arg, *loc = inst
|
||||
if isinstance(op, str):
|
||||
op = opcode.opmap[op]
|
||||
self.assertEqual(op in opcode.hasarg,
|
||||
arg is not None,
|
||||
f"{opcode.opname[op]=} {arg=}")
|
||||
self.assertTrue(all(isinstance(l, int) for l in loc))
|
||||
|
||||
|
||||
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
|
||||
class CodegenTestCase(CompilationStepTestCase):
|
||||
|
||||
def generate_code(self, ast):
|
||||
insts, _ = compiler_codegen(ast, "my_file.py", 0)
|
||||
insts, _ = _testinternalcapi.compiler_codegen(ast, "my_file.py", 0)
|
||||
return insts
|
||||
|
||||
|
||||
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
|
||||
class CfgOptimizationTestCase(CompilationStepTestCase):
|
||||
|
||||
def get_optimized(self, insts, consts, nlocals=0):
|
||||
insts = self.normalize_insts(insts)
|
||||
insts = self.complete_insts_info(insts)
|
||||
insts = optimize_cfg(insts, consts, nlocals)
|
||||
def get_optimized(self, seq, consts, nlocals=0):
|
||||
insts = _testinternalcapi.optimize_cfg(seq, consts, nlocals)
|
||||
return insts, consts
|
||||
|
||||
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
|
||||
class AssemblerTestCase(CompilationStepTestCase):
|
||||
|
||||
def get_code_object(self, filename, insts, metadata):
|
||||
co = assemble_code_object(filename, insts, metadata)
|
||||
co = _testinternalcapi.assemble_code_object(filename, insts, metadata)
|
||||
return co
|
||||
|
||||
143
Lib/test/test__opcode.py
vendored
Normal file
143
Lib/test/test__opcode.py
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
import dis
|
||||
from test.support.import_helper import import_module
|
||||
import unittest
|
||||
import opcode
|
||||
|
||||
_opcode = import_module("_opcode")
|
||||
from _opcode import stack_effect
|
||||
|
||||
|
||||
class OpListTests(unittest.TestCase):
|
||||
def check_bool_function_result(self, func, ops, expected):
|
||||
for op in ops:
|
||||
if isinstance(op, str):
|
||||
op = dis.opmap[op]
|
||||
with self.subTest(opcode=op, func=func):
|
||||
self.assertIsInstance(func(op), bool)
|
||||
self.assertEqual(func(op), expected)
|
||||
|
||||
def test_invalid_opcodes(self):
|
||||
invalid = [-100, -1, 255, 512, 513, 1000]
|
||||
self.check_bool_function_result(_opcode.is_valid, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_arg, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_const, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_name, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_jump, invalid, False)
|
||||
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)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'dis' has no attribute 'opmap'
|
||||
def test_is_valid(self):
|
||||
names = [
|
||||
'CACHE',
|
||||
'POP_TOP',
|
||||
'IMPORT_NAME',
|
||||
'JUMP',
|
||||
'INSTRUMENTED_RETURN_VALUE',
|
||||
]
|
||||
opcodes = [dis.opmap[opname] for opname in names]
|
||||
self.check_bool_function_result(_opcode.is_valid, opcodes, True)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'dis' has no attribute 'hasarg'
|
||||
def test_oplists(self):
|
||||
def check_function(self, func, expected):
|
||||
for op in [-10, 520]:
|
||||
with self.subTest(opcode=op, func=func):
|
||||
res = func(op)
|
||||
self.assertIsInstance(res, bool)
|
||||
self.assertEqual(res, op in expected)
|
||||
|
||||
check_function(self, _opcode.has_arg, dis.hasarg)
|
||||
check_function(self, _opcode.has_const, dis.hasconst)
|
||||
check_function(self, _opcode.has_name, dis.hasname)
|
||||
check_function(self, _opcode.has_jump, dis.hasjump)
|
||||
check_function(self, _opcode.has_free, dis.hasfree)
|
||||
check_function(self, _opcode.has_local, dis.haslocal)
|
||||
check_function(self, _opcode.has_exc, dis.hasexc)
|
||||
|
||||
|
||||
class StackEffectTests(unittest.TestCase):
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_stack_effect(self):
|
||||
self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1)
|
||||
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
|
||||
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1)
|
||||
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2)
|
||||
self.assertRaises(ValueError, stack_effect, 30000)
|
||||
# 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:
|
||||
continue
|
||||
with self.subTest(opname=name):
|
||||
stack_effect(code)
|
||||
stack_effect(code, 0)
|
||||
# All not defined opcodes
|
||||
for code in set(range(256)) - set(dis.opmap.values()):
|
||||
with self.subTest(opcode=code):
|
||||
self.assertRaises(ValueError, stack_effect, code)
|
||||
self.assertRaises(ValueError, stack_effect, code, 0)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_stack_effect_jump(self):
|
||||
FOR_ITER = dis.opmap['FOR_ITER']
|
||||
self.assertEqual(stack_effect(FOR_ITER, 0), 1)
|
||||
self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1)
|
||||
self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), 1)
|
||||
JUMP_FORWARD = dis.opmap['JUMP_FORWARD']
|
||||
self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0)
|
||||
self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=True), 0)
|
||||
self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=False), 0)
|
||||
# All defined opcodes
|
||||
has_arg = dis.hasarg
|
||||
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:
|
||||
continue
|
||||
with self.subTest(opname=name):
|
||||
if code not in has_arg:
|
||||
common = stack_effect(code)
|
||||
jump = stack_effect(code, jump=True)
|
||||
nojump = stack_effect(code, jump=False)
|
||||
else:
|
||||
common = stack_effect(code, 0)
|
||||
jump = stack_effect(code, 0, jump=True)
|
||||
nojump = stack_effect(code, 0, jump=False)
|
||||
if code in has_jump or code in has_exc:
|
||||
self.assertEqual(common, max(jump, nojump))
|
||||
else:
|
||||
self.assertEqual(jump, common)
|
||||
self.assertEqual(nojump, common)
|
||||
|
||||
|
||||
class SpecializationStatsTests(unittest.TestCase):
|
||||
def test_specialization_stats(self):
|
||||
stat_names = ["success", "failure", "hit", "deferred", "miss", "deopt"]
|
||||
specialized_opcodes = [
|
||||
op.lower()
|
||||
for op in opcode._specializations
|
||||
if opcode._inline_cache_entries.get(op, 0)
|
||||
]
|
||||
self.assertIn('load_attr', specialized_opcodes)
|
||||
self.assertIn('binary_subscr', specialized_opcodes)
|
||||
|
||||
stats = _opcode.get_specialization_stats()
|
||||
if stats is not None:
|
||||
self.assertIsInstance(stats, dict)
|
||||
self.assertCountEqual(stats.keys(), specialized_opcodes)
|
||||
self.assertCountEqual(
|
||||
stats['load_attr'].keys(),
|
||||
stat_names + ['failure_kinds'])
|
||||
for sn in stat_names:
|
||||
self.assertIsInstance(stats['load_attr'][sn], int)
|
||||
self.assertIsInstance(
|
||||
stats['load_attr']['failure_kinds'],
|
||||
tuple)
|
||||
for v in stats['load_attr']['failure_kinds']:
|
||||
self.assertIsInstance(v, int)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -198,27 +198,27 @@ pub struct CodeObject<C: Constant = ConstantData> {
|
||||
pub instructions: Box<[CodeUnit]>,
|
||||
pub locations: Box<[SourceLocation]>,
|
||||
pub flags: CodeFlags,
|
||||
/// Number of positional-only arguments
|
||||
pub posonlyarg_count: u32,
|
||||
// Number of positional-only arguments
|
||||
pub arg_count: u32,
|
||||
pub kwonlyarg_count: u32,
|
||||
pub source_path: C::Name,
|
||||
pub first_line_number: Option<OneIndexed>,
|
||||
pub max_stackdepth: u32,
|
||||
/// Name of the object that created this code object
|
||||
pub obj_name: C::Name,
|
||||
// Name of the object that created this code object
|
||||
/// Qualified name of the object (like CPython's co_qualname)
|
||||
pub qualname: C::Name,
|
||||
// Qualified name of the object (like CPython's co_qualname)
|
||||
pub cell2arg: Option<Box<[i32]>>,
|
||||
pub constants: Box<[C]>,
|
||||
pub names: Box<[C::Name]>,
|
||||
pub varnames: Box<[C::Name]>,
|
||||
pub cellvars: Box<[C::Name]>,
|
||||
pub freevars: Box<[C::Name]>,
|
||||
/// Line number table (CPython 3.11+ format)
|
||||
pub linetable: Box<[u8]>,
|
||||
// Line number table (CPython 3.11+ format)
|
||||
/// Exception handling table
|
||||
pub exceptiontable: Box<[u8]>,
|
||||
// Exception handling table
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@@ -294,6 +294,12 @@ impl OpArg {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for OpArg {
|
||||
fn from(raw: u32) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct OpArgState {
|
||||
|
||||
@@ -22,7 +22,7 @@ tkinter = ["dep:tk-sys", "dep:tcl-sys"]
|
||||
[dependencies]
|
||||
# rustpython crates
|
||||
rustpython-derive = { workspace = true }
|
||||
rustpython-vm = { workspace = true, default-features = false }
|
||||
rustpython-vm = { workspace = true, default-features = false, features = ["compiler"]}
|
||||
rustpython-common = { workspace = true }
|
||||
|
||||
ahash = { workspace = true }
|
||||
|
||||
@@ -38,6 +38,7 @@ mod locale;
|
||||
mod math;
|
||||
#[cfg(unix)]
|
||||
mod mmap;
|
||||
mod opcode;
|
||||
mod pyexpat;
|
||||
mod pystruct;
|
||||
mod random;
|
||||
@@ -135,6 +136,7 @@ pub fn get_module_inits() -> impl Iterator<Item = (Cow<'static, str>, StdlibInit
|
||||
"_json" => json::make_module,
|
||||
"math" => math::make_module,
|
||||
"pyexpat" => pyexpat::make_module,
|
||||
"_opcode" => opcode::make_module,
|
||||
"_random" => random::make_module,
|
||||
"_statistics" => statistics::make_module,
|
||||
"_struct" => pystruct::make_module,
|
||||
|
||||
282
stdlib/src/opcode.rs
Normal file
282
stdlib/src/opcode.rs
Normal file
@@ -0,0 +1,282 @@
|
||||
pub(crate) use opcode::make_module;
|
||||
|
||||
#[pymodule]
|
||||
mod opcode {
|
||||
use crate::vm::{
|
||||
AsObject, PyObjectRef, PyResult, VirtualMachine,
|
||||
builtins::{PyBool, PyInt, PyIntRef, PyNone},
|
||||
bytecode::Instruction,
|
||||
match_class,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
|
||||
struct Opcode(Instruction);
|
||||
|
||||
impl Deref for Opcode {
|
||||
type Target = Instruction;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
// https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Include/opcode_ids.h#L238
|
||||
const HAVE_ARGUMENT: i32 = 44;
|
||||
|
||||
pub fn try_from_pyint(raw: PyIntRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
let instruction = raw
|
||||
.try_to_primitive::<u8>(vm)
|
||||
.and_then(|v| {
|
||||
Instruction::try_from(v).map_err(|_| {
|
||||
vm.new_exception_empty(vm.ctx.exceptions.value_error.to_owned())
|
||||
})
|
||||
})
|
||||
.map_err(|_| vm.new_value_error("invalid opcode or oparg"))?;
|
||||
|
||||
Ok(Self(instruction))
|
||||
}
|
||||
|
||||
/// https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Include/internal/pycore_opcode_metadata.h#L914-L916
|
||||
#[must_use]
|
||||
pub const fn is_valid(opcode: i32) -> bool {
|
||||
opcode >= 0 && opcode < 268 && opcode != 255
|
||||
}
|
||||
|
||||
// All `has_*` methods below mimics
|
||||
// https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Include/internal/pycore_opcode_metadata.h#L966-L1190
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_arg(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode) && opcode > Self::HAVE_ARGUMENT
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_const(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode) && matches!(opcode, 83 | 103 | 240)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_name(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode)
|
||||
&& matches!(
|
||||
opcode,
|
||||
63 | 66
|
||||
| 67
|
||||
| 74
|
||||
| 75
|
||||
| 82
|
||||
| 90
|
||||
| 91
|
||||
| 92
|
||||
| 93
|
||||
| 108
|
||||
| 113
|
||||
| 114
|
||||
| 259
|
||||
| 260
|
||||
| 261
|
||||
| 262
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_jump(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode)
|
||||
&& matches!(
|
||||
opcode,
|
||||
72 | 77 | 78 | 79 | 97 | 98 | 99 | 100 | 104 | 256 | 257
|
||||
)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_free(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode) && matches!(opcode, 64 | 84 | 89 | 94 | 109)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_local(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode)
|
||||
&& matches!(opcode, 65 | 85 | 86 | 87 | 88 | 110 | 111 | 112 | 258 | 267)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn has_exc(opcode: i32) -> bool {
|
||||
Self::is_valid(opcode) && matches!(opcode, 264..=266)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
const ENABLE_SPECIALIZATION: i8 = 1;
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct StackEffectArgs {
|
||||
#[pyarg(positional)]
|
||||
opcode: PyIntRef,
|
||||
#[pyarg(positional, optional)]
|
||||
oparg: Option<PyObjectRef>,
|
||||
#[pyarg(named, optional)]
|
||||
jump: Option<PyObjectRef>,
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn stack_effect(args: StackEffectArgs, vm: &VirtualMachine) -> PyResult<i32> {
|
||||
let oparg = args
|
||||
.oparg
|
||||
.map(|v| {
|
||||
if !v.fast_isinstance(vm.ctx.types.int_type) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
v.class().name()
|
||||
)));
|
||||
}
|
||||
v.downcast_ref::<PyInt>()
|
||||
.ok_or_else(|| vm.new_type_error(""))?
|
||||
.try_to_primitive::<u32>(vm)
|
||||
})
|
||||
.unwrap_or(Ok(0))?;
|
||||
|
||||
let jump = args
|
||||
.jump
|
||||
.map(|v| {
|
||||
match_class!(match v {
|
||||
b @ PyBool => Ok(b.is(&vm.ctx.true_value)),
|
||||
_n @ PyNone => Ok(false),
|
||||
_ => {
|
||||
Err(vm.new_value_error("stack_effect: jump must be False, True or None"))
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or(Ok(false))?;
|
||||
|
||||
let opcode = Opcode::try_from_pyint(args.opcode, vm)?;
|
||||
|
||||
Ok(opcode.stack_effect(oparg.into(), jump))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn is_valid(opcode: i32) -> bool {
|
||||
Opcode::is_valid(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_arg(opcode: i32) -> bool {
|
||||
Opcode::has_arg(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_const(opcode: i32) -> bool {
|
||||
Opcode::has_const(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_name(opcode: i32) -> bool {
|
||||
Opcode::has_name(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_jump(opcode: i32) -> bool {
|
||||
Opcode::has_jump(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_free(opcode: i32) -> bool {
|
||||
Opcode::has_free(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_local(opcode: i32) -> bool {
|
||||
Opcode::has_local(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn has_exc(opcode: i32) -> bool {
|
||||
Opcode::has_exc(opcode)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_intrinsic1_descs(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
[
|
||||
"INTRINSIC_1_INVALID",
|
||||
"INTRINSIC_PRINT",
|
||||
"INTRINSIC_IMPORT_STAR",
|
||||
"INTRINSIC_STOPITERATION_ERROR",
|
||||
"INTRINSIC_ASYNC_GEN_WRAP",
|
||||
"INTRINSIC_UNARY_POSITIVE",
|
||||
"INTRINSIC_LIST_TO_TUPLE",
|
||||
"INTRINSIC_TYPEVAR",
|
||||
"INTRINSIC_PARAMSPEC",
|
||||
"INTRINSIC_TYPEVARTUPLE",
|
||||
"INTRINSIC_SUBSCRIPT_GENERIC",
|
||||
"INTRINSIC_TYPEALIAS",
|
||||
]
|
||||
.into_iter()
|
||||
.map(|x| vm.ctx.new_str(x).into())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_intrinsic2_descs(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
[
|
||||
"INTRINSIC_2_INVALID",
|
||||
"INTRINSIC_PREP_RERAISE_STAR",
|
||||
"INTRINSIC_TYPEVAR_WITH_BOUND",
|
||||
"INTRINSIC_TYPEVAR_WITH_CONSTRAINTS",
|
||||
"INTRINSIC_SET_FUNCTION_TYPE_PARAMS",
|
||||
"INTRINSIC_SET_TYPEPARAM_DEFAULT",
|
||||
]
|
||||
.into_iter()
|
||||
.map(|x| vm.ctx.new_str(x).into())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_nb_ops(vm: &VirtualMachine) -> Vec<PyObjectRef> {
|
||||
[
|
||||
("NB_ADD", "+"),
|
||||
("NB_AND", "&"),
|
||||
("NB_FLOOR_DIVIDE", "//"),
|
||||
("NB_LSHIFT", "<<"),
|
||||
("NB_MATRIX_MULTIPLY", "@"),
|
||||
("NB_MULTIPLY", "*"),
|
||||
("NB_REMAINDER", "%"),
|
||||
("NB_OR", "|"),
|
||||
("NB_POWER", "**"),
|
||||
("NB_RSHIFT", ">>"),
|
||||
("NB_SUBTRACT", "-"),
|
||||
("NB_TRUE_DIVIDE", "/"),
|
||||
("NB_XOR", "^"),
|
||||
("NB_INPLACE_ADD", "+="),
|
||||
("NB_INPLACE_AND", "&="),
|
||||
("NB_INPLACE_FLOOR_DIVIDE", "//="),
|
||||
("NB_INPLACE_LSHIFT", "<<="),
|
||||
("NB_INPLACE_MATRIX_MULTIPLY", "@="),
|
||||
("NB_INPLACE_MULTIPLY", "*="),
|
||||
("NB_INPLACE_REMAINDER", "%="),
|
||||
("NB_INPLACE_OR", "|="),
|
||||
("NB_INPLACE_POWER", "**="),
|
||||
("NB_INPLACE_RSHIFT", ">>="),
|
||||
("NB_INPLACE_SUBTRACT", "-="),
|
||||
("NB_INPLACE_TRUE_DIVIDE", "/="),
|
||||
("NB_INPLACE_XOR", "^="),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(a, b)| {
|
||||
vm.ctx
|
||||
.new_tuple(vec![vm.ctx.new_str(a).into(), vm.ctx.new_str(b).into()])
|
||||
.into()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_executor(_code: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
// TODO
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_specialization_stats(vm: &VirtualMachine) -> PyObjectRef {
|
||||
vm.ctx.none()
|
||||
}
|
||||
}
|
||||
@@ -837,6 +837,15 @@ impl PyCode {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn _varname_from_oparg(&self, opcode: i32, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
let idx_err = |vm: &VirtualMachine| vm.new_index_error("tuple index out of range");
|
||||
|
||||
let idx = usize::try_from(opcode).map_err(|_| idx_err(vm))?;
|
||||
let name = self.code.varnames.get(idx).ok_or_else(|| idx_err(vm))?;
|
||||
Ok(name.to_object())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PyCode {
|
||||
|
||||
Reference in New Issue
Block a user