basicblocks.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 445 行

SCALA
445
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author  Martin Odersky */// $Id: BasicBlocks.scala 13720 2008-01-17 17:09:38Z dragos $package scala.tools.nsc.backend.icode//import scala.tools.nsc.ast._import scala.collection.mutable.{Map, Set}import scala.collection.jcl.LinkedHashSetimport scala.tools.nsc.util.{Position,NoPosition}import scala.tools.nsc.backend.icode.analysis.ProgramPointtrait BasicBlocks {  self: ICodes =>  import opcodes._  /** This class represents a basic block. Each   *  basic block contains a list of instructions that are   *  either executed all, or none. No jumps   *  to/from the "middle" of the basic block are allowed.   */  class BasicBlock (theLabel: Int, val method: IMethod)        extends AnyRef        with ProgramPoint[BasicBlock] {    def code = method.code        /** The label of the block */    val label = theLabel    /** When set, the <code>emit</code> methods will be ignored. */    var ignore: Boolean = false    var preds: List[BasicBlock] = null    /** Is this block the head of a while? */    var loopHeader = false        /** Is this block the start block of an exception handler? */    var exceptionHandlerHeader = false        /** Local variables that are in scope at entry of this basic block. Used     *  for debugging information.     */    var varsInScope: Set[Local] = new LinkedHashSet()        /** ICode instructions, used as temporary storage while emitting code.     * Once closed is called, only the `instrs' array should be used.     */    private var instructionList: List[Instruction] = Nil    private var _lastInstruction: Instruction = null    private var closed: Boolean = false    private var instrs: Array[Instruction] = _    private var touched = false    def toList: List[Instruction] = {      if (closed && touched)        instructionList = List.fromArray(instrs)      instructionList    }        /** return the underlying array of instructions */    def getArray: Array[Instruction] = {      assert(closed)      instrs    }    def fromList(is: List[Instruction]) {      instrs = toInstructionArray(is)      closed = true    }    // public:    /** Return the index of inst. Uses reference equality.     *  Returns -1 if not found.     */    def indexOf(inst: Instruction): Int = {      assert(closed)      var i = 0      while (i < instrs.length) {        if (instrs(i) eq inst) return i        i += 1      }      -1    }    /** Compute an hashCode for the block *///    override def hashCode() = label;    /** Apply a function to all the instructions of the block. */    def traverse(f: Instruction => Unit) = {      if (!closed) {        dump        global.abort("Traversing an open block!: " + label)      }      instrs foreach f    }    def traverseBackwards(f: Instruction => Unit) = {      var i = instrs.length - 1      while (i >= 0) {        f(instrs(i))        i -= 1      }    }    /** The number of instructions in this basic block so far. */    def size: Int =      if (isClosed)        instrs.length      else        instructionList.length    /** Return the index of the instruction which produced the value      *  consumed by the given instruction.      */    def findDef(pos: Int): Option[Int] = {      assert(closed)      var i = pos      var d = 0      while (i > 0) {        i -= 1        val prod = instrs(i).produced        if (prod > 0 && d == 0)          return Some(i)        d += (instrs(i).consumed - instrs(i).produced)      }      None    }        /** Return the n-th instruction. */    def apply(n: Int): Instruction =      if (closed)        instrs(n)      else        instructionList.reverse(n)    ///////////////////// Substitutions ///////////////////////    /**     * Replace the instruction at the given position. Used by labels when     * they are anchored. It retains the position of the previous instruction.     */    def replaceInstruction(pos: Int, instr: Instruction): Boolean = {      assert(closed, "Instructions can be replaced only after the basic block is closed")      instr.pos = instrs(pos).pos      instrs(pos) = instr      true    }    /**     * Replace the given instruction with the new one.      * Returns `true' if it actually changed something.      * It retains the position of the previous instruction.     */    def replaceInstruction(oldInstr: Instruction, newInstr: Instruction): Boolean = {      assert(closed, "Instructions can be replaced only after the basic block is closed")      var i = 0      var changed = false      while (i < instrs.length && !changed) {        if (instrs(i) == oldInstr) {          newInstr.pos = oldInstr.pos          instrs(i) = newInstr          changed = true        }        i += 1      }      changed    }    /** Replaces <code>iold</code> with <code>is</code>. It does not update     *  the position field in the newly inserted instrucitons, so it behaves     *  differently than the one-instruction versions of this function.     *     *  @param iold ..     *  @param is   ..     *  @return     ..     */    def replaceInstruction(iold: Instruction, is: List[Instruction]): Boolean = {      assert(closed, "Instructions can be replaced only after the basic block is closed")      var i = 0      var changed = false      while (i < instrs.length && (instrs(i) ne iold))        i += 1      if (i < instrs.length) {        val newInstrs = new Array[Instruction](instrs.length + is.length - 1);        changed = true        Array.copy(instrs, 0, newInstrs, 0, i)        var j = i        for (val x <- is) {          newInstrs(j) = x          j += 1        }        if (i + 1 < instrs.length)          Array.copy(instrs, i + 1, newInstrs, j, instrs.length - i - 1)        instrs = newInstrs;      }      changed    }        /** Insert instructions in 'is' immediately after index 'idx'. */    def insertAfter(idx: Int, is: List[Instruction]) {      assert(closed, "Instructions can be replaced only after the basic block is closed")      var i = idx + 1      if (i < instrs.length) {        val newInstrs = new Array[Instruction](instrs.length + is.length);        Array.copy(instrs, 0, newInstrs, 0, i)        var j = i        for (val x <- is) {          newInstrs(j) = x          j += 1        }        if (i + 1 < instrs.length)          Array.copy(instrs, i + 1, newInstrs, j, instrs.length - i)        instrs = newInstrs;      }    }    /** Removes instructions found at the given positions.     *     *  @param positions ...     */    def removeInstructionsAt(positions: Int*) {      assert(closed)      val removed = positions.toList      val newInstrs = new Array[Instruction](instrs.length - positions.length)      var i = 0      var j = 0      while (i < instrs.length) {        if (!removed.contains(i)) {          newInstrs(j) = instrs(i)          j += 1        }        i += 1      }      instrs = newInstrs    }        /** Remove the last instruction of this basic block. It is     *  fast for an open block, but slower when the block is closed.     */    def removeLastInstruction: Unit = {      if (closed)         removeInstructionsAt(size)      else {        instructionList = instructionList.tail        touched = true      }    }    /** Replaces all instructions found in the map.     *     *  @param map ...     */    def subst(map: Map[Instruction, Instruction]): Unit =      if (!closed) substOnList(map) else {        var i = 0        while (i < instrs.length) {          map get instrs(i) match {            case Some(instr) => touched = replaceInstruction(i, instr)            case None => ()          }          i = i + 1        }      }    private def substOnList(map: Map[Instruction, Instruction]) {      def subst(l: List[Instruction]): List[Instruction] = l match {        case Nil => Nil        case x :: xs =>          map.get(x) match {            case Some(newInstr) => newInstr :: subst(xs)            case None => x :: subst(xs)          }      }      instructionList = subst(instructionList)    }    ////////////////////// Emit //////////////////////    /** Add a new instruction at the end of the block,     *  using the same source position as the last emitted instruction     */    def emit(instr: Instruction): Unit =      if (!instructionList.isEmpty)        emit(instr, instructionList.head.pos)      else        emit(instr, NoPosition)    def emit(instr: Instruction, pos: Position) = {      if (closed) {        print()        Console.println("trying to emit: " + instr)      }      assert (!closed || ignore, "BasicBlock closed")      if (!ignore) {        touched = true        instr.pos = pos        instructionList = instr :: instructionList        _lastInstruction = instr      }    }        def emit(instrs: Seq[Instruction]) {      instrs foreach (i => emit(i, i.pos))    }    /** Close the block */    def close = {       assert(instructionList.length > 0,              "Empty block.")      closed = true      instructionList = instructionList.reverse      instrs = toInstructionArray(instructionList)    }    def open = {      assert(closed)      closed = false      ignore = false      instructionList = instructionList.reverse  // prepare for appending to the head    }    def clear: Unit = {      instructionList = Nil      instrs = null      preds  = null    }    def isEmpty: Boolean = instructionList.isEmpty    /** Enter ignore mode: new 'emit'ted instructions will not be     *  added to this basic block. It makes the generation of THROW     *  and RETURNs easier.     */    def enterIgnoreMode = ignore = true    def exitIgnoreMode = {      assert(ignore, "Exit ignore mode when not in ignore mode.")      ignore = false    }    /** Return the last instruction of this basic block. */    def lastInstruction =      if (closed)        instrs(instrs.length - 1)      else        instructionList.head    def firstInstruction =      if (closed)        instrs(0)      else        instructionList.last    /** Convert the list to an array */    def toInstructionArray(l: List[Instruction]): Array[Instruction] = {      var array = new Array[Instruction](l.length)      var i: Int = 0      l foreach (x => { array(i) = x; i += 1 })      array    }    def isClosed = closed    def successors : List[BasicBlock] = if (isEmpty) Nil else {      var res = lastInstruction match {        case JUMP (whereto) => List(whereto)        case CJUMP(success, failure, _, _) => failure :: success :: Nil        case CZJUMP(success, failure, _, _) => failure :: success :: Nil        case SWITCH(_,labels) => labels        case RETURN(_) => Nil        case THROW() => Nil        case _ =>          if (isClosed) {            dump            global.abort("The last instruction is not a control flow instruction: " + lastInstruction)          }          else Nil      }      method.exh.foreach { e: ExceptionHandler =>        if (e.covers(this)) res = e.startBlock :: res      }      res    }    /** Returns the precessors of this block, in the current 'code' chunk.     *  This is signifficant only if there are exception handlers, which live     *  in different code 'chunks' than the rest of the method.     */    def predecessors: List[BasicBlock] = {      preds = code.blocks.elements.filter (_.successors.contains(this)).toList      preds    }    override def equals(other: Any): Boolean = other match {      case that: BasicBlock => (that.label == label) && (that.code == code)      case _ => false    }    override def hashCode = label        // Instead of it, rather use a printer    def print() { print(java.lang.System.out) }    def print(out: java.io.PrintStream) {      out.println("block #"+label+" :")      toList.foreach(i => out.println("  " + i))      out.print("Successors: ")      successors.foreach((x: BasicBlock) => out.print(" "+x.label.toString()))      out.println()    }    def fullString: String = {      val buf = new StringBuilder()      buf.append("Block ").append(label.toString())      buf.append("\nSuccessors: ").append(successors)      buf.append("\nPredecessors: ").append(predecessors)      buf.toString()    }    override def toString(): String = "" + label  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?