blob: b2f91aad1f921399e49e45f5040fb7516bb2c59e [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
10
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000011def xxx_sort(l):
12 l = l[:]
13 def sorter(a, b):
14 return cmp(a.bid, b.bid)
15 l.sort(sorter)
16 return l
17
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000018class FlowGraph:
19 def __init__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000020 self.current = self.entry = Block()
21 self.exit = Block("exit")
22 self.blocks = misc.Set()
23 self.blocks.add(self.entry)
24 self.blocks.add(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000025
26 def startBlock(self, block):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000027 if self._debug:
28 if self.current:
29 print "end", repr(self.current)
Jeremy Hylton542b11a2001-04-12 20:21:39 +000030 print " next", self.current.next
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000031 print " ", self.current.get_children()
32 print repr(block)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000033 self.current = block
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000034
Jeremy Hylton542b11a2001-04-12 20:21:39 +000035 def nextBlock(self, block=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000036 # XXX think we need to specify when there is implicit transfer
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000037 # from one block to the next. might be better to represent this
38 # with explicit JUMP_ABSOLUTE instructions that are optimized
39 # out when they are unnecessary.
Thomas Wouters46cc7c02000-08-12 20:32:46 +000040 #
41 # I think this strategy works: each block has a child
42 # designated as "next" which is returned as the last of the
43 # children. because the nodes in a graph are emitted in
44 # reverse post order, the "next" block will always be emitted
45 # immediately after its parent.
46 # Worry: maintaining this invariant could be tricky
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000047 if block is None:
48 block = self.newBlock()
49
50 # Note: If the current block ends with an unconditional
51 # control transfer, then it is incorrect to add an implicit
52 # transfer to the block graph. The current code requires
53 # these edges to get the blocks emitted in the right order,
54 # however. :-( If a client needs to remove these edges, call
55 # pruneEdges().
56
Thomas Wouters46cc7c02000-08-12 20:32:46 +000057 self.current.addNext(block)
58 self.startBlock(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000059
60 def newBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000061 b = Block()
62 self.blocks.add(b)
63 return b
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000064
65 def startExitBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000066 self.startBlock(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000067
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000068 _debug = 0
69
70 def _enable_debug(self):
71 self._debug = 1
72
73 def _disable_debug(self):
74 self._debug = 0
75
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000076 def emit(self, *inst):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000077 if self._debug:
78 print "\t", inst
Thomas Wouters46cc7c02000-08-12 20:32:46 +000079 if inst[0] == 'RETURN_VALUE':
80 self.current.addOutEdge(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000081 if len(inst) == 2 and isinstance(inst[1], Block):
82 self.current.addOutEdge(inst[1])
Thomas Wouters46cc7c02000-08-12 20:32:46 +000083 self.current.emit(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000084
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000085 def getBlocksInOrder(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000086 """Return the blocks in reverse postorder
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000087
Thomas Wouters46cc7c02000-08-12 20:32:46 +000088 i.e. each node appears before all of its successors
89 """
90 # XXX make sure every node that doesn't have an explicit next
91 # is set so that next points to exit
92 for b in self.blocks.elements():
93 if b is self.exit:
94 continue
95 if not b.next:
96 b.addNext(self.exit)
97 order = dfs_postorder(self.entry, {})
98 order.reverse()
Jeremy Hylton542b11a2001-04-12 20:21:39 +000099 self.fixupOrder(order, self.exit)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000100 # hack alert
101 if not self.exit in order:
102 order.append(self.exit)
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000103
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000104 return order
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000105
Jeremy Hylton542b11a2001-04-12 20:21:39 +0000106 def fixupOrder(self, blocks, default_next):
107 """Fixup bad order introduced by DFS."""
108
109 # XXX This is a total mess. There must be a better way to get
110 # the code blocks in the right order.
111
112 self.fixupOrderHonorNext(blocks, default_next)
113 self.fixupOrderForward(blocks, default_next)
114
115 def fixupOrderHonorNext(self, blocks, default_next):
116 """Fix one problem with DFS.
117
118 The DFS uses child block, but doesn't know about the special
119 "next" block. As a result, the DFS can order blocks so that a
120 block isn't next to the right block for implicit control
121 transfers.
122 """
123 index = {}
124 for i in range(len(blocks)):
125 index[blocks[i]] = i
126
127 for i in range(0, len(blocks) - 1):
128 b = blocks[i]
129 n = blocks[i + 1]
130 if not b.next or b.next[0] == default_next or b.next[0] == n:
131 continue
132 # The blocks are in the wrong order. Find the chain of
133 # blocks to insert where they belong.
134 cur = b
135 chain = []
136 elt = cur
137 while elt.next and elt.next[0] != default_next:
138 chain.append(elt.next[0])
139 elt = elt.next[0]
140 # Now remove the blocks in the chain from the current
141 # block list, so that they can be re-inserted.
142 l = []
143 for b in chain:
144 assert index[b] > i
145 l.append((index[b], b))
146 l.sort()
147 l.reverse()
148 for j, b in l:
149 del blocks[index[b]]
150 # Insert the chain in the proper location
151 blocks[i:i + 1] = [cur] + chain
152 # Finally, re-compute the block indexes
153 for i in range(len(blocks)):
154 index[blocks[i]] = i
155
156 def fixupOrderForward(self, blocks, default_next):
157 """Make sure all JUMP_FORWARDs jump forward"""
158 index = {}
159 chains = []
160 cur = []
161 for b in blocks:
162 index[b] = len(chains)
163 cur.append(b)
164 if b.next and b.next[0] == default_next:
165 chains.append(cur)
166 cur = []
167 chains.append(cur)
168
169 while 1:
170 constraints = []
171
172 for i in range(len(chains)):
173 l = chains[i]
174 for b in l:
175 for c in b.get_children():
176 if index[c] < i:
177 forward_p = 0
178 for inst in b.insts:
179 if inst[0] == 'JUMP_FORWARD':
180 if inst[1] == c:
181 forward_p = 1
182 if not forward_p:
183 continue
184 constraints.append((index[c], i))
185
186 if not constraints:
187 break
188
189 # XXX just do one for now
190 # do swaps to get things in the right order
191 goes_before, a_chain = constraints[0]
192 assert a_chain > goes_before
193 c = chains[a_chain]
194 chains.remove(c)
195 chains.insert(goes_before, c)
196
197
198 del blocks[:]
199 for c in chains:
200 for b in c:
201 blocks.append(b)
202
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000203 def getBlocks(self):
204 return self.blocks.elements()
205
206 def getRoot(self):
207 """Return nodes appropriate for use with dominator"""
208 return self.entry
209
210 def getContainedGraphs(self):
211 l = []
212 for b in self.getBlocks():
213 l.extend(b.getContainedGraphs())
214 return l
215
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000216def dfs_postorder(b, seen):
217 """Depth-first search of tree rooted at b, return in postorder"""
218 order = []
219 seen[b] = b
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000220 for c in b.get_children():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000221 if seen.has_key(c):
222 continue
223 order = order + dfs_postorder(c, seen)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000224 order.append(b)
225 return order
226
227class Block:
228 _count = 0
229
230 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000231 self.insts = []
232 self.inEdges = misc.Set()
233 self.outEdges = misc.Set()
234 self.label = label
235 self.bid = Block._count
236 self.next = []
237 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000238
239 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000240 if self.label:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000241 return "<block %s id=%d>" % (self.label, self.bid)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000242 else:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000243 return "<block id=%d>" % (self.bid)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000244
245 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000246 insts = map(str, self.insts)
247 return "<block %s %d:\n%s>" % (self.label, self.bid,
248 string.join(insts, '\n'))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000249
250 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000251 op = inst[0]
252 if op[:4] == 'JUMP':
253 self.outEdges.add(inst[1])
254 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000255
256 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000257 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000258
259 def addInEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000260 self.inEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000261
262 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000263 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000264
265 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000266 self.next.append(block)
267 assert len(self.next) == 1, map(str, self.next)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000268
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000269 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
270 'JUMP_ABSOLUTE', 'JUMP_FORWARD')
271
272 def pruneNext(self):
273 """Remove bogus edge for unconditional transfers
274
275 Each block has a next edge that accounts for implicit control
276 transfers, e.g. from a JUMP_IF_FALSE to the block that will be
277 executed if the test is true.
278
279 These edges must remain for the current assembler code to
280 work. If they are removed, the dfs_postorder gets things in
281 weird orders. However, they shouldn't be there for other
282 purposes, e.g. conversion to SSA form. This method will
283 remove the next edge when it follows an unconditional control
284 transfer.
285 """
286 try:
287 op, arg = self.insts[-1]
288 except (IndexError, ValueError):
289 return
290 if op in self._uncond_transfer:
291 self.next = []
292
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000293 def get_children(self):
294 if self.next and self.next[0] in self.outEdges:
295 self.outEdges.remove(self.next[0])
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000296 return self.outEdges.elements() + self.next
Jeremy Hyltona5058122000-02-14 14:14:29 +0000297
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000298 def getContainedGraphs(self):
299 """Return all graphs contained within this block.
300
301 For example, a MAKE_FUNCTION block will contain a reference to
302 the graph for the function body.
303 """
304 contained = []
305 for inst in self.insts:
306 if len(inst) == 1:
307 continue
308 op = inst[1]
309 if hasattr(op, 'graph'):
310 contained.append(op.graph)
311 return contained
312
Jeremy Hyltona5058122000-02-14 14:14:29 +0000313# flags for code objects
314CO_OPTIMIZED = 0x0001
315CO_NEWLOCALS = 0x0002
316CO_VARARGS = 0x0004
317CO_VARKEYWORDS = 0x0008
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000318CO_NESTED = 0x0010
Jeremy Hyltona5058122000-02-14 14:14:29 +0000319
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000320# the FlowGraph is transformed in place; it exists in one of these states
321RAW = "RAW"
322FLAT = "FLAT"
323CONV = "CONV"
324DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000325
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000326class PyFlowGraph(FlowGraph):
327 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000328
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000329 def __init__(self, name, filename, args=(), optimized=0, klass=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000330 self.super_init()
331 self.name = name
332 self.filename = filename
333 self.docstring = None
334 self.args = args # XXX
335 self.argcount = getArgCount(args)
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000336 self.klass = klass
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000337 if optimized:
338 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
339 else:
340 self.flags = 0
341 self.consts = []
342 self.names = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000343 # Free variables found by the symbol table scan, including
344 # variables used only in nested scopes, are included here.
345 self.freevars = []
346 self.cellvars = []
347 # The closure list is used to track the order of cell
348 # variables and free variables in the resulting code object.
349 # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
350 # kinds of variables.
351 self.closure = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000352 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000353 for i in range(len(self.varnames)):
354 var = self.varnames[i]
355 if isinstance(var, TupleArg):
356 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000357 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000358
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000359 def setDocstring(self, doc):
360 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000361
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000362 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000363 self.flags = self.flags | flag
364 if flag == CO_VARARGS:
365 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000366
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000367 def setFreeVars(self, names):
368 self.freevars = list(names)
369
370 def setCellVars(self, names):
371 self.cellvars = names
372
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000373 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000374 """Get a Python code object"""
375 if self.stage == RAW:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000376 self.flattenGraph()
377 if self.stage == FLAT:
378 self.convertArgs()
379 if self.stage == CONV:
380 self.makeByteCode()
381 if self.stage == DONE:
382 return self.newCodeObject()
383 raise RuntimeError, "inconsistent PyFlowGraph state"
Jeremy Hyltona5058122000-02-14 14:14:29 +0000384
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000385 def dump(self, io=None):
386 if io:
387 save = sys.stdout
388 sys.stdout = io
389 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000390 for t in self.insts:
391 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000392 if opname == "SET_LINENO":
393 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000394 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000395 print "\t", "%3d" % pc, opname
396 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000397 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000398 print "\t", "%3d" % pc, opname, t[1]
399 pc = pc + 3
400 if io:
401 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000402
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000403 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000404 """Arrange the blocks in order and resolve jumps"""
405 assert self.stage == RAW
406 self.insts = insts = []
407 pc = 0
408 begin = {}
409 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000410 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000411 begin[b] = pc
412 for inst in b.getInstructions():
413 insts.append(inst)
414 if len(inst) == 1:
415 pc = pc + 1
416 else:
417 # arg takes 2 bytes
418 pc = pc + 3
419 end[b] = pc
420 pc = 0
421 for i in range(len(insts)):
422 inst = insts[i]
423 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000424 pc = pc + 1
425 else:
426 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000427 opname = inst[0]
428 if self.hasjrel.has_elt(opname):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000429 oparg = inst[1]
430 offset = begin[oparg] - pc
431 insts[i] = opname, offset
432 elif self.hasjabs.has_elt(opname):
433 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000434 self.stacksize = findDepth(self.insts)
435 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000436
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000437 hasjrel = misc.Set()
438 for i in dis.hasjrel:
439 hasjrel.add(dis.opname[i])
440 hasjabs = misc.Set()
441 for i in dis.hasjabs:
442 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000443
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000444 def convertArgs(self):
445 """Convert arguments from symbolic to concrete form"""
446 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000447 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000448 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000449 for i in range(len(self.insts)):
450 t = self.insts[i]
451 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000452 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000453 conv = self._converters.get(opname, None)
454 if conv:
455 self.insts[i] = opname, conv(self, oparg)
456 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000457
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000458 def sort_cellvars(self):
459 """Sort cellvars in the order of varnames and prune from freevars.
460 """
461 cells = {}
462 for name in self.cellvars:
463 cells[name] = 1
464 self.cellvars = [name for name in self.varnames
465 if cells.has_key(name)]
466 for name in self.cellvars:
467 del cells[name]
468 self.cellvars = self.cellvars + cells.keys()
469 self.closure = self.cellvars + self.freevars
470
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000471 def _lookupName(self, name, list):
472 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000473
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000474 This routine uses a list instead of a dictionary, because a
475 dictionary can't store two different keys if the keys have the
476 same value but different types, e.g. 2 and 2L. The compiler
477 must treat these two separately, so it does an explicit type
478 comparison before comparing the values.
479 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000480 t = type(name)
481 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000482 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000483 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000484 end = len(list)
485 list.append(name)
486 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000487
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000488 _converters = {}
489 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000490 if hasattr(arg, 'getCode'):
491 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000492 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000493
494 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000495 self._lookupName(arg, self.names)
496 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000497 _convert_STORE_FAST = _convert_LOAD_FAST
498 _convert_DELETE_FAST = _convert_LOAD_FAST
499
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000500 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000501 if self.klass is None:
502 self._lookupName(arg, self.varnames)
503 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000504
505 def _convert_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000506 self._lookupName(arg, self.varnames)
507 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000508 _convert_STORE_NAME = _convert_NAME
509 _convert_DELETE_NAME = _convert_NAME
510 _convert_IMPORT_NAME = _convert_NAME
511 _convert_IMPORT_FROM = _convert_NAME
512 _convert_STORE_ATTR = _convert_NAME
513 _convert_LOAD_ATTR = _convert_NAME
514 _convert_DELETE_ATTR = _convert_NAME
515 _convert_LOAD_GLOBAL = _convert_NAME
516 _convert_STORE_GLOBAL = _convert_NAME
517 _convert_DELETE_GLOBAL = _convert_NAME
518
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000519 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000520 self._lookupName(arg, self.names)
521 self._lookupName(arg, self.varnames)
522 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000523 _convert_LOAD_DEREF = _convert_DEREF
524 _convert_STORE_DEREF = _convert_DEREF
525
526 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000527 self._lookupName(arg, self.varnames)
528 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000529
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000530 _cmp = list(dis.cmp_op)
531 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000532 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000533
534 # similarly for other opcodes...
535
536 for name, obj in locals().items():
537 if name[:9] == "_convert_":
538 opname = name[9:]
539 _converters[opname] = obj
540 del name, obj, opname
541
542 def makeByteCode(self):
543 assert self.stage == CONV
544 self.lnotab = lnotab = LineAddrTable()
545 for t in self.insts:
546 opname = t[0]
547 if len(t) == 1:
548 lnotab.addCode(self.opnum[opname])
549 else:
550 oparg = t[1]
551 if opname == "SET_LINENO":
552 lnotab.nextLine(oparg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000553 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000554 try:
555 lnotab.addCode(self.opnum[opname], lo, hi)
556 except ValueError:
557 print opname, oparg
558 print self.opnum[opname], lo, hi
559 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000560 self.stage = DONE
561
Jeremy Hyltona5058122000-02-14 14:14:29 +0000562 opnum = {}
563 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000564 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000565 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000566
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000567 def newCodeObject(self):
568 assert self.stage == DONE
569 if self.flags == 0:
570 nlocals = 0
571 else:
572 nlocals = len(self.varnames)
573 argcount = self.argcount
574 if self.flags & CO_VARKEYWORDS:
575 argcount = argcount - 1
576 return new.code(argcount, nlocals, self.stacksize, self.flags,
577 self.lnotab.getCode(), self.getConsts(),
578 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000579 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000580 self.lnotab.getTable(), tuple(self.freevars),
581 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000582
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000583 def getConsts(self):
584 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000585
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000586 Must convert references to code (MAKE_FUNCTION) to code
587 objects recursively.
588 """
589 l = []
590 for elt in self.consts:
591 if isinstance(elt, PyFlowGraph):
592 elt = elt.getCode()
593 l.append(elt)
594 return tuple(l)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000595
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000596def isJump(opname):
597 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000598 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000599
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000600class TupleArg:
601 """Helper for marking func defs with nested tuples in arglist"""
602 def __init__(self, count, names):
603 self.count = count
604 self.names = names
605 def __repr__(self):
606 return "TupleArg(%s, %s)" % (self.count, self.names)
607 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000608 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000609
610def getArgCount(args):
611 argcount = len(args)
612 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000613 for arg in args:
614 if isinstance(arg, TupleArg):
615 numNames = len(misc.flatten(arg.names))
616 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000617 return argcount
618
619def twobyte(val):
620 """Convert an int argument into high and low bytes"""
621 assert type(val) == types.IntType
622 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000623
624class LineAddrTable:
625 """lnotab
626
Tim Peters2a7f3842001-06-09 09:26:21 +0000627 This class builds the lnotab, which is documented in compile.c.
628 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000629
630 For each SET_LINENO instruction after the first one, two bytes are
631 added to lnotab. (In some cases, multiple two-byte entries are
632 added.) The first byte is the distance in bytes between the
633 instruction for the last SET_LINENO and the current SET_LINENO.
634 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000635 greater than 255, multiple two-byte entries are added -- see
636 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000637 """
638
639 def __init__(self):
640 self.code = []
641 self.codeOffset = 0
642 self.firstline = 0
643 self.lastline = 0
644 self.lastoff = 0
645 self.lnotab = []
646
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000647 def addCode(self, *args):
648 for arg in args:
649 self.code.append(chr(arg))
650 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000651
652 def nextLine(self, lineno):
653 if self.firstline == 0:
654 self.firstline = lineno
655 self.lastline = lineno
656 else:
657 # compute deltas
658 addr = self.codeOffset - self.lastoff
659 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000660 # Python assumes that lineno always increases with
661 # increasing bytecode address (lnotab is unsigned char).
662 # Depending on when SET_LINENO instructions are emitted
663 # this is not always true. Consider the code:
664 # a = (1,
665 # b)
666 # In the bytecode stream, the assignment to "a" occurs
667 # after the loading of "b". This works with the C Python
668 # compiler because it only generates a SET_LINENO instruction
669 # for the assignment.
670 if line > 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000671 push = self.lnotab.append
672 while addr > 255:
673 push(255); push(0)
674 addr -= 255
675 while line > 255:
676 push(addr); push(255)
677 line -= 255
678 addr = 0
679 if addr > 0 or line > 0:
680 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000681 self.lastline = lineno
682 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000683
684 def getCode(self):
685 return string.join(self.code, '')
686
687 def getTable(self):
688 return string.join(map(chr, self.lnotab), '')
689
Jeremy Hyltona5058122000-02-14 14:14:29 +0000690class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000691 # XXX 1. need to keep track of stack depth on jumps
692 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000693
694 def findDepth(self, insts):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000695 depth = 0
696 maxDepth = 0
697 for i in insts:
698 opname = i[0]
699 delta = self.effect.get(opname, 0)
700 if delta > 1:
701 depth = depth + delta
702 elif delta < 0:
703 if depth > maxDepth:
704 maxDepth = depth
705 depth = depth + delta
706 else:
707 if depth > maxDepth:
708 maxDepth = depth
709 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000710 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000711 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000712 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000713 depth = depth + delta
714 break
715 # if we still haven't found a match
716 if delta == 0:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000717 meth = getattr(self, opname, None)
718 if meth is not None:
719 depth = depth + meth(i[1])
Jeremy Hylton772dd412000-02-21 22:46:00 +0000720 if depth < 0:
721 depth = 0
722 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000723
724 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000725 'POP_TOP': -1,
726 'DUP_TOP': 1,
727 'SLICE+1': -1,
728 'SLICE+2': -1,
729 'SLICE+3': -2,
730 'STORE_SLICE+0': -1,
731 'STORE_SLICE+1': -2,
732 'STORE_SLICE+2': -2,
733 'STORE_SLICE+3': -3,
734 'DELETE_SLICE+0': -1,
735 'DELETE_SLICE+1': -2,
736 'DELETE_SLICE+2': -2,
737 'DELETE_SLICE+3': -3,
738 'STORE_SUBSCR': -3,
739 'DELETE_SUBSCR': -2,
740 # PRINT_EXPR?
741 'PRINT_ITEM': -1,
742 'LOAD_LOCALS': 1,
743 'RETURN_VALUE': -1,
744 'EXEC_STMT': -2,
745 'BUILD_CLASS': -2,
746 'STORE_NAME': -1,
747 'STORE_ATTR': -2,
748 'DELETE_ATTR': -1,
749 'STORE_GLOBAL': -1,
750 'BUILD_MAP': 1,
751 'COMPARE_OP': -1,
752 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000753 'IMPORT_STAR': -1,
754 'IMPORT_NAME': 0,
755 'IMPORT_FROM': 1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000756 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000757 # use pattern match
758 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000759 ('BINARY_', -1),
760 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000761 ]
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000762
763 # special cases:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000764 # UNPACK_SEQUENCE, BUILD_TUPLE,
Jeremy Hyltona5058122000-02-14 14:14:29 +0000765 # BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000766 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000767 return count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000768 def BUILD_TUPLE(self, count):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000769 return -count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000770 def BUILD_LIST(self, count):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000771 return -count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000772 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000773 hi, lo = divmod(argc, 256)
774 return lo + hi * 2
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000775 def CALL_FUNCTION_VAR(self, argc):
776 return self.CALL_FUNCTION(argc)+1
777 def CALL_FUNCTION_KW(self, argc):
778 return self.CALL_FUNCTION(argc)+1
779 def CALL_FUNCTION_VAR_KW(self, argc):
780 return self.CALL_FUNCTION(argc)+2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000781 def MAKE_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000782 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000783 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000784 if argc == 2:
785 return -1
786 elif argc == 3:
787 return -2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000788
789findDepth = StackDepthTracker().findDepth