mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			184 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# This script generates the opcode.h header file.
 | 
						|
 | 
						|
import sys
 | 
						|
import tokenize
 | 
						|
 | 
						|
SCRIPT_NAME = "Tools/scripts/generate_opcode_h.py"
 | 
						|
PYTHON_OPCODE = "Lib/opcode.py"
 | 
						|
 | 
						|
header = f"""
 | 
						|
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
 | 
						|
 | 
						|
#ifndef Py_OPCODE_H
 | 
						|
#define Py_OPCODE_H
 | 
						|
#ifdef __cplusplus
 | 
						|
extern "C" {{
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/* Instruction opcodes for compiled code */
 | 
						|
""".lstrip()
 | 
						|
 | 
						|
footer = """
 | 
						|
#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT)
 | 
						|
 | 
						|
/* Reserve some bytecodes for internal use in the compiler.
 | 
						|
 * The value of 240 is arbitrary. */
 | 
						|
#define IS_ARTIFICIAL(op) ((op) > 240)
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif /* !Py_OPCODE_H */
 | 
						|
"""
 | 
						|
 | 
						|
internal_header = f"""
 | 
						|
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}
 | 
						|
 | 
						|
#ifndef Py_INTERNAL_OPCODE_H
 | 
						|
#define Py_INTERNAL_OPCODE_H
 | 
						|
#ifdef __cplusplus
 | 
						|
extern "C" {{
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef Py_BUILD_CORE
 | 
						|
#  error "this header requires Py_BUILD_CORE define"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "opcode.h"
 | 
						|
""".lstrip()
 | 
						|
 | 
						|
internal_footer = """
 | 
						|
#ifdef __cplusplus
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif  // !Py_INTERNAL_OPCODE_H
 | 
						|
"""
 | 
						|
 | 
						|
DEFINE = "#define {:<38} {:>3}\n"
 | 
						|
 | 
						|
UINT32_MASK = (1<<32)-1
 | 
						|
 | 
						|
def write_int_array_from_ops(name, ops, out):
 | 
						|
    bits = 0
 | 
						|
    for op in ops:
 | 
						|
        bits |= 1<<op
 | 
						|
    out.write(f"static const uint32_t {name}[8] = {{\n")
 | 
						|
    for i in range(8):
 | 
						|
        out.write(f"    {bits & UINT32_MASK}U,\n")
 | 
						|
        bits >>= 32
 | 
						|
    assert bits == 0
 | 
						|
    out.write(f"}};\n")
 | 
						|
 | 
						|
