示例#1
0
 def make_code(self, int_array, name="testcode"):
   """Utility method for creating CodeType objects."""
   return loadmarshal.CodeType(
       argcount=0, kwonlyargcount=0, nlocals=2, stacksize=2, flags=0,
       consts=[None, 1, 2], names=[], varnames=["x", "y"], filename="",
       name=name, firstlineno=1, lnotab=[], freevars=[], cellvars=[],
       code=compat.int_array_to_bytes(int_array),
       python_version=self.python_version)
示例#2
0
 def assertLineNumbers(self, code, co_lnotab, expected):
     """Assert that the opcodes have the expected line numbers."""
     ops = self.dis(code,
                    co_lnotab=compat.int_array_to_bytes(co_lnotab),
                    co_firstlineno=1)
     self.assertEqual(len(ops), len(expected))
     for o, e in zip(ops, expected):
         self.assertEqual(e, o.line)
示例#3
0
class BytecodeTest(test_base.BaseTest, test_utils.MakeCodeMixin):
    """Tests for process_code in blocks.py and VM integration."""

    # We only test Python 2 bytecode.
    PY_MAJOR_VERSIONS = [2]

    def setUp(self):
        super(BytecodeTest, self).setUp()
        self.errorlog = errors.ErrorLog()
        self.trace_vm = TraceVM(self.options, self.loader)

    def test_simple(self):
        # Disassembled from:
        # | return None
        code = self.make_code(
            [
                0x64,
                1,
                0,  # 0 LOAD_CONST, arg=1 (1)
                0x53,  # 3 RETURN_VALUE
            ],
            name="simple")
        code = blocks.process_code(code)
        v = vm.VirtualMachine(self.errorlog, self.options, loader=self.loader)
        v.run_bytecode(v.program.NewCFGNode(), code)

    def test_diamond(self):
        # Disassembled from:
        # | if []:
        # |   y = 1
        # | elif []:
        # |   y = 2
        # | elif []:
        # |   y = None
        # | return y
        o = test_utils.Py2Opcodes
        code = self.make_code([
            o.BUILD_LIST,
            0,
            0,
            o.POP_JUMP_IF_FALSE,
            15,
            0,
            o.LOAD_CONST,
            1,
            0,
            o.STORE_FAST,
            1,
            0,
            o.JUMP_FORWARD,
            30,
            0,
            o.BUILD_LIST,
            0,
            0,
            o.POP_JUMP_IF_FALSE,
            30,
            0,
            o.LOAD_CONST,
            2,
            0,
            o.STORE_FAST,
            1,
            0,
            o.JUMP_FORWARD,
            15,
            0,
            o.BUILD_LIST,
            0,
            0,
            o.POP_JUMP_IF_FALSE,
            45,
            0,
            o.LOAD_CONST,
            0,
            0,
            o.STORE_FAST,
            1,
            0,
            o.JUMP_FORWARD,
            0,
            0,
            o.LOAD_FAST,
            1,
            0,
            o.RETURN_VALUE,
        ])
        code = blocks.process_code(code)
        v = vm.VirtualMachine(self.errorlog, self.options, loader=self.loader)
        v.run_bytecode(v.program.NewCFGNode(), code)

    src_nested_loop = textwrap.dedent("""
    y = [1,2,3]
    z = 0
    for x in y:
      for a in y:
        if x:
          z += x*a
    """)
    code_nested_loop = compat.int_array_to_bytes([
        dis.opmap["LOAD_CONST"],
        0,
        0,  # [0], 0, arg=0
        dis.opmap["LOAD_CONST"],
        1,
        0,  # [1], 3, arg=1
        dis.opmap["LOAD_CONST"],
        2,
        0,  # [2], 6, arg=2
        dis.opmap["BUILD_LIST"],
        3,
        0,  # [3], 9, arg=3
        dis.opmap["STORE_NAME"],
        0,
        0,  # [4], 12, arg=0
        dis.opmap["LOAD_CONST"],
        3,
        0,  # [5], 15, arg=3
        dis.opmap["STORE_NAME"],
        1,
        0,  # [6], 18, arg=1
        dis.opmap["SETUP_LOOP"],
        54,
        0,  # [7], 21, dest=78
        dis.opmap["LOAD_NAME"],
        0,
        0,  # [8], 24, arg=0
        dis.opmap["GET_ITER"],  # [9], 27
        dis.opmap["FOR_ITER"],
        46,
        0,  # [10], 28, dest=77
        dis.opmap["STORE_NAME"],
        2,
        0,  # [11], 31, arg=2
        dis.opmap["SETUP_LOOP"],
        37,
        0,  # [12], 34, dest=74
        dis.opmap["LOAD_NAME"],
        0,
        0,  # [13], 37, arg=0
        dis.opmap["GET_ITER"],  # [14], 40
        dis.opmap["FOR_ITER"],
        29,
        0,  # [15], 41, dest=73
        dis.opmap["STORE_NAME"],
        3,
        0,  # [16], 44, arg=3
        dis.opmap["LOAD_NAME"],
        2,
        0,  # [17], 47, arg=2
        dis.opmap["POP_JUMP_IF_FALSE"],
        41,
        0,  # [18], 50, dest=41
        dis.opmap["LOAD_NAME"],
        1,
        0,  # [19], 53, arg=1
        dis.opmap["LOAD_NAME"],
        2,
        0,  # [20], 56, arg=2
        dis.opmap["LOAD_NAME"],
        3,
        0,  # [21], 59, arg=3
        dis.opmap["BINARY_MULTIPLY"],  # [22], 62
        dis.opmap["INPLACE_ADD"],  # [23], 63
        dis.opmap["STORE_NAME"],
        1,
        0,  # [24], 64, arg=1
        dis.opmap["JUMP_ABSOLUTE"],
        41,
        0,  # [25], 67, dest=41
        dis.opmap["JUMP_ABSOLUTE"],
        41,
        0,  # [26], 70 (unreachable), dest=41
        dis.opmap["POP_BLOCK"],  # [27], 73
        dis.opmap["JUMP_ABSOLUTE"],
        28,
        0,  # [28], 74, dest=28
        dis.opmap["POP_BLOCK"],  # [29], 77
        dis.opmap["LOAD_CONST"],
        4,
        0,  # [30], 78, arg=4
        dis.opmap["RETURN_VALUE"],  # [31], 81
    ])

    def test_each_instruction_once_loops(self):
        code_nested_loop = pyc.compile_src(src=self.src_nested_loop,
                                           python_version=self.python_version,
                                           python_exe=utils.get_python_exe(
                                               self.python_version),
                                           filename="<>")
        self.assertEqual(code_nested_loop.co_code, self.code_nested_loop)
        self.trace_vm.run_program(self.src_nested_loop, "", maximum_depth=10)
        # We expect all instructions, except 26, in the above to execute.
        six.assertCountEqual(self, self.trace_vm.instructions_executed,
                             set(range(32)) - {26})

    src_deadcode = textwrap.dedent("""
    if False:
      x = 2
    raise RuntimeError
    x = 42
    """)
    code_deadcode = compat.int_array_to_bytes([
        dis.opmap["LOAD_NAME"],
        0,
        0,  # [0] 0, arg=0
        dis.opmap["POP_JUMP_IF_FALSE"],
        15,
        0,  # [1] 3, dest=15
        dis.opmap["LOAD_CONST"],
        0,
        0,  # [2] 6, arg=0
        dis.opmap["STORE_NAME"],
        1,
        0,  # [3] 9, arg=1
        dis.opmap["JUMP_FORWARD"],
        0,
        0,  # [4] 12, dest=15
        dis.opmap["LOAD_NAME"],
        2,
        0,  # [5] 15, arg=2
        dis.opmap["RAISE_VARARGS"],
        1,
        0,  # [6] 18, arg=1
        dis.opmap["LOAD_CONST"],
        1,
        0,  # [7] 21 (unreachable), arg=1
        dis.opmap["STORE_NAME"],
        1,
        0,  # [8] 24 (unreachable), arg=1
        dis.opmap["LOAD_CONST"],
        2,
        0,  # [9] 27 (unreachable), arg=2
        dis.opmap["RETURN_VALUE"],  # [10] 30 (unreachable)
    ])

    def test_each_instruction_once_dead_code(self):
        code_deadcode = pyc.compile_src(src=self.src_deadcode,
                                        python_version=self.python_version,
                                        python_exe=utils.get_python_exe(
                                            self.python_version),
                                        filename="<>")
        self.assertEqual(code_deadcode.co_code, self.code_deadcode)
        try:
            self.trace_vm.run_program(self.src_deadcode, "", maximum_depth=10)
        except vm.VirtualMachineError:
            pass  # The code we test throws an exception. Ignore it.
        six.assertCountEqual(self, self.trace_vm.instructions_executed,
                             [0, 1, 5, 6])
示例#4
0
 def dis(self, code):
     """Return the opcodes from disassbling a code sequence."""
     return opcodes.dis(compat.int_array_to_bytes(code),
                        self.PYTHON_VERSION)
示例#5
0
 def dis(self, code):
   """Return the opcodes from disassbling a code sequence."""
   return opcodes.dis(compat.int_array_to_bytes(code), self.python_version)