def get_func_from_code(code_object, fn_name): executor_code = Bytecode() executor_code.append(Instr('LOAD_CONST', code_object)) executor_code.append(Instr('LOAD_CONST', fn_name)) executor_code.append(Instr('MAKE_FUNCTION', 0)) executor_code.append(Instr('RETURN_VALUE')) executor_code.flags = CompilerFlags.OPTIMIZED | CompilerFlags.NEWLOCALS | CompilerFlags.NOFREE return eval(executor_code.to_code())
def _make_trampoline(target_func): bytecode = Bytecode([ Instr('LOAD_CONST', target_func), Instr('LOAD_FAST', 'args'), Instr('LOAD_FAST', 'kwargs'), Instr('CALL_FUNCTION_EX', 1), Instr('RETURN_VALUE') ]) def new_varargs_func(): def func(*args, **kwargs): pass return func tramp = new_varargs_func() bytecode.flags = tramp.__code__.co_flags tramp.__code__ = bytecode.to_code() return tramp
def run_bytecode(ops): cs = [] labels = [] patches = [] for c, rep in ops: if c == '>' or c == '<': # ptr += rep if c == '<': rep = -rep codes = [ I("LOAD_FAST", "ptr"), I("LOAD_CONST", rep), I("BINARY_ADD"), I("STORE_FAST", "ptr"), ] cs.extend(codes) elif c == '+' or c == '-': # *ptr += rep if c == '-': rep = -rep codes = [ I("LOAD_FAST", "mem"), I("LOAD_FAST", "ptr"), I("DUP_TOP_TWO"), I("BINARY_SUBSCR"), I("LOAD_CONST", rep), I("BINARY_ADD"), I("LOAD_CONST", 0xff), I("BINARY_AND"), I("ROT_THREE"), I("STORE_SUBSCR"), ] cs.extend(codes) elif c == '0': # *ptr = 0 codes = [ I("LOAD_CONST", 0), I("LOAD_FAST", "mem"), I("LOAD_FAST", "ptr"), I("STORE_SUBSCR") ] cs.extend(codes) elif c == '.': codes = [ I("LOAD_FAST", "sys_write"), I("LOAD_FAST", "mem"), I("LOAD_FAST", "ptr"), I("BINARY_SUBSCR"), I("LOAD_CONST", rep), I("CALL_FUNCTION", 2), I("POP_TOP") ] cs.extend(codes) elif c == ',': codes = [ I("LOAD_FAST", "sys_read"), I("LOAD_CONST", rep), I("CALL_FUNCTION", 1), I("LOAD_FAST", "mem"), I("LOAD_FAST", "ptr"), I("STORE_SUBSCR") ] cs.extend(codes) elif c == '[': start_label = Label() codes = [ start_label, I("LOAD_FAST", "mem"), I("LOAD_FAST", "ptr"), I("BINARY_SUBSCR"), I("LOAD_CONST", 0), I("COMPARE_OP", Compare.EQ), None, ] cs.extend(codes) labels.append(start_label) patches.append(len(cs) - 1) elif c == ']': start_label = labels.pop() end_label = Label() pp = patches.pop() cs[pp] = I("POP_JUMP_IF_TRUE", end_label) codes = [ end_label, I("LOAD_FAST", "mem"), I("LOAD_FAST", "ptr"), I("BINARY_SUBSCR"), I("LOAD_CONST", 0), I("COMPARE_OP", Compare.EQ), I("POP_JUMP_IF_FALSE", start_label) ] cs.extend(codes) cs.extend([I("LOAD_CONST", None), I("RETURN_VALUE")]) assert not labels and not patches for x in cs: print(x) def sys_write(c, rep): sys.stdout.write(chr(c) * rep) sys.stdout.flush() def sys_read(rep): data = sys.stdin.read(rep) return ord(data[-1]) & 0xff mem_size = 10**6 env = dict(mem=array.array('B', [0] * mem_size), ptr=0, sys_read=sys_read, sys_write=sys_write) load_cs = [] for k in env: load_cs.extend([I("LOAD_NAME", k), I("STORE_FAST", k)]) bc = Bytecode(load_cs + cs) bc.flags = CompilerFlags(CompilerFlags.OPTIMIZED) code = PeepholeOptimizer().optimize(bc.to_code()) exec(code, {}, env)
def as_namedlist(name, bases, namespace: dict): try: module = sys._getframe(1).f_globals.get('__name__', '__main__') except (AttributeError, ValueError): module = '__main__' namespace = {**namespace} annotations: dict = namespace.get('__annotations__') try: filepath = sys.modules[module].__file__ except (AttributeError, IndexError): filepath = "<unknown>" if annotations is not None: for i, (k, v) in enumerate(annotations.items()): if k in namespace: raise AttributeError getter_code = Bytecode() getter_code.filename = filepath getter_code.argcount = 1 getter_code.argnames.append('self') getter_code.append(Instr('LOAD_FAST', 'self')) getter_code.append(Instr('LOAD_CONST', i)) getter_code.append(Instr('BINARY_SUBSCR')) getter_code.append(Instr('RETURN_VALUE')) getter_code.flags = CompilerFlags.OPTIMIZED | CompilerFlags.NEWLOCALS | CompilerFlags.NOFREE getter_fn = property(get_func_from_code(getter_code.to_code(), k)) setter_code = Bytecode() setter_code.filename = filepath setter_code.argcount = 2 setter_code.argnames.extend(['self', 'value']) setter_code.append(Instr('LOAD_FAST', 'value')) setter_code.append(Instr('LOAD_FAST', 'self')) setter_code.append(Instr('LOAD_CONST', i)) setter_code.append(Instr('STORE_SUBSCR')) setter_code.append(Instr('LOAD_CONST', None)) setter_code.append(Instr('RETURN_VALUE')) setter_code.flags = CompilerFlags.OPTIMIZED | CompilerFlags.NEWLOCALS | CompilerFlags.NOFREE setter_fn = getter_fn.setter( get_func_from_code(setter_code.to_code(), k)) namespace[k] = setter_fn init_code = Bytecode() init_code.name = '__init__' init_code.filename = filepath ary_num = len(annotations) args = list(annotations) init_code.argcount = ary_num + 1 init_code.argnames.extend(['self', *args]) if ary_num: init_code.append(Instr('LOAD_FAST', 'self')) if ary_num >= 4: init_code.append(Instr('DUP_TOP')) for i in range((ary_num - 2) // 2): init_code.append(Instr('DUP_TOP_TWO')) if ary_num % 2: init_code.append(Instr('DUP_TOP')) else: for i in range(ary_num - 1): init_code.append(Instr('DUP_TOP')) for i in range(ary_num): init_code.append(Instr("LOAD_FAST", args[i])) init_code.append(Instr("LIST_APPEND", ary_num - i)) init_code.append(Instr('LOAD_CONST', None)) init_code.append(Instr('RETURN_VALUE')) init_code.flags = CompilerFlags.OPTIMIZED | CompilerFlags.NEWLOCALS | CompilerFlags.NOFREE namespace['__init__'] = get_func_from_code(init_code.to_code(), '__init__') fmt = '{}({})'.format(name, ', '.join(f'{arg}={{!r}}' for arg in args)) str_code = Bytecode() str_code.argcount = 1 str_code.argnames.append('self') str_code.append(Instr('LOAD_CONST', fmt.format)) str_code.append(Instr('LOAD_FAST', 'self')) str_code.append(Instr('CALL_FUNCTION_EX', 0)) str_code.append(Instr('RETURN_VALUE')) str_code.flags = CompilerFlags.OPTIMIZED | CompilerFlags.NEWLOCALS | CompilerFlags.NOFREE namespace['__str__'] = get_func_from_code(str_code.to_code(), '__str__') return bases if any(issubclass(t, list) for t in bases) else (*bases, list), namespace