def test_stack_effects(self): # Verify all opcodes are handled and that "jump=None" really returns # the max of the other cases. from bytecode.concrete import ConcreteInstr def check(instr): jump = instr.stack_effect(jump=True) no_jump = instr.stack_effect(jump=False) max_effect = instr.stack_effect(jump=None) self.assertEqual(instr.stack_effect(), max_effect) self.assertEqual(max_effect, max(jump, no_jump)) if not instr.has_jump(): self.assertEqual(jump, no_jump) for name, op in opcode.opmap.items(): with self.subTest(name): # Use ConcreteInstr instead of Instr because it doesn't care # what kind of argument it is constructed with. if op < opcode.HAVE_ARGUMENT: check(ConcreteInstr(name)) else: for arg in range(256): check(ConcreteInstr(name, arg)) # LOAD_CONST uses a concrete python object as its oparg, however, in # dis.stack_effect(opcode.opmap['LOAD_CONST'], oparg), # oparg should be the index of that python object in the constants. # # Fortunately, for an instruction whose oparg isn't equivalent to its # form in binary files(pyc format), the stack effect is a # constant which does not depend on its oparg. # # The second argument of dis.stack_effect cannot be # more than 2**31 - 1. If stack effect of an instruction is # independent of its oparg, we pass 0 as the second argument # of dis.stack_effect. # (As a result we can calculate stack_effect for # any LOAD_CONST instructions, even for large integers) for arg in 2**31, 2**32, 2**63, 2**64, -1: self.assertEqual(Instr("LOAD_CONST", arg).stack_effect(), 1)
def get_instructions(self): instructions = [] jumps = [] for block in self: target_block = block.get_jump() if target_block is not None: instr = block[-1] instr = ConcreteInstr(instr.name, 0, lineno=instr.lineno) jumps.append((target_block, instr)) instructions.extend(block[:-1]) instructions.append(instr) else: instructions.extend(block) for target_block, instr in jumps: instr.arg = self.get_block_index(target_block) return instructions
def _flat(self): instructions = [] jumps = [] for block in self: target_block = block.get_jump() if target_block is not None: instr = block[-1] instr = ConcreteInstr(instr.name, 0, lineno=instr.lineno) jumps.append((target_block, instr)) instructions.extend(block[:-1]) instructions.append(instr) else: instructions.extend(block) for target_block, instr in jumps: instr.arg = self.get_block_index(target_block) return instructions
def test_stack_effects(self): # Verify all opcodes are handled and that "jump=None" really returns # the max of the other cases. from bytecode.concrete import ConcreteInstr for name, op in opcode.opmap.items(): # Use ConcreteInstr instead of Instr because it doesn't care what # kind of argument it is constructed with. if op < opcode.HAVE_ARGUMENT: instr = ConcreteInstr(name) else: instr = ConcreteInstr(name, 0) jump = instr.stack_effect(jump=True) no_jump = instr.stack_effect(jump=False) max_effect = instr.stack_effect(jump=None) msg = "op=%s" % name self.assertEqual(instr.stack_effect(), max_effect, msg) self.assertEqual(max_effect, max(jump, no_jump), msg) if not instr.has_jump(): self.assertEqual(jump, no_jump, msg)