示例#1
0
    def check(self, source, function=False):
        ref_code = get_code(source, function=function)

        code = ConcreteBytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        code = Bytecode.from_code(ref_code).to_code()
        self.assertEqual(code, ref_code)

        bytecode = Bytecode.from_code(ref_code)
        blocks = ControlFlowGraph.from_bytecode(bytecode)
        code = blocks.to_bytecode().to_code()
        self.assertEqual(code, ref_code)
示例#2
0
    def optimize(self, code_obj):
        bytecode = Bytecode.from_code(code_obj)
        cfg = ControlFlowGraph.from_bytecode(bytecode)

        self.optimize_cfg(cfg)

        bytecode = cfg.to_bytecode()
        code = bytecode.to_code()
        return code
示例#3
0
 def test_from_code_load_fast(self):
     code = get_code("""
         def func():
             x = 33
             y = x
     """, function=True)
     code = Bytecode.from_code(code)
     self.assertEqual(code,
                      [Instr('LOAD_CONST', 33, lineno=2),
                       Instr('STORE_FAST', 'x', lineno=2),
                       Instr('LOAD_FAST', 'x', lineno=3),
                       Instr('STORE_FAST', 'y', lineno=3),
                       Instr('LOAD_CONST', None, lineno=3),
                       Instr('RETURN_VALUE', lineno=3)])
示例#4
0
 def test_label3(self):
     """
     When you delete ``extended_arg`` that have a value of 0, the following
     will fail when calling ``Bytecode.to_concrete_bytecode()`` because
     it cant find a label to correspond to the jump target
     """
     code = get_code("""
         def func(x):
             if x == 1:
                 return x +1
             elif x == 2:
                 return x + 1
             elif x == 3:
                 return x + 1
             elif x == 4:
                 return x + 1
             elif x == 5:
                 return x + 1
             elif x == 6:
                 return x + 1
             elif x == 7:
                 return x + 1
             elif x == 8:
                 return x + 1
             elif x == 9:
                 return x + 1
             elif x == 10:
                 return x + 1
             elif x == 11:
                 return x + 1
             elif x == 12:
                 return x + 1
             elif x == 13:
                 return x + 1
             elif x == 14:
                 return x + 1
             elif x == 15:
                 return x + 1
             elif x == 16:
                 return x + 1
             elif x == 17:
                 return x + 1
             return -1
     """,
                     function=True)
     code = Bytecode.from_code(code)
     concrete = code.to_concrete_bytecode()
     self.assertIsInstance(concrete, ConcreteBytecode)
示例#5
0
    def __init__(self, path: str, module_name='', to_import=['*']):

        self.path = path
        self.to_import = to_import
        self.module_name = module_name
        self._local_methods = []
        source = open(path, 'rb')

        compiled_source = compile(source.read(), path, 'exec')

        self.bc = Bytecode.from_code(compiled_source)
        self.cfg = ControlFlowGraph.from_bytecode(self.bc)

        source.close()

        self.build()
示例#6
0
    def __init__(self, module, block, module_name, extra):
        self.module = module
        self.block = block
        self.module_name = module_name
        self._extra = extra
        self._id = uuid4()
        self.name = self.block[1].arg
        self.start_line_no = self.block[0].lineno
        self.code_object = self.block[0].arg

#        dis.dis(code_object)
        self.code, self.dictionary_defs = preprocess_method_body(self.code_object, self.name)

        self.bytecode = Bytecode.from_code(self.code)

        self.setup()
示例#7
0
 def test_from_code_load_fast(self):
     code = get_code("""
         def func():
             x = 33
             y = x
     """,
                     function=True)
     code = Bytecode.from_code(code)
     self.assertEqual(code, [
         Instr('LOAD_CONST', 33, lineno=2),
         Instr('STORE_FAST', 'x', lineno=2),
         Instr('LOAD_FAST', 'x', lineno=3),
         Instr('STORE_FAST', 'y', lineno=3),
         Instr('LOAD_CONST', None, lineno=3),
         Instr('RETURN_VALUE', lineno=3)
     ])
