1 # This script generates the opcode.h header file.
2
3 import sys
4 import tokenize
5
6 SCRIPT_NAME = "Tools/scripts/generate_opcode_h.py"
7 PYTHON_OPCODE = "Lib/opcode.py"
8
9 header = f"""
10 // Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
11
12 #ifndef Py_OPCODE_H
13 #define Py_OPCODE_H
14 #ifdef __cplusplus
15 extern "C" {{
16 #endif
17
18
19 /* Instruction opcodes for compiled code */
20 """.lstrip()
21
22 footer = """
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
35 internal_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
41 extern "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
51 internal_footer = """
52 #ifdef __cplusplus
53 }
54 #endif
55 #endif // !Py_INTERNAL_OPCODE_H
56 """
57
58 DEFINE = "#define {:<38} {:>3}\n"
59
60 UINT32_MASK = (1<<32)-1
61
62 def 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
73 def 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
176 if __name__ == '__main__':
177 main(sys.argv[1], sys.argv[2], sys.argv[3])