blob: 7f44d463e9463392baefe85337a6eb7cdf489515 [file] [log] [blame]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00001"""A flow graph representation for Python bytecode"""
Jeremy Hyltona5058122000-02-14 14:14:29 +00002
Jeremy Hyltona5058122000-02-14 14:14:29 +00003import dis
4import new
Jeremy Hylton314e3fb2000-11-06 03:43:11 +00005import sys
Jeremy Hyltona5058122000-02-14 14:14:29 +00006
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00007from compiler import misc
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +00008from compiler.consts \
9 import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000010
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000011class FlowGraph:
12 def __init__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000013 self.current = self.entry = Block()
14 self.exit = Block("exit")
15 self.blocks = misc.Set()
16 self.blocks.add(self.entry)
17 self.blocks.add(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000018
19 def startBlock(self, block):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000020 if self._debug:
21 if self.current:
22 print "end", repr(self.current)
Jeremy Hylton542b11a2001-04-12 20:21:39 +000023 print " next", self.current.next
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000024 print " ", self.current.get_children()
25 print repr(block)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000026 self.current = block
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000027
Jeremy Hylton542b11a2001-04-12 20:21:39 +000028 def nextBlock(self, block=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000029 # XXX think we need to specify when there is implicit transfer
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000030 # from one block to the next. might be better to represent this
31 # with explicit JUMP_ABSOLUTE instructions that are optimized
32 # out when they are unnecessary.
Thomas Wouters46cc7c02000-08-12 20:32:46 +000033 #
34 # I think this strategy works: each block has a child
35 # designated as "next" which is returned as the last of the
36 # children. because the nodes in a graph are emitted in
37 # reverse post order, the "next" block will always be emitted
38 # immediately after its parent.
39 # Worry: maintaining this invariant could be tricky
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000040 if block is None:
41 block = self.newBlock()
42
43 # Note: If the current block ends with an unconditional
44 # control transfer, then it is incorrect to add an implicit
45 # transfer to the block graph. The current code requires
46 # these edges to get the blocks emitted in the right order,
47 # however. :-( If a client needs to remove these edges, call
48 # pruneEdges().
Tim Peterse0c446b2001-10-18 21:57:37 +000049
Thomas Wouters46cc7c02000-08-12 20:32:46 +000050 self.current.addNext(block)
51 self.startBlock(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000052
53 def newBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000054 b = Block()
55 self.blocks.add(b)
56 return b
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000057
58 def startExitBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000059 self.startBlock(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000060
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000061 _debug = 0
62
63 def _enable_debug(self):
64 self._debug = 1
65
66 def _disable_debug(self):
67 self._debug = 0
68
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000069 def emit(self, *inst):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000070 if self._debug:
71 print "\t", inst
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +000072 if inst[0] in ['RETURN_VALUE', 'YIELD_VALUE']:
Thomas Wouters46cc7c02000-08-12 20:32:46 +000073 self.current.addOutEdge(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000074 if len(inst) == 2 and isinstance(inst[1], Block):
75 self.current.addOutEdge(inst[1])
Thomas Wouters46cc7c02000-08-12 20:32:46 +000076 self.current.emit(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000077
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000078 def getBlocksInOrder(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000079 """Return the blocks in reverse postorder
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000080
Thomas Wouters46cc7c02000-08-12 20:32:46 +000081 i.e. each node appears before all of its successors
82 """
83 # XXX make sure every node that doesn't have an explicit next
84 # is set so that next points to exit
85 for b in self.blocks.elements():
86 if b is self.exit:
87 continue
88 if not b.next:
89 b.addNext(self.exit)
90 order = dfs_postorder(self.entry, {})
91 order.reverse()
Jeremy Hylton542b11a2001-04-12 20:21:39 +000092 self.fixupOrder(order, self.exit)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000093 # hack alert
94 if not self.exit in order:
95 order.append(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000096
Thomas Wouters46cc7c02000-08-12 20:32:46 +000097 return order
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000098
Jeremy Hylton542b11a2001-04-12 20:21:39 +000099 def fixupOrder(self, blocks, default_next):
100 """Fixup bad order introduced by DFS."""
101
102 # XXX This is a total mess. There must be a better way to get
103 # the code blocks in the right order.
Tim Peterse0c446b2001-10-18 21:57:37 +0000104
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000105 self.fixupOrderHonorNext(blocks, default_next)
106 self.fixupOrderForward(blocks, default_next)
107
108 def fixupOrderHonorNext(self, blocks, default_next):
109 """Fix one problem with DFS.
Tim Peterse0c446b2001-10-18 21:57:37 +0000110
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000111 The DFS uses child block, but doesn't know about the special
112 "next" block. As a result, the DFS can order blocks so that a
113 block isn't next to the right block for implicit control
114 transfers.
115 """
116 index = {}
117 for i in range(len(blocks)):
118 index[blocks[i]] = i
119
120 for i in range(0, len(blocks) - 1):
121 b = blocks[i]
122 n = blocks[i + 1]
123 if not b.next or b.next[0] == default_next or b.next[0] == n:
124 continue
125 # The blocks are in the wrong order. Find the chain of
126 # blocks to insert where they belong.
127 cur = b
128 chain = []
129 elt = cur
130 while elt.next and elt.next[0] != default_next:
131 chain.append(elt.next[0])
132 elt = elt.next[0]
133 # Now remove the blocks in the chain from the current
134 # block list, so that they can be re-inserted.
135 l = []
136 for b in chain:
137 assert index[b] > i
138 l.append((index[b], b))
139 l.sort()
140 l.reverse()
141 for j, b in l:
142 del blocks[index[b]]
143 # Insert the chain in the proper location
144 blocks[i:i + 1] = [cur] + chain
145 # Finally, re-compute the block indexes
146 for i in range(len(blocks)):
147 index[blocks[i]] = i
148
149 def fixupOrderForward(self, blocks, default_next):
150 """Make sure all JUMP_FORWARDs jump forward"""
151 index = {}
152 chains = []
153 cur = []
154 for b in blocks:
155 index[b] = len(chains)
156 cur.append(b)
157 if b.next and b.next[0] == default_next:
158 chains.append(cur)
159 cur = []
160 chains.append(cur)
161
162 while 1:
163 constraints = []
164
165 for i in range(len(chains)):
166 l = chains[i]
167 for b in l:
168 for c in b.get_children():
169 if index[c] < i:
170 forward_p = 0
171 for inst in b.insts:
172 if inst[0] == 'JUMP_FORWARD':
173 if inst[1] == c:
174 forward_p = 1
175 if not forward_p:
176 continue
177 constraints.append((index[c], i))
178
179 if not constraints:
180 break
181
182 # XXX just do one for now
183 # do swaps to get things in the right order
184 goes_before, a_chain = constraints[0]
185 assert a_chain > goes_before
186 c = chains[a_chain]
187 chains.remove(c)
188 chains.insert(goes_before, c)
189
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000190 del blocks[:]
191 for c in chains:
192 for b in c:
193 blocks.append(b)
Tim Peterse0c446b2001-10-18 21:57:37 +0000194
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000195 def getBlocks(self):
196 return self.blocks.elements()
197
198 def getRoot(self):
199 """Return nodes appropriate for use with dominator"""
200 return self.entry
Tim Peterse0c446b2001-10-18 21:57:37 +0000201
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000202 def getContainedGraphs(self):
203 l = []
204 for b in self.getBlocks():
205 l.extend(b.getContainedGraphs())
206 return l
207
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000208def dfs_postorder(b, seen):
209 """Depth-first search of tree rooted at b, return in postorder"""
210 order = []
211 seen[b] = b
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000212 for c in b.get_children():
Guido van Rossum49061f72006-08-19 15:28:37 +0000213 if c in seen:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000214 continue
215 order = order + dfs_postorder(c, seen)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000216 order.append(b)
217 return order
218
219class Block:
220 _count = 0
221
222 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000223 self.insts = []
224 self.inEdges = misc.Set()
225 self.outEdges = misc.Set()
226 self.label = label
227 self.bid = Block._count
228 self.next = []
229 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000230
231 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000232 if self.label:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000233 return "<block %s id=%d>" % (self.label, self.bid)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000234 else:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000235 return "<block id=%d>" % (self.bid)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000236
237 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000238 insts = map(str, self.insts)
239 return "<block %s %d:\n%s>" % (self.label, self.bid,
Neal Norwitza312c3a2002-06-06 18:30:10 +0000240 '\n'.join(insts))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000241
242 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000243 op = inst[0]
244 if op[:4] == 'JUMP':
245 self.outEdges.add(inst[1])
246 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000247
248 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000249 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000250
251 def addInEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000252 self.inEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000253
254 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000255 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000256
257 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000258 self.next.append(block)
259 assert len(self.next) == 1, map(str, self.next)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000260
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000261 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS', 'YIELD_VALUE',
Jeremy Hylton92638482001-08-29 22:27:14 +0000262 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP')
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000263
264 def pruneNext(self):
265 """Remove bogus edge for unconditional transfers
266
267 Each block has a next edge that accounts for implicit control
268 transfers, e.g. from a JUMP_IF_FALSE to the block that will be
269 executed if the test is true.
270
271 These edges must remain for the current assembler code to
272 work. If they are removed, the dfs_postorder gets things in
273 weird orders. However, they shouldn't be there for other
274 purposes, e.g. conversion to SSA form. This method will
275 remove the next edge when it follows an unconditional control
276 transfer.
277 """
278 try:
279 op, arg = self.insts[-1]
280 except (IndexError, ValueError):
281 return
282 if op in self._uncond_transfer:
283 self.next = []
284
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000285 def get_children(self):
286 if self.next and self.next[0] in self.outEdges:
287 self.outEdges.remove(self.next[0])
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000288 return self.outEdges.elements() + self.next
Jeremy Hyltona5058122000-02-14 14:14:29 +0000289
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000290 def getContainedGraphs(self):
291 """Return all graphs contained within this block.
292
293 For example, a MAKE_FUNCTION block will contain a reference to
294 the graph for the function body.
295 """
296 contained = []
297 for inst in self.insts:
298 if len(inst) == 1:
299 continue
300 op = inst[1]
301 if hasattr(op, 'graph'):
302 contained.append(op.graph)
303 return contained
304
Jeremy Hyltona5058122000-02-14 14:14:29 +0000305# flags for code objects
Jeremy Hyltona5058122000-02-14 14:14:29 +0000306
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000307# the FlowGraph is transformed in place; it exists in one of these states
308RAW = "RAW"
309FLAT = "FLAT"
310CONV = "CONV"
311DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000312
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000313class PyFlowGraph(FlowGraph):
314 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000315
Guido van Rossum4f72a782006-10-27 23:31:49 +0000316 def __init__(self, name, filename,
317 args=(), kwonlyargs={}, optimized=0, klass=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000318 self.super_init()
319 self.name = name
320 self.filename = filename
321 self.docstring = None
322 self.args = args # XXX
323 self.argcount = getArgCount(args)
Guido van Rossum4f72a782006-10-27 23:31:49 +0000324 self.kwonlyargs = kwonlyargs
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000325 self.klass = klass
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000326 if optimized:
Tim Peterse0c446b2001-10-18 21:57:37 +0000327 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000328 else:
329 self.flags = 0
330 self.consts = []
331 self.names = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000332 # Free variables found by the symbol table scan, including
333 # variables used only in nested scopes, are included here.
334 self.freevars = []
335 self.cellvars = []
336 # The closure list is used to track the order of cell
337 # variables and free variables in the resulting code object.
338 # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
339 # kinds of variables.
340 self.closure = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000341 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000342 for i in range(len(self.varnames)):
343 var = self.varnames[i]
344 if isinstance(var, TupleArg):
345 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000346 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000347
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000348 def setDocstring(self, doc):
349 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000350
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000351 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000352 self.flags = self.flags | flag
353 if flag == CO_VARARGS:
354 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000355
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000356 def checkFlag(self, flag):
357 if self.flags & flag:
358 return 1
359
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000360 def setFreeVars(self, names):
361 self.freevars = list(names)
362
363 def setCellVars(self, names):
364 self.cellvars = names
365
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000366 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000367 """Get a Python code object"""
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000368 assert self.stage == RAW
369 self.computeStackDepth()
370 self.flattenGraph()
371 assert self.stage == FLAT
372 self.convertArgs()
373 assert self.stage == CONV
374 self.makeByteCode()
375 assert self.stage == DONE
376 return self.newCodeObject()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000377
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000378 def dump(self, io=None):
379 if io:
380 save = sys.stdout
381 sys.stdout = io
382 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000383 for t in self.insts:
384 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000385 if opname == "SET_LINENO":
386 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000387 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000388 print "\t", "%3d" % pc, opname
389 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000390 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000391 print "\t", "%3d" % pc, opname, t[1]
392 pc = pc + 3
393 if io:
394 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000395
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000396 def computeStackDepth(self):
397 """Compute the max stack depth.
398
399 Approach is to compute the stack effect of each basic block.
400 Then find the path through the code with the largest total
401 effect.
402 """
403 depth = {}
404 exit = None
405 for b in self.getBlocks():
406 depth[b] = findDepth(b.getInstructions())
407
408 seen = {}
409
410 def max_depth(b, d):
Guido van Rossum49061f72006-08-19 15:28:37 +0000411 if b in seen:
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000412 return d
413 seen[b] = 1
414 d = d + depth[b]
415 children = b.get_children()
416 if children:
417 return max([max_depth(c, d) for c in children])
418 else:
419 if not b.label == "exit":
420 return max_depth(self.exit, d)
421 else:
422 return d
423
424 self.stacksize = max_depth(self.entry, 0)
425
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000426 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000427 """Arrange the blocks in order and resolve jumps"""
428 assert self.stage == RAW
429 self.insts = insts = []
430 pc = 0
431 begin = {}
432 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000433 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000434 begin[b] = pc
435 for inst in b.getInstructions():
436 insts.append(inst)
437 if len(inst) == 1:
438 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000439 elif inst[0] != "SET_LINENO":
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000440 # arg takes 2 bytes
441 pc = pc + 3
442 end[b] = pc
443 pc = 0
444 for i in range(len(insts)):
445 inst = insts[i]
446 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000447 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000448 elif inst[0] != "SET_LINENO":
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000449 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000450 opname = inst[0]
451 if self.hasjrel.has_elt(opname):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000452 oparg = inst[1]
453 offset = begin[oparg] - pc
454 insts[i] = opname, offset
455 elif self.hasjabs.has_elt(opname):
456 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000457 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000458
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000459 hasjrel = misc.Set()
460 for i in dis.hasjrel:
461 hasjrel.add(dis.opname[i])
462 hasjabs = misc.Set()
463 for i in dis.hasjabs:
464 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000465
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000466 def convertArgs(self):
467 """Convert arguments from symbolic to concrete form"""
468 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000469 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000470 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000471 for i in range(len(self.insts)):
472 t = self.insts[i]
473 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000474 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000475 conv = self._converters.get(opname, None)
476 if conv:
477 self.insts[i] = opname, conv(self, oparg)
478 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000479
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000480 def sort_cellvars(self):
481 """Sort cellvars in the order of varnames and prune from freevars.
482 """
483 cells = {}
484 for name in self.cellvars:
485 cells[name] = 1
486 self.cellvars = [name for name in self.varnames
Guido van Rossum49061f72006-08-19 15:28:37 +0000487 if name in cells]
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000488 for name in self.cellvars:
489 del cells[name]
490 self.cellvars = self.cellvars + cells.keys()
491 self.closure = self.cellvars + self.freevars
492
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000493 def _lookupName(self, name, list):
494 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000495
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000496 This routine uses a list instead of a dictionary, because a
497 dictionary can't store two different keys if the keys have the
498 same value but different types, e.g. 2 and 2L. The compiler
499 must treat these two separately, so it does an explicit type
500 comparison before comparing the values.
501 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000502 t = type(name)
503 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000504 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000505 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000506 end = len(list)
507 list.append(name)
508 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000509
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000510 _converters = {}
511 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000512 if hasattr(arg, 'getCode'):
513 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000514 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000515
516 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000517 self._lookupName(arg, self.names)
518 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000519 _convert_STORE_FAST = _convert_LOAD_FAST
520 _convert_DELETE_FAST = _convert_LOAD_FAST
521
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000522 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000523 if self.klass is None:
524 self._lookupName(arg, self.varnames)
525 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000526
527 def _convert_NAME(self, arg):
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000528 if self.klass is None:
529 self._lookupName(arg, self.varnames)
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000530 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000531 _convert_STORE_NAME = _convert_NAME
532 _convert_DELETE_NAME = _convert_NAME
533 _convert_IMPORT_NAME = _convert_NAME
534 _convert_IMPORT_FROM = _convert_NAME
535 _convert_STORE_ATTR = _convert_NAME
536 _convert_LOAD_ATTR = _convert_NAME
537 _convert_DELETE_ATTR = _convert_NAME
538 _convert_LOAD_GLOBAL = _convert_NAME
539 _convert_STORE_GLOBAL = _convert_NAME
540 _convert_DELETE_GLOBAL = _convert_NAME
541
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000542 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000543 self._lookupName(arg, self.names)
544 self._lookupName(arg, self.varnames)
545 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000546 _convert_LOAD_DEREF = _convert_DEREF
547 _convert_STORE_DEREF = _convert_DEREF
548
549 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000550 self._lookupName(arg, self.varnames)
551 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000552
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000553 _cmp = list(dis.cmp_op)
554 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000555 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000556
557 # similarly for other opcodes...
558
559 for name, obj in locals().items():
560 if name[:9] == "_convert_":
561 opname = name[9:]
Tim Peterse0c446b2001-10-18 21:57:37 +0000562 _converters[opname] = obj
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000563 del name, obj, opname
564
565 def makeByteCode(self):
566 assert self.stage == CONV
567 self.lnotab = lnotab = LineAddrTable()
568 for t in self.insts:
569 opname = t[0]
570 if len(t) == 1:
571 lnotab.addCode(self.opnum[opname])
572 else:
573 oparg = t[1]
574 if opname == "SET_LINENO":
575 lnotab.nextLine(oparg)
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000576 continue
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000577 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000578 try:
579 lnotab.addCode(self.opnum[opname], lo, hi)
580 except ValueError:
581 print opname, oparg
582 print self.opnum[opname], lo, hi
583 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000584 self.stage = DONE
585
Jeremy Hyltona5058122000-02-14 14:14:29 +0000586 opnum = {}
587 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000588 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000589 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000590
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000591 def newCodeObject(self):
592 assert self.stage == DONE
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000593 if (self.flags & CO_NEWLOCALS) == 0:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000594 nlocals = 0
595 else:
596 nlocals = len(self.varnames)
597 argcount = self.argcount
598 if self.flags & CO_VARKEYWORDS:
599 argcount = argcount - 1
Guido van Rossum4f72a782006-10-27 23:31:49 +0000600 kwonlyargcount = len(self.kwonlyargs)
601 return new.code(argcount, kwonlyargcount,
602 nlocals, self.stacksize, self.flags,
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000603 self.lnotab.getCode(), self.getConsts(),
604 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000605 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000606 self.lnotab.getTable(), tuple(self.freevars),
607 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000608
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000609 def getConsts(self):
610 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000611
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000612 Must convert references to code (MAKE_FUNCTION) to code
613 objects recursively.
614 """
615 l = []
616 for elt in self.consts:
617 if isinstance(elt, PyFlowGraph):
618 elt = elt.getCode()
619 l.append(elt)
620 return tuple(l)
Tim Peterse0c446b2001-10-18 21:57:37 +0000621
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000622def isJump(opname):
623 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000624 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000625
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000626class TupleArg:
627 """Helper for marking func defs with nested tuples in arglist"""
628 def __init__(self, count, names):
629 self.count = count
630 self.names = names
631 def __repr__(self):
632 return "TupleArg(%s, %s)" % (self.count, self.names)
633 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000634 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000635
636def getArgCount(args):
637 argcount = len(args)
638 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000639 for arg in args:
640 if isinstance(arg, TupleArg):
641 numNames = len(misc.flatten(arg.names))
642 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000643 return argcount
644
645def twobyte(val):
646 """Convert an int argument into high and low bytes"""
Neal Norwitzd752f7d2005-11-25 03:17:59 +0000647 assert isinstance(val, int)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000648 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000649
650class LineAddrTable:
651 """lnotab
Tim Peterse0c446b2001-10-18 21:57:37 +0000652
Tim Peters2a7f3842001-06-09 09:26:21 +0000653 This class builds the lnotab, which is documented in compile.c.
654 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000655
656 For each SET_LINENO instruction after the first one, two bytes are
657 added to lnotab. (In some cases, multiple two-byte entries are
658 added.) The first byte is the distance in bytes between the
659 instruction for the last SET_LINENO and the current SET_LINENO.
660 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000661 greater than 255, multiple two-byte entries are added -- see
662 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000663 """
664
665 def __init__(self):
666 self.code = []
667 self.codeOffset = 0
668 self.firstline = 0
669 self.lastline = 0
670 self.lastoff = 0
671 self.lnotab = []
672
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000673 def addCode(self, *args):
674 for arg in args:
675 self.code.append(chr(arg))
676 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000677
678 def nextLine(self, lineno):
679 if self.firstline == 0:
680 self.firstline = lineno
681 self.lastline = lineno
682 else:
683 # compute deltas
684 addr = self.codeOffset - self.lastoff
685 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000686 # Python assumes that lineno always increases with
687 # increasing bytecode address (lnotab is unsigned char).
688 # Depending on when SET_LINENO instructions are emitted
689 # this is not always true. Consider the code:
690 # a = (1,
691 # b)
692 # In the bytecode stream, the assignment to "a" occurs
693 # after the loading of "b". This works with the C Python
694 # compiler because it only generates a SET_LINENO instruction
695 # for the assignment.
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000696 if line >= 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000697 push = self.lnotab.append
698 while addr > 255:
699 push(255); push(0)
700 addr -= 255
701 while line > 255:
702 push(addr); push(255)
703 line -= 255
704 addr = 0
705 if addr > 0 or line > 0:
706 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000707 self.lastline = lineno
708 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000709
710 def getCode(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000711 return ''.join(self.code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000712
713 def getTable(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000714 return ''.join(map(chr, self.lnotab))
Tim Peterse0c446b2001-10-18 21:57:37 +0000715
Jeremy Hyltona5058122000-02-14 14:14:29 +0000716class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000717 # XXX 1. need to keep track of stack depth on jumps
718 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000719
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000720 def findDepth(self, insts, debug=0):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000721 depth = 0
722 maxDepth = 0
723 for i in insts:
724 opname = i[0]
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000725 if debug:
726 print i,
727 delta = self.effect.get(opname, None)
728 if delta is not None:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000729 depth = depth + delta
730 else:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000731 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000732 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000733 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000734 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000735 depth = depth + delta
736 break
737 # if we still haven't found a match
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000738 if delta is None:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000739 meth = getattr(self, opname, None)
740 if meth is not None:
741 depth = depth + meth(i[1])
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000742 if depth > maxDepth:
743 maxDepth = depth
744 if debug:
745 print depth, maxDepth
Jeremy Hylton772dd412000-02-21 22:46:00 +0000746 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000747
748 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000749 'POP_TOP': -1,
750 'DUP_TOP': 1,
Neal Norwitz10be2ea2006-03-03 20:29:11 +0000751 'LIST_APPEND': -2,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000752 'SLICE+1': -1,
753 'SLICE+2': -1,
754 'SLICE+3': -2,
755 'STORE_SLICE+0': -1,
756 'STORE_SLICE+1': -2,
757 'STORE_SLICE+2': -2,
758 'STORE_SLICE+3': -3,
759 'DELETE_SLICE+0': -1,
760 'DELETE_SLICE+1': -2,
761 'DELETE_SLICE+2': -2,
762 'DELETE_SLICE+3': -3,
763 'STORE_SUBSCR': -3,
764 'DELETE_SUBSCR': -2,
765 # PRINT_EXPR?
766 'PRINT_ITEM': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000767 'RETURN_VALUE': -1,
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000768 'YIELD_VALUE': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000769 'BUILD_CLASS': -2,
770 'STORE_NAME': -1,
771 'STORE_ATTR': -2,
772 'DELETE_ATTR': -1,
773 'STORE_GLOBAL': -1,
774 'BUILD_MAP': 1,
775 'COMPARE_OP': -1,
776 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000777 'IMPORT_STAR': -1,
Thomas Woutersfa0cf4f2006-03-03 18:16:20 +0000778 'IMPORT_NAME': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000779 'IMPORT_FROM': 1,
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000780 'LOAD_ATTR': 0, # unlike other loads
Jeremy Hylton92638482001-08-29 22:27:14 +0000781 # close enough...
782 'SETUP_EXCEPT': 3,
783 'SETUP_FINALLY': 3,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000784 'FOR_ITER': 1,
Guido van Rossumf6694362006-03-10 02:28:35 +0000785 'WITH_CLEANUP': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000786 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000787 # use pattern match
788 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000789 ('BINARY_', -1),
790 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000791 ]
Tim Peterse0c446b2001-10-18 21:57:37 +0000792
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000793 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000794 return count-1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000795 def BUILD_TUPLE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000796 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000797 def BUILD_LIST(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000798 return -count+1
Guido van Rossum86e58e22006-08-28 15:27:34 +0000799 def BUILD_SET(self, count):
800 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000801 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000802 hi, lo = divmod(argc, 256)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000803 return -(lo + hi * 2)
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000804 def CALL_FUNCTION_VAR(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000805 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000806 def CALL_FUNCTION_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000807 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000808 def CALL_FUNCTION_VAR_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000809 return self.CALL_FUNCTION(argc)-2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000810 def MAKE_FUNCTION(self, argc):
Guido van Rossum4f72a782006-10-27 23:31:49 +0000811 hi, lo = divmod(argc, 256)
812 return -(lo + hi * 2)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000813 def MAKE_CLOSURE(self, argc):
814 # XXX need to account for free variables too!
815 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000816 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000817 if argc == 2:
818 return -1
819 elif argc == 3:
820 return -2
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000821 def DUP_TOPX(self, argc):
822 return argc
Tim Peterse0c446b2001-10-18 21:57:37 +0000823
Jeremy Hyltona5058122000-02-14 14:14:29 +0000824findDepth = StackDepthTracker().findDepth