Use BasicInterpreter instead of SourceInterpreter in LocalReturnsTransformer
This commit is contained in:
@@ -8,11 +8,17 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
|
||||||
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
|
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.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
|
||||||
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
|
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.peek
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
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) {
|
private fun preprocessNodeBeforeInline(node: MethodNode, returnLabelOwner: ReturnLabelOwner) {
|
||||||
try {
|
try {
|
||||||
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
|
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
|
||||||
@@ -786,7 +784,7 @@ class MethodInliner(
|
|||||||
ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node)
|
ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node)
|
||||||
}
|
}
|
||||||
|
|
||||||
val frames = analyzeMethodNodeBeforeInline(node)
|
val frames = analyzeMethodNodeWithBasicInterpreter(node)
|
||||||
|
|
||||||
val localReturnsNormalizer = LocalReturnsNormalizer()
|
val localReturnsNormalizer = LocalReturnsNormalizer()
|
||||||
|
|
||||||
@@ -937,7 +935,7 @@ class MethodInliner(
|
|||||||
private class LocalReturn(
|
private class LocalReturn(
|
||||||
private val returnInsn: AbstractInsnNode,
|
private val returnInsn: AbstractInsnNode,
|
||||||
private val insertBeforeInsn: AbstractInsnNode,
|
private val insertBeforeInsn: AbstractInsnNode,
|
||||||
private val frame: Frame<SourceValue>
|
private val frame: Frame<BasicValue>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun transform(insnList: InsnList, returnVariableIndex: Int) {
|
fun transform(insnList: InsnList, returnVariableIndex: Int) {
|
||||||
@@ -955,7 +953,7 @@ class MethodInliner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (stackSize > 0) {
|
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
|
val popOpcode = if (stackElementSize == 1) Opcodes.POP else Opcodes.POP2
|
||||||
insnList.insertBefore(insertBeforeInsn, InsnNode(popOpcode))
|
insnList.insertBefore(insertBeforeInsn, InsnNode(popOpcode))
|
||||||
stackSize--
|
stackSize--
|
||||||
@@ -976,7 +974,7 @@ class MethodInliner(
|
|||||||
internal fun addLocalReturnToTransform(
|
internal fun addLocalReturnToTransform(
|
||||||
returnInsn: AbstractInsnNode,
|
returnInsn: AbstractInsnNode,
|
||||||
insertBeforeInsn: AbstractInsnNode,
|
insertBeforeInsn: AbstractInsnNode,
|
||||||
sourceValueFrame: Frame<SourceValue>
|
sourceValueFrame: Frame<BasicValue>
|
||||||
) {
|
) {
|
||||||
assert(isReturnOpcode(returnInsn.opcode)) { "return instruction expected" }
|
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] }
|
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>?> {
|
private fun analyzeMethodNodeBeforeInline(node: MethodNode): Array<Frame<SourceValue>?> {
|
||||||
val analyzer = object : Analyzer<SourceValue>(SourceInterpreter()) {
|
val analyzer = object : Analyzer<SourceValue>(SourceInterpreter()) {
|
||||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<SourceValue> {
|
override fun newFrame(nLocals: Int, nStack: Int): Frame<SourceValue> {
|
||||||
|
|||||||
Reference in New Issue
Block a user