示例#1
0
 def test_build_tuple_unpack_seq_const(self):
     # x, y = (3, 4)
     code = Bytecode([
         Instr('LOAD_CONST', 3),
         Instr('LOAD_CONST', 4),
         Instr('BUILD_TUPLE', 2),
         Instr('UNPACK_SEQUENCE', 2),
         Instr('STORE_NAME', 'x'),
         Instr('STORE_NAME', 'y')
     ])
     self.check(code, Instr('LOAD_CONST', (3, 4)),
                Instr('UNPACK_SEQUENCE', 2), Instr('STORE_NAME', 'x'),
                Instr('STORE_NAME', 'y'))
示例#2
0
    def test_dont_optimize(self):
        # x = 3 < 5
        code = Bytecode([
            Instr('LOAD_CONST', 3),
            Instr('LOAD_CONST', 5),
            Instr('COMPARE_OP', Compare.LT),
            Instr('STORE_NAME', 'x'),
            Instr('LOAD_CONST', None),
            Instr('RETURN_VALUE')
        ])
        self.check_dont_optimize(code)

        # x = (10, 20, 30)[1:]
        code = Bytecode([
            Instr('LOAD_CONST', (10, 20, 30)),
            Instr('LOAD_CONST', 1),
            Instr('LOAD_CONST', None),
            Instr('BUILD_SLICE', 2),
            Instr('BINARY_SUBSCR'),
            Instr('STORE_NAME', 'x')
        ])
        self.check_dont_optimize(code)
示例#3
0
 def test_negative_size_build(self):
     opnames = (
         "BUILD_TUPLE",
         "BUILD_LIST",
         "BUILD_SET",
     )
     for opname in opnames:
         with self.subTest():
             code = Bytecode()
             code.first_lineno = 1
             code.extend([Instr(opname, 1)])
             with self.assertRaises(RuntimeError):
                 code.compute_stacksize()
示例#4
0
    def test_dead_code_jump(self):
        label = Label()
        code = Bytecode([
            Instr('LOAD_NAME', 'x'),
            Instr('JUMP_ABSOLUTE', label),
            # dead code
            Instr('LOAD_NAME', 'y'),
            Instr('STORE_NAME', 'test'),
            label,
            Instr('STORE_NAME', 'test')
        ])

        self.check(code, Instr('LOAD_NAME', 'x'), Instr('STORE_NAME', 'test'))
示例#5
0
    def test_dont_optimize(self):
        # x = 3 < 5
        code = Bytecode([
            Instr("LOAD_CONST", 3),
            Instr("LOAD_CONST", 5),
            Instr("COMPARE_OP", Compare.LT),
            Instr("STORE_NAME", "x"),
            Instr("LOAD_CONST", None),
            Instr("RETURN_VALUE"),
        ])
        self.check_dont_optimize(code)

        # x = (10, 20, 30)[1:]
        code = Bytecode([
            Instr("LOAD_CONST", (10, 20, 30)),
            Instr("LOAD_CONST", 1),
            Instr("LOAD_CONST", None),
            Instr("BUILD_SLICE", 2),
            Instr("BINARY_SUBSCR"),
            Instr("STORE_NAME", "x"),
        ])
        self.check_dont_optimize(code)
示例#6
0
    def test_dead_code_jump(self):
        label = Label()
        code = Bytecode([
            Instr("LOAD_NAME", "x"),
            Instr("JUMP_ABSOLUTE", label),
            # dead code
            Instr("LOAD_NAME", "y"),
            Instr("STORE_NAME", "test"),
            label,
            Instr("STORE_NAME", "test"),
        ])

        self.check(code, Instr("LOAD_NAME", "x"), Instr("STORE_NAME", "test"))
