diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2016-02-14 21:20:54 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2016-02-14 21:20:54 +0100 |
commit | 9b334b2ea3f9eee0582447658dcf2ac244121644 (patch) | |
tree | 507f29dbf75604928b56d224c9ac379aa3ebf290 /src/compiler | |
parent | f70c77e1c4d5b6c951669d79cf73a1ff0b932312 (diff) | |
download | scala-9b334b2ea3f9eee0582447658dcf2ac244121644.tar.gz scala-9b334b2ea3f9eee0582447658dcf2ac244121644.tar.bz2 scala-9b334b2ea3f9eee0582447658dcf2ac244121644.zip |
Avoid generating ACONST_NULL; POP; ACONST_NULL when loading null
When loading a value of type scala.runtime.Null$ we need to add
POP; ACONST_NULL, see comment in BCodeBodyBuilder.adapt.
This is however not necessary if the null value is a simple ACONST_NULL.
This patch eliminates that redundancy.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 22 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala | 10 |
2 files changed, 21 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 1e7ea0c09d..8a90eb9780 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -717,7 +717,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { // for callsites marked `f(): @inline/noinline`. For nullary calls, the attachment // is on the Select node (not on the Apply node added by UnCurry). def checkInlineAnnotated(t: Tree): Unit = { - if (t.hasAttachment[InlineAnnotatedAttachment]) bc.jmethod.instructions.getLast match { + if (t.hasAttachment[InlineAnnotatedAttachment]) lastInsn match { case m: MethodInsnNode => if (app.hasAttachment[NoInlineCallsiteAttachment.type]) noInlineAnnotatedCallsites += m else inlineAnnotatedCallsites += m @@ -888,10 +888,24 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { * emitted instruction was an ATHROW. As explained above, it is OK to emit a second ATHROW, * the verifiers will be happy. */ - emit(asm.Opcodes.ATHROW) + if (lastInsn.getOpcode != asm.Opcodes.ATHROW) + emit(asm.Opcodes.ATHROW) } else if (from.isNullType) { - bc drop from - emit(asm.Opcodes.ACONST_NULL) + /* After loading an expression of type `scala.runtime.Null$`, introduce POP; ACONST_NULL. + * This is required to pass the verifier: in Scala's type system, Null conforms to any + * reference type. In bytecode, the type Null is represented by scala.runtime.Null$, which + * is not a subtype of all reference types. Example: + * + * def nl: Null = null // in bytecode, nl has return type scala.runtime.Null$ + * val a: String = nl // OK for Scala but not for the JVM, scala.runtime.Null$ does not conform to String + * + * In order to fix the above problem, the value returned by nl is dropped and ACONST_NULL is + * inserted instead - after all, an expression of type scala.runtime.Null$ can only be null. + */ + if (lastInsn.getOpcode != asm.Opcodes.ACONST_NULL) { + bc drop from + emit(asm.Opcodes.ACONST_NULL) + } } else (from, to) match { case (BYTE, LONG) | (SHORT, LONG) | (CHAR, LONG) | (INT, LONG) => bc.emitT2T(INT, LONG) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index 9dea21154f..96796b3244 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -437,9 +437,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { var varsInScope: List[Tuple2[Symbol, asm.Label]] = null // (local-var-sym -> start-of-scope) // helpers around program-points. - def lastInsn: asm.tree.AbstractInsnNode = { - mnode.instructions.getLast - } + def lastInsn: asm.tree.AbstractInsnNode = mnode.instructions.getLast def currProgramPoint(): asm.Label = { lastInsn match { case labnode: asm.tree.LabelNode => labnode.getLabel @@ -598,13 +596,11 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { genLoad(rhs, returnType) rhs match { - case Block(_, Return(_)) => () - case Return(_) => () + case Return(_) | Block(_, Return(_)) | Throw(_) | Block(_, Throw(_)) => () case EmptyTree => globalError("Concrete method has no definition: " + dd + ( if (settings.debug) "(found: " + methSymbol.owner.info.decls.toList.mkString(", ") + ")" - else "") - ) + else "")) case _ => bc emitRETURN returnType } |