| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | """A flow graph representation for Python bytecode""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | import dis | 
					
						
							|  |  |  | import new | 
					
						
							|  |  |  | import string | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | import types | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from compiler import misc | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  | def xxx_sort(l): | 
					
						
							|  |  |  |     l = l[:] | 
					
						
							|  |  |  |     def sorter(a, b): | 
					
						
							|  |  |  |         return cmp(a.bid, b.bid) | 
					
						
							|  |  |  |     l.sort(sorter) | 
					
						
							|  |  |  |     return l | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | class FlowGraph: | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.current = self.entry = Block() | 
					
						
							|  |  |  |         self.exit = Block("exit") | 
					
						
							|  |  |  |         self.blocks = misc.Set() | 
					
						
							|  |  |  |         self.blocks.add(self.entry) | 
					
						
							|  |  |  |         self.blocks.add(self.exit) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def startBlock(self, block): | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         if self._debug: | 
					
						
							|  |  |  |             if self.current: | 
					
						
							|  |  |  |                 print "end", repr(self.current) | 
					
						
							|  |  |  |                 print "   ", self.current.get_children() | 
					
						
							|  |  |  |             print repr(block) | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.current = block | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     def nextBlock(self, block=None, force=0): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         # XXX think we need to specify when there is implicit transfer | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         # from one block to the next.  might be better to represent this | 
					
						
							|  |  |  |         # with explicit JUMP_ABSOLUTE instructions that are optimized | 
					
						
							|  |  |  |         # out when they are unnecessary. | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         # | 
					
						
							|  |  |  |         # I think this strategy works: each block has a child | 
					
						
							|  |  |  |         # designated as "next" which is returned as the last of the | 
					
						
							|  |  |  |         # children.  because the nodes in a graph are emitted in | 
					
						
							|  |  |  |         # reverse post order, the "next" block will always be emitted | 
					
						
							|  |  |  |         # immediately after its parent. | 
					
						
							|  |  |  |         # Worry: maintaining this invariant could be tricky | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         if block is None: | 
					
						
							|  |  |  |             block = self.newBlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Note: If the current block ends with an unconditional | 
					
						
							|  |  |  |         # control transfer, then it is incorrect to add an implicit | 
					
						
							|  |  |  |         # transfer to the block graph.  The current code requires | 
					
						
							|  |  |  |         # these edges to get the blocks emitted in the right order, | 
					
						
							|  |  |  |         # however. :-(  If a client needs to remove these edges, call | 
					
						
							|  |  |  |         # pruneEdges(). | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.current.addNext(block) | 
					
						
							|  |  |  |         self.startBlock(block) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def newBlock(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         b = Block() | 
					
						
							|  |  |  |         self.blocks.add(b) | 
					
						
							|  |  |  |         return b | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def startExitBlock(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.startBlock(self.exit) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     _debug = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _enable_debug(self): | 
					
						
							|  |  |  |         self._debug = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _disable_debug(self): | 
					
						
							|  |  |  |         self._debug = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     def emit(self, *inst): | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         if self._debug: | 
					
						
							|  |  |  |             print "\t", inst | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         if inst[0] == 'RETURN_VALUE': | 
					
						
							|  |  |  |             self.current.addOutEdge(self.exit) | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         if len(inst) == 2 and isinstance(inst[1], Block): | 
					
						
							|  |  |  |             self.current.addOutEdge(inst[1]) | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.current.emit(inst) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     def getBlocksInOrder(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         """Return the blocks in reverse postorder
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         i.e. each node appears before all of its successors | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # XXX make sure every node that doesn't have an explicit next | 
					
						
							|  |  |  |         # is set so that next points to exit | 
					
						
							|  |  |  |         for b in self.blocks.elements(): | 
					
						
							|  |  |  |             if b is self.exit: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if not b.next: | 
					
						
							|  |  |  |                 b.addNext(self.exit) | 
					
						
							|  |  |  |         order = dfs_postorder(self.entry, {}) | 
					
						
							|  |  |  |         order.reverse() | 
					
						
							|  |  |  |         # hack alert | 
					
						
							|  |  |  |         if not self.exit in order: | 
					
						
							|  |  |  |             order.append(self.exit) | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ##        for b in order: | 
					
						
							|  |  |  | ##            print repr(b) | 
					
						
							|  |  |  | ##            print "\t", b.get_children() | 
					
						
							|  |  |  | ##            print b | 
					
						
							|  |  |  | ##            print | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         return order | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     def getBlocks(self): | 
					
						
							|  |  |  |         return self.blocks.elements() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getRoot(self): | 
					
						
							|  |  |  |         """Return nodes appropriate for use with dominator""" | 
					
						
							|  |  |  |         return self.entry | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def getContainedGraphs(self): | 
					
						
							|  |  |  |         l = [] | 
					
						
							|  |  |  |         for b in self.getBlocks(): | 
					
						
							|  |  |  |             l.extend(b.getContainedGraphs()) | 
					
						
							|  |  |  |         return l | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | def dfs_postorder(b, seen): | 
					
						
							|  |  |  |     """Depth-first search of tree rooted at b, return in postorder""" | 
					
						
							|  |  |  |     order = [] | 
					
						
							|  |  |  |     seen[b] = b | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     for c in b.get_children(): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         if seen.has_key(c): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         order = order + dfs_postorder(c, seen) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     order.append(b) | 
					
						
							|  |  |  |     return order | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Block: | 
					
						
							|  |  |  |     _count = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, label=''): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.insts = [] | 
					
						
							|  |  |  |         self.inEdges = misc.Set() | 
					
						
							|  |  |  |         self.outEdges = misc.Set() | 
					
						
							|  |  |  |         self.label = label | 
					
						
							|  |  |  |         self.bid = Block._count | 
					
						
							|  |  |  |         self.next = [] | 
					
						
							|  |  |  |         Block._count = Block._count + 1 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         if self.label: | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |             return "<block %s id=%d>" % (self.label, self.bid) | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |             return "<block id=%d>" % (self.bid) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         insts = map(str, self.insts) | 
					
						
							|  |  |  |         return "<block %s %d:\n%s>" % (self.label, self.bid, | 
					
						
							|  |  |  |                                        string.join(insts, '\n'))  | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def emit(self, inst): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         op = inst[0] | 
					
						
							|  |  |  |         if op[:4] == 'JUMP': | 
					
						
							|  |  |  |             self.outEdges.add(inst[1]) | 
					
						
							|  |  |  |         self.insts.append(inst) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def getInstructions(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         return self.insts | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def addInEdge(self, block): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.inEdges.add(block) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def addOutEdge(self, block): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.outEdges.add(block) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def addNext(self, block): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.next.append(block) | 
					
						
							|  |  |  |         assert len(self.next) == 1, map(str, self.next) | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:47:39 +00:00
										 |  |  |     _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS', | 
					
						
							|  |  |  |                         'JUMP_ABSOLUTE', 'JUMP_FORWARD') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pruneNext(self): | 
					
						
							|  |  |  |         """Remove bogus edge for unconditional transfers
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Each block has a next edge that accounts for implicit control | 
					
						
							|  |  |  |         transfers, e.g. from a JUMP_IF_FALSE to the block that will be | 
					
						
							|  |  |  |         executed if the test is true. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         These edges must remain for the current assembler code to | 
					
						
							|  |  |  |         work. If they are removed, the dfs_postorder gets things in | 
					
						
							|  |  |  |         weird orders.  However, they shouldn't be there for other | 
					
						
							|  |  |  |         purposes, e.g. conversion to SSA form.  This method will | 
					
						
							|  |  |  |         remove the next edge when it follows an unconditional control | 
					
						
							|  |  |  |         transfer. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             op, arg = self.insts[-1] | 
					
						
							|  |  |  |         except (IndexError, ValueError): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         if op in self._uncond_transfer: | 
					
						
							|  |  |  |             self.next = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     def get_children(self): | 
					
						
							|  |  |  |         if self.next and self.next[0] in self.outEdges: | 
					
						
							|  |  |  |             self.outEdges.remove(self.next[0]) | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         return self.outEdges.elements() + self.next | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |     def getContainedGraphs(self): | 
					
						
							|  |  |  |         """Return all graphs contained within this block.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         For example, a MAKE_FUNCTION block will contain a reference to | 
					
						
							|  |  |  |         the graph for the function body. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         contained = [] | 
					
						
							|  |  |  |         for inst in self.insts: | 
					
						
							|  |  |  |             if len(inst) == 1: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             op = inst[1] | 
					
						
							|  |  |  |             if hasattr(op, 'graph'): | 
					
						
							|  |  |  |                 contained.append(op.graph) | 
					
						
							|  |  |  |         return contained | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | # flags for code objects | 
					
						
							|  |  |  | CO_OPTIMIZED = 0x0001 | 
					
						
							|  |  |  | CO_NEWLOCALS = 0x0002 | 
					
						
							|  |  |  | CO_VARARGS = 0x0004 | 
					
						
							|  |  |  | CO_VARKEYWORDS = 0x0008 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | # the FlowGraph is transformed in place; it exists in one of these states | 
					
						
							|  |  |  | RAW = "RAW" | 
					
						
							|  |  |  | FLAT = "FLAT" | 
					
						
							|  |  |  | CONV = "CONV" | 
					
						
							|  |  |  | DONE = "DONE" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PyFlowGraph(FlowGraph): | 
					
						
							|  |  |  |     super_init = FlowGraph.__init__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, name, filename, args=(), optimized=0): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.super_init() | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.filename = filename | 
					
						
							|  |  |  |         self.docstring = None | 
					
						
							|  |  |  |         self.args = args # XXX | 
					
						
							|  |  |  |         self.argcount = getArgCount(args) | 
					
						
							|  |  |  |         if optimized: | 
					
						
							|  |  |  |             self.flags = CO_OPTIMIZED | CO_NEWLOCALS  | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.flags = 0 | 
					
						
							|  |  |  |         self.consts = [] | 
					
						
							|  |  |  |         self.names = [] | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |         self.varnames = list(args) or [] | 
					
						
							| 
									
										
										
										
											2000-02-17 22:09:35 +00:00
										 |  |  |         for i in range(len(self.varnames)): | 
					
						
							|  |  |  |             var = self.varnames[i] | 
					
						
							|  |  |  |             if isinstance(var, TupleArg): | 
					
						
							|  |  |  |                 self.varnames[i] = var.getName() | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |         self.stage = RAW | 
					
						
							| 
									
										
										
										
											2000-02-16 00:50:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     def setDocstring(self, doc): | 
					
						
							|  |  |  |         self.docstring = doc | 
					
						
							|  |  |  |         self.consts.insert(0, doc) | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     def setFlag(self, flag): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.flags = self.flags | flag | 
					
						
							|  |  |  |         if flag == CO_VARARGS: | 
					
						
							|  |  |  |             self.argcount = self.argcount - 1 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     def getCode(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         """Get a Python code object""" | 
					
						
							|  |  |  |         if self.stage == RAW: | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |             self.flattenGraph() | 
					
						
							|  |  |  |         if self.stage == FLAT: | 
					
						
							|  |  |  |             self.convertArgs() | 
					
						
							|  |  |  |         if self.stage == CONV: | 
					
						
							|  |  |  |             self.makeByteCode() | 
					
						
							|  |  |  |         if self.stage == DONE: | 
					
						
							|  |  |  |             return self.newCodeObject() | 
					
						
							|  |  |  |         raise RuntimeError, "inconsistent PyFlowGraph state" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dump(self, io=None): | 
					
						
							|  |  |  |         if io: | 
					
						
							|  |  |  |             save = sys.stdout | 
					
						
							|  |  |  |             sys.stdout = io | 
					
						
							|  |  |  |         pc = 0 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |         for t in self.insts: | 
					
						
							|  |  |  |             opname = t[0] | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |             if opname == "SET_LINENO": | 
					
						
							|  |  |  |                 print | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |             if len(t) == 1: | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |                 print "\t", "%3d" % pc, opname | 
					
						
							|  |  |  |                 pc = pc + 1 | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 print "\t", "%3d" % pc, opname, t[1] | 
					
						
							|  |  |  |                 pc = pc + 3 | 
					
						
							|  |  |  |         if io: | 
					
						
							|  |  |  |             sys.stdout = save | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def flattenGraph(self): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         """Arrange the blocks in order and resolve jumps""" | 
					
						
							|  |  |  |         assert self.stage == RAW | 
					
						
							|  |  |  |         self.insts = insts = [] | 
					
						
							|  |  |  |         pc = 0 | 
					
						
							|  |  |  |         begin = {} | 
					
						
							|  |  |  |         end = {} | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         for b in self.getBlocksInOrder(): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |             begin[b] = pc | 
					
						
							|  |  |  |             for inst in b.getInstructions(): | 
					
						
							|  |  |  |                 insts.append(inst) | 
					
						
							|  |  |  |                 if len(inst) == 1: | 
					
						
							|  |  |  |                     pc = pc + 1 | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     # arg takes 2 bytes | 
					
						
							|  |  |  |                     pc = pc + 3 | 
					
						
							|  |  |  |             end[b] = pc | 
					
						
							|  |  |  |         pc = 0 | 
					
						
							|  |  |  |         for i in range(len(insts)): | 
					
						
							|  |  |  |             inst = insts[i] | 
					
						
							|  |  |  |             if len(inst) == 1: | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |                 pc = pc + 1 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |                 pc = pc + 3 | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |             opname = inst[0] | 
					
						
							|  |  |  |             if self.hasjrel.has_elt(opname): | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |                 oparg = inst[1] | 
					
						
							|  |  |  |                 offset = begin[oparg] - pc | 
					
						
							|  |  |  |                 insts[i] = opname, offset | 
					
						
							|  |  |  |             elif self.hasjabs.has_elt(opname): | 
					
						
							|  |  |  |                 insts[i] = opname, begin[inst[1]] | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         self.stacksize = findDepth(self.insts) | 
					
						
							|  |  |  |         self.stage = FLAT | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     hasjrel = misc.Set() | 
					
						
							|  |  |  |     for i in dis.hasjrel: | 
					
						
							|  |  |  |         hasjrel.add(dis.opname[i]) | 
					
						
							|  |  |  |     hasjabs = misc.Set() | 
					
						
							|  |  |  |     for i in dis.hasjabs: | 
					
						
							|  |  |  |         hasjabs.add(dis.opname[i]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def convertArgs(self): | 
					
						
							|  |  |  |         """Convert arguments from symbolic to concrete form""" | 
					
						
							|  |  |  |         assert self.stage == FLAT | 
					
						
							|  |  |  |         for i in range(len(self.insts)): | 
					
						
							|  |  |  |             t = self.insts[i] | 
					
						
							|  |  |  |             if len(t) == 2: | 
					
						
							|  |  |  |                 opname = t[0] | 
					
						
							|  |  |  |                 oparg = t[1] | 
					
						
							|  |  |  |                 conv = self._converters.get(opname, None) | 
					
						
							|  |  |  |                 if conv: | 
					
						
							|  |  |  |                     self.insts[i] = opname, conv(self, oparg) | 
					
						
							|  |  |  |         self.stage = CONV | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-17 22:58:54 +00:00
										 |  |  |     def _lookupName(self, name, list): | 
					
						
							|  |  |  |         """Return index of name in list, appending if necessary""" | 
					
						
							| 
									
										
										
										
											2000-10-13 21:58:13 +00:00
										 |  |  |         found = None | 
					
						
							|  |  |  |         t = type(name) | 
					
						
							|  |  |  |         for i in range(len(list)): | 
					
						
							|  |  |  |             # must do a comparison on type first to prevent UnicodeErrors  | 
					
						
							|  |  |  |             if t == type(list[i]) and list[i] == name: | 
					
						
							|  |  |  |                 found = 1 | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |         if found: | 
					
						
							| 
									
										
										
										
											2000-02-17 22:58:54 +00:00
										 |  |  |             # this is cheap, but incorrect in some cases, e.g 2 vs. 2L | 
					
						
							|  |  |  |             if type(name) == type(list[i]): | 
					
						
							|  |  |  |                 return i | 
					
						
							|  |  |  |             for i in range(len(list)): | 
					
						
							|  |  |  |                 elt = list[i] | 
					
						
							|  |  |  |                 if type(elt) == type(name) and elt == name: | 
					
						
							|  |  |  |                     return i | 
					
						
							|  |  |  |         end = len(list) | 
					
						
							|  |  |  |         list.append(name) | 
					
						
							|  |  |  |         return end | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     _converters = {} | 
					
						
							|  |  |  |     def _convert_LOAD_CONST(self, arg): | 
					
						
							| 
									
										
										
										
											2000-11-06 03:43:11 +00:00
										 |  |  |         if hasattr(arg, 'getCode'): | 
					
						
							|  |  |  |             arg = arg.getCode() | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |         return self._lookupName(arg, self.consts) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _convert_LOAD_FAST(self, arg): | 
					
						
							|  |  |  |         self._lookupName(arg, self.names) | 
					
						
							|  |  |  |         return self._lookupName(arg, self.varnames) | 
					
						
							|  |  |  |     _convert_STORE_FAST = _convert_LOAD_FAST | 
					
						
							|  |  |  |     _convert_DELETE_FAST = _convert_LOAD_FAST | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _convert_NAME(self, arg): | 
					
						
							|  |  |  |         return self._lookupName(arg, self.names) | 
					
						
							|  |  |  |     _convert_LOAD_NAME = _convert_NAME | 
					
						
							|  |  |  |     _convert_STORE_NAME = _convert_NAME | 
					
						
							|  |  |  |     _convert_DELETE_NAME = _convert_NAME | 
					
						
							|  |  |  |     _convert_IMPORT_NAME = _convert_NAME | 
					
						
							|  |  |  |     _convert_IMPORT_FROM = _convert_NAME | 
					
						
							|  |  |  |     _convert_STORE_ATTR = _convert_NAME | 
					
						
							|  |  |  |     _convert_LOAD_ATTR = _convert_NAME | 
					
						
							|  |  |  |     _convert_DELETE_ATTR = _convert_NAME | 
					
						
							|  |  |  |     _convert_LOAD_GLOBAL = _convert_NAME | 
					
						
							|  |  |  |     _convert_STORE_GLOBAL = _convert_NAME | 
					
						
							|  |  |  |     _convert_DELETE_GLOBAL = _convert_NAME | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _cmp = list(dis.cmp_op) | 
					
						
							|  |  |  |     def _convert_COMPARE_OP(self, arg): | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         return self._cmp.index(arg) | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # similarly for other opcodes... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for name, obj in locals().items(): | 
					
						
							|  |  |  |         if name[:9] == "_convert_": | 
					
						
							|  |  |  |             opname = name[9:] | 
					
						
							|  |  |  |             _converters[opname] = obj             | 
					
						
							|  |  |  |     del name, obj, opname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def makeByteCode(self): | 
					
						
							|  |  |  |         assert self.stage == CONV | 
					
						
							|  |  |  |         self.lnotab = lnotab = LineAddrTable() | 
					
						
							|  |  |  |         for t in self.insts: | 
					
						
							|  |  |  |             opname = t[0] | 
					
						
							|  |  |  |             if len(t) == 1: | 
					
						
							|  |  |  |                 lnotab.addCode(self.opnum[opname]) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 oparg = t[1] | 
					
						
							|  |  |  |                 if opname == "SET_LINENO": | 
					
						
							|  |  |  |                     lnotab.nextLine(oparg) | 
					
						
							|  |  |  |                 hi, lo = twobyte(oparg) | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |                 try: | 
					
						
							|  |  |  |                     lnotab.addCode(self.opnum[opname], lo, hi) | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     print opname, oparg | 
					
						
							|  |  |  |                     print self.opnum[opname], lo, hi | 
					
						
							|  |  |  |                     raise | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |         self.stage = DONE | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     opnum = {} | 
					
						
							|  |  |  |     for num in range(len(dis.opname)): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         opnum[dis.opname[num]] = num | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     del num | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     def newCodeObject(self): | 
					
						
							|  |  |  |         assert self.stage == DONE | 
					
						
							|  |  |  |         if self.flags == 0: | 
					
						
							|  |  |  |             nlocals = 0 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             nlocals = len(self.varnames) | 
					
						
							|  |  |  |         argcount = self.argcount | 
					
						
							|  |  |  |         if self.flags & CO_VARKEYWORDS: | 
					
						
							|  |  |  |             argcount = argcount - 1 | 
					
						
							|  |  |  |         return new.code(argcount, nlocals, self.stacksize, self.flags, | 
					
						
							|  |  |  |                         self.lnotab.getCode(), self.getConsts(), | 
					
						
							|  |  |  |                         tuple(self.names), tuple(self.varnames), | 
					
						
							| 
									
										
										
										
											2000-05-02 22:32:59 +00:00
										 |  |  |                         self.filename, self.name, self.lnotab.firstline, | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |                         self.lnotab.getTable()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getConsts(self): | 
					
						
							|  |  |  |         """Return a tuple for the const slot of the code object
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Must convert references to code (MAKE_FUNCTION) to code | 
					
						
							|  |  |  |         objects recursively. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         l = [] | 
					
						
							|  |  |  |         for elt in self.consts: | 
					
						
							|  |  |  |             if isinstance(elt, PyFlowGraph): | 
					
						
							|  |  |  |                 elt = elt.getCode() | 
					
						
							|  |  |  |             l.append(elt) | 
					
						
							|  |  |  |         return tuple(l) | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | def isJump(opname): | 
					
						
							|  |  |  |     if opname[:4] == 'JUMP': | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | class TupleArg: | 
					
						
							|  |  |  |     """Helper for marking func defs with nested tuples in arglist""" | 
					
						
							|  |  |  |     def __init__(self, count, names): | 
					
						
							|  |  |  |         self.count = count | 
					
						
							|  |  |  |         self.names = names | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "TupleArg(%s, %s)" % (self.count, self.names) | 
					
						
							|  |  |  |     def getName(self): | 
					
						
							|  |  |  |         return ".nested%d" % self.count | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | def getArgCount(args): | 
					
						
							|  |  |  |     argcount = len(args) | 
					
						
							|  |  |  |     if args: | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |         for arg in args: | 
					
						
							|  |  |  |             if isinstance(arg, TupleArg): | 
					
						
							|  |  |  |                 numNames = len(misc.flatten(arg.names)) | 
					
						
							|  |  |  |                 argcount = argcount - numNames | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     return argcount | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  | def twobyte(val): | 
					
						
							|  |  |  |     """Convert an int argument into high and low bytes""" | 
					
						
							|  |  |  |     assert type(val) == types.IntType | 
					
						
							|  |  |  |     return divmod(val, 256) | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class LineAddrTable: | 
					
						
							|  |  |  |     """lnotab
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     This class builds the lnotab, which is undocumented but described | 
					
						
							|  |  |  |     by com_set_lineno in compile.c.  Here's an attempt at explanation: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     For each SET_LINENO instruction after the first one, two bytes are | 
					
						
							|  |  |  |     added to lnotab.  (In some cases, multiple two-byte entries are | 
					
						
							|  |  |  |     added.)  The first byte is the distance in bytes between the | 
					
						
							|  |  |  |     instruction for the last SET_LINENO and the current SET_LINENO. | 
					
						
							|  |  |  |     The second byte is offset in line numbers.  If either offset is | 
					
						
							|  |  |  |     greater than 255, multiple two-byte entries are added -- one entry | 
					
						
							|  |  |  |     for each factor of 255. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self.code = [] | 
					
						
							|  |  |  |         self.codeOffset = 0 | 
					
						
							|  |  |  |         self.firstline = 0 | 
					
						
							|  |  |  |         self.lastline = 0 | 
					
						
							|  |  |  |         self.lastoff = 0 | 
					
						
							|  |  |  |         self.lnotab = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-03-06 18:53:14 +00:00
										 |  |  |     def addCode(self, *args): | 
					
						
							|  |  |  |         for arg in args: | 
					
						
							|  |  |  |             self.code.append(chr(arg)) | 
					
						
							|  |  |  |         self.codeOffset = self.codeOffset + len(args) | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def nextLine(self, lineno): | 
					
						
							|  |  |  |         if self.firstline == 0: | 
					
						
							|  |  |  |             self.firstline = lineno | 
					
						
							|  |  |  |             self.lastline = lineno | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # compute deltas | 
					
						
							|  |  |  |             addr = self.codeOffset - self.lastoff | 
					
						
							|  |  |  |             line = lineno - self.lastline | 
					
						
							| 
									
										
										
										
											2000-09-01 20:47:37 +00:00
										 |  |  |             # Python assumes that lineno always increases with | 
					
						
							|  |  |  |             # increasing bytecode address (lnotab is unsigned char). | 
					
						
							|  |  |  |             # Depending on when SET_LINENO instructions are emitted | 
					
						
							|  |  |  |             # this is not always true.  Consider the code: | 
					
						
							|  |  |  |             #     a = (1, | 
					
						
							|  |  |  |             #          b) | 
					
						
							|  |  |  |             # In the bytecode stream, the assignment to "a" occurs | 
					
						
							|  |  |  |             # after the loading of "b".  This works with the C Python | 
					
						
							|  |  |  |             # compiler because it only generates a SET_LINENO instruction | 
					
						
							|  |  |  |             # for the assignment. | 
					
						
							|  |  |  |             if line > 0: | 
					
						
							|  |  |  |                 while addr > 0 or line > 0: | 
					
						
							|  |  |  |                     # write the values in 1-byte chunks that sum | 
					
						
							|  |  |  |                     # to desired value | 
					
						
							|  |  |  |                     trunc_addr = addr | 
					
						
							|  |  |  |                     trunc_line = line | 
					
						
							|  |  |  |                     if trunc_addr > 255: | 
					
						
							|  |  |  |                         trunc_addr = 255 | 
					
						
							|  |  |  |                     if trunc_line > 255: | 
					
						
							|  |  |  |                         trunc_line = 255 | 
					
						
							|  |  |  |                     self.lnotab.append(trunc_addr) | 
					
						
							|  |  |  |                     self.lnotab.append(trunc_line) | 
					
						
							|  |  |  |                     addr = addr - trunc_addr | 
					
						
							|  |  |  |                     line = line - trunc_line | 
					
						
							|  |  |  |                 self.lastline = lineno | 
					
						
							|  |  |  |                 self.lastoff = self.codeOffset | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def getCode(self): | 
					
						
							|  |  |  |         return string.join(self.code, '') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getTable(self): | 
					
						
							|  |  |  |         return string.join(map(chr, self.lnotab), '') | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | class StackDepthTracker: | 
					
						
							| 
									
										
										
										
											2000-03-16 20:06:59 +00:00
										 |  |  |     # XXX 1. need to keep track of stack depth on jumps | 
					
						
							|  |  |  |     # XXX 2. at least partly as a result, this code is broken | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def findDepth(self, insts): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         depth = 0 | 
					
						
							|  |  |  |         maxDepth = 0 | 
					
						
							|  |  |  |         for i in insts: | 
					
						
							|  |  |  |             opname = i[0] | 
					
						
							|  |  |  |             delta = self.effect.get(opname, 0) | 
					
						
							|  |  |  |             if delta > 1: | 
					
						
							|  |  |  |                 depth = depth + delta | 
					
						
							|  |  |  |             elif delta < 0: | 
					
						
							|  |  |  |                 if depth > maxDepth: | 
					
						
							|  |  |  |                     maxDepth = depth | 
					
						
							|  |  |  |                 depth = depth + delta | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if depth > maxDepth: | 
					
						
							|  |  |  |                     maxDepth = depth | 
					
						
							|  |  |  |                 # now check patterns | 
					
						
							| 
									
										
										
										
											2000-05-02 22:32:59 +00:00
										 |  |  |                 for pat, pat_delta in self.patterns: | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |                     if opname[:len(pat)] == pat: | 
					
						
							| 
									
										
										
										
											2000-05-02 22:32:59 +00:00
										 |  |  |                         delta = pat_delta | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |                         depth = depth + delta | 
					
						
							|  |  |  |                         break | 
					
						
							|  |  |  |                 # if we still haven't found a match | 
					
						
							|  |  |  |                 if delta == 0: | 
					
						
							| 
									
										
										
										
											2000-05-02 22:32:59 +00:00
										 |  |  |                     meth = getattr(self, opname, None) | 
					
						
							|  |  |  |                     if meth is not None: | 
					
						
							|  |  |  |                         depth = depth + meth(i[1]) | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |             if depth < 0: | 
					
						
							|  |  |  |                 depth = 0 | 
					
						
							|  |  |  |         return maxDepth | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     effect = { | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         'POP_TOP': -1, | 
					
						
							|  |  |  |         'DUP_TOP': 1, | 
					
						
							|  |  |  |         'SLICE+1': -1, | 
					
						
							|  |  |  |         'SLICE+2': -1, | 
					
						
							|  |  |  |         'SLICE+3': -2, | 
					
						
							|  |  |  |         'STORE_SLICE+0': -1, | 
					
						
							|  |  |  |         'STORE_SLICE+1': -2, | 
					
						
							|  |  |  |         'STORE_SLICE+2': -2, | 
					
						
							|  |  |  |         'STORE_SLICE+3': -3, | 
					
						
							|  |  |  |         'DELETE_SLICE+0': -1, | 
					
						
							|  |  |  |         'DELETE_SLICE+1': -2, | 
					
						
							|  |  |  |         'DELETE_SLICE+2': -2, | 
					
						
							|  |  |  |         'DELETE_SLICE+3': -3, | 
					
						
							|  |  |  |         'STORE_SUBSCR': -3, | 
					
						
							|  |  |  |         'DELETE_SUBSCR': -2, | 
					
						
							|  |  |  |         # PRINT_EXPR? | 
					
						
							|  |  |  |         'PRINT_ITEM': -1, | 
					
						
							|  |  |  |         'LOAD_LOCALS': 1, | 
					
						
							|  |  |  |         'RETURN_VALUE': -1, | 
					
						
							|  |  |  |         'EXEC_STMT': -2, | 
					
						
							|  |  |  |         'BUILD_CLASS': -2, | 
					
						
							|  |  |  |         'STORE_NAME': -1, | 
					
						
							|  |  |  |         'STORE_ATTR': -2, | 
					
						
							|  |  |  |         'DELETE_ATTR': -1, | 
					
						
							|  |  |  |         'STORE_GLOBAL': -1, | 
					
						
							|  |  |  |         'BUILD_MAP': 1, | 
					
						
							|  |  |  |         'COMPARE_OP': -1, | 
					
						
							|  |  |  |         'STORE_FAST': -1, | 
					
						
							| 
									
										
										
										
											2000-10-12 20:23:23 +00:00
										 |  |  |         'IMPORT_STAR': -1, | 
					
						
							|  |  |  |         'IMPORT_NAME': 0, | 
					
						
							|  |  |  |         'IMPORT_FROM': 1, | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     # use pattern match | 
					
						
							|  |  |  |     patterns = [ | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         ('BINARY_', -1), | 
					
						
							|  |  |  |         ('LOAD_', 1), | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2000-03-06 18:53:14 +00:00
										 |  |  |      | 
					
						
							|  |  |  |     # special cases: | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |     # UNPACK_SEQUENCE, BUILD_TUPLE, | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     # BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE | 
					
						
							| 
									
										
										
										
											2000-08-12 20:32:46 +00:00
										 |  |  |     def UNPACK_SEQUENCE(self, count): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         return count | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     def BUILD_TUPLE(self, count): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         return -count | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     def BUILD_LIST(self, count): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         return -count | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     def CALL_FUNCTION(self, argc): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         hi, lo = divmod(argc, 256) | 
					
						
							|  |  |  |         return lo + hi * 2 | 
					
						
							| 
									
										
										
										
											2000-05-02 22:32:59 +00:00
										 |  |  |     def CALL_FUNCTION_VAR(self, argc): | 
					
						
							|  |  |  |         return self.CALL_FUNCTION(argc)+1 | 
					
						
							|  |  |  |     def CALL_FUNCTION_KW(self, argc): | 
					
						
							|  |  |  |         return self.CALL_FUNCTION(argc)+1 | 
					
						
							|  |  |  |     def CALL_FUNCTION_VAR_KW(self, argc): | 
					
						
							|  |  |  |         return self.CALL_FUNCTION(argc)+2 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     def MAKE_FUNCTION(self, argc): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         return -argc | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |     def BUILD_SLICE(self, argc): | 
					
						
							| 
									
										
										
										
											2000-02-21 22:46:00 +00:00
										 |  |  |         if argc == 2: | 
					
						
							|  |  |  |             return -1 | 
					
						
							|  |  |  |         elif argc == 3: | 
					
						
							|  |  |  |             return -2 | 
					
						
							| 
									
										
										
										
											2000-02-14 14:14:29 +00:00
										 |  |  |      | 
					
						
							|  |  |  | findDepth = StackDepthTracker().findDepth |