blob: e1fb063193e091fb9d4543ee61f63f5ae9ad7d95 [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 Hylton36cc6a22000-03-16 20:06:59 +00006import types
Jeremy Hyltona5058122000-02-14 14:14:29 +00007
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00008from compiler import misc
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +00009from compiler.consts \
10 import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000011
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000012class FlowGraph:
13 def __init__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000014 self.current = self.entry = Block()
15 self.exit = Block("exit")
16 self.blocks = misc.Set()
17 self.blocks.add(self.entry)
18 self.blocks.add(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000019
20 def startBlock(self, block):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000021 if self._debug:
22 if self.current:
23 print "end", repr(self.current)
Jeremy Hylton542b11a2001-04-12 20:21:39 +000024 print " next", self.current.next
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000025 print " ", self.current.get_children()
26 print repr(block)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000027 self.current = block
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000028
Jeremy Hylton542b11a2001-04-12 20:21:39 +000029 def nextBlock(self, block=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000030 # XXX think we need to specify when there is implicit transfer
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000031 # from one block to the next. might be better to represent this
32 # with explicit JUMP_ABSOLUTE instructions that are optimized
33 # out when they are unnecessary.
Thomas Wouters46cc7c02000-08-12 20:32:46 +000034 #
35 # I think this strategy works: each block has a child
36 # designated as "next" which is returned as the last of the
37 # children. because the nodes in a graph are emitted in
38 # reverse post order, the "next" block will always be emitted
39 # immediately after its parent.
40 # Worry: maintaining this invariant could be tricky
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000041 if block is None:
42 block = self.newBlock()
43
44 # Note: If the current block ends with an unconditional
45 # control transfer, then it is incorrect to add an implicit
46 # transfer to the block graph. The current code requires
47 # these edges to get the blocks emitted in the right order,
48 # however. :-( If a client needs to remove these edges, call
49 # pruneEdges().
Tim Peterse0c446b2001-10-18 21:57:37 +000050
Thomas Wouters46cc7c02000-08-12 20:32:46 +000051 self.current.addNext(block)
52 self.startBlock(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000053
54 def newBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000055 b = Block()
56 self.blocks.add(b)
57 return b
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000058
59 def startExitBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000060 self.startBlock(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000061
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000062 _debug = 0
63
64 def _enable_debug(self):
65 self._debug = 1
66
67 def _disable_debug(self):
68 self._debug = 0
69
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000070 def emit(self, *inst):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000071 if self._debug:
72 print "\t", inst
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +000073 if inst[0] in ['RETURN_VALUE', 'YIELD_VALUE']:
Thomas Wouters46cc7c02000-08-12 20:32:46 +000074 self.current.addOutEdge(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000075 if len(inst) == 2 and isinstance(inst[1], Block):
76 self.current.addOutEdge(inst[1])
Thomas Wouters46cc7c02000-08-12 20:32:46 +000077 self.current.emit(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000078
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000079 def getBlocksInOrder(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000080 """Return the blocks in reverse postorder
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000081
Thomas Wouters46cc7c02000-08-12 20:32:46 +000082 i.e. each node appears before all of its successors
83 """
84 # XXX make sure every node that doesn't have an explicit next
85 # is set so that next points to exit
86 for b in self.blocks.elements():
87 if b is self.exit:
88 continue
89 if not b.next:
90 b.addNext(self.exit)
91 order = dfs_postorder(self.entry, {})
92 order.reverse()
Jeremy Hylton542b11a2001-04-12 20:21:39 +000093 self.fixupOrder(order, self.exit)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000094 # hack alert
95 if not self.exit in order:
96 order.append(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000097
Thomas Wouters46cc7c02000-08-12 20:32:46 +000098 return order
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000099
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000100 def fixupOrder(self, blocks, default_next):
101 """Fixup bad order introduced by DFS."""
102
103 # XXX This is a total mess. There must be a better way to get
104 # the code blocks in the right order.
Tim Peterse0c446b2001-10-18 21:57:37 +0000105
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000106 self.fixupOrderHonorNext(blocks, default_next)
107 self.fixupOrderForward(blocks, default_next)
108
109 def fixupOrderHonorNext(self, blocks, default_next):
110 """Fix one problem with DFS.
Tim Peterse0c446b2001-10-18 21:57:37 +0000111
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000112 The DFS uses child block, but doesn't know about the special
113 "next" block. As a result, the DFS can order blocks so that a
114 block isn't next to the right block for implicit control
115 transfers.
116 """
117 index = {}
118 for i in range(len(blocks)):
119 index[blocks[i]] = i
120
121 for i in range(0, len(blocks) - 1):
122 b = blocks[i]
123 n = blocks[i + 1]
124 if not b.next or b.next[0] == default_next or b.next[0] == n:
125 continue
126 # The blocks are in the wrong order. Find the chain of
127 # blocks to insert where they belong.
128 cur = b
129 chain = []
130 elt = cur
131 while elt.next and elt.next[0] != default_next:
132 chain.append(elt.next[0])
133 elt = elt.next[0]
134 # Now remove the blocks in the chain from the current
135 # block list, so that they can be re-inserted.
136 l = []
137 for b in chain:
138 assert index[b] > i
139 l.append((index[b], b))
140 l.sort()
141 l.reverse()
142 for j, b in l:
143 del blocks[index[b]]
144 # Insert the chain in the proper location
145 blocks[i:i + 1] = [cur] + chain
146 # Finally, re-compute the block indexes
147 for i in range(len(blocks)):
148 index[blocks[i]] = i
149
150 def fixupOrderForward(self, blocks, default_next):
151 """Make sure all JUMP_FORWARDs jump forward"""
152 index = {}
153 chains = []
154 cur = []
155 for b in blocks:
156 index[b] = len(chains)
157 cur.append(b)
158 if b.next and b.next[0] == default_next:
159 chains.append(cur)
160 cur = []
161 chains.append(cur)
162
163 while 1:
164 constraints = []
165
166 for i in range(len(chains)):
167 l = chains[i]
168 for b in l:
169 for c in b.get_children():
170 if index[c] < i:
171 forward_p = 0
172 for inst in b.insts:
173 if inst[0] == 'JUMP_FORWARD':
174 if inst[1] == c:
175 forward_p = 1
176 if not forward_p:
177 continue
178 constraints.append((index[c], i))
179
180 if not constraints:
181 break
182
183 # XXX just do one for now
184 # do swaps to get things in the right order
185 goes_before, a_chain = constraints[0]
186 assert a_chain > goes_before
187 c = chains[a_chain]
188 chains.remove(c)
189 chains.insert(goes_before, c)
190
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000191 del blocks[:]
192 for c in chains:
193 for b in c:
194 blocks.append(b)
Tim Peterse0c446b2001-10-18 21:57:37 +0000195
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000196 def getBlocks(self):
197 return self.blocks.elements()
198
199 def getRoot(self):
200 """Return nodes appropriate for use with dominator"""
201 return self.entry
Tim Peterse0c446b2001-10-18 21:57:37 +0000202
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000203 def getContainedGraphs(self):
204 l = []
205 for b in self.getBlocks():
206 l.extend(b.getContainedGraphs())
207 return l
208
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000209def dfs_postorder(b, seen):
210 """Depth-first search of tree rooted at b, return in postorder"""
211 order = []
212 seen[b] = b
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000213 for c in b.get_children():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000214 if seen.has_key(c):
215 continue
216 order = order + dfs_postorder(c, seen)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000217 order.append(b)
218 return order
219
220class Block:
221 _count = 0
222
223 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000224 self.insts = []
225 self.inEdges = misc.Set()
226 self.outEdges = misc.Set()
227 self.label = label
228 self.bid = Block._count
229 self.next = []
230 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000231
232 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000233 if self.label:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000234 return "<block %s id=%d>" % (self.label, self.bid)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000235 else:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000236 return "<block id=%d>" % (self.bid)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000237
238 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000239 insts = map(str, self.insts)
240 return "<block %s %d:\n%s>" % (self.label, self.bid,
Neal Norwitza312c3a2002-06-06 18:30:10 +0000241 '\n'.join(insts))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000242
243 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000244 op = inst[0]
245 if op[:4] == 'JUMP':
246 self.outEdges.add(inst[1])
247 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000248
249 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000250 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000251
252 def addInEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000253 self.inEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000254
255 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000256 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000257
258 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000259 self.next.append(block)
260 assert len(self.next) == 1, map(str, self.next)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000261
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000262 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS', 'YIELD_VALUE',
Jeremy Hylton92638482001-08-29 22:27:14 +0000263 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP')
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000264
265 def pruneNext(self):
266 """Remove bogus edge for unconditional transfers
267
268 Each block has a next edge that accounts for implicit control
269 transfers, e.g. from a JUMP_IF_FALSE to the block that will be
270 executed if the test is true.
271
272 These edges must remain for the current assembler code to
273 work. If they are removed, the dfs_postorder gets things in
274 weird orders. However, they shouldn't be there for other
275 purposes, e.g. conversion to SSA form. This method will
276 remove the next edge when it follows an unconditional control
277 transfer.
278 """
279 try:
280 op, arg = self.insts[-1]
281 except (IndexError, ValueError):
282 return
283 if op in self._uncond_transfer:
284 self.next = []
285
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000286 def get_children(self):
287 if self.next and self.next[0] in self.outEdges:
288 self.outEdges.remove(self.next[0])
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000289 return self.outEdges.elements() + self.next
Jeremy Hyltona5058122000-02-14 14:14:29 +0000290
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000291 def getContainedGraphs(self):
292 """Return all graphs contained within this block.
293
294 For example, a MAKE_FUNCTION block will contain a reference to
295 the graph for the function body.
296 """
297 contained = []
298 for inst in self.insts:
299 if len(inst) == 1:
300 continue
301 op = inst[1]
302 if hasattr(op, 'graph'):
303 contained.append(op.graph)
304 return contained
305
Jeremy Hyltona5058122000-02-14 14:14:29 +0000306# flags for code objects
Jeremy Hyltona5058122000-02-14 14:14:29 +0000307
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000308# the FlowGraph is transformed in place; it exists in one of these states
309RAW = "RAW"
310FLAT = "FLAT"
311CONV = "CONV"
312DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000313
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000314class PyFlowGraph(FlowGraph):
315 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000316
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000317 def __init__(self, name, filename, args=(), 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)
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000324 self.klass = klass
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000325 if optimized:
Tim Peterse0c446b2001-10-18 21:57:37 +0000326 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000327 else:
328 self.flags = 0
329 self.consts = []
330 self.names = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000331 # Free variables found by the symbol table scan, including
332 # variables used only in nested scopes, are included here.
333 self.freevars = []
334 self.cellvars = []
335 # The closure list is used to track the order of cell
336 # variables and free variables in the resulting code object.
337 # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
338 # kinds of variables.
339 self.closure = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000340 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000341 for i in range(len(self.varnames)):
342 var = self.varnames[i]
343 if isinstance(var, TupleArg):
344 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000345 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000346
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000347 def setDocstring(self, doc):
348 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000349
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000350 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000351 self.flags = self.flags | flag
352 if flag == CO_VARARGS:
353 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000354
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000355 def checkFlag(self, flag):
356 if self.flags & flag:
357 return 1
358
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000359 def setFreeVars(self, names):
360 self.freevars = list(names)
361
362 def setCellVars(self, names):
363 self.cellvars = names
364
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000365 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000366 """Get a Python code object"""
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000367 assert self.stage == RAW
368 self.computeStackDepth()
369 self.flattenGraph()
370 assert self.stage == FLAT
371 self.convertArgs()
372 assert self.stage == CONV
373 self.makeByteCode()
374 assert self.stage == DONE
375 return self.newCodeObject()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000376
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000377 def dump(self, io=None):
378 if io:
379 save = sys.stdout
380 sys.stdout = io
381 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000382 for t in self.insts:
383 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000384 if opname == "SET_LINENO":
385 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000386 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000387 print "\t", "%3d" % pc, opname
388 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000389 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000390 print "\t", "%3d" % pc, opname, t[1]
391 pc = pc + 3
392 if io:
393 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000394
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000395 def computeStackDepth(self):
396 """Compute the max stack depth.
397
398 Approach is to compute the stack effect of each basic block.
399 Then find the path through the code with the largest total
400 effect.
401 """
402 depth = {}
403 exit = None
404 for b in self.getBlocks():
405 depth[b] = findDepth(b.getInstructions())
406
407 seen = {}
408
409 def max_depth(b, d):
410 if seen.has_key(b):
411 return d
412 seen[b] = 1
413 d = d + depth[b]
414 children = b.get_children()
415 if children:
416 return max([max_depth(c, d) for c in children])
417 else:
418 if not b.label == "exit":
419 return max_depth(self.exit, d)
420 else:
421 return d
422
423 self.stacksize = max_depth(self.entry, 0)
424
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000425 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000426 """Arrange the blocks in order and resolve jumps"""
427 assert self.stage == RAW
428 self.insts = insts = []
429 pc = 0
430 begin = {}
431 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000432 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000433 begin[b] = pc
434 for inst in b.getInstructions():
435 insts.append(inst)
436 if len(inst) == 1:
437 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000438 elif inst[0] != "SET_LINENO":
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000439 # arg takes 2 bytes
440 pc = pc + 3
441 end[b] = pc
442 pc = 0
443 for i in range(len(insts)):
444 inst = insts[i]
445 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000446 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000447 elif inst[0] != "SET_LINENO":
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000448 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000449 opname = inst[0]
450 if self.hasjrel.has_elt(opname):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000451 oparg = inst[1]
452 offset = begin[oparg] - pc
453 insts[i] = opname, offset
454 elif self.hasjabs.has_elt(opname):
455 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000456 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000457
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000458 hasjrel = misc.Set()
459 for i in dis.hasjrel:
460 hasjrel.add(dis.opname[i])
461 hasjabs = misc.Set()
462 for i in dis.hasjabs:
463 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000464
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000465 def convertArgs(self):
466 """Convert arguments from symbolic to concrete form"""
467 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000468 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000469 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000470 for i in range(len(self.insts)):
471 t = self.insts[i]
472 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000473 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000474 conv = self._converters.get(opname, None)
475 if conv:
476 self.insts[i] = opname, conv(self, oparg)
477 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000478
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000479 def sort_cellvars(self):
480 """Sort cellvars in the order of varnames and prune from freevars.
481 """
482 cells = {}
483 for name in self.cellvars:
484 cells[name] = 1
485 self.cellvars = [name for name in self.varnames
486 if cells.has_key(name)]
487 for name in self.cellvars:
488 del cells[name]
489 self.cellvars = self.cellvars + cells.keys()
490 self.closure = self.cellvars + self.freevars
491
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000492 def _lookupName(self, name, list):
493 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000494
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000495 This routine uses a list instead of a dictionary, because a
496 dictionary can't store two different keys if the keys have the
497 same value but different types, e.g. 2 and 2L. The compiler
498 must treat these two separately, so it does an explicit type
499 comparison before comparing the values.
500 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000501 t = type(name)
502 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000503 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000504 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000505 end = len(list)
506 list.append(name)
507 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000508
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000509 _converters = {}
510 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000511 if hasattr(arg, 'getCode'):
512 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000513 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000514
515 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000516 self._lookupName(arg, self.names)
517 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000518 _convert_STORE_FAST = _convert_LOAD_FAST
519 _convert_DELETE_FAST = _convert_LOAD_FAST
520
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000521 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000522 if self.klass is None:
523 self._lookupName(arg, self.varnames)
524 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000525
526 def _convert_NAME(self, arg):
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000527 if self.klass is None:
528 self._lookupName(arg, self.varnames)
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000529 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000530 _convert_STORE_NAME = _convert_NAME
531 _convert_DELETE_NAME = _convert_NAME
532 _convert_IMPORT_NAME = _convert_NAME
533 _convert_IMPORT_FROM = _convert_NAME
534 _convert_STORE_ATTR = _convert_NAME
535 _convert_LOAD_ATTR = _convert_NAME
536 _convert_DELETE_ATTR = _convert_NAME
537 _convert_LOAD_GLOBAL = _convert_NAME
538 _convert_STORE_GLOBAL = _convert_NAME
539 _convert_DELETE_GLOBAL = _convert_NAME
540
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000541 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000542 self._lookupName(arg, self.names)
543 self._lookupName(arg, self.varnames)
544 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000545 _convert_LOAD_DEREF = _convert_DEREF
546 _convert_STORE_DEREF = _convert_DEREF
547
548 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000549 self._lookupName(arg, self.varnames)
550 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000551
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000552 _cmp = list(dis.cmp_op)
553 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000554 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000555
556 # similarly for other opcodes...
557
558 for name, obj in locals().items():
559 if name[:9] == "_convert_":
560 opname = name[9:]
Tim Peterse0c446b2001-10-18 21:57:37 +0000561 _converters[opname] = obj
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000562 del name, obj, opname
563
564 def makeByteCode(self):
565 assert self.stage == CONV
566 self.lnotab = lnotab = LineAddrTable()
567 for t in self.insts:
568 opname = t[0]
569 if len(t) == 1:
570 lnotab.addCode(self.opnum[opname])
571 else:
572 oparg = t[1]
573 if opname == "SET_LINENO":
574 lnotab.nextLine(oparg)
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000575 continue
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000576 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000577 try:
578 lnotab.addCode(self.opnum[opname], lo, hi)
579 except ValueError:
580 print opname, oparg
581 print self.opnum[opname], lo, hi
582 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000583 self.stage = DONE
584
Jeremy Hyltona5058122000-02-14 14:14:29 +0000585 opnum = {}
586 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000587 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000588 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000589
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000590 def newCodeObject(self):
591 assert self.stage == DONE
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000592 if (self.flags & CO_NEWLOCALS) == 0:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000593 nlocals = 0
594 else:
595 nlocals = len(self.varnames)
596 argcount = self.argcount
597 if self.flags & CO_VARKEYWORDS:
598 argcount = argcount - 1
599 return new.code(argcount, nlocals, self.stacksize, self.flags,
600 self.lnotab.getCode(), self.getConsts(),
601 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000602 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000603 self.lnotab.getTable(), tuple(self.freevars),
604 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000605
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000606 def getConsts(self):
607 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000608
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000609 Must convert references to code (MAKE_FUNCTION) to code
610 objects recursively.
611 """
612 l = []
613 for elt in self.consts:
614 if isinstance(elt, PyFlowGraph):
615 elt = elt.getCode()
616 l.append(elt)
617 return tuple(l)
Tim Peterse0c446b2001-10-18 21:57:37 +0000618
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000619def isJump(opname):
620 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000621 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000622
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000623class TupleArg:
624 """Helper for marking func defs with nested tuples in arglist"""
625 def __init__(self, count, names):
626 self.count = count
627 self.names = names
628 def __repr__(self):
629 return "TupleArg(%s, %s)" % (self.count, self.names)
630 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000631 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000632
633def getArgCount(args):
634 argcount = len(args)
635 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000636 for arg in args:
637 if isinstance(arg, TupleArg):
638 numNames = len(misc.flatten(arg.names))
639 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000640 return argcount
641
642def twobyte(val):
643 """Convert an int argument into high and low bytes"""
644 assert type(val) == types.IntType
645 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000646
647class LineAddrTable:
648 """lnotab
Tim Peterse0c446b2001-10-18 21:57:37 +0000649
Tim Peters2a7f3842001-06-09 09:26:21 +0000650 This class builds the lnotab, which is documented in compile.c.
651 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000652
653 For each SET_LINENO instruction after the first one, two bytes are
654 added to lnotab. (In some cases, multiple two-byte entries are
655 added.) The first byte is the distance in bytes between the
656 instruction for the last SET_LINENO and the current SET_LINENO.
657 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000658 greater than 255, multiple two-byte entries are added -- see
659 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000660 """
661
662 def __init__(self):
663 self.code = []
664 self.codeOffset = 0
665 self.firstline = 0
666 self.lastline = 0
667 self.lastoff = 0
668 self.lnotab = []
669
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000670 def addCode(self, *args):
671 for arg in args:
672 self.code.append(chr(arg))
673 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000674
675 def nextLine(self, lineno):
676 if self.firstline == 0:
677 self.firstline = lineno
678 self.lastline = lineno
679 else:
680 # compute deltas
681 addr = self.codeOffset - self.lastoff
682 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000683 # Python assumes that lineno always increases with
684 # increasing bytecode address (lnotab is unsigned char).
685 # Depending on when SET_LINENO instructions are emitted
686 # this is not always true. Consider the code:
687 # a = (1,
688 # b)
689 # In the bytecode stream, the assignment to "a" occurs
690 # after the loading of "b". This works with the C Python
691 # compiler because it only generates a SET_LINENO instruction
692 # for the assignment.
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000693 if line >= 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000694 push = self.lnotab.append
695 while addr > 255:
696 push(255); push(0)
697 addr -= 255
698 while line > 255:
699 push(addr); push(255)
700 line -= 255
701 addr = 0
702 if addr > 0 or line > 0:
703 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000704 self.lastline = lineno
705 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000706
707 def getCode(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000708 return ''.join(self.code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000709
710 def getTable(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000711 return ''.join(map(chr, self.lnotab))
Tim Peterse0c446b2001-10-18 21:57:37 +0000712
Jeremy Hyltona5058122000-02-14 14:14:29 +0000713class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000714 # XXX 1. need to keep track of stack depth on jumps
715 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000716
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000717 def findDepth(self, insts, debug=0):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000718 depth = 0
719 maxDepth = 0
720 for i in insts:
721 opname = i[0]
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000722 if debug:
723 print i,
724 delta = self.effect.get(opname, None)
725 if delta is not None:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000726 depth = depth + delta
727 else:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000728 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000729 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000730 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000731 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000732 depth = depth + delta
733 break
734 # if we still haven't found a match
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000735 if delta is None:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000736 meth = getattr(self, opname, None)
737 if meth is not None:
738 depth = depth + meth(i[1])
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000739 if depth > maxDepth:
740 maxDepth = depth
741 if debug:
742 print depth, maxDepth
Jeremy Hylton772dd412000-02-21 22:46:00 +0000743 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000744
745 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000746 'POP_TOP': -1,
747 'DUP_TOP': 1,
748 'SLICE+1': -1,
749 'SLICE+2': -1,
750 'SLICE+3': -2,
751 'STORE_SLICE+0': -1,
752 'STORE_SLICE+1': -2,
753 'STORE_SLICE+2': -2,
754 'STORE_SLICE+3': -3,
755 'DELETE_SLICE+0': -1,
756 'DELETE_SLICE+1': -2,
757 'DELETE_SLICE+2': -2,
758 'DELETE_SLICE+3': -3,
759 'STORE_SUBSCR': -3,
760 'DELETE_SUBSCR': -2,
761 # PRINT_EXPR?
762 'PRINT_ITEM': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000763 'RETURN_VALUE': -1,
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000764 'YIELD_VALUE': -1,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000765 'EXEC_STMT': -3,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000766 'BUILD_CLASS': -2,
767 'STORE_NAME': -1,
768 'STORE_ATTR': -2,
769 'DELETE_ATTR': -1,
770 'STORE_GLOBAL': -1,
771 'BUILD_MAP': 1,
772 'COMPARE_OP': -1,
773 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000774 'IMPORT_STAR': -1,
775 'IMPORT_NAME': 0,
776 'IMPORT_FROM': 1,
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000777 'LOAD_ATTR': 0, # unlike other loads
Jeremy Hylton92638482001-08-29 22:27:14 +0000778 # close enough...
779 'SETUP_EXCEPT': 3,
780 'SETUP_FINALLY': 3,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000781 'FOR_ITER': 1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000782 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000783 # use pattern match
784 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000785 ('BINARY_', -1),
786 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000787 ]
Tim Peterse0c446b2001-10-18 21:57:37 +0000788
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000789 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000790 return count-1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000791 def BUILD_TUPLE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000792 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000793 def BUILD_LIST(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000794 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000795 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000796 hi, lo = divmod(argc, 256)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000797 return -(lo + hi * 2)
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000798 def CALL_FUNCTION_VAR(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000799 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000800 def CALL_FUNCTION_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000801 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000802 def CALL_FUNCTION_VAR_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000803 return self.CALL_FUNCTION(argc)-2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000804 def MAKE_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000805 return -argc
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000806 def MAKE_CLOSURE(self, argc):
807 # XXX need to account for free variables too!
808 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000809 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000810 if argc == 2:
811 return -1
812 elif argc == 3:
813 return -2
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000814 def DUP_TOPX(self, argc):
815 return argc
Tim Peterse0c446b2001-10-18 21:57:37 +0000816
Jeremy Hyltona5058122000-02-14 14:14:29 +0000817findDepth = StackDepthTracker().findDepth