示例#1
0
    def test_from_bytecode_loop(self):
        # for x in (1, 2, 3):
        #     if x == 2:
        #         break
        #     continue

        label_loop_start = Label()
        label_loop_exit = Label()
        label_loop_end = Label()

        code = Bytecode()
        code.extend((Instr('SETUP_LOOP', label_loop_end, lineno=1),
                     Instr('LOAD_CONST', (1, 2, 3), lineno=1),
                     Instr('GET_ITER', lineno=1),

                     label_loop_start,
                     Instr('FOR_ITER', label_loop_exit, lineno=1),
                     Instr('STORE_NAME', 'x', lineno=1),
                     Instr('LOAD_NAME', 'x', lineno=2),
                     Instr('LOAD_CONST', 2, lineno=2),
                     Instr('COMPARE_OP', Compare.EQ, lineno=2),
                     Instr('POP_JUMP_IF_FALSE', label_loop_start, lineno=2),
                     Instr('BREAK_LOOP', lineno=3),
                     Instr('JUMP_ABSOLUTE', label_loop_start, lineno=4),

                     Instr('JUMP_ABSOLUTE', label_loop_start, lineno=4),

                     label_loop_exit,
                     Instr('POP_BLOCK', lineno=4),

                     label_loop_end,
                     Instr('LOAD_CONST', None, lineno=4),
                     Instr('RETURN_VALUE', lineno=4),
        ))
        blocks = ControlFlowGraph.from_bytecode(code)

        expected = [[Instr('SETUP_LOOP', blocks[8], lineno=1)],

                    [Instr('LOAD_CONST', (1, 2, 3), lineno=1),
                     Instr('GET_ITER', lineno=1)],

                    [Instr('FOR_ITER', blocks[7], lineno=1)],

                    [Instr('STORE_NAME', 'x', lineno=1),
                     Instr('LOAD_NAME', 'x', lineno=2),
                     Instr('LOAD_CONST', 2, lineno=2),
                     Instr('COMPARE_OP', Compare.EQ, lineno=2),
                     Instr('POP_JUMP_IF_FALSE', blocks[2], lineno=2)],

                    [Instr('BREAK_LOOP', lineno=3)],

                    [Instr('JUMP_ABSOLUTE', blocks[2], lineno=4)],

                    [Instr('JUMP_ABSOLUTE', blocks[2], lineno=4)],

                    [Instr('POP_BLOCK', lineno=4)],

                    [Instr('LOAD_CONST', None, lineno=4),
                     Instr('RETURN_VALUE', lineno=4)]]
        self.assertBlocksEqual(blocks, *expected)
示例#2
0
    def test_label2(self):
        bytecode = Bytecode()
        label = Label()
        bytecode.extend(
            [
                Instr("LOAD_NAME", "test", lineno=1),
                Instr("POP_JUMP_IF_FALSE", label),
                Instr("LOAD_CONST", 5, lineno=2),
                Instr("STORE_NAME", "x"),
                Instr("JUMP_FORWARD", label),
                Instr("LOAD_CONST", 7, lineno=4),
                Instr("STORE_NAME", "x"),
                label,
                Instr("LOAD_CONST", None),
                Instr("RETURN_VALUE"),
            ]
        )

        concrete = bytecode.to_concrete_bytecode()
        expected = [
            ConcreteInstr("LOAD_NAME", 0, lineno=1),
            ConcreteInstr("POP_JUMP_IF_FALSE", 14, lineno=1),
            ConcreteInstr("LOAD_CONST", 0, lineno=2),
            ConcreteInstr("STORE_NAME", 1, lineno=2),
            ConcreteInstr("JUMP_FORWARD", 4, lineno=2),
            ConcreteInstr("LOAD_CONST", 1, lineno=4),
            ConcreteInstr("STORE_NAME", 1, lineno=4),
            ConcreteInstr("LOAD_CONST", 2, lineno=4),
            ConcreteInstr("RETURN_VALUE", lineno=4),
        ]
        self.assertListEqual(list(concrete), expected)
        self.assertListEqual(concrete.consts, [5, 7, None])
        self.assertListEqual(concrete.names, ["test", "x"])
        self.assertListEqual(concrete.varnames, [])
