blob: dcc8bc08fa8609a84dbdb214774da58d7d9f5e97 [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 Hylton36cc6a22000-03-16 20:06:59 +00006import types
Jeremy Hyltona5058122000-02-14 14:14:29 +00007
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00008from compiler import misc
9
10class FlowGraph:
11 def __init__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000012 self.current = self.entry = Block()
13 self.exit = Block("exit")
14 self.blocks = misc.Set()
15 self.blocks.add(self.entry)
16 self.blocks.add(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000017
18 def startBlock(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000019 self.current = block
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000020
21 def nextBlock(self, block=None):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000022 if block is None:
23 block = self.newBlock()
24 # XXX think we need to specify when there is implicit transfer
25 # from one block to the next
26 #
27 # I think this strategy works: each block has a child
28 # designated as "next" which is returned as the last of the
29 # children. because the nodes in a graph are emitted in
30 # reverse post order, the "next" block will always be emitted
31 # immediately after its parent.
32 # Worry: maintaining this invariant could be tricky
33 self.current.addNext(block)
34 self.startBlock(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000035
36 def newBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000037 b = Block()
38 self.blocks.add(b)
39 return b
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000040
41 def startExitBlock(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000042 self.startBlock(self.exit)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000043
44 def emit(self, *inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000045 # XXX should jump instructions implicitly call nextBlock?
46 if inst[0] == 'RETURN_VALUE':
47 self.current.addOutEdge(self.exit)
48 self.current.emit(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000049
50 def getBlocks(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000051 """Return the blocks in reverse postorder
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000052
Thomas Wouters46cc7c02000-08-12 20:32:46 +000053 i.e. each node appears before all of its successors
54 """
55 # XXX make sure every node that doesn't have an explicit next
56 # is set so that next points to exit
57 for b in self.blocks.elements():
58 if b is self.exit:
59 continue
60 if not b.next:
61 b.addNext(self.exit)
62 order = dfs_postorder(self.entry, {})
63 order.reverse()
64 # hack alert
65 if not self.exit in order:
66 order.append(self.exit)
67 return order
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000068
69def dfs_postorder(b, seen):
70 """Depth-first search of tree rooted at b, return in postorder"""
71 order = []
72 seen[b] = b
73 for c in b.children():
Thomas Wouters46cc7c02000-08-12 20:32:46 +000074 if seen.has_key(c):
75 continue
76 order = order + dfs_postorder(c, seen)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000077 order.append(b)
78 return order
79
80class Block:
81 _count = 0
82
83 def __init__(self, label=''):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000084 self.insts = []
85 self.inEdges = misc.Set()
86 self.outEdges = misc.Set()
87 self.label = label
88 self.bid = Block._count
89 self.next = []
90 Block._count = Block._count + 1
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000091
92 def __repr__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +000093 if self.label:
94 return "<block %s id=%d len=%d>" % (self.label, self.bid,
95 len(self.insts))
96 else:
97 return "<block id=%d len=%d>" % (self.bid, len(self.insts))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000098
99 def __str__(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000100 insts = map(str, self.insts)
101 return "<block %s %d:\n%s>" % (self.label, self.bid,
102 string.join(insts, '\n'))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000103
104 def emit(self, inst):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000105 op = inst[0]
106 if op[:4] == 'JUMP':
107 self.outEdges.add(inst[1])
108 self.insts.append(inst)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000109
110 def getInstructions(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000111 return self.insts
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000112
113 def addInEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000114 self.inEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000115
116 def addOutEdge(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000117 self.outEdges.add(block)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000118
119 def addNext(self, block):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000120 self.next.append(block)
121 assert len(self.next) == 1, map(str, self.next)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000122
123 def children(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000124 return self.outEdges.elements() + self.next
Jeremy Hyltona5058122000-02-14 14:14:29 +0000125
126# flags for code objects
127CO_OPTIMIZED = 0x0001
128CO_NEWLOCALS = 0x0002
129CO_VARARGS = 0x0004
130CO_VARKEYWORDS = 0x0008
131
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000132# the FlowGraph is transformed in place; it exists in one of these states
133RAW = "RAW"
134FLAT = "FLAT"
135CONV = "CONV"
136DONE = "DONE"
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000137
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000138class PyFlowGraph(FlowGraph):
139 super_init = FlowGraph.__init__
Jeremy Hyltona5058122000-02-14 14:14:29 +0000140
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000141 def __init__(self, name, filename, args=(), optimized=0):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000142 self.super_init()
143 self.name = name
144 self.filename = filename
145 self.docstring = None
146 self.args = args # XXX
147 self.argcount = getArgCount(args)
148 if optimized:
149 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
150 else:
151 self.flags = 0
152 self.consts = []
153 self.names = []
Jeremy Hyltona5058122000-02-14 14:14:29 +0000154 self.varnames = list(args) or []
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000155 for i in range(len(self.varnames)):
156 var = self.varnames[i]
157 if isinstance(var, TupleArg):
158 self.varnames[i] = var.getName()
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000159 self.stage = RAW
Jeremy Hyltona5058122000-02-14 14:14:29 +0000160
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000161 def setDocstring(self, doc):
162 self.docstring = doc
163 self.consts.insert(0, doc)
Jeremy Hylton2ce27b22000-02-16 00:50:29 +0000164
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000165 def setFlag(self, flag):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000166 self.flags = self.flags | flag
167 if flag == CO_VARARGS:
168 self.argcount = self.argcount - 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000169
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000170 def getCode(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000171 """Get a Python code object"""
172 if self.stage == RAW:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000173 self.flattenGraph()
174 if self.stage == FLAT:
175 self.convertArgs()
176 if self.stage == CONV:
177 self.makeByteCode()
178 if self.stage == DONE:
179 return self.newCodeObject()
180 raise RuntimeError, "inconsistent PyFlowGraph state"
Jeremy Hyltona5058122000-02-14 14:14:29 +0000181
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000182 def dump(self, io=None):
183 if io:
184 save = sys.stdout
185 sys.stdout = io
186 pc = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000187 for t in self.insts:
188 opname = t[0]
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000189 if opname == "SET_LINENO":
190 print
Jeremy Hyltona5058122000-02-14 14:14:29 +0000191 if len(t) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000192 print "\t", "%3d" % pc, opname
193 pc = pc + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000194 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000195 print "\t", "%3d" % pc, opname, t[1]
196 pc = pc + 3
197 if io:
198 sys.stdout = save
Jeremy Hyltona5058122000-02-14 14:14:29 +0000199
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000200 def flattenGraph(self):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000201 """Arrange the blocks in order and resolve jumps"""
202 assert self.stage == RAW
203 self.insts = insts = []
204 pc = 0
205 begin = {}
206 end = {}
207 for b in self.getBlocks():
208 begin[b] = pc
209 for inst in b.getInstructions():
210 insts.append(inst)
211 if len(inst) == 1:
212 pc = pc + 1
213 else:
214 # arg takes 2 bytes
215 pc = pc + 3
216 end[b] = pc
217 pc = 0
218 for i in range(len(insts)):
219 inst = insts[i]
220 if len(inst) == 1:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000221 pc = pc + 1
222 else:
223 pc = pc + 3
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000224 opname = inst[0]
225 if self.hasjrel.has_elt(opname):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000226 oparg = inst[1]
227 offset = begin[oparg] - pc
228 insts[i] = opname, offset
229 elif self.hasjabs.has_elt(opname):
230 insts[i] = opname, begin[inst[1]]
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000231 self.stacksize = findDepth(self.insts)
232 self.stage = FLAT
Jeremy Hyltona5058122000-02-14 14:14:29 +0000233
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000234 hasjrel = misc.Set()
235 for i in dis.hasjrel:
236 hasjrel.add(dis.opname[i])
237 hasjabs = misc.Set()
238 for i in dis.hasjabs:
239 hasjabs.add(dis.opname[i])
Jeremy Hyltona5058122000-02-14 14:14:29 +0000240
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000241 def convertArgs(self):
242 """Convert arguments from symbolic to concrete form"""
243 assert self.stage == FLAT
244 for i in range(len(self.insts)):
245 t = self.insts[i]
246 if len(t) == 2:
247 opname = t[0]
248 oparg = t[1]
249 conv = self._converters.get(opname, None)
250 if conv:
251 self.insts[i] = opname, conv(self, oparg)
252 self.stage = CONV
Jeremy Hyltona5058122000-02-14 14:14:29 +0000253
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000254 def _lookupName(self, name, list):
255 """Return index of name in list, appending if necessary"""
Jeremy Hylton9c048f92000-10-13 21:58:13 +0000256 found = None
257 t = type(name)
258 for i in range(len(list)):
259 # must do a comparison on type first to prevent UnicodeErrors
260 if t == type(list[i]) and list[i] == name:
261 found = 1
262 break
263 if found:
Jeremy Hyltonefd06942000-02-17 22:58:54 +0000264 # this is cheap, but incorrect in some cases, e.g 2 vs. 2L
265 if type(name) == type(list[i]):
266 return i
267 for i in range(len(list)):
268 elt = list[i]
269 if type(elt) == type(name) and elt == name:
270 return i
271 end = len(list)
272 list.append(name)
273 return end
Jeremy Hyltona5058122000-02-14 14:14:29 +0000274
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000275 _converters = {}
276 def _convert_LOAD_CONST(self, arg):
277 return self._lookupName(arg, self.consts)
278
279 def _convert_LOAD_FAST(self, arg):
280 self._lookupName(arg, self.names)
281 return self._lookupName(arg, self.varnames)
282 _convert_STORE_FAST = _convert_LOAD_FAST
283 _convert_DELETE_FAST = _convert_LOAD_FAST
284
285 def _convert_NAME(self, arg):
286 return self._lookupName(arg, self.names)
287 _convert_LOAD_NAME = _convert_NAME
288 _convert_STORE_NAME = _convert_NAME
289 _convert_DELETE_NAME = _convert_NAME
290 _convert_IMPORT_NAME = _convert_NAME
291 _convert_IMPORT_FROM = _convert_NAME
292 _convert_STORE_ATTR = _convert_NAME
293 _convert_LOAD_ATTR = _convert_NAME
294 _convert_DELETE_ATTR = _convert_NAME
295 _convert_LOAD_GLOBAL = _convert_NAME
296 _convert_STORE_GLOBAL = _convert_NAME
297 _convert_DELETE_GLOBAL = _convert_NAME
298
299 _cmp = list(dis.cmp_op)
300 def _convert_COMPARE_OP(self, arg):
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000301 return self._cmp.index(arg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000302
303 # similarly for other opcodes...
304
305 for name, obj in locals().items():
306 if name[:9] == "_convert_":
307 opname = name[9:]
308 _converters[opname] = obj
309 del name, obj, opname
310
311 def makeByteCode(self):
312 assert self.stage == CONV
313 self.lnotab = lnotab = LineAddrTable()
314 for t in self.insts:
315 opname = t[0]
316 if len(t) == 1:
317 lnotab.addCode(self.opnum[opname])
318 else:
319 oparg = t[1]
320 if opname == "SET_LINENO":
321 lnotab.nextLine(oparg)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000322 hi, lo = twobyte(oparg)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000323 try:
324 lnotab.addCode(self.opnum[opname], lo, hi)
325 except ValueError:
326 print opname, oparg
327 print self.opnum[opname], lo, hi
328 raise
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000329 self.stage = DONE
330
Jeremy Hyltona5058122000-02-14 14:14:29 +0000331 opnum = {}
332 for num in range(len(dis.opname)):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000333 opnum[dis.opname[num]] = num
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000334 del num
Jeremy Hyltona5058122000-02-14 14:14:29 +0000335
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000336 def newCodeObject(self):
337 assert self.stage == DONE
338 if self.flags == 0:
339 nlocals = 0
340 else:
341 nlocals = len(self.varnames)
342 argcount = self.argcount
343 if self.flags & CO_VARKEYWORDS:
344 argcount = argcount - 1
345 return new.code(argcount, nlocals, self.stacksize, self.flags,
346 self.lnotab.getCode(), self.getConsts(),
347 tuple(self.names), tuple(self.varnames),
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000348 self.filename, self.name, self.lnotab.firstline,
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000349 self.lnotab.getTable())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000350
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000351 def getConsts(self):
352 """Return a tuple for the const slot of the code object
Jeremy Hyltona5058122000-02-14 14:14:29 +0000353
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000354 Must convert references to code (MAKE_FUNCTION) to code
355 objects recursively.
356 """
357 l = []
358 for elt in self.consts:
359 if isinstance(elt, PyFlowGraph):
360 elt = elt.getCode()
361 l.append(elt)
362 return tuple(l)
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000363
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000364def isJump(opname):
365 if opname[:4] == 'JUMP':
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000366 return 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000367
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000368class TupleArg:
369 """Helper for marking func defs with nested tuples in arglist"""
370 def __init__(self, count, names):
371 self.count = count
372 self.names = names
373 def __repr__(self):
374 return "TupleArg(%s, %s)" % (self.count, self.names)
375 def getName(self):
376 return ".nested%d" % self.count
377
378def getArgCount(args):
379 argcount = len(args)
380 if args:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000381 for arg in args:
382 if isinstance(arg, TupleArg):
383 numNames = len(misc.flatten(arg.names))
384 argcount = argcount - numNames
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000385 return argcount
386
387def twobyte(val):
388 """Convert an int argument into high and low bytes"""
389 assert type(val) == types.IntType
390 return divmod(val, 256)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000391
392class LineAddrTable:
393 """lnotab
394
395 This class builds the lnotab, which is undocumented but described
396 by com_set_lineno in compile.c. Here's an attempt at explanation:
397
398 For each SET_LINENO instruction after the first one, two bytes are
399 added to lnotab. (In some cases, multiple two-byte entries are
400 added.) The first byte is the distance in bytes between the
401 instruction for the last SET_LINENO and the current SET_LINENO.
402 The second byte is offset in line numbers. If either offset is
403 greater than 255, multiple two-byte entries are added -- one entry
404 for each factor of 255.
405 """
406
407 def __init__(self):
408 self.code = []
409 self.codeOffset = 0
410 self.firstline = 0
411 self.lastline = 0
412 self.lastoff = 0
413 self.lnotab = []
414
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000415 def addCode(self, *args):
416 for arg in args:
417 self.code.append(chr(arg))
418 self.codeOffset = self.codeOffset + len(args)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000419
420 def nextLine(self, lineno):
421 if self.firstline == 0:
422 self.firstline = lineno
423 self.lastline = lineno
424 else:
425 # compute deltas
426 addr = self.codeOffset - self.lastoff
427 line = lineno - self.lastline
Jeremy Hylton92f39722000-09-01 20:47:37 +0000428 # Python assumes that lineno always increases with
429 # increasing bytecode address (lnotab is unsigned char).
430 # Depending on when SET_LINENO instructions are emitted
431 # this is not always true. Consider the code:
432 # a = (1,
433 # b)
434 # In the bytecode stream, the assignment to "a" occurs
435 # after the loading of "b". This works with the C Python
436 # compiler because it only generates a SET_LINENO instruction
437 # for the assignment.
438 if line > 0:
439 while addr > 0 or line > 0:
440 # write the values in 1-byte chunks that sum
441 # to desired value
442 trunc_addr = addr
443 trunc_line = line
444 if trunc_addr > 255:
445 trunc_addr = 255
446 if trunc_line > 255:
447 trunc_line = 255
448 self.lnotab.append(trunc_addr)
449 self.lnotab.append(trunc_line)
450 addr = addr - trunc_addr
451 line = line - trunc_line
452 self.lastline = lineno
453 self.lastoff = self.codeOffset
Jeremy Hyltona5058122000-02-14 14:14:29 +0000454
455 def getCode(self):
456 return string.join(self.code, '')
457
458 def getTable(self):
459 return string.join(map(chr, self.lnotab), '')
460
Jeremy Hyltona5058122000-02-14 14:14:29 +0000461class StackDepthTracker:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000462 # XXX 1. need to keep track of stack depth on jumps
463 # XXX 2. at least partly as a result, this code is broken
Jeremy Hyltona5058122000-02-14 14:14:29 +0000464
465 def findDepth(self, insts):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000466 depth = 0
467 maxDepth = 0
468 for i in insts:
469 opname = i[0]
470 delta = self.effect.get(opname, 0)
471 if delta > 1:
472 depth = depth + delta
473 elif delta < 0:
474 if depth > maxDepth:
475 maxDepth = depth
476 depth = depth + delta
477 else:
478 if depth > maxDepth:
479 maxDepth = depth
480 # now check patterns
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000481 for pat, pat_delta in self.patterns:
Jeremy Hylton772dd412000-02-21 22:46:00 +0000482 if opname[:len(pat)] == pat:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000483 delta = pat_delta
Jeremy Hylton772dd412000-02-21 22:46:00 +0000484 depth = depth + delta
485 break
486 # if we still haven't found a match
487 if delta == 0:
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000488 meth = getattr(self, opname, None)
489 if meth is not None:
490 depth = depth + meth(i[1])
Jeremy Hylton772dd412000-02-21 22:46:00 +0000491 if depth < 0:
492 depth = 0
493 return maxDepth
Jeremy Hyltona5058122000-02-14 14:14:29 +0000494
495 effect = {
Jeremy Hylton772dd412000-02-21 22:46:00 +0000496 'POP_TOP': -1,
497 'DUP_TOP': 1,
498 'SLICE+1': -1,
499 'SLICE+2': -1,
500 'SLICE+3': -2,
501 'STORE_SLICE+0': -1,
502 'STORE_SLICE+1': -2,
503 'STORE_SLICE+2': -2,
504 'STORE_SLICE+3': -3,
505 'DELETE_SLICE+0': -1,
506 'DELETE_SLICE+1': -2,
507 'DELETE_SLICE+2': -2,
508 'DELETE_SLICE+3': -3,
509 'STORE_SUBSCR': -3,
510 'DELETE_SUBSCR': -2,
511 # PRINT_EXPR?
512 'PRINT_ITEM': -1,
513 'LOAD_LOCALS': 1,
514 'RETURN_VALUE': -1,
515 'EXEC_STMT': -2,
516 'BUILD_CLASS': -2,
517 'STORE_NAME': -1,
518 'STORE_ATTR': -2,
519 'DELETE_ATTR': -1,
520 'STORE_GLOBAL': -1,
521 'BUILD_MAP': 1,
522 'COMPARE_OP': -1,
523 'STORE_FAST': -1,
Jeremy Hylton4e1be722000-10-12 20:23:23 +0000524 'IMPORT_STAR': -1,
525 'IMPORT_NAME': 0,
526 'IMPORT_FROM': 1,
Jeremy Hylton772dd412000-02-21 22:46:00 +0000527 }
Jeremy Hyltona5058122000-02-14 14:14:29 +0000528 # use pattern match
529 patterns = [
Jeremy Hylton772dd412000-02-21 22:46:00 +0000530 ('BINARY_', -1),
531 ('LOAD_', 1),
Jeremy Hylton772dd412000-02-21 22:46:00 +0000532 ]
Jeremy Hyltonabd7ebf2000-03-06 18:53:14 +0000533
534 # special cases:
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000535 # UNPACK_SEQUENCE, BUILD_TUPLE,
Jeremy Hyltona5058122000-02-14 14:14:29 +0000536 # BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
Thomas Wouters46cc7c02000-08-12 20:32:46 +0000537 def UNPACK_SEQUENCE(self, count):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000538 return count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000539 def BUILD_TUPLE(self, count):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000540 return -count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000541 def BUILD_LIST(self, count):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000542 return -count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000543 def CALL_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000544 hi, lo = divmod(argc, 256)
545 return lo + hi * 2
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000546 def CALL_FUNCTION_VAR(self, argc):
547 return self.CALL_FUNCTION(argc)+1
548 def CALL_FUNCTION_KW(self, argc):
549 return self.CALL_FUNCTION(argc)+1
550 def CALL_FUNCTION_VAR_KW(self, argc):
551 return self.CALL_FUNCTION(argc)+2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000552 def MAKE_FUNCTION(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000553 return -argc
Jeremy Hyltona5058122000-02-14 14:14:29 +0000554 def BUILD_SLICE(self, argc):
Jeremy Hylton772dd412000-02-21 22:46:00 +0000555 if argc == 2:
556 return -1
557 elif argc == 3:
558 return -2
Jeremy Hyltona5058122000-02-14 14:14:29 +0000559
560findDepth = StackDepthTracker().findDepth