summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-06-04 20:05:47 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2015-06-04 20:55:10 +0200
commita112422e91018b7f01add6c9d40bec5eb010c321 (patch)
tree13d9df355cfba3b0fb00873298be8169ece8c778
parent460e10cdb2fdfb9becaed5590ec77c7d5324a4db (diff)
downloadscala-a112422e91018b7f01add6c9d40bec5eb010c321.tar.gz
scala-a112422e91018b7f01add6c9d40bec5eb010c321.tar.bz2
scala-a112422e91018b7f01add6c9d40bec5eb010c321.zip
Compiler option for disabling nullness analysis
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala18
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala8
4 files changed, 23 insertions, 9 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
index 4c81b85d0a..2cc6d67a3c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
@@ -121,10 +121,10 @@ sealed trait NullnessValue extends Value {
def merge(other: NullnessValue) = NullnessValue(nullness merge other.nullness, isSize2)
}
-object NullValue extends NullnessValue { def nullness = Null; def isSize2 = false; override def toString = "Null" }
+object NullValue extends NullnessValue { def nullness = Null; def isSize2 = false; override def toString = "Null" }
object UnknownValue1 extends NullnessValue { def nullness = Unknown; def isSize2 = false; override def toString = "Unknown1" }
object UnknownValue2 extends NullnessValue { def nullness = Unknown; def isSize2 = true; override def toString = "Unknown2" }
-object NotNullValue extends NullnessValue { def nullness = NotNull; def isSize2 = false; override def toString = "NotNull" }
+object NotNullValue extends NullnessValue { def nullness = NotNull; def isSize2 = false; override def toString = "NotNull" }
object NullnessValue {
def apply(nullness: Nullness, isSize2: Boolean): NullnessValue = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
index 911bf3d189..9bd016f964 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -333,7 +333,7 @@ object BytecodeUtils {
def frameAt(instruction: AbstractInsnNode): Frame[V] = analyzer.frameAt(instruction, methodNode)
}
- implicit class AnalyzerExtendsions[V <: Value](val analyzer: Analyzer[V]) extends AnyVal {
+ implicit class AnalyzerExtensions[V <: Value](val analyzer: Analyzer[V]) extends AnyVal {
def frameAt(instruction: AbstractInsnNode, methodNode: MethodNode): Frame[V] = analyzer.getFrames()(methodNode.instructions.indexOf(instruction))
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index c6df86b297..0932564b1f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -8,6 +8,7 @@ package backend.jvm
package opt
import scala.reflect.internal.util.{NoPosition, Position}
+import scala.tools.asm.tree.analysis.{Value, Analyzer, BasicInterpreter}
import scala.tools.asm.{Opcodes, Type}
import scala.tools.asm.tree._
import scala.collection.convert.decorateAsScala._
@@ -100,9 +101,21 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
// call is known to be not-null, in which case we don't have to emit a null check when inlining.
// It is also used to get the stack height at the call site.
localOpt.minimalRemoveUnreachableCode(methodNode, definingClass.internalName)
- val analyzer = new NullnessAnalyzer
+
+ val analyzer: Analyzer[_ <: Value] = {
+ if (compilerSettings.YoptNullnessTracking) new NullnessAnalyzer
+ else new Analyzer(new BasicInterpreter)
+ }
analyzer.analyze(definingClass.internalName, methodNode)
+ def receiverNotNullByAnalysis(call: MethodInsnNode, numArgs: Int) = analyzer match {
+ case nullnessAnalyzer: NullnessAnalyzer =>
+ val frame = nullnessAnalyzer.frameAt(call, methodNode)
+ frame.getStack(frame.getStackSize - 1 - numArgs).nullness == NotNull
+
+ case _ => false
+ }
+
methodNode.instructions.iterator.asScala.collect({
case call: MethodInsnNode =>
val callee: Either[OptimizerWarning, Callee] = for {
@@ -131,8 +144,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
val receiverNotNull = call.getOpcode == Opcodes.INVOKESTATIC || {
val numArgs = Type.getArgumentTypes(call.desc).length
- val frame = analyzer.frameAt(call, methodNode)
- frame.getStack(frame.getStackSize - 1 - numArgs).nullness == NotNull
+ receiverNotNullByAnalysis(call, numArgs)
}
Callsite(
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 35ee889c58..953e43eaca 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -234,15 +234,16 @@ trait ScalaSettings extends AbsScalaSettings
val emptyLineNumbers = Choice("empty-line-numbers", "Eliminate unnecessary line number information.")
val emptyLabels = Choice("empty-labels", "Eliminate and collapse redundant labels in the bytecode.")
val compactLocals = Choice("compact-locals", "Eliminate empty slots in the sequence of local variables.")
- val inlineProject = Choice("inline-project", "Inline only methods defined in the files being compiled")
- val inlineGlobal = Choice("inline-global", "Inline methods from any source, including classfiles on the compile classpath")
+ val nullnessTracking = Choice("nullness-tracking", "Track nullness / non-nullness of local variables and apply optimizations.")
+ val inlineProject = Choice("inline-project", "Inline only methods defined in the files being compiled.")
+ val inlineGlobal = Choice("inline-global", "Inline methods from any source, including classfiles on the compile classpath.")
val lNone = Choice("l:none", "Don't enable any optimizations.")
private val defaultChoices = List(unreachableCode)
val lDefault = Choice("l:default", "Enable default optimizations: "+ defaultChoices.mkString(","), expandsTo = defaultChoices)
- private val methodChoices = List(unreachableCode, simplifyJumps, emptyLineNumbers, emptyLabels, compactLocals)
+ private val methodChoices = List(unreachableCode, simplifyJumps, emptyLineNumbers, emptyLabels, compactLocals, nullnessTracking)
val lMethod = Choice("l:method", "Enable intra-method optimizations: "+ methodChoices.mkString(","), expandsTo = methodChoices)
private val projectChoices = List(lMethod, inlineProject)
@@ -264,6 +265,7 @@ trait ScalaSettings extends AbsScalaSettings
def YoptEmptyLineNumbers = Yopt.contains(YoptChoices.emptyLineNumbers)
def YoptEmptyLabels = Yopt.contains(YoptChoices.emptyLabels)
def YoptCompactLocals = Yopt.contains(YoptChoices.compactLocals)
+ def YoptNullnessTracking = Yopt.contains(YoptChoices.nullnessTracking)
def YoptInlineProject = Yopt.contains(YoptChoices.inlineProject)
def YoptInlineGlobal = Yopt.contains(YoptChoices.inlineGlobal)