示例#1
0
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())
示例#2
0
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
示例#3
0
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)
示例#4
0
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