def test_legalize(self): code = Bytecode() code.first_lineno = 3 code.extend( [ Instr("LOAD_CONST", 7), Instr("STORE_NAME", "x"), Instr("LOAD_CONST", 8, lineno=4), Instr("STORE_NAME", "y"), SetLineno(5), Instr("LOAD_CONST", 9, lineno=6), Instr("STORE_NAME", "z"), ] ) blocks = ControlFlowGraph.from_bytecode(code) blocks.legalize() self.assertBlocksEqual( blocks, [ Instr("LOAD_CONST", 7, lineno=3), Instr("STORE_NAME", "x", lineno=3), Instr("LOAD_CONST", 8, lineno=4), Instr("STORE_NAME", "y", lineno=4), Instr("LOAD_CONST", 9, lineno=5), Instr("STORE_NAME", "z", lineno=5), ], )
def test_setlineno(self): # x = 7 # y = 8 # z = 9 code = Bytecode() code.first_lineno = 3 code.extend([ Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y'), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", 'z') ]) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.consts, [7, 8, 9]) self.assertEqual(concrete.names, ['x', 'y', 'z']) code.extend([ ConcreteInstr("LOAD_CONST", 0, lineno=3), ConcreteInstr("STORE_NAME", 0, lineno=3), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1, lineno=4), ConcreteInstr("LOAD_CONST", 2, lineno=5), ConcreteInstr("STORE_NAME", 2, lineno=5) ])
def test_setlineno(self): # x = 7 # y = 8 # z = 9 code = Bytecode() code.first_lineno = 3 code.extend( [ Instr("LOAD_CONST", 7), Instr("STORE_NAME", "x"), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", "y"), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", "z"), ] ) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.consts, [7, 8, 9]) self.assertEqual(concrete.names, ["x", "y", "z"]) self.assertListEqual( list(concrete), [ ConcreteInstr("LOAD_CONST", 0, lineno=3), ConcreteInstr("STORE_NAME", 0, lineno=3), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1, lineno=4), ConcreteInstr("LOAD_CONST", 2, lineno=5), ConcreteInstr("STORE_NAME", 2, lineno=5), ], )
def test_negative_size_unpack(self): with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr("UNPACK_SEQUENCE", 1)]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_copy(self): code = Bytecode() code.first_lineno = 3 code.extend( [ Instr("LOAD_CONST", 7), Instr("STORE_NAME", "x"), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", "y"), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", "z"), ] ) copy_code = code.copy() self.assertEqual(code, copy_code) for name in ( "argcount", "posonlyargcount", "kwonlyargcount", "first_lineno", "name", "filename", "docstring", "cellvars", "freevars", "argnames", ): self.assertEqual(getattr(code, name, None), getattr(copy_code, name, None))
def test_legalize(self): code = Bytecode() code.first_lineno = 3 code.extend( [ Instr("LOAD_CONST", 7), Instr("STORE_NAME", "x"), Instr("LOAD_CONST", 8, lineno=4), Instr("STORE_NAME", "y"), Label(), SetLineno(5), Instr("LOAD_CONST", 9, lineno=6), Instr("STORE_NAME", "z"), ] ) code.legalize() self.assertListEqual( code, [ Instr("LOAD_CONST", 7, lineno=3), Instr("STORE_NAME", "x", lineno=3), Instr("LOAD_CONST", 8, lineno=4), Instr("STORE_NAME", "y", lineno=4), Label(), Instr("LOAD_CONST", 9, lineno=5), Instr("STORE_NAME", "z", lineno=5), ], )
def test_setlineno(self): # x = 7 # y = 8 # z = 9 code = Bytecode() code.first_lineno = 3 code.extend([Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y'), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", 'z')]) blocks = ControlFlowGraph.from_bytecode(code) self.assertBlocksEqual(blocks, [Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y'), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", 'z')])
def test_slice(self): code = Bytecode() code.first_lineno = 3 code.extend([ Instr("LOAD_CONST", 7), Instr("STORE_NAME", "x"), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", "y"), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", "z"), ]) sliced_code = code[:] self.assertEqual(code, sliced_code) for name in ( "argcount", "posonlyargcount", "first_lineno", "name", "filename", "docstring", "cellvars", "freevars", "argnames", ): Undefined = object() self.assertEqual(getattr(code, name, Undefined), getattr(sliced_code, name, Undefined))
def test_negative_size_build_const_map(self): code = Bytecode() code.first_lineno = 1 code.extend( [Instr("LOAD_CONST", ("a", )), Instr("BUILD_CONST_KEY_MAP", 1)]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_negative_size_build_const_map_with_disable_check_of_pre_and_post( self): code = Bytecode() code.first_lineno = 1 code.extend( [Instr("LOAD_CONST", ("a", )), Instr("BUILD_CONST_KEY_MAP", 1)]) co = code.to_code(check_pre_and_post=False) self.assertEqual(co.co_stacksize, 1)
def test_not_enough_rot_with_disable_check_of_pre_and_post(self): opnames = ["ROT_TWO", "ROT_THREE"] for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr("LOAD_CONST", 1), Instr(opname)]) co = code.to_code(check_pre_and_post=False) self.assertEqual(co.co_stacksize, 1)
def test_not_enough_rot(self): opnames = ["ROT_TWO", "ROT_THREE"] for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr("LOAD_CONST", 1), Instr(opname)]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_handling_of_extended_arg(self): code = Bytecode() code.first_lineno = 3 code.extend([Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), Instr("EXTENDED_ARG", 1), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y')]) self.assertEqual(code.compute_stacksize(), 1)
def test_handling_of_set_lineno(self): code = Bytecode() code.first_lineno = 3 code.extend([Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y'), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", 'z')]) self.assertEqual(code.compute_stacksize(), 1)
def test_negative_size_build(self): opnames = ( "BUILD_TUPLE", "BUILD_LIST", "BUILD_SET", ) for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr(opname, 1)]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_negative_size_unary_with_disable_check_of_pre_and_post(self): opnames = ( "UNARY_POSITIVE", "UNARY_NEGATIVE", "UNARY_NOT", "UNARY_INVERT", ) for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr(opname)]) co = code.to_code(check_pre_and_post=False) self.assertEqual(co.co_stacksize, 0)
def test_negative_size_unary(self): opnames = ( "UNARY_POSITIVE", "UNARY_NEGATIVE", "UNARY_NOT", "UNARY_INVERT", ) for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr(opname)]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_to_code(self): code = Bytecode() code.first_lineno = 50 code.extend([Instr("LOAD_NAME", "print"), Instr("LOAD_CONST", "%s"), Instr("LOAD_GLOBAL", "a"), Instr("BINARY_MODULO"), Instr("CALL_FUNCTION", 1), Instr("RETURN_VALUE")]) co = code.to_code() # hopefully this is obvious from inspection? :-) self.assertEqual(co.co_stacksize, 3) co = code.to_code(stacksize=42) self.assertEqual(co.co_stacksize, 42)
def test_for_iter_stack_effect_computation(self): with self.subTest(): code = Bytecode() code.first_lineno = 1 lab1 = Label() lab2 = Label() code.extend([ lab1, Instr("FOR_ITER", lab2), Instr("STORE_FAST", "i"), Instr("JUMP_ABSOLUTE", lab1), lab2, ]) with self.assertRaises(RuntimeError): # Use compute_stacksize since the code is so broken that conversion # to from concrete is actually broken code.compute_stacksize(check_pre_and_post=False)
def test_to_code(self): code = Bytecode() code.first_lineno = 50 code.extend([ Instr("LOAD_NAME", "print"), Instr("LOAD_CONST", "%s"), Instr("LOAD_GLOBAL", "a"), Instr("BINARY_MODULO"), Instr("CALL_FUNCTION", 1), Instr("RETURN_VALUE"), ]) co = code.to_code() # hopefully this is obvious from inspection? :-) self.assertEqual(co.co_stacksize, 3) co = code.to_code(stacksize=42) self.assertEqual(co.co_stacksize, 42)
def test_negative_size_binary_with_disable_check_of_pre_and_post(self): opnames = ( "BINARY_POWER", "BINARY_MULTIPLY", "BINARY_FLOOR_DIVIDE", "BINARY_TRUE_DIVIDE", "BINARY_MODULO", "BINARY_ADD", "BINARY_SUBTRACT", "BINARY_SUBSCR", "BINARY_LSHIFT", "BINARY_RSHIFT", "BINARY_AND", "BINARY_XOR", "BINARY_OR", ) for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr("LOAD_CONST", 1), Instr(opname)]) co = code.to_code(check_pre_and_post=False) self.assertEqual(co.co_stacksize, 1)
def test_negative_size_binary(self): opnames = ( "BINARY_POWER", "BINARY_MULTIPLY", "BINARY_FLOOR_DIVIDE", "BINARY_TRUE_DIVIDE", "BINARY_MODULO", "BINARY_ADD", "BINARY_SUBTRACT", "BINARY_SUBSCR", "BINARY_LSHIFT", "BINARY_RSHIFT", "BINARY_AND", "BINARY_XOR", "BINARY_OR", ) for opname in opnames: with self.subTest(): code = Bytecode() code.first_lineno = 1 code.extend([Instr("LOAD_CONST", 1), Instr(opname)]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_setlineno(self): # x = 7 # y = 8 # z = 9 code = Bytecode() code.first_lineno = 3 code.extend([Instr("LOAD_CONST", 7), Instr("STORE_NAME", 'x'), SetLineno(4), Instr("LOAD_CONST", 8), Instr("STORE_NAME", 'y'), SetLineno(5), Instr("LOAD_CONST", 9), Instr("STORE_NAME", 'z')]) concrete = code.to_concrete_bytecode() self.assertEqual(concrete.consts, [7, 8, 9]) self.assertEqual(concrete.names, ['x', 'y', 'z']) code.extend([ConcreteInstr("LOAD_CONST", 0, lineno=3), ConcreteInstr("STORE_NAME", 0, lineno=3), ConcreteInstr("LOAD_CONST", 1, lineno=4), ConcreteInstr("STORE_NAME", 1, lineno=4), ConcreteInstr("LOAD_CONST", 2, lineno=5), ConcreteInstr("STORE_NAME", 2, lineno=5)])
def modify(self, code, *, inner=False): initial_bytecode = Bytecode.from_code(code) modified_bytecode = Bytecode() modified_bytecode.first_lineno = initial_bytecode.first_lineno modified_bytecode.argcount = code.co_argcount modified_bytecode.argnames = initial_bytecode.argnames modified_bytecode.name = initial_bytecode.name modified_bytecode.freevars = code.co_freevars modified_bytecode.cellvars = code.co_cellvars first_line_no = initial_bytecode.first_lineno if inner: modified_bytecode.extend([ Instr('LOAD_NAME', arg=self._command, lineno=first_line_no), Instr('LOAD_CONST', arg=DebugCommand.STEP_OVER, lineno=first_line_no), Instr('COMPARE_OP', arg=Compare.EQ, lineno=first_line_no), Instr('STORE_NAME', arg='is_over', lineno=first_line_no), ]) # добавляем инструкции отладки перед первой строкой модуля if not inner: modified_bytecode.extend( self._get_trace_func_call_instructions(first_line_no)) previous_line_no = first_line_no for instr in initial_bytecode: if not isinstance(instr, Instr): modified_bytecode.append(instr) continue if isinstance(instr.arg, types.CodeType): old_instr_name = instr.name new_co = self.modify(instr.arg, inner=True) instr.set(old_instr_name, new_co) skip = Label() if instr.lineno != previous_line_no: if inner: modified_bytecode.extend([ Instr('LOAD_NAME', arg='is_over', lineno=instr.lineno), Instr('POP_JUMP_IF_TRUE', arg=skip, lineno=instr.lineno) ]) modified_bytecode.extend([ Instr('LOAD_NAME', arg=self._command, lineno=instr.lineno), Instr('LOAD_CONST', arg=DebugCommand.STEP_OUT, lineno=instr.lineno), Instr('COMPARE_OP', arg=Compare.EQ, lineno=instr.lineno), Instr('POP_JUMP_IF_TRUE', arg=skip, lineno=instr.lineno) ]) modified_bytecode.extend( self._get_trace_func_call_instructions(instr.lineno)) if inner: modified_bytecode.append(skip) previous_line_no = instr.lineno modified_bytecode.append(instr) code = modified_bytecode.to_code() return code
def test_not_enough_dup(self): code = Bytecode() code.first_lineno = 1 code.extend([Instr("LOAD_CONST", 1), Instr("DUP_TOP_TWO")]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_empty_dup(self): code = Bytecode() code.first_lineno = 1 code.extend([Instr("DUP_TOP")]) with self.assertRaises(RuntimeError): code.compute_stacksize()
def test_negative_size_call(self): code = Bytecode() code.first_lineno = 1 code.extend([Instr("CALL_FUNCTION", 0)]) with self.assertRaises(RuntimeError): code.compute_stacksize()