def test_every_inner_setup_is_over_variable(bytecode_modifier, sample_inner):
    modified = bytecode_modifier.modify(sample_inner, inner=True)
    bc = Bytecode.from_code(modified)
    is_over_setup_instructions = bc[:4]

    assert is_over_setup_instructions[0].name == 'LOAD_NAME'
    assert is_over_setup_instructions[0].arg == bytecode_modifier._command

    assert is_over_setup_instructions[1].name == 'LOAD_CONST'
    assert is_over_setup_instructions[1].arg == DebugCommand.STEP_OVER

    assert is_over_setup_instructions[2].name == 'COMPARE_OP'
    assert is_over_setup_instructions[2].arg == Compare.EQ

    assert is_over_setup_instructions[3].name == 'STORE_NAME'
    assert is_over_setup_instructions[3].arg == 'is_over'
示例#9
0
    def test_from_code_freevars(self):
        ns = {}
        exec(textwrap.dedent('''
            def create_func():
                x = 1
                def func():
                    return x
                return func

            func = create_func()
        '''), ns, ns)
        code = ns['func'].__code__

        bytecode = Bytecode.from_code(code)
        self.assertEqual(bytecode,
                         [Instr('LOAD_DEREF', FreeVar('x'), lineno=5),
                          Instr('RETURN_VALUE', lineno=5)])
示例#10
0
def support_recursion_bytecode(func):

    bytecodes = Bytecode.from_code(func.__code__)

    localvars = set()
    undefined = set()
    
    for inst in bytecodes:
        if  inst.name == "STORE_FAST" and inst.arg.startswith("p"):
            localvars.add(inst.arg)
        elif  inst.name == "LOAD_FAST" and inst.arg.startswith("p"):
            if inst.arg in localvars:
                undefined .add(inst.arg)

    ## define dummies
    def define_dummy_parser(v):
        code = [Instr("LOAD_GLOBAL", 'pFail'),
                Instr("LOAD_CONST", "null parser"),
                Instr("CALL_FUNCTION", 1),
                Instr("STORE_FAST", v)]
        return code

    result = []
    
    for v in undefined:
        codes = define_dummy_parser(v)
        result.extend(codes)

    ## change assign to iadd
    def modify_store_bytecode(v):
        code = [Instr("LOAD_FAST", v),
                Instr("ROT_TWO"),
                Instr("INPLACE_ADD"),
                Instr("STORE_FAST", v)]
        return code
        
    for inst in bytecodes:
        if  inst.name == "STORE_FAST" and \
            inst.arg.startswith("p") and \
            inst.arg in undefined:
            codes = modify_store_bytecode(inst.arg)
            result.extend(codes)
        else:
            result.append(inst)            

    return Bytecode(result)
示例#11
0
    def test_from_code_freevars(self):
        ns = {}
        exec(textwrap.dedent('''
            def create_func():
                x = 1
                def func():
                    return x
                return func

            func = create_func()
        '''), ns, ns)
        code = ns['func'].__code__

        bytecode = Bytecode.from_code(code)
        self.assertEqual(bytecode,
                         [Instr('LOAD_DEREF', FreeVar('x'), lineno=5),
                          Instr('RETURN_VALUE', lineno=5)])
