summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala7
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala5
-rw-r--r--test/files/run/t8601-closure-elim.flags1
-rw-r--r--test/files/run/t8601-closure-elim.scala26
-rw-r--r--test/files/run/t8601c.flags1
-rw-r--r--test/files/run/t8601c.scala12
6 files changed, 47 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
index c49f23852f..a866173a88 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala
@@ -56,11 +56,8 @@ abstract class ClosureElimination extends SubComponent {
case (BOX(t1), UNBOX(t2)) if (t1 == t2) =>
Some(Nil)
- case (LOAD_FIELD(sym, isStatic), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) =>
- if (isStatic)
- Some(Nil)
- else
- Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
+ case (LOAD_FIELD(sym, /* isStatic */false), DROP(_)) if !sym.hasAnnotation(definitions.VolatileAttr) && inliner.isClosureClass(sym.owner) =>
+ Some(DROP(REFERENCE(definitions.ObjectClass)) :: Nil)
case _ => None
}
diff --git a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
index 3c983e6fdf..18bf63e237 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/DeadCodeElimination.scala
@@ -172,6 +172,11 @@ abstract class DeadCodeElimination extends SubComponent {
LOAD_EXCEPTION(_) | SWITCH(_, _) | MONITOR_ENTER() | MONITOR_EXIT() | CHECK_CAST(_) =>
moveToWorkList()
+ case LOAD_FIELD(sym, isStatic) if isStatic || !inliner.isClosureClass(sym.owner) =>
+ // static load may trigger static initization.
+ // non-static load can throw NPE (but we know closure fields can't be accessed via a
+ // null reference.
+ moveToWorkList()
case CALL_METHOD(m1, _) if isSideEffecting(m1) =>
moveToWorkList()
diff --git a/test/files/run/t8601-closure-elim.flags b/test/files/run/t8601-closure-elim.flags
new file mode 100644
index 0000000000..49d036a887
--- /dev/null
+++ b/test/files/run/t8601-closure-elim.flags
@@ -0,0 +1 @@
+-optimize
diff --git a/test/files/run/t8601-closure-elim.scala b/test/files/run/t8601-closure-elim.scala
new file mode 100644
index 0000000000..2c5b03af77
--- /dev/null
+++ b/test/files/run/t8601-closure-elim.scala
@@ -0,0 +1,26 @@
+import scala.tools.partest.BytecodeTest
+import scala.tools.asm
+import scala.tools.asm.util._
+import scala.collection.JavaConverters._
+
+object Test extends BytecodeTest {
+ val nullChecks = Set(asm.Opcodes.NEW)
+
+ def show: Unit = {
+ def test(methodName: String) {
+ val classNode = loadClassNode("Foo")
+ val methodNode = getMethod(classNode, "b")
+ val ops = methodNode.instructions.iterator.asScala.map(_.getOpcode).toList
+ assert(!ops.contains(asm.Opcodes.NEW), ops)// should be allocation free if the closure is eliminiated
+ }
+ test("b")
+ }
+}
+
+class Foo {
+ @inline final def a(x: Int => Int) = x(1)
+ final def b {
+ val delta = 0
+ a(x => delta + 1)
+ }
+}
diff --git a/test/files/run/t8601c.flags b/test/files/run/t8601c.flags
new file mode 100644
index 0000000000..1182725e86
--- /dev/null
+++ b/test/files/run/t8601c.flags
@@ -0,0 +1 @@
+-optimize \ No newline at end of file
diff --git a/test/files/run/t8601c.scala b/test/files/run/t8601c.scala
new file mode 100644
index 0000000000..c487d6825e
--- /dev/null
+++ b/test/files/run/t8601c.scala
@@ -0,0 +1,12 @@
+object Test {
+ def loadField(x: scala.runtime.IntRef): Unit = x.elem
+ def storeField(x: scala.runtime.IntRef): Unit = x.elem = 42
+
+ def check(x: => Any) = try { x; sys.error("failed to throw NPE!") } catch { case _: NullPointerException => }
+
+ def main(args: Array[String]) {
+ check(loadField(null)) // bug: did not NPE under -Ydead-code
+ check(storeField(null))
+
+ }
+}