示例#3
0
 def test_slice(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"),
     ])
     sliced_code = code[:]
     self.assertEqual(code, sliced_code)
     for name in (
             "argcount",
             "posonlyargcount",
             "first_lineno",
             "name",
             "filename",
             "docstring",
             "cellvars",
             "freevars",
             "argnames",
     ):
         Undefined = object()
         self.assertEqual(getattr(code, name, Undefined),
                          getattr(sliced_code, name, Undefined))
示例#4
0
    def test_jumps(self):
        # if test:
        #     x = 12
        # else:
        #     x = 37
        code = Bytecode()
        label_else = Label()
        label_return = Label()
        code.extend([Instr('LOAD_NAME', 'test', lineno=1),
                     Instr('POP_JUMP_IF_FALSE', label_else),
                     Instr('LOAD_CONST', 12, lineno=2),
                     Instr('STORE_NAME', 'x'),
                     Instr('JUMP_FORWARD', label_return),
                     label_else,
                         Instr('LOAD_CONST', 37, lineno=4),
                         Instr('STORE_NAME', 'x'),
                     label_return,
                         Instr('LOAD_CONST', None, lineno=4),
                         Instr('RETURN_VALUE')])

        code = code.to_concrete_bytecode()
        expected = [ConcreteInstr('LOAD_NAME', 0, lineno=1),
                    ConcreteInstr('POP_JUMP_IF_FALSE', 15, lineno=1),
                    ConcreteInstr('LOAD_CONST', 0, lineno=2),
                    ConcreteInstr('STORE_NAME', 1, lineno=2),
                    ConcreteInstr('JUMP_FORWARD', 6, lineno=2),
                    ConcreteInstr('LOAD_CONST', 1, lineno=4),
                    ConcreteInstr('STORE_NAME', 1, lineno=4),
                    ConcreteInstr('LOAD_CONST', 2, lineno=4),
                    ConcreteInstr('RETURN_VALUE', lineno=4)]
        self.assertListEqual(list(code), expected)
        self.assertListEqual(code.consts, [12, 37, None])
        self.assertListEqual(code.names, ['test', 'x'])
        self.assertListEqual(code.varnames, [])
示例#5
0
 def test_negative_size_unpack(self):
     with self.subTest():
         code = Bytecode()
         code.first_lineno = 1
         code.extend([Instr("UNPACK_SEQUENCE", 1)])
         with self.assertRaises(RuntimeError):
             code.compute_stacksize()
