ยปCore Development>Code coverage>Lib/compiler/pyassem.py

Python code coverage for Lib/compiler/pyassem.py

#countcontent
12"""A flow graph representation for Python bytecode"""
2n/a
32import dis
42import types
52import sys
6n/a
72from compiler import misc
82from compiler.consts \
9n/a import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
10n/a
114class FlowGraph:
122 def __init__(self):
131059 self.current = self.entry = Block()
141059 self.exit = Block("exit")
151059 self.blocks = misc.Set()
161059 self.blocks.add(self.entry)
171059 self.blocks.add(self.exit)
18n/a
192 def startBlock(self, block):
202627 if self._debug:
210 if self.current:
220 print "end", repr(self.current)
230 print " next", self.current.next
240 print " prev", self.current.prev
250 print " ", self.current.get_children()
260 print repr(block)
272627 self.current = block
28n/a
292 def nextBlock(self, block=None):
30n/a # XXX think we need to specify when there is implicit transfer
31n/a # from one block to the next. might be better to represent this
32n/a # with explicit JUMP_ABSOLUTE instructions that are optimized
33n/a # out when they are unnecessary.
34n/a #
35n/a # I think this strategy works: each block has a child
36n/a # designated as "next" which is returned as the last of the
37n/a # children. because the nodes in a graph are emitted in
38n/a # reverse post order, the "next" block will always be emitted
39n/a # immediately after its parent.
40n/a # Worry: maintaining this invariant could be tricky
411312 if block is None:
42315 block = self.newBlock()
43n/a
44n/a # Note: If the current block ends with an unconditional control
45n/a # transfer, then it is techically incorrect to add an implicit
46n/a # transfer to the block graph. Doing so results in code generation
47n/a # for unreachable blocks. That doesn't appear to be very common
48n/a # with Python code and since the built-in compiler doesn't optimize
49n/a # it out we don't either.
501312 self.current.addNext(block)
511312 self.startBlock(block)
52n/a
532 def newBlock(self):
541838 b = Block()
551838 self.blocks.add(b)
561838 return b
57n/a
582 def startExitBlock(self):
591028 self.startBlock(self.exit)
60n/a
612 _debug = 0
62n/a
632 def _enable_debug(self):
640 self._debug = 1
65n/a
662 def _disable_debug(self):
670 self._debug = 0
68n/a
692 def emit(self, *inst):
7037535 if self._debug:
710 print "\t", inst
7237535 if len(inst) == 2 and isinstance(inst[1], Block):
731173 self.current.addOutEdge(inst[1])
7437535 self.current.emit(inst)
75n/a
762 def getBlocksInOrder(self):
77n/a """Return the blocks in reverse postorder
78n/a
79n/a i.e. each node appears before all of its successors
80n/a """
811059 order = order_blocks(self.entry, self.exit)
821059 return order
83n/a
842 def getBlocks(self):
851059 return self.blocks.elements()
86n/a
872 def getRoot(self):
88n/a """Return nodes appropriate for use with dominator"""
890 return self.entry
90n/a
912 def getContainedGraphs(self):
920 l = []
930 for b in self.getBlocks():
940 l.extend(b.getContainedGraphs())
950 return l
96n/a
97n/a
982def order_blocks(start_block, exit_block):
99n/a """Order blocks so that they are emitted in the right order"""
100n/a # Rules:
101n/a # - when a block has a next block, the next block must be emitted just after
102n/a # - when a block has followers (relative jumps), it must be emitted before
103n/a # them
104n/a # - all reachable blocks must be emitted
1051059 order = []
106n/a
107n/a # Find all the blocks to be emitted.
1081059 remaining = set()
1091059 todo = [start_block]
1104089 while todo:
1113030 b = todo.pop()
1123030 if b in remaining:
113372 continue
1142658 remaining.add(b)
1155143 for c in b.get_children():
1162485 if c not in remaining:
1171971 todo.append(c)
118n/a
119n/a # A block is dominated by another block if that block must be emitted
120n/a # before it.
1211059 dominators = {}
1223717 for b in remaining:
1232658 if __debug__ and b.next:
1241312 assert b is b.next[0].prev[0], (b, b.next)
125n/a # Make sure every block appears in dominators, even if no
126n/a # other block must precede it.
1272658 dominators.setdefault(b, set())
128n/a # preceeding blocks dominate following blocks
1294677 for c in b.get_followers():
1302019 while 1:
1313292 dominators.setdefault(c, set()).add(b)
132n/a # Any block that has a next pointer leading to c is also
133n/a # dominated because the whole chain will be emitted at once.
134n/a # Walk backwards and add them all.
1353292 if c.prev and c.prev[0] is not b:
1361273 c = c.prev[0]
137n/a else:
1382019 break
139n/a
1401059 def find_next():
141n/a # Find a block that can be emitted next.
1421496 for b in remaining:
1432181 for c in dominators[b]:
1441894 if c in remaining:
1451209 break # can't emit yet, dominated by a remaining block
146n/a else:
147287 return b
1480 assert 0, 'circular dependency, cannot find next block'
149n/a
1501059 b = start_block
1511059 while 1:
1522658 order.append(b)
1532658 remaining.discard(b)
1542658 if b.next:
1551312 b = b.next[0]
1561312 continue
1571346 elif b is not exit_block and not b.has_unconditional_transfer():
1581042 order.append(exit_block)
1591346 if not remaining:
1601059 break
161287 b = find_next()
1621059 return order
163n/a
164n/a
1654class Block:
1662 _count = 0
167n/a
1682 def __init__(self, label=''):
1693956 self.insts = []
1703956 self.outEdges = set()
1713956 self.label = label
1723956 self.bid = Block._count
1733956 self.next = []
1743956 self.prev = []
1753956 Block._count = Block._count + 1
176n/a
1772 def __repr__(self):
1780 if self.label:
1790 return "<block %s id=%d>" % (self.label, self.bid)
180n/a else:
1810 return "<block id=%d>" % (self.bid)
182n/a
1832 def __str__(self):
1840 insts = map(str, self.insts)
1850 return "<block %s %d:\n%s>" % (self.label, self.bid,
1860 '\n'.join(insts))
187n/a
1882 def emit(self, inst):
18937535 op = inst[0]
19037535 self.insts.append(inst)
191n/a
1922 def getInstructions(self):
1937656 return self.insts
194n/a
1952 def addOutEdge(self, block):
1961173 self.outEdges.add(block)
197n/a
1982 def addNext(self, block):
1991312 self.next.append(block)
2001312 assert len(self.next) == 1, map(str, self.next)
2011312 block.prev.append(self)
2021312 assert len(block.prev) == 1, map(str, block.prev)
203n/a
2040 _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',
2052 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP',
206n/a )
207n/a
2082 def has_unconditional_transfer(self):
209n/a """Returns True if there is an unconditional transfer to an other block
210n/a at the end of this block. This means there is no risk for the bytecode
211n/a executer to go past this block's bytecode."""
2121346 try:
2131346 op, arg = self.insts[-1]
214535 except (IndexError, ValueError):
215535 return
216811 return op in self._uncond_transfer
217n/a
2182 def get_children(self):
2196375 return list(self.outEdges) + self.next
220n/a
2212 def get_followers(self):
222n/a """Get the whole list of followers, including the next block."""
2232658 followers = set(self.next)
224n/a # Blocks that must be emitted *after* this one, because of
225n/a # bytecode offsets (e.g. relative jumps) pointing to them.
22638157 for inst in self.insts:
22735499 if inst[0] in PyFlowGraph.hasjrel:
228756 followers.add(inst[1])
2292658 return followers
230n/a
2312 def getContainedGraphs(self):
232n/a """Return all graphs contained within this block.
233n/a
234n/a For example, a MAKE_FUNCTION block will contain a reference to
235n/a the graph for the function body.
236n/a """
2370 contained = []
2380 for inst in self.insts:
2390 if len(inst) == 1:
2400 continue
2410 op = inst[1]
2420 if hasattr(op, 'graph'):
2430 contained.append(op.graph)
2440 return contained
245n/a
246n/a# flags for code objects
247n/a
248n/a# the FlowGraph is transformed in place; it exists in one of these states
2492RAW = "RAW"
2502FLAT = "FLAT"
2512CONV = "CONV"
2522DONE = "DONE"
253n/a
2544class PyFlowGraph(FlowGraph):
2552 super_init = FlowGraph.__init__
256n/a
2572 def __init__(self, name, filename, args=(), optimized=0, klass=None):
2581059 self.super_init()
2591059 self.name = name
2601059 self.filename = filename
2611059 self.docstring = None
2621059 self.args = args # XXX
2631059 self.argcount = getArgCount(args)
2641059 self.klass = klass
2651059 if optimized:
266637 self.flags = CO_OPTIMIZED | CO_NEWLOCALS
267n/a else:
268422 self.flags = 0
2691059 self.consts = []
2701059 self.names = []
271n/a # Free variables found by the symbol table scan, including
272n/a # variables used only in nested scopes, are included here.
2731059 self.freevars = []
2741059 self.cellvars = []
275n/a # The closure list is used to track the order of cell
276n/a # variables and free variables in the resulting code object.
277n/a # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
278n/a # kinds of variables.
2791059 self.closure = []
2801059 self.varnames = list(args) or []
2812004 for i in range(len(self.varnames)):
282945 var = self.varnames[i]
283945 if isinstance(var, TupleArg):
2840 self.varnames[i] = var.getName()
2851059 self.stage = RAW
286n/a
2872 def setDocstring(self, doc):
28849 self.docstring = doc
289n/a
2902 def setFlag(self, flag):
291430 self.flags = self.flags | flag
292430 if flag == CO_VARARGS:
29324 self.argcount = self.argcount - 1
294n/a
2952 def checkFlag(self, flag):
29663 if self.flags & flag:
2970 return 1
298n/a
2992 def setFreeVars(self, names):
3001028 self.freevars = list(names)
301n/a
3022 def setCellVars(self, names):
3031028 self.cellvars = names
304n/a
3052 def getCode(self):
306n/a """Get a Python code object"""
3071059 assert self.stage == RAW
3081059 self.computeStackDepth()
3091059 self.flattenGraph()
3101059 assert self.stage == FLAT
3111059 self.convertArgs()
3121059 assert self.stage == CONV
3131059 self.makeByteCode()
3141059 assert self.stage == DONE
3151059 return self.newCodeObject()
316n/a
3172 def dump(self, io=None):
3180 if io:
3190 save = sys.stdout
3200 sys.stdout = io
3210 pc = 0
3220 for t in self.insts:
3230 opname = t[0]
3240 if opname == "SET_LINENO":
3250 print
3260 if len(t) == 1:
3270 print "\t", "%3d" % pc, opname
3280 pc = pc + 1
329n/a else:
3300 print "\t", "%3d" % pc, opname, t[1]
3310 pc = pc + 3
3320 if io:
3330 sys.stdout = save
334n/a
3352 def computeStackDepth(self):
336n/a """Compute the max stack depth.
337n/a
338n/a Approach is to compute the stack effect of each basic block.
339n/a Then find the path through the code with the largest total
340n/a effect.
341n/a """
3421059 depth = {}
3431059 exit = None
3445015 for b in self.getBlocks():
3453956 depth[b] = findDepth(b.getInstructions())
346n/a
3471059 seen = {}
348n/a
3491059 def max_depth(b, d):
3504603 if b in seen:
351886 return d
3523717 seen[b] = 1
3533717 d = d + depth[b]
3543717 children = b.get_children()
3553717 if children:
3564084 return max([max_depth(c, d) for c in children])
357n/a else:
3582118 if not b.label == "exit":
3591059 return max_depth(self.exit, d)
360n/a else:
3611059 return d
362n/a
3631059 self.stacksize = max_depth(self.entry, 0)
364n/a
3652 def flattenGraph(self):
366n/a """Arrange the blocks in order and resolve jumps"""
3671059 assert self.stage == RAW
3681059 self.insts = insts = []
3691059 pc = 0
3701059 begin = {}
3711059 end = {}
3724759 for b in self.getBlocksInOrder():
3733700 begin[b] = pc
37441201 for inst in b.getInstructions():
37537501 insts.append(inst)
37637501 if len(inst) == 1:
3775726 pc = pc + 1
37831775 elif inst[0] != "SET_LINENO":
379n/a # arg takes 2 bytes
38025682 pc = pc + 3
3813700 end[b] = pc
3821059 pc = 0
38338560 for i in range(len(insts)):
38437501 inst = insts[i]
38537501 if len(inst) == 1:
3865726 pc = pc + 1
38731775 elif inst[0] != "SET_LINENO":
38825682 pc = pc + 3
38937501 opname = inst[0]
39037501 if opname in self.hasjrel:
391756 oparg = inst[1]
392756 offset = begin[oparg] - pc
393756 insts[i] = opname, offset
39436745 elif opname in self.hasjabs:
395417 insts[i] = opname, begin[inst[1]]
3961059 self.stage = FLAT
397n/a
3982 hasjrel = set()
39914 for i in dis.hasjrel:
40012 hasjrel.add(dis.opname[i])
4012 hasjabs = set()
40214 for i in dis.hasjabs:
40312 hasjabs.add(dis.opname[i])
404n/a
4052 def convertArgs(self):
406n/a """Convert arguments from symbolic to concrete form"""
4071059 assert self.stage == FLAT
4081059 self.consts.insert(0, self.docstring)
4091059 self.sort_cellvars()
41038560 for i in range(len(self.insts)):
41137501 t = self.insts[i]
41237501 if len(t) == 2:
41331775 opname, oparg = t
41431775 conv = self._converters.get(opname, None)
41531775 if conv:
41618551 self.insts[i] = opname, conv(self, oparg)
4171059 self.stage = CONV
418n/a
4192 def sort_cellvars(self):
420n/a """Sort cellvars in the order of varnames and prune from freevars.
421n/a """
4221059 cells = {}
4231143 for name in self.cellvars:
42484 cells[name] = 1
4252004 self.cellvars = [name for name in self.varnames
426945 if name in cells]
4271072 for name in self.cellvars:
42813 del cells[name]
4291059 self.cellvars = self.cellvars + cells.keys()
4301059 self.closure = self.cellvars + self.freevars
431n/a
4322 def _lookupName(self, name, list):
433n/a """Return index of name in list, appending if necessary
434n/a
435n/a This routine uses a list instead of a dictionary, because a
436n/a dictionary can't store two different keys if the keys have the
437n/a same value but different types, e.g. 2 and 2L. The compiler
438n/a must treat these two separately, so it does an explicit type
439n/a comparison before comparing the values.
440n/a """
44129773 t = type(name)
442266651 for i in range(len(list)):
443254911 if t == type(list[i]) and list[i] == name:
44418033 return i
44511740 end = len(list)
44611740 list.append(name)
44711740 return end
448n/a
4492 _converters = {}
4502 def _convert_LOAD_CONST(self, arg):
4515512 if hasattr(arg, 'getCode'):
4521028 arg = arg.getCode()
4535512 return self._lookupName(arg, self.consts)
454n/a
4552 def _convert_LOAD_FAST(self, arg):
4565628 self._lookupName(arg, self.names)
4575628 return self._lookupName(arg, self.varnames)
4582 _convert_STORE_FAST = _convert_LOAD_FAST
4592 _convert_DELETE_FAST = _convert_LOAD_FAST
460n/a
4612 def _convert_LOAD_NAME(self, arg):
462187 if self.klass is None:
463139 self._lookupName(arg, self.varnames)
464187 return self._lookupName(arg, self.names)
465n/a
4662 def _convert_NAME(self, arg):
4676208 if self.klass is None:
4684666 self._lookupName(arg, self.varnames)
4696208 return self._lookupName(arg, self.names)
4702 _convert_STORE_NAME = _convert_NAME
4712 _convert_DELETE_NAME = _convert_NAME
4722 _convert_IMPORT_NAME = _convert_NAME
4732 _convert_IMPORT_FROM = _convert_NAME
4742 _convert_STORE_ATTR = _convert_NAME
4752 _convert_LOAD_ATTR = _convert_NAME
4762 _convert_DELETE_ATTR = _convert_NAME
4772 _convert_LOAD_GLOBAL = _convert_NAME
4782 _convert_STORE_GLOBAL = _convert_NAME
4792 _convert_DELETE_GLOBAL = _convert_NAME
480n/a
4812 def _convert_DEREF(self, arg):
482497 self._lookupName(arg, self.names)
483497 self._lookupName(arg, self.varnames)
484497 return self._lookupName(arg, self.closure)
4852 _convert_LOAD_DEREF = _convert_DEREF
4862 _convert_STORE_DEREF = _convert_DEREF
487n/a
4882 def _convert_LOAD_CLOSURE(self, arg):
489157 self._lookupName(arg, self.varnames)
490157 return self._lookupName(arg, self.closure)
491n/a
4922 _cmp = list(dis.cmp_op)
4932 def _convert_COMPARE_OP(self, arg):
494362 return self._cmp.index(arg)
495n/a
496n/a # similarly for other opcodes...
497n/a
49884 for name, obj in locals().items():
49982 if name[:9] == "_convert_":
50042 opname = name[9:]
50142 _converters[opname] = obj
5022 del name, obj, opname
503n/a
5042 def makeByteCode(self):
5051059 assert self.stage == CONV
5061059 self.lnotab = lnotab = LineAddrTable()
50738560 for t in self.insts:
50837501 opname = t[0]
50937501 if len(t) == 1:
5105726 lnotab.addCode(self.opnum[opname])
511n/a else:
51231775 oparg = t[1]
51331775 if opname == "SET_LINENO":
5146093 lnotab.nextLine(oparg)
5156093 continue
51625682 hi, lo = twobyte(oparg)
51725682 try:
51825682 lnotab.addCode(self.opnum[opname], lo, hi)
5190 except ValueError:
5200 print opname, oparg
5210 print self.opnum[opname], lo, hi
5220 raise
5231059 self.stage = DONE
524n/a
5252 opnum = {}
526514 for num in range(len(dis.opname)):
527512 opnum[dis.opname[num]] = num
5282 del num
529n/a
5302 def newCodeObject(self):
5311059 assert self.stage == DONE
5321059 if (self.flags & CO_NEWLOCALS) == 0:
53331 nlocals = 0
534n/a else:
5351028 nlocals = len(self.varnames)
5361059 argcount = self.argcount
5371059 if self.flags & CO_VARKEYWORDS:
5384 argcount = argcount - 1
5391059 return types.CodeType(argcount, nlocals, self.stacksize, self.flags,
5401059 self.lnotab.getCode(), self.getConsts(),
5411059 tuple(self.names), tuple(self.varnames),
5421059 self.filename, self.name, self.lnotab.firstline,
5431059 self.lnotab.getTable(), tuple(self.freevars),
5441059 tuple(self.cellvars))
545n/a
5462 def getConsts(self):
547n/a """Return a tuple for the const slot of the code object
548n/a
549n/a Must convert references to code (MAKE_FUNCTION) to code
550n/a objects recursively.
551n/a """
5521059 l = []
5535304 for elt in self.consts:
5544245 if isinstance(elt, PyFlowGraph):
5550 elt = elt.getCode()
5564245 l.append(elt)
5571059 return tuple(l)
558n/a
5592def isJump(opname):
5600 if opname[:4] == 'JUMP':
5610 return 1
562n/a
5634class TupleArg:
5642 """Helper for marking func defs with nested tuples in arglist"""
5652 def __init__(self, count, names):
5660 self.count = count
5670 self.names = names
5682 def __repr__(self):
5690 return "TupleArg(%s, %s)" % (self.count, self.names)
5702 def getName(self):
5710 return ".%d" % self.count
572n/a
5732def getArgCount(args):
5741059 argcount = len(args)
5751059 if args:
5761548 for arg in args:
577945 if isinstance(arg, TupleArg):
5780 numNames = len(misc.flatten(arg.names))
5790 argcount = argcount - numNames
5801059 return argcount
581n/a
5822def twobyte(val):
583n/a """Convert an int argument into high and low bytes"""
58425682 assert isinstance(val, int)
58525682 return divmod(val, 256)
586n/a
5874class LineAddrTable:
588n/a """lnotab
589n/a
590n/a This class builds the lnotab, which is documented in compile.c.
591n/a Here's a brief recap:
592n/a
593n/a For each SET_LINENO instruction after the first one, two bytes are
594n/a added to lnotab. (In some cases, multiple two-byte entries are
595n/a added.) The first byte is the distance in bytes between the
596n/a instruction for the last SET_LINENO and the current SET_LINENO.
597n/a The second byte is offset in line numbers. If either offset is
598n/a greater than 255, multiple two-byte entries are added -- see
599n/a compile.c for the delicate details.
6002 """
601n/a
6022 def __init__(self):
6031059 self.code = []
6041059 self.codeOffset = 0
6051059 self.firstline = 0
6061059 self.lastline = 0
6071059 self.lastoff = 0
6081059 self.lnotab = []
609n/a
6102 def addCode(self, *args):
611114180 for arg in args:
61282772 self.code.append(chr(arg))
61331408 self.codeOffset = self.codeOffset + len(args)
614n/a
6152 def nextLine(self, lineno):
6166093 if self.firstline == 0:
6171080 self.firstline = lineno
6181080 self.lastline = lineno
619n/a else:
620n/a # compute deltas
6215013 addr = self.codeOffset - self.lastoff
6225013 line = lineno - self.lastline
623n/a # Python assumes that lineno always increases with
624n/a # increasing bytecode address (lnotab is unsigned char).
625n/a # Depending on when SET_LINENO instructions are emitted
626n/a # this is not always true. Consider the code:
627n/a # a = (1,
628n/a # b)
629n/a # In the bytecode stream, the assignment to "a" occurs
630n/a # after the loading of "b". This works with the C Python
631n/a # compiler because it only generates a SET_LINENO instruction
632n/a # for the assignment.
6335013 if line >= 0:
6344960 push = self.lnotab.append
6354961 while addr > 255:
6361 push(255); push(0)
6371 addr -= 255
6384979 while line > 255:
63919 push(addr); push(255)
64019 line -= 255
64119 addr = 0
6424960 if addr > 0 or line > 0:
6434960 push(addr); push(line)
6444960 self.lastline = lineno
6454960 self.lastoff = self.codeOffset
646n/a
6472 def getCode(self):
6481059 return ''.join(self.code)
649n/a
6502 def getTable(self):
6511059 return ''.join(map(chr, self.lnotab))
652n/a
6534class StackDepthTracker:
654n/a # XXX 1. need to keep track of stack depth on jumps
655n/a # XXX 2. at least partly as a result, this code is broken
656n/a
6572 def findDepth(self, insts, debug=0):
6583956 depth = 0
6593956 maxDepth = 0
66041491 for i in insts:
66137535 opname = i[0]
66237535 if debug:
6630 print i,
66437535 delta = self.effect.get(opname, None)
66537535 if delta is not None:
66610130 depth = depth + delta
667n/a else:
668n/a # now check patterns
66968191 for pat, pat_delta in self.patterns:
67054444 if opname[:len(pat)] == pat:
67113658 delta = pat_delta
67213658 depth = depth + delta
67313658 break
674n/a # if we still haven't found a match
67527405 if delta is None:
67613747 meth = getattr(self, opname, None)
67713747 if meth is not None:
6785807 depth = depth + meth(i[1])
67937535 if depth > maxDepth:
6805633 maxDepth = depth
68137535 if debug:
6820 print depth, maxDepth
6833956 return maxDepth
684n/a
6852 effect = {
6862 'POP_TOP': -1,
6872 'DUP_TOP': 1,
6882 'LIST_APPEND': -1,
6892 'SET_ADD': -1,
6902 'MAP_ADD': -2,
6912 'SLICE+1': -1,
6922 'SLICE+2': -1,
6932 'SLICE+3': -2,
6942 'STORE_SLICE+0': -1,
6952 'STORE_SLICE+1': -2,
6962 'STORE_SLICE+2': -2,
6972 'STORE_SLICE+3': -3,
6982 'DELETE_SLICE+0': -1,
6992 'DELETE_SLICE+1': -2,
7002 'DELETE_SLICE+2': -2,
7012 'DELETE_SLICE+3': -3,
7022 'STORE_SUBSCR': -3,
7032 'DELETE_SUBSCR': -2,
704n/a # PRINT_EXPR?
7052 'PRINT_ITEM': -1,
7062 'RETURN_VALUE': -1,
7072 'YIELD_VALUE': -1,
7082 'EXEC_STMT': -3,
7092 'BUILD_CLASS': -2,
7102 'STORE_NAME': -1,
7112 'STORE_ATTR': -2,
7122 'DELETE_ATTR': -1,
7132 'STORE_GLOBAL': -1,
7142 'BUILD_MAP': 1,
7152 'COMPARE_OP': -1,
7162 'STORE_FAST': -1,
7172 'IMPORT_STAR': -1,
7182 'IMPORT_NAME': -1,
7192 'IMPORT_FROM': 1,
7202 'LOAD_ATTR': 0, # unlike other loads
721n/a # close enough...
7222 'SETUP_EXCEPT': 3,
7232 'SETUP_FINALLY': 3,
7242 'FOR_ITER': 1,
7252 'WITH_CLEANUP': -1,
726n/a }
727n/a # use pattern match
728n/a patterns = [
7292 ('BINARY_', -1),
7302 ('LOAD_', 1),
731n/a ]
732n/a
7332 def UNPACK_SEQUENCE(self, count):
73435 return count-1
7352 def BUILD_TUPLE(self, count):
7361039 return -count+1
7372 def BUILD_LIST(self, count):
738326 return -count+1
7392 def BUILD_SET(self, count):
7404 return -count+1
7412 def CALL_FUNCTION(self, argc):
7423375 hi, lo = divmod(argc, 256)
7433375 return -(lo + hi * 2)
7442 def CALL_FUNCTION_VAR(self, argc):
7455 return self.CALL_FUNCTION(argc)-1
7462 def CALL_FUNCTION_KW(self, argc):
7473 return self.CALL_FUNCTION(argc)-1
7482 def CALL_FUNCTION_VAR_KW(self, argc):
7497 return self.CALL_FUNCTION(argc)-2
7502 def MAKE_FUNCTION(self, argc):
751888 return -argc
7522 def MAKE_CLOSURE(self, argc):
753n/a # XXX need to account for free variables too!
754140 return -argc
7552 def BUILD_SLICE(self, argc):
7560 if argc == 2:
7570 return -1
7580 elif argc == 3:
7590 return -2
7602 def DUP_TOPX(self, argc):
7610 return argc
762n/a
7632findDepth = StackDepthTracker().findDepth