diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2007-09-13 10:21:22 +0000 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2007-09-13 10:21:22 +0000 |
commit | 6900f59041b0077620a09f71f4378a1cf96b3066 (patch) | |
tree | 28e76730f87cf47c62f4101fbd74759e7e0d7d67 | |
parent | c1ce17b26427f97dacea8d36eefcd5b604dfe89b (diff) | |
download | scala-6900f59041b0077620a09f71f4378a1cf96b3066.tar.gz scala-6900f59041b0077620a09f71f4378a1cf96b3066.tar.bz2 scala-6900f59041b0077620a09f71f4378a1cf96b3066.zip |
Fixed dead code elimination phase:
- better handling of 'dead' DROP
- fixed computeCompensations (VerifyErrors in corner cases)
- fixed generation of LOAD_EXCEPTION on all exceptional paths, when optimizations enabled
9 files changed, 65 insertions, 27 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 8ea3f68ebe..ce917e5386 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -520,8 +520,6 @@ abstract class GenICode extends SubComponent { (pat.symbol.tpe.typeSymbol, kind, { ctx: Context => - if (settings.Xdce.value) - ctx.bb.emit(LOAD_EXCEPTION(), pat.pos) ctx.bb.emit(STORE_LOCAL(exception), pat.pos); val ctx1 = genLoad(body, ctx, kind); if (guardResult) { @@ -542,8 +540,6 @@ abstract class GenICode extends SubComponent { .setFlag(Flags.SYNTHETIC) .setInfo(definitions.ThrowableClass.tpe), REFERENCE(definitions.ThrowableClass), false)); - if (settings.Xdce.value) - ctx.bb.emit(LOAD_EXCEPTION()) ctx.bb.emit(STORE_LOCAL(exception)); val ctx1 = genLoad(finalizer, ctx, UNIT); ctx1.bb.emit(LOAD_LOCAL(exception)); @@ -1956,7 +1952,9 @@ abstract class GenICode extends SubComponent { val exhs = handlers.map { handler => val exh = this.newHandler(handler._1, handler._2) - val ctx1 = handler._3(outerCtx.enterHandler(exh)) + var ctx1 = outerCtx.enterHandler(exh) + if (settings.Xdce.value) ctx1.bb.emit(LOAD_EXCEPTION()) + ctx1 = handler._3(ctx1) ctx1.bb.emit(JUMP(afterCtx.bb)) ctx1.bb.close exh diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 7590dea711..2064f84af0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -65,7 +65,9 @@ trait Opcodes { self: ICodes => /** This abstract method returns the number of produced elements on the stack */ def produced : Int = 0 - /** This instruction consumes these types from the top of the stack. */ + /** This instruction consumes these types from the top of the stack, the first + * element in the list is the deepest element on the stack. + */ def consumedTypes: List[TypeKind] = Nil /** This instruction produces these types on top of the stack. */ 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 ec2e8e1c93..cca21adc98 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -452,14 +452,15 @@ abstract class CopyPropagation { out } - /** Drop everything known about record fields. + /** 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) => - Record(cls, new HashMap[Symbol, Value]) + bindings.retain { (sym: Symbol, v: Value) => !sym.hasFlag(symtab.Flags.MUTABLE) } + Record(cls, bindings) case _ => v }} diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala index e8c4436f74..e5838245c3 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala @@ -7,7 +7,8 @@ package scala.tools.nsc.backend.icode.analysis -import scala.collection.jcl.{Map, HashMap, Set, HashSet, LinkedHashSet} +import scala.collection.jcl.{HashMap, Set, HashSet, LinkedHashSet} +import scala.collection.mutable.Map /** A generic framework for data flow analysis. */ diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala index 79c3bf341b..56c1e2b83b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala @@ -209,7 +209,11 @@ abstract class TypeFlowAnalysis { stack.pop if (op != NOT) stack.pop - stack push kind + val k = kind match { + case BYTE | SHORT | CHAR => INT + case _ => kind + } + stack push k case Logical(op, kind) => stack.pop2 diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index 7defa675b4..e51e89ddbd 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -157,6 +157,10 @@ abstract class ClosureElimination extends SubComponent { case _ => () } + case Boxed(LocalVar(loc1)) :: _ => + val value = info.getBinding(loc1) + bb.replaceInstruction(i, DROP(icodes.AnyRefReference) :: valueToInstruction(value) :: Nil) + log("replaced " + i + " with " + value) case _ => () } diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala index dd66c557ce..de00968145 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala @@ -99,11 +99,21 @@ abstract class DeadCodeElimination extends SubComponent { defs = defs + ((bb, idx)) -> rd.vars // Console.println(i + ": " + (bb, idx) + " rd: " + rd + " and having: " + defs) case RETURN(_) | JUMP(_) | CJUMP(_, _, _, _) | CZJUMP(_, _, _, _) | STORE_FIELD(_, _) | - DROP(_) | THROW() | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | + THROW() | STORE_ARRAY_ITEM(_) | SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION() | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() => worklist += ((bb, idx)) - case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)) + case CALL_METHOD(m1, _) if isSideEffecting(m1) => worklist += ((bb, idx)); log("marking " + m1) case CALL_METHOD(m1, SuperCall(_)) => worklist += ((bb, idx)) // super calls to constructor + case DROP(_) => + val necessary = findDefs(bb, idx, 1) exists { p => + val (bb1, idx1) = p + bb1(idx1) match { + case CALL_METHOD(m1, _) if isSideEffecting(m1) => true + case LOAD_EXCEPTION() | DUP(_) | LOAD_MODULE(_) => true + case _ => false + } + } + if (necessary) worklist += ((bb, idx)) case _ => () } rd = rdef.interpret(bb, idx, rd); @@ -127,8 +137,10 @@ abstract class DeadCodeElimination extends SubComponent { useful(bb) += idx instr match { case LOAD_LOCAL(l1) => - for ((l2, bb1, idx1) <- defs((bb, idx)) if l1 == l2; if !useful(bb1)(idx1)) + for ((l2, bb1, idx1) <- defs((bb, idx)) if l1 == l2; if !useful(bb1)(idx1)) { + log("\tAdding " + bb1(idx1)) worklist += ((bb1, idx1)) + } case nw @ NEW(REFERENCE(sym)) => assert(nw.init ne null, "null new.init at: " + bb + ": " + idx + "(" + instr + ")") @@ -140,8 +152,10 @@ abstract class DeadCodeElimination extends SubComponent { () case _ => - for ((bb1, idx1) <- findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) + for ((bb1, idx1) <- findDefs(bb, idx, instr.consumed) if !useful(bb1)(idx1)) { + log("\tAdding " + bb1(idx1)) worklist += ((bb1, idx1)) + } } } } @@ -195,10 +209,12 @@ abstract class DeadCodeElimination extends SubComponent { assert(bb.isClosed, "Open block in computeCompensations") for ((i, idx) <- bb.toList.zipWithIndex) { if (!useful(bb)(idx)) { - val defs = findDefs(bb, idx, i.consumed) - for (d <- defs) { - if (!compensations.isDefinedAt(d)) - compensations(d) = i.consumedTypes map DROP + for ((consumedType, depth) <- i.consumedTypes.reverse.zipWithIndex) { + val defs = findDefs(bb, idx, i.consumed, depth) + for (d <- defs) { + if (!compensations.isDefinedAt(d)) + compensations(d) = List(DROP(consumedType)) + } } } } @@ -230,7 +246,11 @@ abstract class DeadCodeElimination extends SubComponent { abort("could not find init in: " + method) } - def findDefs(bb: BasicBlock, idx: Int, m: Int): List[(BasicBlock, Int)] = if (idx > 0) { + /** Return the instructions that produced the 'm' elements on the stack, below given 'depth'. + * for instance, findefs(bb, idx, 1, 1) returns the instructions that might have produced the + * value found below the topmost element of the stack. + */ + def findDefs(bb: BasicBlock, idx: Int, m: Int, depth: Int): List[(BasicBlock, Int)] = if (idx > 0) { assert(bb.isClosed) var instrs = bb.getArray var res: List[(BasicBlock, Int)] = Nil @@ -266,12 +286,20 @@ abstract class DeadCodeElimination extends SubComponent { stack.take(m) flatMap (_.toList) } + /** Return the definitions that produced the topmost 'm' elements on the stack, + * and that reach the instruction at index 'idx' in basic block 'bb'. + */ + def findDefs(bb: BasicBlock, idx: Int, m: Int): List[(BasicBlock, Int)] = + findDefs(bb, idx, m, 0) + /** Is 'sym' a side-effecting method? TODO: proper analysis. */ private def isSideEffecting(sym: Symbol): Boolean = { !(sym.isGetter // for testing only || (sym.isConstructor && sym.owner.owner == definitions.getModule("scala.runtime").moduleClass) - || (sym.isConstructor && inliner.isClosureClass(sym.owner))) + || (sym.isConstructor && inliner.isClosureClass(sym.owner)) +/* || definitions.isBox(sym) + || definitions.isUnbox(sym)*/) } } /* DeadCode */ } diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 177b7301f5..c7d33a7693 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -308,6 +308,7 @@ abstract class Inliners extends SubComponent { if (settings.debug.value) log("\tlooked up method: " + concreteMethod.fullNameString) } + if (settings.debug.value) log("Treating " + i + "\n\tclasses.contains: " + classes.contains(receiver) @@ -335,12 +336,11 @@ abstract class Inliners extends SubComponent { callsPrivate -= m; } else { if (settings.debug.value) - log("inline failed because:\n\tinc.symbol != m.symbol: " + (inc.symbol != m.symbol) + log("inline failed for " + inc + " because:\n\tinc.symbol != m.symbol: " + (inc.symbol != m.symbol) + "\n\t(inlinedMethods(inc.symbol) < 2): " + (inlinedMethods(inc.symbol) < 2) - + "\n\tinc.code ne null: " + (inc.code ne null) - + "\n\tinc.code.blocks.length < MAX_INLINE_SIZE: " + (inc.code.blocks.length < MAX_INLINE_SIZE) + "(" + inc.code.blocks.length + ")" - + "\n\tisSafeToInline(m, inc, info.stack): " + isSafeToInline(m, inc, info.stack) - + "\n\tshouldInline heuristics: " + shouldInline(m, inc)); + + "\n\tinc.code ne null: " + (inc.code ne null) + (if (inc.code ne null) + "\n\tisSafeToInline(m, inc, info.stack): " + isSafeToInline(m, inc, info.stack) + + "\n\tshouldInline heuristics: " + shouldInline(m, inc) else "")); } case None => (); diff --git a/test/files/run/exceptions-2.scala b/test/files/run/exceptions-2.scala index 3802297d84..d76a52f5e8 100644 --- a/test/files/run/exceptions-2.scala +++ b/test/files/run/exceptions-2.scala @@ -94,7 +94,7 @@ object Test { try { val a: Leaf = null; - a.x; + println(a.x); } catch { case Leaf(a) => Console.println(a); case _: NullPointerException => Console.println("Exception occurred"); @@ -104,7 +104,7 @@ object Test { def method3: Unit = try { try { val a: Leaf = null; - a.x; + println(a.x); } catch { case Leaf(a) => Console.println(a); } |