示例#6
0
    def test_setlineno(self):
        # x = 7
        # y = 8
        # z = 9
        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')])

        blocks = ControlFlowGraph.from_bytecode(code)
        self.assertBlocksEqual(blocks,
                               [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')])
示例#7
0
    def test_from_bytecode(self):
        bytecode = Bytecode()
        label = Label()
        bytecode.extend([Instr('LOAD_NAME', 'test', lineno=1),
                         Instr('POP_JUMP_IF_FALSE', label, lineno=1),
                         Instr('LOAD_CONST', 5, lineno=2),
                         Instr('STORE_NAME', 'x', lineno=2),
                         Instr('JUMP_FORWARD', label, lineno=2),
                             # dead code!
                             Instr('LOAD_CONST', 7, lineno=4),
                             Instr('STORE_NAME', 'x', lineno=4),
                             Label(),  # unused label
                         label,
                             Label(),  # unused label
                             Instr('LOAD_CONST', None, lineno=4),
                             Instr('RETURN_VALUE', lineno=4)])

        blocks = ControlFlowGraph.from_bytecode(bytecode)
        label2 = blocks[3]
        self.assertBlocksEqual(blocks,
                               [Instr('LOAD_NAME', 'test', lineno=1),
                                Instr('POP_JUMP_IF_FALSE', label2, lineno=1)],
                               [Instr('LOAD_CONST', 5, lineno=2),
                                Instr('STORE_NAME', 'x', lineno=2),
                                Instr('JUMP_FORWARD', label2, lineno=2)],
                               [Instr('LOAD_CONST', 7, lineno=4),
                                Instr('STORE_NAME', 'x', lineno=4)],
                               [Instr('LOAD_CONST', None, lineno=4),
                                Instr('RETURN_VALUE', lineno=4)])
示例#8
0
    def test_label2(self):
        bytecode = Bytecode()
        label = Label()
        bytecode.extend([
            Instr('LOAD_NAME', 'test', lineno=1),
            Instr('POP_JUMP_IF_FALSE', label),
            Instr('LOAD_CONST', 5, lineno=2),
            Instr('STORE_NAME', 'x'),
            Instr('JUMP_FORWARD', label),
            Instr('LOAD_CONST', 7, lineno=4),
            Instr('STORE_NAME', 'x'), label,
            Instr('LOAD_CONST', None),
            Instr('RETURN_VALUE')
        ])

        concrete = bytecode.to_concrete_bytecode()
        expected = [
            ConcreteInstr('LOAD_NAME', 0, lineno=1),
            ConcreteInstr('POP_JUMP_IF_FALSE',
                          14 if WORDCODE else 21,
                          lineno=1),
            ConcreteInstr('LOAD_CONST', 0, lineno=2),
            ConcreteInstr('STORE_NAME', 1, lineno=2),
            ConcreteInstr('JUMP_FORWARD', 4 if WORDCODE else 6, lineno=2),
            ConcreteInstr('LOAD_CONST', 1, lineno=4),
            ConcreteInstr('STORE_NAME', 1, lineno=4),
            ConcreteInstr('LOAD_CONST', 2, lineno=4),
            ConcreteInstr('RETURN_VALUE', lineno=4)
        ]
        self.assertListEqual(list(concrete), expected)
        self.assertListEqual(concrete.consts, [5, 7, None])
        self.assertListEqual(concrete.names, ['test', 'x'])
        self.assertListEqual(concrete.varnames, [])
示例#9
0
    def test_from_bytecode(self):
        bytecode = Bytecode()
        label = Label()
        bytecode.extend([Instr('LOAD_NAME', 'test', lineno=1),
                         Instr('POP_JUMP_IF_FALSE', label, lineno=1),
                         Instr('LOAD_CONST', 5, lineno=2),
                         Instr('STORE_NAME', 'x', lineno=2),
                         Instr('JUMP_FORWARD', label, lineno=2),
                         # dead code!
                         Instr('LOAD_CONST', 7, lineno=4),
                         Instr('STORE_NAME', 'x', lineno=4),
                         Label(),  # unused label
                         label,
                         Label(),  # unused label
                         Instr('LOAD_CONST', None, lineno=4),
                         Instr('RETURN_VALUE', lineno=4)])

        blocks = ControlFlowGraph.from_bytecode(bytecode)
        label2 = blocks[3]
        self.assertBlocksEqual(blocks,
                               [Instr('LOAD_NAME', 'test', lineno=1),
                                Instr('POP_JUMP_IF_FALSE', label2, lineno=1)],
                               [Instr('LOAD_CONST', 5, lineno=2),
                                Instr('STORE_NAME', 'x', lineno=2),
                                Instr('JUMP_FORWARD', label2, lineno=2)],
                               [Instr('LOAD_CONST', 7, lineno=4),
                                Instr('STORE_NAME', 'x', lineno=4)],
                               [Instr('LOAD_CONST', None, lineno=4),
                                Instr('RETURN_VALUE', lineno=4)])
示例#10
0
    def test_setlineno(self):
        # x = 7
        # y = 8
        # z = 9
        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"),
            ]
        )

        concrete = code.to_concrete_bytecode()
        self.assertEqual(concrete.consts, [7, 8, 9])
        self.assertEqual(concrete.names, ["x", "y", "z"])
        self.assertListEqual(
            list(concrete),
            [
                ConcreteInstr("LOAD_CONST", 0, lineno=3),
                ConcreteInstr("STORE_NAME", 0, lineno=3),
                ConcreteInstr("LOAD_CONST", 1, lineno=4),
                ConcreteInstr("STORE_NAME", 1, lineno=4),
                ConcreteInstr("LOAD_CONST", 2, lineno=5),
                ConcreteInstr("STORE_NAME", 2, lineno=5),
            ],
        )
