diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 147e0f95bbd..bb6b21426f8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -17,8 +17,8 @@ import org.jetbrains.kotlin.codegen.optimization.common.ControlFlowGraph import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful -import org.jetbrains.kotlin.codegen.optimization.fixStack.peek -import org.jetbrains.kotlin.codegen.optimization.fixStack.top +import org.jetbrains.kotlin.codegen.optimization.fixStack.* +import org.jetbrains.kotlin.codegen.optimization.fixStack.HackedFixStackMethodAnalyzerBase import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.config.LanguageFeature @@ -36,8 +36,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.LocalVariablesSorter import org.jetbrains.org.objectweb.asm.commons.MethodRemapper import org.jetbrains.org.objectweb.asm.tree.* -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.util.Printer import java.util.* @@ -57,8 +55,10 @@ class MethodInliner( ) { private val languageVersionSettings = inliningContext.state.languageVersionSettings private val invokeCalls = ArrayList() + //keeps order private val transformations = ArrayList() + //current state private val currentTypeMapping = HashMap() private val result = InlineResult.create() @@ -273,7 +273,8 @@ class MethodInliner( val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift) //TODO add skipped this and receiver - val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift) + val lambdaResult = + inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift) result.mergeWithNotChangeInfo(lambdaResult) result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages) result.reifiedTypeParametersUsages.mergeAll(info.reifiedTypeParametersUsages) @@ -303,7 +304,7 @@ class MethodInliner( } else capturedParamDesc visitFieldInsn( Opcodes.GETSTATIC, realDesc.containingLambdaName, - FieldRemapper.foldName(realDesc.fieldName), realDesc.type.descriptor + foldName(realDesc.fieldName), realDesc.type.descriptor ) } super.visitMethodInsn(opcode, info.newClassName, name, info.newConstructorDescriptor, itf) @@ -441,7 +442,7 @@ class MethodInliner( else -> "" } - val varName = if (!varSuffix.isEmpty() && name == AsmUtil.THIS) AsmUtil.INLINE_DECLARATION_SITE_THIS else name + val varName = if (varSuffix.isNotEmpty() && name == AsmUtil.THIS) AsmUtil.INLINE_DECLARATION_SITE_THIS else name super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index)) } } @@ -533,33 +534,37 @@ class MethodInliner( cur.opcode == Opcodes.GETSTATIC -> { val fieldInsnNode = cur as FieldInsnNode? val className = fieldInsnNode!!.owner - if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) { - recordTransformation( - AnonymousObjectTransformationInfo( - className, awaitClassReification, isAlreadyRegenerated(className), true, - inliningContext.nameGenerator + when { + isAnonymousSingletonLoad(className, fieldInsnNode.name) -> { + recordTransformation( + AnonymousObjectTransformationInfo( + className, awaitClassReification, isAlreadyRegenerated(className), true, + inliningContext.nameGenerator + ) ) - ) - awaitClassReification = false - } else if (isWhenMappingAccess(className, fieldInsnNode.name)) { - recordTransformation( - WhenMappingTransformationInfo( - className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode + awaitClassReification = false + } + isWhenMappingAccess(className, fieldInsnNode.name) -> { + recordTransformation( + WhenMappingTransformationInfo( + className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode + ) ) - ) - } else if (fieldInsnNode.isCheckAssertionsStatus()) { - fieldInsnNode.owner = inlineCallSiteInfo.ownerClassName - when { - // In inline function itself: - inliningContext.parent == null -> inliningContext - // In method of regenerated object - field should already exist: - inliningContext.parent is RegeneratedClassContext -> inliningContext.parent - // In lambda inlined into the root function: - inliningContext.parent.parent == null -> inliningContext.parent - // In lambda inlined into a method of a regenerated object: - else -> inliningContext.parent.parent as? RegeneratedClassContext - ?: throw AssertionError("couldn't find class for \$assertionsDisabled (context = $inliningContext)") - }.generateAssertField = true + } + fieldInsnNode.isCheckAssertionsStatus() -> { + fieldInsnNode.owner = inlineCallSiteInfo.ownerClassName + when { + // In inline function itself: + inliningContext.parent == null -> inliningContext + // In method of regenerated object - field should already exist: + inliningContext.parent is RegeneratedClassContext -> inliningContext.parent + // In lambda inlined into the root function: + inliningContext.parent.parent == null -> inliningContext.parent + // In lambda inlined into a method of a regenerated object: + else -> inliningContext.parent.parent as? RegeneratedClassContext + ?: throw AssertionError("couldn't find class for \$assertionsDisabled (context = $inliningContext)") + }.generateAssertField = true + } } } @@ -588,7 +593,7 @@ class MethodInliner( assert(lambdaInfo.lambdaClassType.internalName == nodeRemapper.originalLambdaInternalName) { "Wrong bytecode template for contract template: ${lambdaInfo.lambdaClassType.internalName} != ${nodeRemapper.originalLambdaInternalName}" } - fieldInsn.name = FieldRemapper.foldName(fieldInsn.name) + fieldInsn.name = foldName(fieldInsn.name) fieldInsn.opcode = Opcodes.PUTSTATIC toDelete.addAll(stackTransformations) } @@ -742,7 +747,7 @@ class MethodInliner( ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node) } - val frames = analyzeMethodNodeWithInterpreter(node, BasicInterpreter()) + val frames = HackedFixStackMethodAnalyzerBase("", node, FixStackInterpreter()).analyze() val localReturnsNormalizer = LocalReturnsNormalizer() @@ -831,9 +836,9 @@ class MethodInliner( if (inliningContext.isInliningLambda && inliningContext.lambdaInfo is IrExpressionLambda && !inliningContext.parent!!.isInliningLambda) { val capturedVars = inliningContext.lambdaInfo.capturedVars var offset = parameters.realParametersSizeOnStack - val map = capturedVars.map { + val map = capturedVars.associate { offset to it.also { offset += it.type.size } - }.toMap() + } var cur: AbstractInsnNode? = node.instructions.first while (cur != null) { @@ -878,6 +883,7 @@ class MethodInliner( } } + @Suppress("SameParameterValue") private fun wrapException(originalException: Throwable, node: MethodNode, errorSuffix: String): RuntimeException { return if (originalException is InlineException) { InlineException("$errorPrefix: $errorSuffix", originalException) @@ -890,7 +896,7 @@ class MethodInliner( private class LocalReturn( private val returnInsn: AbstractInsnNode, private val insertBeforeInsn: AbstractInsnNode, - private val frame: Frame + private val frame: Frame ) { fun transform(insnList: InsnList, returnVariableIndex: Int) { @@ -901,22 +907,19 @@ class MethodInliner( if (expectedStackSize == actualStackSize) return var stackSize = actualStackSize + val topValue = frame.getStack(stackSize - 1) if (isReturnWithValue) { - val storeOpcode = Opcodes.ISTORE + returnInsn.opcode - Opcodes.IRETURN - insnList.insertBefore(insertBeforeInsn, VarInsnNode(storeOpcode, returnVariableIndex)) + insnList.insertBefore(insertBeforeInsn, VarInsnNode(topValue.storeOpcode, returnVariableIndex)) stackSize-- } while (stackSize > 0) { - val stackElementSize = frame.getStack(stackSize - 1).size - val popOpcode = if (stackElementSize == 1) Opcodes.POP else Opcodes.POP2 - insnList.insertBefore(insertBeforeInsn, InsnNode(popOpcode)) + insnList.insertBefore(insertBeforeInsn, InsnNode(frame.getStack(stackSize - 1).popOpcode)) stackSize-- } if (isReturnWithValue) { - val loadOpcode = Opcodes.ILOAD + returnInsn.opcode - Opcodes.IRETURN - insnList.insertBefore(insertBeforeInsn, VarInsnNode(loadOpcode, returnVariableIndex)) + insnList.insertBefore(insertBeforeInsn, VarInsnNode(topValue.loadOpcode, returnVariableIndex)) } } } @@ -926,10 +929,10 @@ class MethodInliner( private var returnVariableSize = 0 private var returnOpcode = -1 - internal fun addLocalReturnToTransform( + fun addLocalReturnToTransform( returnInsn: AbstractInsnNode, insertBeforeInsn: AbstractInsnNode, - sourceValueFrame: Frame + sourceValueFrame: Frame ) { assert(isReturnOpcode(returnInsn.opcode)) { "return instruction expected" } assert(returnOpcode < 0 || returnOpcode == returnInsn.opcode) { "Return op should be " + Printer.OPCODES[returnOpcode] + ", got " + Printer.OPCODES[returnInsn.opcode] } @@ -938,11 +941,7 @@ class MethodInliner( localReturns.add(LocalReturn(returnInsn, insertBeforeInsn, sourceValueFrame)) if (returnInsn.opcode != Opcodes.RETURN) { - returnVariableSize = if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) { - 2 - } else { - 1 - } + returnVariableSize = if (returnInsn.opcode == Opcodes.LRETURN || returnInsn.opcode == Opcodes.DRETURN) 2 else 1 } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt index a5054a2041f..a235a21a632 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/HackedFixStackMethodAnalyzerBase.kt @@ -94,7 +94,11 @@ internal open class HackedFixStackMethodAnalyzerBase( if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) { visitNopInsn(f, insn) } else { - current.init(f).execute(insnNode, interpreter) + current.init(f) + if (insnOpcode != Opcodes.RETURN) { + // Don't care about possibly incompatible return type + current.execute(insnNode, interpreter) + } when { insnNode is JumpInsnNode ->