blob: 5098f2c1ee9ea8f92dd676d86da23413ded7c5aa [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)
125 # preceeding blocks dominate following blocks
126 for c in b.get_followers():
127 while 1:
128 dominators.setdefault(c, set()).add(b)
129 # Any block that has a next pointer leading to c is also
130 # dominated because the whole chain will be emitted at once.
131 # Walk backwards and add them all.
132 if c.prev and c.prev[0] is not b:
133 c = c.prev[0]
134 else:
135 break
136
137 def find_next():
138 # Find a block that can be emitted next.
139 for b in remaining:
140 for c in dominators[b]:
141 if c in remaining:
142 break # can't emit yet, dominated by a remaining block
143 else:
144 return b
145 assert 0, 'circular dependency, cannot find next block'
146
147 b = start_block
148 while 1:
149 order.append(b)
150 remaining.discard(b)
151 if b.next:
152 b = b.next[0]
153 continue
154 elif b is not exit_block and not b.has_unconditional_transfer():
155 order.append(exit_block)
156 if not remaining:
157 break
158 b = find_next()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000159 return order
160
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000161
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000162class Block:
163 _count = 0
164
165 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000166 self.insts = []
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000167 self.outEdges = set()
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000168 self.label = label
169 self.bid = Block._count
170 self.next = []
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000171 self.prev = []
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000172 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000173
174 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000175 if self.label:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000176 return "<block %s id=%d>" % (self.label, self.bid)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000177 else:
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000178 return "<block id=%d>" % (self.bid)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000179
180 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000181 insts = map(str, self.insts)
182 return "<block %s %d:\n%s>" % (self.label, self.bid,
Neal Norwitza312c3a2002-06-06 18:30:10 +0000183 '\n'.join(insts))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000184
185 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000186 op = inst[0]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000187 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000188
189 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000190 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000191
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000192 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000193 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000194
195 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000196 self.next.append(block)
197 assert len(self.next) == 1, map(str, self.next)
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000198 block.prev.append(self)
199 assert len(block.prev) == 1, map(str, block.prev)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000200
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000201 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
202 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP',
203 )
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000204
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000205 def has_unconditional_transfer(self):
206 """Returns True if there is an unconditional transfer to an other block
207 at the end of this block. This means there is no risk for the bytecode
208 executer to go past this block's bytecode."""
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000209 try:
210 op, arg = self.insts[-1]
211 except (IndexError, ValueError):
212 return
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000213 return op in self._uncond_transfer
Jeremy Hyltoneefaeb72000-11-06 03:47:39 +0000214
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000215 def get_children(self):
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000216 return list(self.outEdges) + self.next
217
218 def get_followers(self):
219 """Get the whole list of followers, including the next block."""
220 followers = set(self.next)
221 # Blocks that must be emitted *after* this one, because of
222 # bytecode offsets (e.g. relative jumps) pointing to them.
223 for inst in self.insts:
224 if inst[0] in PyFlowGraph.hasjrel:
225 followers.add(inst[1])
226 return followers
Jeremy Hyltona5058122000-02-14 14:14:29 +0000227
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000228 def getContainedGraphs(self):
229 """Return all graphs contained within this block.
230
231 For example, a MAKE_FUNCTION block will contain a reference to
232 the graph for the function body.
233 """
234 contained = []
235 for inst in self.insts:
236 if len(inst) == 1:
237 continue
238 op = inst[1]
239 if hasattr(op, 'graph'):
240 contained.append(op.graph)
241 return contained
242
Jeremy Hyltona5058122000-02-14 14:14:29 +0000243# flags for code objects
Jeremy Hyltona5058122000-02-14 14:14:29 +0000244
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000245# the FlowGraph is transformed in place; it exists in one of these states
246RAW = "RAW"
247FLAT = "FLAT"
248CONV = "CONV"
249DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000250
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000251class PyFlowGraph(FlowGraph):
252 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000253
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000254 def __init__(self, name, filename, args=(), optimized=0, klass=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000255 self.super_init()
256 self.name = name
257 self.filename = filename
258 self.docstring = None
259 self.args = args # XXX
260 self.argcount = getArgCount(args)
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000261 self.klass = klass
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000262 if optimized:
Tim Peterse0c446b2001-10-18 21:57:37 +0000263 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000264 else:
265 self.flags = 0
266 self.consts = []
267 self.names = []
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000268 # Free variables found by the symbol table scan, including
269 # variables used only in nested scopes, are included here.
270 self.freevars = []
271 self.cellvars = []
272 # The closure list is used to track the order of cell
273 # variables and free variables in the resulting code object.
274 # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
275 # kinds of variables.
276 self.closure = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000277 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000278 for i in range(len(self.varnames)):
279 var = self.varnames[i]
280 if isinstance(var, TupleArg):
281 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000282 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000283
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000284 def setDocstring(self, doc):
285 self.docstring = doc
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000286
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000287 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000288 self.flags = self.flags | flag
289 if flag == CO_VARARGS:
290 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000291
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000292 def checkFlag(self, flag):
293 if self.flags & flag:
294 return 1
295
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000296 def setFreeVars(self, names):
297 self.freevars = list(names)
298
299 def setCellVars(self, names):
300 self.cellvars = names
301
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000302 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000303 """Get a Python code object"""
Jeremy Hylton3e0055f2005-10-20 19:59:25 +0000304 assert self.stage == RAW
305 self.computeStackDepth()
306 self.flattenGraph()
307 assert self.stage == FLAT
308 self.convertArgs()
309 assert self.stage == CONV
310 self.makeByteCode()
311 assert self.stage == DONE
312 return self.newCodeObject()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000313
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000314 def dump(self, io=None):
315 if io:
316 save = sys.stdout
317 sys.stdout = io
318 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000319 for t in self.insts:
320 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000321 if opname == "SET_LINENO":
322 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000323 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000324 print "\t", "%3d" % pc, opname
325 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000326 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000327 print "\t", "%3d" % pc, opname, t[1]
328 pc = pc + 3
329 if io:
330 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000331
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000332 def computeStackDepth(self):
333 """Compute the max stack depth.
334
335 Approach is to compute the stack effect of each basic block.
336 Then find the path through the code with the largest total
337 effect.
338 """
339 depth = {}
340 exit = None
341 for b in self.getBlocks():
342 depth[b] = findDepth(b.getInstructions())
343
344 seen = {}
345
346 def max_depth(b, d):
Georg Brandl2d2fe572008-12-15 08:58:59 +0000347 if b in seen:
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000348 return d
349 seen[b] = 1
350 d = d + depth[b]
351 children = b.get_children()
352 if children:
353 return max([max_depth(c, d) for c in children])
354 else:
355 if not b.label == "exit":
356 return max_depth(self.exit, d)
357 else:
358 return d
359
360 self.stacksize = max_depth(self.entry, 0)
361
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000362 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000363 """Arrange the blocks in order and resolve jumps"""
364 assert self.stage == RAW
365 self.insts = insts = []
366 pc = 0
367 begin = {}
368 end = {}
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000369 for b in self.getBlocksInOrder():
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000370 begin[b] = pc
371 for inst in b.getInstructions():
372 insts.append(inst)
373 if len(inst) == 1:
374 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000375 elif inst[0] != "SET_LINENO":
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000376 # arg takes 2 bytes
377 pc = pc + 3
378 end[b] = pc
379 pc = 0
380 for i in range(len(insts)):
381 inst = insts[i]
382 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000383 pc = pc + 1
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000384 elif inst[0] != "SET_LINENO":
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000385 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000386 opname = inst[0]
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000387 if opname in self.hasjrel:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000388 oparg = inst[1]
389 offset = begin[oparg] - pc
390 insts[i] = opname, offset
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000391 elif opname in self.hasjabs:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000392 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000393 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000394
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000395 hasjrel = set()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000396 for i in dis.hasjrel:
397 hasjrel.add(dis.opname[i])
Neil Schemenauer4db626f2009-02-06 21:08:52 +0000398 hasjabs = set()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000399 for i in dis.hasjabs:
400 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000401
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000402 def convertArgs(self):
403 """Convert arguments from symbolic to concrete form"""
404 assert self.stage == FLAT
Jeremy Hylton5af105e2001-04-11 16:21:51 +0000405 self.consts.insert(0, self.docstring)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000406 self.sort_cellvars()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000407 for i in range(len(self.insts)):
408 t = self.insts[i]
409 if len(t) == 2:
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000410 opname, oparg = t
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000411 conv = self._converters.get(opname, None)
412 if conv:
413 self.insts[i] = opname, conv(self, oparg)
414 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000415
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000416 def sort_cellvars(self):
417 """Sort cellvars in the order of varnames and prune from freevars.
418 """
419 cells = {}
420 for name in self.cellvars:
421 cells[name] = 1
422 self.cellvars = [name for name in self.varnames
Georg Brandl2d2fe572008-12-15 08:58:59 +0000423 if name in cells]
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000424 for name in self.cellvars:
425 del cells[name]
426 self.cellvars = self.cellvars + cells.keys()
427 self.closure = self.cellvars + self.freevars
428
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000429 def _lookupName(self, name, list):
430 """Return index of name in list, appending if necessary
Jeremy Hyltone4e9cd42001-08-29 18:09:50 +0000431
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000432 This routine uses a list instead of a dictionary, because a
433 dictionary can't store two different keys if the keys have the
434 same value but different types, e.g. 2 and 2L. The compiler
435 must treat these two separately, so it does an explicit type
436 comparison before comparing the values.
437 """
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000438 t = type(name)
439 for i in range(len(list)):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000440 if t == type(list[i]) and list[i] == name:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000441 return i
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000442 end = len(list)
443 list.append(name)
444 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000445
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000446 _converters = {}
447 def _convert_LOAD_CONST(self, arg):
Jeremy Hylton314e3fb2000-11-06 03:43:11 +0000448 if hasattr(arg, 'getCode'):
449 arg = arg.getCode()
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000450 return self._lookupName(arg, self.consts)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000451
452 def _convert_LOAD_FAST(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000453 self._lookupName(arg, self.names)
454 return self._lookupName(arg, self.varnames)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000455 _convert_STORE_FAST = _convert_LOAD_FAST
456 _convert_DELETE_FAST = _convert_LOAD_FAST
457
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000458 def _convert_LOAD_NAME(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000459 if self.klass is None:
460 self._lookupName(arg, self.varnames)
461 return self._lookupName(arg, self.names)
Jeremy Hylton63db7b92001-08-28 16:36:12 +0000462
463 def _convert_NAME(self, arg):
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000464 if self.klass is None:
465 self._lookupName(arg, self.varnames)
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000466 return self._lookupName(arg, self.names)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000467 _convert_STORE_NAME = _convert_NAME
468 _convert_DELETE_NAME = _convert_NAME
469 _convert_IMPORT_NAME = _convert_NAME
470 _convert_IMPORT_FROM = _convert_NAME
471 _convert_STORE_ATTR = _convert_NAME
472 _convert_LOAD_ATTR = _convert_NAME
473 _convert_DELETE_ATTR = _convert_NAME
474 _convert_LOAD_GLOBAL = _convert_NAME
475 _convert_STORE_GLOBAL = _convert_NAME
476 _convert_DELETE_GLOBAL = _convert_NAME
477
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000478 def _convert_DEREF(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000479 self._lookupName(arg, self.names)
480 self._lookupName(arg, self.varnames)
481 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000482 _convert_LOAD_DEREF = _convert_DEREF
483 _convert_STORE_DEREF = _convert_DEREF
484
485 def _convert_LOAD_CLOSURE(self, arg):
Jeremy Hyltonbf77c462001-08-29 19:45:33 +0000486 self._lookupName(arg, self.varnames)
487 return self._lookupName(arg, self.closure)
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000488
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000489 _cmp = list(dis.cmp_op)
490 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000491 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000492
493 # similarly for other opcodes...
494
495 for name, obj in locals().items():
496 if name[:9] == "_convert_":
497 opname = name[9:]
Tim Peterse0c446b2001-10-18 21:57:37 +0000498 _converters[opname] = obj
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000499 del name, obj, opname
500
501 def makeByteCode(self):
502 assert self.stage == CONV
503 self.lnotab = lnotab = LineAddrTable()
504 for t in self.insts:
505 opname = t[0]
506 if len(t) == 1:
507 lnotab.addCode(self.opnum[opname])
508 else:
509 oparg = t[1]
510 if opname == "SET_LINENO":
511 lnotab.nextLine(oparg)
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000512 continue
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000513 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000514 try:
515 lnotab.addCode(self.opnum[opname], lo, hi)
516 except ValueError:
517 print opname, oparg
518 print self.opnum[opname], lo, hi
519 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000520 self.stage = DONE
521
Jeremy Hyltona5058122000-02-14 14:14:29 +0000522 opnum = {}
523 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000524 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000525 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000526
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000527 def newCodeObject(self):
528 assert self.stage == DONE
Jeremy Hylton1e99a772001-09-14 22:49:08 +0000529 if (self.flags & CO_NEWLOCALS) == 0:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000530 nlocals = 0
531 else:
532 nlocals = len(self.varnames)
533 argcount = self.argcount
534 if self.flags & CO_VARKEYWORDS:
535 argcount = argcount - 1
Christian Heimesc756d002007-11-27 21:34:01 +0000536 return types.CodeType(argcount, nlocals, self.stacksize, self.flags,
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000537 self.lnotab.getCode(), self.getConsts(),
538 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000539 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton364f9b92001-04-12 06:40:42 +0000540 self.lnotab.getTable(), tuple(self.freevars),
541 tuple(self.cellvars))
Jeremy Hyltona5058122000-02-14 14:14:29 +0000542
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000543 def getConsts(self):
544 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000545
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000546 Must convert references to code (MAKE_FUNCTION) to code
547 objects recursively.
548 """
549 l = []
550 for elt in self.consts:
551 if isinstance(elt, PyFlowGraph):
552 elt = elt.getCode()
553 l.append(elt)
554 return tuple(l)
Tim Peterse0c446b2001-10-18 21:57:37 +0000555
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000556def isJump(opname):
557 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000558 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000559
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000560class TupleArg:
561 """Helper for marking func defs with nested tuples in arglist"""
562 def __init__(self, count, names):
563 self.count = count
564 self.names = names
565 def __repr__(self):
566 return "TupleArg(%s, %s)" % (self.count, self.names)
567 def getName(self):
Jeremy Hyltonbfb0cf82001-04-12 17:33:34 +0000568 return ".%d" % self.count
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000569
570def getArgCount(args):
571 argcount = len(args)
572 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000573 for arg in args:
574 if isinstance(arg, TupleArg):
575 numNames = len(misc.flatten(arg.names))
576 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000577 return argcount
578
579def twobyte(val):
580 """Convert an int argument into high and low bytes"""
Neal Norwitzd752f7d2005-11-25 03:17:59 +0000581 assert isinstance(val, int)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000582 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000583
584class LineAddrTable:
585 """lnotab
Tim Peterse0c446b2001-10-18 21:57:37 +0000586
Tim Peters2a7f3842001-06-09 09:26:21 +0000587 This class builds the lnotab, which is documented in compile.c.
588 Here's a brief recap:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000589
590 For each SET_LINENO instruction after the first one, two bytes are
591 added to lnotab. (In some cases, multiple two-byte entries are
592 added.) The first byte is the distance in bytes between the
593 instruction for the last SET_LINENO and the current SET_LINENO.
594 The second byte is offset in line numbers. If either offset is
Tim Peters2a7f3842001-06-09 09:26:21 +0000595 greater than 255, multiple two-byte entries are added -- see
596 compile.c for the delicate details.
Jeremy Hyltona5058122000-02-14 14:14:29 +0000597 """
598
599 def __init__(self):
600 self.code = []
601 self.codeOffset = 0
602 self.firstline = 0
603 self.lastline = 0
604 self.lastoff = 0
605 self.lnotab = []
606
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000607 def addCode(self, *args):
608 for arg in args:
609 self.code.append(chr(arg))
610 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000611
612 def nextLine(self, lineno):
613 if self.firstline == 0:
614 self.firstline = lineno
615 self.lastline = lineno
616 else:
617 # compute deltas
618 addr = self.codeOffset - self.lastoff
619 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000620 # Python assumes that lineno always increases with
621 # increasing bytecode address (lnotab is unsigned char).
622 # Depending on when SET_LINENO instructions are emitted
623 # this is not always true. Consider the code:
624 # a = (1,
625 # b)
626 # In the bytecode stream, the assignment to "a" occurs
627 # after the loading of "b". This works with the C Python
628 # compiler because it only generates a SET_LINENO instruction
629 # for the assignment.
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000630 if line >= 0:
Tim Peters2a7f3842001-06-09 09:26:21 +0000631 push = self.lnotab.append
632 while addr > 255:
633 push(255); push(0)
634 addr -= 255
635 while line > 255:
636 push(addr); push(255)
637 line -= 255
638 addr = 0
639 if addr > 0 or line > 0:
640 push(addr); push(line)
Jeremy Hylton92f39722000-09-01 20:47:37 +0000641 self.lastline = lineno
642 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000643
644 def getCode(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000645 return ''.join(self.code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000646
647 def getTable(self):
Neal Norwitza312c3a2002-06-06 18:30:10 +0000648 return ''.join(map(chr, self.lnotab))
Tim Peterse0c446b2001-10-18 21:57:37 +0000649
Jeremy Hyltona5058122000-02-14 14:14:29 +0000650class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000651 # XXX 1. need to keep track of stack depth on jumps
652 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000653
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000654 def findDepth(self, insts, debug=0):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000655 depth = 0
656 maxDepth = 0
657 for i in insts:
658 opname = i[0]
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000659 if debug:
660 print i,
661 delta = self.effect.get(opname, None)
662 if delta is not None:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000663 depth = depth + delta
664 else:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000665 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000666 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000667 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000668 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000669 depth = depth + delta
670 break
671 # if we still haven't found a match
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000672 if delta is None:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000673 meth = getattr(self, opname, None)
674 if meth is not None:
675 depth = depth + meth(i[1])
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000676 if depth > maxDepth:
677 maxDepth = depth
678 if debug:
679 print depth, maxDepth
Jeremy Hylton772dd412000-02-21 22:46:00 +0000680 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000681
682 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000683 'POP_TOP': -1,
684 'DUP_TOP': 1,
Neal Norwitz10be2ea2006-03-03 20:29:11 +0000685 'LIST_APPEND': -2,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000686 'SLICE+1': -1,
687 'SLICE+2': -1,
688 'SLICE+3': -2,
689 'STORE_SLICE+0': -1,
690 'STORE_SLICE+1': -2,
691 'STORE_SLICE+2': -2,
692 'STORE_SLICE+3': -3,
693 'DELETE_SLICE+0': -1,
694 'DELETE_SLICE+1': -2,
695 'DELETE_SLICE+2': -2,
696 'DELETE_SLICE+3': -3,
697 'STORE_SUBSCR': -3,
698 'DELETE_SUBSCR': -2,
699 # PRINT_EXPR?
700 'PRINT_ITEM': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000701 'RETURN_VALUE': -1,
Jeremy Hyltonaccb62b2002-12-31 18:17:44 +0000702 'YIELD_VALUE': -1,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000703 'EXEC_STMT': -3,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000704 'BUILD_CLASS': -2,
705 'STORE_NAME': -1,
706 'STORE_ATTR': -2,
707 'DELETE_ATTR': -1,
708 'STORE_GLOBAL': -1,
709 'BUILD_MAP': 1,
710 'COMPARE_OP': -1,
711 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000712 'IMPORT_STAR': -1,
Thomas Woutersfa0cf4f2006-03-03 18:16:20 +0000713 'IMPORT_NAME': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000714 'IMPORT_FROM': 1,
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000715 'LOAD_ATTR': 0, # unlike other loads
Jeremy Hylton92638482001-08-29 22:27:14 +0000716 # close enough...
717 'SETUP_EXCEPT': 3,
718 'SETUP_FINALLY': 3,
Jeremy Hylton71ebc332001-08-30 20:25:55 +0000719 'FOR_ITER': 1,
Guido van Rossumf6694362006-03-10 02:28:35 +0000720 'WITH_CLEANUP': -1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000721 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000722 # use pattern match
723 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000724 ('BINARY_', -1),
725 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000726 ]
Tim Peterse0c446b2001-10-18 21:57:37 +0000727
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000728 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000729 return count-1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000730 def BUILD_TUPLE(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000731 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000732 def BUILD_LIST(self, count):
Jeremy Hylton4ba90012001-08-29 20:55:17 +0000733 return -count+1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000734 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000735 hi, lo = divmod(argc, 256)
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000736 return -(lo + hi * 2)
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000737 def CALL_FUNCTION_VAR(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000738 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000739 def CALL_FUNCTION_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000740 return self.CALL_FUNCTION(argc)-1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000741 def CALL_FUNCTION_VAR_KW(self, argc):
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000742 return self.CALL_FUNCTION(argc)-2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000743 def MAKE_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000744 return -argc
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000745 def MAKE_CLOSURE(self, argc):
746 # XXX need to account for free variables too!
747 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000748 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000749 if argc == 2:
750 return -1
751 elif argc == 3:
752 return -2
Jeremy Hylton138d90e2001-10-17 13:37:29 +0000753 def DUP_TOPX(self, argc):
754 return argc
Tim Peterse0c446b2001-10-18 21:57:37 +0000755
Jeremy Hyltona5058122000-02-14 14:14:29 +0000756findDepth = StackDepthTracker().findDepth