Eliminate only first {ASTORE, ALOAD} in locals elimination

of ALOAD.
 #KT-25912: Fixed.
This commit is contained in:
Ilmir Usmanov
2018-08-07 17:41:55 +03:00
parent ff70b837ee
commit a470fd21ca
15 changed files with 119 additions and 28 deletions
@@ -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))
@@ -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) {
@@ -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()
+23
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");