[pypy-svn] r50426 - pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler

arigo at codespeak.net arigo at codespeak.net
Mon Jan 7 16:26:36 CET 2008


Author: arigo
Date: Mon Jan  7 16:26:30 2008
New Revision: 50426

Modified:
   pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pyassem.py
   pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pycodegen.py
Log:
Start pyassem from scratch, copy-pasting some bits of the old one.


Modified: pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pyassem.py
==============================================================================
--- pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pyassem.py	(original)
+++ pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pyassem.py	Mon Jan  7 16:26:30 2008
@@ -1,449 +1,19 @@
-"""A flow graph representation for Python bytecode"""
-
-import sys
-
-from pypy.interpreter.astcompiler import misc, ast
 from pypy.interpreter.astcompiler.consts \
      import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
 from pypy.interpreter.pycode import PyCode
-from pypy.interpreter.baseobjspace import W_Root
 from pypy.tool import stdlib_opcode as pythonopcode
 from pypy.interpreter.error import OperationError
 
+
 class InternalCompilerError(Exception):
     """Something went wrong in the ast compiler."""
 
 
-class BlockSet:
-    """A Set implementation specific to Blocks
-    it uses Block.bid as keys to underlying dict"""
-    def __init__(self):
-        self.elts = {}
-    def __len__(self):
-        return len(self.elts)
-    def __contains__(self, elt):
-        return elt.bid in self.elts
-    def add(self, elt):
-        self.elts[elt.bid] = elt
-    def elements(self):
-        return self.elts.values()
-    def has_elt(self, elt):
-        return elt.bid in self.elts
-    def remove(self, elt):
-        del self.elts[elt.bid]
-    def copy(self):
-        c = BlockSet()
-        c.elts.update(self.elts)
-        return c
-
-
-class Instr:
-    has_arg = False
-    
-    def __init__(self, op):
-        self.op = op
-
-class InstrWithArg(Instr):
-    has_arg = True
-
-class InstrName(InstrWithArg):
-    def __init__(self, inst, name):
-        Instr.__init__(self, inst)
-        self.name = name
-
-    def getArg(self):
-        "NOT_RPYTHON"
-        return self.name
-
-class InstrInt(InstrWithArg):
-    def __init__(self, inst, intval):
-        Instr.__init__(self, inst)
-        self.intval = intval
-
-    def getArg(self):
-        "NOT_RPYTHON"
-        return self.intval        
-
-class InstrBlock(InstrWithArg):
-    def __init__(self, inst, block):
-        Instr.__init__(self, inst)
-        self.block = block
-
-    def getArg(self):
-        "NOT_RPYTHON"
-        return self.block        
-
-class InstrObj(InstrWithArg):
-    def __init__(self, inst, obj):
-        Instr.__init__(self, inst)
-        self.obj = obj
-
-    def getArg(self):
-        "NOT_RPYTHON"
-        return self.obj
-
-class InstrCode(InstrWithArg):
-    def __init__(self, inst, gen):
-        Instr.__init__(self, inst)
-        self.gen = gen
-
-    def getArg(self):
-        "NOT_RPYTHON"
-        return self.gen
-
-class FlowGraph:
-    def __init__(self, space):
-        self.space = space
-        self.current = self.entry = Block(space)
-        self.exit = Block(space,"exit")
-        self.blocks = BlockSet()
-        self.blocks.add(self.entry)
-        self.blocks.add(self.exit)
-
-    def startBlock(self, block):
-        if self._debug:
-            if self.current:
-                print "end", repr(self.current)
-                print "    next", self.current.next
-                print "   ", self.current.get_children()
-            print repr(block)
-        assert block is not None
-        self.current = block
-
-    def nextBlock(self, block=None):
-        # XXX think we need to specify when there is implicit transfer
-        # 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.
-        #
-        # 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
-        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().
-
-        self.current.addNext(block)
-        self.startBlock(block)
-
-    def newBlock(self):
-        b = Block(self.space)
-        self.blocks.add(b)
-        return b
-
-    def startExitBlock(self):
-        self.startBlock(self.exit)
-
-    _debug = 0
-
-    def _enable_debug(self):
-        self._debug = 1
-
-    def _disable_debug(self):
-        self._debug = 0
-
-    def emit(self, inst):
-        if self._debug:
-            print "\t", inst
-        if inst in ['RETURN_VALUE', 'YIELD_VALUE']:
-            self.current.addOutEdge(self.exit)
-        self.current.emit( Instr(inst) )
-
-    #def emitop(self, inst, arg ):
-    #    if self._debug:
-    #        print "\t", inst, arg
-    #    self.current.emit( (inst,arg) )
-
-    def emitop_obj(self, inst, obj ):
-        if self._debug:
-            print "\t", inst, repr(obj)
-        self.current.emit( InstrObj(inst,obj) )
-
-    def emitop_code(self, inst, obj ):
-        if self._debug:
-            print "\t", inst, repr(obj)
-        self.current.emit( InstrCode(inst, obj) )
-
-    def emitop_int(self, inst, intval ):
-        if self._debug:
-            print "\t", inst, intval
-        assert isinstance(intval,int)
-        self.current.emit( InstrInt(inst,intval) )
-        
-    def emitop_block(self, inst, block):
-        if self._debug:
-            print "\t", inst, block
-        assert isinstance(block, Block)
-        self.current.addOutEdge( block )
-        self.current.emit( InstrBlock(inst,block) )
-
-    def emitop_name(self, inst, name ):
-        if self._debug:
-            print "\t", inst, name
-        assert isinstance(name,str)
-        self.current.emit( InstrName(inst,name) )
-
-    def getBlocksInOrder(self):
-        """Return the blocks in reverse postorder
-
-        i.e. each node appears before all of its successors
-        """
-        # TODO: What we need here is a topological sort that
-        
-        
-        # 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()
-        self.fixupOrder(order, self.exit)
-        # hack alert
-        if not self.exit in order:
-            order.append(self.exit)
-
-        return order
-
-    def fixupOrder(self, blocks, default_next):
-        """Fixup bad order introduced by DFS."""
-
-        # XXX This is a total mess.  There must be a better way to get
-        # the code blocks in the right order.
-
-        self.fixupOrderHonorNext(blocks, default_next)
-        self.fixupOrderForward(blocks, default_next)
-
-    def fixupOrderHonorNext(self, blocks, default_next):
-        """Fix one problem with DFS.
-
-        The DFS uses child block, but doesn't know about the special
-        "next" block.  As a result, the DFS can order blocks so that a
-        block isn't next to the right block for implicit control
-        transfers.
-        """
-        new_blocks = blocks
-        blocks = blocks[:]
-        del new_blocks[:]
-        i = 0
-        while i < len(blocks) - 1:
-            b = blocks[i]
-            n = blocks[i + 1]
-            i += 1
-            new_blocks.append(b)
-            if not b.next or b.next[0] == default_next or b.next[0] == n:
-                continue
-            # The blocks are in the wrong order.  Find the chain of
-            # blocks to insert where they belong.
-            cur = b
-            chain = []
-            elt = cur
-            while elt.next and elt.next[0] != default_next:
-                chain.append(elt.next[0])
-                elt = elt.next[0]
-            # Now remove the blocks in the chain from the current
-            # block list, so that they can be re-inserted.
-            for b in chain:
-                for j in range(i + 1, len(blocks)):
-                    if blocks[j] == b:
-                        del blocks[j]
-                        break
-                else:
-                    assert False, "Can't find block"
-                    
-            new_blocks.extend(chain)
-        if i == len(blocks) - 1:
-            new_blocks.append(blocks[i])
-            
-    def fixupOrderForward(self, blocks, default_next):
-        """Make sure all JUMP_FORWARDs jump forward"""
-        index = {}
-        chains = []
-        cur = []
-        for b in blocks:
-            index[b.bid] = len(chains)
-            cur.append(b)
-            if b.next and b.next[0] == default_next:
-                chains.append(cur)
-                cur = []
-        chains.append(cur)
-
-        while 1:
-            constraints = []
-
-            for i in range(len(chains)):
-                l = chains[i]
-                for b in l:
-                    for c in b.get_children():
-                        if index[c.bid] < i:
-                            forward_p = 0
-                            for inst in b.insts:
-                                # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-                                # other bytecodes need the same logic, but
-                                # trying to do that throws this function into
-                                # an infinite loop.  Sad sad sad.
-                                # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-                                if inst.op == 'JUMP_FORWARD':
-                                    assert isinstance(inst, InstrBlock)
-                                    if inst.block == c:
-                                        forward_p = 1
-                            if not forward_p:
-                                continue
-                            constraints.append((index[c.bid], i))
-
-            if not constraints:
-                break
-
-            # XXX just do one for now
-            # do swaps to get things in the right order
-            goes_before, a_chain = constraints[0]
-            assert a_chain > goes_before >= 0
-            c = chains[a_chain]
-            del chains[a_chain]
-            chains.insert(goes_before, c)
-
-        del blocks[:]
-        for c in chains:
-            for b in c:
-                blocks.append(b)
-
-    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
-
-def dfs_postorder(b, seen):
-    """Depth-first search of tree rooted at b, return in postorder"""
-    order = []
-    seen[b.bid] = b
-    for c in b.get_children():
-        if c.bid in seen:
-            continue
-        order = order + dfs_postorder(c, seen)
-    order.append(b)
-    return order
-
-BlockCounter = misc.Counter(0)
-
-class Block:
-
-    def __init__(self, space, label=''):
-        self.insts = []
-        self.inEdges = BlockSet()
-        self.outEdges = BlockSet()
-        self.label = label
-        self.bid = BlockCounter.next()
-        self.next = []
-        self.space = space
-
-    def __repr__(self):
-        if self.label:
-            return "<block %s id=%d>" % (self.label, self.bid)
-        else:
-            return "<block id=%d>" % (self.bid)
-
-    def __str__(self):
-        insts = [ str(i) for i in  self.insts ]
-        return "<block %s %d:\n%s>" % (self.label, self.bid,
-                                       '\n'.join(insts))
-
-    def emit(self, inst):
-        op = inst.op
-        if op[:4] == 'JUMP':
-            assert isinstance(inst, InstrBlock)
-            self.outEdges.add(inst.block)
-##         if op=="LOAD_CONST":
-##             assert isinstance( inst[1], W_Root ) or hasattr( inst[1], 'getCode')
-        self.insts.append( inst )
-
-    def getInstructions(self):
-        return self.insts
-
-    def addInEdge(self, block):
-        self.inEdges.add(block)
-
-    def addOutEdge(self, block):
-        self.outEdges.add(block)
-
-    def addNext(self, block):
-        self.next.append(block)
-        assert len(self.next) == 1, [ str(i) for i in self.next ]
-
-    _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS', 'YIELD_VALUE',
-                        'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP')
-
-    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:
-            inst = self.insts[-1]
-        except (IndexError, ValueError):
-            return
-        if inst.op in self._uncond_transfer:
-            self.next = []
-
-    def get_children(self):
-        if self.next and self.next[0].bid in self.outEdges.elts:
-            self.outEdges.remove(self.next[0])
-        return self.outEdges.elements() + self.next
-
-    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 isinstance(inst, InstrCode):
-                gen = inst.gen
-                if gen:
-                    contained.append(gen)
-        return contained
-
-# flags for code objects
-
-# the FlowGraph is transformed in place; it exists in one of these states
-RAW = "RAW"
-FLAT = "FLAT"
-CONV = "CONV"
-DONE = "DONE"
-
-class PyFlowGraph(FlowGraph):
+class PyFlowGraph(object):
 
     def __init__(self, space, name, filename, argnames=None,
                  optimized=0, klass=0, newlocals=0):
