typeflowanalysis.scala

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

SCALA
362
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author  Martin Odersky */// $Id: TypeFlowAnalysis.scala 14416 2008-03-19 01:17:25Z mihaylov $package scala.tools.nsc.backend.icode.analysisimport scala.collection.mutable.{Map, HashMap}/** A data-flow analysis on types, that works on <code>ICode</code>. * *  @author Iulian Dragos */abstract class TypeFlowAnalysis {  val global: Global  import global._  /** The lattice of ICode types.   */  object typeLattice extends CompleteLattice {    type Elem = icodes.TypeKind    val Object = icodes.REFERENCE(global.definitions.ObjectClass)    val All    = icodes.REFERENCE(global.definitions.AllClass)    def top    = Object    def bottom = All    def lub2(a: Elem, b: Elem) =      if (a eq bottom) b      else if (b eq bottom) a      else icodes.lub(a, b)  }  /** The lattice of type stacks. It is a straight forward extension of   *  the type lattice (lub is pairwise lub of the list elements).   */  object typeStackLattice extends CompleteLattice {    import icodes._    type Elem = TypeStack    override val top    = new TypeStack    override val bottom = new TypeStack    val exceptionHandlerStack: TypeStack = new TypeStack(List(REFERENCE(definitions.AnyRefClass)))    def lub2(s1: TypeStack, s2: TypeStack) = {      if (s1 eq bottom) s2      else if (s2 eq bottom) s1      else if (s1 eq exceptionHandlerStack) s1      else if (s2 eq exceptionHandlerStack) s2      else {        if (s1.length != s2.length)          throw new CheckerError("Incompatible stacks: " + s1 + " and " + s2);        new TypeStack(List.map2(s1.types, s2.types) (icodes.lub))      }    }  }  /** A map which returns the bottom type for unfound elements */  class VarBinding extends  HashMap[icodes.Local, icodes.TypeKind] {    override def get(l: icodes.Local) = super.get(l) match {      case Some(t) => Some(t)      case None    => Some(typeLattice.bottom)    }    def this(o: VarBinding) = {      this()      this ++= o    }  }  /** The type flow lattice contains a binding from local variable   *  names to types and a type stack.   */  object typeFlowLattice extends CompleteLattice {    import icodes._    type Elem = IState[VarBinding, icodes.TypeStack]    override val top    = new Elem(new VarBinding, typeStackLattice.top)    override val bottom = new Elem(new VarBinding, typeStackLattice.bottom)        def lub2(a: Elem, b: Elem) = {      val IState(env1, s1) = a      val IState(env2, s2) = b      val resultingLocals = new VarBinding      for (binding1 <- env1.elements) {        val tp2 = env2(binding1._1)        resultingLocals += (binding1._1 -> typeLattice.lub2(binding1._2, tp2))      }      for (binding2 <- env2.elements if resultingLocals(binding2._1) eq typeLattice.bottom) {        val tp1 = env1(binding2._1)        resultingLocals += (binding2._1 -> typeLattice.lub2(binding2._2, tp1))      }      IState(resultingLocals, typeStackLattice.lub2(a.stack, b.stack))    }  }  class MethodTFA extends DataFlowAnalysis[typeFlowLattice.type] {    import icodes._    import icodes.opcodes._    type P = BasicBlock    val lattice = typeFlowLattice    val STRING = icodes.REFERENCE(TypeFlowAnalysis.this.global.definitions.StringClass)    var method: IMethod = _    /** Initialize the in/out maps for the analysis of the given method. */    def init(m: icodes.IMethod) {      this.method = m      init {        worklist += m.code.startBlock        worklist ++= (m.exh map (_.startBlock))        m.code.blocks.foreach { b =>          in(b)  = typeFlowLattice.bottom          out(b) = typeFlowLattice.bottom        }        m.exh foreach { e =>          in(e.startBlock) = lattice.IState(in(e.startBlock).vars, typeStackLattice.exceptionHandlerStack)        }      }    }    /** reinitialize the analysis, keeping around solutions from a previous run. */    def reinit(m: icodes.IMethod) {      if ((this.method eq null) || (this.method.symbol != m.symbol))         init(m)      else reinit {        for (b <- m.code.blocks; if !in.isDefinedAt(b)) {          for (p <- b.predecessors) {            worklist += p            if (out.isDefinedAt(p))              in(b) = out(p)            else              in(b)  = typeFlowLattice.bottom          }          out(b) = typeFlowLattice.bottom        }        for (exh <- m.exh; if !in.isDefinedAt(exh.startBlock)) {          worklist += exh.startBlock          in(exh.startBlock) = lattice.IState(in(exh.startBlock).vars, typeStackLattice.exceptionHandlerStack)        }      }    }    def this(m: icodes.IMethod) {      this()      init(m)    }    def run = {      forwardAnalysis(blockTransfer)      if (settings.debug.value) {        linearizer.linearize(method).foreach(b => if (b != method.code.startBlock)          assert(visited.contains(b),             "Block " + b + " in " + this.method + " has input equal to bottom -- not visited? .." + visited));      }    }    def blockTransfer(b: BasicBlock, in: lattice.Elem): lattice.Elem = {      b.toList.foldLeft(in)(interpret)    }    /** Abstract interpretation for one instruction. */    def interpret(in: typeFlowLattice.Elem, i: Instruction): typeFlowLattice.Elem = {      val out = lattice.IState(new VarBinding(in.vars), new TypeStack(in.stack))      val bindings = out.vars      val stack = out.stack//      if (settings.debug.value) {//        Console.println("Stack: " + stack);//        Console.println(i);//      }       i match {        case THIS(clasz) =>          stack push toTypeKind(clasz.tpe)        case CONSTANT(const) =>          stack push toTypeKind(const.tpe)        case LOAD_ARRAY_ITEM(kind) =>          val Pair(idxKind, ARRAY(elem)) = stack.pop2          assert(idxKind == INT || idxKind == CHAR || idxKind == SHORT || idxKind == BYTE)          stack.push(elem)        case LOAD_LOCAL(local) =>          val t = bindings(local)          stack push (if (t == typeLattice.bottom) local.kind  else t)        case LOAD_FIELD(field, isStatic) =>          if (!isStatic)            stack.pop          stack push toTypeKind(field.tpe)        case LOAD_MODULE(module) =>          stack push toTypeKind(module.tpe)        case STORE_ARRAY_ITEM(kind) =>          stack.pop3        case STORE_LOCAL(local) =>          val t = stack.pop          bindings += (local -> t)                case STORE_THIS(_) =>          stack.pop        case STORE_FIELD(field, isStatic) =>          if (isStatic)            stack.pop          else            stack.pop2        case CALL_PRIMITIVE(primitive) =>          primitive match {            case Negation(kind) =>              stack.pop; stack.push(kind)            case Test(_, kind, zero) =>              stack.pop              if (!zero) stack.pop              stack push BOOL;            case Comparison(_, _) =>              stack.pop2              stack push INT            case Arithmetic(op, kind) =>              stack.pop              if (op != NOT)                stack.pop              val k = kind match {                case BYTE | SHORT | CHAR => INT                case _ => kind              }              stack push k            case Logical(op, kind) =>              stack.pop2              stack push kind            case Shift(op, kind) =>              stack.pop2              stack push kind            case Conversion(src, dst) =>              stack.pop              stack push dst            case ArrayLength(kind) =>              stack.pop              stack push INT            case StartConcat =>              stack.push(ConcatClass)            case EndConcat =>              stack.pop              stack.push(STRING)            case StringConcat(el) =>              stack.pop2              stack push ConcatClass          }        case CALL_METHOD(method, style) => style match {          case Dynamic =>            stack.pop(1 + method.info.paramTypes.length)            stack.push(toTypeKind(method.info.resultType))          case Static(onInstance) =>            if (onInstance) {              stack.pop(1 + method.info.paramTypes.length)              if (!method.isConstructor)                stack.push(toTypeKind(method.info.resultType));            } else {              stack.pop(method.info.paramTypes.length)              stack.push(toTypeKind(method.info.resultType))            }          case SuperCall(mix) =>            stack.pop(1 + method.info.paramTypes.length)            stack.push(toTypeKind(method.info.resultType))        }        case BOX(kind) =>          stack.pop          stack.push(BOXED(kind))        case UNBOX(kind) =>          stack.pop          stack.push(kind)        case NEW(kind) =>          stack.push(kind)        case CREATE_ARRAY(elem, dims) =>          stack.pop(dims)          stack.push(ARRAY(elem))        case IS_INSTANCE(tpe) =>          stack.pop          stack.push(BOOL)        case CHECK_CAST(tpe) =>          stack.pop          stack.push(tpe)        case SWITCH(tags, labels) =>          stack.pop        case JUMP(whereto) =>          ()        case CJUMP(success, failure, cond, kind) =>          stack.pop2        case CZJUMP(success, failure, cond, kind) =>          stack.pop        case RETURN(kind) =>          if (kind != UNIT)            stack.pop;        case THROW() =>          stack.pop        case DROP(kind) =>          stack.pop        case DUP(kind) =>          stack.push(stack.head)        case MONITOR_ENTER() =>          stack.pop        case MONITOR_EXIT() =>          stack.pop                  case SCOPE_ENTER(_) | SCOPE_EXIT(_) =>          ()        case LOAD_EXCEPTION() =>          stack.pop(stack.length)          stack.push(typeLattice.Object)                  case _ =>          dump          abort("Unknown instruction: " + i)      }      out    } // interpret  }}

⌨️ 快捷键说明

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