copypropagation.scala

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

SCALA
534
字号
          }          out.stack = out.stack drop 1;                  case STORE_THIS(_) =>          cleanReferencesTo(out, This)          out.stack = out.stack drop 1                  case STORE_FIELD(field, isStatic) =>          if (isStatic)             out.stack = out.stack.drop(1);          else {            out.stack = out.stack.drop(2);            cleanReferencesTo(out, Field(AllRecords, field));            in.stack match {              case v :: Record(_, bindings) :: vs =>                bindings += (field -> v)              case _ => ();            }          }                  case CALL_PRIMITIVE(primitive) =>          out.stack = Unknown :: out.stack.drop(i.consumed)        case CALL_METHOD(method, style) => style match {          case Dynamic =>            out = simulateCall(in, method, false)          case Static(onInstance) =>            if (onInstance) {              val obj = out.stack.drop(method.info.paramTypes.length).head//              if (method.isPrimaryConstructor) {              if (method.isPrimaryConstructor/* && isClosureClass(method.owner)*/) {                obj match {                  case Record(_, bindings) =>                    for (v <- out.stack.take(method.info.paramTypes.length + 1)                         if v ne obj) {                       bindings ++= getBindingsForPrimaryCtor(in, method);                    }                  case _ => ()                }                // put the Record back on the stack and remove the 'returned' value                out.stack = out.stack.drop(1 + method.info.paramTypes.length)              } else                out = simulateCall(in, method, false)            } else               out = simulateCall(in, method, true)          case SuperCall(_) =>            out = simulateCall(in, method, false)        }                case BOX(tpe) =>          val top = out.stack.head          top match {            case Deref(loc) =>               out.stack = Boxed(loc) :: out.stack.tail            case _ =>              out.stack = Unknown :: out.stack.drop(1)          }        case UNBOX(tpe) =>          val top = out.stack.head          top match {            case Boxed(loc) => Deref(loc) :: out.stack.tail            case _          => out.stack = Unknown :: out.stack.drop(1)          }                  case NEW(kind) =>          val v1 =             kind match {              case REFERENCE(cls) =>/*                if (isClosureClass(cls))                  Record(cls, new HashMap[Symbol, Value])                else Unknown */                Record(cls, new HashMap[Symbol, Value])              // bq: changed from _ to null, otherwise would be unreachable              case null =>                Unknown            }          out.stack = v1 :: out.stack        case CREATE_ARRAY(elem, dims) =>          out.stack = Unknown :: out.stack.drop(dims)                  case IS_INSTANCE(tpe) =>          out.stack = Unknown :: out.stack.drop(1)                  case CHECK_CAST(tpe) =>          out.stack = Unknown :: out.stack.drop(1)                  case SWITCH(tags, labels) =>          out.stack = out.stack.drop(1)                  case JUMP(whereto) =>          ()                  case CJUMP(success, failure, cond, kind) =>          out.stack = out.stack.drop(2)                  case CZJUMP(success, failure, cond, kind) =>          out.stack = out.stack.drop(1)                  case RETURN(kind) =>          if (kind != UNIT)            out.stack = out.stack.drop(1)                  case THROW() =>          out.stack = out.stack.drop(1)                  case DROP(kind) =>          out.stack = out.stack.drop(1)                  case DUP(kind) =>          out.stack = out.stack.head :: out.stack                  case MONITOR_ENTER() =>          out.stack = out.stack.drop(1);                 case MONITOR_EXIT() =>          out.stack = out.stack.drop(1)        case SCOPE_ENTER(_) | SCOPE_EXIT(_) =>          ()                case LOAD_EXCEPTION() =>          out.stack = Unknown :: Nil        case _ =>          dump          abort("Unknown instruction: " + i)      }      out    } /* def interpret */    /** Remove all references to this local variable from both stack     *  and bindings. It is called when a new assignment destroys      *  previous copy-relations.     */    final def cleanReferencesTo(s: copyLattice.State, target: Location) {      def cleanRecord(r: Record): Record = {        r.bindings retain { (loc, value) =>          value match {            case Deref(loc1) if (loc1 == target) => false            case Boxed(loc1) if (loc1 == target)  => false            case _ => true          }        }        r      }      s.stack = s.stack map { v => v match {        case Record(_, bindings) =>          cleanRecord(v.asInstanceOf[Record])        case Boxed(loc1) if (loc1 == target) => Unknown        case _ => v      }}      s.bindings retain { (loc, value) =>        (value match {          case Deref(loc1) if (loc1 == target) => false          case Boxed(loc1) if (loc1 == target) => false          case Record(_, _) =>             cleanRecord(value.asInstanceOf[Record]);            true          case _ => true        }) &&         (loc match {          case l: Location if (l == target) => false          case _ => true        })      }    }    /** Update the state <code>s</code> after the call to <code>method</code>.     *  The stack elements are dropped and replaced by the result of the call.     *  If the method is impure, all bindings to record fields are cleared.     *     *  @param state  ...     *  @param method ...     *  @param static ...     *  @return       ...     */    final def simulateCall(state: copyLattice.State, method: Symbol, static: Boolean): copyLattice.State = {      val out = new copyLattice.State(state.bindings, state.stack);      out.stack = out.stack.drop(method.info.paramTypes.length + (if (static) 0 else 1));      if (method.info.resultType != definitions.UnitClass.tpe && !method.isConstructor)        out.stack = Unknown :: out.stack;      if (!isPureMethod(method))        invalidateRecords(out);      out    }    /** Drop everything known about mutable record fields.     *     *  @param state ...     */    final def invalidateRecords(state: copyLattice.State) {      state.stack = state.stack map { v => v match {        case Record(cls, bindings) =>          bindings.retain { (sym: Symbol, v: Value) => !sym.hasFlag(symtab.Flags.MUTABLE) }          Record(cls, bindings)        case _ => v      }}      state.bindings retain {(loc, value) =>        value match {          case Deref(Field(_, _)) => false          case Boxed(Field(_, _)) => false          case _ => true        }      }    }    /** Return bindings from an object fields to the values on the stack. This     *  method has to find the correct mapping from fields to the order in which     *  they are passed on the stack. It works for primary constructors.     */    private def getBindingsForPrimaryCtor(in: copyLattice.State, ctor: Symbol): Map[Symbol, Value] = {      val paramAccessors = ctor.owner.constrParamAccessors;      var values = in.stack.take(1 + ctor.info.paramTypes.length).reverse.drop(1);      val bindings = new HashMap[Symbol, Value];      if (settings.debug.value) log("getBindings for: " + ctor)      // this relies on having the same order in paramAccessors and      // the arguments on the stack. It should be the same!      for ((p, i) <- paramAccessors.zipWithIndex) {//        assert(p.tpe == ctor.tpe.paramTypes(i), "In: " + ctor.fullNameString + " having: " + (paramAccessors map (_.tpe))+ " vs. " + ctor.tpe.paramTypes)	if (p.tpe == ctor.tpe.paramTypes(i))	  bindings += (p -> values.head);        values = values.tail;      }      if (settings.debug.value) log("\t" + bindings)      bindings    }    /** Is <code>cls</code> a closure class?     *     *  @param cls ...     *  @return    ...     */    final def isClosureClass(cls: Symbol): Boolean =         cls.isFinal &&        cls.tpe.parents.exists { t =>           val TypeRef(_, sym, _) = t;          definitions.FunctionClass exists sym.==        }    /** Is symbol <code>m</code> a pure method?     *     *  @param m ...     *  @return  ...     */    final def isPureMethod(m: Symbol): Boolean =       m.isGetter // abstract getters are still pure, as we 'know'    final override def toString(): String = {      var res = ""      for (b <- this.method.code.blocks.toList)        res = (res + "\nIN(" + b.label + "):\t Bindings: " + in(b).bindings +               "\nIN(" + b.label +"):\t Stack: " + in(b).stack) + "\n";      res    }  } /* class CopyAnalysis */}

⌨️ 快捷键说明

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