1cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2cef7893435aa41160dd1255c43cb8498279738ccChris Craik# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3cef7893435aa41160dd1255c43cb8498279738ccChris Craik
4cef7893435aa41160dd1255c43cb8498279738ccChris Craik"""Bytecode manipulation for coverage.py"""
5cef7893435aa41160dd1255c43cb8498279738ccChris Craik
6cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport opcode
7cef7893435aa41160dd1255c43cb8498279738ccChris Craikimport types
8cef7893435aa41160dd1255c43cb8498279738ccChris Craik
9cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom coverage.backward import byte_to_int
10cef7893435aa41160dd1255c43cb8498279738ccChris Craik
11cef7893435aa41160dd1255c43cb8498279738ccChris Craik
12cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass ByteCode(object):
13cef7893435aa41160dd1255c43cb8498279738ccChris Craik    """A single bytecode."""
14cef7893435aa41160dd1255c43cb8498279738ccChris Craik    def __init__(self):
15cef7893435aa41160dd1255c43cb8498279738ccChris Craik        # The offset of this bytecode in the code object.
16cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.offset = -1
17cef7893435aa41160dd1255c43cb8498279738ccChris Craik
18cef7893435aa41160dd1255c43cb8498279738ccChris Craik        # The opcode, defined in the `opcode` module.
19cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.op = -1
20cef7893435aa41160dd1255c43cb8498279738ccChris Craik
21cef7893435aa41160dd1255c43cb8498279738ccChris Craik        # The argument, a small integer, whose meaning depends on the opcode.
22cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.arg = -1
23cef7893435aa41160dd1255c43cb8498279738ccChris Craik
24cef7893435aa41160dd1255c43cb8498279738ccChris Craik        # The offset in the code object of the next bytecode.
25cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.next_offset = -1
26cef7893435aa41160dd1255c43cb8498279738ccChris Craik
27cef7893435aa41160dd1255c43cb8498279738ccChris Craik        # The offset to jump to.
28cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.jump_to = -1
29cef7893435aa41160dd1255c43cb8498279738ccChris Craik
30cef7893435aa41160dd1255c43cb8498279738ccChris Craik
31cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass ByteCodes(object):
32cef7893435aa41160dd1255c43cb8498279738ccChris Craik    """Iterator over byte codes in `code`.
33cef7893435aa41160dd1255c43cb8498279738ccChris Craik
34cef7893435aa41160dd1255c43cb8498279738ccChris Craik    This handles the logic of EXTENDED_ARG byte codes internally.  Those byte
35cef7893435aa41160dd1255c43cb8498279738ccChris Craik    codes are not returned by this iterator.
36cef7893435aa41160dd1255c43cb8498279738ccChris Craik
37cef7893435aa41160dd1255c43cb8498279738ccChris Craik    Returns `ByteCode` objects.
38cef7893435aa41160dd1255c43cb8498279738ccChris Craik
39cef7893435aa41160dd1255c43cb8498279738ccChris Craik    """
40cef7893435aa41160dd1255c43cb8498279738ccChris Craik    def __init__(self, code):
41cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.code = code
42cef7893435aa41160dd1255c43cb8498279738ccChris Craik
43cef7893435aa41160dd1255c43cb8498279738ccChris Craik    def __getitem__(self, i):
44cef7893435aa41160dd1255c43cb8498279738ccChris Craik        return byte_to_int(self.code[i])
45cef7893435aa41160dd1255c43cb8498279738ccChris Craik
46cef7893435aa41160dd1255c43cb8498279738ccChris Craik    def __iter__(self):
47cef7893435aa41160dd1255c43cb8498279738ccChris Craik        offset = 0
48cef7893435aa41160dd1255c43cb8498279738ccChris Craik        ext_arg = 0
49cef7893435aa41160dd1255c43cb8498279738ccChris Craik        while offset < len(self.code):
50cef7893435aa41160dd1255c43cb8498279738ccChris Craik            bc = ByteCode()
51cef7893435aa41160dd1255c43cb8498279738ccChris Craik            bc.op = self[offset]
52cef7893435aa41160dd1255c43cb8498279738ccChris Craik            bc.offset = offset
53cef7893435aa41160dd1255c43cb8498279738ccChris Craik
54cef7893435aa41160dd1255c43cb8498279738ccChris Craik            next_offset = offset+1
55cef7893435aa41160dd1255c43cb8498279738ccChris Craik            if bc.op >= opcode.HAVE_ARGUMENT:
56cef7893435aa41160dd1255c43cb8498279738ccChris Craik                bc.arg = ext_arg + self[offset+1] + 256*self[offset+2]
57cef7893435aa41160dd1255c43cb8498279738ccChris Craik                next_offset += 2
58cef7893435aa41160dd1255c43cb8498279738ccChris Craik
59cef7893435aa41160dd1255c43cb8498279738ccChris Craik                label = -1
60cef7893435aa41160dd1255c43cb8498279738ccChris Craik                if bc.op in opcode.hasjrel:
61cef7893435aa41160dd1255c43cb8498279738ccChris Craik                    label = next_offset + bc.arg
62cef7893435aa41160dd1255c43cb8498279738ccChris Craik                elif bc.op in opcode.hasjabs:
63cef7893435aa41160dd1255c43cb8498279738ccChris Craik                    label = bc.arg
64cef7893435aa41160dd1255c43cb8498279738ccChris Craik                bc.jump_to = label
65cef7893435aa41160dd1255c43cb8498279738ccChris Craik
66cef7893435aa41160dd1255c43cb8498279738ccChris Craik            bc.next_offset = offset = next_offset
67cef7893435aa41160dd1255c43cb8498279738ccChris Craik            if bc.op == opcode.EXTENDED_ARG:
68cef7893435aa41160dd1255c43cb8498279738ccChris Craik                ext_arg = bc.arg * 256*256
69cef7893435aa41160dd1255c43cb8498279738ccChris Craik            else:
70cef7893435aa41160dd1255c43cb8498279738ccChris Craik                ext_arg = 0
71cef7893435aa41160dd1255c43cb8498279738ccChris Craik                yield bc
72cef7893435aa41160dd1255c43cb8498279738ccChris Craik
73cef7893435aa41160dd1255c43cb8498279738ccChris Craik
74cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass CodeObjects(object):
75cef7893435aa41160dd1255c43cb8498279738ccChris Craik    """Iterate over all the code objects in `code`."""
76cef7893435aa41160dd1255c43cb8498279738ccChris Craik    def __init__(self, code):
77cef7893435aa41160dd1255c43cb8498279738ccChris Craik        self.stack = [code]
78cef7893435aa41160dd1255c43cb8498279738ccChris Craik
79cef7893435aa41160dd1255c43cb8498279738ccChris Craik    def __iter__(self):
80cef7893435aa41160dd1255c43cb8498279738ccChris Craik        while self.stack:
81cef7893435aa41160dd1255c43cb8498279738ccChris Craik            # We're going to return the code object on the stack, but first
82cef7893435aa41160dd1255c43cb8498279738ccChris Craik            # push its children for later returning.
83cef7893435aa41160dd1255c43cb8498279738ccChris Craik            code = self.stack.pop()
84cef7893435aa41160dd1255c43cb8498279738ccChris Craik            for c in code.co_consts:
85cef7893435aa41160dd1255c43cb8498279738ccChris Craik                if isinstance(c, types.CodeType):
86cef7893435aa41160dd1255c43cb8498279738ccChris Craik                    self.stack.append(c)
87cef7893435aa41160dd1255c43cb8498279738ccChris Craik            yield code
88