blob: 286be0c8c7d02616d804cafbeea17912e3ccd0d8 [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
Christian Heimesc756d002007-11-27 21:34:01 +00004import types
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
Neil Schemenauer4db626f2009-02-06 21:08:52 +000024 print " prev", self.current.prev
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000025 print " ", self.current.get_children()
26 print repr(block)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000027 self.current = block
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000028
Jeremy Hylton542b11a2001-04-12 20:21:39 +000029 def nextBlock(self, block=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000030 # XXX think we need to specify when there is implicit transfer
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000031 # from one block to the next. might be better to represent this
32 # with explicit JUMP_ABSOLUTE instructions that are optimized
33 # out when they are unnecessary.
Thomas Wouters46cc7c02000-08-12 20:32:46 +000034 #
35 # I think this strategy works: each block has a child
36 # designated as "next" which is returned as the last of the
37 # children. because the nodes in a graph are emitted in
38 # reverse post order, the "next" block will always be emitted
39 # immediately after its parent.
40 # Worry: maintaining this invariant could be tricky
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000041 if block is None:
42 block = self.newBlock()
43
Neil Schemenauer4db626f2009-02-06 21:08:52 +000044 # Note: If the current block ends with an unconditional control
45 # transfer, then it is techically incorrect to add an implicit
46 # transfer to the block graph. Doing so results in code generation
47 # for unreachable blocks. That doesn't appear to be very common
48 # with Python code and since the built-in compiler doesn't optimize
49 # it out we don't either.
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 Hylton314e3fb2000-11-06 03:43:11 +000072 if len(inst) == 2 and isinstance(inst[1], Block):
73 self.current.addOutEdge(inst[1])
Thomas Wouters46cc7c02000-08-12 20:32:46 +000074 self.current.emit(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000075
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000076 def getBlocksInOrder(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000077 """Return the blocks in reverse postorder
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000078
Thomas Wouters46cc7c02000-08-12 20:32:46 +000079 i.e. each node appears before all of its successors
80 """
Neil Schemenauer4db626f2009-02-06 21:08:52 +000081 order = order_blocks(self.entry, self.exit)
Thomas Wouters46cc7c02000-08-12 20:32:46 +000082 return order
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000083
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000084 def getBlocks(self):
85 return self.blocks.elements()
86
87 def getRoot(self):
88 """Return nodes appropriate for use with dominator"""
89 return self.entry
Tim Peterse0c446b2001-10-18 21:57:37 +000090
Jeremy Hylton314e3fb2000-11-06 03:43:11 +000091 def getContainedGraphs(self):
92 l = []
93 for b in self.getBlocks():
94 l.extend(b.getContainedGraphs())
95 return l
96
Neil Schemenauer4db626f2009-02-06 21:08:52 +000097
98def order_blocks(start_block, exit_block):
99 """Order blocks so that they are emitted in the right order"""
100 # Rules:
101 # - when a block has a next block, the next block must be emitted just after
102 # - when a block has followers (relative jumps), it must be emitted before
103 # them
104 # - all reachable blocks must be emitted
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000105 order = []
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000106
107 # Find all the blocks to be emitted.
108 remaining = set()
109 todo = [start_block]
110 while todo:
111 b = todo.pop()
112 if b in remaining:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000113 continue
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000114 remaining.add(b)
115 for c in b.get_children():
116 if c not in remaining:
117 todo.append(c)
118
119 # A block is dominated by another block if that block must be emitted
120 # before it.
121 dominators = {}
122 for b in remaining:
123 if __debug__ and b.next:
124 assert b is b.next[0].prev[0], (b, b.next)
Jeffrey Yasskin68d68522009-02-28 19:03:21 +0000125 # Make sure every block appears in dominators, even if no
126 # other block must precede it.
127 dominators.setdefault(b, set())
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000128 # preceeding blocks dominate following blocks
129 for c in b.get_followers():
130 while 1:
131 dominators.setdefault(c, set()).add(b)
132 # Any block that has a next pointer leading to c is also
133 # dominated because the whole chain will be emitted at once.
134 # Walk backwards and add them all.
135 if c.prev and c.prev[0] is not b:
136 c = c.prev[0]
137 else:
138 break
139
140 def find_next():
141 # Find a block that can be emitted next.
142 for b in remaining:
143 for c in dominators[b]:
144 if c in remaining:
145 break # can't emit yet, dominated by a remaining block
146 else:
147 return b
148 assert 0, 'circular dependency, cannot find next block'
149
150 b = start_block
151 while 1:
152 order.append(b)
153 remaining.discard(b)
154 if b.next:
155 b = b.next[0]
156 continue
157 elif b is not exit_block and not b.has_unconditional_transfer():
158 order.append(exit_block)
159 if not remaining:
160 break
161 b = find_next()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000162 return order
163
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000164
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000165class Block:
166 _count = 0
167
168 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000169 self.insts = []
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000170 self.outEdges = set()
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000171 self.label = label
172 self.bid = Block._count
173 self.next = []
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000174 self.prev = []
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000175 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000176
177 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000178 if self.label:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000179 return "<block %s id=%d>" % (self.label, self.bid)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000180 else:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000181 return "<block id=%d>" % (self.bid)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000182
183 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000184 insts = map(str, self.insts)
185 return "<block %s %d:\n%s>" % (self.label, self.bid,
Neal Norwitza312c3a2002-06-06 18:30:10 +0000186 '\n'.join(insts))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000187
188 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000189 op = inst[0]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000190 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000191
192 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000193 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000194
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000195 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000196 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000197
198 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000199 self.next.append(block)
200 assert len(self.next) == 1, map(str, self.next)
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000201 block.prev.append(self)
202 assert len(block.prev) == 1, map(str, block.prev)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000203
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000204 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
205 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP',
206 )
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000207
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000208 def has_unconditional_transfer(self):
209 """Returns True if there is an unconditional transfer to an other block
210 at the end of this block. This means there is no risk for the bytecode
211 executer to go past this block's bytecode."""
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000212 try:
213 op, arg = self.insts[-1]
214 except (IndexError, ValueError):
215 return
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000216 return op in self._uncond_transfer
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000217
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000218 def get_children(self):
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000219 return list(self.outEdges) + self.next
220
221 def get_followers(self):
222 """Get the whole list of followers, including the next block."""
223 followers = set(self.next)
224 # Blocks that must be emitted *after* this one, because of
225 # bytecode offsets (e.g. relative jumps) pointing to them.
226 for inst in self.insts:
227 if inst[0] in PyFlowGraph.hasjrel:
228 followers.add(inst[1])
229 return followers
Jeremy Hyltona5058122000-02-14 14:14:29 +0000230
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000231 def getContainedGraphs(self):
232 """Return all graphs contained within this block.
233
234 For example, a MAKE_FUNCTION block will contain a reference to
235 the graph for the function body.
236 """
237 contained = []
238 for inst in self.insts:
239 if len(inst) == 1:
240 continue
241 op = inst[1]
242 if hasattr(op, 'graph'):
243 contained.append(op.graph)
244 return contained
245
Jeremy Hyltona5058122000-02-14 14:14:29 +0000246# flags for code objects
Jeremy Hyltona5058122000-02-14 14:14:29 +0000247
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000248# the FlowGraph is transformed in place; it exists in one of these states
249RAW = "RAW"
250FLAT = "FLAT"
251CONV = "CONV"
252DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000253
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000254class PyFlowGraph(FlowGraph):
255 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000256
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000257 def __init__(self, name, filename, args=(), optimized=0, klass=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000258 self.super_init()
259 self.name = name
260 self.filename = filename
261 self.docstring = None
262 self.args = args # XXX
263 self.argcount = getArgCount(args)
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000264 self.klass = klass
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000265 if optimized:
Tim Peterse0c446b2001-10-18 21:57:37 +0000266 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000267 else:
268 self.flags = 0
269 self.consts = []
270 self.names = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000271 # Free variables found by the symbol table scan, including
272 # variables used only in nested scopes, are included here.
273 self.freevars = []
274 self.cellvars = []
275 # The closure list is used to track the order of cell
276 # variables and free variables in the resulting code object.
277 # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
278 # kinds of variables.
279 self.closure = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000280 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000281 for i in range(len(self.varnames)):
282 var = self.varnames[i]
283 if isinstance(var, TupleArg):
284 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000285 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000286
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000287 def setDocstring(self, doc):
288 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000289
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000290 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000291 self.flags = self.flags | flag
292 if flag == CO_VARARGS:
293 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000294
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000295 def checkFlag(self, flag):
296 if self.flags & flag:
297 return 1
298
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000299 def setFreeVars(self, names):
300 self.freevars = list(names)
301
302 def setCellVars(self, names):
303 self.cellvars = names
304
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000305 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000306 """Get a Python code object"""
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000307 assert self.stage == RAW
308 self.computeStackDepth()
309 self.flattenGraph()
310 assert self.stage == FLAT
311 self.convertArgs()
312 assert self.stage == CONV
313 self.makeByteCode()
314 assert self.stage == DONE
315 return self.newCodeObject()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000316
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000317 def dump(self, io=None):
318 if io:
319 save = sys.stdout
320 sys.stdout = io
321 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000322 for t in self.insts:
323 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000324 if opname == "SET_LINENO":
325 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000326 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000327 print "\t", "%3d" % pc, opname
328 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000329 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000330 print "\t", "%3d" % pc, opname, t[1]
331 pc = pc + 3
332 if io:
333 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000334
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000335 def computeStackDepth(self):
336 """Compute the max stack depth.
337
338 Approach is to compute the stack effect of each basic block.
339 Then find the path through the code with the largest total
340 effect.
341 """
342 depth = {}
343 exit = None
344 for b in self.getBlocks():
345 depth[b] = findDepth(b.getInstructions())
346
347 seen = {}
348
349 def max_depth(b, d):
Georg Brandl2d2fe572008-12-15 08:58:59 +0000350 if b in seen:
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000351 return d
352 seen[b] = 1
353 d = d + depth[b]
354 children = b.get_children()
355 if children:
356 return max([max_depth(c, d) for c in children])
357 else:
358 if not b.label == "exit":
359 return max_depth(self.exit, d)
360 else:
361 return d
362
363 self.stacksize = max_depth(self.entry, 0)
364
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000365 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000366 """Arrange the blocks in order and resolve jumps"""
367 assert self.stage == RAW
368 self.insts = insts = []
369 pc = 0
370 begin = {}
371 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000372 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000373 begin[b] = pc
374 for inst in b.getInstructions():
375 insts.append(inst)
376 if len(inst) == 1:
377 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000378 elif inst[0] != "SET_LINENO":
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000379 # arg takes 2 bytes
380 pc = pc + 3
381 end[b] = pc
382 pc = 0
383 for i in range(len(insts)):
384 inst = insts[i]
385 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000386 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000387 elif inst[0] != "SET_LINENO":
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000388 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000389 opname = inst[0]
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000390 if opname in self.hasjrel:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000391 oparg = inst[1]
392 offset = begin[oparg] - pc
393 insts[i] = opname, offset
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000394 elif opname in self.hasjabs:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000395 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000396 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000397
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000398 hasjrel = set()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000399 for i in dis.hasjrel:
400 hasjrel.add(dis.opname[i])
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000401 hasjabs = set()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000402 for i in dis.hasjabs:
403 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000404
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000405 def convertArgs(self):
406 """Convert arguments from symbolic to concrete form"""
407 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000408 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000409 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000410 for i in range(len(self.insts)):
411 t = self.insts[i]
412 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000413 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000414 conv = self._converters.get(opname, None)
415 if conv:
416 self.insts[i] = opname, conv(self, oparg)
417 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000418
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000419 def sort_cellvars(self):
420 """Sort cellvars in the order of varnames and prune from freevars.
421 """
422 cells = {}
423 for name in self.cellvars:
424 cells[name] = 1
425 self.cellvars = [name for name in self.varnames
Georg Brandl2d2fe572008-12-15 08:58:59 +0000426 if name in cells]
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000427 for name in self.cellvars:
428 del cells[name]
429 self.cellvars = self.cellvars + cells.keys()
430 self.closure = self.cellvars + self.freevars
431
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000432 def _lookupName(self, name, list):
433 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000434
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000435 This routine uses a list instead of a dictionary, because a
436 dictionary can't store two different keys if the keys have the
437 same value but different types, e.g. 2 and 2L. The compiler
438 must treat these two separately, so it does an explicit type
439 comparison before comparing the values.
440 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000441 t = type(name)
442 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000443 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000444 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000445 end = len(list)
446 list.append(name)
447 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000448
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000449 _converters = {}
450 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000451 if hasattr(arg, 'getCode'):
452 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000453 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000454
455 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000456 self._lookupName(arg, self.names)
457 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000458 _convert_STORE_FAST = _convert_LOAD_FAST
459 _convert_DELETE_FAST = _convert_LOAD_FAST
460
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000461 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000462 if self.klass is None:
463 self._lookupName(arg, self.varnames)
464 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000465
466 def _convert_NAME(self, arg):
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000467 if self.klass is None:
468 self._lookupName(arg, self.varnames)
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000469 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000470 _convert_STORE_NAME = _convert_NAME
471 _convert_DELETE_NAME = _convert_NAME
472 _convert_IMPORT_NAME = _convert_NAME
473 _convert_IMPORT_FROM = _convert_NAME
474 _convert_STORE_ATTR = _convert_NAME
475 _convert_LOAD_ATTR = _convert_NAME
476 _convert_DELETE_ATTR = _convert_NAME
477 _convert_LOAD_GLOBAL = _convert_NAME
478 _convert_STORE_GLOBAL = _convert_NAME
479 _convert_DELETE_GLOBAL = _convert_NAME
480
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000481 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000482 self._lookupName(arg, self.names)
483 self._lookupName(arg, self.varnames)
484 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000485 _convert_LOAD_DEREF = _convert_DEREF
486 _convert_STORE_DEREF = _convert_DEREF
487
488 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000489 self._lookupName(arg, self.varnames)
490 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000491
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000492 _cmp = list(dis.cmp_op)
493 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000494 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000495
496 # similarly for other opcodes...
497
498 for name, obj in locals().items():
499 if name[:9] == "_convert_":
500 opname = name[9:]
Tim Peterse0c446b2001-10-18 21:57:37 +0000501 _converters[opname] = obj
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000502 del name, obj, opname
503
504 def makeByteCode(self):
505 assert self.stage == CONV
506 self.lnotab = lnotab = LineAddrTable()
507 for t in self.insts:
508 opname = t[0]
509 if len(t) == 1:
510 lnotab.addCode(self.opnum[opname])
511 else:
512 oparg = t[1]
513 if opname == "SET_LINENO":
514 lnotab.nextLine(oparg)
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000515 continue
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000516 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000517 try:
518 lnotab.addCode(self.opnum[opname], lo, hi)
519 except ValueError:
520 print opname, oparg
521 print self.opnum[opname], lo, hi
522 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000523 self.stage = DONE
524
Jeremy Hyltona5058122000-02-14 14:14:29 +0000525 opnum = {}
526 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000527 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000528 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000529
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000530 def newCodeObject(self):
531 assert self.stage == DONE
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000532 if (self.flags & CO_NEWLOCALS) == 0:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000533 nlocals = 0
534 else:
535 nlocals = len(self.varnames)
536 argcount = self.argcount
537 if self.flags & CO_VARKEYWORDS:
538 argcount = argcount - 1
Christian Heimesc756d002007-11-27 21:34:01 +0000539 return types.CodeType(argcount, nlocals, self.stacksize, self.flags,
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000540 self.lnotab.getCode(), self.getConsts(),
541 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000542 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000543 self.lnotab.getTable(), tuple(self.freevars),
544 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000545
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000546 def getConsts(self):
547 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000548
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000549 Must convert references to code (MAKE_FUNCTION) to code
550 objects recursively.
551 """
552 l = []
553 for elt in self.consts:
554 if isinstance(elt, PyFlowGraph):
555 elt = elt.getCode()
556 l.append(elt)
557 return tuple(l)
Tim Peterse0c446b2001-10-18 21:57:37 +0000558
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000559def isJump(opname):
560 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000561 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000562
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000563class TupleArg:
564 """Helper for marking func defs with nested tuples in arglist"""
565 def __init__(self, count, names):
566 self.count = count
567 self.names = names
568 def __repr__(self):
569 return "TupleArg(%s, %s)" % (self.count, self.names)
570 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000571 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000572
573def getArgCount(args):
574 argcount = len(args)
575 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000576 for arg in args:
577 if isinstance(arg, TupleArg):
578 numNames = len(misc.flatten(arg.names))
579 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000580 return argcount
581
582def twobyte(val):
583 """Convert an int argument into high and low bytes"""
Neal Norwitzd752f7d2005-11-25 03:17:59 +0000584 assert isinstance(val, int)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000585 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000586
587class LineAddrTable:
588 """lnotab
Tim Peterse0c446b2001-10-18 21:57:37 +0000589
Tim Peters2a7f3842001-06-09 09:26:21 +0000590 This class builds the lnotab, which is documented in compile.c.
591 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000592
593 For each SET_LINENO instruction after the first one, two bytes are
594 added to lnotab. (In some cases, multiple two-byte entries are
595 added.) The first byte is the distance in bytes between the
596 instruction for the last SET_LINENO and the current SET_LINENO.
597 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000598 greater than 255, multiple two-byte entries are added -- see
599 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000600 """
601
602 def __init__(self):
603 self.code = []
604 self.codeOffset = 0
605 self.firstline = 0
606 self.lastline = 0
607 self.lastoff = 0
608 self.lnotab = []
609
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000610 def addCode(self, *args):
611 for arg in args:
612 self.code.append(chr(arg))
613 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000614
615 def nextLine(self, lineno):
616 if self.firstline == 0:
617 self.firstline = lineno
618 self.lastline = lineno
619 else:
620 # compute deltas
621 addr = self.codeOffset - self.lastoff
622 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000623 # Python assumes that lineno always increases with
624 # increasing bytecode address (lnotab is unsigned char).
625 # Depending on when SET_LINENO instructions are emitted
626 # this is not always true. Consider the code:
627 # a = (1,
628 # b)
629 # In the bytecode stream, the assignment to "a" occurs
630 # after the loading of "b". This works with the C Python
631 # compiler because it only generates a SET_LINENO instruction
632 # for the assignment.
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000633 if line >= 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000634 push = self.lnotab.append
635 while addr > 255:
636 push(255); push(0)
637 addr -= 255
638 while line > 255:
639 push(addr); push(255)
640 line -= 255
641 addr = 0
642 if addr > 0 or line > 0:
643 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000644 self.lastline = lineno
645 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000646
647 def getCode(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000648 return ''.join(self.code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000649
650 def getTable(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000651 return ''.join(map(chr, self.lnotab))
Tim Peterse0c446b2001-10-18 21:57:37 +0000652
Jeremy Hyltona5058122000-02-14 14:14:29 +0000653class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000654 # XXX 1. need to keep track of stack depth on jumps
655 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000656
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000657 def findDepth(self, insts, debug=0):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000658 depth = 0
659 maxDepth = 0
660 for i in insts:
661 opname = i[0]
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000662 if debug:
663 print i,
664 delta = self.effect.get(opname, None)
665 if delta is not None:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000666 depth = depth + delta
667 else:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000668 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000669 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000670 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000671 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000672 depth = depth + delta
673 break
674 # if we still haven't found a match
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000675 if delta is None:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000676 meth = getattr(self, opname, None)
677 if meth is not None:
678 depth = depth + meth(i[1])
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000679 if depth > maxDepth:
680 maxDepth = depth
681 if debug:
682 print depth, maxDepth
Jeremy Hylton772dd412000-02-21 22:46:00 +0000683 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000684
685 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000686 'POP_TOP': -1,
687 'DUP_TOP': 1,
Alexandre Vassalottib6465472010-01-11 22:36:12 +0000688 'LIST_APPEND': -1,
689 'SET_ADD': -1,
690 'MAP_ADD': -2,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000691 'SLICE+1': -1,
692 'SLICE+2': -1,
693 'SLICE+3': -2,
694 'STORE_SLICE+0': -1,
695 'STORE_SLICE+1': -2,
696 'STORE_SLICE+2': -2,
697 'STORE_SLICE+3': -3,
698 'DELETE_SLICE+0': -1,
699 'DELETE_SLICE+1': -2,
700 'DELETE_SLICE+2': -2,
701 'DELETE_SLICE+3': -3,
702 'STORE_SUBSCR': -3,
703 'DELETE_SUBSCR': -2,
704 # PRINT_EXPR?
705 'PRINT_ITEM': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000706 'RETURN_VALUE': -1,
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000707 'YIELD_VALUE': -1,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000708 'EXEC_STMT': -3,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000709 'BUILD_CLASS': -2,
710 'STORE_NAME': -1,
711 'STORE_ATTR': -2,
712 'DELETE_ATTR': -1,
713 'STORE_GLOBAL': -1,
714 'BUILD_MAP': 1,
715 'COMPARE_OP': -1,
716 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000717 'IMPORT_STAR': -1,
Thomas Woutersfa0cf4f2006-03-03 18:16:20 +0000718 'IMPORT_NAME': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000719 'IMPORT_FROM': 1,
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000720 'LOAD_ATTR': 0, # unlike other loads
Jeremy Hylton92638482001-08-29 22:27:14 +0000721 # close enough...
722 'SETUP_EXCEPT': 3,
723 'SETUP_FINALLY': 3,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000724 'FOR_ITER': 1,
Guido van Rossumf6694362006-03-10 02:28:35 +0000725 'WITH_CLEANUP': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000726 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000727 # use pattern match
728 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000729 ('BINARY_', -1),
730 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000731 ]
Tim Peterse0c446b2001-10-18 21:57:37 +0000732
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000733 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000734 return count-1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000735 def BUILD_TUPLE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000736 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000737 def BUILD_LIST(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000738 return -count+1
Alexandre Vassalottiee936a22010-01-09 23:35:54 +0000739 def BUILD_SET(self, count):
740 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000741 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000742 hi, lo = divmod(argc, 256)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000743 return -(lo + hi * 2)
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000744 def CALL_FUNCTION_VAR(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000745 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000746 def CALL_FUNCTION_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000747 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000748 def CALL_FUNCTION_VAR_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000749 return self.CALL_FUNCTION(argc)-2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000750 def MAKE_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000751 return -argc
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000752 def MAKE_CLOSURE(self, argc):
753 # XXX need to account for free variables too!
754 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000755 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000756 if argc == 2:
757 return -1
758 elif argc == 3:
759 return -2
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000760 def DUP_TOPX(self, argc):
761 return argc
Tim Peterse0c446b2001-10-18 21:57:37 +0000762
Jeremy Hyltona5058122000-02-14 14:14:29 +0000763findDepth = StackDepthTracker().findDepth