示例#12
0
 def test_from_code(self):
     code = get_code("""
         if test:
             x = 1
         else:
             x = 2
     """)
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     if sys.version_info < (3, 10):
         self.assertEqual(
             bytecode,
             [
                 Instr("LOAD_NAME", "test", lineno=1),
                 Instr("POP_JUMP_IF_FALSE", label_else, lineno=1),
                 Instr("LOAD_CONST", 1, lineno=2),
                 Instr("STORE_NAME", "x", lineno=2),
                 Instr("JUMP_FORWARD", label_exit, lineno=2),
                 label_else,
                 Instr("LOAD_CONST", 2, lineno=4),
                 Instr("STORE_NAME", "x", lineno=4),
                 label_exit,
                 Instr("LOAD_CONST", None, lineno=4),
                 Instr("RETURN_VALUE", lineno=4),
             ],
         )
     # Control flow handling appears to have changed under Python 3.10
     else:
         self.assertEqual(
             bytecode,
             [
                 Instr("LOAD_NAME", "test", lineno=1),
                 Instr("POP_JUMP_IF_FALSE", label_else, lineno=1),
                 Instr("LOAD_CONST", 1, lineno=2),
                 Instr("STORE_NAME", "x", lineno=2),
                 Instr("LOAD_CONST", None, lineno=2),
                 Instr("RETURN_VALUE", lineno=2),
                 label_else,
                 Instr("LOAD_CONST", 2, lineno=4),
                 Instr("STORE_NAME", "x", lineno=4),
                 Instr("LOAD_CONST", None, lineno=4),
                 Instr("RETURN_VALUE", lineno=4),
             ],
         )
def preprocess_method_body(source_code_obj, MethodName):

    src = inspect.getsource(source_code_obj)

    ast_tree = ast.parse(src)

    visitor = RewriteDicts()
    ast_tree = visitor.visit(ast_tree)

    ast.fix_missing_locations(ast_tree)
    updated_code = compile(ast_tree, filename='<ast>', mode='exec')
    bc = Bytecode.from_code(updated_code)

    dlist = visitor.updated_dicts
    RewriteDicts.updated_dicts = []
    RewriteDicts.last_store_name = None

    return bc[0].arg, dlist
示例#14
0
文件: hook_bc.py 项目: thautwarm/AOP
    def exec_module(self, module):
        code = self.loader.get_code(module.__name__)
        if code is None:
            raise ImportError('cannot load module {!r} when get_code() '
                              'returns None'.format(module.__name__))
        bc = Bytecode.from_code(code)

        def update_bc():
            for each in bc:
                yield Instr("LOAD_CONST", each)
                yield Instr("PRINT_EXPR")
                yield each

        lst = list(update_bc())
        bc.clear()
        bc.extend(lst)
        code = bc.to_code()
        exec(code, module.__dict__)
示例#15
0
    def _ast_to_instr(self, astobj, lineno):

        src = astor.to_source(astobj).replace('"""', "'")

        cp = compile(src, filename='<ast>', mode='eval')
        bc = Bytecode.from_code(cp)
        instructions = bc[:-1]
        for instr in instructions:
            instr.lineno = lineno

        # if its calling a method, we don't want it to do `LOAD_NAME`
        if instructions[-1].opcode == pyop.CALL_FUNCTION and instructions[
                0].opcode == pyop.LOAD_NAME:
            instructions[0] = Instr("LOAD_GLOBAL",
                                    arg=instructions[0].arg,
                                    lineno=instructions[0].lineno)

        return instructions
示例#16
0
文件: base.py 项目: codelv/atom-db
def generate_function(source: str,
                      namespace: DictType[str, Any],
                      fn_name: str,
                      optimize: bool = True) -> Callable[..., Any]:
    """Generate an optimized function

    Parameters
    ----------
    source: str
        The function source code
    namespaced: dict
        Namespace available to the function
    fn_name: str
        The name of the generated function.

    Returns
    -------
    fn: function
        The function generated.

    """
    # print(source)
    try:
        assert source.startswith(f"def {fn_name}") or source.startswith(
            f"async def {fn_name}")
        code = compile(source, __name__, "exec", optimize=1)
    except Exception as e:
        raise RuntimeError(f"Could not generate code: {e}:\n{source}")

    result: DictType[str, Any] = {}
    exec(code, namespace, result)

    # Optimize global access
    fn = result[fn_name]
    fn.__source__ = source
    if optimize:
        bc = Bytecode.from_code(fn.__code__)
        for i, inst in enumerate(bc):
            if isinstance(inst, Label):
                continue
            if inst.name == "LOAD_GLOBAL" and inst.arg in namespace:
                bc[i] = Instr("LOAD_CONST", namespace[inst.arg])
        fn.__code__ = bc.to_code()
    return fn
