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 + -
显示快捷键?