blob: d9d294b18b27231f0ae2aa8c732222a3c31f5c38 [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
5import string
Jeremy Hylton314e3fb2000-11-06 03:43:11 +00006import sys
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00007import types
Jeremy Hyltona5058122000-02-14 14:14:29 +00008
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00009from compiler import misc
Jeremy Hylton71ebc332001-08-30 20:25:55 +000010from compiler.consts import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, \
11 CO_VARKEYWORDS
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000012
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000013def xxx_sort(l):
14 l = l[:]
15 def sorter(a, b):
16 return cmp(a.bid, b.bid)
17 l.sort(sorter)
18 return l
19
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000020class FlowGraph:
21 def __init__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000022 self.current = self.entry = Block()
23 self.exit = Block("exit")
24 self.blocks = misc.Set()
25 self.blocks.add(self.entry)
26 self.blocks.add(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000027
28 def startBlock(self, block):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000029 if self._debug:
30 if self.current:
31 print "end", repr(self.current)
Jeremy Hylton542b11a2001-04-12 20:21:39 +000032 print " next", self.current.next
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000033 print " ", self.current.get_children()
34 print repr(block)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000035 self.current = block
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000036
Jeremy Hylton542b11a2001-04-12 20:21:39 +000037 def nextBlock(self, block=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000038 # XXX think we need to specify when there is implicit transfer
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000039 # from one block to the next. might be better to represent this
40 # with explicit JUMP_ABSOLUTE instructions that are optimized
41 # out when they are unnecessary.
Thomas Wouters46cc7c02000-08-12 20:32:46 +000042 #
43 # I think this strategy works: each block has a child
44 # designated as "next" which is returned as the last of the
45 # children. because the nodes in a graph are emitted in
46 # reverse post order, the "next" block will always be emitted
47 # immediately after its parent.
48 # Worry: maintaining this invariant could be tricky
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000049 if block is None:
50 block = self.newBlock()
51
52 # Note: If the current block ends with an unconditional
53 # control transfer, then it is incorrect to add an implicit
54 # transfer to the block graph. The current code requires
55 # these edges to get the blocks emitted in the right order,
56 # however. :-( If a client needs to remove these edges, call
57 # pruneEdges().
58
Thomas Wouters46cc7c02000-08-12 20:32:46 +000059 self.current.addNext(block)
60 self.startBlock(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000061
62 def newBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000063 b = Block()
64 self.blocks.add(b)
65 return b
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000066
67 def startExitBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000068 self.startBlock(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000069
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000070 _debug = 0
71
72 def _enable_debug(self):
73 self._debug = 1
74
75 def _disable_debug(self):
76 self._debug = 0
77
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000078 def emit(self, *inst):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000079 if self._debug:
80 print "\t", inst
Thomas Wouters46cc7c02000-08-12 20:32:46 +000081 if inst[0] == 'RETURN_VALUE':
82 self.current.addOutEdge(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000083 if len(inst) == 2 and isinstance(inst[1], Block):
84 self.current.addOutEdge(inst[1])
Thomas Wouters46cc7c02000-08-12 20:32:46 +000085 self.current.emit(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000086
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000087 def getBlocksInOrder(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000088 """Return the blocks in reverse postorder
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000089
Thomas Wouters46cc7c02000-08-12 20:32:46 +000090 i.e. each node appears before all of its successors
91 """
92 # XXX make sure every node that doesn't have an explicit next
93 # is set so that next points to exit
94 for b in self.blocks.elements():
95 if b is self.exit:
96 continue
97 if not b.next:
98 b.addNext(self.exit)
99 order = dfs_postorder(self.entry, {})
100 order.reverse()
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000101 self.fixupOrder(order, self.exit)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000102 # hack alert
103 if not self.exit in order:
104 order.append(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000105
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000106 return order
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000107
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000108 def fixupOrder(self, blocks, default_next):
109 """Fixup bad order introduced by DFS."""
110
111 # XXX This is a total mess. There must be a better way to get
112 # the code blocks in the right order.
113
114 self.fixupOrderHonorNext(blocks, default_next)
115 self.fixupOrderForward(blocks, default_next)
116
117 def fixupOrderHonorNext(self, blocks, default_next):
118 """Fix one problem with DFS.
119
120 The DFS uses child block, but doesn't know about the special
121 "next" block. As a result, the DFS can order blocks so that a
122 block isn't next to the right block for implicit control
123 transfers.
124 """
125 index = {}
126 for i in range(len(blocks)):
127 index[blocks[i]] = i
128
129 for i in range(0, len(blocks) - 1):
130 b = blocks[i]
131 n = blocks[i + 1]
132 if not b.next or b.next[0] == default_next or b.next[0] == n:
133 continue
134 # The blocks are in the wrong order. Find the chain of
135 # blocks to insert where they belong.
136 cur = b
137 chain = []
138 elt = cur
139 while elt.next and elt.next[0] != default_next:
140 chain.append(elt.next[0])
141 elt = elt.next[0]
142 # Now remove the blocks in the chain from the current
143 # block list, so that they can be re-inserted.
144 l = []
145 for b in chain:
146 assert index[b] > i
147 l.append((index[b], b))
148 l.sort()
149 l.reverse()
150 for j, b in l:
151 del blocks[index[b]]
152 # Insert the chain in the proper location
153 blocks[i:i + 1] = [cur] + chain
154 # Finally, re-compute the block indexes
155 for i in range(len(blocks)):
156 index[blocks[i]] = i
157
158 def fixupOrderForward(self, blocks, default_next):
159 """Make sure all JUMP_FORWARDs jump forward"""
160 index = {}
161 chains = []
162 cur = []
163 for b in blocks:
164 index[b] = len(chains)
165 cur.append(b)
166 if b.next and b.next[0] == default_next:
167 chains.append(cur)
168 cur = []
169 chains.append(cur)
170
171 while 1:
172 constraints = []
173
174 for i in range(len(chains)):
175 l = chains[i]
176 for b in l:
177 for c in b.get_children():
178 if index[c] < i:
179 forward_p = 0
180 for inst in b.insts:
181 if inst[0] == 'JUMP_FORWARD':
182 if inst[1] == c:
183 forward_p = 1
184 if not forward_p:
185 continue
186 constraints.append((index[c], i))
187
188 if not constraints:
189 break
190
191 # XXX just do one for now
192 # do swaps to get things in the right order
193 goes_before, a_chain = constraints[0]
194 assert a_chain > goes_before
195 c = chains[a_chain]
196 chains.remove(c)
197 chains.insert(goes_before, c)
198
199
200 del blocks[:]
201 for c in chains:
202 for b in c:
203 blocks.append(b)
204
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000205 def getBlocks(self):
206 return self.blocks.elements()
207
208 def getRoot(self):
209 """Return nodes appropriate for use with dominator"""
210 return self.entry
211
212 def getContainedGraphs(self):
213 l = []
214 for b in self.getBlocks():
215 l.extend(b.getContainedGraphs())
216 return l
217
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000218def dfs_postorder(b, seen):
219 """Depth-first search of tree rooted at b, return in postorder"""
220 order = []
221 seen[b] = b
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000222 for c in b.get_children():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000223 if seen.has_key(c):
224 continue
225 order = order + dfs_postorder(c, seen)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000226 order.append(b)
227 return order
228
229class Block:
230 _count = 0
231
232 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000233 self.insts = []
234 self.inEdges = misc.Set()
235 self.outEdges = misc.Set()
236 self.label = label
237 self.bid = Block._count
238 self.next = []
239 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000240
241 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000242 if self.label:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000243 return "<block %s id=%d>" % (self.label, self.bid)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000244 else:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000245 return "<block id=%d>" % (self.bid)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000246
247 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000248 insts = map(str, self.insts)
249 return "<block %s %d:\n%s>" % (self.label, self.bid,
250 string.join(insts, '\n'))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000251
252 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000253 op = inst[0]
254 if op[:4] == 'JUMP':
255 self.outEdges.add(inst[1])
256 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000257
258 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000259 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000260
261 def addInEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000262 self.inEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000263
264 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000265 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000266
267 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000268 self.next.append(block)
269 assert len(self.next) == 1, map(str, self.next)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000270
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000271 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
Jeremy Hylton92638482001-08-29 22:27:14 +0000272 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP')
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000273
274 def pruneNext(self):
275 """Remove bogus edge for unconditional transfers
276
277 Each block has a next edge that accounts for implicit control
278 transfers, e.g. from a JUMP_IF_FALSE to the block that will be
279 executed if the test is true.
280
281 These edges must remain for the current assembler code to
282 work. If they are removed, the dfs_postorder gets things in
283 weird orders. However, they shouldn't be there for other
284 purposes, e.g. conversion to SSA form. This method will
285 remove the next edge when it follows an unconditional control
286 transfer.
287 """
288 try:
289 op, arg = self.insts[-1]
290 except (IndexError, ValueError):
291 return
292 if op in self._uncond_transfer:
293 self.next = []
294
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000295 def get_children(self):
296 if self.next and self.next[0] in self.outEdges:
297 self.outEdges.remove(self.next[0])
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000298 return self.outEdges.elements() + self.next
Jeremy Hyltona5058122000-02-14 14:14:29 +0000299
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000300 def getContainedGraphs(self):
301 """Return all graphs contained within this block.
302
303 For example, a MAKE_FUNCTION block will contain a reference to
304 the graph for the function body.
305 """
306 contained = []
307 for inst in self.insts:
308 if len(inst) == 1:
309 continue
310 op = inst[1]
311 if hasattr(op, 'graph'):
312 contained.append(op.graph)
313 return contained
314
Jeremy Hyltona5058122000-02-14 14:14:29 +0000315# flags for code objects
Jeremy Hyltona5058122000-02-14 14:14:29 +0000316
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000317# the FlowGraph is transformed in place; it exists in one of these states
318RAW = "RAW"
319FLAT = "FLAT"
320CONV = "CONV"
321DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000322
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000323class PyFlowGraph(FlowGraph):
324 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000325
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000326 def __init__(self, name, filename, args=(), optimized=0, klass=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000327 self.super_init()
328 self.name = name
329 self.filename = filename
330 self.docstring = None
331 self.args = args # XXX
332 self.argcount = getArgCount(args)
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000333 self.klass = klass
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000334 if optimized:
335 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
336 else:
337 self.flags = 0
338 self.consts = []
339 self.names = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000340 # Free variables found by the symbol table scan, including
341 # variables used only in nested scopes, are included here.
342 self.freevars = []
343 self.cellvars = []
344 # The closure list is used to track the order of cell
345 # variables and free variables in the resulting code object.
346 # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
347 # kinds of variables.
348 self.closure = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000349 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000350 for i in range(len(self.varnames)):
351 var = self.varnames[i]
352 if isinstance(var, TupleArg):
353 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000354 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000355
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000356 def setDocstring(self, doc):
357 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000358
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000359 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000360 self.flags = self.flags | flag
361 if flag == CO_VARARGS:
362 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000363
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000364 def checkFlag(self, flag):
365 if self.flags & flag:
366 return 1
367
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000368 def setFreeVars(self, names):
369 self.freevars = list(names)
370
371 def setCellVars(self, names):
372 self.cellvars = names
373
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000374 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000375 """Get a Python code object"""
376 if self.stage == RAW:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000377 self.flattenGraph()
378 if self.stage == FLAT:
379 self.convertArgs()
380 if self.stage == CONV:
381 self.makeByteCode()
382 if self.stage == DONE:
383 return self.newCodeObject()
384 raise RuntimeError, "inconsistent PyFlowGraph state"
Jeremy Hyltona5058122000-02-14 14:14:29 +0000385
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000386 def dump(self, io=None):
387 if io:
388 save = sys.stdout
389 sys.stdout = io
390 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000391 for t in self.insts:
392 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000393 if opname == "SET_LINENO":
394 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000395 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000396 print "\t", "%3d" % pc, opname
397 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000398 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000399 print "\t", "%3d" % pc, opname, t[1]
400 pc = pc + 3
401 if io:
402 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000403
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000404 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000405 """Arrange the blocks in order and resolve jumps"""
406 assert self.stage == RAW
407 self.insts = insts = []
408 pc = 0
409 begin = {}
410 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000411 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000412 begin[b] = pc
413 for inst in b.getInstructions():
414 insts.append(inst)
415 if len(inst) == 1:
416 pc = pc + 1
417 else:
418 # arg takes 2 bytes
419 pc = pc + 3
420 end[b] = pc
421 pc = 0
422 for i in range(len(insts)):
423 inst = insts[i]
424 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000425 pc = pc + 1
426 else:
427 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000428 opname = inst[0]
429 if self.hasjrel.has_elt(opname):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000430 oparg = inst[1]
431 offset = begin[oparg] - pc
432 insts[i] = opname, offset
433 elif self.hasjabs.has_elt(opname):
434 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000435 self.stacksize = findDepth(self.insts)
436 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000437
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000438 hasjrel = misc.Set()
439 for i in dis.hasjrel:
440 hasjrel.add(dis.opname[i])
441 hasjabs = misc.Set()
442 for i in dis.hasjabs:
443 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000444
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000445 def convertArgs(self):
446 """Convert arguments from symbolic to concrete form"""
447 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000448 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000449 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000450 for i in range(len(self.insts)):
451 t = self.insts[i]
452 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000453 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000454 conv = self._converters.get(opname, None)
455 if conv:
456 self.insts[i] = opname, conv(self, oparg)
457 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000458
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000459 def sort_cellvars(self):
460 """Sort cellvars in the order of varnames and prune from freevars.
461 """
462 cells = {}
463 for name in self.cellvars:
464 cells[name] = 1
465 self.cellvars = [name for name in self.varnames
466 if cells.has_key(name)]
467 for name in self.cellvars:
468 del cells[name]
469 self.cellvars = self.cellvars + cells.keys()
470 self.closure = self.cellvars + self.freevars
471
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000472 def _lookupName(self, name, list):
473 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000474
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000475 This routine uses a list instead of a dictionary, because a
476 dictionary can't store two different keys if the keys have the
477 same value but different types, e.g. 2 and 2L. The compiler
478 must treat these two separately, so it does an explicit type
479 comparison before comparing the values.
480 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000481 t = type(name)
482 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000483 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000484 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000485 end = len(list)
486 list.append(name)
487 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000488
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000489 _converters = {}
490 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000491 if hasattr(arg, 'getCode'):
492 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000493 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000494
495 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000496 self._lookupName(arg, self.names)
497 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000498 _convert_STORE_FAST = _convert_LOAD_FAST
499 _convert_DELETE_FAST = _convert_LOAD_FAST
500
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000501 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000502 if self.klass is None:
503 self._lookupName(arg, self.varnames)
504 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000505
506 def _convert_NAME(self, arg):
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000507 if self.klass is None:
508 self._lookupName(arg, self.varnames)
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000509 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000510 _convert_STORE_NAME = _convert_NAME
511 _convert_DELETE_NAME = _convert_NAME
512 _convert_IMPORT_NAME = _convert_NAME
513 _convert_IMPORT_FROM = _convert_NAME
514 _convert_STORE_ATTR = _convert_NAME
515 _convert_LOAD_ATTR = _convert_NAME
516 _convert_DELETE_ATTR = _convert_NAME
517 _convert_LOAD_GLOBAL = _convert_NAME
518 _convert_STORE_GLOBAL = _convert_NAME
519 _convert_DELETE_GLOBAL = _convert_NAME
520
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000521 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000522 self._lookupName(arg, self.names)
523 self._lookupName(arg, self.varnames)
524 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000525 _convert_LOAD_DEREF = _convert_DEREF
526 _convert_STORE_DEREF = _convert_DEREF
527
528 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000529 self._lookupName(arg, self.varnames)
530 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000531
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000532 _cmp = list(dis.cmp_op)
533 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000534 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000535
536 # similarly for other opcodes...
537
538 for name, obj in locals().items():
539 if name[:9] == "_convert_":
540 opname = name[9:]
541 _converters[opname] = obj
542 del name, obj, opname
543
544 def makeByteCode(self):
545 assert self.stage == CONV
546 self.lnotab = lnotab = LineAddrTable()
547 for t in self.insts:
548 opname = t[0]
549 if len(t) == 1:
550 lnotab.addCode(self.opnum[opname])
551 else:
552 oparg = t[1]
553 if opname == "SET_LINENO":
554 lnotab.nextLine(oparg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000555 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000556 try:
557 lnotab.addCode(self.opnum[opname], lo, hi)
558 except ValueError:
559 print opname, oparg
560 print self.opnum[opname], lo, hi
561 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000562 self.stage = DONE
563
Jeremy Hyltona5058122000-02-14 14:14:29 +0000564 opnum = {}
565 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000566 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000567 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000568
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000569 def newCodeObject(self):
570 assert self.stage == DONE
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000571 if (self.flags & CO_NEWLOCALS) == 0:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000572 nlocals = 0
573 else:
574 nlocals = len(self.varnames)
575 argcount = self.argcount
576 if self.flags & CO_VARKEYWORDS:
577 argcount = argcount - 1
578 return new.code(argcount, nlocals, self.stacksize, self.flags,
579 self.lnotab.getCode(), self.getConsts(),
580 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000581 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000582 self.lnotab.getTable(), tuple(self.freevars),
583 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000584
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000585 def getConsts(self):
586 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000587
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000588 Must convert references to code (MAKE_FUNCTION) to code
589 objects recursively.
590 """
591 l = []
592 for elt in self.consts:
593 if isinstance(elt, PyFlowGraph):
594 elt = elt.getCode()
595 l.append(elt)
596 return tuple(l)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000597
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000598def isJump(opname):
599 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000600 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000601
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000602class TupleArg:
603 """Helper for marking func defs with nested tuples in arglist"""
604 def __init__(self, count, names):
605 self.count = count
606 self.names = names
607 def __repr__(self):
608 return "TupleArg(%s, %s)" % (self.count, self.names)
609 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000610 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000611
612def getArgCount(args):
613 argcount = len(args)
614 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000615 for arg in args:
616 if isinstance(arg, TupleArg):
617 numNames = len(misc.flatten(arg.names))
618 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000619 return argcount
620
621def twobyte(val):
622 """Convert an int argument into high and low bytes"""
623 assert type(val) == types.IntType
624 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000625
626class LineAddrTable:
627 """lnotab
628
Tim Peters2a7f3842001-06-09 09:26:21 +0000629 This class builds the lnotab, which is documented in compile.c.
630 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000631
632 For each SET_LINENO instruction after the first one, two bytes are
633 added to lnotab. (In some cases, multiple two-byte entries are
634 added.) The first byte is the distance in bytes between the
635 instruction for the last SET_LINENO and the current SET_LINENO.
636 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000637 greater than 255, multiple two-byte entries are added -- see
638 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000639 """
640
641 def __init__(self):
642 self.code = []
643 self.codeOffset = 0
644 self.firstline = 0
645 self.lastline = 0
646 self.lastoff = 0
647 self.lnotab = []
648
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000649 def addCode(self, *args):
650 for arg in args:
651 self.code.append(chr(arg))
652 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000653
654 def nextLine(self, lineno):
655 if self.firstline == 0:
656 self.firstline = lineno
657 self.lastline = lineno
658 else:
659 # compute deltas
660 addr = self.codeOffset - self.lastoff
661 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000662 # Python assumes that lineno always increases with
663 # increasing bytecode address (lnotab is unsigned char).
664 # Depending on when SET_LINENO instructions are emitted
665 # this is not always true. Consider the code:
666 # a = (1,
667 # b)
668 # In the bytecode stream, the assignment to "a" occurs
669 # after the loading of "b". This works with the C Python
670 # compiler because it only generates a SET_LINENO instruction
671 # for the assignment.
672 if line > 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000673 push = self.lnotab.append
674 while addr > 255:
675 push(255); push(0)
676 addr -= 255
677 while line > 255:
678 push(addr); push(255)
679 line -= 255
680 addr = 0
681 if addr > 0 or line > 0:
682 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000683 self.lastline = lineno
684 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000685
686 def getCode(self):
687 return string.join(self.code, '')
688
689 def getTable(self):
690 return string.join(map(chr, self.lnotab), '')
691
Jeremy Hyltona5058122000-02-14 14:14:29 +0000692class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000693 # XXX 1. need to keep track of stack depth on jumps
694 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000695
696 def findDepth(self, insts):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000697 depth = 0
698 maxDepth = 0
699 for i in insts:
700 opname = i[0]
701 delta = self.effect.get(opname, 0)
702 if delta > 1:
703 depth = depth + delta
704 elif delta < 0:
705 if depth > maxDepth:
706 maxDepth = depth
707 depth = depth + delta
708 else:
709 if depth > maxDepth:
710 maxDepth = depth
711 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000712 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000713 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000714 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000715 depth = depth + delta
716 break
717 # if we still haven't found a match
718 if delta == 0:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000719 meth = getattr(self, opname, None)
720 if meth is not None:
721 depth = depth + meth(i[1])
Jeremy Hylton772dd412000-02-21 22:46:00 +0000722 if depth < 0:
723 depth = 0
724 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000725
726 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000727 'POP_TOP': -1,
728 'DUP_TOP': 1,
729 'SLICE+1': -1,
730 'SLICE+2': -1,
731 'SLICE+3': -2,
732 'STORE_SLICE+0': -1,
733 'STORE_SLICE+1': -2,
734 'STORE_SLICE+2': -2,
735 'STORE_SLICE+3': -3,
736 'DELETE_SLICE+0': -1,
737 'DELETE_SLICE+1': -2,
738 'DELETE_SLICE+2': -2,
739 'DELETE_SLICE+3': -3,
740 'STORE_SUBSCR': -3,
741 'DELETE_SUBSCR': -2,
742 # PRINT_EXPR?
743 'PRINT_ITEM': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000744 'RETURN_VALUE': -1,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000745 'EXEC_STMT': -3,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000746 'BUILD_CLASS': -2,
747 'STORE_NAME': -1,
748 'STORE_ATTR': -2,
749 'DELETE_ATTR': -1,
750 'STORE_GLOBAL': -1,
751 'BUILD_MAP': 1,
752 'COMPARE_OP': -1,
753 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000754 'IMPORT_STAR': -1,
755 'IMPORT_NAME': 0,
756 'IMPORT_FROM': 1,
Jeremy Hylton92638482001-08-29 22:27:14 +0000757 # close enough...
758 'SETUP_EXCEPT': 3,
759 'SETUP_FINALLY': 3,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000760 'FOR_ITER': 1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000761 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000762 # use pattern match
763 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000764 ('BINARY_', -1),
765 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000766 ]
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000767
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000768 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000769 return count-1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000770 def BUILD_TUPLE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000771 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000772 def BUILD_LIST(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000773 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000774 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000775 hi, lo = divmod(argc, 256)
776 return lo + hi * 2
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000777 def CALL_FUNCTION_VAR(self, argc):
778 return self.CALL_FUNCTION(argc)+1
779 def CALL_FUNCTION_KW(self, argc):
780 return self.CALL_FUNCTION(argc)+1
781 def CALL_FUNCTION_VAR_KW(self, argc):
782 return self.CALL_FUNCTION(argc)+2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000783 def MAKE_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000784 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000785 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000786 if argc == 2:
787 return -1
788 elif argc == 3:
789 return -2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000790
791findDepth = StackDepthTracker().findDepth