def testDiamond(self): self.assertEqual(self.codeDiamond.func_code.co_code, self.codeDiamondBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeDiamond.func_code) expected = [(0, 15), (18, 28), (31, 38), (41, 44)] self.checkBlocks(table, expected) bb = table.get_basic_block # Check the POP_JUMP_IF_FALSE conditional jump self.assertItemsEqual(bb(0).outgoing, [bb(18), bb(31)]) # Check the jumps at the end of the 2 of branches self.assertItemsEqual(bb(18).outgoing, [bb(41)]) self.assertItemsEqual(bb(38).outgoing, [bb(41)]) # Check the return self.assertItemsEqual(bb(44).outgoing, [None]) # Check the incoming of the entry block self.assertItemsEqual(bb(0).incoming, []) # Check the incoming of the 2 if branches self.assertItemsEqual(bb(18).incoming, [bb(15)]) self.assertItemsEqual(bb(31).incoming, [bb(15)]) # Check incoming of the merge block. self.assertItemsEqual(bb(44).incoming, [bb(28), bb(38)])
def testNestedLoopsOrder(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeNestedLoops.func_code) bb = table.get_basic_block self.assertEqual(table.get_ancestors_first_traversal(), [bb(o) for o in [0, 13, 16, 26, 29, 49, 50, 53, 54]])
def testNestedLoops(self): self.assertEqual(self.codeNestedLoops.func_code.co_code, self.codeNestedLoopsBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeNestedLoops.func_code) expected = [(0, 12), (13, 13), (16, 25), (26, 26), (29, 46), (49, 49), (50, 50), (53, 53), (54, 57)] self.checkBlocks(table, expected) bb = table.get_basic_block self.assertItemsEqual(bb(13).incoming, [bb(12), bb(50)]) self.assertItemsEqual(bb(13).outgoing, [bb(16), bb(53)]) self.assertItemsEqual(bb(26).incoming, [bb(25), bb(46)]) self.assertItemsEqual(bb(26).outgoing, [bb(29), bb(49)]) self.assertEndsWith( bb(43).get_name(), "tests/test_pycfg.py:{}-{}".format(self.codeNestedLoopsLineNumber + 2, self.codeNestedLoopsLineNumber + 3))
def testRaiseOrder(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeRaise.func_code) bb = table.get_basic_block self.assertEqual(table.get_ancestors_first_traversal(), [bb(o) for o in [0, 6, 9]])
def testDiamondOrder(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeDiamond.func_code) bb = table.get_basic_block self.assertEqual(table.get_ancestors_first_traversal(), [bb(o) for o in [0, 18, 31, 41]])
def testLoopOrder(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeLoop.func_code) bb = table.get_basic_block self.assertEqual(table.get_ancestors_first_traversal(), [bb(o) for o in [0, 13, 16, 32, 33]])
def testBreak(self): self.assertEqual(self.codeBreak.func_code.co_code, self.codeBreakBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeBreak.func_code) bb = table.get_basic_block self.assertItemsEqual(bb(13).incoming, [bb(12), bb(49)]) self.assertItemsEqual(bb(31).incoming, [bb(28)]) self.assertItemsEqual(bb(31).outgoing, [None])
def testContinue(self): self.assertEqual(self.codeContinue.func_code.co_code, self.codeContinueBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeContinue.func_code) bb = table.get_basic_block self.assertItemsEqual(bb(31).outgoing, [bb(13)]) self.assertItemsEqual(bb(13).incoming, [bb(12), bb(51), bb(31)]) self.assertItemsEqual(bb(13).outgoing, [bb(16), bb(54)])
def testLoopDominators(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeLoop.func_code) bb = table.get_basic_block self.assertEqual(bb(0)._dominators, {bb(0)}) self.assertEqual(bb(13)._dominators, {bb(0), bb(13)}) self.assertEqual(bb(16)._dominators, {bb(0), bb(13), bb(16)}) self.assertEqual(bb(32)._dominators, {bb(0), bb(13), bb(32)}) self.assertEqual(bb(33)._dominators, {bb(0), bb(13), bb(32), bb(33)})
def testNestedLoopsReachable(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeNestedLoops.func_code) bb = table.get_basic_block self.assertEqual(bb(26)._reachable_from, set([bb(0), bb(13), bb(16), bb(26), bb(29), bb(49), bb(50)])) self.assertTrue(table.reachable_from(41, 50)) self.assertTrue(table.reachable_from(50, 41)) self.assertFalse(table.reachable_from(41, 53))
def testDiamondDominators(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeDiamond.func_code) bb = table.get_basic_block self.assertEqual(bb(0)._dominators, {bb(0)}) self.assertEqual(bb(18)._dominators, {bb(0), bb(18)}) self.assertEqual(bb(31)._dominators, {bb(0), bb(31)}) self.assertEqual(bb(41)._dominators, {bb(0), bb(41)}) self.assertTrue(table.dominates(0, 37)) self.assertFalse(table.dominates(24, 41)) self.assertTrue(table.dominates(21, 28)) self.assertFalse(table.dominates(28, 21))
def testOneBlock(self): # Check the code to make sure the test will fail if the compilation changes. self.assertEqual(self.codeOneBlock.func_code.co_code, self.codeOneBlockBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeOneBlock.func_code) # Should all be one basic block. self.assertIs(table.get_basic_block(0), table.get_basic_block(3)) self.assertIs(table.get_basic_block(0), table.get_basic_block(6)) self.assertIs(table.get_basic_block(0), table.get_basic_block(7)) # No incoming self.assertItemsEqual(table.get_basic_block(0).incoming, []) # Outgoing is an unknown return location self.assertItemsEqual(table.get_basic_block(0).outgoing, [None])
def testLoop(self): self.assertEqual(self.codeLoop.func_code.co_code, self.codeLoopBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeLoop.func_code) expected = [(0, 12), (13, 13), (16, 29), (32, 32), (33, 36)] self.checkBlocks(table, expected) bb = table.get_basic_block # Check outgoing of the loop handler instruction. self.assertItemsEqual(bb(13).outgoing, [bb(16), bb(32)]) self.assertItemsEqual(bb(0).outgoing, [bb(13)])
def testYield(self): self.assertEqual(self.codeYield.func_code.co_code, self.codeYieldBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeYield.func_code) expected = [(0, 3), (4, 8), (9, 13), (14, 18)] self.checkBlocks(table, expected) bb = table.get_basic_block # We both branch to unknown and to the best instruction for each yield. self.assertItemsEqual(bb(0).outgoing, [None, bb(4)]) self.assertItemsEqual(bb(4).outgoing, [None, bb(9)]) self.assertItemsEqual(bb(9).incoming, [bb(8)]) self.assertItemsEqual(bb(9).outgoing, [None, bb(14)])
def testRaise(self): self.assertEqual(self.codeRaise.func_code.co_code, self.codeRaiseBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeRaise.func_code) expected = [(0, 3), (6, 6), (9, 12)] self.checkBlocks(table, expected) bb = table.get_basic_block # CALL_FUNCTION could either continue or raise self.assertItemsEqual(bb(0).outgoing, [bb(6), None]) # RAISE_VARARGS always raises self.assertItemsEqual(bb(6).outgoing, [None]) # This basic block is unreachable self.assertItemsEqual(bb(9).incoming, []) # We return to an unknown location self.assertItemsEqual(bb(9).outgoing, [None])
def testTriangle(self): self.assertEqual(self.codeTriangle.func_code.co_code, self.codeTriangleBytecode) cfg = pycfg.CFG() table = cfg.get_block_table(self.codeTriangle.func_code) expected = [(0, 15), (18, 28), (31, 34)] self.checkBlocks(table, expected) bb = table.get_basic_block # Check the POP_JUMP_IF_FALSE conditional jump self.assertItemsEqual(bb(0).outgoing, [bb(18), bb(31)]) # Check the return self.assertItemsEqual(bb(44).outgoing, [None]) # Check the incoming of the entry block self.assertItemsEqual(bb(0).incoming, []) # Check incoming of the merge block. self.assertItemsEqual(bb(44).incoming, [bb(28), bb(15)]) self.assertEndsWith( bb(21).get_name(), "tests/test_pycfg.py:{0}-{0}".format(self.codeTriangleLineNumber+2))
def testNestedLoopsDominators(self): cfg = pycfg.CFG() table = cfg.get_block_table(self.codeNestedLoops.func_code) bb = table.get_basic_block self.assertEqual(bb(0)._dominators, {bb(0)}) self.assertEqual(bb(13)._dominators, {bb(0), bb(13)}) self.assertEqual(bb(16)._dominators, {bb(0), bb(13), bb(16)}) self.assertEqual(bb(26)._dominators, {bb(0), bb(13), bb(16), bb(26)}) self.assertEqual(bb(29)._dominators, {bb(0), bb(13), bb(16), bb(26), bb(29)}) self.assertEqual(bb(49)._dominators, {bb(0), bb(13), bb(16), bb(26), bb(49)}) self.assertEqual(bb(50)._dominators, {bb(0), bb(13), bb(16), bb(26), bb(49), bb(50)}) self.assertEqual(bb(53)._dominators, {bb(0), bb(13), bb(53)}) self.assertEqual(bb(54)._dominators, {bb(0), bb(13), bb(53), bb(54)})
def __init__(self): super(AncestorTraversalVirtualMachine, self).__init__() self.cfg = pycfg.CFG()