]> git.proxmox.com Git - mirror_edk2.git/blobdiff - AppPkg/Applications/Python/Python-2.7.2/Lib/compiler/pyassem.py
edk2: Remove AppPkg, StdLib, StdLibPrivateInternalFiles
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / compiler / pyassem.py
diff --git a/AppPkg/Applications/Python/Python-2.7.2/Lib/compiler/pyassem.py b/AppPkg/Applications/Python/Python-2.7.2/Lib/compiler/pyassem.py
deleted file mode 100644 (file)
index ffefd7f..0000000
+++ /dev/null
@@ -1,763 +0,0 @@
-"""A flow graph representation for Python bytecode"""\r
-\r
-import dis\r
-import types\r
-import sys\r
-\r
-from compiler import misc\r
-from compiler.consts \\r
-     import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS\r
-\r
-class FlowGraph:\r
-    def __init__(self):\r
-        self.current = self.entry = Block()\r
-        self.exit = Block("exit")\r
-        self.blocks = misc.Set()\r
-        self.blocks.add(self.entry)\r
-        self.blocks.add(self.exit)\r
-\r
-    def startBlock(self, block):\r
-        if self._debug:\r
-            if self.current:\r
-                print "end", repr(self.current)\r
-                print "    next", self.current.next\r
-                print "    prev", self.current.prev\r
-                print "   ", self.current.get_children()\r
-            print repr(block)\r
-        self.current = block\r
-\r
-    def nextBlock(self, block=None):\r
-        # XXX think we need to specify when there is implicit transfer\r
-        # from one block to the next.  might be better to represent this\r
-        # with explicit JUMP_ABSOLUTE instructions that are optimized\r
-        # out when they are unnecessary.\r
-        #\r
-        # I think this strategy works: each block has a child\r
-        # designated as "next" which is returned as the last of the\r
-        # children.  because the nodes in a graph are emitted in\r
-        # reverse post order, the "next" block will always be emitted\r
-        # immediately after its parent.\r
-        # Worry: maintaining this invariant could be tricky\r
-        if block is None:\r
-            block = self.newBlock()\r
-\r
-        # Note: If the current block ends with an unconditional control\r
-        # transfer, then it is techically incorrect to add an implicit\r
-        # transfer to the block graph. Doing so results in code generation\r
-        # for unreachable blocks.  That doesn't appear to be very common\r
-        # with Python code and since the built-in compiler doesn't optimize\r
-        # it out we don't either.\r
-        self.current.addNext(block)\r
-        self.startBlock(block)\r
-\r
-    def newBlock(self):\r
-        b = Block()\r
-        self.blocks.add(b)\r
-        return b\r
-\r
-    def startExitBlock(self):\r
-        self.startBlock(self.exit)\r
-\r
-    _debug = 0\r
-\r
-    def _enable_debug(self):\r
-        self._debug = 1\r
-\r
-    def _disable_debug(self):\r
-        self._debug = 0\r
-\r
-    def emit(self, *inst):\r
-        if self._debug:\r
-            print "\t", inst\r
-        if len(inst) == 2 and isinstance(inst[1], Block):\r
-            self.current.addOutEdge(inst[1])\r
-        self.current.emit(inst)\r
-\r
-    def getBlocksInOrder(self):\r
-        """Return the blocks in reverse postorder\r
-\r
-        i.e. each node appears before all of its successors\r
-        """\r
-        order = order_blocks(self.entry, self.exit)\r
-        return order\r
-\r
-    def getBlocks(self):\r
-        return self.blocks.elements()\r
-\r
-    def getRoot(self):\r
-        """Return nodes appropriate for use with dominator"""\r
-        return self.entry\r
-\r
-    def getContainedGraphs(self):\r
-        l = []\r
-        for b in self.getBlocks():\r
-            l.extend(b.getContainedGraphs())\r
-        return l\r
-\r
-\r
-def order_blocks(start_block, exit_block):\r
-    """Order blocks so that they are emitted in the right order"""\r
-    # Rules:\r
-    # - when a block has a next block, the next block must be emitted just after\r
-    # - when a block has followers (relative jumps), it must be emitted before\r
-    #   them\r
-    # - all reachable blocks must be emitted\r
-    order = []\r
-\r
-    # Find all the blocks to be emitted.\r
-    remaining = set()\r
-    todo = [start_block]\r
-    while todo:\r
-        b = todo.pop()\r
-        if b in remaining:\r
-            continue\r
-        remaining.add(b)\r
-        for c in b.get_children():\r
-            if c not in remaining:\r
-                todo.append(c)\r
-\r
-    # A block is dominated by another block if that block must be emitted\r
-    # before it.\r
-    dominators = {}\r
-    for b in remaining:\r
-        if __debug__ and b.next:\r
-            assert b is b.next[0].prev[0], (b, b.next)\r
-        # Make sure every block appears in dominators, even if no\r
-        # other block must precede it.\r
-        dominators.setdefault(b, set())\r
-        # preceeding blocks dominate following blocks\r
-        for c in b.get_followers():\r
-            while 1:\r
-                dominators.setdefault(c, set()).add(b)\r
-                # Any block that has a next pointer leading to c is also\r
-                # dominated because the whole chain will be emitted at once.\r
-                # Walk backwards and add them all.\r
-                if c.prev and c.prev[0] is not b:\r
-                    c = c.prev[0]\r
-                else:\r
-                    break\r
-\r
-    def find_next():\r
-        # Find a block that can be emitted next.\r
-        for b in remaining:\r
-            for c in dominators[b]:\r
-                if c in remaining:\r
-                    break # can't emit yet, dominated by a remaining block\r
-            else:\r
-                return b\r
-        assert 0, 'circular dependency, cannot find next block'\r
-\r
-    b = start_block\r
-    while 1:\r
-        order.append(b)\r
-        remaining.discard(b)\r
-        if b.next:\r
-            b = b.next[0]\r
-            continue\r
-        elif b is not exit_block and not b.has_unconditional_transfer():\r
-            order.append(exit_block)\r
-        if not remaining:\r
-            break\r
-        b = find_next()\r
-    return order\r
-\r
-\r
-class Block:\r
-    _count = 0\r
-\r
-    def __init__(self, label=''):\r
-        self.insts = []\r
-        self.outEdges = set()\r
-        self.label = label\r
-        self.bid = Block._count\r
-        self.next = []\r
-        self.prev = []\r
-        Block._count = Block._count + 1\r
-\r
-    def __repr__(self):\r
-        if self.label:\r
-            return "<block %s id=%d>" % (self.label, self.bid)\r
-        else:\r
-            return "<block id=%d>" % (self.bid)\r
-\r
-    def __str__(self):\r
-        insts = map(str, self.insts)\r
-        return "<block %s %d:\n%s>" % (self.label, self.bid,\r
-                                       '\n'.join(insts))\r
-\r
-    def emit(self, inst):\r
-        op = inst[0]\r
-        self.insts.append(inst)\r
-\r
-    def getInstructions(self):\r
-        return self.insts\r
-\r
-    def addOutEdge(self, block):\r
-        self.outEdges.add(block)\r
-\r
-    def addNext(self, block):\r
-        self.next.append(block)\r
-        assert len(self.next) == 1, map(str, self.next)\r
-        block.prev.append(self)\r
-        assert len(block.prev) == 1, map(str, block.prev)\r
-\r
-    _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS',\r
-                        'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP',\r
-                        )\r
-\r
-    def has_unconditional_transfer(self):\r
-        """Returns True if there is an unconditional transfer to an other block\r
-        at the end of this block. This means there is no risk for the bytecode\r
-        executer to go past this block's bytecode."""\r
-        try:\r
-            op, arg = self.insts[-1]\r
-        except (IndexError, ValueError):\r
-            return\r
-        return op in self._uncond_transfer\r
-\r
-    def get_children(self):\r
-        return list(self.outEdges) + self.next\r
-\r
-    def get_followers(self):\r
-        """Get the whole list of followers, including the next block."""\r
-        followers = set(self.next)\r
-        # Blocks that must be emitted *after* this one, because of\r
-        # bytecode offsets (e.g. relative jumps) pointing to them.\r
-        for inst in self.insts:\r
-            if inst[0] in PyFlowGraph.hasjrel:\r
-                followers.add(inst[1])\r
-        return followers\r
-\r
-    def getContainedGraphs(self):\r
-        """Return all graphs contained within this block.\r
-\r
-        For example, a MAKE_FUNCTION block will contain a reference to\r
-        the graph for the function body.\r
-        """\r
-        contained = []\r
-        for inst in self.insts:\r
-            if len(inst) == 1:\r
-                continue\r
-            op = inst[1]\r
-            if hasattr(op, 'graph'):\r
-                contained.append(op.graph)\r
-        return contained\r
-\r
-# flags for code objects\r
-\r
-# the FlowGraph is transformed in place; it exists in one of these states\r
-RAW = "RAW"\r
-FLAT = "FLAT"\r
-CONV = "CONV"\r
-DONE = "DONE"\r
-\r
-class PyFlowGraph(FlowGraph):\r
-    super_init = FlowGraph.__init__\r
-\r
-    def __init__(self, name, filename, args=(), optimized=0, klass=None):\r
-        self.super_init()\r
-        self.name = name\r
-        self.filename = filename\r
-        self.docstring = None\r
-        self.args = args # XXX\r
-        self.argcount = getArgCount(args)\r
-        self.klass = klass\r
-        if optimized:\r
-            self.flags = CO_OPTIMIZED | CO_NEWLOCALS\r
-        else:\r
-            self.flags = 0\r
-        self.consts = []\r
-        self.names = []\r
-        # Free variables found by the symbol table scan, including\r
-        # variables used only in nested scopes, are included here.\r
-        self.freevars = []\r
-        self.cellvars = []\r
-        # The closure list is used to track the order of cell\r
-        # variables and free variables in the resulting code object.\r
-        # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both\r
-        # kinds of variables.\r
-        self.closure = []\r
-        self.varnames = list(args) or []\r
-        for i in range(len(self.varnames)):\r
-            var = self.varnames[i]\r
-            if isinstance(var, TupleArg):\r
-                self.varnames[i] = var.getName()\r
-        self.stage = RAW\r
-\r
-    def setDocstring(self, doc):\r
-        self.docstring = doc\r
-\r
-    def setFlag(self, flag):\r
-        self.flags = self.flags | flag\r
-        if flag == CO_VARARGS:\r
-            self.argcount = self.argcount - 1\r
-\r
-    def checkFlag(self, flag):\r
-        if self.flags & flag:\r
-            return 1\r
-\r
-    def setFreeVars(self, names):\r
-        self.freevars = list(names)\r
-\r
-    def setCellVars(self, names):\r
-        self.cellvars = names\r
-\r
-    def getCode(self):\r
-        """Get a Python code object"""\r
-        assert self.stage == RAW\r
-        self.computeStackDepth()\r
-        self.flattenGraph()\r
-        assert self.stage == FLAT\r
-        self.convertArgs()\r
-        assert self.stage == CONV\r
-        self.makeByteCode()\r
-        assert self.stage == DONE\r
-        return self.newCodeObject()\r
-\r
-    def dump(self, io=None):\r
-        if io:\r
-            save = sys.stdout\r
-            sys.stdout = io\r
-        pc = 0\r
-        for t in self.insts:\r
-            opname = t[0]\r
-            if opname == "SET_LINENO":\r
-                print\r
-            if len(t) == 1:\r
-                print "\t", "%3d" % pc, opname\r
-                pc = pc + 1\r
-            else:\r
-                print "\t", "%3d" % pc, opname, t[1]\r
-                pc = pc + 3\r
-        if io:\r
-            sys.stdout = save\r
-\r
-    def computeStackDepth(self):\r
-        """Compute the max stack depth.\r
-\r
-        Approach is to compute the stack effect of each basic block.\r
-        Then find the path through the code with the largest total\r
-        effect.\r
-        """\r
-        depth = {}\r
-        exit = None\r
-        for b in self.getBlocks():\r
-            depth[b] = findDepth(b.getInstructions())\r
-\r
-        seen = {}\r
-\r
-        def max_depth(b, d):\r
-            if b in seen:\r
-                return d\r
-            seen[b] = 1\r
-            d = d + depth[b]\r
-            children = b.get_children()\r
-            if children:\r
-                return max([max_depth(c, d) for c in children])\r
-            else:\r
-                if not b.label == "exit":\r
-                    return max_depth(self.exit, d)\r
-                else:\r
-                    return d\r
-\r
-        self.stacksize = max_depth(self.entry, 0)\r
-\r
-    def flattenGraph(self):\r
-        """Arrange the blocks in order and resolve jumps"""\r
-        assert self.stage == RAW\r
-        self.insts = insts = []\r
-        pc = 0\r
-        begin = {}\r
-        end = {}\r
-        for b in self.getBlocksInOrder():\r
-            begin[b] = pc\r
-            for inst in b.getInstructions():\r
-                insts.append(inst)\r
-                if len(inst) == 1:\r
-                    pc = pc + 1\r
-                elif inst[0] != "SET_LINENO":\r
-                    # arg takes 2 bytes\r
-                    pc = pc + 3\r
-            end[b] = pc\r
-        pc = 0\r
-        for i in range(len(insts)):\r
-            inst = insts[i]\r
-            if len(inst) == 1:\r
-                pc = pc + 1\r
-            elif inst[0] != "SET_LINENO":\r
-                pc = pc + 3\r
-            opname = inst[0]\r
-            if opname in self.hasjrel:\r
-                oparg = inst[1]\r
-                offset = begin[oparg] - pc\r
-                insts[i] = opname, offset\r
-            elif opname in self.hasjabs:\r
-                insts[i] = opname, begin[inst[1]]\r
-        self.stage = FLAT\r
-\r
-    hasjrel = set()\r
-    for i in dis.hasjrel:\r
-        hasjrel.add(dis.opname[i])\r
-    hasjabs = set()\r
-    for i in dis.hasjabs:\r
-        hasjabs.add(dis.opname[i])\r
-\r
-    def convertArgs(self):\r
-        """Convert arguments from symbolic to concrete form"""\r
-        assert self.stage == FLAT\r
-        self.consts.insert(0, self.docstring)\r
-        self.sort_cellvars()\r
-        for i in range(len(self.insts)):\r
-            t = self.insts[i]\r
-            if len(t) == 2:\r
-                opname, oparg = t\r
-                conv = self._converters.get(opname, None)\r
-                if conv:\r
-                    self.insts[i] = opname, conv(self, oparg)\r
-        self.stage = CONV\r
-\r
-    def sort_cellvars(self):\r
-        """Sort cellvars in the order of varnames and prune from freevars.\r
-        """\r
-        cells = {}\r
-        for name in self.cellvars:\r
-            cells[name] = 1\r
-        self.cellvars = [name for name in self.varnames\r
-                         if name in cells]\r
-        for name in self.cellvars:\r
-            del cells[name]\r
-        self.cellvars = self.cellvars + cells.keys()\r
-        self.closure = self.cellvars + self.freevars\r
-\r
-    def _lookupName(self, name, list):\r
-        """Return index of name in list, appending if necessary\r
-\r
-        This routine uses a list instead of a dictionary, because a\r
-        dictionary can't store two different keys if the keys have the\r
-        same value but different types, e.g. 2 and 2L.  The compiler\r
-        must treat these two separately, so it does an explicit type\r
-        comparison before comparing the values.\r
-        """\r
-        t = type(name)\r
-        for i in range(len(list)):\r
-            if t == type(list[i]) and list[i] == name:\r
-                return i\r
-        end = len(list)\r
-        list.append(name)\r
-        return end\r
-\r
-    _converters = {}\r
-    def _convert_LOAD_CONST(self, arg):\r
-        if hasattr(arg, 'getCode'):\r
-            arg = arg.getCode()\r
-        return self._lookupName(arg, self.consts)\r
-\r
-    def _convert_LOAD_FAST(self, arg):\r
-        self._lookupName(arg, self.names)\r
-        return self._lookupName(arg, self.varnames)\r
-    _convert_STORE_FAST = _convert_LOAD_FAST\r
-    _convert_DELETE_FAST = _convert_LOAD_FAST\r
-\r
-    def _convert_LOAD_NAME(self, arg):\r
-        if self.klass is None:\r
-            self._lookupName(arg, self.varnames)\r
-        return self._lookupName(arg, self.names)\r
-\r
-    def _convert_NAME(self, arg):\r
-        if self.klass is None:\r
-            self._lookupName(arg, self.varnames)\r
-        return self._lookupName(arg, self.names)\r
-    _convert_STORE_NAME = _convert_NAME\r
-    _convert_DELETE_NAME = _convert_NAME\r
-    _convert_IMPORT_NAME = _convert_NAME\r
-    _convert_IMPORT_FROM = _convert_NAME\r
-    _convert_STORE_ATTR = _convert_NAME\r
-    _convert_LOAD_ATTR = _convert_NAME\r
-    _convert_DELETE_ATTR = _convert_NAME\r
-    _convert_LOAD_GLOBAL = _convert_NAME\r
-    _convert_STORE_GLOBAL = _convert_NAME\r
-    _convert_DELETE_GLOBAL = _convert_NAME\r
-\r
-    def _convert_DEREF(self, arg):\r
-        self._lookupName(arg, self.names)\r
-        self._lookupName(arg, self.varnames)\r
-        return self._lookupName(arg, self.closure)\r
-    _convert_LOAD_DEREF = _convert_DEREF\r
-    _convert_STORE_DEREF = _convert_DEREF\r
-\r
-    def _convert_LOAD_CLOSURE(self, arg):\r
-        self._lookupName(arg, self.varnames)\r
-        return self._lookupName(arg, self.closure)\r
-\r
-    _cmp = list(dis.cmp_op)\r
-    def _convert_COMPARE_OP(self, arg):\r
-        return self._cmp.index(arg)\r
-\r
-    # similarly for other opcodes...\r
-\r
-    for name, obj in locals().items():\r
-        if name[:9] == "_convert_":\r
-            opname = name[9:]\r
-            _converters[opname] = obj\r
-    del name, obj, opname\r
-\r
-    def makeByteCode(self):\r
-        assert self.stage == CONV\r
-        self.lnotab = lnotab = LineAddrTable()\r
-        for t in self.insts:\r
-            opname = t[0]\r
-            if len(t) == 1:\r
-                lnotab.addCode(self.opnum[opname])\r
-            else:\r
-                oparg = t[1]\r
-                if opname == "SET_LINENO":\r
-                    lnotab.nextLine(oparg)\r
-                    continue\r
-                hi, lo = twobyte(oparg)\r
-                try:\r
-                    lnotab.addCode(self.opnum[opname], lo, hi)\r
-                except ValueError:\r
-                    print opname, oparg\r
-                    print self.opnum[opname], lo, hi\r
-                    raise\r
-        self.stage = DONE\r
-\r
-    opnum = {}\r
-    for num in range(len(dis.opname)):\r
-        opnum[dis.opname[num]] = num\r
-    del num\r
-\r
-    def newCodeObject(self):\r
-        assert self.stage == DONE\r
-        if (self.flags & CO_NEWLOCALS) == 0:\r
-            nlocals = 0\r
-        else:\r
-            nlocals = len(self.varnames)\r
-        argcount = self.argcount\r
-        if self.flags & CO_VARKEYWORDS:\r
-            argcount = argcount - 1\r
-        return types.CodeType(argcount, nlocals, self.stacksize, self.flags,\r
-                        self.lnotab.getCode(), self.getConsts(),\r
-                        tuple(self.names), tuple(self.varnames),\r
-                        self.filename, self.name, self.lnotab.firstline,\r
-                        self.lnotab.getTable(), tuple(self.freevars),\r
-                        tuple(self.cellvars))\r
-\r
-    def getConsts(self):\r
-        """Return a tuple for the const slot of the code object\r
-\r
-        Must convert references to code (MAKE_FUNCTION) to code\r
-        objects recursively.\r
-        """\r
-        l = []\r
-        for elt in self.consts:\r
-            if isinstance(elt, PyFlowGraph):\r
-                elt = elt.getCode()\r
-            l.append(elt)\r
-        return tuple(l)\r
-\r
-def isJump(opname):\r
-    if opname[:4] == 'JUMP':\r
-        return 1\r
-\r
-class TupleArg:\r
-    """Helper for marking func defs with nested tuples in arglist"""\r
-    def __init__(self, count, names):\r
-        self.count = count\r
-        self.names = names\r
-    def __repr__(self):\r
-        return "TupleArg(%s, %s)" % (self.count, self.names)\r
-    def getName(self):\r
-        return ".%d" % self.count\r
-\r
-def getArgCount(args):\r
-    argcount = len(args)\r
-    if args:\r
-        for arg in args:\r
-            if isinstance(arg, TupleArg):\r
-                numNames = len(misc.flatten(arg.names))\r
-                argcount = argcount - numNames\r
-    return argcount\r
-\r
-def twobyte(val):\r
-    """Convert an int argument into high and low bytes"""\r
-    assert isinstance(val, int)\r
-    return divmod(val, 256)\r
-\r
-class LineAddrTable:\r
-    """lnotab\r
-\r
-    This class builds the lnotab, which is documented in compile.c.\r
-    Here's a brief recap:\r
-\r
-    For each SET_LINENO instruction after the first one, two bytes are\r
-    added to lnotab.  (In some cases, multiple two-byte entries are\r
-    added.)  The first byte is the distance in bytes between the\r
-    instruction for the last SET_LINENO and the current SET_LINENO.\r
-    The second byte is offset in line numbers.  If either offset is\r
-    greater than 255, multiple two-byte entries are added -- see\r
-    compile.c for the delicate details.\r
-    """\r
-\r
-    def __init__(self):\r
-        self.code = []\r
-        self.codeOffset = 0\r
-        self.firstline = 0\r
-        self.lastline = 0\r
-        self.lastoff = 0\r
-        self.lnotab = []\r
-\r
-    def addCode(self, *args):\r
-        for arg in args:\r
-            self.code.append(chr(arg))\r
-        self.codeOffset = self.codeOffset + len(args)\r
-\r
-    def nextLine(self, lineno):\r
-        if self.firstline == 0:\r
-            self.firstline = lineno\r
-            self.lastline = lineno\r
-        else:\r
-            # compute deltas\r
-            addr = self.codeOffset - self.lastoff\r
-            line = lineno - self.lastline\r
-            # Python assumes that lineno always increases with\r
-            # increasing bytecode address (lnotab is unsigned char).\r
-            # Depending on when SET_LINENO instructions are emitted\r
-            # this is not always true.  Consider the code:\r
-            #     a = (1,\r
-            #          b)\r
-            # In the bytecode stream, the assignment to "a" occurs\r
-            # after the loading of "b".  This works with the C Python\r
-            # compiler because it only generates a SET_LINENO instruction\r
-            # for the assignment.\r
-            if line >= 0:\r
-                push = self.lnotab.append\r
-                while addr > 255:\r
-                    push(255); push(0)\r
-                    addr -= 255\r
-                while line > 255:\r
-                    push(addr); push(255)\r
-                    line -= 255\r
-                    addr = 0\r
-                if addr > 0 or line > 0:\r
-                    push(addr); push(line)\r
-                self.lastline = lineno\r
-                self.lastoff = self.codeOffset\r
-\r
-    def getCode(self):\r
-        return ''.join(self.code)\r
-\r
-    def getTable(self):\r
-        return ''.join(map(chr, self.lnotab))\r
-\r
-class StackDepthTracker:\r
-    # XXX 1. need to keep track of stack depth on jumps\r
-    # XXX 2. at least partly as a result, this code is broken\r
-\r
-    def findDepth(self, insts, debug=0):\r
-        depth = 0\r
-        maxDepth = 0\r
-        for i in insts:\r
-            opname = i[0]\r
-            if debug:\r
-                print i,\r
-            delta = self.effect.get(opname, None)\r
-            if delta is not None:\r
-                depth = depth + delta\r
-            else:\r
-                # now check patterns\r
-                for pat, pat_delta in self.patterns:\r
-                    if opname[:len(pat)] == pat:\r
-                        delta = pat_delta\r
-                        depth = depth + delta\r
-                        break\r
-                # if we still haven't found a match\r
-                if delta is None:\r
-                    meth = getattr(self, opname, None)\r
-                    if meth is not None:\r
-                        depth = depth + meth(i[1])\r
-            if depth > maxDepth:\r
-                maxDepth = depth\r
-            if debug:\r
-                print depth, maxDepth\r
-        return maxDepth\r
-\r
-    effect = {\r
-        'POP_TOP': -1,\r
-        'DUP_TOP': 1,\r
-        'LIST_APPEND': -1,\r
-        'SET_ADD': -1,\r
-        'MAP_ADD': -2,\r
-        'SLICE+1': -1,\r
-        'SLICE+2': -1,\r
-        'SLICE+3': -2,\r
-        'STORE_SLICE+0': -1,\r
-        'STORE_SLICE+1': -2,\r
-        'STORE_SLICE+2': -2,\r
-        'STORE_SLICE+3': -3,\r
-        'DELETE_SLICE+0': -1,\r
-        'DELETE_SLICE+1': -2,\r
-        'DELETE_SLICE+2': -2,\r
-        'DELETE_SLICE+3': -3,\r
-        'STORE_SUBSCR': -3,\r
-        'DELETE_SUBSCR': -2,\r
-        # PRINT_EXPR?\r
-        'PRINT_ITEM': -1,\r
-        'RETURN_VALUE': -1,\r
-        'YIELD_VALUE': -1,\r
-        'EXEC_STMT': -3,\r
-        'BUILD_CLASS': -2,\r
-        'STORE_NAME': -1,\r
-        'STORE_ATTR': -2,\r
-        'DELETE_ATTR': -1,\r
-        'STORE_GLOBAL': -1,\r
-        'BUILD_MAP': 1,\r
-        'COMPARE_OP': -1,\r
-        'STORE_FAST': -1,\r
-        'IMPORT_STAR': -1,\r
-        'IMPORT_NAME': -1,\r
-        'IMPORT_FROM': 1,\r
-        'LOAD_ATTR': 0, # unlike other loads\r
-        # close enough...\r
-        'SETUP_EXCEPT': 3,\r
-        'SETUP_FINALLY': 3,\r
-        'FOR_ITER': 1,\r
-        'WITH_CLEANUP': -1,\r
-        }\r
-    # use pattern match\r
-    patterns = [\r
-        ('BINARY_', -1),\r
-        ('LOAD_', 1),\r
-        ]\r
-\r
-    def UNPACK_SEQUENCE(self, count):\r
-        return count-1\r
-    def BUILD_TUPLE(self, count):\r
-        return -count+1\r
-    def BUILD_LIST(self, count):\r
-        return -count+1\r
-    def BUILD_SET(self, count):\r
-        return -count+1\r
-    def CALL_FUNCTION(self, argc):\r
-        hi, lo = divmod(argc, 256)\r
-        return -(lo + hi * 2)\r
-    def CALL_FUNCTION_VAR(self, argc):\r
-        return self.CALL_FUNCTION(argc)-1\r
-    def CALL_FUNCTION_KW(self, argc):\r
-        return self.CALL_FUNCTION(argc)-1\r
-    def CALL_FUNCTION_VAR_KW(self, argc):\r
-        return self.CALL_FUNCTION(argc)-2\r
-    def MAKE_FUNCTION(self, argc):\r
-        return -argc\r
-    def MAKE_CLOSURE(self, argc):\r
-        # XXX need to account for free variables too!\r
-        return -argc\r
-    def BUILD_SLICE(self, argc):\r
-        if argc == 2:\r
-            return -1\r
-        elif argc == 3:\r
-            return -2\r
-    def DUP_TOPX(self, argc):\r
-        return argc\r
-\r
-findDepth = StackDepthTracker().findDepth\r