diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala | 94 |
1 files changed, 37 insertions, 57 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 53111d0ade..9d48d7a0d3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -3,7 +3,8 @@ * @author Martin Odersky */ -package scala.tools.nsc +package scala +package tools.nsc package backend.icode.analysis import scala.collection.{ mutable, immutable } @@ -26,12 +27,8 @@ abstract class CopyPropagation { case object This extends Location /** Values that can be on the stack. */ - abstract class Value { - def isRecord = false - } - case class Record(cls: Symbol, bindings: mutable.Map[Symbol, Value]) extends Value { - override def isRecord = true - } + sealed abstract class Value { } + case class Record(cls: Symbol, bindings: mutable.Map[Symbol, Value]) extends Value { } /** The value of some location in memory. */ case class Deref(l: Location) extends Value @@ -91,16 +88,6 @@ abstract class CopyPropagation { loop(l) getOrElse Deref(LocalVar(l)) } - /* Return the binding for the given field of the given record */ - def getBinding(r: Record, f: Symbol): Value = { - assert(r.bindings contains f, "Record " + r + " does not contain a field " + f) - - r.bindings(f) match { - case Deref(LocalVar(l)) => getBinding(l) - case target => target - } - } - /** Return a local which contains the same value as this field, if any. * If the field holds a reference to a local, the returned value is the * binding of that local. @@ -137,7 +124,7 @@ abstract class CopyPropagation { } override def toString(): String = - "\nBindings: " + bindings + "\nStack: " + stack; + "\nBindings: " + bindings + "\nStack: " + stack def dup: State = { val b: Bindings = mutable.HashMap() @@ -178,7 +165,7 @@ abstract class CopyPropagation { val resBindings = mutable.HashMap[Location, Value]() for ((k, v) <- a.bindings if b.bindings.isDefinedAt(k) && v == b.bindings(k)) - resBindings += (k -> v); + resBindings += (k -> v) new State(resBindings, resStack) } } @@ -203,20 +190,20 @@ abstract class CopyPropagation { debuglog("CopyAnalysis added point: " + b) } m.exh foreach { e => - in(e.startBlock) = new copyLattice.State(copyLattice.emptyBinding, copyLattice.exceptionHandlerStack); + 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.startBlock) = new lattice.State(lattice.emptyBinding, Nil); + in(m.startBlock) = new lattice.State(lattice.emptyBinding, Nil) } } override def run() { forwardAnalysis(blockTransfer) - if (settings.debug.value) { + if (settings.debug) { linearizer.linearize(method).foreach(b => if (b != method.startBlock) assert(in(b) != lattice.bottom, - "Block " + b + " in " + this.method + " has input equal to bottom -- not visited?")); + "Block " + b + " in " + this.method + " has input equal to bottom -- not visited?")) } } @@ -241,7 +228,7 @@ abstract class CopyPropagation { case CONSTANT(k) => if (k.tag != UnitTag) - out.stack = Const(k) :: out.stack; + out.stack = Const(k) :: out.stack case LOAD_ARRAY_ITEM(_) => out.stack = (Unknown :: out.stack.drop(2)) @@ -290,14 +277,14 @@ abstract class CopyPropagation { v match { case Deref(LocalVar(other)) => if (other != local) - out.bindings += (LocalVar(local) -> v); + out.bindings += (LocalVar(local) -> v) case _ => out.bindings += (LocalVar(local) -> v) } case Nil => sys.error("Incorrect icode in " + method + ". Expecting something on the stack.") } - out.stack = out.stack drop 1; + out.stack = out.stack drop 1 case STORE_THIS(_) => cleanReferencesTo(out, This) @@ -305,14 +292,14 @@ abstract class CopyPropagation { case STORE_FIELD(field, isStatic) => if (isStatic) - out.stack = out.stack.drop(1); + out.stack = out.stack.drop(1) else { - out.stack = out.stack.drop(2); - cleanReferencesTo(out, Field(AllRecords, field)); + out.stack = out.stack.drop(2) + cleanReferencesTo(out, Field(AllRecords, field)) in.stack match { case v :: Record(_, bindings) :: vs => bindings += (field -> v) - case _ => (); + case _ => () } } @@ -322,7 +309,7 @@ abstract class CopyPropagation { case CALL_METHOD(method, style) => style match { case Dynamic => - out = simulateCall(in, method, false) + out = simulateCall(in, method, static = false) case Static(onInstance) => if (onInstance) { @@ -333,19 +320,19 @@ abstract class CopyPropagation { case Record(_, bindings) => for (v <- out.stack.take(method.info.paramTypes.length + 1) if v ne obj) { - bindings ++= getBindingsForPrimaryCtor(in, method); + 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) + out = simulateCall(in, method, static = false) } else - out = simulateCall(in, method, true) + out = simulateCall(in, method, static = true) case SuperCall(_) => - out = simulateCall(in, method, false) + out = simulateCall(in, method, static = false) } case BOX(tpe) => @@ -404,7 +391,7 @@ abstract class CopyPropagation { out.stack = out.stack.head :: out.stack case MONITOR_ENTER() => - out.stack = out.stack.drop(1); + out.stack = out.stack.drop(1) case MONITOR_EXIT() => out.stack = out.stack.drop(1) @@ -452,7 +439,7 @@ abstract class CopyPropagation { case Deref(loc1) if (loc1 == target) => false case Boxed(loc1) if (loc1 == target) => false case rec @ Record(_, _) => - cleanRecord(rec); + cleanRecord(rec) true case _ => true }) && @@ -463,22 +450,17 @@ abstract class CopyPropagation { } } - /** Update the state <code>s</code> after the call to <code>method</code>. + /** Update the state `s` after the call to `method`. * 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; + 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.UnitTpe && !method.isConstructor) + out.stack = Unknown :: out.stack if (!isPureMethod(method)) - invalidateRecords(out); + invalidateRecords(out) out } @@ -519,8 +501,8 @@ abstract class CopyPropagation { * they are passed on the stack. It works for primary constructors. */ private def getBindingsForPrimaryCtor(in: copyLattice.State, ctor: Symbol): mutable.Map[Symbol, Value] = { - val paramAccessors = ctor.owner.constrParamAccessors; - var values = in.stack.take(1 + ctor.info.paramTypes.length).reverse.drop(1); + val paramAccessors = ctor.owner.constrParamAccessors + var values = in.stack.take(1 + ctor.info.paramTypes.length).reverse.drop(1) val bindings = mutable.HashMap[Symbol, Value]() debuglog("getBindings for: " + ctor + " acc: " + paramAccessors) @@ -546,24 +528,22 @@ abstract class CopyPropagation { // + " having acc: " + (paramAccessors map (_.tpe))+ " vs. params" + paramTypes // + "\n\t failed at pos " + i + " with " + p.tpe + " == " + paramTypes(i)) if (p.tpe == paramTypes(i)) - bindings += (p -> values.head); - values = values.tail; + bindings += (p -> values.head) + values = values.tail } debuglog("\t" + bindings) bindings } - /** Is symbol <code>m</code> a pure method? - * - * @param m ... - * @return ... + /** Is symbol `m` a pure method? */ final def isPureMethod(m: Symbol): Boolean = m.isGetter // abstract getters are still pure, as we 'know' final override def toString() = ( - method.blocks map { b => + if (method eq null) List("<null>") + else method.blocks map { b => "\nIN(%s):\t Bindings: %s".format(b.label, in(b).bindings) + "\nIN(%s):\t Stack: %s".format(b.label, in(b).stack) } |