示例#11
0
    def test_setlineno(self):
        # x = 7
        # y = 8
        # z = 9
        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')])

        blocks = ControlFlowGraph.from_bytecode(code)
        self.assertBlocksEqual(blocks,
                               [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')])
示例#12
0
    def test_legalize(self):
        code = Bytecode()
        code.first_lineno = 3
        code.extend(
            [
                Instr("LOAD_CONST", 7),
                Instr("STORE_NAME", "x"),
                Instr("LOAD_CONST", 8, lineno=4),
                Instr("STORE_NAME", "y"),
                SetLineno(5),
                Instr("LOAD_CONST", 9, lineno=6),
                Instr("STORE_NAME", "z"),
            ]
        )

        blocks = ControlFlowGraph.from_bytecode(code)
        blocks.legalize()
        self.assertBlocksEqual(
            blocks,
            [
                Instr("LOAD_CONST", 7, lineno=3),
                Instr("STORE_NAME", "x", lineno=3),
                Instr("LOAD_CONST", 8, lineno=4),
                Instr("STORE_NAME", "y", lineno=4),
                Instr("LOAD_CONST", 9, lineno=5),
                Instr("STORE_NAME", "z", lineno=5),
            ],
        )
示例#13
0
    def test_copy(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"),
            ]
        )

        copy_code = code.copy()
        self.assertEqual(code, copy_code)
        for name in (
            "argcount",
            "posonlyargcount",
            "kwonlyargcount",
            "first_lineno",
            "name",
            "filename",
            "docstring",
            "cellvars",
            "freevars",
            "argnames",
        ):
            self.assertEqual(getattr(code, name, None), getattr(copy_code, name, None))
示例#14
0
    def test_setlineno(self):
        # x = 7
        # y = 8
        # z = 9
        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')
        ])

        concrete = code.to_concrete_bytecode()
        self.assertEqual(concrete.consts, [7, 8, 9])
        self.assertEqual(concrete.names, ['x', 'y', 'z'])
        code.extend([
            ConcreteInstr("LOAD_CONST", 0, lineno=3),
            ConcreteInstr("STORE_NAME", 0, lineno=3),
            ConcreteInstr("LOAD_CONST", 1, lineno=4),
            ConcreteInstr("STORE_NAME", 1, lineno=4),
            ConcreteInstr("LOAD_CONST", 2, lineno=5),
            ConcreteInstr("STORE_NAME", 2, lineno=5)
        ])
示例#15
0
    def test_label2(self):
        bytecode = Bytecode()
        label = Label()
        bytecode.extend([Instr('LOAD_NAME', 'test', lineno=1),
                         Instr('POP_JUMP_IF_FALSE', label),
                         Instr('LOAD_CONST', 5, lineno=2),
                         Instr('STORE_NAME', 'x'),
                         Instr('JUMP_FORWARD', label),
                         Instr('LOAD_CONST', 7, lineno=4),
                         Instr('STORE_NAME', 'x'),
                         label,
                         Instr('LOAD_CONST', None),
                         Instr('RETURN_VALUE')])

        concrete = bytecode.to_concrete_bytecode()
        expected = [ConcreteInstr('LOAD_NAME', 0, lineno=1),
                    ConcreteInstr('POP_JUMP_IF_FALSE',
                                  14 if WORDCODE else 21, lineno=1),
                    ConcreteInstr('LOAD_CONST', 0, lineno=2),
                    ConcreteInstr('STORE_NAME', 1, lineno=2),
                    ConcreteInstr('JUMP_FORWARD',
                                  4 if WORDCODE else 6, lineno=2),
                    ConcreteInstr('LOAD_CONST', 1, lineno=4),
                    ConcreteInstr('STORE_NAME', 1, lineno=4),
                    ConcreteInstr('LOAD_CONST', 2, lineno=4),
                    ConcreteInstr('RETURN_VALUE', lineno=4)]
        self.assertListEqual(list(concrete), expected)
        self.assertListEqual(concrete.consts, [5, 7, None])
        self.assertListEqual(concrete.names, ['test', 'x'])
        self.assertListEqual(concrete.varnames, [])
