|
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
|
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
|
3 |
1 """Bytecode manipulation for coverage.py""" |
4 """Bytecode manipulation for coverage.py""" |
2 |
5 |
3 import opcode, types |
6 import opcode |
|
7 import types |
4 |
8 |
5 from .backward import byte_to_int |
9 from coverage.backward import byte_to_int |
|
10 |
6 |
11 |
7 class ByteCode(object): |
12 class ByteCode(object): |
8 """A single bytecode.""" |
13 """A single bytecode.""" |
9 def __init__(self): |
14 def __init__(self): |
10 # The offset of this bytecode in the code object. |
15 # The offset of this bytecode in the code object. |
24 |
29 |
25 |
30 |
26 class ByteCodes(object): |
31 class ByteCodes(object): |
27 """Iterator over byte codes in `code`. |
32 """Iterator over byte codes in `code`. |
28 |
33 |
|
34 This handles the logic of EXTENDED_ARG byte codes internally. Those byte |
|
35 codes are not returned by this iterator. |
|
36 |
29 Returns `ByteCode` objects. |
37 Returns `ByteCode` objects. |
30 |
38 |
31 """ |
39 """ |
32 # pylint: disable=R0924 |
|
33 def __init__(self, code): |
40 def __init__(self, code): |
34 self.code = code |
41 self.code = code |
35 |
42 |
36 def __getitem__(self, i): |
43 def __getitem__(self, i): |
37 return byte_to_int(self.code[i]) |
44 return byte_to_int(self.code[i]) |
38 |
45 |
39 def __iter__(self): |
46 def __iter__(self): |
40 offset = 0 |
47 offset = 0 |
|
48 ext_arg = 0 |
41 while offset < len(self.code): |
49 while offset < len(self.code): |
42 bc = ByteCode() |
50 bc = ByteCode() |
43 bc.op = self[offset] |
51 bc.op = self[offset] |
44 bc.offset = offset |
52 bc.offset = offset |
45 |
53 |
46 next_offset = offset+1 |
54 next_offset = offset+1 |
47 if bc.op >= opcode.HAVE_ARGUMENT: |
55 if bc.op >= opcode.HAVE_ARGUMENT: |
48 bc.arg = self[offset+1] + 256*self[offset+2] |
56 bc.arg = ext_arg + self[offset+1] + 256*self[offset+2] |
49 next_offset += 2 |
57 next_offset += 2 |
50 |
58 |
51 label = -1 |
59 label = -1 |
52 if bc.op in opcode.hasjrel: |
60 if bc.op in opcode.hasjrel: |
53 label = next_offset + bc.arg |
61 label = next_offset + bc.arg |
54 elif bc.op in opcode.hasjabs: |
62 elif bc.op in opcode.hasjabs: |
55 label = bc.arg |
63 label = bc.arg |
56 bc.jump_to = label |
64 bc.jump_to = label |
57 |
65 |
58 bc.next_offset = offset = next_offset |
66 bc.next_offset = offset = next_offset |
59 yield bc |
67 if bc.op == opcode.EXTENDED_ARG: |
|
68 ext_arg = bc.arg * 256*256 |
|
69 else: |
|
70 ext_arg = 0 |
|
71 yield bc |
60 |
72 |
61 |
73 |
62 class CodeObjects(object): |
74 class CodeObjects(object): |
63 """Iterate over all the code objects in `code`.""" |
75 """Iterate over all the code objects in `code`.""" |
64 def __init__(self, code): |
76 def __init__(self, code): |