copypropagation.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 534 行 · 第 1/2 页

SCALA
534
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author  Martin Odersky */// $Id: CopyPropagation.scala 14416 2008-03-19 01:17:25Z mihaylov $package scala.tools.nsc.backend.icode.analysisimport scala.collection.mutable.{Map, HashMap}import scala.tools.nsc.symtab.Flags.DEFERRED/** A modified copy-propagation like analysis. It  *  is augmented with a record-like value which is used *  to represent closures. * *  @author Iulian Dragos */abstract class CopyPropagation {  val global: Global  import global._  import icodes._  /** Locations can be local variables, this, and fields. */  abstract sealed class Location;  case class LocalVar(l: Local) extends Location  case class Field(r: Record, sym: Symbol) extends Location  case object This extends Location  /** Values that can be on the stack. */  abstract class Value {    def isRecord = false  }  case class Record(cls: Symbol, bindings: Map[Symbol, Value]) extends Value {    override def isRecord = true  }  case class Deref(l: Location) extends Value  case class Boxed(l: Location) extends Value  case object Unknown extends Value  object AllRecords extends Record(NoSymbol, new HashMap[Symbol, Value])  /** The lattice for this analysis.   */  object copyLattice extends CompleteLattice {    type Bindings = Map[Location, Value]    def emptyBinding = new HashMap[Location, Value]()    class State(val bindings: Bindings, var stack: List[Value]) {      override def equals(that: Any): Boolean =         (this eq that.asInstanceOf[AnyRef]) ||        that.isInstanceOf[State] && {          val other = that.asInstanceOf[State]          /* comparison with bottom is reference equality! */          if ((other eq bottom) || (this eq bottom))            (this eq other)          else {            this.bindings == other.bindings &&            List.forall2(this.stack, other.stack) { (a, b) => a == b }          }        }      /* Return an alias for the given local. It returns the last       * local in the chain of aliased locals. Cycles are not allowed       * to exist (by construction).       */      def getAlias(l: Local): Local = {        var target = l        var stop = false                while (bindings.isDefinedAt(LocalVar(target)) && !stop) {          bindings(LocalVar(target)) match {            case Deref(LocalVar(t)) => target = t            case _ => stop = true          }        }        target      }      /* Return the value bound to the given local. */      def getBinding(l: Local): Value = {        var target = l        var stop = false        var value: Value = Deref(LocalVar(target))                while (bindings.isDefinedAt(LocalVar(target)) && !stop) {//          Console.println("finding binding for " + target)          value = bindings(LocalVar(target))          value match {            case Deref(LocalVar(t)) => target = t            case _ => stop = true          }        }        value      }      /* Return the binding for the given field of the given record */      def getBinding(r: Record, f: Symbol): Value = {        assert(r.bindings.isDefinedAt(f),               "Record " + r + " does not contain a field " + f);        var target: Value = r.bindings(f);        target match {          case Deref(LocalVar(sym)) => getBinding(sym)          case _ => target        }      }            /** Return a local which contains the same value as this field, if any. */      def getLocalForField(r: Record, f: Symbol): Option[Value] = {        assert(r.bindings.isDefinedAt(f),            "Record " + r + " does not contain a field " + f);        var target: Value = r.bindings(f)        target match {          case Deref(LocalVar(l)) => Some(Deref(LocalVar(getAlias(l))))          case Deref(This)    => Some(target)          case _  => None        }      }      override def toString(): String =        "\nBindings: " + bindings + "\nStack: " + stack;      def dup: State = {        val b: Bindings = new HashMap()        b ++= bindings        new State(b, stack)      }    }    type Elem = State    val top    = new State(emptyBinding, Nil)    val bottom = new State(emptyBinding, Nil)    val exceptionHandlerStack = Unknown :: Nil    def lub2(a: Elem, b: Elem): Elem = {      if (a eq bottom)      b      else if (b eq bottom) a      else if (a == b) a      else {        val resStack =           if (a.stack eq exceptionHandlerStack) a.stack          else if (b.stack eq exceptionHandlerStack) b.stack          else {            if (a.stack.length != b.stack.length)              throw new LubError(a, b, "Invalid stacks in states: ");            List.map2(a.stack, b.stack) { (v1, v2) =>               if (v1 == v2) v1 else Unknown             }          }      /*        if (a.stack.length != b.stack.length)          throw new LubError(a, b, "Invalid stacks in states: ");        val resStack = List.map2(a.stack, b.stack) { (v1, v2) =>           if (v1 == v2) v1 else Unknown         }        */        val commonPairs = a.bindings.toList intersect (b.bindings.toList)        val resBindings = new HashMap[Location, Value]        for ((k, v) <- commonPairs)          resBindings += (k -> v);        new State(resBindings, resStack)      }    }  }  final class CopyAnalysis extends DataFlowAnalysis[copyLattice.type] {    type P = BasicBlock    val lattice = copyLattice    var method: IMethod = _    def init(m: IMethod) {      this.method = m      init {        worklist += m.code.startBlock        worklist ++= (m.exh map (_.startBlock))        m.code.blocks.foreach { b =>          in(b)  = lattice.bottom          out(b) = lattice.bottom          assert(out.contains(b))          log("Added point: " + b)        }         m.exh foreach { e =>          in(e.startBlock) = new copyLattice.State(copyLattice.emptyBinding, copyLattice.exceptionHandlerStack);        }        // first block is special: it's not bottom, but a precisely defined state with no bindings        in(m.code.startBlock) = new lattice.State(lattice.emptyBinding, Nil);      }    }    override def run {      forwardAnalysis(blockTransfer)      if (settings.debug.value) {        linearizer.linearize(method).foreach(b => if (b != method.code.startBlock)          assert(in(b) != lattice.bottom,             "Block " + b + " in " + this.method + " has input equal to bottom -- not visited?"));      }    }    def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem =      b.toList.foldLeft(in)(interpret)        import opcodes._    /** Abstract interpretation for one instruction. */    def interpret(in: copyLattice.Elem, i: Instruction): copyLattice.Elem = {      var out = in.dup      if (settings.debug.value) {        log("- " + i)        log("in: " + in)        log("\n")      }      i match {        case THIS(_) =>          out.stack = Deref(This) :: out.stack        case CONSTANT(k) =>          if (k.tag != UnitTag)            out.stack = Unknown :: out.stack;                  case LOAD_ARRAY_ITEM(_) =>          out.stack = (Unknown :: out.stack.drop(2))        case LOAD_LOCAL(local) =>          out.stack = Deref(LocalVar(local)) :: out.stack        case LOAD_FIELD(field, isStatic) =>          if (isStatic)            out.stack = Unknown :: out.stack; /* ignore static fields */          else {            val v1 = in.stack match {              case (r @ Record(cls, bindings)) :: xs =>                Deref(Field(r, field))              case _ => Unknown            }            out.stack = v1 :: out.stack.drop(1)          }                    case LOAD_MODULE(module) =>          out.stack = Unknown :: out.stack                  case STORE_ARRAY_ITEM(kind) =>          out.stack = out.stack.drop(3)        case STORE_LOCAL(local) =>          cleanReferencesTo(out, LocalVar(local))          in.stack match {            case Unknown :: xs => ()            case v :: vs =>               v match {                case Deref(LocalVar(other)) =>                  if (other != local)                     out.bindings += (LocalVar(local) -> v);                case _ =>                  out.bindings += (LocalVar(local) -> v)              }            case Nil =>              Predef.error("Incorrect icode in " + method + ". Expecting something on the stack.")

⌨️ 快捷键说明

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