示例#16
0
    def test_legalize(self):
        code = Bytecode()
        code.first_lineno = 3
        code.extend(
            [
                Instr("LOAD_CONST", 7),
                Instr("STORE_NAME", "x"),
                Instr("LOAD_CONST", 8, lineno=4),
                Instr("STORE_NAME", "y"),
                Label(),
                SetLineno(5),
                Instr("LOAD_CONST", 9, lineno=6),
                Instr("STORE_NAME", "z"),
            ]
        )

        code.legalize()
        self.assertListEqual(
            code,
            [
                Instr("LOAD_CONST", 7, lineno=3),
                Instr("STORE_NAME", "x", lineno=3),
                Instr("LOAD_CONST", 8, lineno=4),
                Instr("STORE_NAME", "y", lineno=4),
                Label(),
                Instr("LOAD_CONST", 9, lineno=5),
                Instr("STORE_NAME", "z", lineno=5),
            ],
        )
示例#17
0
    def test_extreme_compute_jumps_convergence(self):
        """Test of compute_jumps() requiring absurd number of passes.

        NOTE:  This test also serves to demonstrate that there is no worst
        case: the number of passes can be unlimited (or, actually, limited by
        the size of the provided code).

        This is an extension of test_compute_jumps_convergence.  Instead of
        two jumps, where the earlier gets extended after the latter, we
        instead generate a series of many jumps.  Each pass of compute_jumps()
        extends one more instruction, which in turn causes the one behind it
        to be extended on the next pass.
        """
        if not WORDCODE:
            return

        # N: the number of unextended instructions that can be squeezed into a
        # set of bytes adressable by the arg of an unextended instruction.
        # The answer is "128", but here's how we arrive at it (and it also
        # hints at how to make this work for pre-WORDCODE).
        max_unextended_offset = 1 << 8
        unextended_branch_instr_size = 2
        N = max_unextended_offset // unextended_branch_instr_size

        nop = 'UNARY_POSITIVE'  # don't use NOP, dis.stack_effect will raise

        # The number of jumps will be equal to the number of labels.  The
        # number of passes of compute_jumps() required will be one greater
        # than this.
        labels = [Label() for x in range(0, 3 * N)]

        code = Bytecode()
        code.extend(
            Instr('JUMP_FORWARD', labels[len(labels) - x - 1])
            for x in range(0, len(labels)))
        end_of_jumps = len(code)
        code.extend(Instr(nop) for x in range(0, N))

        # Now insert the labels.  The first is N instructions (i.e. 256
        # bytes) after the last jump.  Then they proceed to earlier positions
        # 4 bytes at a time.  While the targets are in the range of the nop
        # instructions, 4 bytes is two instructions.  When the targets are in
        # the range of JUMP_FORWARD instructions we have to allow for the fact
        # that the instructions will have been extended to four bytes each, so
        # working backwards 4 bytes per label means just one instruction per
        # label.
        offset = end_of_jumps + N
        for l in range(0, len(labels)):
            code.insert(offset, labels[l])
            if offset <= end_of_jumps:
                offset -= 1
            else:
                offset -= 2

        code.insert(0, Instr("LOAD_CONST", 0))
        del end_of_jumps
        code.append(Instr('RETURN_VALUE'))

        code.to_code(compute_jumps_passes=(len(labels) + 1))