示例#7
0
    def test_build_list_unpack_seq(self):
        for build_list in ('BUILD_TUPLE', 'BUILD_LIST'):
            # x, = [a]
            code = Bytecode([
                Instr('LOAD_NAME', 'a'),
                Instr(build_list, 1),
                Instr('UNPACK_SEQUENCE', 1),
                Instr('STORE_NAME', 'x')
            ])
            self.check(code, Instr('LOAD_NAME', 'a'), Instr('STORE_NAME', 'x'))

            # x, y = [a, b]
            code = Bytecode([
                Instr('LOAD_NAME', 'a'),
                Instr('LOAD_NAME', 'b'),
                Instr(build_list, 2),
                Instr('UNPACK_SEQUENCE', 2),
                Instr('STORE_NAME', 'x'),
                Instr('STORE_NAME', 'y')
            ])
            self.check(code, Instr('LOAD_NAME', 'a'), Instr('LOAD_NAME', 'b'),
                       Instr('ROT_TWO'), Instr('STORE_NAME', 'x'),
                       Instr('STORE_NAME', 'y'))

            # x, y, z = [a, b, c]
            code = Bytecode([
                Instr('LOAD_NAME', 'a'),
                Instr('LOAD_NAME', 'b'),
                Instr('LOAD_NAME', 'c'),
                Instr(build_list, 3),
                Instr('UNPACK_SEQUENCE', 3),
                Instr('STORE_NAME', 'x'),
                Instr('STORE_NAME', 'y'),
                Instr('STORE_NAME', 'z')
            ])
            self.check(code, Instr('LOAD_NAME', 'a'), Instr('LOAD_NAME', 'b'),
                       Instr('LOAD_NAME', 'c'), Instr('ROT_THREE'),
                       Instr('ROT_TWO'), Instr('STORE_NAME', 'x'),
                       Instr('STORE_NAME', 'y'), Instr('STORE_NAME', 'z'))
示例#8
0
 def test_handling_of_extended_arg(self):
     code = Bytecode()
     code.first_lineno = 3
     code.extend(
         [
             Instr("LOAD_CONST", 7),
             Instr("STORE_NAME", "x"),
             Instr("EXTENDED_ARG", 1),
             Instr("LOAD_CONST", 8),
             Instr("STORE_NAME", "y"),
         ]
     )
     self.assertEqual(code.compute_stacksize(), 1)
示例#9
0
    def test_compute_jumps_convergence(self):
        # Consider the following sequence of instructions:
        #
        #     JUMP_ABSOLUTE Label1
        #     JUMP_ABSOLUTE Label2
        #     ...126 instructions...
        #   Label1:                 Offset 254 on first pass, 256 second pass
        #     NOP
        #     ... many more instructions ...
        #   Label2:                 Offset > 256 on first pass
        #
        # On first pass of compute_jumps(), Label2 will be at address 254, so
        # that value encodes into the single byte arg of JUMP_ABSOLUTE.
        #
        # On second pass compute_jumps() the instr at Label1 will have offset
        # of 256 so will also be given an EXTENDED_ARG.
        #
        # Thus we need to make an additional pass.  This test only verifies
        # case where 2 passes is insufficient but three is enough.
        #
        # On Python > 3.10 we need to double the number since the offset is now
        # in term of instructions and not bytes.

        # Create code from comment above.
        code = Bytecode()
        label1 = Label()
        label2 = Label()
        nop = "NOP"
        code.append(Instr("JUMP_ABSOLUTE", label1))
        code.append(Instr("JUMP_ABSOLUTE", label2))
        # Need 254 * 2 + 2 since the arg will change by 1 instruction rather than 2
        # bytes.
        for x in range(4, 510 if OFFSET_AS_INSTRUCTION else 254, 2):
            code.append(Instr(nop))
        code.append(label1)
        code.append(Instr(nop))
        for x in range(
                514 if OFFSET_AS_INSTRUCTION else 256,
                600 if OFFSET_AS_INSTRUCTION else 300,
                2,
        ):
            code.append(Instr(nop))
        code.append(label2)
        code.append(Instr(nop))

        # This should pass by default.
        code.to_code()

        # Try with max of two passes:  it should raise
        with self.assertRaises(RuntimeError):
            code.to_code(compute_jumps_passes=2)
