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