Use BasicInterpreter instead of SourceInterpreter in LocalReturnsTransformer

This commit is contained in:
Ilmir Usmanov
2020-05-04 20:22:44 +02:00
parent 841e588c87
commit 3173113cb3
@@ -8,11 +8,17 @@ package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
import org.jetbrains.kotlin.codegen.inline.coroutines.*
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.inline.coroutines.isSuspendLambdaCapturedByOuterObjectOrLambda
import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspend
import org.jetbrains.kotlin.codegen.inline.coroutines.surroundInvokesWithSuspendMarkersIfNeeded
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.*
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.config.LanguageFeature
@@ -766,14 +772,6 @@ class MethodInliner(
}
}
private fun isSuspendCall(invoke: AbstractInsnNode?): Boolean {
if (invoke !is MethodInsnNode) return false
// We can't have suspending constructors.
assert(invoke.opcode != Opcodes.INVOKESPECIAL)
if (Type.getReturnType(invoke.desc) != OBJECT_TYPE) return false
return Type.getArgumentTypes(invoke.desc).let { it.isNotEmpty() && it.last() == languageVersionSettings.continuationAsmType() }
}
private fun preprocessNodeBeforeInline(node: MethodNode, returnLabelOwner: ReturnLabelOwner) {
try {
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
@@ -786,7 +784,7 @@ class MethodInliner(
ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node)
}
val frames = analyzeMethodNodeBeforeInline(node)
val frames = analyzeMethodNodeWithBasicInterpreter(node)
val localReturnsNormalizer = LocalReturnsNormalizer()
@@ -937,7 +935,7 @@ class MethodInliner(
private class LocalReturn(
private val returnInsn: AbstractInsnNode,
private val insertBeforeInsn: AbstractInsnNode,
private val frame: Frame<SourceValue>
private val frame: Frame<BasicValue>
) {
fun transform(insnList: InsnList, returnVariableIndex: Int) {
@@ -955,7 +953,7 @@ class MethodInliner(
}
while (stackSize > 0) {
val stackElementSize = frame.getStack(stackSize - 1).getSize()
val stackElementSize = frame.getStack(stackSize - 1).size
val popOpcode = if (stackElementSize == 1) Opcodes.POP else Opcodes.POP2
insnList.insertBefore(insertBeforeInsn, InsnNode(popOpcode))
stackSize--
@@ -976,7 +974,7 @@ class MethodInliner(
internal fun addLocalReturnToTransform(
returnInsn: AbstractInsnNode,
insertBeforeInsn: AbstractInsnNode,
sourceValueFrame: Frame<SourceValue>
sourceValueFrame: Frame<BasicValue>
) {
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] }
@@ -1026,6 +1024,28 @@ class MethodInliner(
)
}
private fun analyzeMethodNodeWithBasicInterpreter(node: MethodNode): Array<Frame<BasicValue>?> {
val analyzer = object : Analyzer<BasicValue>(BasicInterpreter()) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> {
return object : Frame<BasicValue>(nLocals, nStack) {
@Throws(AnalyzerException::class)
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
// This can be a void non-local return from a non-void method; Frame#execute would throw and do nothing else.
if (insn.opcode == Opcodes.RETURN) return
super.execute(insn, interpreter)
}
}
}
}
try {
return analyzer.analyze("fake", node)
} catch (e: AnalyzerException) {
throw RuntimeException(e)
}
}
private fun analyzeMethodNodeBeforeInline(node: MethodNode): Array<Frame<SourceValue>?> {
val analyzer = object : Analyzer<SourceValue>(SourceInterpreter()) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<SourceValue> {