summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-01-22 22:33:29 +0100
committerLukas Rytz <lukas.rytz@gmail.com>2016-01-23 07:26:13 +0100
commit8d3be4dc79cb4679fc4994c32b21e10847e5518f (patch)
tree526242bc68fd901933a961dc14e55633129fb65d
parent7443037a6d1376709b3d83f10e66c9155f76dbaa (diff)
downloadscala-8d3be4dc79cb4679fc4994c32b21e10847e5518f.tar.gz
scala-8d3be4dc79cb4679fc4994c32b21e10847e5518f.tar.bz2
scala-8d3be4dc79cb4679fc4994c32b21e10847e5518f.zip
Harden methods to recognize method invocations to optimize
The previous methods to identify method invocations that can be optimized, such as `isPredefAutoBox`, were String-based. Now we obtain class and method signatures from symbols through the BTypes infrastructure. We also piggy-back on specialization's type transformer to create all specialized subclasses of Tuple1/Tuple2. We'll do the same in the future for FunctionN, but the current JFunctionN are written in Java and specialized artisanally.
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala8
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala273
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala138
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala285
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala20
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala4
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala2
16 files changed, 350 insertions, 405 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 422e2080f0..c6124e7177 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -1353,7 +1353,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val inlineExceptionHandlersPhase = phaseNamed("inlinehandlers")
val closelimPhase = phaseNamed("closelim")
val dcePhase = phaseNamed("dce")
- // val jvmPhase = phaseNamed("jvm")
+ val jvmPhase = phaseNamed("jvm")
def runIsAt(ph: Phase) = globalPhase.id == ph.id
def runIsAtOptimiz = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index adaf870c46..58c1d0e497 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -643,7 +643,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) =>
val nativeKind = tpeTK(expr)
genLoad(expr, nativeKind)
- val MethodNameAndType(mname, methodType) = asmBoxTo(nativeKind)
+ val MethodNameAndType(mname, methodType) = srBoxesRuntimeBoxToMethods(nativeKind)
bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, app.pos)
generatedType = boxResultType(fun.symbol) // was typeToBType(fun.symbol.tpe.resultType)
@@ -651,7 +651,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genLoad(expr)
val boxType = unboxResultType(fun.symbol) // was typeToBType(fun.symbol.owner.linkedClassOfClass.tpe)
generatedType = boxType
- val MethodNameAndType(mname, methodType) = asmUnboxTo(boxType)
+ val MethodNameAndType(mname, methodType) = srBoxesRuntimeUnboxToMethods(boxType)
bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, app.pos)
case app @ Apply(fun, args) =>
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index ef3fab7617..f1b9e8ea94 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -1113,7 +1113,7 @@ abstract class BTypes {
*/
/**
- * Just a named pair, used in CoreBTypes.asmBoxTo/asmUnboxTo.
+ * Just a named pair, used in CoreBTypes.srBoxesRuntimeBoxToMethods/srBoxesRuntimeUnboxToMethods.
*/
final case class MethodNameAndType(name: String, methodType: MethodBType)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index a2bf8e5725..35b84cc4a9 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -109,7 +109,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
assert(classSym != NoSymbol, "Cannot create ClassBType from NoSymbol")
assert(classSym.isClass, s"Cannot create ClassBType from non-class symbol $classSym")
assertClassNotArrayNotPrimitive(classSym)
- assert(!primitiveTypeMap.contains(classSym) || isCompilingPrimitive, s"Cannot create ClassBType for primitive class symbol $classSym")
+ assert(!primitiveTypeToBType.contains(classSym) || isCompilingPrimitive, s"Cannot create ClassBType for primitive class symbol $classSym")
if (classSym == NothingClass) srNothingRef
else if (classSym == NullClass) srNullRef
else {
@@ -155,7 +155,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
def primitiveOrClassToBType(sym: Symbol): BType = {
assertClassNotArray(sym)
assert(!sym.isImplClass, sym)
- primitiveTypeMap.getOrElse(sym, classBTypeFromSymbol(sym))
+ primitiveTypeToBType.getOrElse(sym, classBTypeFromSymbol(sym))
}
/**
@@ -217,7 +217,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
def assertClassNotArrayNotPrimitive(sym: Symbol): Unit = {
assertClassNotArray(sym)
- assert(!primitiveTypeMap.contains(sym) || isCompilingPrimitive, sym)
+ assert(!primitiveTypeToBType.contains(sym) || isCompilingPrimitive, sym)
}
private def setClassInfo(classSym: Symbol, classBType: ClassBType): ClassBType = {
@@ -240,7 +240,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
superClassSym == ObjectClass
else
// A ClassBType for a primitive class (scala.Boolean et al) is only created when compiling these classes.
- ((superClassSym != NoSymbol) && !superClassSym.isInterface) || (isCompilingPrimitive && primitiveTypeMap.contains(classSym)),
+ ((superClassSym != NoSymbol) && !superClassSym.isInterface) || (isCompilingPrimitive && primitiveTypeToBType.contains(classSym)),
s"Bad superClass for $classSym: $superClassSym"
)
val superClass = if (superClassSym == NoSymbol) None
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
index 0317e08d9e..0eaf509133 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -1,7 +1,7 @@
package scala.tools.nsc
package backend.jvm
-import scala.annotation.switch
+import scala.tools.nsc.backend.jvm.BTypes.InternalName
/**
* Core BTypes and some other definitions. The initialization of these definitions requires access
@@ -29,14 +29,14 @@ import scala.annotation.switch
class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
import bTypes._
import global._
- import rootMirror.{requiredClass, requiredModule, getClassIfDefined}
+ import rootMirror.{requiredClass, requiredModule, getRequiredClass, getClassIfDefined}
import definitions._
/**
* Maps primitive types to their corresponding PrimitiveBType. The map is defined lexically above
* the first use of `classBTypeFromSymbol` because that method looks at the map.
*/
- lazy val primitiveTypeMap: Map[Symbol, PrimitiveBType] = Map(
+ lazy val primitiveTypeToBType: Map[Symbol, PrimitiveBType] = Map(
UnitClass -> UNIT,
BooleanClass -> BOOL,
CharClass -> CHAR,
@@ -45,34 +45,22 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
IntClass -> INT,
LongClass -> LONG,
FloatClass -> FLOAT,
- DoubleClass -> DOUBLE
- )
-
- private lazy val BOXED_UNIT : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.Void])
- private lazy val BOXED_BOOLEAN : ClassBType = classBTypeFromSymbol(BoxedBooleanClass)
- private lazy val BOXED_BYTE : ClassBType = classBTypeFromSymbol(BoxedByteClass)
- private lazy val BOXED_SHORT : ClassBType = classBTypeFromSymbol(BoxedShortClass)
- private lazy val BOXED_CHAR : ClassBType = classBTypeFromSymbol(BoxedCharacterClass)
- private lazy val BOXED_INT : ClassBType = classBTypeFromSymbol(BoxedIntClass)
- private lazy val BOXED_LONG : ClassBType = classBTypeFromSymbol(BoxedLongClass)
- private lazy val BOXED_FLOAT : ClassBType = classBTypeFromSymbol(BoxedFloatClass)
- private lazy val BOXED_DOUBLE : ClassBType = classBTypeFromSymbol(BoxedDoubleClass)
+ DoubleClass -> DOUBLE)
/**
* Map from primitive types to their boxed class type. Useful when pushing class literals onto the
* operand stack (ldc instruction taking a class literal), see genConstant.
*/
lazy val boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = Map(
- UNIT -> BOXED_UNIT,
- BOOL -> BOXED_BOOLEAN,
- BYTE -> BOXED_BYTE,
- SHORT -> BOXED_SHORT,
- CHAR -> BOXED_CHAR,
- INT -> BOXED_INT,
- LONG -> BOXED_LONG,
- FLOAT -> BOXED_FLOAT,
- DOUBLE -> BOXED_DOUBLE
- )
+ UNIT -> classBTypeFromSymbol(requiredClass[java.lang.Void]),
+ BOOL -> classBTypeFromSymbol(BoxedBooleanClass),
+ BYTE -> classBTypeFromSymbol(BoxedByteClass),
+ SHORT -> classBTypeFromSymbol(BoxedShortClass),
+ CHAR -> classBTypeFromSymbol(BoxedCharacterClass),
+ INT -> classBTypeFromSymbol(BoxedIntClass),
+ LONG -> classBTypeFromSymbol(BoxedLongClass),
+ FLOAT -> classBTypeFromSymbol(BoxedFloatClass),
+ DOUBLE -> classBTypeFromSymbol(BoxedDoubleClass))
lazy val boxedClasses: Set[ClassBType] = boxedClassOfPrimitive.values.toSet
@@ -82,7 +70,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
*/
lazy val boxResultType: Map[Symbol, ClassBType] = {
for ((valueClassSym, boxMethodSym) <- currentRun.runDefinitions.boxMethod)
- yield boxMethodSym -> boxedClassOfPrimitive(primitiveTypeMap(valueClassSym))
+ yield boxMethodSym -> boxedClassOfPrimitive(primitiveTypeToBType(valueClassSym))
}
/**
@@ -90,7 +78,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
* For example, the method symbol for `Byte.unbox()`) is mapped to the PrimitiveBType BYTE. */
lazy val unboxResultType: Map[Symbol, PrimitiveBType] = {
for ((valueClassSym, unboxMethodSym) <- currentRun.runDefinitions.unboxMethod)
- yield unboxMethodSym -> primitiveTypeMap(valueClassSym)
+ yield unboxMethodSym -> primitiveTypeToBType(valueClassSym)
}
/*
@@ -106,6 +94,7 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
lazy val ObjectRef : ClassBType = classBTypeFromSymbol(ObjectClass)
lazy val StringRef : ClassBType = classBTypeFromSymbol(StringClass)
+ lazy val PredefRef : ClassBType = classBTypeFromSymbol(PredefModule.moduleClass)
lazy val jlStringBuilderRef : ClassBType = classBTypeFromSymbol(StringBuilderClass)
lazy val jlThrowableRef : ClassBType = classBTypeFromSymbol(ThrowableClass)
lazy val jlCloneableRef : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
@@ -116,56 +105,135 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
lazy val sbScalaBeanInfoRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.beans.ScalaBeanInfo])
lazy val jliSerializedLambdaRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.SerializedLambda])
lazy val jliMethodHandlesRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodHandles])
- lazy val jliMethodHandlesLookupRef : ClassBType = classBTypeFromSymbol(exitingPickler(rootMirror.getRequiredClass("java.lang.invoke.MethodHandles.Lookup"))) // didn't find a reliable non-stringly-typed way that works for inner classes in the backend
+ lazy val jliMethodHandlesLookupRef : ClassBType = classBTypeFromSymbol(exitingPickler(getRequiredClass("java.lang.invoke.MethodHandles.Lookup"))) // didn't find a reliable non-stringly-typed way that works for inner classes in the backend
lazy val srLambdaDeserializerRef : ClassBType = classBTypeFromSymbol(requiredModule[scala.runtime.LambdaDeserializer.type].moduleClass)
lazy val srBoxesRunTimeRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime])
lazy val srBoxedUnitRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxedUnit])
- lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
+ private def methodNameAndType(cls: Symbol, name: Name, static: Boolean = false, filterOverload: Symbol => Boolean = _ => true): MethodNameAndType = {
+ val holder = if (static) cls.companionModule.moduleClass else cls
+ val method = holder.info.member(name).suchThat(filterOverload)
+ assert(!method.isOverloaded, method)
+ MethodNameAndType(name.toString, methodBTypeFromSymbol(method))
+ }
- // TODO @lry avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
- lazy val AndroidParcelableInterface : Symbol = getClassIfDefined("android.os.Parcelable")
- lazy val AndroidCreatorClass : Symbol = getClassIfDefined("android.os.Parcelable$Creator")
+ private def srBoxesRuntimeMethods(getName: (String, String) => String): Map[BType, MethodNameAndType] = {
+ ScalaValueClassesNoUnit.map(primitive => {
+ val bType = primitiveTypeToBType(primitive)
+ val name = newTermName(getName(primitive.name.toString, boxedClass(primitive).name.toString))
+ (bType, methodNameAndType(BoxesRunTimeClass, name))
+ })(collection.breakOut)
+ }
- lazy val BeanInfoAttr: Symbol = requiredClass[scala.beans.BeanInfo]
+ // Z -> MethodNameAndType(boxToBoolean,(Z)Ljava/lang/Boolean;)
+ lazy val srBoxesRuntimeBoxToMethods: Map[BType, MethodNameAndType] = srBoxesRuntimeMethods((primitive, boxed) => "boxTo" + boxed)
- /* The Object => String overload. */
- lazy val String_valueOf: Symbol = {
- getMember(StringModule, nme.valueOf) filter (sym => sym.info.paramTypes match {
- case List(pt) => pt.typeSymbol == ObjectClass
- case _ => false
- })
+ // Z -> MethodNameAndType(unboxToBoolean,(Ljava/lang/Object;)Z)
+ lazy val srBoxesRuntimeUnboxToMethods: Map[BType, MethodNameAndType] = srBoxesRuntimeMethods((primitive, boxed) => "unboxTo" + primitive)
+
+ def singleParamOfClass(cls: Symbol) = (s: Symbol) => s.paramss match {
+ case List(List(param)) => param.info.typeSymbol == cls
+ case _ => false
}
- /**
- * Methods in scala.runtime.BoxesRuntime
- */
- lazy val asmBoxTo : Map[BType, MethodNameAndType] = Map(
- BOOL -> MethodNameAndType("boxToBoolean", MethodBType(List(BOOL), BOXED_BOOLEAN)),
- BYTE -> MethodNameAndType("boxToByte", MethodBType(List(BYTE), BOXED_BYTE)),
- CHAR -> MethodNameAndType("boxToCharacter", MethodBType(List(CHAR), BOXED_CHAR)),
- SHORT -> MethodNameAndType("boxToShort", MethodBType(List(SHORT), BOXED_SHORT)),
- INT -> MethodNameAndType("boxToInteger", MethodBType(List(INT), BOXED_INT)),
- LONG -> MethodNameAndType("boxToLong", MethodBType(List(LONG), BOXED_LONG)),
- FLOAT -> MethodNameAndType("boxToFloat", MethodBType(List(FLOAT), BOXED_FLOAT)),
- DOUBLE -> MethodNameAndType("boxToDouble", MethodBType(List(DOUBLE), BOXED_DOUBLE))
- )
-
- lazy val asmUnboxTo: Map[BType, MethodNameAndType] = Map(
- BOOL -> MethodNameAndType("unboxToBoolean", MethodBType(List(ObjectRef), BOOL)),
- BYTE -> MethodNameAndType("unboxToByte", MethodBType(List(ObjectRef), BYTE)),
- CHAR -> MethodNameAndType("unboxToChar", MethodBType(List(ObjectRef), CHAR)),
- SHORT -> MethodNameAndType("unboxToShort", MethodBType(List(ObjectRef), SHORT)),
- INT -> MethodNameAndType("unboxToInt", MethodBType(List(ObjectRef), INT)),
- LONG -> MethodNameAndType("unboxToLong", MethodBType(List(ObjectRef), LONG)),
- FLOAT -> MethodNameAndType("unboxToFloat", MethodBType(List(ObjectRef), FLOAT)),
- DOUBLE -> MethodNameAndType("unboxToDouble", MethodBType(List(ObjectRef), DOUBLE))
- )
+ // java/lang/Boolean -> MethodNameAndType(valueOf,(Z)Ljava/lang/Boolean;)
+ lazy val javaBoxMethods: Map[InternalName, MethodNameAndType] = {
+ ScalaValueClassesNoUnit.map(primitive => {
+ val boxed = boxedClass(primitive)
+ val method = methodNameAndType(boxed, newTermName("valueOf"), static = true, filterOverload = singleParamOfClass(primitive))
+ (classBTypeFromSymbol(boxed).internalName, method)
+ })(collection.breakOut)
+ }
+
+ // java/lang/Boolean -> MethodNameAndType(booleanValue,()Z)
+ lazy val javaUnboxMethods: Map[InternalName, MethodNameAndType] = {
+ ScalaValueClassesNoUnit.map(primitive => {
+ val boxed = boxedClass(primitive)
+ val name = primitive.name.toString.toLowerCase + "Value"
+ (classBTypeFromSymbol(boxed).internalName, methodNameAndType(boxed, newTermName(name)))
+ })(collection.breakOut)
+ }
+
+ private def predefBoxingMethods(getName: (String, String) => String): Map[String, MethodBType] = {
+ ScalaValueClassesNoUnit.map(primitive => {
+ val boxed = boxedClass(primitive)
+ val name = getName(primitive.name.toString, boxed.name.toString)
+ (name, methodNameAndType(PredefModule.moduleClass, newTermName(name)).methodType)
+ })(collection.breakOut)
+ }
+
+ // boolean2Boolean -> (Z)Ljava/lang/Boolean;
+ lazy val predefAutoBoxMethods: Map[String, MethodBType] = predefBoxingMethods((primitive, boxed) => primitive.toLowerCase + "2" + boxed)
+
+ // Boolean2boolean -> (Ljava/lang/Boolean;)Z
+ lazy val predefAutoUnboxMethods: Map[String, MethodBType] = predefBoxingMethods((primitive, boxed) => boxed + "2" + primitive.toLowerCase)
+
+ private def staticRefMethods(name: Name): Map[InternalName, MethodNameAndType] = {
+ allRefClasses.map(refClass =>
+ (classBTypeFromSymbol(refClass).internalName, methodNameAndType(refClass, name, static = true)))(collection.breakOut)
+ }
+
+ // scala/runtime/BooleanRef -> MethodNameAndType(create,(Z)Lscala/runtime/BooleanRef;)
+ lazy val srRefCreateMethods: Map[InternalName, MethodNameAndType] = staticRefMethods(nme.create)
+
+ // scala/runtime/BooleanRef -> MethodNameAndType(zero,()Lscala/runtime/BooleanRef;)
+ lazy val srRefZeroMethods: Map[InternalName, MethodNameAndType] = staticRefMethods(nme.zero)
+
+ // java/lang/Boolean -> MethodNameAndType(<init>,(Z)V)
+ lazy val primitiveBoxConstructors: Map[InternalName, MethodNameAndType] = {
+ ScalaValueClassesNoUnit.map(primitive => {
+ val boxed = boxedClass(primitive)
+ (classBTypeFromSymbol(boxed).internalName, methodNameAndType(boxed, nme.CONSTRUCTOR, filterOverload = singleParamOfClass(primitive)))
+ })(collection.breakOut)
+ }
+
+ private def nonOverloadedConstructors(classes: Iterable[Symbol]): Map[InternalName, MethodNameAndType] = {
+ classes.map(cls => (classBTypeFromSymbol(cls).internalName, methodNameAndType(cls, nme.CONSTRUCTOR)))(collection.breakOut)
+ }
+
+ // scala/runtime/BooleanRef -> MethodNameAndType(<init>,(Z)V)
+ lazy val srRefConstructors: Map[InternalName, MethodNameAndType] = nonOverloadedConstructors(allRefClasses)
+
+ private def specializedSubclasses(cls: Symbol): List[Symbol] = {
+ exitingSpecialize(cls.info) // the `transformInfo` method of specialization adds specialized subclasses to the `specializedClass` map
+ specializeTypes.specializedClass.collect({
+ case ((`cls`, _), specCls) => specCls
+ }).toList
+ }
+
+ // scala/Tuple3 -> MethodNameAndType(<init>,(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V)
+ // scala/Tuple2$mcZC$sp -> MethodNameAndType(<init>,(ZC)V)
+ lazy val tupleClassConstructors: Map[InternalName, MethodNameAndType] = {
+ val tupleClassSymbols = TupleClass.seq ++ specializedSubclasses(TupleClass(1)) ++ specializedSubclasses(TupleClass(2))
+ nonOverloadedConstructors(tupleClassSymbols)
+ }
+
+ // enumeration of specialized classes is temporary, while we still use the java-defined JFunctionN.
+ // once we switch to ordinary FunctionN, we can use specializedSubclasses just like for tuples.
+ private def functionClasses(base: String): Set[Symbol] = {
+ def primitives = Iterator("B", "S", "I", "J", "C", "F", "D", "Z", "V")
+ def ijfd = Iterator("I", "J", "F", "D")
+ def ijfdzv = Iterator("I", "J", "F", "D", "Z", "V")
+ def ijd = Iterator("I", "J", "D")
+ val classNames = Set.empty[String] ++ {
+ (0 to 22).map(base + _)
+ } ++ {
+ primitives.map(base + "0$mc" + _ + "$sp") // Function0
+ } ++ {
+ // return type specializations appear first in the name string (alphabetical sorting)
+ for (r <- ijfdzv; a <- ijfd) yield base + "1$mc" + r + a + "$sp" // Function1
+ } ++ {
+ for (r <- ijfdzv; a <- ijd; b <- ijd) yield base + "2$mc" + r + a + b + "$sp" // Function2
+ }
+ classNames map getRequiredClass
+ }
+
+ lazy val srJFunctionRefs: Set[InternalName] = functionClasses("scala.runtime.java8.JFunction").map(classBTypeFromSymbol(_).internalName)
lazy val typeOfArrayOp: Map[Int, BType] = {
import scalaPrimitives._
Map(
- (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
+ (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
(List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE)) ++
(List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT)) ++
(List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR)) ++
@@ -176,6 +244,22 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
(List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectRef)) : _*
)
}
+
+ lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
+
+ // TODO @lry avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
+ lazy val AndroidParcelableInterface : Symbol = getClassIfDefined("android.os.Parcelable")
+ lazy val AndroidCreatorClass : Symbol = getClassIfDefined("android.os.Parcelable$Creator")
+
+ lazy val BeanInfoAttr: Symbol = requiredClass[scala.beans.BeanInfo]
+
+ /* The Object => String overload. */
+ lazy val String_valueOf: Symbol = {
+ getMember(StringModule, nme.valueOf) filter (sym => sym.info.paramTypes match {
+ case List(pt) => pt.typeSymbol == ObjectClass
+ case _ => false
+ })
+ }
}
/**
@@ -191,10 +275,14 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
import bTypes._
def boxedClasses: Set[ClassBType]
+ def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType]
- def ObjectRef : ClassBType
def srNothingRef : ClassBType
def srNullRef : ClassBType
+
+ def ObjectRef : ClassBType
+ def StringRef : ClassBType
+ def PredefRef : ClassBType
def jlCloneableRef : ClassBType
def jiSerializableRef : ClassBType
def juHashMapRef : ClassBType
@@ -206,8 +294,23 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
def srBoxesRunTimeRef : ClassBType
def srBoxedUnitRef : ClassBType
- def asmBoxTo : Map[BType, MethodNameAndType]
- def asmUnboxTo: Map[BType, MethodNameAndType]
+ def srBoxesRuntimeBoxToMethods : Map[BType, MethodNameAndType]
+ def srBoxesRuntimeUnboxToMethods : Map[BType, MethodNameAndType]
+
+ def javaBoxMethods : Map[InternalName, MethodNameAndType]
+ def javaUnboxMethods : Map[InternalName, MethodNameAndType]
+
+ def predefAutoBoxMethods : Map[String, MethodBType]
+ def predefAutoUnboxMethods : Map[String, MethodBType]
+
+ def srRefCreateMethods : Map[InternalName, MethodNameAndType]
+ def srRefZeroMethods : Map[InternalName, MethodNameAndType]
+
+ def primitiveBoxConstructors : Map[InternalName, MethodNameAndType]
+ def srRefConstructors : Map[InternalName, MethodNameAndType]
+ def tupleClassConstructors : Map[InternalName, MethodNameAndType]
+
+ def srJFunctionRefs: Set[InternalName]
}
/**
@@ -222,20 +325,21 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
_coreBTypes = coreBTypes.asInstanceOf[CoreBTypes[bTypes.type]]
}
- def primitiveTypeMap: Map[Symbol, PrimitiveBType] = _coreBTypes.primitiveTypeMap
+ def primitiveTypeToBType: Map[Symbol, PrimitiveBType] = _coreBTypes.primitiveTypeToBType
def boxedClasses: Set[ClassBType] = _coreBTypes.boxedClasses
-
def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = _coreBTypes.boxedClassOfPrimitive
def boxResultType: Map[Symbol, ClassBType] = _coreBTypes.boxResultType
def unboxResultType: Map[Symbol, PrimitiveBType] = _coreBTypes.unboxResultType
+ def srNothingRef : ClassBType = _coreBTypes.srNothingRef
+ def srNullRef : ClassBType = _coreBTypes.srNullRef
+
def ObjectRef : ClassBType = _coreBTypes.ObjectRef
def StringRef : ClassBType = _coreBTypes.StringRef
+ def PredefRef : ClassBType = _coreBTypes.PredefRef
def jlStringBuilderRef : ClassBType = _coreBTypes.jlStringBuilderRef
- def srNothingRef : ClassBType = _coreBTypes.srNothingRef
- def srNullRef : ClassBType = _coreBTypes.srNullRef
def jlThrowableRef : ClassBType = _coreBTypes.jlThrowableRef
def jlCloneableRef : ClassBType = _coreBTypes.jlCloneableRef
def jiSerializableRef : ClassBType = _coreBTypes.jiSerializableRef
@@ -250,6 +354,28 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def srBoxesRunTimeRef : ClassBType = _coreBTypes.srBoxesRunTimeRef
def srBoxedUnitRef : ClassBType = _coreBTypes.srBoxedUnitRef
+ def srBoxesRuntimeBoxToMethods : Map[BType, MethodNameAndType] = _coreBTypes.srBoxesRuntimeBoxToMethods
+ def srBoxesRuntimeUnboxToMethods : Map[BType, MethodNameAndType] = _coreBTypes.srBoxesRuntimeUnboxToMethods
+
+ def javaBoxMethods : Map[InternalName, MethodNameAndType] = _coreBTypes.javaBoxMethods
+ def javaUnboxMethods : Map[InternalName, MethodNameAndType] = _coreBTypes.javaUnboxMethods
+
+ def predefAutoBoxMethods : Map[String, MethodBType] = _coreBTypes.predefAutoBoxMethods
+ def predefAutoUnboxMethods : Map[String, MethodBType] = _coreBTypes.predefAutoUnboxMethods
+
+ def srRefCreateMethods : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefCreateMethods
+ def srRefZeroMethods : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefZeroMethods
+
+ def primitiveBoxConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.primitiveBoxConstructors
+ def srRefConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.srRefConstructors
+ def tupleClassConstructors : Map[InternalName, MethodNameAndType] = _coreBTypes.tupleClassConstructors
+
+ def srJFunctionRefs: Set[InternalName] = _coreBTypes.srJFunctionRefs
+
+ def typeOfArrayOp: Map[Int, BType] = _coreBTypes.typeOfArrayOp
+
+ // Some symbols. These references should probably be moved to Definitions.
+
def hashMethodSym: Symbol = _coreBTypes.hashMethodSym
def AndroidParcelableInterface : Symbol = _coreBTypes.AndroidParcelableInterface
@@ -258,9 +384,4 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes:
def BeanInfoAttr: Symbol = _coreBTypes.BeanInfoAttr
def String_valueOf: Symbol = _coreBTypes.String_valueOf
-
- def asmBoxTo : Map[BType, MethodNameAndType] = _coreBTypes.asmBoxTo
- def asmUnboxTo: Map[BType, MethodNameAndType] = _coreBTypes.asmUnboxTo
-
- def typeOfArrayOp: Map[Int, BType] = _coreBTypes.typeOfArrayOp
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
index baf82032f7..e8630c65d9 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala
@@ -3,9 +3,11 @@ package backend.jvm
package analysis
import scala.annotation.switch
-import scala.tools.asm.{Opcodes, Handle, Type, Label}
+import scala.tools.asm.{Handle, Type, Label}
+import scala.tools.asm.Opcodes._
import scala.tools.asm.tree._
import scala.tools.asm.tree.analysis.{Frame, BasicInterpreter, Analyzer, Value}
+import GenBCode._
import scala.tools.nsc.backend.jvm.BTypes._
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils
import scala.tools.nsc.backend.jvm.opt.BytecodeUtils._
@@ -24,6 +26,7 @@ import scala.collection.convert.decorateAsScala._
*/
class BackendUtils[BT <: BTypes](val btypes: BT) {
import btypes._
+ import btypes.coreBTypes._
import callGraph.ClosureInstantiation
/**
@@ -73,8 +76,6 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
*/
def addLambdaDeserialize(classNode: ClassNode): Unit = {
val cw = classNode
- import scala.tools.asm.Opcodes._
- import btypes.coreBTypes._
// Make sure to reference the ClassBTypes of all types that are used in the code generated
// here (e.g. java/util/Map) are initialized. Initializing a ClassBType adds it to the
@@ -145,14 +146,137 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
(result, map, hasSerializableClosureInstantiation)
}
- def getBoxedUnit: FieldInsnNode = new FieldInsnNode(Opcodes.GETSTATIC, coreBTypes.srBoxedUnitRef.internalName, "UNIT", coreBTypes.srBoxedUnitRef.descriptor)
+ def getBoxedUnit: FieldInsnNode = new FieldInsnNode(GETSTATIC, srBoxedUnitRef.internalName, "UNIT", srBoxedUnitRef.descriptor)
private val anonfunAdaptedName = """.*\$anonfun\$\d+\$adapted""".r
def hasAdaptedImplMethod(closureInit: ClosureInstantiation): Boolean = {
- BytecodeUtils.isrJFunctionType(Type.getReturnType(closureInit.lambdaMetaFactoryCall.indy.desc).getInternalName) &&
+ isrJFunctionType(Type.getReturnType(closureInit.lambdaMetaFactoryCall.indy.desc).getInternalName) &&
anonfunAdaptedName.pattern.matcher(closureInit.lambdaMetaFactoryCall.implMethod.getName).matches
}
+ private def primitiveAsmTypeToBType(primitiveType: Type): PrimitiveBType = (primitiveType.getSort: @switch) match {
+ case Type.BOOLEAN => BOOL
+ case Type.BYTE => BYTE
+ case Type.CHAR => CHAR
+ case Type.SHORT => SHORT
+ case Type.INT => INT
+ case Type.LONG => LONG
+ case Type.FLOAT => FLOAT
+ case Type.DOUBLE => DOUBLE
+ case _ => null
+ }
+
+ def isScalaBox(insn: MethodInsnNode): Boolean = {
+ insn.owner == srBoxesRunTimeRef.internalName && {
+ val args = Type.getArgumentTypes(insn.desc)
+ args.length == 1 && (srBoxesRuntimeBoxToMethods.get(primitiveAsmTypeToBType(args(0))) match {
+ case Some(MethodNameAndType(name, tp)) => name == insn.name && tp.descriptor == insn.desc
+ case _ => false
+ })
+ }
+ }
+
+ def getScalaBox(primitiveType: Type): MethodInsnNode = {
+ val bType = primitiveAsmTypeToBType(primitiveType)
+ val MethodNameAndType(name, methodBType) = srBoxesRuntimeBoxToMethods(bType)
+ new MethodInsnNode(INVOKESTATIC, srBoxesRunTimeRef.internalName, name, methodBType.descriptor, /*itf =*/ false)
+ }
+
+ def isScalaUnbox(insn: MethodInsnNode): Boolean = {
+ insn.owner == srBoxesRunTimeRef.internalName && (srBoxesRuntimeUnboxToMethods.get(primitiveAsmTypeToBType(Type.getReturnType(insn.desc))) match {
+ case Some(MethodNameAndType(name, tp)) => name == insn.name && tp.descriptor == insn.desc
+ case _ => false
+ })
+ }
+
+ def getScalaUnbox(primitiveType: Type): MethodInsnNode = {
+ val bType = primitiveAsmTypeToBType(primitiveType)
+ val MethodNameAndType(name, methodBType) = srBoxesRuntimeUnboxToMethods(bType)
+ new MethodInsnNode(INVOKESTATIC, srBoxesRunTimeRef.internalName, name, methodBType.descriptor, /*itf =*/ false)
+ }
+
+ private def calleeInMap(insn: MethodInsnNode, map: Map[InternalName, MethodNameAndType]): Boolean = map.get(insn.owner) match {
+ case Some(MethodNameAndType(name, tp)) => insn.name == name && insn.desc == tp.descriptor
+ case _ => false
+ }
+
+ def isJavaBox(insn: MethodInsnNode): Boolean = calleeInMap(insn, javaBoxMethods)
+ def isJavaUnbox(insn: MethodInsnNode): Boolean = calleeInMap(insn, javaUnboxMethods)
+
+ def isPredefAutoBox(insn: MethodInsnNode): Boolean = {
+ insn.owner == PredefRef.internalName && (predefAutoBoxMethods.get(insn.name) match {
+ case Some(tp) => insn.desc == tp.descriptor
+ case _ => false
+ })
+ }
+
+ def isPredefAutoUnbox(insn: MethodInsnNode): Boolean = {
+ insn.owner == PredefRef.internalName && (predefAutoUnboxMethods.get(insn.name) match {
+ case Some(tp) => insn.desc == tp.descriptor
+ case _ => false
+ })
+ }
+
+ def isRefCreate(insn: MethodInsnNode): Boolean = calleeInMap(insn, srRefCreateMethods)
+ def isRefZero(insn: MethodInsnNode): Boolean = calleeInMap(insn, srRefZeroMethods)
+
+ def runtimeRefClassBoxedType(refClass: InternalName): Type = Type.getArgumentTypes(srRefCreateMethods(refClass).methodType.descriptor)(0)
+
+ def isSideEffectFreeCall(insn: MethodInsnNode): Boolean = {
+ isScalaBox(insn) || isScalaUnbox(insn) ||
+ isJavaBox(insn) || // not java unbox, it may NPE
+ isSideEffectFreeConstructorCall(insn)
+ }
+
+ def isNonNullMethodInvocation(mi: MethodInsnNode): Boolean = {
+ isJavaBox(mi) || isScalaBox(mi) || isPredefAutoBox(mi) || isRefCreate(mi) || isRefZero(mi)
+ }
+
+ def isModuleLoad(insn: AbstractInsnNode, moduleName: InternalName): Boolean = insn match {
+ case fi: FieldInsnNode => fi.getOpcode == GETSTATIC && fi.owner == moduleName && fi.name == "MODULE$" && fi.desc == ("L" + moduleName + ";")
+ case _ => false
+ }
+
+ def isPredefLoad(insn: AbstractInsnNode) = isModuleLoad(insn, PredefRef.internalName)
+
+ def isPrimitiveBoxConstructor(insn: MethodInsnNode): Boolean = calleeInMap(insn, primitiveBoxConstructors)
+ def isRuntimeRefConstructor(insn: MethodInsnNode): Boolean = calleeInMap(insn, srRefConstructors)
+ def isTupleConstructor(insn: MethodInsnNode): Boolean = calleeInMap(insn, tupleClassConstructors)
+
+ // unused objects created by these constructors are eliminated by pushPop
+ private lazy val sideEffectFreeConstructors: Set[(String, String)] = {
+ val ownerDesc = (p: (InternalName, MethodNameAndType)) => (p._1, p._2.methodType.descriptor)
+ primitiveBoxConstructors.map(ownerDesc).toSet ++
+ srRefConstructors.map(ownerDesc) ++
+ tupleClassConstructors.map(ownerDesc) ++ Set(
+ (ObjectRef.internalName, MethodBType(Nil, UNIT).descriptor),
+ (StringRef.internalName, MethodBType(Nil, UNIT).descriptor),
+ (StringRef.internalName, MethodBType(List(StringRef), UNIT).descriptor),
+ (StringRef.internalName, MethodBType(List(ArrayBType(CHAR)), UNIT).descriptor))
+ }
+
+ def isSideEffectFreeConstructorCall(insn: MethodInsnNode): Boolean = {
+ insn.name == INSTANCE_CONSTRUCTOR_NAME && sideEffectFreeConstructors((insn.owner, insn.desc))
+ }
+
+ private lazy val classesOfSideEffectFreeConstructors = sideEffectFreeConstructors.map(_._1)
+
+ def isNewForSideEffectFreeConstructor(insn: AbstractInsnNode) = {
+ insn.getOpcode == NEW && {
+ val ti = insn.asInstanceOf[TypeInsnNode]
+ classesOfSideEffectFreeConstructors.contains(ti.desc)
+ }
+ }
+
+ def isBoxedUnit(insn: AbstractInsnNode) = {
+ insn.getOpcode == GETSTATIC && {
+ val fi = insn.asInstanceOf[FieldInsnNode]
+ fi.owner == srBoxedUnitRef.internalName && fi.name == "UNIT" && fi.desc == srBoxedUnitRef.descriptor
+ }
+ }
+
+ def isrJFunctionType(internalName: InternalName): Boolean = srJFunctionRefs(internalName)
+
/**
* Visit the class node and collect all referenced nested classes.
*/
@@ -287,15 +411,13 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
* Analyzer: its implementation also skips over unreachable code in the same way.
*/
def computeMaxLocalsMaxStack(method: MethodNode): Unit = {
- import Opcodes._
-
if (isAbstractMethod(method) || isNativeMethod(method)) {
method.maxLocals = 0
method.maxStack = 0
} else if (!maxLocalsMaxStackComputed(method)) {
val size = method.instructions.size
- var maxLocals = (Type.getArgumentsAndReturnSizes(method.desc) >> 2) - (if (isStaticMethod(method)) 1 else 0)
+ var maxLocals = parametersSize(method)
var maxStack = 0
// queue of instruction indices where analysis should start
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
index 2181f00850..dd19ad594f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/InstructionStackEffect.scala
@@ -335,5 +335,4 @@ object InstructionStackEffect {
IFNONNULL => t(1, 0)
}
}
-
}
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 1078d0085e..30e73f8ac2 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzer.scala
@@ -63,7 +63,7 @@ object NullnessValue {
def unknown(insn: AbstractInsnNode) = if (BytecodeUtils.instructionResultSize(insn) == 2) UnknownValue2 else UnknownValue1
}
-final class NullnessInterpreter extends Interpreter[NullnessValue](Opcodes.ASM5) {
+final class NullnessInterpreter(bTypes: BTypes) extends Interpreter[NullnessValue](Opcodes.ASM5) {
def newValue(tp: Type): NullnessValue = {
// ASM loves giving semantics to null. The behavior here is the same as in SourceInterpreter,
// which is provided by the framework.
@@ -114,7 +114,7 @@ final class NullnessInterpreter extends Interpreter[NullnessValue](Opcodes.ASM5)
def ternaryOperation(insn: AbstractInsnNode, value1: NullnessValue, value2: NullnessValue, value3: NullnessValue): NullnessValue = UnknownValue1
def naryOperation(insn: AbstractInsnNode, values: util.List[_ <: NullnessValue]): NullnessValue = insn match {
- case mi: MethodInsnNode if isNonNullMethodInvocation(mi) =>
+ case mi: MethodInsnNode if bTypes.backendUtils.isNonNullMethodInvocation(mi) =>
NotNullValue
case _ =>
@@ -197,7 +197,7 @@ class NullnessFrame(nLocals: Int, nStack: Int) extends AliasingFrame[NullnessVal
* This class is required to override the `newFrame` methods, which makes makes sure the analyzer
* uses NullnessFrames.
*/
-class NullnessAnalyzer extends Analyzer[NullnessValue](new NullnessInterpreter) {
+class NullnessAnalyzer(bTypes: BTypes) extends Analyzer[NullnessValue](new NullnessInterpreter(bTypes)) {
override def newFrame(nLocals: Int, nStack: Int): NullnessFrame = new NullnessFrame(nLocals, nStack)
override def newFrame(src: Frame[_ <: NullnessValue]): NullnessFrame = new NullnessFrame(src)
}
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 f83167eabf..ff36f36589 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -348,291 +348,6 @@ object BytecodeUtils {
}
}
- def isSideEffectFreeCall(insn: MethodInsnNode): Boolean = {
- isScalaBox(insn) || isScalaUnbox(insn) ||
- isJavaBox(insn) || // not java unbox, it may NPE
- isSideEffectFreeConstructorCall(insn)
- }
-
- def isNonNullMethodInvocation(mi: MethodInsnNode): Boolean = {
- isJavaBox(mi) || isScalaBox(mi) || isPredefAutoBox(mi) || isRefCreate(mi) || isRefZero(mi)
- }
-
- private val srBoxesRunTimeName = "scala/runtime/BoxesRunTime"
-
- private val boxToMethods = Map(
- Type.BOOLEAN -> ("boxToBoolean", "(Z)Ljava/lang/Boolean;"),
- Type.BYTE -> ("boxToByte", "(B)Ljava/lang/Byte;"),
- Type.CHAR -> ("boxToCharacter", "(C)Ljava/lang/Character;"),
- Type.SHORT -> ("boxToShort", "(S)Ljava/lang/Short;"),
- Type.INT -> ("boxToInteger", "(I)Ljava/lang/Integer;"),
- Type.LONG -> ("boxToLong", "(J)Ljava/lang/Long;"),
- Type.FLOAT -> ("boxToFloat", "(F)Ljava/lang/Float;"),
- Type.DOUBLE -> ("boxToDouble", "(D)Ljava/lang/Double;"))
-
- def isScalaBox(insn: MethodInsnNode): Boolean = {
- insn.owner == srBoxesRunTimeName && {
- val args = Type.getArgumentTypes(insn.desc)
- args.length == 1 && (boxToMethods.get(args(0).getSort) match {
- case Some((name, desc)) => name == insn.name && desc == insn.desc
- case _ => false
- })
- }
- }
-
- def getScalaBox(primitiveType: Type): MethodInsnNode = {
- val (method, desc) = boxToMethods(primitiveType.getSort)
- new MethodInsnNode(INVOKESTATIC, srBoxesRunTimeName, method, desc, /*itf =*/ false)
- }
-
- private val unboxToMethods = Map(
- Type.BOOLEAN -> ("unboxToBoolean", "(Ljava/lang/Object;)Z"),
- Type.BYTE -> ("unboxToByte", "(Ljava/lang/Object;)B"),
- Type.CHAR -> ("unboxToChar", "(Ljava/lang/Object;)C"),
- Type.SHORT -> ("unboxToShort", "(Ljava/lang/Object;)S"),
- Type.INT -> ("unboxToInt", "(Ljava/lang/Object;)I"),
- Type.LONG -> ("unboxToLong", "(Ljava/lang/Object;)J"),
- Type.FLOAT -> ("unboxToFloat", "(Ljava/lang/Object;)F"),
- Type.DOUBLE -> ("unboxToDouble", "(Ljava/lang/Object;)D"))
-
- def isScalaUnbox(insn: MethodInsnNode): Boolean = {
- insn.owner == srBoxesRunTimeName && (unboxToMethods.get(Type.getReturnType(insn.desc).getSort) match {
- case Some((name, desc)) => name == insn.name && desc == insn.desc
- case _ => false
- })
- }
-
- def getScalaUnbox(primitiveType: Type): MethodInsnNode = {
- val (method, desc) = unboxToMethods(primitiveType.getSort)
- new MethodInsnNode(INVOKESTATIC, srBoxesRunTimeName, method, desc, /*itf =*/ false)
- }
-
- def isJavaBox(insn: MethodInsnNode): Boolean = {
- insn.name == "valueOf" && {
- val args = Type.getArgumentTypes(insn.desc)
- args.length == 1 && ((args(0).getSort: @switch) match {
- case Type.BOOLEAN => insn.owner == "java/lang/Boolean" && insn.desc == "(Z)Ljava/lang/Boolean;"
- case Type.BYTE => insn.owner == "java/lang/Byte" && insn.desc == "(B)Ljava/lang/Byte;"
- case Type.CHAR => insn.owner == "java/lang/Character" && insn.desc == "(C)Ljava/lang/Character;"
- case Type.SHORT => insn.owner == "java/lang/Short" && insn.desc == "(S)Ljava/lang/Short;"
- case Type.INT => insn.owner == "java/lang/Integer" && insn.desc == "(I)Ljava/lang/Integer;"
- case Type.LONG => insn.owner == "java/lang/Long" && insn.desc == "(J)Ljava/lang/Long;"
- case Type.FLOAT => insn.owner == "java/lang/Float" && insn.desc == "(F)Ljava/lang/Float;"
- case Type.DOUBLE => insn.owner == "java/lang/Double" && insn.desc == "(D)Ljava/lang/Double;"
- case _ => false
- })
- }
- }
-
- def isJavaUnbox(insn: MethodInsnNode): Boolean = {
- insn.desc.startsWith("()") && {
- (Type.getReturnType(insn.desc).getSort: @switch) match {
- case Type.BOOLEAN => insn.owner == "java/lang/Boolean" && insn.name == "booleanValue"
- case Type.BYTE => insn.owner == "java/lang/Byte" && insn.name == "byteValue"
- case Type.CHAR => insn.owner == "java/lang/Character" && insn.name == "charValue"
- case Type.SHORT => insn.owner == "java/lang/Short" && insn.name == "shortValue"
- case Type.INT => insn.owner == "java/lang/Integer" && insn.name == "intValue"
- case Type.LONG => insn.owner == "java/lang/Long" && insn.name == "longValue"
- case Type.FLOAT => insn.owner == "java/lang/Float" && insn.name == "floatValue"
- case Type.DOUBLE => insn.owner == "java/lang/Double" && insn.name == "doubleValue"
- case _ => false
- }
- }
- }
-
- def isPredefAutoBox(insn: MethodInsnNode): Boolean = {
- insn.owner == "scala/Predef$" && {
- val args = Type.getArgumentTypes(insn.desc)
- args.length == 1 && ((args(0).getSort: @switch) match {
- case Type.BOOLEAN => insn.name == "boolean2Boolean" && insn.desc == "(Z)Ljava/lang/Boolean;"
- case Type.BYTE => insn.name == "byte2Byte" && insn.desc == "(B)Ljava/lang/Byte;"
- case Type.CHAR => insn.name == "char2Character" && insn.desc == "(C)Ljava/lang/Character;"
- case Type.SHORT => insn.name == "short2Short" && insn.desc == "(S)Ljava/lang/Short;"
- case Type.INT => insn.name == "int2Integer" && insn.desc == "(I)Ljava/lang/Integer;"
- case Type.LONG => insn.name == "long2Long" && insn.desc == "(J)Ljava/lang/Long;"
- case Type.FLOAT => insn.name == "float2Float" && insn.desc == "(F)Ljava/lang/Float;"
- case Type.DOUBLE => insn.name == "double2Double" && insn.desc == "(D)Ljava/lang/Double;"
- case _ => false
- })
- }
- }
-
- def isPredefAutoUnbox(insn: MethodInsnNode): Boolean = {
- insn.owner == "scala/Predef$" && {
- (Type.getReturnType(insn.desc).getSort: @switch) match {
- case Type.BOOLEAN => insn.name == "Boolean2boolean" && insn.desc == "(Ljava/lang/Boolean;)Z"
- case Type.BYTE => insn.name == "Byte2byte" && insn.desc == "(Ljava/lang/Byte;)B"
- case Type.CHAR => insn.name == "Character2char" && insn.desc == "(Ljava/lang/Character;)C"
- case Type.SHORT => insn.name == "Short2short" && insn.desc == "(Ljava/lang/Short;)S"
- case Type.INT => insn.name == "Integer2int" && insn.desc == "(Ljava/lang/Integer;)I"
- case Type.LONG => insn.name == "Long2long" && insn.desc == "(Ljava/lang/Long;)J"
- case Type.FLOAT => insn.name == "Float2float" && insn.desc == "(Ljava/lang/Float;)F"
- case Type.DOUBLE => insn.name == "Double2double" && insn.desc == "(Ljava/lang/Double;)D"
- case _ => false
- }
- }
- }
-
- def isRefCreate(insn: MethodInsnNode): Boolean = {
- insn.name == "create" && {
- val args = Type.getArgumentTypes(insn.desc)
- args.length == 1 && ((args(0).getSort: @switch) match {
- case Type.BOOLEAN => insn.owner == "scala/runtime/BooleanRef" && insn.desc == "(Z)Lscala/runtime/BooleanRef;" || insn.owner == "scala/runtime/VolatileBooleanRef" && insn.desc == "(Z)Lscala/runtime/VolatileBooleanRef;"
- case Type.BYTE => insn.owner == "scala/runtime/ByteRef" && insn.desc == "(B)Lscala/runtime/ByteRef;" || insn.owner == "scala/runtime/VolatileByteRef" && insn.desc == "(B)Lscala/runtime/VolatileByteRef;"
- case Type.CHAR => insn.owner == "scala/runtime/CharRef" && insn.desc == "(C)Lscala/runtime/CharRef;" || insn.owner == "scala/runtime/VolatileCharRef" && insn.desc == "(C)Lscala/runtime/VolatileCharRef;"
- case Type.SHORT => insn.owner == "scala/runtime/ShortRef" && insn.desc == "(S)Lscala/runtime/ShortRef;" || insn.owner == "scala/runtime/VolatileShortRef" && insn.desc == "(S)Lscala/runtime/VolatileShortRef;"
- case Type.INT => insn.owner == "scala/runtime/IntRef" && insn.desc == "(I)Lscala/runtime/IntRef;" || insn.owner == "scala/runtime/VolatileIntRef" && insn.desc == "(I)Lscala/runtime/VolatileIntRef;"
- case Type.LONG => insn.owner == "scala/runtime/LongRef" && insn.desc == "(J)Lscala/runtime/LongRef;" || insn.owner == "scala/runtime/VolatileLongRef" && insn.desc == "(J)Lscala/runtime/VolatileLongRef;"
- case Type.FLOAT => insn.owner == "scala/runtime/FloatRef" && insn.desc == "(F)Lscala/runtime/FloatRef;" || insn.owner == "scala/runtime/VolatileFloatRef" && insn.desc == "(F)Lscala/runtime/VolatileFloatRef;"
- case Type.DOUBLE => insn.owner == "scala/runtime/DoubleRef" && insn.desc == "(D)Lscala/runtime/DoubleRef;" || insn.owner == "scala/runtime/VolatileDoubleRef" && insn.desc == "(D)Lscala/runtime/VolatileDoubleRef;"
- case Type.OBJECT => insn.owner == "scala/runtime/ObjectRef" && insn.desc == "(Ljava/lang/Object;)Lscala/runtime/ObjectRef;" || insn.owner == "scala/runtime/VolatileObjectRef" && insn.desc == "(Ljava/lang/Object;)Lscala/runtime/VolatileObjectRef;"
- case _ => false
- })
- }
- }
-
- private val jlObjectType = Type.getType("Ljava/lang/Object;")
-
- private val runtimeRefClassesAndTypes = Map(
- ("scala/runtime/BooleanRef", Type.BOOLEAN_TYPE),
- ("scala/runtime/ByteRef", Type.BYTE_TYPE),
- ("scala/runtime/CharRef", Type.CHAR_TYPE),
- ("scala/runtime/ShortRef", Type.SHORT_TYPE),
- ("scala/runtime/IntRef", Type.INT_TYPE),
- ("scala/runtime/LongRef", Type.LONG_TYPE),
- ("scala/runtime/FloatRef", Type.FLOAT_TYPE),
- ("scala/runtime/DoubleRef", Type.DOUBLE_TYPE),
- ("scala/runtime/ObjectRef", jlObjectType),
- ("scala/runtime/VolatileBooleanRef", Type.BOOLEAN_TYPE),
- ("scala/runtime/VolatileByteRef", Type.BYTE_TYPE),
- ("scala/runtime/VolatileCharRef", Type.CHAR_TYPE),
- ("scala/runtime/VolatileShortRef", Type.SHORT_TYPE),
- ("scala/runtime/VolatileIntRef", Type.INT_TYPE),
- ("scala/runtime/VolatileLongRef", Type.LONG_TYPE),
- ("scala/runtime/VolatileFloatRef", Type.FLOAT_TYPE),
- ("scala/runtime/VolatileDoubleRef", Type.DOUBLE_TYPE),
- ("scala/runtime/VolatileObjectRef", jlObjectType))
-
- def isRefZero(insn: MethodInsnNode): Boolean = {
- insn.name == "zero" && runtimeRefClassesAndTypes.contains(insn.owner) && insn.desc == "()L" + insn.owner + ";"
- }
-
- def runtimeRefClassBoxedType(refClass: InternalName): Type = runtimeRefClassesAndTypes(refClass)
-
- def isModuleLoad(insn: AbstractInsnNode, moduleName: InternalName): Boolean = insn match {
- case fi: FieldInsnNode => fi.getOpcode == GETSTATIC && fi.owner == moduleName && fi.name == "MODULE$" && fi.desc == ("L" + moduleName + ";")
- case _ => false
- }
-
- def isPredefLoad(insn: AbstractInsnNode) = isModuleLoad(insn, "scala/Predef$")
-
- private val primitiveBoxConstructors = Set(
- "java/lang/Boolean(Z)V",
- "java/lang/Byte(B)V",
- "java/lang/Character(C)V",
- "java/lang/Short(S)V",
- "java/lang/Integer(I)V",
- "java/lang/Long(J)V",
- "java/lang/Float(F)V",
- "java/lang/Double(D)V")
-
- def isPrimitiveBoxConstructor(insn: MethodInsnNode): Boolean = {
- insn.name == INSTANCE_CONSTRUCTOR_NAME && primitiveBoxConstructors(insn.owner + insn.desc)
- }
-
- private val runtimeRefConstructors = Set(
- "scala/runtime/ObjectRef(Ljava/lang/Object;)V",
- "scala/runtime/BooleanRef(Z)V",
- "scala/runtime/ByteRef(B)V",
- "scala/runtime/CharRef(C)V",
- "scala/runtime/ShortRef(S)V",
- "scala/runtime/IntRef(I)V",
- "scala/runtime/LongRef(J)V",
- "scala/runtime/FloatRef(F)V",
- "scala/runtime/DoubleRef(D)V",
-
- "scala/runtime/VolatileObjectRef(Ljava/lang/Object;)V",
- "scala/runtime/VolatileBooleanRef(Z)V",
- "scala/runtime/VolatileByteRef(B)V",
- "scala/runtime/VolatileCharRef(C)V",
- "scala/runtime/VolatileShortRef(S)V",
- "scala/runtime/VolatileIntRef(I)V",
- "scala/runtime/VolatileLongRef(J)V",
- "scala/runtime/VolatileFloatRef(F)V",
- "scala/runtime/VolatileDoubleRef(D)V")
-
- def isRuntimeRefConstructor(insn: MethodInsnNode): Boolean = {
- insn.name == INSTANCE_CONSTRUCTOR_NAME && runtimeRefConstructors(insn.owner + insn.desc)
- }
-
- private val tupleConstructors = Set.empty[String] ++ {
- (1 to 22).map(n => "scala/Tuple" + n + "(" + ("Ljava/lang/Object;" * n) + ")V")
- } ++ {
- Iterator("I", "J", "D").map(t => "scala/Tuple1$mc" + t + "$sp(" + t + ")V")
- } ++ {
- def tuple2Specs = Iterator("I", "J", "D", "C", "Z")
- for (a <- tuple2Specs; b <- tuple2Specs) yield "scala/Tuple2$mc" + a + b + "$sp(" + a + b + ")V"
- }
-
- def isTupleConstructor(insn: MethodInsnNode): Boolean = {
- insn.name == INSTANCE_CONSTRUCTOR_NAME && tupleConstructors(insn.owner + insn.desc)
- }
-
- // unused objects created by these constructors are eliminated by pushPop
- private val sideEffectFreeConstructors = primitiveBoxConstructors ++
- runtimeRefConstructors ++
- tupleConstructors ++ Set(
- "java/lang/Object()V",
- "java/lang/String()V",
- "java/lang/String(Ljava/lang/String;)V",
- "java/lang/String([C)V"
- )
-
- def isSideEffectFreeConstructorCall(insn: MethodInsnNode): Boolean = {
- insn.name == INSTANCE_CONSTRUCTOR_NAME && sideEffectFreeConstructors(insn.owner + insn.desc)
- }
-
- private val classesForSideEffectFreeConstructors = sideEffectFreeConstructors.map(s => s.substring(0, s.indexOf('(')))
-
- // we only eliminate `NEW C` if the class C has a constructor that we consider side-effect free.
- // removing a `NEW` eliminates a potential NoClassDefFoundError, so we only do it for core classes.
- def isNewForSideEffectFreeConstructor(insn: AbstractInsnNode) = {
- insn.getOpcode == NEW && {
- val ti = insn.asInstanceOf[TypeInsnNode]
- classesForSideEffectFreeConstructors(ti.desc)
- }
- }
-
- def isBoxedUnit(insn: AbstractInsnNode) = {
- insn.getOpcode == GETSTATIC && {
- val fi = insn.asInstanceOf[FieldInsnNode]
- fi.owner == "scala/runtime/BoxedUnit" && fi.name == "UNIT" && fi.desc == "Lscala/runtime/BoxedUnit;"
- }
- }
-
- private def buildFunctionTypes(base: String): Set[InternalName] = {
- def primitives = Iterator("B", "S", "I", "J", "C", "F", "D", "Z", "V")
- def ijfd = Iterator("I", "J", "F", "D")
- def ijfdzv = Iterator("I", "J", "F", "D", "Z", "V")
- def ijd = Iterator("I", "J", "D")
- Set.empty[String] ++ {
- (0 to 22).map(base + _)
- } ++ {
- primitives.map(base + "0$mc" + _ + "$sp") // Function0
- } ++ {
- // return type specializations appear first in the name string (alphabetical sorting)
- for (r <- ijfdzv; a <- ijfd) yield base + "1$mc" + r + a + "$sp" // Function1
- } ++ {
- for (r <- ijfdzv; a <- ijd; b <- ijd) yield base + "2$mc" + r + a + b + "$sp" // Function2
- }
- }
-
- private val srJFunctionTypes: Set[InternalName] = buildFunctionTypes("scala/runtime/java8/JFunction")
- def isrJFunctionType(internalName: InternalName): Boolean = srJFunctionTypes(internalName)
-
- private val sFunctionTypes: Set[InternalName] = buildFunctionTypes("scala/Function")
- def isScalaFunctionType(internalName: InternalName): Boolean = sFunctionTypes(internalName)
-
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 64677ddcc0..863bb2d10a 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -103,7 +103,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
val analyzer = {
if (compilerSettings.YoptNullnessTracking && AsmAnalyzer.sizeOKForNullness(methodNode)) {
- Some(new AsmAnalyzer(methodNode, definingClass.internalName, new NullnessAnalyzer))
+ Some(new AsmAnalyzer(methodNode, definingClass.internalName, new NullnessAnalyzer(btypes)))
} else if (AsmAnalyzer.sizeOKForBasicValue(methodNode)) {
Some(new AsmAnalyzer(methodNode, definingClass.internalName))
} else None
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
index 35bc82d098..f98a08a6a9 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ClosureOptimizer.scala
@@ -254,18 +254,6 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) {
Type.VOID <= sort && sort <= Type.DOUBLE
}
- private def unboxOp(primitiveType: Type): MethodInsnNode = {
- val bType = bTypeForDescriptorOrInternalNameFromClassfile(primitiveType.getDescriptor)
- val MethodNameAndType(name, methodBType) = asmUnboxTo(bType)
- new MethodInsnNode(INVOKESTATIC, srBoxesRunTimeRef.internalName, name, methodBType.descriptor, /*itf =*/ false)
- }
-
- private def boxOp(primitiveType: Type): MethodInsnNode = {
- val bType = bTypeForDescriptorOrInternalNameFromClassfile(primitiveType.getDescriptor)
- val MethodNameAndType(name, methodBType) = asmBoxTo(bType)
- new MethodInsnNode(INVOKESTATIC, srBoxesRunTimeRef.internalName, name, methodBType.descriptor, /*itf =*/ false)
- }
-
/**
* The argument types of the lambda body method may differ in two ways from the argument types of
* the closure member method that is invoked (and replaced by a call to the body).
@@ -291,9 +279,9 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) {
if (invokeArgTypes(i) == implMethodArgTypes(i)) {
res(i) = None
} else if (isPrimitiveType(implMethodArgTypes(i)) && invokeArgTypes(i).getDescriptor == ObjectRef.descriptor) {
- res(i) = Some(unboxOp(implMethodArgTypes(i)))
+ res(i) = Some(getScalaUnbox(implMethodArgTypes(i)))
} else if (isPrimitiveType(invokeArgTypes(i)) && implMethodArgTypes(i).getDescriptor == ObjectRef.descriptor) {
- res(i) = Some(boxOp(invokeArgTypes(i)))
+ res(i) = Some(getScalaBox(invokeArgTypes(i)))
} else {
assert(!isPrimitiveType(invokeArgTypes(i)), invokeArgTypes(i))
assert(!isPrimitiveType(implMethodArgTypes(i)), implMethodArgTypes(i))
@@ -354,12 +342,12 @@ class ClosureOptimizer[BT <: BTypes](val btypes: BT) {
if (isPrimitiveType(invocationReturnType) && bodyReturnType.getDescriptor == ObjectRef.descriptor) {
val op =
if (invocationReturnType.getSort == Type.VOID) getPop(1)
- else unboxOp(invocationReturnType)
+ else getScalaUnbox(invocationReturnType)
ownerMethod.instructions.insertBefore(invocation, op)
} else if (isPrimitiveType(bodyReturnType) && invocationReturnType.getDescriptor == ObjectRef.descriptor) {
val op =
if (bodyReturnType.getSort == Type.VOID) getBoxedUnit
- else boxOp(bodyReturnType)
+ else getScalaBox(bodyReturnType)
ownerMethod.instructions.insertBefore(invocation, op)
} else {
// see comment of that method
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
index 8db922a635..cd4d5be197 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/LocalOpt.scala
@@ -364,7 +364,7 @@ class LocalOpt[BT <: BTypes](val btypes: BT) {
*/
def nullnessOptimizations(method: MethodNode, ownerClassName: InternalName): Boolean = {
AsmAnalyzer.sizeOKForNullness(method) && {
- lazy val nullnessAnalyzer = new AsmAnalyzer(method, ownerClassName, new NullnessAnalyzer)
+ lazy val nullnessAnalyzer = new AsmAnalyzer(method, ownerClassName, new NullnessAnalyzer(btypes))
// When running nullness optimizations the method may still have unreachable code. Analyzer
// frames of unreachable instructions are `null`.
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index d1be1558b9..43f698d7ba 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -31,11 +31,6 @@ abstract class LambdaLift extends InfoTransform {
}
}
- /** scala.runtime.*Ref classes */
- private lazy val allRefClasses: Set[Symbol] = {
- refClass.values.toSet ++ volatileRefClass.values.toSet ++ Set(VolatileObjectRefClass, ObjectRefClass)
- }
-
/** Each scala.runtime.*Ref class has a static method `create(value)` that simply instantiates the Ref to carry that value. */
private lazy val refCreateMethod: Map[Symbol, Symbol] = {
mapFrom(allRefClasses.toList)(x => getMemberMethod(x.companionModule, nme.create))
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 5ce5c39145..f2da7614a3 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -93,6 +93,10 @@ trait Definitions extends api.StandardDefinitions {
lazy val refClass = classesMap(x => getRequiredClass("scala.runtime." + x + "Ref"))
lazy val volatileRefClass = classesMap(x => getRequiredClass("scala.runtime.Volatile" + x + "Ref"))
+ lazy val allRefClasses: Set[Symbol] = {
+ refClass.values.toSet ++ volatileRefClass.values.toSet ++ Set(VolatileObjectRefClass, ObjectRefClass)
+ }
+
def isNumericSubClass(sub: Symbol, sup: Symbol) = (
(numericWeight contains sub)
&& (numericWeight contains sup)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 0132fff17c..46e4371cfa 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -424,6 +424,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.boxedClass
definitions.refClass
definitions.volatileRefClass
+ definitions.allRefClasses
definitions.UnitClass
definitions.ByteClass
definitions.ShortClass
diff --git a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
index a7d1dc168a..daff6fc223 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/analysis/NullnessAnalyzerTest.scala
@@ -33,7 +33,7 @@ class NullnessAnalyzerTest extends ClearAfterClass {
val noOptCompiler = NullnessAnalyzerTest.noOptCompiler
import noOptCompiler.genBCode.bTypes.backendUtils._
- def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer)
+ def newNullnessAnalyzer(methodNode: MethodNode, classInternalName: InternalName = "C") = new AsmAnalyzer(methodNode, classInternalName, new NullnessAnalyzer(noOptCompiler.genBCode.bTypes))
def testNullness(analyzer: AsmAnalyzer[NullnessValue], method: MethodNode, query: String, index: Int, nullness: NullnessValue): Unit = {
for (i <- findInstr(method, query)) {