def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/internal/pycore_opcode.h'):
 | 
						|
    opcode = {}
 | 
						|
    if hasattr(tokenize, 'open'):
 | 
						|
        fp = tokenize.open(opcode_py)   # Python 3.2+
 | 
						|
    else:
 | 
						|
        fp = open(opcode_py)            # Python 2.7
 | 
						|
    with fp:
 | 
						|
        code = fp.read()
 | 
						|
    exec(code, opcode)
 | 
						|
    opmap = opcode['opmap']
 | 
						|
    opname = opcode['opname']
 | 
						|
    hasconst = opcode['hasconst']
 | 
						|
    hasjrel = opcode['hasjrel']
 | 
						|
    hasjabs = opcode['hasjabs']
 | 
						|
    used = [ False ] * 256
 | 
						|
    next_op = 1
 | 
						|
 | 
						|
    for name, op in opmap.items():
 | 
						|
        used[op] = True
 | 
						|
 | 
						|
    specialized_opmap = {}
 | 
						|
    opname_including_specialized = opname.copy()
 | 
						|
    for name in opcode['_specialized_instructions']:
 | 
						|
        while used[next_op]:
 | 
						|
            next_op += 1
 | 
						|
        specialized_opmap[name] = next_op
 | 
						|
        opname_including_specialized[next_op] = name
 | 
						|
        used[next_op] = True
 | 
						|
    specialized_opmap['DO_TRACING'] = 255
 | 
						|
    opname_including_specialized[255] = 'DO_TRACING'
 | 
						|
    used[255] = True
 | 
						|
 | 
						|
    with (open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj):
 | 
						|
        fobj.write(header)
 | 
						|
        iobj.write(internal_header)
 | 
						|
 | 
						|
        for name in opname:
 | 
						|
            if name in opmap:
 | 
						|
                fobj.write(DEFINE.format(name, opmap[name]))
 | 
						|
            if name == 'POP_EXCEPT': # Special entry for HAVE_ARGUMENT
 | 
						|
                fobj.write(DEFINE.format("HAVE_ARGUMENT", opcode["HAVE_ARGUMENT"]))
 | 
						|
 | 
						|
        for name, op in specialized_opmap.items():
 | 
						|
            fobj.write(DEFINE.format(name, op))
 | 
						|
 | 
						|
        iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n")
 | 
						|
        iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n")
 | 
						|
        iobj.write("\nextern const uint8_t _PyOpcode_Original[256];\n")
 | 
						|
        iobj.write("\n#ifdef NEED_OPCODE_TABLES\n")
 | 
						|
        write_int_array_from_ops("_PyOpcode_RelativeJump", opcode['hasjrel'], iobj)
 | 
						|
        write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], iobj)
 | 
						|
 | 
						|
        iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n")
 | 
						|
        for i, entries in enumerate(opcode["_inline_cache_entries"]):
 | 
						|
            if entries:
 | 
						|
                iobj.write(f"    [{opname[i]}] = {entries},\n")
 | 
						|
        iobj.write("};\n")
 | 
						|
 | 
						|
        deoptcodes = {}
 | 
						|
        for basic in opmap:
 | 
						|
            deoptcodes[basic] = basic
 | 
						|
        for basic, family in opcode["_specializations"].items():
 | 
						|
            for specialized in family:
 | 
						|
                deoptcodes[specialized] = basic
 | 
						|
        iobj.write("\nconst uint8_t _PyOpcode_Deopt[256] = {\n")
 | 
						|
        for opt, deopt in sorted(deoptcodes.items()):
 | 
						|
            iobj.write(f"    [{opt}] = {deopt},\n")
 | 
						|
        iobj.write("};\n")
 | 
						|
        iobj.write("\nconst uint8_t _PyOpcode_Original[256] = {\n")
 | 
						|
        for opt, deopt in sorted(deoptcodes.items()):
 | 
						|
            if opt.startswith("EXTENDED_ARG"):
 | 
						|
                deopt = "EXTENDED_ARG_QUICK"
 | 
						|
            iobj.write(f"    [{opt}] = {deopt},\n")
 | 
						|
        iobj.write("};\n")
 | 
						|
        iobj.write("#endif   // NEED_OPCODE_TABLES\n")
 | 
						|
 | 
						|
        fobj.write("\n")
 | 
						|
        fobj.write("#define HAS_CONST(op) (false\\")
 | 
						|
        for op in hasconst:
 | 
						|
            fobj.write(f"\n    || ((op) == {op}) \\")
 | 
						|
        fobj.write("\n    )\n")
 | 
						|
 | 
						|
        fobj.write("\n")
 | 
						|
        for i, (op, _) in enumerate(opcode["_nb_ops"]):
 | 
						|
            fobj.write(DEFINE.format(op, i))
 | 
						|
 | 
						|
        iobj.write("\n")
 | 
						|
        iobj.write("#ifdef Py_DEBUG\n")
 | 
						|
        iobj.write("static const char *const _PyOpcode_OpName[256] = {\n")
 | 
						|
        for op, name in enumerate(opname_including_specialized):
 | 
						|
            if name[0] != "<":
 | 
						|
                op = name
 | 
						|
            iobj.write(f'''    [{op}] = "{name}",\n''')
 | 
						|
        iobj.write("};\n")
 | 
						|
        iobj.write("#endif\n")
 | 
						|
 | 
						|
        iobj.write("\n")
 | 
						|
        iobj.write("#define EXTRA_CASES \\\n")
 | 
						|
        for i, flag in enumerate(used):
 | 
						|
            if not flag:
 | 
						|
                iobj.write(f"    case {i}: \\\n")
 | 
						|
        iobj.write("        ;\n")
 | 
						|
 | 
						|
        fobj.write(footer)
 | 
						|
        iobj.write(internal_footer)
 | 
						|
 | 
						|
 | 
						|
    print(f"{outfile} regenerated from {opcode_py}")
 | 
						|
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main(sys.argv[1], sys.argv[2], sys.argv[3])
 |