示例#18
0
 def test_negative_size_build_const_map(self):
     code = Bytecode()
     code.first_lineno = 1
     code.extend(
         [Instr("LOAD_CONST", ("a", )),
          Instr("BUILD_CONST_KEY_MAP", 1)])
     with self.assertRaises(RuntimeError):
         code.compute_stacksize()
示例#19
0
    def test_extreme_compute_jumps_convergence(self):
        """Test of compute_jumps() requiring absurd number of passes.

        NOTE:  This test also serves to demonstrate that there is no worst
        case: the number of passes can be unlimited (or, actually, limited by
        the size of the provided code).

        This is an extension of test_compute_jumps_convergence.  Instead of
        two jumps, where the earlier gets extended after the latter, we
        instead generate a series of many jumps.  Each pass of compute_jumps()
        extends one more instruction, which in turn causes the one behind it
        to be extended on the next pass.
        """
        if not WORDCODE:
            return

        # N: the number of unextended instructions that can be squeezed into a
        # set of bytes adressable by the arg of an unextended instruction.
        # The answer is "128", but here's how we arrive at it (and it also
        # hints at how to make this work for pre-WORDCODE).
        max_unextended_offset = 1 << 8
        unextended_branch_instr_size = 2
        N = max_unextended_offset // unextended_branch_instr_size

        nop = 'UNARY_POSITIVE'   # don't use NOP, dis.stack_effect will raise

        # The number of jumps will be equal to the number of labels.  The
        # number of passes of compute_jumps() required will be one greater
        # than this.
        labels = [Label() for x in range(0, 3 * N)]

        code = Bytecode()
        code.extend(Instr('JUMP_FORWARD', labels[len(labels) - x - 1])
                    for x in range(0, len(labels)))
        end_of_jumps = len(code)
        code.extend(Instr(nop) for x in range(0, N))

        # Now insert the labels.  The first is N instructions (i.e. 256
        # bytes) after the last jump.  Then they proceed to earlier positions
        # 4 bytes at a time.  While the targets are in the range of the nop
        # instructions, 4 bytes is two instructions.  When the targets are in
        # the range of JUMP_FORWARD instructions we have to allow for the fact
        # that the instructions will have been extended to four bytes each, so
        # working backwards 4 bytes per label means just one instruction per
        # label.
        offset = end_of_jumps + N
        for l in range(0, len(labels)):
            code.insert(offset, labels[l])
            if offset <= end_of_jumps:
                offset -= 1
            else:
                offset -= 2

        code.insert(0, Instr("LOAD_CONST", 0))
        del end_of_jumps
        code.append(Instr('RETURN_VALUE'))

        code.to_code(compute_jumps_passes=(len(labels) + 1))
示例#20
0
    def test_from_bytecode_loop(self):
        # for x in (1, 2, 3):
        #     if x == 2:
        #         break
        #     continue

        label_loop_start = Label()
        label_loop_exit = Label()
        label_loop_end = Label()

        code = Bytecode()
        code.extend((
            Instr("SETUP_LOOP", label_loop_end, lineno=1),
            Instr("LOAD_CONST", (1, 2, 3), lineno=1),
            Instr("GET_ITER", lineno=1),
            label_loop_start,
            Instr("FOR_ITER", label_loop_exit, lineno=1),
            Instr("STORE_NAME", "x", lineno=1),
            Instr("LOAD_NAME", "x", lineno=2),
            Instr("LOAD_CONST", 2, lineno=2),
            Instr("COMPARE_OP", Compare.EQ, lineno=2),
            Instr("POP_JUMP_IF_FALSE", label_loop_start, lineno=2),
            Instr("BREAK_LOOP", lineno=3),
            Instr("JUMP_ABSOLUTE", label_loop_start, lineno=4),
            Instr("JUMP_ABSOLUTE", label_loop_start, lineno=4),
            label_loop_exit,
            Instr("POP_BLOCK", lineno=4),
            label_loop_end,
            Instr("LOAD_CONST", None, lineno=4),
            Instr("RETURN_VALUE", lineno=4),
        ))
        blocks = ControlFlowGraph.from_bytecode(code)

        expected = [
            [Instr("SETUP_LOOP", blocks[8], lineno=1)],
            [
                Instr("LOAD_CONST", (1, 2, 3), lineno=1),
                Instr("GET_ITER", lineno=1)
            ],
            [Instr("FOR_ITER", blocks[7], lineno=1)],
            [
                Instr("STORE_NAME", "x", lineno=1),
                Instr("LOAD_NAME", "x", lineno=2),
                Instr("LOAD_CONST", 2, lineno=2),
                Instr("COMPARE_OP", Compare.EQ, lineno=2),
                Instr("POP_JUMP_IF_FALSE", blocks[2], lineno=2),
            ],
            [Instr("BREAK_LOOP", lineno=3)],
            [Instr("JUMP_ABSOLUTE", blocks[2], lineno=4)],
            [Instr("JUMP_ABSOLUTE", blocks[2], lineno=4)],
            [Instr("POP_BLOCK", lineno=4)],
            [
                Instr("LOAD_CONST", None, lineno=4),
                Instr("RETURN_VALUE", lineno=4)
            ],
        ]
        self.assertBlocksEqual(blocks, *expected)
