1# This script generates the opcode.h header file. 2 3import sys 4import tokenize 5 6SCRIPT_NAME = "Tools/scripts/generate_opcode_h.py" 7PYTHON_OPCODE = "Lib/opcode.py" 8 9header = f""" 10// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE} 11 12#ifndef Py_OPCODE_H 13#define Py_OPCODE_H 14#ifdef __cplusplus 15extern "C" {{ 16#endif 17 18 19/* Instruction opcodes for compiled code */ 20""".lstrip() 21 22footer = """ 23#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) 24 25/* Reserve some bytecodes for internal use in the compiler. 26 * The value of 240 is arbitrary. */ 27#define IS_ARTIFICIAL(op) ((op) > 240) 28 29#ifdef __cplusplus 30} 31#endif 32#endif /* !Py_OPCODE_H */ 33""" 34 35internal_header = f""" 36// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE} 37 38#ifndef Py_INTERNAL_OPCODE_H 39#define Py_INTERNAL_OPCODE_H 40#ifdef __cplusplus 41extern "C" {{ 42#endif 43 44#ifndef Py_BUILD_CORE 45# error "this header requires Py_BUILD_CORE define" 46#endif 47 48#include "opcode.h" 49""".lstrip() 50 51internal_footer = """ 52#ifdef __cplusplus 53} 54#endif 55#endif // !Py_INTERNAL_OPCODE_H 56""" 57 58DEFINE = "#define {:<38} {:>3}\n" 59 60UINT32_MASK = (1<<32)-1 61 62def write_int_array_from_ops(name, ops, out): 63 bits = 0 64 for op in ops: 65 bits |= 1<<op 66 out.write(f"static const uint32_t {name}[8] = {{\n") 67 for i in range(8): 68 out.write(f" {bits & UINT32_MASK}U,\n") 69 bits >>= 32 70 assert bits == 0 71 out.write(f"}};\n") 72 73def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/internal/pycore_opcode.h'): 74 opcode = {} 75 if hasattr(tokenize, 'open'): 76 fp = tokenize.open(opcode_py) # Python 3.2+ 77 else: 78 fp = open(opcode_py) # Python 2.7 79 with fp: 80 code = fp.read() 81 exec(code, opcode) 82 opmap = opcode['opmap'] 83 opname = opcode['opname'] 84 hasconst = opcode['hasconst'] 85 hasjrel = opcode['hasjrel'] 86 hasjabs = opcode['hasjabs'] 87 used = [ False ] * 256 88 next_op = 1 89 90 for name, op in opmap.items(): 91 used[op] = True 92 93 specialized_opmap = {} 94 opname_including_specialized = opname.copy() 95 for name in opcode['_specialized_instructions']: 96 while used[next_op]: 97 next_op += 1 98 specialized_opmap[name] = next_op 99 opname_including_specialized[next_op] = name 100 used[next_op] = True 101 specialized_opmap['DO_TRACING'] = 255 102 opname_including_specialized[255] = 'DO_TRACING' 103 used[255] = True 104 105 with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj: 106 fobj.write(header) 107 iobj.write(internal_header) 108 109 for name in opname: 110 if name in opmap: 111 fobj.write(DEFINE.format(name, opmap[name])) 112 if name == 'POP_EXCEPT': # Special entry for HAVE_ARGUMENT 113 fobj.write(DEFINE.format("HAVE_ARGUMENT", opcode["HAVE_ARGUMENT"])) 114 115 for name, op in specialized_opmap.items(): 116 fobj.write(DEFINE.format(name, op)) 117 118 iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n") 119 iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n") 120 iobj.write("\n#ifdef NEED_OPCODE_TABLES\n") 121 write_int_array_from_ops("_PyOpcode_RelativeJump", opcode['hasjrel'], iobj) 122 write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], iobj) 123 124 iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n") 125 for i, entries in enumerate(opcode["_inline_cache_entries"]): 126 if entries: 127 iobj.write(f" [{opname[i]}] = {entries},\n") 128 iobj.write("};\n") 129 130 deoptcodes = {} 131 for basic in opmap: 132 deoptcodes[basic] = basic 133 for basic, family in opcode["_specializations"].items(): 134 for specialized in family: 135 deoptcodes[specialized] = basic 136 iobj.write("\nconst uint8_t _PyOpcode_Deopt[256] = {\n") 137 for opt, deopt in sorted(deoptcodes.items()): 138 iobj.write(f" [{opt}] = {deopt},\n") 139 iobj.write("};\n") 140 iobj.write("#endif // NEED_OPCODE_TABLES\n") 141 142 fobj.write("\n") 143 fobj.write("#define HAS_CONST(op) (false\\") 144 for op in hasconst: 145 fobj.write(f"\n || ((op) == {op}) \\") 146 fobj.write("\n )\n") 147 148 fobj.write("\n") 149 for i, (op, _) in enumerate(opcode["_nb_ops"]): 150 fobj.write(DEFINE.format(op, i)) 151 152 iobj.write("\n") 153 iobj.write("#ifdef Py_DEBUG\n") 154 iobj.write("static const char *const _PyOpcode_OpName[256] = {\n") 155 for op, name in enumerate(opname_including_specialized): 156 if name[0] != "<": 157 op = name 158 iobj.write(f''' [{op}] = "{name}",\n''') 159 iobj.write("};\n") 160 iobj.write("#endif\n") 161 162 iobj.write("\n") 163 iobj.write("#define EXTRA_CASES \\\n") 164 for i, flag in enumerate(used): 165 if not flag: 166 iobj.write(f" case {i}: \\\n") 167 iobj.write(" ;\n") 168 169 fobj.write(footer) 170 iobj.write(internal_footer) 171 172 173 print(f"{outfile} regenerated from {opcode_py}") 174 175 176if __name__ == '__main__': 177 main(sys.argv[1], sys.argv[2], sys.argv[3]) 178