-        FlowGraph.__init__(self, space)
+        self.space = space
         if argnames is None:
             argnames = []
         self.name = name
@@ -471,8 +41,8 @@
         # kinds of variables.
         self.closure = []
         self.varnames = list(argnames)
-        self.stage = RAW
-        self.orderedblocks = []
+        # The bytecode we are building, as a list of characters
+        self.co_code = []
 
     def setDocstring(self, doc):
         self.docstring = doc
@@ -492,273 +62,78 @@
     def setCellVars(self, names):
         self.cellvars = names
 
-    def getCode(self):
-        """Get a Python code object"""
-        if self.stage == RAW:
-            self.computeStackDepth()
-            self.convertArgs()
-        if self.stage == CONV:
-            self.flattenGraph()
-        if self.stage == FLAT:
-            self.makeByteCode()
-        if self.stage == DONE:
-            return self.newCodeObject()
-        raise InternalCompilerError("inconsistent PyFlowGraph state")
-
-    def dump(self, io=None):
-        if io:
-            save = sys.stdout
-            sys.stdout = io
-        pc = 0
-        for t in self.insts:
-            opname = t.op
-            if opname == "SET_LINENO":
-                print
-            if not t.has_arg:
-                print "\t", "%3d" % pc, opname
-                pc = pc + 1
-            else:
-                print "\t", "%3d" % pc, opname, t.getArg()
-                pc = pc + 3
-        if io:
-            sys.stdout = save
-
-    def _max_depth(self, depth, seen, b, d):
-        if b in seen:
-            return d
-        seen[b] = 1
-        d = d + depth[b]
-        children = b.get_children()
-        if children:
-            maxd = -1
-            for c in children:
-                childd =self._max_depth(depth, seen, c, d)
-                if childd > maxd:
-                    maxd = childd
-            return maxd
-        else:
-            if not b.label == "exit":
-                return self._max_depth(depth, seen, self.exit, d)
-            else:
-                return d
-
-    def computeStackDepth(self):
-        """Compute the max stack depth.
-
-        Approach is to compute the stack effect of each basic block.
-        Then find the path through the code with the largest total
-        effect.
-        """
-        depth = {}
-        exit = None
-        for b in self.getBlocks():
-            depth[b] = findDepth(b.getInstructions())
-
-        seen = {}
-
-        self.stacksize = self._max_depth( depth, seen, self.entry, 0)
-
-    def flattenGraph(self):
-        """Arrange the blocks in order and resolve jumps"""
-        assert self.stage == CONV
-        self.insts = insts = []
-        firstline = 0
-        pc = 0
-        begin = {}
-        end = {}
-        forward_refs = []
-        for b in self.orderedblocks:
-            # Prune any setlineno before the 'implicit return' block.
-            if b is self.exit:
-                while len(insts) and insts[-1].op == "SET_LINENO":
-                    insts.pop()
-            begin[b] = pc
-            for inst in b.getInstructions():
-                if not inst.has_arg:
-                    insts.append(inst)
-                    pc = pc + 1
-                elif inst.op != "SET_LINENO":
-                    if inst.op in self.hasjrel:
-                        assert isinstance(inst, InstrBlock)
-                        # relative jump - no extended arg
-                        block = inst.block
-                        inst = InstrInt(inst.op, 0)
-                        forward_refs.append( (block,  inst, pc) )
-                        insts.append(inst)
-                        pc = pc + 3
-                    elif inst.op in self.hasjabs:
-                        # absolute jump - can be extended if backward
-                        assert isinstance(inst, InstrBlock)
-                        arg = inst.block
-                        if arg in begin:
-                            # can only extend argument if backward
-                            offset = begin[arg]
-                            hi = offset // 65536
-                            lo = offset % 65536
-                            if hi>0:
-                                # extended argument
-                                insts.append( InstrInt("EXTENDED_ARG", hi) )
-                                pc = pc + 3
-                            inst = InstrInt(inst.op, lo)
-                        else:
-                            inst = InstrInt(inst.op, 0)
-                            forward_refs.append( (arg,  inst, pc ) )
-                        insts.append(inst)
-                        pc = pc + 3
-                    else:
-                        assert isinstance(inst, InstrInt)
-                        arg = inst.intval
-                        # numerical arg
-                        hi = arg // 65536
-                        lo = arg % 65536
-                        if hi>0:
-                            # extended argument
-                            insts.append( InstrInt("EXTENDED_ARG", hi) )
-                            inst.intval = lo
-                            pc = pc + 3    
-                        insts.append(inst)
-                        pc = pc + 3
-                else:
-                    insts.append(inst)
-                    if firstline == 0:
-                        firstline = inst.intval
-            end[b] = pc
-        pc = 0
-
-        for block, inst, pc in forward_refs:
-            opname = inst.op
-            abspos = begin[block]
-            if opname in self.hasjrel:
-                offset = abspos - pc - 3
-                if offset < 0:
-                    raise InternalCompilerError("unexpected backward jump")
-                inst.intval = offset
-            else:
-                inst.intval = abspos
-        self.firstline = firstline
-        self.stage = FLAT
-
-    hasjrel = {}
-    for i in pythonopcode.hasjrel:
-        hasjrel[pythonopcode.opname[i]] = True
-    hasjabs = {}
-    for i in pythonopcode.hasjabs:
-        hasjabs[pythonopcode.opname[i]] = True
+    # ____________________________________________________________
+    # Simple instructions
 