示例#17
0
    def func_info(cls, func: types.FunctionType) -> types.FunctionType:
        names = func.__code__.co_names
        code = Bytecode.from_code(func.__code__)
        codeinfo = cls.code_info(code)

        def r_compile():
            jit_func = Aware.f(self)
            print("jit_func", type(jit_func))
            bc = Bytecode()

            bc.append(PyInstr(InstrNames.LOAD_CONST, jit_func))
            bc.extend([load_arg(each, cellvars, lineno) for each in argnames])
            bc.extend([
                PyInstr(InstrNames.CALL_FUNCTION, len(argnames)),
                PyInstr(InstrNames.RETURN_VALUE)
            ])
            bc._copy_attr_from(code)
            start_func.__code__ = bc.to_code()
            start_func.__jit__ = jit_func
            return jit_func

        start_func = copy_func(func)
        start_func_code = Bytecode()
        lineno = code.first_lineno
        argnames = code.argnames
        start_func_code.argnames = argnames
        cellvars = code.cellvars
        start_func_code.extend([
            PyInstr(InstrNames.LOAD_CONST, r_compile, lineno=lineno),
            PyInstr(InstrNames.CALL_FUNCTION, 0, lineno=lineno),
            *(load_arg(each, cellvars, lineno) for each in argnames),
            PyInstr(InstrNames.CALL_FUNCTION, len(argnames), lineno=lineno),
            PyInstr(InstrNames.RETURN_VALUE, lineno=lineno)
        ])
        start_func_code._copy_attr_from(code)
        self = PyFuncInfo(func.__name__, func.__module__, func.__defaults__,
                          func.__kwdefaults__, func.__closure__,
                          func.__globals__, codeinfo, func, {}, names)
        start_func.__code__ = start_func_code.to_code()
        start_func.__func_info__ = self
        start_func.__compile__ = r_compile
        start_func.__jit__ = None
        return start_func
示例#18
0
    def instrument(target_code, jointpoint_payload):
        func_bytecode = Bytecode.from_code(target_code)
        beginpoint = 0
        endpoint = -2
        for jointpoint, payload_func in jointpoint_payload.items():
            if isinstance(jointpoint, str):
                jointpoint = (jointpoint, )
            if jointpoint[0] == 'func_begin':
                func_bytecode = FunctionInstrumenter.instrument_func_begin(
                    func_bytecode, payload_func)
            elif jointpoint[0] == 'func_end':
                func_bytecode = FunctionInstrumenter.instrument_func_end(
                    func_bytecode, payload_func)
            elif jointpoint[0] == 'line_before':
                lines = ()
                if type(jointpoint) == tuple and len(jointpoint) > 1:
                    lines = jointpoint[1]
                func_bytecode = LineInstrumenter.instrument_line_begin(
                    func_bytecode, payload_func, lines)
            elif jointpoint[0] == 'line_after':
                lines = ()
                if type(jointpoint) == tuple and len(jointpoint) > 1:
                    lines = jointpoint[1]
                func_bytecode = LineInstrumenter.instrument_line_end(
                    func_bytecode, payload_func, lines)
            elif jointpoint[0] == 'var_def':
                varnames = ()
                if type(jointpoint) == tuple and len(jointpoint) > 1:
                    varnames = jointpoint[1]
                func_bytecode = VariableInstrumenter.instrument_var_def(
                    func_bytecode, payload_func, varnames)
            elif jointpoint[0] == 'var_use':
                varnames = ()
                if type(jointpoint) == tuple and len(jointpoint) > 1:
                    varnames = jointpoint[1]
                func_bytecode = VariableInstrumenter.instrument_var_use(
                    func_bytecode, payload_func, varnames)
            else:
                #ToDo
                pass

        return func_bytecode.to_code()
