Skip to content

Commit f2d7838

Browse files
committed
Merge pull request scala#4657 from lrytz/backports
backports from 2.12.x
2 parents 4c6dcfe + 241bb9a commit f2d7838

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+952
-429
lines changed

src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import java.io.{StringWriter, PrintWriter}
1010
import scala.tools.asm.util.{CheckClassAdapter, TraceClassVisitor, TraceMethodVisitor, Textifier}
1111
import scala.tools.asm.{ClassWriter, Attribute, ClassReader}
1212
import scala.collection.convert.decorateAsScala._
13+
import scala.tools.nsc.backend.jvm.analysis.InitialProducer
1314
import scala.tools.nsc.backend.jvm.opt.InlineInfoAttributePrototype
1415

1516
object AsmUtils {
@@ -81,13 +82,16 @@ object AsmUtils {
8182
/**
8283
* Returns a human-readable representation of the given instruction.
8384
*/
84-
def textify(insn: AbstractInsnNode): String = {
85-
val trace = new TraceMethodVisitor(new Textifier)
86-
insn.accept(trace)
87-
val sw = new StringWriter
88-
val pw = new PrintWriter(sw)
89-
trace.p.print(pw)
90-
sw.toString.trim
85+
def textify(insn: AbstractInsnNode): String = insn match {
86+
case _: InitialProducer =>
87+
insn.toString
88+
case _ =>
89+
val trace = new TraceMethodVisitor(new Textifier)
90+
insn.accept(trace)
91+
val sw = new StringWriter
92+
val pw = new PrintWriter(sw)
93+
trace.p.print(pw)
94+
sw.toString.trim
9195
}
9296

9397
/**

src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,17 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
256256
if (hasAbstractMethod) ACC_ABSTRACT else 0
257257
}
258258
GenBCode.mkFlags(
259-
if (classSym.isPublic) ACC_PUBLIC else 0,
260-
if (classSym.isFinal) ACC_FINAL else 0,
259+
// SI-9393: the classfile / java source parser make java annotation symbols look like classes.
260+
// here we recover the actual classfile flags.
261+
if (classSym.hasJavaAnnotationFlag) ACC_ANNOTATION | ACC_INTERFACE | ACC_ABSTRACT else 0,
262+
if (classSym.isPublic) ACC_PUBLIC else 0,
263+
if (classSym.isFinal) ACC_FINAL else 0,
261264
// see the link above. javac does the same: ACC_SUPER for all classes, but not interfaces.
262-
if (classSym.isInterface) ACC_INTERFACE else ACC_SUPER,
265+
if (classSym.isInterface) ACC_INTERFACE else ACC_SUPER,
263266
// for Java enums, we cannot trust `hasAbstractFlag` (see comment in enumFlags)
264-
if (!classSym.hasEnumFlag && classSym.hasAbstractFlag) ACC_ABSTRACT else 0,
265-
if (classSym.isArtifact) ACC_SYNTHETIC else 0,
266-
if (classSym.hasEnumFlag) enumFlags else 0
267+
if (!classSym.hasJavaEnumFlag && classSym.hasAbstractFlag) ACC_ABSTRACT else 0,
268+
if (classSym.isArtifact) ACC_SYNTHETIC else 0,
269+
if (classSym.hasJavaEnumFlag) enumFlags else 0
267270
)
268271
}
269272

@@ -310,10 +313,10 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
310313
}
311314

312315
private def retentionPolicyOf(annot: AnnotationInfo): Symbol =
313-
annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).map(assoc =>
316+
annot.atp.typeSymbol.getAnnotation(AnnotationRetentionAttr).map(_.assocs).flatMap(assoc =>
314317
assoc.collectFirst {
315318
case (`nme`.value, LiteralAnnotArg(Constant(value: Symbol))) => value
316-
}).flatten.getOrElse(AnnotationRetentionPolicyClassValue)
319+
}).getOrElse(AnnotationRetentionPolicyClassValue)
317320

318321
def implementedInterfaces(classSym: Symbol): List[Symbol] = {
319322
// Additional interface parents based on annotations and other cues
@@ -322,9 +325,18 @@ final class BCodeAsmCommon[G <: Global](val global: G) {
322325
case _ => None
323326
}
324327

325-
def isInterfaceOrTrait(sym: Symbol) = sym.isInterface || sym.isTrait
328+
// SI-9393: java annotations are interfaces, but the classfile / java source parsers make them look like classes.
329+
def isInterfaceOrTrait(sym: Symbol) = sym.isInterface || sym.isTrait || sym.hasJavaAnnotationFlag
326330

327-
val allParents = classSym.info.parents ++ classSym.annotations.flatMap(newParentForAnnotation)
331+
val classParents = {
332+
val parents = classSym.info.parents
333+
// SI-9393: the classfile / java source parsers add Annotation and ClassfileAnnotation to the
334+
// parents of a java annotations. undo this for the backend (where we need classfile-level information).
335+
if (classSym.hasJavaAnnotationFlag) parents.filterNot(c => c.typeSymbol == ClassfileAnnotationClass || c.typeSymbol == AnnotationClass)
336+
else parents
337+
}
338+
339+
val allParents = classParents ++ classSym.annotations.flatMap(newParentForAnnotation)
328340

329341
// We keep the superClass when computing minimizeParents to eliminate more interfaces.
330342
// Example: T can be eliminated from D

src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,10 +632,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
632632
case _ =>
633633
abort(s"Cannot instantiate $tpt of kind: $generatedType")
634634
}
635-
case Apply(_, args) if app.hasAttachment[delambdafy.LambdaMetaFactoryCapable] =>
635+
case Apply(fun, args) if app.hasAttachment[delambdafy.LambdaMetaFactoryCapable] =>
636636
val attachment = app.attachments.get[delambdafy.LambdaMetaFactoryCapable].get
637637
genLoadArguments(args, paramTKs(app))
638638
genInvokeDynamicLambda(attachment.target, attachment.arity, attachment.functionalInterface)
639+
generatedType = asmMethodType(fun.symbol).returnType
639640

640641
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) =>
641642
val nativeKind = tpeTK(expr)

src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
329329
// If the `sym` is a java module class, we use the java class instead. This ensures that we
330330
// register the class (instead of the module class) in innerClassBufferASM.
331331
// The two symbols have the same name, so the resulting internalName is the same.
332-
val classSym = if (sym.isJavaDefined && sym.isModuleClass) sym.linkedClassOfClass else sym
332+
// Phase travel (exitingPickler) required for SI-6613 - linkedCoC is only reliable in early phases (nesting)
333+
val classSym = if (sym.isJavaDefined && sym.isModuleClass) exitingPickler(sym.linkedClassOfClass) else sym
333334
getClassBTypeAndRegisterInnerClass(classSym).internalName
334335
}
335336

@@ -714,7 +715,8 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
714715
{
715716
val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", "(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", null, null)
716717
mv.visitCode()
717-
mv.visitFieldInsn(GETSTATIC, clazz.javaBinaryName.encoded, "$deserializeLambdaCache$", "Ljava/util/Map;")
718+
// javaBinaryName returns the internal name of a class. Also used in BTypesFromsymbols.classBTypeFromSymbol.
719+
mv.visitFieldInsn(GETSTATIC, clazz.javaBinaryName.toString, "$deserializeLambdaCache$", "Ljava/util/Map;")
718720
mv.visitVarInsn(ASTORE, 1)
719721
mv.visitVarInsn(ALOAD, 1)
720722
val l0 = new asm.Label()
@@ -724,13 +726,13 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
724726
mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V", false)
725727
mv.visitVarInsn(ASTORE, 1)
726728
mv.visitVarInsn(ALOAD, 1)
727-
mv.visitFieldInsn(PUTSTATIC, clazz.javaBinaryName.encoded, "$deserializeLambdaCache$", "Ljava/util/Map;")
729+
mv.visitFieldInsn(PUTSTATIC, clazz.javaBinaryName.toString, "$deserializeLambdaCache$", "Ljava/util/Map;")
728730
mv.visitLabel(l0)
729-
mv.visitFrame(asm.Opcodes.F_APPEND,1, Array("java/util/Map"), 0, null)
731+
mv.visitFieldInsn(GETSTATIC, "scala/compat/java8/runtime/LambdaDeserializer$", "MODULE$", "Lscala/compat/java8/runtime/LambdaDeserializer$;")
730732
mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false)
731733
mv.visitVarInsn(ALOAD, 1)
732734
mv.visitVarInsn(ALOAD, 0)
733-
mv.visitMethodInsn(INVOKESTATIC, "scala/compat/java8/runtime/LambdaDeserializer", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false)
735+
mv.visitMethodInsn(INVOKEVIRTUAL, "scala/compat/java8/runtime/LambdaDeserializer$", "deserializeLambda", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/util/Map;Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", false)
734736
mv.visitInsn(ARETURN)
735737
mv.visitEnd()
736738
}

src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
153153
*/
154154
private def initJClass(jclass: asm.ClassVisitor) {
155155

156-
val ps = claszSymbol.info.parents
157-
val superClass: String = if (ps.isEmpty) ObjectReference.internalName else internalName(ps.head.typeSymbol)
158-
val interfaceNames = classBTypeFromSymbol(claszSymbol).info.get.interfaces map {
156+
val bType = classBTypeFromSymbol(claszSymbol)
157+
val superClass = bType.info.get.superClass.getOrElse(ObjectReference).internalName
158+
val interfaceNames = bType.info.get.interfaces map {
159159
case classBType =>
160160
if (classBType.isNestedClass.get) { innerClassBufferASM += classBType }
161161
classBType.internalName

src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,18 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
216216
}
217217

218218
private def setClassInfo(classSym: Symbol, classBType: ClassBType): ClassBType = {
219-
val superClassSym = if (classSym.isImplClass) ObjectClass else classSym.superClass
219+
// Check for isImplClass: trait implementation classes have NoSymbol as superClass
220+
// Check for hasAnnotationFlag for SI-9393: the classfile / java source parsers add
221+
// scala.annotation.Annotation as superclass to java annotations. In reality, java
222+
// annotation classfiles have superclass Object (like any interface classfile).
223+
val superClassSym = if (classSym.isImplClass || classSym.hasJavaAnnotationFlag) ObjectClass else {
224+
val sc = classSym.superClass
225+
// SI-9393: Java annotation classes don't have the ABSTRACT/INTERFACE flag, so they appear
226+
// (wrongly) as superclasses. Fix this for BTypes: the java annotation will appear as interface
227+
// (handled by method implementedInterfaces), the superclass is set to Object.
228+
if (sc.hasJavaAnnotationFlag) ObjectClass
229+
else sc
230+
}
220231
assert(
221232
if (classSym == ObjectClass)
222233
superClassSym == NoSymbol
@@ -351,7 +362,15 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
351362
val isTopLevel = innerClassSym.rawowner.isPackageClass
352363
// impl classes are considered top-level, see comment in BTypes
353364
if (isTopLevel || considerAsTopLevelImplementationArtifact(innerClassSym)) None
354-
else {
365+
else if (innerClassSym.rawowner.isTerm) {
366+
// This case should never be reached: the lambdalift phase mutates the rawowner field of all
367+
// classes to be the enclosing class. SI-9392 shows an errant macro that leaves a reference
368+
// to a local class symbol that no longer exists, which is not updated by lambdalift.
369+
devWarning(innerClassSym.pos,
370+
s"""The class symbol $innerClassSym with the term symbol ${innerClassSym.rawowner} as `rawowner` reached the backend.
371+
|Most likely this indicates a stale reference to a non-existing class introduced by a macro, see SI-9392.""".stripMargin)
372+
None
373+
} else {
355374
// See comment in BTypes, when is a class marked static in the InnerClass table.
356375
val isStaticNestedClass = isOriginallyStaticOwner(innerClassSym.originalOwner)
357376

@@ -559,7 +578,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
559578
if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
560579
if (sym.isArtifact) ACC_SYNTHETIC else 0,
561580
if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
562-
if (sym.hasEnumFlag) ACC_ENUM else 0,
581+
if (sym.hasJavaEnumFlag) ACC_ENUM else 0,
563582
if (sym.isVarargsMethod) ACC_VARARGS else 0,
564583
if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0,
565584
if (sym.isDeprecated) asm.Opcodes.ACC_DEPRECATED else 0

src/compiler/scala/tools/nsc/backend/jvm/BackendReporting.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package scala.tools.nsc
22
package backend.jvm
33

4-
import scala.tools.asm.tree.{AbstractInsnNode, MethodNode}
4+
import scala.tools.asm.tree.{InvokeDynamicInsnNode, AbstractInsnNode, MethodNode}
55
import scala.tools.nsc.backend.jvm.BTypes.InternalName
66
import scala.reflect.internal.util.Position
77
import scala.tools.nsc.settings.ScalaSettings
@@ -246,11 +246,16 @@ object BackendReporting {
246246
case class ResultingMethodTooLarge(calleeDeclarationClass: InternalName, name: String, descriptor: String,
247247
callsiteClass: InternalName, callsiteName: String, callsiteDesc: String) extends CannotInlineWarning
248248

249+
case object UnknownInvokeDynamicInstruction extends OptimizerWarning {
250+
override def toString = "The callee contains an InvokeDynamic instruction with an unknown bootstrap method (not a LambdaMetaFactory)."
251+
def emitWarning(settings: ScalaSettings): Boolean = settings.YoptWarningEmitAtInlineFailed
252+
}
253+
249254
/**
250255
* Used in `rewriteClosureApplyInvocations` when a closure apply callsite cannot be rewritten
251256
* to the closure body method.
252257
*/
253-
trait RewriteClosureApplyToClosureBodyFailed extends OptimizerWarning {
258+
sealed trait RewriteClosureApplyToClosureBodyFailed extends OptimizerWarning {
254259
def pos: Position
255260

256261
override def emitWarning(settings: ScalaSettings): Boolean = this match {

src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
307307
if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
308308
if (sym.isArtifact) ACC_SYNTHETIC else 0,
309309
if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
310-
if (sym.hasEnumFlag) ACC_ENUM else 0,
310+
if (sym.hasJavaEnumFlag) ACC_ENUM else 0,
311311
if (sym.isVarargsMethod) ACC_VARARGS else 0,
312312
if (sym.hasFlag(Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0
313313
)

src/compiler/scala/tools/nsc/backend/jvm/analysis/ProdConsAnalyzer.scala

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,20 @@ import scala.collection.convert.decorateAsScala._
5757
* copying operations.
5858
*/
5959
class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName) {
60+
61+
/* Timers for benchmarking ProdCons
62+
import scala.reflect.internal.util.Statistics._
63+
import ProdConsAnalyzer._
64+
val analyzerTimer = newSubTimer(classInternalName + "#" + methodNode.name + " - analysis", prodConsAnalyzerTimer)
65+
val consumersTimer = newSubTimer(classInternalName + "#" + methodNode.name + " - consumers", prodConsAnalyzerTimer)
66+
*/
67+
6068
val analyzer = new Analyzer(new InitialProducerSourceInterpreter)
69+
70+
// val start = analyzerTimer.start()
6171
analyzer.analyze(classInternalName, methodNode)
72+
// analyzerTimer.stop(start)
73+
// println(analyzerTimer.line)
6274

6375
def frameAt(insn: AbstractInsnNode) = analyzer.frameAt(insn, methodNode)
6476

@@ -103,7 +115,11 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
103115
def initialProducersForValueAt(insn: AbstractInsnNode, slot: Int): Set[AbstractInsnNode] = {
104116
def initialProducers(insn: AbstractInsnNode, producedSlot: Int): Set[AbstractInsnNode] = {
105117
if (isCopyOperation(insn)) {
106-
_initialProducersCache.getOrElseUpdate((insn, producedSlot), {
118+
val key = (insn, producedSlot)
119+
_initialProducersCache.getOrElseUpdate(key, {
120+
// prevent infinite recursion if an instruction is its own producer or consumer
121+
// see cyclicProdCons in ProdConsAnalyzerTest
122+
_initialProducersCache(key) = Set.empty
107123
val (sourceValue, sourceValueSlot) = copyOperationSourceValue(insn, producedSlot)
108124
sourceValue.insns.iterator.asScala.flatMap(initialProducers(_, sourceValueSlot)).toSet
109125
})
@@ -121,7 +137,11 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
121137
def ultimateConsumersOfValueAt(insn: AbstractInsnNode, slot: Int): Set[AbstractInsnNode] = {
122138
def ultimateConsumers(insn: AbstractInsnNode, consumedSlot: Int): Set[AbstractInsnNode] = {
123139
if (isCopyOperation(insn)) {
124-
_ultimateConsumersCache.getOrElseUpdate((insn, consumedSlot), {
140+
val key = (insn, consumedSlot)
141+
_ultimateConsumersCache.getOrElseUpdate(key, {
142+
// prevent infinite recursion if an instruction is its own producer or consumer
143+
// see cyclicProdCons in ProdConsAnalyzerTest
144+
_ultimateConsumersCache(key) = Set.empty
125145
for {
126146
producedSlot <- copyOperationProducedValueSlots(insn, consumedSlot)
127147
consumer <- consumersOfValueAt(insn.getNext, producedSlot)
@@ -384,6 +404,7 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
384404

385405
/** For each instruction, a set of potential consumers of the produced values. */
386406
private lazy val _consumersOfOutputsFrom: Map[AbstractInsnNode, Vector[Set[AbstractInsnNode]]] = {
407+
// val start = consumersTimer.start()
387408
var res = Map.empty[AbstractInsnNode, Vector[Set[AbstractInsnNode]]]
388409
for {
389410
insn <- methodNode.instructions.iterator.asScala
@@ -396,13 +417,20 @@ class ProdConsAnalyzer(methodNode: MethodNode, classInternalName: InternalName)
396417
val outputIndex = producedSlots.indexOf(i)
397418
res = res.updated(producer, currentConsumers.updated(outputIndex, currentConsumers(outputIndex) + insn))
398419
}
420+
// consumersTimer.stop(start)
421+
// println(consumersTimer.line)
399422
res
400423
}
401424

402425
private val _initialProducersCache: mutable.AnyRefMap[(AbstractInsnNode, Int), Set[AbstractInsnNode]] = mutable.AnyRefMap.empty
403426
private val _ultimateConsumersCache: mutable.AnyRefMap[(AbstractInsnNode, Int), Set[AbstractInsnNode]] = mutable.AnyRefMap.empty
404427
}
405428

429+
object ProdConsAnalyzer {
430+
import scala.reflect.internal.util.Statistics._
431+
val prodConsAnalyzerTimer = newTimer("Time in ProdConsAnalyzer", "jvm")
432+
}
433+
406434
/**
407435
* A class for pseudo-instructions representing the initial producers of local values that have
408436
* no producer instruction in the method:

src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import scala.collection.mutable
1212
import scala.reflect.internal.util.Collections._
1313
import scala.tools.asm.commons.CodeSizeEvaluator
1414
import scala.tools.asm.tree.analysis._
15-
import scala.tools.asm.{MethodWriter, ClassWriter, Label, Opcodes}
15+
import scala.tools.asm.{MethodWriter, ClassWriter, Label, Opcodes, Type}
1616
import scala.tools.asm.tree._
1717
import GenBCode._
1818
import scala.collection.convert.decorateAsScala._
@@ -104,6 +104,8 @@ object BytecodeUtils {
104104

105105
def isStrictfpMethod(methodNode: MethodNode): Boolean = (methodNode.access & Opcodes.ACC_STRICT) != 0
106106

107+
def isReference(t: Type) = t.getSort == Type.OBJECT || t.getSort == Type.ARRAY
108+
107109
def nextExecutableInstruction(instruction: AbstractInsnNode, alsoKeep: AbstractInsnNode => Boolean = Set()): Option[AbstractInsnNode] = {
108110
var result = instruction
109111
do { result = result.getNext }
@@ -330,6 +332,26 @@ object BytecodeUtils {
330332
)).toList
331333
}
332334

335+
/**
336+
* This method is used by optimizer components to eliminate phantom values of instruction
337+
* that load a value of type `Nothing$` or `Null$`. Such values on the stack don't interact well
338+
* with stack map frames.
339+
*
340+
* For example, `opt.getOrElse(throw e)` is re-written to an invocation of the lambda body, a
341+
* method with return type `Nothing$`. Similarly for `opt.getOrElse(null)` and `Null$`.
342+
*
343+
* During bytecode generation this is handled by BCodeBodyBuilder.adapt. See the comment in that
344+
* method which explains the issue with such phantom values.
345+
*/
346+
def fixLoadedNothingOrNullValue(loadedType: Type, loadInstr: AbstractInsnNode, methodNode: MethodNode, bTypes: BTypes): Unit = {
347+
if (loadedType == bTypes.coreBTypes.RT_NOTHING.toASMType) {
348+
methodNode.instructions.insert(loadInstr, new InsnNode(Opcodes.ATHROW))
349+
} else if (loadedType == bTypes.coreBTypes.RT_NULL.toASMType) {
350+
methodNode.instructions.insert(loadInstr, new InsnNode(Opcodes.ACONST_NULL))
351+
methodNode.instructions.insert(loadInstr, new InsnNode(Opcodes.POP))
352+
}
353+
}
354+
333355
/**
334356
* A wrapper to make ASM's Analyzer a bit easier to use.
335357
*/

0 commit comments

Comments
 (0)