From: Mikhail Bogdanov <mikhael.bogdanov@jetbrains.com>
Date: Sat, 5 Sep 2020 21:26:10 +0200
Subject: compiler/backend: Backport fix for compiling with ASM 8

Origin: https://github.com/JetBrains/kotlin/commit/db50afeafee3442069cf477f85f7195dbd228dcc
Bug: https://youtrack.jetbrains.com/issue/KT-39013

General rule to use linkedLabel or linkWithLabel when label from node is reused
in other instructions. If label is not linked then it will point to another
labelNode when visited
---
 .../jetbrains/kotlin/codegen/ExpressionCodegen.java  |  2 +-
 .../src/org/jetbrains/kotlin/codegen/codegenUtil.kt  | 20 ++++++++++++++++++++
 .../coroutines/CoroutineTransformerMethodVisitor.kt  |  3 ++-
 .../codegen/inline/InlineCodegenForDefaultBody.kt    |  4 +++-
 .../codegen/inline/InternalFinallyBlockInliner.java  |  3 ++-
 .../jetbrains/kotlin/codegen/inline/MethodInliner.kt |  2 +-
 .../nullCheck/RedundantNullCheckMethodTransformer.kt |  5 +++--
 .../kotlin/backend/jvm/codegen/ExpressionCodegen.kt  |  4 +++-
 8 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
index 61b42d4..c7cc6f6 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java
@@ -1535,7 +1535,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
             assert topOfStack == finallyBlockStackElement : "Top element of stack doesn't equals processing finally block";
 
             KtTryExpression jetTryExpression = finallyBlockStackElement.expression;
