コード例 #1
0
    def test_call_without_arguments(self):
        module_block = BasicBlock([
            # def callee():
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="callee"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="callee"),
            # result = callee()
            Instr("LOAD_NAME", arg="callee"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="result"),
            # return result
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        callee_block = BasicBlock([
            Instr("LOAD_CONST", arg=0),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(callee_block)

        module_file = "simple_call.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #2
0
    def test_simple_control_dependency_2(self):
        # If condition evaluated to false, with two relevant variables (but no influence on result)
        def func() -> int:
            foo = 1
            bar = 2
            result = 3

            if foo == bar:
                result = 1

            return result

        init_basic_block = BasicBlock([
            # result = 3
            Instr("LOAD_CONST", arg=3),
            Instr("STORE_FAST", arg="result"),
        ])
        return_basic_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(init_basic_block)
        expected_instructions.extend(return_basic_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #3
0
    def test_simple_control_dependency_4(self):
        # If-elif-else with else branch true
        def func() -> int:
            foo = 1
            bar = 2

            if foo == bar:
                result = 1
            elif foo > bar:
                result = 2
            else:
                result = 3

            return result

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        else_block = BasicBlock([
            # result = 3
            Instr("LOAD_CONST", arg=3),
            Instr("STORE_FAST", arg="result")
        ])
        elif_cond = BasicBlock([
            # elif foo == 1:
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.GT),
            Instr("POP_JUMP_IF_FALSE", arg=else_block),
        ])
        if_cond = BasicBlock([
            # if foo == bar
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.EQ),
            Instr("POP_JUMP_IF_FALSE", arg=elif_cond),
        ])
        init_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # bar = 2
            Instr("LOAD_CONST", arg=2),
            Instr("STORE_FAST", arg="bar"),
        ])

        expected_instructions = []
        expected_instructions.extend(init_block)
        expected_instructions.extend(if_cond)
        expected_instructions.extend(elif_cond)
        expected_instructions.extend(else_block)
        expected_instructions.extend(return_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #4
0
    def _create_consecutive_blocks(
        bytecode_cfg: ControlFlowGraph, first: BasicBlock, amount: int
    ) -> Tuple[BasicBlock, ...]:
        """Split the given basic block into more blocks.

        The blocks are consecutive in the list of basic blocks.

        Args:
            bytecode_cfg: The control-flow graph
            first: The first basic block
            amount: The amount of consecutive blocks that should be created.

        Returns:
            A tuple of consecutive basic blocks
        """
        assert amount > 0, "Amount of created basic blocks must be positive."
        current: BasicBlock = first
        nodes: List[BasicBlock] = []
        # Can be any instruction, as it is discarded anyway.
        dummy_instruction = Instr("POP_TOP")
        for _ in range(amount):
            # Insert dummy instruction, which we can use to split off another block
            current.insert(0, dummy_instruction)
            current = bytecode_cfg.split_block(current, 1)
            nodes.append(current)

        # Move instructions back to first block.
        first.clear()
        first.extend(current)
        # Clear instructions in all created blocks.
        for node in nodes:
            node.clear()
        return tuple(nodes)
コード例 #5
0
    def test_nested_class(self):
        def func():
            # STORE_DEREF, LOAD_CLOSURE, LOAD_CLASSDEREF
            x = []

            class NestedClass:
                y = x

            class_attr = NestedClass.y

            result = class_attr
            return result

        freevar_x = FreeVar("x")
        cellvar_x = CellVar("x")
        function_block = BasicBlock([
            # x = []
            Instr("BUILD_LIST", arg=0),
            Instr("STORE_DEREF", arg=cellvar_x),

            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # class_attr = NestedClass.y
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("LOAD_ATTR", arg="y"),
            Instr("STORE_FAST", arg="class_attr"),

            # result = class_attr
            Instr("LOAD_FAST", arg="class_attr"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # y = x
            Instr("LOAD_CLASSDEREF", arg=freevar_x),
            Instr("STORE_NAME", arg="y"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_nested_class")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #6
0
    def test_closures(self):
        # Closure function

        freevar_foo = FreeVar("foo")
        cellvar_foo = CellVar("foo")
        module_block = BasicBlock([
            # def outer_function(foo):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="outer_function"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="outer_function"),

            # inner = outer_function('a')
            Instr("LOAD_NAME", arg="outer_function"),
            Instr("LOAD_CONST", arg="a"),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_NAME", arg="inner"),

            # result = inner("abc")
            Instr("LOAD_NAME", arg="inner"),
            Instr("LOAD_CONST", arg="abc"),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_NAME", arg="result"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        outer_function_block = BasicBlock([
            # def inner_function(bar):
            Instr("LOAD_CLOSURE", arg=cellvar_foo),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="outer_function.<locals>.inner_function"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("STORE_FAST", arg="inner_function"),

            # return inner
            Instr("LOAD_FAST", arg="inner_function"),
            Instr("RETURN_VALUE"),
        ])
        inner_function_block = BasicBlock([
            # return foo in bar
            Instr("LOAD_DEREF", arg=freevar_foo),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.IN),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(outer_function_block)
        expected_instructions.extend(inner_function_block)

        module_file = "closure.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(expected_instructions), len(dynamic_slice.sliced_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #7
0
    def test_data_dependency_4(self):
        # Explicit attribute dependencies (full cover)
        module_block = BasicBlock([
            # class Foo:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="Foo"),
            # ob.attr1 = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_NAME", arg="ob"),
            Instr("STORE_ATTR", arg="attr1"),
            # ob.attr2 = ob.attr2.append(ob.attr1)
            Instr("LOAD_NAME", arg="ob"),
            Instr("LOAD_ATTR", arg="attr2"),
            Instr("LOAD_METHOD", arg="append"),
            Instr("LOAD_NAME", arg="ob"),
            Instr("LOAD_ATTR", arg="attr1"),
            Instr("CALL_METHOD", arg=1),
            Instr("LOAD_NAME", arg="ob"),
            Instr("STORE_ATTR", arg="attr2"),

            # result = ob.attr2
            Instr("LOAD_NAME", arg="ob"),
            Instr("LOAD_ATTR", arg="attr2"),
            Instr("STORE_NAME", arg="result"),
            # return
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        class_attr_block = BasicBlock([
            # attr2 = [1, 2, 3]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_NAME", arg="attr2"),
            # return
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(class_attr_block)

        module_file = "attribute_dependencies.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #8
0
    def test_call_unused_argument(self):
        # Call with two arguments, one of which is used in the callee

        module_block = BasicBlock([
            # def callee():
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_CONST", arg=('a', 'b')),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="callee"),
            Instr("MAKE_FUNCTION", arg=4),
            Instr("STORE_NAME", arg="callee"),
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_NAME", arg="foo"),
            # bar = 2
            # This argument is not used by the callee and should therefore be excluded.
            # But it is an implicit data dependency of the call and is incorrectly and imprecisely included.
            # Instr("LOAD_CONST", arg=2),
            # Instr("STORE_NAME", arg="bar"),

            # result = callee()
            Instr("LOAD_NAME", arg="callee"),
            Instr("LOAD_NAME", arg="foo"),
            # Instr("LOAD_NAME", arg="bar"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="result"),
            # return result
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        callee_block = BasicBlock([
            # return a
            Instr("LOAD_FAST", arg="a"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(callee_block)

        module_file = "simple_call_arg.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #9
0
ファイル: emit_IR.py プロジェクト: porglezomp/scheme-jit
    def _add_is_function_check(
            self, function_expr: bytecode.Parameter,
            add_to_block: bytecode.BasicBlock) -> None:
        typeof_var = bytecode.Var(next(self.var_names))
        typeof_instr = bytecode.TypeofInst(
            typeof_var, function_expr)
        is_function_var = bytecode.Var(next(self.var_names))
        is_function_instr = bytecode.BinopInst(
            is_function_var, bytecode.Binop.SYM_EQ,
            typeof_var, bytecode.SymLit(sexp.SSym('function'))
        )
        branch_instr = bytecode.BrnInst(is_function_var, IS_FUNCTION_TRAP)

        for instr in [typeof_instr, is_function_instr, branch_instr]:
            add_to_block.add_inst(instr)
コード例 #10
0
    def test_builtin_addresses(self):
        def func():
            test_dict = {1: "one", 2: "two"}
            # noinspection PyListCreation
            test_list = [1, 2]

            test_list.append(3)

            result = test_dict.get(1)
            return result

        function_block = BasicBlock([
            # test_dict = {1: "one", 2: "two"}
            Instr("LOAD_CONST", arg="one"),
            Instr("LOAD_CONST", arg="two"),
            Instr("LOAD_CONST", arg=(1, 2)),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("STORE_FAST", arg="test_dict"),

            # result = test_dict.get(1)
            Instr("LOAD_FAST", arg="test_dict"),
            Instr("LOAD_METHOD", arg="get"),
            Instr("LOAD_CONST", arg=1),
            Instr("CALL_METHOD", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_builtin_addresses")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #11
0
    def test_simple_loop(self):
        def func():
            result = 0
            for i in range(0, 3):
                result += i
            return result

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        loop_header = BasicBlock([
            Instr("FOR_ITER", arg=return_block),
        ])
        loop_block = BasicBlock([
            # result += i
            Instr("STORE_FAST", arg="i"),
            Instr("LOAD_FAST", arg="result"),
            Instr("LOAD_FAST", arg="i"),
            Instr("INPLACE_ADD"),
            Instr("STORE_FAST", arg="result"),
            Instr("JUMP_ABSOLUTE", arg=loop_header),
        ])
        loop_setup = BasicBlock([
            # for i in range(0, 3):
            Instr("LOAD_GLOBAL", arg="range"),
            Instr("LOAD_CONST", arg=0),
            Instr("LOAD_CONST", arg=3),
            Instr("CALL_FUNCTION", arg=2),
            Instr("GET_ITER"),
        ])
        init_block = BasicBlock([
            Instr("LOAD_CONST", arg=0),
            Instr("STORE_FAST", arg="result"),
        ])

        expected_instructions = []
        expected_instructions.extend(init_block)
        expected_instructions.extend(loop_setup)
        expected_instructions.extend(loop_header)
        expected_instructions.extend(loop_block)
        expected_instructions.extend(return_block)

        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_simple_loop")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #12
0
    def test_call_with_arguments(self):
        # Call with two arguments, one of which is used in the callee

        module_block = BasicBlock([
            # def callee():
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_CONST", arg=('a', 'b')),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="callee"),
            Instr("MAKE_FUNCTION", arg=4),
            Instr("STORE_NAME", arg="callee"),
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_NAME", arg="foo"),
            # bar = 2
            Instr("LOAD_CONST", arg=2),
            Instr("STORE_NAME", arg="bar"),

            # result = callee()
            Instr("LOAD_NAME", arg="callee"),
            Instr("LOAD_NAME", arg="foo"),
            Instr("LOAD_NAME", arg="bar"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="result"),
            # return result
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        callee_block = BasicBlock([
            # return a
            Instr("LOAD_FAST", arg="a"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(callee_block)

        module_file = "simple_call_arg.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #13
0
    def test_simple_control_dependency_1(self):
        # If condition evaluated to true, with relevant variable foo
        def func() -> int:
            foo = 1
            result = 3

            if foo == 1:
                result = 1

            return result

        return_basic_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        if_basic_block = BasicBlock([
            # result = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="result"),
        ])
        init_basic_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # if foo == 1
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_CONST", arg=1),
            Instr("COMPARE_OP", arg=Compare.EQ),
            Instr("POP_JUMP_IF_FALSE", arg=return_basic_block),
        ])

        expected_instructions = []
        expected_instructions.extend(init_basic_block)
        expected_instructions.extend(if_basic_block)
        expected_instructions.extend(return_basic_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #14
0
 def copy_propagate_block(self, block: BasicBlock) -> None:
     copies: Dict[Var, Parameter] = {}
     for i, inst in enumerate(block.instructions):
         if isinstance(inst, CopyInst):
             value = inst.value
             while value in copies:
                 assert isinstance(value, Var)
                 value = copies[value]
             copies[inst.dest] = value
         else:
             block.instructions[i] = inst.copy_prop(copies)
コード例 #15
0
ファイル: test_misc.py プロジェクト: vedanova/neoinvoice
    def test_blocks_broken_jump(self):
        block = BasicBlock()
        code = ControlFlowGraph()
        code[0].append(Instr('JUMP_ABSOLUTE', block))

        expected = textwrap.dedent("""
            block1:
                JUMP_ABSOLUTE <error: unknown block>

        """).lstrip("\n")
        self.check_dump_bytecode(code, expected)
コード例 #16
0
ファイル: test_cfg.py プロジェクト: st-rnd/bytecode
    def test_get_block_index(self):
        blocks = ControlFlowGraph()
        block0 = blocks[0]
        block1 = blocks.add_block()
        block2 = blocks.add_block()
        self.assertEqual(blocks.get_block_index(block0), 0)
        self.assertEqual(blocks.get_block_index(block1), 1)
        self.assertEqual(blocks.get_block_index(block2), 2)

        other_block = BasicBlock()
        self.assertRaises(ValueError, blocks.get_block_index, other_block)
コード例 #17
0
 def mergable(block: BasicBlock) -> bool:
     # @TODO: Branch switching for conditional+unconditional jumps.
     # It would be nice to be able to use the better one of the two
     # tails.
     assert self.preds
     last = block.instructions[-1]
     if isinstance(last, JmpInst):
         return len(self.preds[id(last.target)]) == 1
     elif isinstance(last, TrapInst) and len(block.instructions) > 1:
         prev = block.instructions[-2]
         if isinstance(prev, (BrInst, BrnInst)):
             if not len(self.preds[id(prev.target)]) == 1:
                 return False
             new_target = block.split_after(-2)
             block.instructions[-1] = JmpInst(prev.target)
             if isinstance(prev, BrInst):
                 block.instructions[-2] = BrnInst(prev.cond, new_target)
             else:
                 block.instructions[-2] = BrInst(prev.cond, new_target)
             return True
     return False
コード例 #18
0
    def test_import_star(self):
        # IMPORT_STAR with access to immutable variable
        main_module_block = BasicBlock([
            # from tests.slicer.example_modules.import_star_def import *
            Instr("IMPORT_NAME",
                  "tests.slicer.example_modules.import_star_def"),
            Instr("IMPORT_STAR"),

            # result = Foo.test
            Instr("LOAD_NAME", arg="star_imported"),
            Instr("STORE_NAME", arg="result"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])
        dependency_module_block = BasicBlock([
            # star_imported = "test"
            Instr("LOAD_CONST", arg="test"),
            Instr("STORE_NAME", arg="star_imported"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(main_module_block)
        expected_instructions.extend(dependency_module_block)

        module_dependency_file = "import_star_def.py"
        module_dependency_path = example_modules_path + module_dependency_file
        instrument_module(module_dependency_path)

        module_file = "import_star_main.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)

        compile_module(module_dependency_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #19
0
    def test_lambda(self):
        def func():
            x = lambda a: a + 10

            result = x(1)
            return result

        function_block = BasicBlock([
            # x = lambda a: a + 10
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_lambda.<locals>.func.<locals>.<lambda>"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="x"),

            # result = x(1)
            Instr("LOAD_FAST", arg="x"),
            Instr("LOAD_CONST", arg=1),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        lambda_block = BasicBlock([
            # lambda a: a + 10
            Instr("LOAD_FAST", arg="a"),
            Instr("LOAD_CONST", arg=10),
            Instr("BINARY_ADD"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(lambda_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_lambda")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #20
0
    def test_invalid_arg(self):
        label = Label()
        block = BasicBlock()

        # EXTENDED_ARG
        self.assertRaises(ValueError, Instr, "EXTENDED_ARG", 0)

        # has_jump()
        self.assertRaises(TypeError, Instr, "JUMP_ABSOLUTE", 1)
        self.assertRaises(TypeError, Instr, "JUMP_ABSOLUTE", 1.0)
        Instr("JUMP_ABSOLUTE", label)
        Instr("JUMP_ABSOLUTE", block)

        # hasfree
        self.assertRaises(TypeError, Instr, "LOAD_DEREF", "x")
        Instr("LOAD_DEREF", CellVar("x"))
        Instr("LOAD_DEREF", FreeVar("x"))

        # haslocal
        self.assertRaises(TypeError, Instr, "LOAD_FAST", 1)
        Instr("LOAD_FAST", "x")

        # hasname
        self.assertRaises(TypeError, Instr, "LOAD_NAME", 1)
        Instr("LOAD_NAME", "x")

        # hasconst
        self.assertRaises(ValueError, Instr, "LOAD_CONST")  # UNSET
        self.assertRaises(ValueError, Instr, "LOAD_CONST", label)
        self.assertRaises(ValueError, Instr, "LOAD_CONST", block)
        Instr("LOAD_CONST", 1.0)
        Instr("LOAD_CONST", object())

        # hascompare
        self.assertRaises(TypeError, Instr, "COMPARE_OP", 1)
        Instr("COMPARE_OP", Compare.EQ)

        # HAVE_ARGUMENT
        self.assertRaises(ValueError, Instr, "CALL_FUNCTION", -1)
        self.assertRaises(TypeError, Instr, "CALL_FUNCTION", 3.0)
        Instr("CALL_FUNCTION", 3)

        # test maximum argument
        self.assertRaises(ValueError, Instr, "CALL_FUNCTION", 2147483647 + 1)
        instr = Instr("CALL_FUNCTION", 2147483647)
        self.assertEqual(instr.arg, 2147483647)

        # not HAVE_ARGUMENT
        self.assertRaises(ValueError, Instr, "NOP", 0)
        Instr("NOP")
コード例 #21
0
ファイル: test_cfg.py プロジェクト: adamchainz/bytecode
    def test_iter_invalid_types(self):
        # Labels are not allowed in basic blocks
        block = BasicBlock()
        block.append(Label())
        with self.assertRaises(ValueError):
            list(block)

        # Only one jump allowed and only at the end
        block = BasicBlock()
        block2 = BasicBlock()
        block.extend([Instr('JUMP_ABSOLUTE', block2),
                     Instr('NOP')])
        with self.assertRaises(ValueError):
            list(block)

        # jump target must be a BasicBlock
        block = BasicBlock()
        label = Label()
        block.extend([Instr('JUMP_ABSOLUTE', label)])
        with self.assertRaises(ValueError):
            list(block)
コード例 #22
0
ファイル: emit_IR.py プロジェクト: porglezomp/scheme-jit
 def _add_arity_check(
         self, function_expr: bytecode.Parameter,
         add_to_block: bytecode.BasicBlock, arity: int) -> None:
     arity_var = bytecode.Var(next(self.var_names))
     add_to_block.add_inst(bytecode.ArityInst(arity_var, function_expr))
     correct_arity_var = bytecode.Var(next(self.var_names))
     add_to_block.add_inst(bytecode.BinopInst(
         correct_arity_var, bytecode.Binop.NUM_EQ,
         arity_var, bytecode.NumLit(sexp.SNum(arity))
     ))
     add_to_block.add_inst(bytecode.BrnInst(correct_arity_var, ARITY_TRAP))
コード例 #23
0
ファイル: runner.py プロジェクト: porglezomp/scheme-jit
 def inst_function(
         name: SSym, params: List[Var],
         return_val: Optional[bytecode.Parameter], *insts: Inst,
         ) -> SFunction:
     """Create a function out of the instructions in insts."""
     begin = BasicBlock('bb0')
     for inst in insts:
         begin.add_inst(inst)
     if return_val is not None:
         begin.add_inst(bytecode.ReturnInst(return_val))
     code = Function(params, begin)
     param_syms = [SSym(p.name) for p in params]
     return SFunction(name, param_syms, Nil, code, False)
コード例 #24
0
    def test_with_extended_arg(self):
        def func():
            p = [1, 2, 3, 4, 5, 6]
            # noinspection PyUnusedLocal
            unused = p
            q, r, *s, t = p  # With extended argument

            result = q, r
            return result

        module_block = BasicBlock([
            # p = [1, 2, 3, 4, 5, 6]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("LOAD_CONST", arg=4),
            Instr("LOAD_CONST", arg=5),
            Instr("LOAD_CONST", arg=6),
            Instr("BUILD_LIST", arg=6),
            Instr("STORE_FAST", arg="p"),
            # q, r, *s, t = p
            Instr("LOAD_FAST", arg="p"),
            # Instr("EXTENDED_ARG", arg=1),  # EXTENDED_ARG can not be in a slice
            Instr("UNPACK_EX", arg=258),
            Instr("STORE_FAST", arg="q"),
            Instr("STORE_FAST", arg="r"),

            # result = q
            Instr("LOAD_FAST", arg="q"),
            Instr("LOAD_FAST", arg="r"),
            Instr("BUILD_TUPLE", arg=2),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_with_extended_arg")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #25
0
 def block_transfer(
     self,
     env: EvalEnv,
     block: BasicBlock,
     types: TypeMap,
     values: ValueMap,
 ) -> List[Tuple[TypeMap, ValueMap]]:
     abstract = []
     for i, inst in enumerate(block.instructions):
         abstract.append((copy.copy(types), copy.copy(values)))
         inst.run_abstract(env, types, values)
         inst = inst.constant_fold(types, values)
         block.instructions[i] = inst
         if isinstance(inst, CallInst):
             func = values[inst.func]
             if (isinstance(func, SFunction) and self.should_inline(
                     env, func, inst.specialization)):  # noqa
                 code = func.get_specialized(inst.specialization)
                 code = copy.deepcopy(code)
                 opt = FunctionOptimizer(code)
                 opt.specialization = inst.specialization
                 opt.inputs = tuple(values[x] for x in inst.args)
                 opt.banned_from_inline = (self.banned_from_inline
                                           | {func.name})
                 opt.optimize(env)
                 if opt.result is not None:
                     ty, val = opt.result
                     types[inst.dest] = ty
                     values[inst.dest] = val
                 if id(block) not in self.inlines:
                     self.inlines[id(block)] = (block, {})
                 self.inlines[id(block)][1][i] = code
         if isinstance(inst, ReturnInst):
             ret_ty = types[inst.ret]
             ret_val = values[inst.ret]
             if self.result is None:
                 self.result = (ret_ty, ret_val)
             else:
                 self.result = (self.result[0].join(ret_ty), self.result[1]
                                if self.result[1] == ret_val else None)
     abstract.append((copy.copy(types), copy.copy(values)))
     return abstract
コード例 #26
0
    def test_mod_untraced_object(self):
        def func():
            lst = [('foo', '3'), ('bar', '1'), ('foobar', '2')]
            lst.sort(
            )  # This is incorrectly excluded, since it is not known that the method modifies the list

            result = lst
            return result

        function_block = BasicBlock([
            # lst = [('foo', '3'), ('bar', '1'), ('foobar', '2')]
            Instr("LOAD_CONST", arg=('foo', '3')),
            Instr("LOAD_CONST", arg=('bar', '1')),
            Instr("LOAD_CONST", arg=('foobar', '2')),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_FAST", arg="lst"),

            # lst.sort()
            # This is incorrectly excluded, since it is not known that the method modifies the list
            Instr("LOAD_FAST", arg="lst"),
            Instr("LOAD_METHOD", arg="sort"),
            Instr("CALL_METHOD", arg=0),
            Instr("POP_TOP"),

            # result = lst
            Instr("LOAD_FAST", arg="lst"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        dynamic_slice = slice_function_at_return(
            func.__code__, test_name="test_mod_untraced_object")
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #27
0
ファイル: test_cfg.py プロジェクト: st-rnd/bytecode
    def test_iter_invalid_types(self):
        # Labels are not allowed in basic blocks
        block = BasicBlock()
        block.append(Label())
        with self.assertRaises(ValueError):
            list(block)

        # Only one jump allowed and only at the end
        block = BasicBlock()
        block2 = BasicBlock()
        block.extend([Instr('JUMP_ABSOLUTE', block2),
                      Instr('NOP')])
        with self.assertRaises(ValueError):
            list(block)

        # jump target must be a BasicBlock
        block = BasicBlock()
        label = Label()
        block.extend([Instr('JUMP_ABSOLUTE', label)])
        with self.assertRaises(ValueError):
            list(block)
コード例 #28
0
    def test_dunder_definition(self):
        def func():
            class NestedClass:
                def __init__(
                    self
                ):  # Definition of dunder methods wrongly excluded, these are not explicitly loaded
                    self.x = 1

            result = NestedClass()
            return result

        function_block = BasicBlock([
            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # result = NestedClass()
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # Definition of dunder methods are wrongly excluded, since these are not explicitly loaded
            # def __init__(self):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr(
                "LOAD_CONST",
                arg=
                "IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
                "func.<locals>.NestedClass.__init__"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="__init__"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        init_block = BasicBlock([
            # self.x = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        expected_instructions.extend(init_block)
        dynamic_slice = slice_function_at_return(
            func.__code__, test_name="test_dunder_definition")
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #29
0
    def test_exception(self):
        # Exception
        def func():
            foo = 1
            bar = 0

            try:
                result = 0 / 0
            except ZeroDivisionError:
                result = foo + bar

            return result

        self.assertEqual(func(), 1)

        dummy_block = BasicBlock([])

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        try_block = BasicBlock([
            # result = foo / bar <- did somehow effect slicing criterion...
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("BINARY_TRUE_DIVIDE"),

            # except ZeroDivisionError:
            Instr("DUP_TOP"),
            Instr("LOAD_GLOBAL", arg="ZeroDivisionError"),
            Instr("COMPARE_OP", arg=Compare.EXC_MATCH),
            Instr("POP_JUMP_IF_FALSE", arg=dummy_block),
        ])
        except_block = BasicBlock([
            # result = foo + bar
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("BINARY_ADD"),
            Instr("STORE_FAST", arg="result"),
            Instr("JUMP_FORWARD", arg=dummy_block),
        ])
        function_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST",
                  arg=1),  # <- excluded because no stack simulation
            Instr("STORE_FAST", arg="foo"),
            # bar = 0
            Instr("LOAD_CONST",
                  arg=0),  # <- excluded because no stack simulation
            Instr("STORE_FAST", arg="bar"),

            # try:
            # Instr("SETUP_FINALLY", arg=try_block),
        ])

        expected_instructions = []
        expected_instructions.extend(return_block)
        expected_instructions.extend(except_block)
        expected_instructions.extend(function_block)
        expected_instructions.extend(try_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
コード例 #30
0
 def test_copy(self):
     block = BasicBlock([Instr("NOP")])
     next_block = BasicBlock()
     block.next_block = next_block
     self.assertEqual(block, block.copy())
     self.assertIs(next_block, block.copy().next_block)
コード例 #31
0
 def test_slice(self):
     block = BasicBlock([Instr("NOP")])
     next_block = BasicBlock()
     block.next_block = next_block
     self.assertEqual(block, block[:])
     self.assertIs(next_block, block[:].next_block)