示例#10
0
    def test_compare_op_unary_not(self):
        for op, not_op in (
            (Compare.IN, Compare.NOT_IN),  # in => not in
            (Compare.NOT_IN, Compare.IN),  # not in => in
            (Compare.IS, Compare.IS_NOT),  # is => is not
            (Compare.IS_NOT, Compare.IS),  # is not => is
        ):
            code = Bytecode([
                Instr("LOAD_NAME", "a"),
                Instr("LOAD_NAME", "b"),
                Instr("COMPARE_OP", op),
                Instr("UNARY_NOT"),
                Instr("STORE_NAME", "x"),
            ])
            self.check(
                code,
                Instr("LOAD_NAME", "a"),
                Instr("LOAD_NAME", "b"),
                Instr("COMPARE_OP", not_op),
                Instr("STORE_NAME", "x"),
            )

        # don't optimize:
        # x = not (a and b is True)
        label_instr5 = Label()
        code = Bytecode([
            Instr("LOAD_NAME", "a"),
            Instr("JUMP_IF_FALSE_OR_POP", label_instr5),
            Instr("LOAD_NAME", "b"),
            Instr("LOAD_CONST", True),
            Instr("COMPARE_OP", Compare.IS),
            label_instr5,
            Instr("UNARY_NOT"),
            Instr("STORE_NAME", "x"),
            Instr("LOAD_CONST", None),
            Instr("RETURN_VALUE"),
        ])
        self.check_dont_optimize(code)
示例#11
0
    def test_uncond_jump_to_uncond_jump(self):
        # Replace JUMP_FORWARD t1 jumping to JUMP_FORWARD t2
        # with JUMP_ABSOLUTE t2

        label = Label()
        label2 = Label()
        label3 = Label()
        label4 = Label()
        code = Bytecode([
            Instr("LOAD_NAME", "test"),
            Instr("POP_JUMP_IF_TRUE", label),
            # redundant jump
            Instr("JUMP_FORWARD", label2),
            label,
            Instr("LOAD_CONST", 1),
            Instr("STORE_NAME", "x"),
            Instr("LOAD_NAME", "test"),
            Instr("POP_JUMP_IF_TRUE", label3),
            label2,
            Instr("JUMP_FORWARD", label4),
            label3,
            Instr("LOAD_CONST", 1),
            Instr("STORE_NAME", "x"),
            label4,
            Instr("LOAD_CONST", None),
            Instr("RETURN_VALUE"),
        ])

        label = Label()
        label3 = Label()
        label4 = Label()
        self.check(
            code,
            Instr("LOAD_NAME", "test"),
            Instr("POP_JUMP_IF_TRUE", label),
            # JUMP_FORWARD label2 was replaced with JUMP_ABSOLUTE label4
            Instr("JUMP_ABSOLUTE", label4),
            label,
            Instr("LOAD_CONST", 1),
            Instr("STORE_NAME", "x"),
            Instr("LOAD_NAME", "test"),
            Instr("POP_JUMP_IF_TRUE", label3),
            Instr("JUMP_FORWARD", label4),
            label3,
            Instr("LOAD_CONST", 1),
            Instr("STORE_NAME", "x"),
            label4,
            Instr("LOAD_CONST", None),
            Instr("RETURN_VALUE"),
        )
示例#12
0
 def test_negative_size_unary(self):
     opnames = (
         "UNARY_POSITIVE",
         "UNARY_NEGATIVE",
         "UNARY_NOT",
         "UNARY_INVERT",
     )
     for opname in opnames:
         with self.subTest():
             code = Bytecode()
             code.first_lineno = 1
             code.extend([Instr(opname)])
             with self.assertRaises(RuntimeError):
                 code.compute_stacksize()