-    def setconst(self, w_consts, w_item, value):
-        space = self.space
-        w_item_type = space.type(w_item)
-        w_key = space.newtuple([w_item, w_item_type])
-        space.setitem(w_consts, w_key, space.wrap(value))
-
-    def convertArgs(self):
-        """Convert arguments from symbolic to concrete form"""
-        assert self.stage == RAW
-        space = self.space
-        self.orderedblocks = self.getBlocksInOrder()
-        self.setconst(self.w_consts, self.docstring, 0)
-        #self.const_list.insert(0, self.docstring)
-        self.sort_cellvars()
-
-        for b in self.orderedblocks:
-            insts = b.getInstructions()
-            for i in range(len(insts)):
-                inst = insts[i]
-                if inst.has_arg:
-                    opname = inst.op
-                    conv = self._converters.get(opname, None)
-                    if conv:
-                        insts[i] = conv(self, inst)
-        self.stage = CONV
+    def emit(self, opname):
+        self.co_code.append(chr(pythonopcode.opmap[opname]))
 
-    def sort_cellvars(self):
-        """Sort cellvars in the order of varnames and prune from freevars.
-        """
-        cells = {}
-        for name in self.cellvars:
-            cells[name] = 1
-        self.cellvars = [name for name in self.varnames
-                         if name in cells]
-        for name in self.cellvars:
-            del cells[name]
-        self.cellvars = self.cellvars + cells.keys()
-        self.closure = self.cellvars + self.freevars
+    def emitop_extended_arg(self, intval):
+        assert intval <= 0x7FFFFFFF
+        self.emit('EXTENDED_ARG')
+        self.co_code.append(chr((intval >> 16) & 0xFF))
+        self.co_code.append(chr((intval >> 24) & 0xFF))
+        return intval & 0xFFFF
+    emitop_extended_arg._dont_inline_ = True
+
+    def emitop_int(self, opname, intval):
+        assert intval >= 0
+        if opname == "SET_LINENO":
+            return  # XXX
+        if intval > 0xFFFF:
+            intval = self.emitop_extended_arg(intval)
+        self.emit(opname)
+        self.co_code.append(chr(intval & 0xFF))
+        self.co_code.append(chr(intval >> 8))
 
