summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2007-09-13 10:21:22 +0000
committerIulian Dragos <jaguarul@gmail.com>2007-09-13 10:21:22 +0000
commit6900f59041b0077620a09f71f4378a1cf96b3066 (patch)
tree28e76730f87cf47c62f4101fbd74759e7e0d7d67
parentc1ce17b26427f97dacea8d36eefcd5b604dfe89b (diff)
downloadscala-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
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/DataFlowAnalysis.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/TypeFlowAnalysis.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala48
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala10
-rw-r--r--test/files/run/exceptions-2.scala4
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);
}