示例#19
0
 def test_from_code_load_fast(self):
     code = get_code(
         """
         def func():
             x = 33
             y = x
     """,
         function=True,
     )
     code = Bytecode.from_code(code)
     self.assertEqual(
         code,
         [
             Instr("LOAD_CONST", 33, lineno=2),
             Instr("STORE_FAST", "x", lineno=2),
             Instr("LOAD_FAST", "x", lineno=3),
             Instr("STORE_FAST", "y", lineno=3),
             Instr("LOAD_CONST", None, lineno=3),
             Instr("RETURN_VALUE", lineno=3),
         ],
     )
示例#20
0
    def test_optimize_code_obj(self):
        # Test optimize() method with a code object
        #
        # x = 3 + 5 => x = 8
        noopt = Bytecode([Instr('LOAD_CONST', 3),
                          Instr('LOAD_CONST', 5),
                          Instr('BINARY_ADD'),
                          Instr('STORE_NAME', 'x'),
                          Instr('LOAD_CONST', None),
                          Instr('RETURN_VALUE')])
        noopt = noopt.to_code()

        optimizer = peephole_opt.PeepholeOptimizer()
        optim = optimizer.optimize(noopt)

        code = Bytecode.from_code(optim)
        self.assertEqual(code,
                         [Instr('LOAD_CONST', 8, lineno=1),
                          Instr('STORE_NAME', 'x', lineno=1),
                          Instr('LOAD_CONST', None, lineno=1),
                          Instr('RETURN_VALUE', lineno=1)])
示例#21
0
 def test_from_code(self):
     code = get_code("""
         if test:
             x = 1
         else:
             x = 2
     """)
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     self.assertEqual(bytecode, [
         Instr('LOAD_NAME', 'test', lineno=1),
         Instr('POP_JUMP_IF_FALSE', label_else, lineno=1),
         Instr('LOAD_CONST', 1, lineno=2),
         Instr('STORE_NAME', 'x', lineno=2),
         Instr('JUMP_FORWARD', label_exit, lineno=2), label_else,
         Instr('LOAD_CONST', 2, lineno=4),
         Instr('STORE_NAME', 'x', lineno=4), label_exit,
         Instr('LOAD_CONST', None, lineno=4),
         Instr('RETURN_VALUE', lineno=4)
     ])
示例#22
0
    def exec_module(self, module):
        code = self.loader.get_code(module.__name__)
        if code is None:
            raise ImportError('cannot load module {!r} when get_code() '
                              'returns None'.format(module.__name__))
        __glob_refs__ = module.__glob_refs__ = {
        }  # from a global symbol to jit functions it's referenced
        bc = Bytecode.from_code(code)

        def update_generations(name):
            functions = __glob_refs__.get(name, None)
            if functions is None:
                return
            for fn in functions:
                fn.__update_global_ref__(name)

        module.__dict__['__update_generations__'] = update_generations

        def update_bc():
            for each in bc:
                yield each
                if isinstance(each,
                              Instr) and each.name == InstrNames.STORE_NAME:

                    yield Instr(InstrNames.LOAD_NAME,
                                '__update_generations__',
                                lineno=each.lineno)
                    yield Instr(InstrNames.LOAD_CONST,
                                each.arg,
                                lineno=each.lineno)
                    yield Instr(InstrNames.CALL_FUNCTION,
                                1,
                                lineno=each.lineno)
                    yield Instr(InstrNames.POP_TOP, lineno=each.lineno)

        lst = list(update_bc())
        bc.clear()
        bc.extend(lst)
        code = bc.to_code()
        exec(code, module.__dict__)
示例#23
0
def wrap_stores_bytecode(func):

    bytecodes = Bytecode.from_code(func.__code__)

    def wrappStore(x):
        code = [
            Instr("LOAD_GLOBAL", 'goo'),
            Instr("LOAD_FAST", x),
            Instr("CALL_FUNCTION", 1),
            Instr("STORE_FAST", x)
        ]
        return code

    new_code = []

    for inst in bytecodes:
        new_code.append(inst.copy())
        if inst.name == "STORE_FAST":
            codes = wrappStore(inst.arg)
            new_code.extend(codes)

    return Bytecode(new_code)
