99
1010class FlowGraph :
1111 def __init__ (self ):
12- self .current = self .entry = Block ()
13- self .exit = Block ("exit" )
14- self .blocks = misc .Set ()
15- self .blocks .add (self .entry )
16- self .blocks .add (self .exit )
12+ self .current = self .entry = Block ()
13+ self .exit = Block ("exit" )
14+ self .blocks = misc .Set ()
15+ self .blocks .add (self .entry )
16+ self .blocks .add (self .exit )
1717
1818 def startBlock (self , block ):
19- self .current = block
19+ self .current = block
2020
2121 def nextBlock (self , block = None ):
22- if block is None :
23- block = self .newBlock ()
24- # XXX think we need to specify when there is implicit transfer
25- # from one block to the next
26- #
27- # I think this strategy works: each block has a child
28- # designated as "next" which is returned as the last of the
29- # children. because the nodes in a graph are emitted in
30- # reverse post order, the "next" block will always be emitted
31- # immediately after its parent.
32- # Worry: maintaining this invariant could be tricky
33- self .current .addNext (block )
34- self .startBlock (block )
22+ if block is None :
23+ block = self .newBlock ()
24+ # XXX think we need to specify when there is implicit transfer
25+ # from one block to the next
26+ #
27+ # I think this strategy works: each block has a child
28+ # designated as "next" which is returned as the last of the
29+ # children. because the nodes in a graph are emitted in
30+ # reverse post order, the "next" block will always be emitted
31+ # immediately after its parent.
32+ # Worry: maintaining this invariant could be tricky
33+ self .current .addNext (block )
34+ self .startBlock (block )
3535
3636 def newBlock (self ):
37- b = Block ()
38- self .blocks .add (b )
39- return b
37+ b = Block ()
38+ self .blocks .add (b )
39+ return b
4040
4141 def startExitBlock (self ):
42- self .startBlock (self .exit )
42+ self .startBlock (self .exit )
4343
4444 def emit (self , * inst ):
45- # XXX should jump instructions implicitly call nextBlock?
46- if inst [0 ] == 'RETURN_VALUE' :
47- self .current .addOutEdge (self .exit )
48- self .current .emit (inst )
45+ # XXX should jump instructions implicitly call nextBlock?
46+ if inst [0 ] == 'RETURN_VALUE' :
47+ self .current .addOutEdge (self .exit )
48+ self .current .emit (inst )
4949
5050 def getBlocks (self ):
51- """Return the blocks in reverse postorder
52-
53- i.e. each node appears before all of its successors
54- """
55- # XXX make sure every node that doesn't have an explicit next
56- # is set so that next points to exit
57- for b in self .blocks .elements ():
58- if b is self .exit :
59- continue
60- if not b .next :
61- b .addNext (self .exit )
62- order = dfs_postorder (self .entry , {})
63- order .reverse ()
64- # hack alert
65- if not self .exit in order :
66- order .append (self .exit )
67- return order
51+ """Return the blocks in reverse postorder
52+
53+ i.e. each node appears before all of its successors
54+ """
55+ # XXX make sure every node that doesn't have an explicit next
56+ # is set so that next points to exit
57+ for b in self .blocks .elements ():
58+ if b is self .exit :
59+ continue
60+ if not b .next :
61+ b .addNext (self .exit )
62+ order = dfs_postorder (self .entry , {})
63+ order .reverse ()
64+ # hack alert
65+ if not self .exit in order :
66+ order .append (self .exit )
67+ return order
6868
6969def dfs_postorder (b , seen ):
7070 """Depth-first search of tree rooted at b, return in postorder"""
7171 order = []
7272 seen [b ] = b
7373 for c in b .children ():
74- if seen .has_key (c ):
75- continue
76- order = order + dfs_postorder (c , seen )
74+ if seen .has_key (c ):
75+ continue
76+ order = order + dfs_postorder (c , seen )
7777 order .append (b )
7878 return order
7979
8080class Block :
8181 _count = 0
8282
8383 def __init__ (self , label = '' ):
84- self .insts = []
85- self .inEdges = misc .Set ()
86- self .outEdges = misc .Set ()
87- self .label = label
88- self .bid = Block ._count
89- self .next = []
90- Block ._count = Block ._count + 1
84+ self .insts = []
85+ self .inEdges = misc .Set ()
86+ self .outEdges = misc .Set ()
87+ self .label = label
88+ self .bid = Block ._count
89+ self .next = []
90+ Block ._count = Block ._count + 1
9191
9292 def __repr__ (self ):
93- if self .label :
94- return "<block %s id=%d len=%d>" % (self .label , self .bid ,
95- len (self .insts ))
96- else :
97- return "<block id=%d len=%d>" % (self .bid , len (self .insts ))
93+ if self .label :
94+ return "<block %s id=%d len=%d>" % (self .label , self .bid ,
95+ len (self .insts ))
96+ else :
97+ return "<block id=%d len=%d>" % (self .bid , len (self .insts ))
9898
9999 def __str__ (self ):
100- insts = map (str , self .insts )
101- return "<block %s %d:\n %s>" % (self .label , self .bid ,
102- string .join (insts , '\n ' ))
100+ insts = map (str , self .insts )
101+ return "<block %s %d:\n %s>" % (self .label , self .bid ,
102+ string .join (insts , '\n ' ))
103103
104104 def emit (self , inst ):
105- op = inst [0 ]
106- if op [:4 ] == 'JUMP' :
107- self .outEdges .add (inst [1 ])
108- self .insts .append (inst )
105+ op = inst [0 ]
106+ if op [:4 ] == 'JUMP' :
107+ self .outEdges .add (inst [1 ])
108+ self .insts .append (inst )
109109
110110 def getInstructions (self ):
111- return self .insts
111+ return self .insts
112112
113113 def addInEdge (self , block ):
114- self .inEdges .add (block )
114+ self .inEdges .add (block )
115115
116116 def addOutEdge (self , block ):
117- self .outEdges .add (block )
117+ self .outEdges .add (block )
118118
119119 def addNext (self , block ):
120- self .next .append (block )
121- assert len (self .next ) == 1 , map (str , self .next )
120+ self .next .append (block )
121+ assert len (self .next ) == 1 , map (str , self .next )
122122
123123 def children (self ):
124- return self .outEdges .elements () + self .next
124+ return self .outEdges .elements () + self .next
125125
126126# flags for code objects
127127CO_OPTIMIZED = 0x0001
@@ -139,18 +139,18 @@ class PyFlowGraph(FlowGraph):
139139 super_init = FlowGraph .__init__
140140
141141 def __init__ (self , name , filename , args = (), optimized = 0 ):
142- self .super_init ()
143- self .name = name
144- self .filename = filename
145- self .docstring = None
146- self .args = args # XXX
147- self .argcount = getArgCount (args )
148- if optimized :
149- self .flags = CO_OPTIMIZED | CO_NEWLOCALS
150- else :
151- self .flags = 0
152- self .consts = []
153- self .names = []
142+ self .super_init ()
143+ self .name = name
144+ self .filename = filename
145+ self .docstring = None
146+ self .args = args # XXX
147+ self .argcount = getArgCount (args )
148+ if optimized :
149+ self .flags = CO_OPTIMIZED | CO_NEWLOCALS
150+ else :
151+ self .flags = 0
152+ self .consts = []
153+ self .names = []
154154 self .varnames = list (args ) or []
155155 for i in range (len (self .varnames )):
156156 var = self .varnames [i ]
@@ -163,13 +163,13 @@ def setDocstring(self, doc):
163163 self .consts .insert (0 , doc )
164164
165165 def setFlag (self , flag ):
166- self .flags = self .flags | flag
167- if flag == CO_VARARGS :
168- self .argcount = self .argcount - 1
166+ self .flags = self .flags | flag
167+ if flag == CO_VARARGS :
168+ self .argcount = self .argcount - 1
169169
170170 def getCode (self ):
171- """Get a Python code object"""
172- if self .stage == RAW :
171+ """Get a Python code object"""
172+ if self .stage == RAW :
173173 self .flattenGraph ()
174174 if self .stage == FLAT :
175175 self .convertArgs ()
@@ -198,38 +198,38 @@ def dump(self, io=None):
198198 sys .stdout = save
199199
200200 def flattenGraph (self ):
201- """Arrange the blocks in order and resolve jumps"""
202- assert self .stage == RAW
203- self .insts = insts = []
204- pc = 0
205- begin = {}
206- end = {}
207- for b in self .getBlocks ():
208- begin [b ] = pc
209- for inst in b .getInstructions ():
210- insts .append (inst )
211- if len (inst ) == 1 :
212- pc = pc + 1
213- else :
214- # arg takes 2 bytes
215- pc = pc + 3
216- end [b ] = pc
217- pc = 0
218- for i in range (len (insts )):
219- inst = insts [i ]
220- if len (inst ) == 1 :
201+ """Arrange the blocks in order and resolve jumps"""
202+ assert self .stage == RAW
203+ self .insts = insts = []
204+ pc = 0
205+ begin = {}
206+ end = {}
207+ for b in self .getBlocks ():
208+ begin [b ] = pc
209+ for inst in b .getInstructions ():
210+ insts .append (inst )
211+ if len (inst ) == 1 :
212+ pc = pc + 1
213+ else :
214+ # arg takes 2 bytes
215+ pc = pc + 3
216+ end [b ] = pc
217+ pc = 0
218+ for i in range (len (insts )):
219+ inst = insts [i ]
220+ if len (inst ) == 1 :
221221 pc = pc + 1
222222 else :
223223 pc = pc + 3
224- opname = inst [0 ]
225- if self .hasjrel .has_elt (opname ):
224+ opname = inst [0 ]
225+ if self .hasjrel .has_elt (opname ):
226226 oparg = inst [1 ]
227227 offset = begin [oparg ] - pc
228228 insts [i ] = opname , offset
229229 elif self .hasjabs .has_elt (opname ):
230230 insts [i ] = opname , begin [inst [1 ]]
231- self .stacksize = findDepth (self .insts )
232- self .stage = FLAT
231+ self .stacksize = findDepth (self .insts )
232+ self .stage = FLAT
233233
234234 hasjrel = misc .Set ()
235235 for i in dis .hasjrel :
@@ -292,7 +292,7 @@ def _convert_NAME(self, arg):
292292
293293 _cmp = list (dis .cmp_op )
294294 def _convert_COMPARE_OP (self , arg ):
295- return self ._cmp .index (arg )
295+ return self ._cmp .index (arg )
296296
297297 # similarly for other opcodes...
298298
@@ -314,12 +314,12 @@ def makeByteCode(self):
314314 if opname == "SET_LINENO" :
315315 lnotab .nextLine (oparg )
316316 hi , lo = twobyte (oparg )
317- try :
318- lnotab .addCode (self .opnum [opname ], lo , hi )
319- except ValueError :
320- print opname , oparg
321- print self .opnum [opname ], lo , hi
322- raise
317+ try :
318+ lnotab .addCode (self .opnum [opname ], lo , hi )
319+ except ValueError :
320+ print opname , oparg
321+ print self .opnum [opname ], lo , hi
322+ raise
323323 self .stage = DONE
324324
325325 opnum = {}
@@ -354,10 +354,10 @@ def getConsts(self):
354354 elt = elt .getCode ()
355355 l .append (elt )
356356 return tuple (l )
357-
357+
358358def isJump (opname ):
359359 if opname [:4 ] == 'JUMP' :
360- return 1
360+ return 1
361361
362362class TupleArg :
363363 """Helper for marking func defs with nested tuples in arglist"""
@@ -372,10 +372,10 @@ def getName(self):
372372def getArgCount (args ):
373373 argcount = len (args )
374374 if args :
375- for arg in args :
376- if isinstance (arg , TupleArg ):
377- numNames = len (misc .flatten (arg .names ))
378- argcount = argcount - numNames
375+ for arg in args :
376+ if isinstance (arg , TupleArg ):
377+ numNames = len (misc .flatten (arg .names ))
378+ argcount = argcount - numNames
379379 return argcount
380380
381381def twobyte (val ):
@@ -513,11 +513,9 @@ def findDepth(self, insts):
513513 ]
514514
515515 # special cases:
516- # UNPACK_TUPLE, UNPACK_LIST , BUILD_TUPLE,
516+ # UNPACK_SEQUENCE , BUILD_TUPLE,
517517 # BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
518- def UNPACK_TUPLE (self , count ):
519- return count
520- def UNPACK_LIST (self , count ):
518+ def UNPACK_SEQUENCE (self , count ):
521519 return count
522520 def BUILD_TUPLE (self , count ):
523521 return - count
0 commit comments