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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user