示例#24
0
 def test_from_code(self):
     code = get_code("""
         if test:
             x = 1
         else:
             x = 2
     """)
     bytecode = Bytecode.from_code(code)
     label_else = Label()
     label_exit = Label()
     self.assertEqual(bytecode,
                      [Instr('LOAD_NAME', 'test', lineno=1),
                       Instr('POP_JUMP_IF_FALSE', label_else, lineno=1),
                       Instr('LOAD_CONST', 1, lineno=2),
                       Instr('STORE_NAME', 'x', lineno=2),
                       Instr('JUMP_FORWARD', label_exit, lineno=2),
                       label_else,
                       Instr('LOAD_CONST', 2, lineno=4),
                       Instr('STORE_NAME', 'x', lineno=4),
                       label_exit,
                       Instr('LOAD_CONST', None, lineno=4),
                       Instr('RETURN_VALUE', lineno=4)])
示例#25
0
    def __init__(self, path: str, module_name='', to_import=['*']):

        self.path = path
        self.to_import = to_import
        self.module_name = module_name
        self._local_methods = []
        self.abi = None
        source = open(path, 'rb')
        source_src = source.read()

        compiled_source = compile(source_src, path, 'exec')

        ast_tree = ast.parse(source_src)
        if module_name == '':
            self.abi = ABI()
            self.abi.visit(ast_tree)

        self.bc = Bytecode.from_code(compiled_source)
        self.cfg = ControlFlowGraph.from_bytecode(self.bc)

        source.close()

        self.build()
示例#26
0
    def test_stack_size_computation_nested_try_except_else_finally(self):
        def test(*args, **kwargs):
            try:
                v = args[1]
            except IndexError:
                try:
                    w = kwargs["value"]
                except KeyError:
                    return -1
                else:
                    return w
                finally:
                    print("second finally")
            else:
                return v
            finally:
                print("first finally")

        # A direct comparison of the stack depth fails because CPython
        # generate dead code that is used in stack computation.
        cpython_stacksize = test.__code__.co_stacksize
        test.__code__ = Bytecode.from_code(test.__code__).to_code()
        self.assertLessEqual(test.__code__.co_stacksize, cpython_stacksize)

        with redirect_stdout(io.BytesIO()) as stdout:
            self.assertEqual(test(1, 4), 4)
            self.assertEqual(stdout.getvalue(), "first finally\n")

        with redirect_stdout(io.BytesIO()) as stdout:
            self.assertEqual(test([], value=3), 3)
            self.assertEqual(stdout.getvalue(),
                             "second finally\nfirst finally\n")

        with redirect_stdout(io.BytesIO()) as stdout:
            self.assertEqual(test([], name=None), -1)
            self.assertEqual(stdout.getvalue(),
                             "second finally\nfirst finally\n")
示例#27
0
def wrap_stores_bytecode(func):

    bytecodes = Bytecode.from_code(func.__code__)

    def wrappStore(x):
        label = x[1:]
        code = [Instr("LOAD_GLOBAL", 'pAst'),
                Instr("LOAD_CONST", label),
                Instr("ROT_THREE"),
                Instr("ROT_THREE"),
                Instr("CALL_FUNCTION", 2),
                Instr("STORE_FAST", x)]
        return code

    new_code = []
    
    for inst in bytecodes:
        if  inst.name == "STORE_FAST" and inst.arg.startswith("p"):
            codes = wrappStore(inst.arg)
            new_code.extend(codes)
        else:
            new_code.append(inst)

    return Bytecode(new_code)