-            Label finallyStart = new Label();
+            Label finallyStart = linkedLabel();
             v.mark(finallyStart);
             finallyBlockStackElement.addGapLabel(finallyStart);
             if (isFinallyMarkerRequired(context)) {
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt
index 2127ada..46a2d1b 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt
@@ -58,6 +58,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
 import org.jetbrains.org.objectweb.asm.Type
 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
 import org.jetbrains.org.objectweb.asm.commons.Method
+import org.jetbrains.org.objectweb.asm.tree.LabelNode
 import org.jetbrains.org.objectweb.asm.tree.MethodNode
 import org.jetbrains.org.objectweb.asm.util.Textifier
 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
@@ -660,3 +661,22 @@ private fun generateLambdaForRunSuspend(
     lambdaBuilder.done()
     return lambdaBuilder.thisName
 }
+
+internal fun LabelNode.linkWithLabel(): LabelNode {
+    // Remember labelNode in label and vise versa.
+    // Before ASM 8 there was JB patch in MethodNode that makes such linking in constructor of LabelNode.
+    //
+    // protected LabelNode getLabelNode(final Label label) {
+    //    if (!(label.info instanceof LabelNode)) {
+    //      //label.info = new LabelNode(label); //[JB: needed for Coverage agent]
+    //      label.info = new LabelNode(); //ASM 8
+    //    }
+    //    return (LabelNode) label.info;
+    //  }
+    if (label.info == null) {
+        label.info = this
+    }
+    return this
+}
+
+fun linkedLabel(): Label = LabelNode().linkWithLabel().label
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt
index 7946b75..a7a3420 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.*
 import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
 import org.jetbrains.kotlin.codegen.optimization.fixStack.top
 import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
+import org.jetbrains.kotlin.codegen.linkWithLabel
 import org.jetbrains.kotlin.config.LanguageVersionSettings
 import org.jetbrains.kotlin.config.isReleaseCoroutines
 import org.jetbrains.kotlin.diagnostics.DiagnosticSink
@@ -666,7 +667,7 @@ class CoroutineTransformerMethodVisitor(
         methodNode: MethodNode,
         suspendMarkerVarIndex: Int
     ): LabelNode {
-        val continuationLabel = LabelNode()
+        val continuationLabel = LabelNode().linkWithLabel()
         val continuationLabelAfterLoadedResult = LabelNode()
         val suspendElementLineNumber = lineNumber
         var nextLineNumberNode = suspension.suspensionCallEnd.findNextOrNull { it is LineNumberNode } as? LineNumberNode
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt
index be30fb3..5d3a3b2 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt
@@ -6,6 +6,7 @@
 package org.jetbrains.kotlin.codegen.inline
 
 import org.jetbrains.kotlin.codegen.*
+import org.jetbrains.kotlin.codegen.linkWithLabel
 import org.jetbrains.kotlin.codegen.state.GenerationState
 import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil
 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
 import org.jetbrains.org.objectweb.asm.Label
 import org.jetbrains.org.objectweb.asm.Type
+import org.jetbrains.org.objectweb.asm.tree.LabelNode
 import org.jetbrains.org.objectweb.asm.tree.MethodNode
 
 class InlineCodegenForDefaultBody(
@@ -41,7 +43,7 @@ class InlineCodegenForDefaultBody(
 
     private val jvmSignature: JvmMethodGenericSignature
 
-    private val methodStartLabel = Label()
+    private val methodStartLabel = linkedLabel()
 
     init {
         assert(InlineUtil.isInline(function)) {
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java
index f309c00..b16c231 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java
@@ -33,6 +33,7 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.*;
 
+import static org.jetbrains.kotlin.codegen.CodegenUtilKt.linkedLabel;
 import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
 import static org.jetbrains.kotlin.codegen.inline.MethodInlinerUtilKt.getNextMeaningful;
 
@@ -187,7 +188,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
                 //Creating temp node for finally block copy with some additional instruction
                 MethodNode finallyBlockCopy = createEmptyMethodNode();
                 Label newFinallyStart = new Label();
-                Label insertedBlockEnd = new Label();
+                Label insertedBlockEnd = linkedLabel();
 
                 boolean generateAloadAstore = nonLocalReturnType != Type.VOID_TYPE && !finallyInfo.isEmpty();
                 if (generateAloadAstore) {
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt
index 364c266..d83ec58 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt
@@ -92,7 +92,7 @@ class MethodInliner(
         }
 
         //substitute returns with "goto end" instruction to keep non local returns in lambdas
-        val end = Label()
+        val end = linkedLabel()
         val isTransformingAnonymousObject = nodeRemapper is RegeneratedLambdaFieldRemapper
         transformedNode = doInline(transformedNode)
         if (!isTransformingAnonymousObject) {
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt
index 5ecfe35..3ffff6e 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.optimization.nullCheck
 import org.jetbrains.kotlin.codegen.coroutines.withInstructionAdapter
 import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
 import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
+import org.jetbrains.kotlin.codegen.linkWithLabel
 import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
 import org.jetbrains.kotlin.codegen.optimization.common.debugText
 import org.jetbrains.kotlin.codegen.optimization.common.isInsn
@@ -246,7 +247,7 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio
                 //  <...>   -- v is null here
 
                 val jumpsIfNull = insn.opcode == Opcodes.IFNULL
-                val originalLabel = insn.label
+                val originalLabel = insn.label.linkWithLabel()
                 originalLabels[insn] = originalLabel
                 insn.label = synthetic(LabelNode(Label()))
 
@@ -310,7 +311,7 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio
                 val originalLabel: LabelNode?
                 val insertAfterNotNull: AbstractInsnNode
                 if (jumpsIfInstance) {
-                    originalLabel = next.label
+                    originalLabel = next.label.linkWithLabel()
                     originalLabels[next] = next.label
                     val newLabel = synthetic(LabelNode(Label()))
                     methodNode.instructions.add(newLabel)
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
index 5aff0a6..9b1e28e 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
@@ -1087,7 +1087,7 @@ class ExpressionCodegen(
             assert(topOfStack === tryInfo) { "Top element of stack doesn't equals processing finally block" }
 
             val tryBlock = tryInfo.tryBlock
-            val finallyStart = markNewLabel()
+            val finallyStart = markNewLinkedLabel()
             tryInfo.gaps.add(finallyStart)
 
             //noinspection ConstantConditions
@@ -1335,6 +1335,8 @@ class ExpressionCodegen(
 
     private fun markNewLabel() = Label().apply { mv.visitLabel(this) }
 
+    private fun markNewLinkedLabel() = linkedLabel().apply { mv.visitLabel(this) }
+
     private fun IrElement.markLineNumber(startOffset: Boolean) {
         val offset = if (startOffset) this.startOffset else endOffset
         if (offset < 0) {
