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()