-    def _lookupName(self, name, list):
-        """Return index of name in list, appending if necessary
-        """
-        assert isinstance(name, str)
-        for i in range(len(list)):
-            if list[i] == name:
-                return i
-        end = len(list)
-        list.append(name)
-        return end
+    # ____________________________________________________________
+    # Instructions with an object argument (LOAD_CONST)
 
-    def _cmpConsts(self, w_left, w_right):
-        space = self.space
-        t = space.type(w_left)
-        if space.is_w(t, space.type(w_right)):
-            if space.is_w(t, space.w_tuple):
-                left_len = space.int_w(space.len(w_left))
-                right_len = space.int_w(space.len(w_right))
-                if left_len == right_len:
-                    for i in range(left_len):
-                        w_lefti = space.getitem(w_left, space.wrap(i))
-                        w_righti = space.getitem(w_right, space.wrap(i))
-                        if not self._cmpConsts(w_lefti, w_righti):
-                            return False
-                    return True
-            elif space.eq_w(w_left, w_right):
-                 return True
-        return False
+    def emitop_obj(self, opname, w_obj):
+        index = self._lookupConst(w_obj, self.w_consts)
+        self.emitop_int(opname, index)
 
     def _lookupConst(self, w_obj, w_dict):
-        """
-        This routine uses a list instead of a dictionary, because a
-        dictionary can't store two different keys if the keys have the
-        same value but different types, e.g. 2 and 2L.  The compiler
-        must treat these two separately, so it does an explicit type
-        comparison before comparing the values.
-        """
         space = self.space
         w_obj_type = space.type(w_obj)
