def test_flag_inference(self): # Check no loss of non-infered flags code = ControlFlowGraph() code.flags |= (CompilerFlags.NEWLOCALS | CompilerFlags.VARARGS | CompilerFlags.VARKEYWORDS | CompilerFlags.NESTED | CompilerFlags.FUTURE_GENERATOR_STOP) code.update_flags() for f in (CompilerFlags.NEWLOCALS, CompilerFlags.VARARGS, CompilerFlags.VARKEYWORDS, CompilerFlags.NESTED, CompilerFlags.NOFREE, CompilerFlags.OPTIMIZED, CompilerFlags.FUTURE_GENERATOR_STOP): self.assertTrue(bool(code.flags & f)) # Infer optimized and nofree code = Bytecode() flags = infer_flags(code) self.assertTrue(bool(flags & CompilerFlags.OPTIMIZED)) self.assertTrue(bool(flags & CompilerFlags.NOFREE)) code.append(ConcreteInstr('STORE_NAME', 1)) flags = infer_flags(code) self.assertFalse(bool(flags & CompilerFlags.OPTIMIZED)) self.assertTrue(bool(flags & CompilerFlags.NOFREE)) code.append(ConcreteInstr('STORE_DEREF', 2)) code.update_flags() self.assertFalse(bool(code.flags & CompilerFlags.OPTIMIZED)) self.assertFalse(bool(code.flags & CompilerFlags.NOFREE)) # Infer generator code = ConcreteBytecode() code.append(ConcreteInstr('YIELD_VALUE')) for is_async, expected in ((False, CompilerFlags.GENERATOR), (True, CompilerFlags.ASYNC_GENERATOR)): self.assertTrue(bool(infer_flags(code, is_async) & expected)) # Infer coroutine code = ConcreteBytecode() code.append(ConcreteInstr('GET_AWAITABLE')) iter_flags = CompilerFlags(CompilerFlags.ITERABLE_COROUTINE) for f, expected in ((CompilerFlags(0), True), (iter_flags, False)): code.flags = f self.assertEqual(bool(infer_flags(code) & CompilerFlags.COROUTINE), expected) # Test check flag sanity code.append(ConcreteInstr('YIELD_VALUE')) code.flags = CompilerFlags(CompilerFlags.GENERATOR | CompilerFlags.COROUTINE) infer_flags(code, is_async=True) # Just want to be sure it pases with self.assertRaises(ValueError): code.update_flags() with self.assertRaises(ValueError): infer_flags(None)
def test_flag_inference(self): # Check no loss of non-infered flags code = ControlFlowGraph() code.flags |= (CompilerFlags.NEWLOCALS | CompilerFlags.VARARGS | CompilerFlags.VARKEYWORDS | CompilerFlags.NESTED | CompilerFlags.FUTURE_GENERATOR_STOP) code.update_flags() for f in (CompilerFlags.NEWLOCALS, CompilerFlags.VARARGS, CompilerFlags.VARKEYWORDS, CompilerFlags.NESTED, CompilerFlags.NOFREE, CompilerFlags.OPTIMIZED, CompilerFlags.FUTURE_GENERATOR_STOP): self.assertTrue(bool(code.flags & f)) # Infer optimized and nofree code = Bytecode() flags = infer_flags(code) self.assertTrue(bool(flags & CompilerFlags.OPTIMIZED)) self.assertTrue(bool(flags & CompilerFlags.NOFREE)) code.append(ConcreteInstr('STORE_NAME', 1)) flags = infer_flags(code) self.assertFalse(bool(flags & CompilerFlags.OPTIMIZED)) self.assertTrue(bool(flags & CompilerFlags.NOFREE)) code.append(ConcreteInstr('STORE_DEREF', 2)) code.update_flags() self.assertFalse(bool(code.flags & CompilerFlags.OPTIMIZED)) self.assertFalse(bool(code.flags & CompilerFlags.NOFREE)) # Infer generator code = ConcreteBytecode() code.append(ConcreteInstr('YIELD_VALUE')) for is_async, expected in ((False, CompilerFlags.GENERATOR), (True, CompilerFlags.ASYNC_GENERATOR)): self.assertTrue(bool(infer_flags(code, is_async) & expected)) # Infer coroutine code = ConcreteBytecode() code.append(ConcreteInstr('GET_AWAITABLE')) iter_flags = CompilerFlags(CompilerFlags.ITERABLE_COROUTINE) for f, expected in ((CompilerFlags(0), True), (iter_flags, False)): code.flags = f self.assertEqual(bool(infer_flags(code) & CompilerFlags.COROUTINE), expected) # Test check flag sanity code.append(ConcreteInstr('YIELD_VALUE')) code.flags = CompilerFlags(CompilerFlags.GENERATOR | CompilerFlags.COROUTINE) infer_flags(code, is_async=True) # Just want to be sure it pases with self.assertRaises(ValueError): code.update_flags() with self.assertRaises(ValueError): infer_flags(None)
def test_to_code(self): # test resolution of jump labels bytecode = ControlFlowGraph() bytecode.first_lineno = 3 bytecode.argcount = 3 bytecode.name = "func" bytecode.filename = "hello.py" bytecode.flags = 0x43 bytecode.argnames = ("arg", "arg2", "arg3", "kwonly", "kwonly2") bytecode.docstring = None block0 = bytecode[0] block1 = bytecode.add_block() block2 = bytecode.add_block() block0.extend([ Instr("LOAD_FAST", "x", lineno=4), Instr("POP_JUMP_IF_FALSE", block2, lineno=4), ]) block1.extend([ Instr("LOAD_FAST", "arg", lineno=5), Instr("STORE_FAST", "x", lineno=5) ]) block2.extend([ Instr("LOAD_CONST", 3, lineno=6), Instr("STORE_FAST", "x", lineno=6), Instr("LOAD_FAST", "x", lineno=7), Instr("RETURN_VALUE", lineno=7), ]) expected = (b"|\x05\x00" b"r\x0c\x00" b"|\x00\x00" b"}\x05\x00" b"d\x01\x00" b"}\x05\x00" b"|\x05\x00" b"S") code = bytecode.to_code() self.assertEqual(code.co_consts, (None, 3)) self.assertEqual(code.co_argcount, 3) self.assertEqual(code.co_nlocals, 6) self.assertEqual(code.co_stacksize, 1) # FIXME: don't use hardcoded constants self.assertEqual(code.co_flags, 0x43) self.assertEqual(code.co_code, expected) self.assertEqual(code.co_names, ()) self.assertEqual(code.co_varnames, ("arg", "arg2", "arg3", "kwonly", "kwonly2", "x")) self.assertEqual(code.co_filename, "hello.py") self.assertEqual(code.co_name, "func") self.assertEqual(code.co_firstlineno, 3) # verify stacksize argument is honored explicit_stacksize = code.co_stacksize + 42 code = bytecode.to_code(stacksize=explicit_stacksize) self.assertEqual(code.co_stacksize, explicit_stacksize)
def test_to_code(self): # test resolution of jump labels bytecode = ControlFlowGraph() bytecode.first_lineno = 3 bytecode.argcount = 3 bytecode.kwonlyargcount = 2 bytecode._stacksize = 1 bytecode.name = 'func' bytecode.filename = 'hello.py' bytecode.flags = 0x43 bytecode.argnames = ('arg', 'arg2', 'arg3', 'kwonly', 'kwonly2') bytecode.docstring = None block0 = bytecode[0] block1 = bytecode.add_block() block2 = bytecode.add_block() block0.extend([ Instr('LOAD_FAST', 'x', lineno=4), Instr('POP_JUMP_IF_FALSE', block2, lineno=4) ]) block1.extend([ Instr('LOAD_FAST', 'arg', lineno=5), Instr('STORE_FAST', 'x', lineno=5) ]) block2.extend([ Instr('LOAD_CONST', 3, lineno=6), Instr('STORE_FAST', 'x', lineno=6), Instr('LOAD_FAST', 'x', lineno=7), Instr('RETURN_VALUE', lineno=7) ]) expected = (b'|\x05\x00' b'r\x0c\x00' b'|\x00\x00' b'}\x05\x00' b'd\x01\x00' b'}\x05\x00' b'|\x05\x00' b'S') code = bytecode.to_bytecode().to_code() self.assertEqual(code.co_consts, (None, 3)) self.assertEqual(code.co_argcount, 3) self.assertEqual(code.co_kwonlyargcount, 2) self.assertEqual(code.co_nlocals, 6) self.assertEqual(code.co_stacksize, 1) # FIXME: don't use hardcoded constants self.assertEqual(code.co_flags, 0x43) self.assertEqual(code.co_code, expected) self.assertEqual(code.co_names, ()) self.assertEqual(code.co_varnames, ('arg', 'arg2', 'arg3', 'kwonly', 'kwonly2', 'x')) self.assertEqual(code.co_filename, 'hello.py') self.assertEqual(code.co_name, 'func') self.assertEqual(code.co_firstlineno, 3)
def test_to_code(self): # test resolution of jump labels bytecode = ControlFlowGraph() bytecode.first_lineno = 3 bytecode.argcount = 3 bytecode.kwonlyargcount = 2 bytecode._stacksize = 1 bytecode.name = 'func' bytecode.filename = 'hello.py' bytecode.flags = 0x43 bytecode.argnames = ('arg', 'arg2', 'arg3', 'kwonly', 'kwonly2') bytecode.docstring = None block0 = bytecode[0] block1 = bytecode.add_block() block2 = bytecode.add_block() block0.extend([Instr('LOAD_FAST', 'x', lineno=4), Instr('POP_JUMP_IF_FALSE', block2, lineno=4)]) block1.extend([Instr('LOAD_FAST', 'arg', lineno=5), Instr('STORE_FAST', 'x', lineno=5)]) block2.extend([Instr('LOAD_CONST', 3, lineno=6), Instr('STORE_FAST', 'x', lineno=6), Instr('LOAD_FAST', 'x', lineno=7), Instr('RETURN_VALUE', lineno=7)]) expected = (b'|\x05\x00' b'r\x0c\x00' b'|\x00\x00' b'}\x05\x00' b'd\x01\x00' b'}\x05\x00' b'|\x05\x00' b'S') code = bytecode.to_bytecode().to_code() self.assertEqual(code.co_consts, (None, 3)) self.assertEqual(code.co_argcount, 3) self.assertEqual(code.co_kwonlyargcount, 2) self.assertEqual(code.co_nlocals, 6) self.assertEqual(code.co_stacksize, 1) # FIXME: don't use hardcoded constants self.assertEqual(code.co_flags, 0x43) self.assertEqual(code.co_code, expected) self.assertEqual(code.co_names, ()) self.assertEqual(code.co_varnames, ('arg', 'arg2', 'arg3', 'kwonly', 'kwonly2', 'x')) self.assertEqual(code.co_filename, 'hello.py') self.assertEqual(code.co_name, 'func') self.assertEqual(code.co_firstlineno, 3)
def test_to_code(self): # test resolution of jump labels bytecode = ControlFlowGraph() bytecode.first_lineno = 3 bytecode.argcount = 3 if sys.version_info > (3, 8): bytecode.posonlyargcount = 0 bytecode.kwonlyargcount = 2 bytecode.name = 'func' bytecode.filename = 'hello.py' bytecode.flags = 0x43 bytecode.argnames = ('arg', 'arg2', 'arg3', 'kwonly', 'kwonly2') bytecode.docstring = None block0 = bytecode[0] block1 = bytecode.add_block() block2 = bytecode.add_block() block0.extend([Instr('LOAD_FAST', 'x', lineno=4), Instr('POP_JUMP_IF_FALSE', block2, lineno=4)]) block1.extend([Instr('LOAD_FAST', 'arg', lineno=5), Instr('STORE_FAST', 'x', lineno=5)]) block2.extend([Instr('LOAD_CONST', 3, lineno=6), Instr('STORE_FAST', 'x', lineno=6), Instr('LOAD_FAST', 'x', lineno=7), Instr('RETURN_VALUE', lineno=7)]) if WORDCODE: expected = (b'|\x05' b'r\x08' b'|\x00' b'}\x05' b'd\x01' b'}\x05' b'|\x05' b'S\x00') else: expected = (b'|\x05\x00' b'r\x0c\x00' b'|\x00\x00' b'}\x05\x00' b'd\x01\x00' b'}\x05\x00' b'|\x05\x00' b'S') code = bytecode.to_code() self.assertEqual(code.co_consts, (None, 3)) self.assertEqual(code.co_argcount, 3) if sys.version_info > (3, 8): self.assertEqual(code.co_posonlyargcount, 0) self.assertEqual(code.co_kwonlyargcount, 2) self.assertEqual(code.co_nlocals, 6) self.assertEqual(code.co_stacksize, 1) # FIXME: don't use hardcoded constants self.assertEqual(code.co_flags, 0x43) self.assertEqual(code.co_code, expected) self.assertEqual(code.co_names, ()) self.assertEqual(code.co_varnames, ('arg', 'arg2', 'arg3', 'kwonly', 'kwonly2', 'x')) self.assertEqual(code.co_filename, 'hello.py') self.assertEqual(code.co_name, 'func') self.assertEqual(code.co_firstlineno, 3) # verify stacksize argument is honored explicit_stacksize = code.co_stacksize + 42 code = bytecode.to_code(stacksize=explicit_stacksize) self.assertEqual(code.co_stacksize, explicit_stacksize)
def test_to_code(self): # test resolution of jump labels bytecode = ControlFlowGraph() bytecode.first_lineno = 3 bytecode.argcount = 3 if sys.version_info > (3, 8): bytecode.posonlyargcount = 0 bytecode.kwonlyargcount = 2 bytecode.name = "func" bytecode.filename = "hello.py" bytecode.flags = 0x43 bytecode.argnames = ("arg", "arg2", "arg3", "kwonly", "kwonly2") bytecode.docstring = None block0 = bytecode[0] block1 = bytecode.add_block() block2 = bytecode.add_block() block0.extend([ Instr("LOAD_FAST", "x", lineno=4), Instr("POP_JUMP_IF_FALSE", block2, lineno=4), ]) block1.extend([ Instr("LOAD_FAST", "arg", lineno=5), Instr("STORE_FAST", "x", lineno=5) ]) block2.extend([ Instr("LOAD_CONST", 3, lineno=6), Instr("STORE_FAST", "x", lineno=6), Instr("LOAD_FAST", "x", lineno=7), Instr("RETURN_VALUE", lineno=7), ]) if OFFSET_AS_INSTRUCTION: # The argument of the jump is divided by 2 expected = (b"|\x05" b"r\x04" b"|\x00" b"}\x05" b"d\x01" b"}\x05" b"|\x05" b"S\x00") else: expected = (b"|\x05" b"r\x08" b"|\x00" b"}\x05" b"d\x01" b"}\x05" b"|\x05" b"S\x00") code = bytecode.to_code() self.assertEqual(code.co_consts, (None, 3)) self.assertEqual(code.co_argcount, 3) if sys.version_info > (3, 8): self.assertEqual(code.co_posonlyargcount, 0) self.assertEqual(code.co_kwonlyargcount, 2) self.assertEqual(code.co_nlocals, 6) self.assertEqual(code.co_stacksize, 1) # FIXME: don't use hardcoded constants self.assertEqual(code.co_flags, 0x43) self.assertEqual(code.co_code, expected) self.assertEqual(code.co_names, ()) self.assertEqual(code.co_varnames, ("arg", "arg2", "arg3", "kwonly", "kwonly2", "x")) self.assertEqual(code.co_filename, "hello.py") self.assertEqual(code.co_name, "func") self.assertEqual(code.co_firstlineno, 3) # verify stacksize argument is honored explicit_stacksize = code.co_stacksize + 42 code = bytecode.to_code(stacksize=explicit_stacksize) self.assertEqual(code.co_stacksize, explicit_stacksize)