Traverse multiple store-load chains for inlined lambda parameters
When a try-catch expression is passed as an argument to the inline lambda parameter, lambda variable on stack is spilled and restored in several different locations (1 for try-block, 1 for each catch-blocks). So it's possible that lambda to be invoked comes from multiple loads, all of which should have the same "root" lambda parameter.
This commit is contained in:
@@ -456,7 +456,7 @@ public class MethodInliner {
|
||||
SourceValue sourceValue = frame.getStack(firstParameterIndex);
|
||||
|
||||
LambdaInfo lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions(
|
||||
this, MethodInlinerUtilKt.singleOrNullInsn(sourceValue), true, instructions, sources, toDelete
|
||||
this, sourceValue, true, instructions, sources, toDelete
|
||||
);
|
||||
|
||||
invokeCalls.add(new InvokeCall(lambdaInfo, currentFinallyDeep));
|
||||
@@ -469,7 +469,7 @@ public class MethodInliner {
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
SourceValue sourceValue = frame.getStack(firstParameterIndex + i);
|
||||
LambdaInfo lambdaInfo = MethodInlinerUtilKt.getLambdaIfExistsAndMarkInstructions(
|
||||
this, MethodInlinerUtilKt.singleOrNullInsn(sourceValue), false, instructions, sources, toDelete
|
||||
this, sourceValue, false, instructions, sources, toDelete
|
||||
);
|
||||
if (lambdaInfo != null) {
|
||||
lambdaMapping.put(offset, lambdaInfo);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnList
|
||||
@@ -25,6 +26,25 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
|
||||
|
||||
fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
sourceValue: SourceValue,
|
||||
processSwap: Boolean,
|
||||
insnList: InsnList,
|
||||
frames: Array<Frame<SourceValue>?>,
|
||||
toDelete: MutableSet<AbstractInsnNode>
|
||||
): LambdaInfo? {
|
||||
val toDeleteInner = SmartSet.create<AbstractInsnNode>()
|
||||
|
||||
val lambdaSet = SmartSet.create<LambdaInfo?>()
|
||||
sourceValue.insns.mapTo(lambdaSet) {
|
||||
getLambdaIfExistsAndMarkInstructions(it, processSwap, insnList, frames, toDeleteInner)
|
||||
}
|
||||
|
||||
return lambdaSet.singleOrNull()?.also {
|
||||
toDelete.addAll(toDeleteInner)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
insnNode: AbstractInsnNode?,
|
||||
processSwap: Boolean,
|
||||
insnList: InsnList,
|
||||
@@ -45,7 +65,7 @@ fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
val storeIns = localFrame.getLocal(varIndex).singleOrNullInsn()
|
||||
if (storeIns is VarInsnNode && storeIns.getOpcode() == Opcodes.ASTORE) {
|
||||
val frame = frames[insnList.indexOf(storeIns)] ?: return null
|
||||
val topOfStack = frame.top()!!.singleOrNullInsn()
|
||||
val topOfStack = frame.top()!!
|
||||
getLambdaIfExistsAndMarkInstructions(topOfStack, processSwap, insnList, frames, toDelete)?.let {
|
||||
//remove intermediate lambda astore, aload instruction: see 'complexStack/simple.1.kt' test
|
||||
toDelete.add(storeIns)
|
||||
@@ -56,7 +76,7 @@ fun MethodInliner.getLambdaIfExistsAndMarkInstructions(
|
||||
}
|
||||
else if (processSwap && insnNode.opcode == Opcodes.SWAP) {
|
||||
val swapFrame = frames[insnList.indexOf(insnNode)] ?: return null
|
||||
val dispatchReceiver = swapFrame.top()!!.singleOrNullInsn()
|
||||
val dispatchReceiver = swapFrame.top()!!
|
||||
getLambdaIfExistsAndMarkInstructions(dispatchReceiver, false, insnList, frames, toDelete)?.let {
|
||||
//remove swap instruction (dispatch receiver would be deleted on recursion call): see 'complexStack/simpleExtension.1.kt' test
|
||||
toDelete.add(insnNode)
|
||||
|
||||
Reference in New Issue
Block a user