+        w_key = space.newtuple([w_obj, w_obj_type])
         try:
-            w_key = space.newtuple([w_obj, w_obj_type])
-            return space.int_w(space.getitem(w_dict, w_key))
+            w_result = space.getitem(w_dict, w_key)
         except OperationError, operr:
             if not operr.match(space, space.w_KeyError):
                 raise
-            lgt = space.int_w(space.len(w_dict))
-            self.setconst(w_dict, w_obj, lgt)
-            return lgt
-
-    _converters = {}
+            w_result = space.len(w_dict)
+            space.setitem(w_dict, w_key, w_result)
+        return space.int_w(w_result)
+
+    # ____________________________________________________________
+    # Instructions with a name argument
+
+    def emitop_name(self, opname, name):
+        conv = self._converters[opname]
+        index = conv(self, name)
+        self.emitop_int(opname, index)
 
-    def _convert_LOAD_CONST(self, inst):
-        if isinstance(inst, InstrCode):
-            w_obj = inst.gen.getCode()
-        else:
-            assert isinstance(inst, InstrObj)
-            w_obj = inst.obj
-        #assert w_obj is not None
-        index = self._lookupConst(w_obj, self.w_consts)
-        return InstrInt(inst.op, index)
+    def _lookupName(self, name, list):
+        """Return index of name in list, appending if necessary
+        """
+        # XXX use dicts instead of lists
+        assert isinstance(name, str)
+        for i in range(len(list)):
+            if list[i] == name:
+                return i
+        end = len(list)
+        list.append(name)
+        return end
 
-    def _convert_LOAD_FAST(self, inst):
-        assert isinstance(inst, InstrName)
-        arg = inst.name
+    def _convert_LOAD_FAST(self, arg):
         self._lookupName(arg, self.names)
-        index= self._lookupName(arg, self.varnames)
-        return InstrInt(inst.op, index)
+        return self._lookupName(arg, self.varnames)
     _convert_STORE_FAST = _convert_LOAD_FAST
     _convert_DELETE_FAST = _convert_LOAD_FAST
 
-    def _convert_NAME(self, inst):
-        assert isinstance(inst, InstrName)
-        arg = inst.name        
-        index = self._lookupName(arg, self.names)
-        return InstrInt(inst.op, index)        
+    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
@@ -772,73 +147,30 @@
     _convert_DELETE_GLOBAL = _convert_NAME
     _convert_LOOKUP_METHOD = _convert_NAME
 
-    def _convert_DEREF(self, inst):
-        assert isinstance(inst, InstrName)
-        arg = inst.name               
+    def _convert_DEREF(self, arg):
         self._lookupName(arg, self.names)
-        index = self._lookupName(arg, self.closure)
-        return InstrInt(inst.op, index)                
+        return self._lookupName(arg, self.closure)
     _convert_LOAD_DEREF = _convert_DEREF
     _convert_STORE_DEREF = _convert_DEREF
 
-    def _convert_LOAD_CLOSURE(self, inst):
-        assert isinstance(inst, InstrName)
-        arg = inst.name                
-        index = self._lookupName(arg, self.closure)
-        return InstrInt(inst.op, index)
-    
-    _cmp = list(pythonopcode.cmp_op)
-    def _convert_COMPARE_OP(self, inst):
-        assert isinstance(inst, InstrName)
-        arg = inst.name                        
-        index = self._cmp.index(arg)
-        return InstrInt(inst.op, index)
-    
+    def _convert_LOAD_CLOSURE(self, arg):
+        return self._lookupName(arg, self.closure)
 
-    # similarly for other opcodes...
+    _cmp = list(pythonopcode.cmp_op)
+    def _convert_COMPARE_OP(self, arg):
+        return self._cmp.index(arg)
 
+    _converters = {}
     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 == FLAT
