JVM: more correctly track inline lambdas in local slots
The analyzer can now handle the case where a parameter containing an inline lambda is overwritten with something else. The local variable remapper still can't handle that, and KT-51950 is caused by a deeper underlying issue (the slot should't get overwritten in the first place), but at least the problem is more visible now: >java.lang.RuntimeException: Trying to access skipped parameter: > Lkotlin/jvm/functions/Function1; at 2
This commit is contained in:
@@ -661,38 +661,18 @@ class MethodInliner(
|
||||
}
|
||||
|
||||
private fun markObsoleteInstruction(instructions: InsnList, sources: Array<out Frame<BasicValue>?>): SmartSet<AbstractInsnNode> {
|
||||
val toDelete = SmartSet.create<AbstractInsnNode>()
|
||||
|
||||
for (insn in instructions) {
|
||||
return instructions.filterIndexedTo(SmartSet.create()) { index, insn ->
|
||||
// Parameter checks are processed separately
|
||||
if (insn.isAloadBeforeCheckParameterIsNotNull()) continue
|
||||
val functionalArgument = getFunctionalArgumentIfExists(insn)
|
||||
if (functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
} else {
|
||||
when (insn.opcode) {
|
||||
Opcodes.ASTORE -> {
|
||||
if (sources[instructions.indexOf(insn)]?.top().functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
}
|
||||
Opcodes.SWAP -> {
|
||||
if (sources[instructions.indexOf(insn)]?.peek(0).functionalArgument is LambdaInfo ||
|
||||
sources[instructions.indexOf(insn)]?.peek(1).functionalArgument is LambdaInfo
|
||||
) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
}
|
||||
Opcodes.ALOAD -> {
|
||||
if (sources[instructions.indexOf(insn)]?.getLocal((insn as VarInsnNode).`var`).functionalArgument is LambdaInfo) {
|
||||
toDelete.add(insn)
|
||||
}
|
||||
}
|
||||
}
|
||||
!insn.isAloadBeforeCheckParameterIsNotNull() && when (insn.opcode) {
|
||||
Opcodes.GETFIELD, Opcodes.GETSTATIC, Opcodes.ALOAD ->
|
||||
sources[index + 1]?.top().functionalArgument is LambdaInfo
|
||||
Opcodes.PUTFIELD, Opcodes.PUTSTATIC, Opcodes.ASTORE ->
|
||||
sources[index]?.top().functionalArgument is LambdaInfo
|
||||
Opcodes.SWAP ->
|
||||
sources[index]?.peek(0).functionalArgument is LambdaInfo || sources[index]?.peek(1).functionalArgument is LambdaInfo
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
return toDelete
|
||||
}
|
||||
|
||||
// Replace ALOAD 0
|
||||
@@ -953,20 +933,18 @@ class MethodInliner(
|
||||
return inliningContext.typeRemapper.hasNoAdditionalMapping(owner)
|
||||
}
|
||||
|
||||
internal fun getFunctionalArgumentIfExists(insnNode: AbstractInsnNode): FunctionalArgument? {
|
||||
internal fun getFunctionalArgumentIfExists(insnNode: FieldInsnNode): FunctionalArgument? {
|
||||
return when {
|
||||
insnNode.opcode == Opcodes.ALOAD ->
|
||||
getFunctionalArgumentIfExists((insnNode as VarInsnNode).`var`)
|
||||
insnNode is FieldInsnNode && insnNode.name.startsWith(CAPTURED_FIELD_FOLD_PREFIX) ->
|
||||
insnNode.name.startsWith(CAPTURED_FIELD_FOLD_PREFIX) ->
|
||||
findCapturedField(insnNode, nodeRemapper).functionalArgument
|
||||
insnNode is FieldInsnNode && inliningContext.root.sourceCompilerForInline.isSuspendLambdaCapturedByOuterObjectOrLambda(insnNode.name) ->
|
||||
inliningContext.root.sourceCompilerForInline.isSuspendLambdaCapturedByOuterObjectOrLambda(insnNode.name) ->
|
||||
NonInlineArgumentForInlineSuspendParameter.INLINE_LAMBDA_AS_VARIABLE
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFunctionalArgumentIfExists(varIndex: Int): FunctionalArgument? {
|
||||
internal fun getFunctionalArgumentIfExists(varIndex: Int): FunctionalArgument? {
|
||||
if (varIndex < parameters.argsSizeOnStack) {
|
||||
return parameters.getParameterByDeclarationSlot(varIndex).functionalArgument
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
@@ -63,22 +64,20 @@ val BasicValue?.functionalArgument
|
||||
get() = (this as? FunctionalArgumentValue)?.functionalArgument
|
||||
|
||||
internal class FunctionalArgumentInterpreter(private val inliner: MethodInliner) : BasicInterpreter(Opcodes.API_VERSION) {
|
||||
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): BasicValue =
|
||||
inliner.getFunctionalArgumentIfExists(local)?.let { FunctionalArgumentValue(it, newValue(type)) } ?: newValue(type)
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? =
|
||||
wrapArgumentInValueIfNeeded(insn, super.unaryOperation(insn, value))
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
|
||||
wrapArgumentInValueIfNeeded(insn, super.copyOperation(insn, value))
|
||||
|
||||
override fun newOperation(insn: AbstractInsnNode): BasicValue? =
|
||||
wrapArgumentInValueIfNeeded(insn, super.newOperation(insn))
|
||||
|
||||
private fun wrapArgumentInValueIfNeeded(
|
||||
insn: AbstractInsnNode,
|
||||
basicValue: BasicValue?
|
||||
): BasicValue? =
|
||||
inliner.getFunctionalArgumentIfExists(insn)
|
||||
?.let { FunctionalArgumentValue(it, basicValue) }
|
||||
?: basicValue
|
||||
private fun wrapArgumentInValueIfNeeded(insn: AbstractInsnNode, basicValue: BasicValue?): BasicValue? =
|
||||
if (insn is FieldInsnNode) // GETFIELD or GETSTATIC
|
||||
inliner.getFunctionalArgumentIfExists(insn)?.let { FunctionalArgumentValue(it, basicValue) } ?: basicValue
|
||||
else
|
||||
basicValue
|
||||
|
||||
override fun merge(v: BasicValue?, w: BasicValue?): BasicValue? =
|
||||
if (v is FunctionalArgumentValue && w is FunctionalArgumentValue && v.functionalArgument == w.functionalArgument) v
|
||||
|
||||
Reference in New Issue
Block a user