示例#28
0
    def test_optimize_code_obj(self):
        # Test optimize() method with a code object
        #
        # x = 3 + 5 => x = 8
        noopt = Bytecode([
            Instr('LOAD_CONST', 3),
            Instr('LOAD_CONST', 5),
            Instr('BINARY_ADD'),
            Instr('STORE_NAME', 'x'),
            Instr('LOAD_CONST', None),
            Instr('RETURN_VALUE')
        ])
        noopt = noopt.to_code()

        optimizer = peephole_opt.PeepholeOptimizer()
        optim = optimizer.optimize(noopt)

        code = Bytecode.from_code(optim)
        self.assertEqual(code, [
            Instr('LOAD_CONST', 8, lineno=1),
            Instr('STORE_NAME', 'x', lineno=1),
            Instr('LOAD_CONST', None, lineno=1),
            Instr('RETURN_VALUE', lineno=1)
        ])
示例#29
0
文件: inspect.py 项目: thautwarm/AOP
import dis
from bytecode import Bytecode


def f(x):
    return x


dis.dis(f)

for each in Bytecode.from_code(f.__code__):
    print(each)
示例#30
0
    def test_label3(self):
        """
        CPython generates useless EXTENDED_ARG 0 in some cases. We need to
        properly track them as otherwise we can end up with broken offset for
        jumps.
        """
        source = """
            def func(x):
                if x == 1:
                    return x + 0
                elif x == 2:
                    return x + 1
                elif x == 3:
                    return x + 2
                elif x == 4:
                    return x + 3
                elif x == 5:
                    return x + 4
                elif x == 6:
                    return x + 5
                elif x == 7:
                    return x + 6
                elif x == 8:
                    return x + 7
                elif x == 9:
                    return x + 8
                elif x == 10:
                    return x + 9
                elif x == 11:
                    return x + 10
                elif x == 12:
                    return x + 11
                elif x == 13:
                    return x + 12
                elif x == 14:
                    return x + 13
                elif x == 15:
                    return x + 14
                elif x == 16:
                    return x + 15
                elif x == 17:
                    return x + 16
                return -1
        """
        code = get_code(source, function=True)
        bcode = Bytecode.from_code(code)
        concrete = bcode.to_concrete_bytecode()
        self.assertIsInstance(concrete, ConcreteBytecode)

        # Ensure that we do not generate broken code
        loc = {}
        exec(textwrap.dedent(source), loc)
        func = loc["func"]
        func.__code__ = bcode.to_code()
        for i, x in enumerate(range(1, 18)):
            self.assertEqual(func(x), x + i)
        self.assertEqual(func(18), -1)

        # Ensure that we properly round trip in such cases
        self.assertEqual(
            ConcreteBytecode.from_code(code).to_code().co_code, code.co_code
        )
示例#31
0
    def test_label3(self):
        """
        CPython generates useless EXTENDED_ARG 0 in some cases. We need to
        properly track them as otherwise we can end up with broken offset for
        jumps.
        """
        source = """
            def func(x):
                if x == 1:
                    return x + 0
                elif x == 2:
                    return x + 1
                elif x == 3:
                    return x + 2
                elif x == 4:
                    return x + 3
                elif x == 5:
                    return x + 4
                elif x == 6:
                    return x + 5
                elif x == 7:
                    return x + 6
                elif x == 8:
                    return x + 7
                elif x == 9:
                    return x + 8
                elif x == 10:
                    return x + 9
                elif x == 11:
                    return x + 10
                elif x == 12:
                    return x + 11
                elif x == 13:
                    return x + 12
                elif x == 14:
                    return x + 13
                elif x == 15:
                    return x + 14
                elif x == 16:
                    return x + 15
                elif x == 17:
                    return x + 16
                return -1
        """
        code = get_code(source, function=True)
        bcode = Bytecode.from_code(code)
        concrete = bcode.to_concrete_bytecode()
        self.assertIsInstance(concrete, ConcreteBytecode)

        # Ensure that we do not generate broken code
        loc = {}
        exec(textwrap.dedent(source), loc)
        func = loc['func']
        func.__code__ = bcode.to_code()
        for i, x in enumerate(range(1, 18)):
            self.assertEqual(func(x), x + i)
        self.assertEqual(func(18), -1)

        # Ensure that we properly round trip in such cases
        self.assertEqual(ConcreteBytecode.from_code(code).to_code().co_code,
                         code.co_code)