-        self.lnotab = lnotab = LineAddrTable(self.firstline)
-        for t in self.insts:
-            opname = t.op
-            if self._debug:
-                if not t.has_arg:
-                    print "x",opname
-                else:
-                    print "x",opname, t.getArg()
-            if not t.has_arg:
-                lnotab.addCode1(self.opnum[opname])
-            else:
-                assert isinstance(t, InstrInt)
-                oparg = t.intval
-                if opname == "SET_LINENO":
-                    lnotab.nextLine(oparg)
-                    continue
-                hi, lo = twobyte(oparg)
-                try:
-                    lnotab.addCode3(self.opnum[opname], lo, hi)
-                except ValueError:
-                    if self._debug:
-                        print opname, oparg
-                        print self.opnum[opname], lo, hi
-                    raise
-        self.stage = DONE
-
-    opnum = {}
-    for num in range(len(pythonopcode.opname)):
-        opnum[pythonopcode.opname[num]] = num
-        # This seems to duplicate dis.opmap from opcode.opmap
-    del num
+    # ____________________________________________________________
 
-    def newCodeObject(self):
-        assert self.stage == DONE
+    def getCode(self):
+        self.stacksize = 20  # XXX!
         if (self.flags & CO_NEWLOCALS) == 0:
             nlocals = 0
         else:
@@ -846,243 +178,27 @@
         argcount = self.argcount
         if self.flags & CO_VARKEYWORDS:
             argcount = argcount - 1
