diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala | 285 |
1 files changed, 0 insertions, 285 deletions
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)) } |