示例#32
0
 def check_stack_size(self, func):
     code = func.__code__
     bytecode = Bytecode.from_code(code)
     cfg = ControlFlowGraph.from_bytecode(bytecode)
     self.assertEqual(code.co_stacksize, cfg.compute_stacksize())
示例#33
0
    def modify(self, code, *, inner=False):
        initial_bytecode = Bytecode.from_code(code)

        modified_bytecode = Bytecode()
        modified_bytecode.first_lineno = initial_bytecode.first_lineno
        modified_bytecode.argcount = code.co_argcount
        modified_bytecode.argnames = initial_bytecode.argnames
        modified_bytecode.name = initial_bytecode.name
        modified_bytecode.freevars = code.co_freevars
        modified_bytecode.cellvars = code.co_cellvars

        first_line_no = initial_bytecode.first_lineno

        if inner:
            modified_bytecode.extend([
                Instr('LOAD_NAME', arg=self._command, lineno=first_line_no),
                Instr('LOAD_CONST',
                      arg=DebugCommand.STEP_OVER,
                      lineno=first_line_no),
                Instr('COMPARE_OP', arg=Compare.EQ, lineno=first_line_no),
                Instr('STORE_NAME', arg='is_over', lineno=first_line_no),
            ])

        # добавляем инструкции отладки перед первой строкой модуля
        if not inner:
            modified_bytecode.extend(
                self._get_trace_func_call_instructions(first_line_no))

        previous_line_no = first_line_no
        for instr in initial_bytecode:
            if not isinstance(instr, Instr):
                modified_bytecode.append(instr)
                continue

            if isinstance(instr.arg, types.CodeType):
                old_instr_name = instr.name
                new_co = self.modify(instr.arg, inner=True)
                instr.set(old_instr_name, new_co)

            skip = Label()
            if instr.lineno != previous_line_no:
                if inner:
                    modified_bytecode.extend([
                        Instr('LOAD_NAME', arg='is_over', lineno=instr.lineno),
                        Instr('POP_JUMP_IF_TRUE',
                              arg=skip,
                              lineno=instr.lineno)
                    ])
                    modified_bytecode.extend([
                        Instr('LOAD_NAME',
                              arg=self._command,
                              lineno=instr.lineno),
                        Instr('LOAD_CONST',
                              arg=DebugCommand.STEP_OUT,
                              lineno=instr.lineno),
                        Instr('COMPARE_OP',
                              arg=Compare.EQ,
                              lineno=instr.lineno),
                        Instr('POP_JUMP_IF_TRUE',
                              arg=skip,
                              lineno=instr.lineno)
                    ])

                modified_bytecode.extend(
                    self._get_trace_func_call_instructions(instr.lineno))

                if inner:
                    modified_bytecode.append(skip)
                previous_line_no = instr.lineno

            modified_bytecode.append(instr)

        code = modified_bytecode.to_code()

        return code
示例#34
0
def test_integration_dominator_tree():
    for_loop_cfg = cfg.CFG.from_bytecode(Bytecode.from_code(for_loop.__code__))
    dom_tree = pdt.DominatorTree.compute(for_loop_cfg)
    # Every node of the cfg should be in the dominator tree
    assert for_loop_cfg.nodes == dom_tree.nodes
示例#35
0
def test_integration_while_loop():
    while_loop_cfg = CFG.from_bytecode(Bytecode.from_code(Foo.receive.__code__))
    assert len(while_loop_cfg.nodes) == 3
    assert while_loop_cfg.entry_node.index == -1
    assert while_loop_cfg.exit_nodes.pop().index == sys.maxsize
示例#36
0
def disassemble(source, *, filename="<string>", function=False):
    code = get_code(source, filename=filename, function=function)
    return Bytecode.from_code(code)
示例#37
0
 def extract_bytecode(func):
     return Bytecode.from_code(func.__code__)