-        # was return new.code, now we just return the parameters and let
-        # the caller create the code object
         return PyCode( self.space, argcount, nlocals,
                        self.stacksize, self.flags,
-                       self.lnotab.getCode(),
+                       ''.join(self.co_code),
                        self.getConsts(),
                        self.names,
                        self.varnames,
                        self.filename, self.name,
-                       self.firstline,
-                       self.lnotab.getTable(),
+                       1,     # XXX! self.firstline,
+                       "",    # XXX! self.lnotab.getTable(),
                        self.freevars,
                        self.cellvars
                        )
 
     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.
         """
         space = self.space
-        l_w = [None] * space.int_w(space.len(self.w_consts))
         keys_w = space.unpackiterable(self.w_consts)
+        l_w = [None] * len(keys_w)
         for w_key in keys_w:
             index = space.int_w(space.getitem(self.w_consts, w_key))
             w_v = space.unpacktuple(w_key)[0]
             l_w[index] = w_v
         return l_w
-
-def isJump(opname):
-    if opname[:4] == 'JUMP':
-        return 1
-
-def twobyte(val):
-    """Convert an int argument into high and low bytes"""
-    assert isinstance(val,int)
-    assert 0 <= val < 65536
-    hi = val // 256
-    lo = val % 256
-    return hi, lo
-
-class LineAddrTable:
-    """lnotab
-
-    This class builds the lnotab, which is documented in compile.c.
-    Here's a brief recap:
-
-    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 -- see
-    compile.c for the delicate details.
-    """
-
-    def __init__(self, firstline):
-        self.code = []
-        self.codeOffset = 0
-        self.firstline = firstline
-        self.lastline = firstline
-        self.lastoff = 0
-        self.lnotab = []
-
-    def addCode1(self, op ):
-        self.code.append(chr(op))
-        self.codeOffset = self.codeOffset + 1
-
-    def addCode3(self, op, hi, lo):
-        self.code.append(chr(op))
-        self.code.append(chr(hi))
-        self.code.append(chr(lo))
-        self.codeOffset = self.codeOffset + 3
-
-    def nextLine(self, lineno):
-        # compute deltas
-        addr = self.codeOffset - self.lastoff
-        line = lineno - self.lastline
-        # 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:
-            push = self.lnotab.append
-            while addr > 255:
-                push(255); push(0)
-                addr -= 255
-            while line > 255:
-                push(addr); push(255)
-                line -= 255
-                addr = 0
-            if addr > 0 or line > 0:
-                push(addr); push(line)
-            self.lastline = lineno
-            self.lastoff = self.codeOffset
-
-    def getCode(self):
-        return ''.join(self.code)
-
-    def getTable(self):
-        return ''.join( [ chr(i) for i in  self.lnotab ] )
-
-
-def depth_UNPACK_SEQUENCE(count):
-    return count-1
-def depth_BUILD_TUPLE(count):
-    return -count+1
-def depth_BUILD_LIST(count):
-    return -count+1
-def depth_CALL_FUNCTION(argc):
-    hi = argc//256
-    lo = argc%256
-    return -(lo + hi * 2)
-def depth_CALL_FUNCTION_VAR(argc):
-    return depth_CALL_FUNCTION(argc)-1
-def depth_CALL_FUNCTION_KW(argc):
-    return depth_CALL_FUNCTION(argc)-1
-def depth_CALL_FUNCTION_VAR_KW(argc):
-    return depth_CALL_FUNCTION(argc)-2
-def depth_CALL_METHOD(argc):
-    return -argc-1
-def depth_MAKE_FUNCTION(argc):
-    return -argc
-def depth_MAKE_CLOSURE(argc):
-    # XXX need to account for free variables too!
-    return -argc
-def depth_BUILD_SLICE(argc):
-    if argc == 2:
-        return -1
-    elif argc == 3:
-        return -2
-    assert False, 'Unexpected argument %s to depth_BUILD_SLICE' % argc
-    
-def depth_DUP_TOPX(argc):
-    return argc
-
-DEPTH_OP_TRACKER = {
-    "UNPACK_SEQUENCE" : depth_UNPACK_SEQUENCE,
-    "BUILD_TUPLE" : depth_BUILD_TUPLE,
-    "BUILD_LIST" : depth_BUILD_LIST,
-    "CALL_FUNCTION" : depth_CALL_FUNCTION,
-    "CALL_FUNCTION_VAR" : depth_CALL_FUNCTION_VAR,
-    "CALL_FUNCTION_KW" : depth_CALL_FUNCTION_KW,
-    "CALL_FUNCTION_VAR_KW" : depth_CALL_FUNCTION_VAR_KW,
-    "MAKE_FUNCTION" : depth_MAKE_FUNCTION,
-    "MAKE_CLOSURE" : depth_MAKE_CLOSURE,
-    "BUILD_SLICE" : depth_BUILD_SLICE,
-    "DUP_TOPX" : depth_DUP_TOPX,
-    }
-
-class StackDepthTracker:
-    # XXX 1. need to keep track of stack depth on jumps
-    # XXX 2. at least partly as a result, this code is broken
-    # XXX 3. Don't need a class here!
-
-    def findDepth(self, insts, debug=0):
-        depth = 0
-        maxDepth = 0
-        for i in insts:
-            opname = i.op
-            if debug:
-                print i,
-            delta = self.effect.get(opname, sys.maxint)
-            if delta != sys.maxint:
-                depth = depth + delta
-            else:
-                # now check patterns
-                for pat, pat_delta in self.patterns:
-                    if opname[:len(pat)] == pat:
-                        delta = pat_delta
-                        depth = depth + delta
-                        break
-                # if we still haven't found a match
-                if delta == sys.maxint:
-                    meth = DEPTH_OP_TRACKER.get( opname, None )
-                    if meth is not None:
-                        assert isinstance(i, InstrInt)
-                        depth = depth + meth(i.intval)
-            if depth > maxDepth:
-                maxDepth = depth
-            if debug:
-                print depth, maxDepth
-        return maxDepth
-
-    effect = {
-        '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,
-        'RETURN_VALUE': -1,
-        'YIELD_VALUE': -1,
-        'EXEC_STMT': -3,
-        'BUILD_CLASS': -2,
-        'STORE_NAME': -1,
-        'STORE_ATTR': -2,
-        'DELETE_ATTR': -1,
-        'STORE_GLOBAL': -1,
-        'BUILD_MAP': 1,
-        'COMPARE_OP': -1,
-        'STORE_FAST': -1,
-        'IMPORT_STAR': -1,
-        'IMPORT_NAME': 0,
-        'IMPORT_FROM': 1,
-        'LOAD_ATTR': 0, # unlike other loads
-        # close enough...
-        'SETUP_EXCEPT': 3,
-        'SETUP_FINALLY': 3,
-        'FOR_ITER': 1,
-        'WITH_CLEANUP': 3,
-        'LOOKUP_METHOD': 1,
-        'LIST_APPEND': -2,
-        }
-    # use pattern match
-    patterns = [
-        ('BINARY_', -1),
-        ('LOAD_', 1),
-        ]
-
-
-findDepth = StackDepthTracker().findDepth

Modified: pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pycodegen.py
==============================================================================
--- pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pycodegen.py	(original)
+++ pypy/branch/simpler-pyassem/pypy/interpreter/astcompiler/pycodegen.py	Mon Jan  7 16:26:30 2008
@@ -161,7 +161,9 @@
         return self.graph.emitop_obj( inst, obj )
 
     def emitop_code(self, inst, gen):
-        return self.graph.emitop_code( inst, gen )    
+        code = gen.getCode()
+        w_code = self.space.wrap(code)
+        return self.graph.emitop_obj( inst, w_code )
 
     def emitop_int(self, inst, op):
         assert isinstance(op, int)
@@ -170,14 +172,10 @@
     def emitop_block(self, inst, block):
         return self.graph.emitop_block( inst, block )
 
-    def nextBlock(self, block=None ):
+    def nextBlock(self, block ):
         """graph delegation"""
         return self.graph.nextBlock( block )
 
-    def startBlock(self, block ):
-        """graph delegation"""
-        return self.graph.startBlock( block )
-
     def newBlock(self):
         """graph delegation"""
         return self.graph.newBlock()
@@ -392,11 +390,10 @@
             self.set_lineno(test)
             nextTest = self.newBlock()
             test.opt_accept_jump_if(self, False, nextTest)
-            self.nextBlock()
             self.emit('POP_TOP')
             suite.accept( self )
             self.emitop_block('JUMP_FORWARD', end)
-            self.startBlock(nextTest)
+            self.nextBlock(nextTest)
             self.emit('POP_TOP')
         if node.else_:
             node.else_.accept( self )
@@ -422,15 +419,14 @@
         self.set_lineno(node, force=True)
         if is_constant_true(self.space, node.test):
             # "while 1:"
-            self.nextBlock()
+            pass
         else:
             node.test.opt_accept_jump_if(self, False, else_)
-            self.nextBlock()
             self.emit('POP_TOP')
         node.body.accept( self )
         self.emitop_block('JUMP_ABSOLUTE', loop)
 
-        self.startBlock(else_) # or just the POPs if not else clause
+        self.nextBlock(else_) # or just the POPs if not else clause
         self.emit('POP_TOP')
         self.emit('POP_BLOCK')
         self.setups.pop()
@@ -475,7 +471,6 @@
         if kind == LOOP:
             self.set_lineno(node)
             self.emitop_block('JUMP_ABSOLUTE', block)
-            self.nextBlock()
         elif kind == EXCEPT or kind == TRY_FINALLY:
             self.set_lineno(node)
             # find the block that starts the loop
@@ -492,7 +487,6 @@
             if kind != LOOP:
                 raise SyntaxError( "'continue' not properly in loop", node.lineno)
             self.emitop_block('CONTINUE_LOOP', loop_block)
-            self.nextBlock()
         elif kind == END_FINALLY:
             msg = "'continue' not supported inside 'finally' clause"
             raise SyntaxError( msg, node.lineno )
@@ -502,7 +496,6 @@
         for child in node.nodes[:-1]:
             child.accept( self )
             self.emitop_block(jump, end)
-            self.nextBlock()
             self.emit('POP_TOP')
         node.nodes[-1].accept( self )
         self.nextBlock(end)
@@ -585,7 +578,6 @@
             self.emit('ROT_THREE')
             self.emitop('COMPARE_OP', op)
             self.emitop_block('JUMP_IF_FALSE', cleanup)
-            self.nextBlock()
             self.emit('POP_TOP')
         # now do the last comparison
         if node.ops:
@@ -595,7 +587,7 @@
         if len(node.ops) > 1:
             end = self.newBlock()
             self.emitop_block('JUMP_FORWARD', end)
-            self.startBlock(cleanup)
+            self.nextBlock(cleanup)
             self.emit('ROT_TWO')
             self.emit('POP_TOP')
             self.nextBlock(end)
@@ -634,11 +626,11 @@
             if cont:
                 skip_one = self.newBlock()
                 self.emitop_block('JUMP_FORWARD', skip_one)
-                self.startBlock(cont)
+                self.nextBlock(cont)
                 self.emit('POP_TOP')
                 self.nextBlock(skip_one)
             self.emitop_block('JUMP_ABSOLUTE', start)
-            self.startBlock(anchor)
+            self.nextBlock(anchor)
         self._implicitNameOp('DELETE', tmpname)
 
         self.__list_count = self.__list_count - 1
@@ -652,7 +644,6 @@
         self.nextBlock(start)
         self.set_lineno(node, force=True)
         self.emitop_block('FOR_ITER', anchor)
-        self.nextBlock()
         node.assign.accept( self )
         return start, anchor
 
@@ -711,11 +702,11 @@
             if cont:
                 skip_one = self.newBlock()
                 self.emitop_block('JUMP_FORWARD', skip_one)
-                self.startBlock(cont)
+                self.nextBlock(cont)
                 self.emit('POP_TOP')
                 self.nextBlock(skip_one)
             self.emitop_block('JUMP_ABSOLUTE', start)
-            self.startBlock(anchor)
+            self.nextBlock(anchor)
         self.emitop_obj('LOAD_CONST', self.space.w_None)
 
     def _visitGenExprFor(self, node):
@@ -731,7 +722,6 @@
         self.nextBlock(start)
         self.set_lineno(node, force=True)
         self.emitop_block('FOR_ITER', anchor)
-        self.nextBlock()
         node.assign.accept( self )
         return start, anchor
 
@@ -752,9 +742,7 @@
             # XXX AssertionError appears to be special case -- it is always
             # loaded as a global even if there is a local name.  I guess this
             # is a sort of renaming op.
-            self.nextBlock()
             node.test.opt_accept_jump_if(self, True, end)
-            self.nextBlock()
             self.emit('POP_TOP')
             self.emitop('LOAD_GLOBAL', 'AssertionError')
             if node.fail:
@@ -795,7 +783,7 @@
         self.emit('POP_BLOCK')
         self.setups.pop()
         self.emitop_block('JUMP_FORWARD', lElse)
-        self.startBlock(handlers)
+        self.nextBlock(handlers)
 
         last = len(node.handlers) - 1
         next = None
@@ -807,7 +795,6 @@
                 self.emitop('COMPARE_OP', 'exception match')
                 next = self.newBlock()
                 self.emitop_block('JUMP_IF_FALSE', next)
-                self.nextBlock()
                 self.emit('POP_TOP')
             else:
                 next = None
@@ -1444,7 +1431,6 @@
         return self.module
 
     def finish(self):
-        self.graph.startExitBlock()
         if not self.isLambda:
             self.emitop_obj('LOAD_CONST', self.space.w_None)
         self.emit('RETURN_VALUE')
@@ -1517,7 +1503,6 @@
         return self.module
 
     def finish(self):
-        self.graph.startExitBlock()
         self.emit('LOAD_LOCALS')
         self.emit('RETURN_VALUE')
 



More information about the Pypy-commit mailing list