示例#13
0
        def r_compile():
            jit_func = Aware.f(self, id(start_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
示例#14
0
 def test_negative_size_unary_with_disable_check_of_pre_and_post(self):
     opnames = (
         "UNARY_POSITIVE",
         "UNARY_NEGATIVE",
         "UNARY_NOT",
         "UNARY_INVERT",
     )
     for opname in opnames:
         with self.subTest():
             code = Bytecode()
             code.first_lineno = 1
             code.extend([Instr(opname)])
             co = code.to_code(check_pre_and_post=False)
             self.assertEqual(co.co_stacksize, 0)
示例#15
0
    def test_label(self):
        code = Bytecode()
        label = Label()
        code.extend([Instr('LOAD_CONST', 'hello', lineno=1),
                     Instr('JUMP_FORWARD', label, lineno=1),
                     label,
                     Instr('POP_TOP', lineno=1)])

        code = code.to_concrete_bytecode()
        expected = [ConcreteInstr('LOAD_CONST', 0, lineno=1),
                    ConcreteInstr('JUMP_FORWARD', 0, lineno=1),
                    ConcreteInstr('POP_TOP', lineno=1)]
        self.assertListEqual(list(code), expected)
        self.assertListEqual(code.consts, ['hello'])
示例#16
0
    def _make_bytecode(self, source, template_locator):
        instructions = []
        symbol_table = {"write_func": io.StringIO.write}

        parser_obj = parser.Parser(self._template_locator)
        sequence = parser_obj.parse(self._get_chunks(source))

        for item in sequence.elements:
            instructions += item.make_bytecode(symbol_table)

        bytecode = Bytecode(instructions +
                            [Instr("LOAD_CONST", None),
                             Instr("RETURN_VALUE")])
        return bytecode.to_code()
示例#17
0
 def test_handling_of_set_lineno(self):
     code = Bytecode()
     code.first_lineno = 3
     code.extend([
         Instr("LOAD_CONST", 7),
         Instr("STORE_NAME", "x"),
         SetLineno(4),
         Instr("LOAD_CONST", 8),
         Instr("STORE_NAME", "y"),
         SetLineno(5),
         Instr("LOAD_CONST", 9),
         Instr("STORE_NAME", "z"),
     ])
     self.assertEqual(code.compute_stacksize(), 1)
示例#18
0
    def test_jump_if_false_to_jump_if_false(self):
        # Replace JUMP_IF_FALSE_OR_POP jumping to POP_JUMP_IF_FALSE <label>
        # with POP_JUMP_IF_FALSE <label>
        #
        #     while n > 0 and start > 3:
        #         func()
        label_instr1 = Label()
        label_instr15 = Label()
        label_instr17 = Label()
        label_instr9 = Label()
        code = Bytecode([
            Instr('SETUP_LOOP', label_instr17),
            label_instr1,
            Instr('LOAD_NAME', 'n'),
            Instr('LOAD_CONST', 0),
            Instr('COMPARE_OP', Compare.GT),
            # JUMP_IF_FALSE_OR_POP jumps to POP_JUMP_IF_FALSE
            # which jumps to label_instr15
            Instr('JUMP_IF_FALSE_OR_POP', label_instr9),
            Instr('LOAD_NAME', 'start'),
            Instr('LOAD_CONST', 3),
            Instr('COMPARE_OP', Compare.GT),
            label_instr9,
            Instr('POP_JUMP_IF_FALSE', label_instr15),
            Instr('LOAD_NAME', 'func'),
            Instr('CALL_FUNCTION', 0),
            Instr('POP_TOP'),
            Instr('JUMP_ABSOLUTE', label_instr1),
            label_instr15,
            Instr('POP_BLOCK'),
            label_instr17,
            Instr('LOAD_CONST', None),
            Instr('RETURN_VALUE')
        ])

        label_instr1 = Label()
        label_instr14 = Label()
        label_instr16 = Label()
        self.check(code, Instr('SETUP_LOOP', label_instr16), label_instr1,
                   Instr('LOAD_NAME', 'n'), Instr('LOAD_CONST', 0),
                   Instr('COMPARE_OP', Compare.GT),
                   Instr('POP_JUMP_IF_FALSE', label_instr14),
                   Instr('LOAD_NAME', 'start'), Instr('LOAD_CONST', 3),
                   Instr('COMPARE_OP', Compare.GT),
                   Instr('POP_JUMP_IF_FALSE', label_instr14),
                   Instr('LOAD_NAME', 'func'), Instr('CALL_FUNCTION', 0),
                   Instr('POP_TOP'), Instr('JUMP_ABSOLUTE', label_instr1),
                   label_instr14, Instr('POP_BLOCK'), label_instr16,
                   Instr('LOAD_CONST', None), Instr('RETURN_VALUE'))
示例#19
0
    def test_unconditional_jump_to_return(self):
        source = """
            def func():
                if test:
                    if test2:
                        x = 10
                    else:
                        x = 20
                else:
                    x = 30
        """

        label_instr11 = Label()
        label_instr14 = Label()
        label_instr7 = Label()
        code = Bytecode([
            Instr('LOAD_GLOBAL', 'test', lineno=2),
            Instr('POP_JUMP_IF_FALSE', label_instr11, lineno=2),
            Instr('LOAD_GLOBAL', 'test2', lineno=3),
            Instr('POP_JUMP_IF_FALSE', label_instr7, lineno=3),
            Instr('LOAD_CONST', 10, lineno=4),
            Instr('STORE_FAST', 'x', lineno=4),
            Instr('JUMP_ABSOLUTE', label_instr14, lineno=4), label_instr7,
            Instr('LOAD_CONST', 20, lineno=6),
            Instr('STORE_FAST', 'x', lineno=6),
            Instr('JUMP_FORWARD', label_instr14, lineno=6), label_instr11,
            Instr('LOAD_CONST', 30, lineno=8),
            Instr('STORE_FAST', 'x', lineno=8), label_instr14,
            Instr('LOAD_CONST', None, lineno=8),
            Instr('RETURN_VALUE', lineno=8)
        ])

        label1 = Label()
        label3 = Label()
        label4 = Label()
        self.check(code, Instr('LOAD_GLOBAL', 'test', lineno=2),
                   Instr('POP_JUMP_IF_FALSE', label3, lineno=2),
                   Instr('LOAD_GLOBAL', 'test2', lineno=3),
                   Instr('POP_JUMP_IF_FALSE', label1, lineno=3),
                   Instr('LOAD_CONST', 10, lineno=4),
                   Instr('STORE_FAST', 'x', lineno=4),
                   Instr('JUMP_ABSOLUTE', label4, lineno=4), label1,
                   Instr('LOAD_CONST', 20, lineno=6),
                   Instr('STORE_FAST', 'x', lineno=6),
                   Instr('JUMP_FORWARD', label4, lineno=6), label3,
                   Instr('LOAD_CONST', 30, lineno=8),
                   Instr('STORE_FAST', 'x', lineno=8), label4,
                   Instr('LOAD_CONST', None, lineno=8),
                   Instr('RETURN_VALUE', lineno=8))
示例#20
0
    def test_uncond_jump_to_uncond_jump(self):
        # Replace JUMP_FORWARD t1 jumping to JUMP_FORWARD t2
        # with JUMP_ABSOLUTE t2

        label = Label()
        label2 = Label()
        label3 = Label()
        label4 = Label()
        code = Bytecode([
            Instr('LOAD_NAME', 'test'),
            Instr('POP_JUMP_IF_TRUE', label),
            # redundant jump
            Instr('JUMP_FORWARD', label2),
            label,
            Instr('LOAD_CONST', 1),
            Instr('STORE_NAME', 'x'),
            Instr('LOAD_NAME', 'test'),
            Instr('POP_JUMP_IF_TRUE', label3),
            label2,
            Instr('JUMP_FORWARD', label4),
            label3,
            Instr('LOAD_CONST', 1),
            Instr('STORE_NAME', 'x'),
            label4,
            Instr('LOAD_CONST', None),
            Instr('RETURN_VALUE')
        ])

        label = Label()
        label3 = Label()
        label4 = Label()
        self.check(
            code,
            Instr('LOAD_NAME', 'test'),
            Instr('POP_JUMP_IF_TRUE', label),
            # JUMP_FORWARD label2 was replaced with JUMP_ABSOLUTE label4
            Instr('JUMP_ABSOLUTE', label4),
            label,
            Instr('LOAD_CONST', 1),
            Instr('STORE_NAME', 'x'),
            Instr('LOAD_NAME', 'test'),
            Instr('POP_JUMP_IF_TRUE', label3),
            Instr('JUMP_FORWARD', label4),
            label3,
            Instr('LOAD_CONST', 1),
            Instr('STORE_NAME', 'x'),
            label4,
            Instr('LOAD_CONST', None),
            Instr('RETURN_VALUE'))
示例#21
0
 def test_cellvars(self):
     code = Bytecode()
     code.cellvars = ["x"]
     code.freevars = ["y"]
     code.extend([
         Instr("LOAD_DEREF", CellVar("x"), lineno=1),
         Instr("LOAD_DEREF", FreeVar("y"), lineno=1),
     ])
     concrete = code.to_concrete_bytecode()
     self.assertEqual(concrete.cellvars, ["x"])
     self.assertEqual(concrete.freevars, ["y"])
     code.extend([
         ConcreteInstr("LOAD_DEREF", 0, lineno=1),
         ConcreteInstr("LOAD_DEREF", 1, lineno=1),
     ])
示例#22
0
 def test_cellvars(self):
     code = Bytecode()
     code.cellvars = ['x']
     code.freevars = ['y']
     code.extend([
         Instr('LOAD_DEREF', CellVar('x'), lineno=1),
         Instr('LOAD_DEREF', FreeVar('y'), lineno=1)
     ])
     concrete = code.to_concrete_bytecode()
     self.assertEqual(concrete.cellvars, ['x'])
     self.assertEqual(concrete.freevars, ['y'])
     code.extend([
         ConcreteInstr("LOAD_DEREF", 0, lineno=1),
         ConcreteInstr("LOAD_DEREF", 1, lineno=1)
     ])
示例#23
0
 def test_build_list_unpack_seq_const(self):
     # x, y, z = [3, 4, 5]
     code = Bytecode([
         Instr('LOAD_CONST', 3),
         Instr('LOAD_CONST', 4),
         Instr('LOAD_CONST', 5),
         Instr('BUILD_LIST', 3),
         Instr('UNPACK_SEQUENCE', 3),
         Instr('STORE_NAME', 'x'),
         Instr('STORE_NAME', 'y'),
         Instr('STORE_NAME', 'z')
     ])
     self.check(code, Instr('LOAD_CONST', 5), Instr('LOAD_CONST', 4),
                Instr('LOAD_CONST', 3), Instr('STORE_NAME', 'x'),
                Instr('STORE_NAME', 'y'), Instr('STORE_NAME', 'z'))
示例#24
0
    def test_max_size(self):
        max_size = 3
        with mock.patch.object(peephole_opt, "MAX_SIZE", max_size):
            # optimized binary operation: size <= maximum size
            #
            # (9,) * size
            size = max_size
            result = (9, ) * size
            code = Bytecode([
                Instr("LOAD_CONST", 9),
                Instr("BUILD_TUPLE", 1),
                Instr("LOAD_CONST", size),
                Instr("BINARY_MULTIPLY"),
                Instr("STORE_NAME", "x"),
            ])
            self.check(code, Instr("LOAD_CONST", result),
                       Instr("STORE_NAME", "x"))

            # don't optimize  binary operation: size > maximum size
            #
            # x = (9,) * size
            size = max_size + 1
            code = Bytecode([
                Instr("LOAD_CONST", 9),
                Instr("BUILD_TUPLE", 1),
                Instr("LOAD_CONST", size),
                Instr("BINARY_MULTIPLY"),
                Instr("STORE_NAME", "x"),
            ])
            self.check(
                code,
                Instr("LOAD_CONST", (9, )),
                Instr("LOAD_CONST", size),
                Instr("BINARY_MULTIPLY"),
                Instr("STORE_NAME", "x"),
            )
示例#25
0
    def test_dont_merge_constants(self):
        # test two constants which are equal but have a different type
        code = Bytecode()
        code.extend([Instr('LOAD_CONST', 5, lineno=1),
                     Instr('LOAD_CONST', 5.0, lineno=1),
                     Instr('LOAD_CONST', -0.0, lineno=1),
                     Instr('LOAD_CONST', +0.0, lineno=1)])

        code = code.to_concrete_bytecode()
        expected = [ConcreteInstr('LOAD_CONST', 0, lineno=1),
                    ConcreteInstr('LOAD_CONST', 1, lineno=1),
                    ConcreteInstr('LOAD_CONST', 2, lineno=1),
                    ConcreteInstr('LOAD_CONST', 3, lineno=1)]
        self.assertListEqual(list(code), expected)
        self.assertListEqual(code.consts, [5, 5.0, -0.0, +0.0])
示例#26
0
    def test_build_set(self):
        # test = x in {1, 2, 3}
        code = Bytecode([
            Instr('LOAD_NAME', 'x'),
            Instr('LOAD_CONST', 1),
            Instr('LOAD_CONST', 2),
            Instr('LOAD_CONST', 3),
            Instr('BUILD_SET', 3),
            Instr('COMPARE_OP', Compare.IN),
            Instr('STORE_NAME', 'test')
        ])

        self.check(code, Instr('LOAD_NAME', 'x'),
                   Instr('LOAD_CONST', frozenset((1, 2, 3))),
                   Instr('COMPARE_OP', Compare.IN),
                   Instr('STORE_NAME', 'test'))
示例#27
0
    def test_build_list(self):
        # test = x in [1, 2, 3]
        code = Bytecode([
            Instr('LOAD_NAME', 'x'),
            Instr('LOAD_CONST', 1),
            Instr('LOAD_CONST', 2),
            Instr('LOAD_CONST', 3),
            Instr('BUILD_LIST', 3),
            Instr('COMPARE_OP', Compare.IN),
            Instr('STORE_NAME', 'test')
        ])

        self.check(code, Instr('LOAD_NAME',
                               'x'), Instr('LOAD_CONST', (1, 2, 3)),
                   Instr('COMPARE_OP', Compare.IN),
                   Instr('STORE_NAME', 'test'))
示例#28
0
    def test_compute_jumps_convergence(self):
        # Consider the following sequence of instructions:
        #
        #     JUMP_ABSOLUTE Label1
        #     JUMP_ABSOLUTE Label2
        #     ...126 instructions...
        #   Label1:                 Offset 254 on first pass, 256 second pass
        #     NOP
        #     ... many more instructions ...
        #   Label2:                 Offset > 256 on first pass
        #
        # On first pass of compute_jumps(), Label2 will be at address 254, so
        # that value encodes into the single byte arg of JUMP_ABSOLUTE.
        #
        # On second pass compute_jumps() the instr at Label1 will have offset
        # of 256 so will also be given an EXTENDED_ARG.
        #
        # Thus we need to make an additional pass.  This test only verifies
        # case where 2 passes is insufficient but three is enough.

        if not WORDCODE:
            # Could be done pre-WORDCODE, but that requires 2**16 bytes of
            # code.
            return

        # Create code from comment above.
        code = Bytecode()
        label1 = Label()
        label2 = Label()
        nop = 'UNARY_POSITIVE'  # don't use NOP, dis.stack_effect will raise
        code.append(Instr('JUMP_ABSOLUTE', label1))
        code.append(Instr('JUMP_ABSOLUTE', label2))
        for x in range(4, 254, 2):
            code.append(Instr(nop))
        code.append(label1)
        code.append(Instr(nop))
        for x in range(256, 300, 2):
            code.append(Instr(nop))
        code.append(label2)
        code.append(Instr(nop))

        # This should pass by default.
        code.to_code()

        # Try with max of two passes:  it should raise
        with self.assertRaises(RuntimeError):
            code.to_code(compute_jumps_passes=2)
示例#29
0
def conditional_jump_example_bytecode() -> Bytecode:
    label_else = Label()
    label_print = Label()
    byte_code = Bytecode([
        Instr("LOAD_NAME", "print"),
        Instr("LOAD_NAME", "test"),
        Instr("POP_JUMP_IF_FALSE", label_else),
        Instr("LOAD_CONST", "yes"),
        Instr("JUMP_FORWARD", label_print),
        label_else,
        Instr("LOAD_CONST", "no"),
        label_print,
        Instr("CALL_FUNCTION", 1),
        Instr("LOAD_CONST", None),
        Instr("RETURN_VALUE"),
    ])
    return byte_code
示例#30
0
    def test_label_at_the_end(self):
        label = Label()
        code = Bytecode([Instr('LOAD_NAME', 'x'),
                         Instr('UNARY_NOT'),
                         Instr('POP_JUMP_IF_FALSE', label),
                         Instr('LOAD_CONST', 9),
                         Instr('STORE_NAME', 'y'),
                         label])

        cfg = ControlFlowGraph.from_bytecode(code)
        self.assertBlocksEqual(cfg,
                               [Instr('LOAD_NAME', 'x'),
                                Instr('UNARY_NOT'),
                                Instr('POP_JUMP_IF_FALSE', cfg[2])],
                               [Instr('LOAD_CONST', 9),
                                Instr('STORE_NAME', 'y')],
                               [])