diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 93d4d6d7366f..3ec63afdb9c3 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -691,7 +691,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { val nativeKind = tpeTK(expr) genLoad(expr, nativeKind) val MethodNameAndType(mname, methodType) = asmBoxTo(nativeKind) - bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor) + bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor, itf = false) generatedType = boxResultType(fun.symbol) // was toTypeKind(fun.symbol.tpe.resultType) case Apply(fun, List(expr)) if isUnbox(fun.symbol) => @@ -699,7 +699,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { val boxType = unboxResultType(fun.symbol) // was toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe) generatedType = boxType val MethodNameAndType(mname, methodType) = asmUnboxTo(boxType) - bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor) + bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor, itf = false) case app @ Apply(fun, args) => val sym = fun.symbol @@ -1150,15 +1150,16 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { } } - if (style.isStatic) { bc.invokestatic (jowner, jname, mdescr) } - else if (style.isSpecial) { bc.invokespecial (jowner, jname, mdescr) } + val isInterface = receiver.isEmittedInterface + if (style.isStatic) { bc.invokestatic (jowner, jname, mdescr, itf = isInterface) } + else if (style.isSpecial) { bc.invokespecial (jowner, jname, mdescr, itf = isInterface) } else if (style.isVirtual) { if (needsInterfaceCall(receiver)) { bc.invokeinterface(jowner, jname, mdescr) } else { bc.invokevirtual (jowner, jname, mdescr) } } else { assert(style.isSuper, s"An unknown InvokeStyle: $style") - bc.invokespecial(jowner, jname, mdescr) + bc.invokespecial(jowner, jname, mdescr, itf = isInterface) initModule() } @@ -1405,7 +1406,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { def genInvokeDynamicLambda(ctor: Symbol, lambdaTarget: Symbol, environmentSize: Int, functionalInterface: Symbol): BType = { debuglog(s"Using invokedynamic rather than `new ${ctor.owner}`") val generatedType = classBTypeFromSymbol(functionalInterface) - val isInterface = lambdaTarget.owner.isInterface + val isInterface = lambdaTarget.owner.isEmittedInterface val invokeStyle = if (lambdaTarget.isStaticMember) asm.Opcodes.H_INVOKESTATIC else if (lambdaTarget.isPrivate || lambdaTarget.isClassConstructor) asm.Opcodes.H_INVOKESPECIAL @@ -1417,7 +1418,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { classBTypeFromSymbol(lambdaTarget.owner).internalName, lambdaTarget.name.mangledString, asmMethodType(lambdaTarget).descriptor, - isInterface) + /* itf = */ isInterface) val (a,b) = lambdaTarget.info.paramTypes.splitAt(environmentSize) var (capturedParamsTypes, lambdaParamTypes) = if(int.doLabmdasFollowJVMMetafactoryOrder) (a,b) else (b,a) @@ -1448,6 +1449,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { new asm.Handle(asm.Opcodes.H_INVOKESTATIC, int.LambdaMetaFactory.javaBinaryName, int.MetafactoryName, "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", - int.LambdaMetaFactory.isInterface) + /* itf = */ int.LambdaMetaFactory.isEmittedInterface) } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala index 68412b5dbdeb..e553fa127d2c 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala @@ -443,7 +443,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters { "serialVersionUID", "J", null, // no java-generic-signature - new java.lang.Long(id) + java.lang.Long.valueOf(id) ).visitEnd() } } // end of trait BCClassGen diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala index 045710192a46..798160f9da04 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala @@ -136,7 +136,7 @@ trait BCodeIdiomatic { emit(Opcodes.ICONST_M1) emit(Opcodes.IXOR) } else if (kind == LONG) { - jmethod.visitLdcInsn(new java.lang.Long(-1)) + jmethod.visitLdcInsn(java.lang.Long.valueOf(-1)) jmethod.visitInsn(Opcodes.LXOR) } else { abort(s"Impossible to negate an $kind") @@ -215,7 +215,8 @@ trait BCodeIdiomatic { invokespecial( JavaStringBuilderClassName, INSTANCE_CONSTRUCTOR_NAME, - "()V" + "()V", + itf = false ) } @@ -325,7 +326,7 @@ trait BCodeIdiomatic { } else if (cst >= java.lang.Short.MIN_VALUE && cst <= java.lang.Short.MAX_VALUE) { jmethod.visitIntInsn(Opcodes.SIPUSH, cst) } else { - jmethod.visitLdcInsn(new Integer(cst)) + jmethod.visitLdcInsn(Integer.valueOf(cst)) } } @@ -334,7 +335,7 @@ trait BCodeIdiomatic { if (cst == 0L || cst == 1L) { emit(Opcodes.LCONST_0 + cst.asInstanceOf[Int]) } else { - jmethod.visitLdcInsn(new java.lang.Long(cst)) + jmethod.visitLdcInsn(java.lang.Long.valueOf(cst)) } } @@ -344,7 +345,7 @@ trait BCodeIdiomatic { if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2 emit(Opcodes.FCONST_0 + cst.asInstanceOf[Int]) } else { - jmethod.visitLdcInsn(new java.lang.Float(cst)) + jmethod.visitLdcInsn(java.lang.Float.valueOf(cst)) } } @@ -354,7 +355,7 @@ trait BCodeIdiomatic { if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d emit(Opcodes.DCONST_0 + cst.asInstanceOf[Int]) } else { - jmethod.visitLdcInsn(new java.lang.Double(cst)) + jmethod.visitLdcInsn(java.lang.Double.valueOf(cst)) } } @@ -398,12 +399,12 @@ trait BCodeIdiomatic { final def rem(tk: BType): Unit = { emitPrimitive(JCodeMethodN.remOpcodes, tk) } // can-multi-thread // can-multi-thread - final def invokespecial(owner: String, name: String, desc: String): Unit = { - jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false) + final def invokespecial(owner: String, name: String, desc: String, itf: Boolean): Unit = { + jmethod.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf) } // can-multi-thread - final def invokestatic(owner: String, name: String, desc: String): Unit = { - jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false) + final def invokestatic(owner: String, name: String, desc: String, itf: Boolean): Unit = { + jmethod.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf) } // can-multi-thread final def invokeinterface(owner: String, name: String, desc: String): Unit = { @@ -414,10 +415,6 @@ trait BCodeIdiomatic { jmethod.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false) } - final def invokedynamic(owner: String, name: String, desc: String): Unit = { - jmethod.visitMethodInsn(Opcodes.INVOKEDYNAMIC, owner, name, desc, false) - } - // can-multi-thread final def goTo(label: asm.Label): Unit = { jmethod.visitJumpInsn(Opcodes.GOTO, label) } // can-multi-thread diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BackendInterface.scala b/src/compiler/scala/tools/nsc/backend/jvm/BackendInterface.scala index 5d3174eb5d4a..ab147f8f7832 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BackendInterface.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BackendInterface.scala @@ -440,6 +440,14 @@ abstract class BackendInterface extends BackendInterfaceDefinitions { def tpe: Type // todo whats the differentce between tpe and info? def thisType: Type + /** Does this symbol actually correspond to an interface that will be emitted? + * In the backend, this should be preferred over `isInterface` because it + * also returns true for the symbols of the fake companion objects we + * create for Java-defined classes. + */ + final def isEmittedInterface: Boolean = isInterface || + isJavaDefined && isModuleClass && companionClass.isInterface + // tests def isClass: Boolean def isType: Boolean diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index 109d97db6b0f..7c5cc1edd468 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -1585,7 +1585,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => if (cst == 0L || cst == 1L) { jmethod.visitInsn(Opcodes.LCONST_0 + cst.asInstanceOf[Int]) } else { - jmethod.visitLdcInsn(new java.lang.Long(cst)) + jmethod.visitLdcInsn(java.lang.Long.valueOf(cst)) } } @@ -2567,7 +2567,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => emit(Opcodes.ICONST_M1) emit(Opcodes.IXOR) } else if(kind == LONG) { - jmethod.visitLdcInsn(new java.lang.Long(-1)) + jmethod.visitLdcInsn(java.lang.Long.valueOf(-1)) jmethod.visitInsn(Opcodes.LXOR) } else { abort("Impossible to negate an " + kind)