summaryrefslogtreecommitdiffstats
path: root/Lib/compiler/pyassem.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/compiler/pyassem.py')
-rw-r--r--Lib/compiler/pyassem.py258
1 files changed, 128 insertions, 130 deletions
diff --git a/Lib/compiler/pyassem.py b/Lib/compiler/pyassem.py
index 6e07987..c8d9e90 100644
--- a/Lib/compiler/pyassem.py
+++ b/Lib/compiler/pyassem.py
@@ -9,71 +9,71 @@ from compiler import misc
class FlowGraph:
def __init__(self):
- self.current = self.entry = Block()
- self.exit = Block("exit")
- self.blocks = misc.Set()
- self.blocks.add(self.entry)
- self.blocks.add(self.exit)
+ self.current = self.entry = Block()
+ self.exit = Block("exit")
+ self.blocks = misc.Set()
+ self.blocks.add(self.entry)
+ self.blocks.add(self.exit)
def startBlock(self, block):
- self.current = block
+ self.current = block
def nextBlock(self, block=None):
- if block is None:
- block = self.newBlock()
- # XXX think we need to specify when there is implicit transfer
- # from one block to the next
- #
- # 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
- self.current.addNext(block)
- self.startBlock(block)
+ if block is None:
+ block = self.newBlock()
+ # XXX think we need to specify when there is implicit transfer
+ # from one block to the next
+ #
+ # 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
+ self.current.addNext(block)
+ self.startBlock(block)
def newBlock(self):
- b = Block()
- self.blocks.add(b)
- return b
+ b = Block()
+ self.blocks.add(b)
+ return b
def startExitBlock(self):
- self.startBlock(self.exit)
+ self.startBlock(self.exit)
def emit(self, *inst):
- # XXX should jump instructions implicitly call nextBlock?
- if inst[0] == 'RETURN_VALUE':
- self.current.addOutEdge(self.exit)
- self.current.emit(inst)
+ # XXX should jump instructions implicitly call nextBlock?
+ if inst[0] == 'RETURN_VALUE':
+ self.current.addOutEdge(self.exit)
+ self.current.emit(inst)
def getBlocks(self):
- """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)
- return order
+ """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)
+ return order
def dfs_postorder(b, seen):
"""Depth-first search of tree rooted at b, return in postorder"""
order = []
seen[b] = b
for c in b.children():
- if seen.has_key(c):
- continue
- order = order + dfs_postorder(c, seen)
+ if seen.has_key(c):
+ continue
+ order = order + dfs_postorder(c, seen)
order.append(b)
return order
@@ -81,47 +81,47 @@ class Block:
_count = 0
def __init__(self, label=''):
- self.insts = []
- self.inEdges = misc.Set()
- self.outEdges = misc.Set()
- self.label = label
- self.bid = Block._count
- self.next = []
- Block._count = Block._count + 1
+ self.insts = []
+ self.inEdges = misc.Set()
+ self.outEdges = misc.Set()
+ self.label = label
+ self.bid = Block._count
+ self.next = []
+ Block._count = Block._count + 1
def __repr__(self):
- if self.label:
- return "<block %s id=%d len=%d>" % (self.label, self.bid,
- len(self.insts))
- else:
- return "<block id=%d len=%d>" % (self.bid, len(self.insts))
+ if self.label:
+ return "<block %s id=%d len=%d>" % (self.label, self.bid,
+ len(self.insts))
+ else:
+ return "<block id=%d len=%d>" % (self.bid, len(self.insts))
def __str__(self):
- insts = map(str, self.insts)
- return "<block %s %d:\n%s>" % (self.label, self.bid,
- string.join(insts, '\n'))
+ insts = map(str, self.insts)
+ return "<block %s %d:\n%s>" % (self.label, self.bid,
+ string.join(insts, '\n'))
def emit(self, inst):
- op = inst[0]
- if op[:4] == 'JUMP':
- self.outEdges.add(inst[1])
- self.insts.append(inst)
+ op = inst[0]
+ if op[:4] == 'JUMP':
+ self.outEdges.add(inst[1])
+ self.insts.append(inst)
def getInstructions(self):
- return self.insts
+ return self.insts
def addInEdge(self, block):
- self.inEdges.add(block)
+ self.inEdges.add(block)
def addOutEdge(self, block):
- self.outEdges.add(block)
+ self.outEdges.add(block)
def addNext(self, block):
- self.next.append(block)
- assert len(self.next) == 1, map(str, self.next)
+ self.next.append(block)
+ assert len(self.next) == 1, map(str, self.next)
def children(self):
- return self.outEdges.elements() + self.next
+ return self.outEdges.elements() + self.next
# flags for code objects
CO_OPTIMIZED = 0x0001
@@ -139,18 +139,18 @@ class PyFlowGraph(FlowGraph):
super_init = FlowGraph.__init__
def __init__(self, name, filename, args=(), optimized=0):
- 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 = []
+ 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 = []
self.varnames = list(args) or []
for i in range(len(self.varnames)):
var = self.varnames[i]
@@ -163,13 +163,13 @@ class PyFlowGraph(FlowGraph):
self.consts.insert(0, doc)
def setFlag(self, flag):
- self.flags = self.flags | flag
- if flag == CO_VARARGS:
- self.argcount = self.argcount - 1
+ self.flags = self.flags | flag
+ if flag == CO_VARARGS:
+ self.argcount = self.argcount - 1
def getCode(self):
- """Get a Python code object"""
- if self.stage == RAW:
+ """Get a Python code object"""
+ if self.stage == RAW:
self.flattenGraph()
if self.stage == FLAT:
self.convertArgs()
@@ -198,38 +198,38 @@ class PyFlowGraph(FlowGraph):
sys.stdout = save
def flattenGraph(self):
- """Arrange the blocks in order and resolve jumps"""
- assert self.stage == RAW
- self.insts = insts = []
- pc = 0
- begin = {}
- end = {}
- for b in self.getBlocks():
- 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:
+ """Arrange the blocks in order and resolve jumps"""
+ assert self.stage == RAW
+ self.insts = insts = []
+ pc = 0
+ begin = {}
+ end = {}
+ for b in self.getBlocks():
+ 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:
pc = pc + 1
else:
pc = pc + 3
- opname = inst[0]
- if self.hasjrel.has_elt(opname):
+ opname = inst[0]
+ if self.hasjrel.has_elt(opname):
oparg = inst[1]
offset = begin[oparg] - pc
insts[i] = opname, offset
elif self.hasjabs.has_elt(opname):
insts[i] = opname, begin[inst[1]]
- self.stacksize = findDepth(self.insts)
- self.stage = FLAT
+ self.stacksize = findDepth(self.insts)
+ self.stage = FLAT
hasjrel = misc.Set()
for i in dis.hasjrel:
@@ -292,7 +292,7 @@ class PyFlowGraph(FlowGraph):
_cmp = list(dis.cmp_op)
def _convert_COMPARE_OP(self, arg):
- return self._cmp.index(arg)
+ return self._cmp.index(arg)
# similarly for other opcodes...
@@ -314,12 +314,12 @@ class PyFlowGraph(FlowGraph):
if opname == "SET_LINENO":
lnotab.nextLine(oparg)
hi, lo = twobyte(oparg)
- try:
- lnotab.addCode(self.opnum[opname], lo, hi)
- except ValueError:
- print opname, oparg
- print self.opnum[opname], lo, hi
- raise
+ try:
+ lnotab.addCode(self.opnum[opname], lo, hi)
+ except ValueError:
+ print opname, oparg
+ print self.opnum[opname], lo, hi
+ raise
self.stage = DONE
opnum = {}
@@ -354,10 +354,10 @@ class PyFlowGraph(FlowGraph):
elt = elt.getCode()
l.append(elt)
return tuple(l)
-
+
def isJump(opname):
if opname[:4] == 'JUMP':
- return 1
+ return 1
class TupleArg:
"""Helper for marking func defs with nested tuples in arglist"""
@@ -372,10 +372,10 @@ class TupleArg:
def getArgCount(args):
argcount = len(args)
if args:
- for arg in args:
- if isinstance(arg, TupleArg):
- numNames = len(misc.flatten(arg.names))
- argcount = argcount - numNames
+ for arg in args:
+ if isinstance(arg, TupleArg):
+ numNames = len(misc.flatten(arg.names))
+ argcount = argcount - numNames
return argcount
def twobyte(val):
@@ -513,11 +513,9 @@ class StackDepthTracker:
]
# special cases:
- # UNPACK_TUPLE, UNPACK_LIST, BUILD_TUPLE,
+ # UNPACK_SEQUENCE, BUILD_TUPLE,
# BUILD_LIST, CALL_FUNCTION, MAKE_FUNCTION, BUILD_SLICE
- def UNPACK_TUPLE(self, count):
- return count
- def UNPACK_LIST(self, count):
+ def UNPACK_SEQUENCE(self, count):
return count
def BUILD_TUPLE(self, count):
return -count