示例#21
0
 def test_not_enough_rot(self):
     opnames = ["ROT_TWO", "ROT_THREE"]
     for opname in opnames:
         with self.subTest():
             code = Bytecode()
             code.first_lineno = 1
             code.extend([Instr("LOAD_CONST", 1), Instr(opname)])
             with self.assertRaises(RuntimeError):
                 code.compute_stacksize()
示例#22
0
 def test_negative_size_build_const_map_with_disable_check_of_pre_and_post(
         self):
     code = Bytecode()
     code.first_lineno = 1
     code.extend(
         [Instr("LOAD_CONST", ("a", )),
          Instr("BUILD_CONST_KEY_MAP", 1)])
     co = code.to_code(check_pre_and_post=False)
     self.assertEqual(co.co_stacksize, 1)
示例#23
0
 def test_not_enough_rot_with_disable_check_of_pre_and_post(self):
     opnames = ["ROT_TWO", "ROT_THREE"]
     for opname in opnames:
         with self.subTest():
             code = Bytecode()
             code.first_lineno = 1
             code.extend([Instr("LOAD_CONST", 1), Instr(opname)])
             co = code.to_code(check_pre_and_post=False)
             self.assertEqual(co.co_stacksize, 1)
示例#24
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)
示例#25
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)])
示例#26
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)])
示例#27
0
    def test_from_bytecode_loop(self):
        # for x in (1, 2, 3):
        #     if x == 2:
        #         break
        #     continue

        label_loop_start = Label()
        label_loop_exit = Label()
        label_loop_end = Label()

        code = Bytecode()
        code.extend((
            Instr('SETUP_LOOP', label_loop_end, lineno=1),
            Instr('LOAD_CONST', (1, 2, 3), lineno=1),
            Instr('GET_ITER', lineno=1),
            label_loop_start,
            Instr('FOR_ITER', label_loop_exit, lineno=1),
            Instr('STORE_NAME', 'x', lineno=1),
            Instr('LOAD_NAME', 'x', lineno=2),
            Instr('LOAD_CONST', 2, lineno=2),
            Instr('COMPARE_OP', Compare.EQ, lineno=2),
            Instr('POP_JUMP_IF_FALSE', label_loop_start, lineno=2),
            Instr('BREAK_LOOP', lineno=3),
            Instr('JUMP_ABSOLUTE', label_loop_start, lineno=4),
            Instr('JUMP_ABSOLUTE', label_loop_start, lineno=4),
            label_loop_exit,
            Instr('POP_BLOCK', lineno=4),
            label_loop_end,
            Instr('LOAD_CONST', None, lineno=4),
            Instr('RETURN_VALUE', lineno=4),
        ))
        blocks = ControlFlowGraph.from_bytecode(code)

        expected = [[Instr('SETUP_LOOP', blocks[8], lineno=1)],
                    [
                        Instr('LOAD_CONST', (1, 2, 3), lineno=1),
                        Instr('GET_ITER', lineno=1)
                    ], [Instr('FOR_ITER', blocks[7], lineno=1)],
                    [
                        Instr('STORE_NAME', 'x', lineno=1),
                        Instr('LOAD_NAME', 'x', lineno=2),
                        Instr('LOAD_CONST', 2, lineno=2),
                        Instr('COMPARE_OP', Compare.EQ, lineno=2),
                        Instr('POP_JUMP_IF_FALSE', blocks[2], lineno=2)
                    ], [Instr('BREAK_LOOP', lineno=3)],
                    [Instr('JUMP_ABSOLUTE', blocks[2], lineno=4)],
                    [Instr('JUMP_ABSOLUTE', blocks[2], lineno=4)],
                    [Instr('POP_BLOCK', lineno=4)],
                    [
                        Instr('LOAD_CONST', None, lineno=4),
                        Instr('RETURN_VALUE', lineno=4)
                    ]]
        self.assertBlocksEqual(blocks, *expected)
