Eliminate only first {ASTORE, ALOAD} in locals elimination
of ALOAD. #KT-25912: Fixed.
This commit is contained in:
+2
-2
@@ -709,7 +709,7 @@ private class SuspensionPoint(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLastParameterIndex(desc: String, access: Int) =
|
||||
internal fun getLastParameterIndex(desc: String, access: Int) =
|
||||
Type.getArgumentTypes(desc).dropLast(1).map { it.size }.sum() + (if (!isStatic(access)) 1 else 0)
|
||||
|
||||
private fun getParameterTypesForCoroutineConstructor(desc: String, hasDispatchReceiver: Boolean, thisName: String) =
|
||||
@@ -842,7 +842,7 @@ private fun AbstractInsnNode?.isInvisibleInDebugVarInsn(methodNode: MethodNode):
|
||||
private val SAFE_OPCODES =
|
||||
((Opcodes.DUP..Opcodes.DUP2_X2) + Opcodes.NOP + Opcodes.POP + Opcodes.POP2 + (Opcodes.IFEQ..Opcodes.GOTO)).toSet()
|
||||
|
||||
private fun replaceFakeContinuationsWithRealOnes(methodNode: MethodNode, continuationIndex: Int) {
|
||||
internal fun replaceFakeContinuationsWithRealOnes(methodNode: MethodNode, continuationIndex: Int) {
|
||||
val fakeContinuations = methodNode.instructions.asSequence().filter(::isFakeContinuationMarker).toList()
|
||||
for (fakeContinuation in fakeContinuations) {
|
||||
methodNode.instructions.removeAll(listOf(fakeContinuation.previous.previous, fakeContinuation.previous))
|
||||
|
||||
+28
-23
@@ -67,23 +67,31 @@ class RedundantLocalsEliminationMethodTransformer(private val languageVersionSet
|
||||
private fun removeWithReplacement(
|
||||
methodNode: MethodNode
|
||||
): Boolean {
|
||||
val insns = findSafeAstorePredecessors(methodNode, ignoreLocalVariableTable = false) {
|
||||
val cfg = ControlFlowGraph.build(methodNode)
|
||||
val insns = findSafeAstorePredecessors(methodNode, cfg, ignoreLocalVariableTable = false) {
|
||||
it.isUnitInstance() || it.opcode == Opcodes.ACONST_NULL || it.opcode == Opcodes.ALOAD
|
||||
}
|
||||
insns.asIterable().firstOrNull { (pred, astore) ->
|
||||
val index = astore.localIndex()
|
||||
for ((pred, astore) in insns) {
|
||||
val aload = findSingleLoadFromAstore(astore, cfg, methodNode) ?: continue
|
||||
|
||||
methodNode.instructions.removeAll(listOf(pred, astore))
|
||||
|
||||
methodNode.instructions.asSequence()
|
||||
.filter { it.opcode == Opcodes.ALOAD && it.localIndex() == index }
|
||||
.toList()
|
||||
.forEach { methodNode.instructions.set(it, pred.clone()) }
|
||||
methodNode.instructions.set(aload, pred.clone())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun findSingleLoadFromAstore(
|
||||
astore: AbstractInsnNode,
|
||||
cfg: ControlFlowGraph,
|
||||
methodNode: MethodNode
|
||||
): AbstractInsnNode? {
|
||||
val aload = methodNode.instructions.asSequence()
|
||||
.singleOrNull { it.opcode == Opcodes.ALOAD && it.localIndex() == astore.localIndex() } ?: return null
|
||||
val succ = findImmediateSuccessors(astore, cfg, methodNode).singleOrNull() ?: return null
|
||||
return if (aload == succ) aload else null
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.clone() = when (this) {
|
||||
is FieldInsnNode -> FieldInsnNode(opcode, owner, name, desc)
|
||||
is VarInsnNode -> VarInsnNode(opcode, `var`)
|
||||
@@ -143,37 +151,34 @@ class RedundantLocalsEliminationMethodTransformer(private val languageVersionSet
|
||||
private fun removeAloadCheckcastContinuationAstore(methodNode: MethodNode, languageVersionSettings: LanguageVersionSettings): Boolean {
|
||||
// Here we ignore the duplicates of continuation in local variable table,
|
||||
// Since it increases performance greatly.
|
||||
val insns = findSafeAstorePredecessors(methodNode, ignoreLocalVariableTable = true) {
|
||||
val cfg = ControlFlowGraph.build(methodNode)
|
||||
val insns = findSafeAstorePredecessors(methodNode, cfg, ignoreLocalVariableTable = true) {
|
||||
it.opcode == Opcodes.CHECKCAST &&
|
||||
(it as TypeInsnNode).desc == languageVersionSettings.continuationAsmType().internalName &&
|
||||
it.previous?.opcode == Opcodes.ALOAD
|
||||
}
|
||||
|
||||
var changed = false
|
||||
|
||||
for ((checkcast, astore) in insns) {
|
||||
val aload = checkcast.previous
|
||||
val index = astore.localIndex()
|
||||
val aloadk = checkcast.previous
|
||||
val aloadn = findSingleLoadFromAstore(astore, cfg, methodNode) ?: continue
|
||||
|
||||
methodNode.instructions.removeAll(listOf(aload, checkcast, astore))
|
||||
|
||||
methodNode.instructions.asSequence()
|
||||
.filter { it.opcode == Opcodes.ALOAD && it.localIndex() == index }
|
||||
.toList()
|
||||
.forEach {
|
||||
methodNode.instructions.insertBefore(it, aload.clone())
|
||||
methodNode.instructions.set(it, checkcast.clone())
|
||||
}
|
||||
methodNode.instructions.removeAll(listOf(aloadk, checkcast, astore))
|
||||
methodNode.instructions.insertBefore(aloadn, aloadk.clone())
|
||||
methodNode.instructions.set(aloadn, checkcast.clone())
|
||||
changed = true
|
||||
}
|
||||
return insns.isNotEmpty()
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun findSafeAstorePredecessors(
|
||||
methodNode: MethodNode,
|
||||
cfg: ControlFlowGraph,
|
||||
ignoreLocalVariableTable: Boolean,
|
||||
predicate: (AbstractInsnNode) -> Boolean
|
||||
): Map<AbstractInsnNode, AbstractInsnNode> {
|
||||
val insns = methodNode.instructions.asSequence().filter { predicate(it) }.toList()
|
||||
|
||||
val cfg = ControlFlowGraph.build(methodNode)
|
||||
val res = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||
|
||||
for (insn in insns) {
|
||||
|
||||
+7
-3
@@ -9,9 +9,7 @@ import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodName
|
||||
import org.jetbrains.kotlin.codegen.coroutines.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
|
||||
import org.jetbrains.kotlin.codegen.writeKotlinMetadata
|
||||
@@ -179,6 +177,12 @@ class AnonymousObjectTransformer(
|
||||
}
|
||||
|
||||
deferringMethods.forEach { method ->
|
||||
replaceFakeContinuationsWithRealOnes(
|
||||
method.intermediate,
|
||||
if (!inliningContext.isContinuation)
|
||||
getLastParameterIndex(method.intermediate.desc, method.intermediate.access)
|
||||
else 0
|
||||
)
|
||||
removeFinallyMarkers(method.intermediate)
|
||||
method.visitEnd()
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
// IGNORE_BACKEND: JS_IR, JVM_IR, JS, NATIVE
|
||||
|
||||
import helpers.*
|
||||
import COROUTINES_PACKAGE.*
|
||||
|
||||
fun box(): String {
|
||||
val gg = object : Grouping<Int, String> {
|
||||
override fun sourceIterator(): Iterator<Int> = listOf(1).iterator()
|
||||
override fun keyOf(element: Int): String = "OK"
|
||||
}
|
||||
|
||||
var res = ""
|
||||
suspend {
|
||||
for (e in gg.sourceIterator()) {
|
||||
val key = gg.keyOf(e)
|
||||
res += key
|
||||
}
|
||||
}.startCoroutine(EmptyContinuation)
|
||||
return res
|
||||
}
|
||||
@@ -20,6 +20,7 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||
@@ -94,6 +95,7 @@ public final class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$2$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
synthetic final field this$0: CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$2
|
||||
@@ -193,6 +195,7 @@ public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||
|
||||
@@ -22,6 +22,7 @@ public final class CrossinlineKt$box$1$doResume$$inlined$filter$1$2$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
synthetic final field this$0: CrossinlineKt$box$1$doResume$$inlined$filter$1$2
|
||||
@@ -87,6 +88,7 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||
@@ -206,6 +208,7 @@ public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||
|
||||
+3
@@ -20,6 +20,7 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||
@@ -94,6 +95,7 @@ public final class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$2$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
synthetic final field this$0: CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$2
|
||||
@@ -193,6 +195,7 @@ public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||
|
||||
+3
@@ -22,6 +22,7 @@ public final class CrossinlineKt$box$1$doResume$$inlined$filter$1$2$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
synthetic final field this$0: CrossinlineKt$box$1$doResume$$inlined$filter$1$2
|
||||
@@ -87,6 +88,7 @@ public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||
@@ -206,6 +208,7 @@ public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
field L$2: java.lang.Object
|
||||
field L$3: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||
|
||||
Vendored
+1
@@ -15,6 +15,7 @@ final class InlineWithoutStateMachineKt$box$1 {
|
||||
@kotlin.Metadata
|
||||
final class InlineWithoutStateMachineKt$complexSuspend$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
field label: int
|
||||
inner class InlineWithoutStateMachineKt$complexSuspend$1
|
||||
|
||||
Vendored
+1
@@ -14,6 +14,7 @@ final class InlineWithoutStateMachineKt$box$1 {
|
||||
@kotlin.Metadata
|
||||
final class InlineWithoutStateMachineKt$complexSuspend$1 {
|
||||
field L$0: java.lang.Object
|
||||
field L$1: java.lang.Object
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class InlineWithoutStateMachineKt$complexSuspend$1
|
||||
|
||||
+10
@@ -5745,6 +5745,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt21605.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines.experimental");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("lastExpressionIsLoop.kt")
|
||||
public void testLastExpressionIsLoop_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
+10
@@ -5745,6 +5745,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt21605.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines.experimental");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("lastExpressionIsLoop.kt")
|
||||
public void testLastExpressionIsLoop_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
+10
@@ -5745,6 +5745,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt21605.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines.experimental");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("lastExpressionIsLoop.kt")
|
||||
public void testLastExpressionIsLoop_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
+5
@@ -5270,6 +5270,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt21605.kt", "kotlin.coroutines.experimental");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines.experimental");
|
||||
}
|
||||
|
||||
@TestMetadata("lastExpressionIsLoop.kt")
|
||||
public void testLastExpressionIsLoop_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
+10
@@ -5485,6 +5485,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt21605.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines.experimental");
|
||||
}
|
||||
|
||||
@TestMetadata("kt25912.kt")
|
||||
public void testKt25912_1_3() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/kt25912.kt", "kotlin.coroutines");
|
||||
}
|
||||
|
||||
@TestMetadata("lastExpressionIsLoop.kt")
|
||||
public void testLastExpressionIsLoop_1_2() throws Exception {
|
||||
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt", "kotlin.coroutines.experimental");
|
||||
|
||||
Reference in New Issue
Block a user