blob: 86e2c49443ba2ac7fa8ded91fbe9db942b1f05b1 [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,
Neal Norwitzc1505362006-12-28 06:47:50 +0000317 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 = []
Neal Norwitzc1505362006-12-28 06:47:50 +0000341 # The varnames list needs to be computed after flags have been set
342 self.varnames = []
343 self.stage = RAW
344
345 def computeVarnames(self):
346 # self.args is positional, vararg, kwarg, kwonly, unpacked. This
347 # order is due to the visit order in symbol module and could change.
348 # argcount is # len(self.args) - len(unpacked). We want
349 # self.varnames to be positional, kwonly, vararg, kwarg, unpacked
350 # and argcount to be len(positional).
351
352 # determine starting index of unpacked, kwonly, vararg
353 u = self.argcount # starting index of unpacked
354 k = u - len(self.kwonlyargs) # starting index of kwonly
355 v = k - self.checkFlag(CO_VARARGS) - self.checkFlag(CO_VARKEYWORDS)
356
357 vars = list(self.args)
358 self.varnames = vars[:v] + vars[k:u] + vars[v:k] + vars[u:]
359 self.argcount = v
360
361 # replace TupleArgs with calculated var name
362 for i in range(self.argcount):
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000363 var = self.varnames[i]
364 if isinstance(var, TupleArg):
365 self.varnames[i] = var.getName()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000366
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000367 def setDocstring(self, doc):
368 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000369
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000370 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000371 self.flags = self.flags | flag
Jeremy Hyltona5058122000-02-14 14:14:29 +0000372
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000373 def checkFlag(self, flag):
Neal Norwitzc1505362006-12-28 06:47:50 +0000374 return (self.flags & flag) == flag
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000375
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000376 def setFreeVars(self, names):
377 self.freevars = list(names)
378
379 def setCellVars(self, names):
380 self.cellvars = names
381
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000382 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000383 """Get a Python code object"""
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000384 assert self.stage == RAW
Neal Norwitzc1505362006-12-28 06:47:50 +0000385 self.computeVarnames()
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000386 self.computeStackDepth()
387 self.flattenGraph()
388 assert self.stage == FLAT
389 self.convertArgs()
390 assert self.stage == CONV
391 self.makeByteCode()
392 assert self.stage == DONE
393 return self.newCodeObject()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000394
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000395 def dump(self, io=None):
396 if io:
397 save = sys.stdout
398 sys.stdout = io
399 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000400 for t in self.insts:
401 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000402 if opname == "SET_LINENO":
403 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000404 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000405 print "\t", "%3d" % pc, opname
406 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000407 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000408 print "\t", "%3d" % pc, opname, t[1]
409 pc = pc + 3
410 if io:
411 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000412
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000413 def computeStackDepth(self):
414 """Compute the max stack depth.
415
416 Approach is to compute the stack effect of each basic block.
417 Then find the path through the code with the largest total
418 effect.
419 """
420 depth = {}
421 exit = None
422 for b in self.getBlocks():
423 depth[b] = findDepth(b.getInstructions())
424
425 seen = {}
426
427 def max_depth(b, d):
Guido van Rossum49061f72006-08-19 15:28:37 +0000428 if b in seen:
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000429 return d
430 seen[b] = 1
431 d = d + depth[b]
432 children = b.get_children()
433 if children:
434 return max([max_depth(c, d) for c in children])
435 else:
436 if not b.label == "exit":
437 return max_depth(self.exit, d)
438 else:
439 return d
440
441 self.stacksize = max_depth(self.entry, 0)
442
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000443 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000444 """Arrange the blocks in order and resolve jumps"""
445 assert self.stage == RAW
446 self.insts = insts = []
447 pc = 0
448 begin = {}
449 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000450 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000451 begin[b] = pc
452 for inst in b.getInstructions():
453 insts.append(inst)
454 if len(inst) == 1:
455 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000456 elif inst[0] != "SET_LINENO":
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000457 # arg takes 2 bytes
458 pc = pc + 3
459 end[b] = pc
460 pc = 0
461 for i in range(len(insts)):
462 inst = insts[i]
463 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000464 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000465 elif inst[0] != "SET_LINENO":
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000466 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000467 opname = inst[0]
468 if self.hasjrel.has_elt(opname):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000469 oparg = inst[1]
470 offset = begin[oparg] - pc
471 insts[i] = opname, offset
472 elif self.hasjabs.has_elt(opname):
473 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000474 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000475
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000476 hasjrel = misc.Set()
477 for i in dis.hasjrel:
478 hasjrel.add(dis.opname[i])
479 hasjabs = misc.Set()
480 for i in dis.hasjabs:
481 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000482
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000483 def convertArgs(self):
484 """Convert arguments from symbolic to concrete form"""
485 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000486 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000487 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000488 for i in range(len(self.insts)):
489 t = self.insts[i]
490 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000491 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000492 conv = self._converters.get(opname, None)
493 if conv:
494 self.insts[i] = opname, conv(self, oparg)
495 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000496
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000497 def sort_cellvars(self):
498 """Sort cellvars in the order of varnames and prune from freevars.
499 """
500 cells = {}
501 for name in self.cellvars:
502 cells[name] = 1
503 self.cellvars = [name for name in self.varnames
Guido van Rossum49061f72006-08-19 15:28:37 +0000504 if name in cells]
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000505 for name in self.cellvars:
506 del cells[name]
507 self.cellvars = self.cellvars + cells.keys()
508 self.closure = self.cellvars + self.freevars
509
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000510 def _lookupName(self, name, list):
511 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000512
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000513 This routine uses a list instead of a dictionary, because a
514 dictionary can't store two different keys if the keys have the
515 same value but different types, e.g. 2 and 2L. The compiler
516 must treat these two separately, so it does an explicit type
517 comparison before comparing the values.
518 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000519 t = type(name)
520 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000521 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000522 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000523 end = len(list)
524 list.append(name)
525 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000526
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000527 _converters = {}
528 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000529 if hasattr(arg, 'getCode'):
530 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000531 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000532
533 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000534 self._lookupName(arg, self.names)
535 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000536 _convert_STORE_FAST = _convert_LOAD_FAST
537 _convert_DELETE_FAST = _convert_LOAD_FAST
538
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000539 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000540 if self.klass is None:
541 self._lookupName(arg, self.varnames)
542 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000543
544 def _convert_NAME(self, arg):
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000545 if self.klass is None:
546 self._lookupName(arg, self.varnames)
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000547 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000548 _convert_STORE_NAME = _convert_NAME
549 _convert_DELETE_NAME = _convert_NAME
550 _convert_IMPORT_NAME = _convert_NAME
551 _convert_IMPORT_FROM = _convert_NAME
552 _convert_STORE_ATTR = _convert_NAME
553 _convert_LOAD_ATTR = _convert_NAME
554 _convert_DELETE_ATTR = _convert_NAME
555 _convert_LOAD_GLOBAL = _convert_NAME
556 _convert_STORE_GLOBAL = _convert_NAME
557 _convert_DELETE_GLOBAL = _convert_NAME
558
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000559 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000560 self._lookupName(arg, self.names)
561 self._lookupName(arg, self.varnames)
562 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000563 _convert_LOAD_DEREF = _convert_DEREF
564 _convert_STORE_DEREF = _convert_DEREF
565
566 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000567 self._lookupName(arg, self.varnames)
568 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000569
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000570 _cmp = list(dis.cmp_op)
571 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000572 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000573
574 # similarly for other opcodes...
575
576 for name, obj in locals().items():
577 if name[:9] == "_convert_":
578 opname = name[9:]
Tim Peterse0c446b2001-10-18 21:57:37 +0000579 _converters[opname] = obj
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000580 del name, obj, opname
581
582 def makeByteCode(self):
583 assert self.stage == CONV
584 self.lnotab = lnotab = LineAddrTable()
585 for t in self.insts:
586 opname = t[0]
587 if len(t) == 1:
588 lnotab.addCode(self.opnum[opname])
589 else:
590 oparg = t[1]
591 if opname == "SET_LINENO":
592 lnotab.nextLine(oparg)
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000593 continue
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000594 hi, lo = twobyte(oparg)
Neal Norwitzc1505362006-12-28 06:47:50 +0000595
596 extended, hi = twobyte(hi)
597 if extended:
598 ehi, elo = twobyte(extended)
599 lnotab.addCode(self.opnum['EXTENDED_ARG'], elo, ehi)
600
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000601 try:
602 lnotab.addCode(self.opnum[opname], lo, hi)
603 except ValueError:
604 print opname, oparg
605 print self.opnum[opname], lo, hi
606 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000607 self.stage = DONE
608
Jeremy Hyltona5058122000-02-14 14:14:29 +0000609 opnum = {}
610 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000611 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000612 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000613
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000614 def newCodeObject(self):
615 assert self.stage == DONE
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000616 if (self.flags & CO_NEWLOCALS) == 0:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000617 nlocals = 0
618 else:
619 nlocals = len(self.varnames)
620 argcount = self.argcount
Guido van Rossum4f72a782006-10-27 23:31:49 +0000621 kwonlyargcount = len(self.kwonlyargs)
622 return new.code(argcount, kwonlyargcount,
623 nlocals, self.stacksize, self.flags,
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000624 self.lnotab.getCode(), self.getConsts(),
625 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000626 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000627 self.lnotab.getTable(), tuple(self.freevars),
628 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000629
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000630 def getConsts(self):
631 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000632
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000633 Must convert references to code (MAKE_FUNCTION) to code
634 objects recursively.
635 """
636 l = []
637 for elt in self.consts:
638 if isinstance(elt, PyFlowGraph):
639 elt = elt.getCode()
640 l.append(elt)
641 return tuple(l)
Tim Peterse0c446b2001-10-18 21:57:37 +0000642
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000643def isJump(opname):
644 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000645 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000646
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000647class TupleArg:
648 """Helper for marking func defs with nested tuples in arglist"""
649 def __init__(self, count, names):
650 self.count = count
651 self.names = names
652 def __repr__(self):
653 return "TupleArg(%s, %s)" % (self.count, self.names)
654 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000655 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000656
657def getArgCount(args):
658 argcount = len(args)
659 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000660 for arg in args:
661 if isinstance(arg, TupleArg):
662 numNames = len(misc.flatten(arg.names))
663 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000664 return argcount
665
666def twobyte(val):
667 """Convert an int argument into high and low bytes"""
Neal Norwitzd752f7d2005-11-25 03:17:59 +0000668 assert isinstance(val, int)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000669 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000670
671class LineAddrTable:
672 """lnotab
Tim Peterse0c446b2001-10-18 21:57:37 +0000673
Tim Peters2a7f3842001-06-09 09:26:21 +0000674 This class builds the lnotab, which is documented in compile.c.
675 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000676
677 For each SET_LINENO instruction after the first one, two bytes are
678 added to lnotab. (In some cases, multiple two-byte entries are
679 added.) The first byte is the distance in bytes between the
680 instruction for the last SET_LINENO and the current SET_LINENO.
681 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000682 greater than 255, multiple two-byte entries are added -- see
683 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000684 """
685
686 def __init__(self):
687 self.code = []
688 self.codeOffset = 0
689 self.firstline = 0
690 self.lastline = 0
691 self.lastoff = 0
692 self.lnotab = []
693
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000694 def addCode(self, *args):
695 for arg in args:
696 self.code.append(chr(arg))
697 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000698
699 def nextLine(self, lineno):
700 if self.firstline == 0:
701 self.firstline = lineno
702 self.lastline = lineno
703 else:
704 # compute deltas
705 addr = self.codeOffset - self.lastoff
706 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000707 # Python assumes that lineno always increases with
708 # increasing bytecode address (lnotab is unsigned char).
709 # Depending on when SET_LINENO instructions are emitted
710 # this is not always true. Consider the code:
711 # a = (1,
712 # b)
713 # In the bytecode stream, the assignment to "a" occurs
714 # after the loading of "b". This works with the C Python
715 # compiler because it only generates a SET_LINENO instruction
716 # for the assignment.
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000717 if line >= 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000718 push = self.lnotab.append
719 while addr > 255:
720 push(255); push(0)
721 addr -= 255
722 while line > 255:
723 push(addr); push(255)
724 line -= 255
725 addr = 0
726 if addr > 0 or line > 0:
727 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000728 self.lastline = lineno
729 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000730
731 def getCode(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000732 return ''.join(self.code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000733
734 def getTable(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000735 return ''.join(map(chr, self.lnotab))
Tim Peterse0c446b2001-10-18 21:57:37 +0000736
Jeremy Hyltona5058122000-02-14 14:14:29 +0000737class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000738 # XXX 1. need to keep track of stack depth on jumps
739 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000740
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000741 def findDepth(self, insts, debug=0):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000742 depth = 0
743 maxDepth = 0
744 for i in insts:
745 opname = i[0]
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000746 if debug:
747 print i,
748 delta = self.effect.get(opname, None)
749 if delta is not None:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000750 depth = depth + delta
751 else:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000752 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000753 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000754 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000755 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000756 depth = depth + delta
757 break
758 # if we still haven't found a match
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000759 if delta is None:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000760 meth = getattr(self, opname, None)
761 if meth is not None:
762 depth = depth + meth(i[1])
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000763 if depth > maxDepth:
764 maxDepth = depth
765 if debug:
766 print depth, maxDepth
Jeremy Hylton772dd412000-02-21 22:46:00 +0000767 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000768
769 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000770 'POP_TOP': -1,
771 'DUP_TOP': 1,
Neal Norwitz10be2ea2006-03-03 20:29:11 +0000772 'LIST_APPEND': -2,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000773 'SLICE+1': -1,
774 'SLICE+2': -1,
775 'SLICE+3': -2,
776 'STORE_SLICE+0': -1,
777 'STORE_SLICE+1': -2,
778 'STORE_SLICE+2': -2,
779 'STORE_SLICE+3': -3,
780 'DELETE_SLICE+0': -1,
781 'DELETE_SLICE+1': -2,
782 'DELETE_SLICE+2': -2,
783 'DELETE_SLICE+3': -3,
784 'STORE_SUBSCR': -3,
785 'DELETE_SUBSCR': -2,
786 # PRINT_EXPR?
787 'PRINT_ITEM': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000788 'RETURN_VALUE': -1,
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000789 'YIELD_VALUE': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000790 'BUILD_CLASS': -2,
791 'STORE_NAME': -1,
792 'STORE_ATTR': -2,
793 'DELETE_ATTR': -1,
794 'STORE_GLOBAL': -1,
795 'BUILD_MAP': 1,
796 'COMPARE_OP': -1,
797 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000798 'IMPORT_STAR': -1,
Thomas Woutersfa0cf4f2006-03-03 18:16:20 +0000799 'IMPORT_NAME': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000800 'IMPORT_FROM': 1,
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000801 'LOAD_ATTR': 0, # unlike other loads
Jeremy Hylton92638482001-08-29 22:27:14 +0000802 # close enough...
803 'SETUP_EXCEPT': 3,
804 'SETUP_FINALLY': 3,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000805 'FOR_ITER': 1,
Guido van Rossumf6694362006-03-10 02:28:35 +0000806 'WITH_CLEANUP': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000807 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000808 # use pattern match
809 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000810 ('BINARY_', -1),
811 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000812 ]
Tim Peterse0c446b2001-10-18 21:57:37 +0000813
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000814 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000815 return count-1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000816 def BUILD_TUPLE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000817 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000818 def BUILD_LIST(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000819 return -count+1
Guido van Rossum86e58e22006-08-28 15:27:34 +0000820 def BUILD_SET(self, count):
821 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000822 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000823 hi, lo = divmod(argc, 256)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000824 return -(lo + hi * 2)
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000825 def CALL_FUNCTION_VAR(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000826 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000827 def CALL_FUNCTION_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000828 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000829 def CALL_FUNCTION_VAR_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000830 return self.CALL_FUNCTION(argc)-2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000831 def MAKE_FUNCTION(self, argc):
Guido van Rossum4f72a782006-10-27 23:31:49 +0000832 hi, lo = divmod(argc, 256)
Neal Norwitzc1505362006-12-28 06:47:50 +0000833 ehi, hi = divmod(hi, 256)
834 return -(lo + hi * 2 + ehi)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000835 def MAKE_CLOSURE(self, argc):
836 # XXX need to account for free variables too!
837 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000838 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000839 if argc == 2:
840 return -1
841 elif argc == 3:
842 return -2
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000843 def DUP_TOPX(self, argc):
844 return argc
Tim Peterse0c446b2001-10-18 21:57:37 +0000845
Jeremy Hyltona5058122000-02-14 14:14:29 +0000846findDepth = StackDepthTracker().findDepth