示例#28
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)
示例#29
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()
示例#30
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)
示例#31
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()
示例#32
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'])
示例#33
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
示例#34
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'])
示例#35
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),
     ])
示例#36
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])
示例#37
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])
示例#38
0
    def test_to_code(self):
        code = Bytecode()
        code.first_lineno = 50
        code.extend([Instr("LOAD_NAME", "print"),
                     Instr("LOAD_CONST", "%s"),
                     Instr("LOAD_GLOBAL", "a"),
                     Instr("BINARY_MODULO"),
                     Instr("CALL_FUNCTION", 1),
                     Instr("RETURN_VALUE")])
        co = code.to_code()
        # hopefully this is obvious from inspection? :-)
        self.assertEqual(co.co_stacksize, 3)

        co = code.to_code(stacksize=42)
        self.assertEqual(co.co_stacksize, 42)
示例#39
0
    def test_to_code(self):
        code = Bytecode()
        code.first_lineno = 50
        code.extend([
            Instr("LOAD_NAME", "print"),
            Instr("LOAD_CONST", "%s"),
            Instr("LOAD_GLOBAL", "a"),
            Instr("BINARY_MODULO"),
            Instr("CALL_FUNCTION", 1),
            Instr("RETURN_VALUE"),
        ])
        co = code.to_code()
        # hopefully this is obvious from inspection? :-)
        self.assertEqual(co.co_stacksize, 3)

        co = code.to_code(stacksize=42)
        self.assertEqual(co.co_stacksize, 42)
示例#40
0
 def test_for_iter_stack_effect_computation(self):
     with self.subTest():
         code = Bytecode()
         code.first_lineno = 1
         lab1 = Label()
         lab2 = Label()
         code.extend([
             lab1,
             Instr("FOR_ITER", lab2),
             Instr("STORE_FAST", "i"),
             Instr("JUMP_ABSOLUTE", lab1),
             lab2,
         ])
         with self.assertRaises(RuntimeError):
             # Use compute_stacksize since the code is so broken that conversion
             # to from concrete is actually broken
             code.compute_stacksize(check_pre_and_post=False)
示例#41
0
    def test_setlineno(self):
        # x = 7
        # y = 8
        # z = 9
        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')])

        concrete = code.to_concrete_bytecode()
        self.assertEqual(concrete.consts, [7, 8, 9])
        self.assertEqual(concrete.names, ['x', 'y', 'z'])
        code.extend([ConcreteInstr("LOAD_CONST", 0, lineno=3),
                     ConcreteInstr("STORE_NAME", 0, lineno=3),
                     ConcreteInstr("LOAD_CONST", 1, lineno=4),
                     ConcreteInstr("STORE_NAME", 1, lineno=4),
                     ConcreteInstr("LOAD_CONST", 2, lineno=5),
                     ConcreteInstr("STORE_NAME", 2, lineno=5)])