diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index 214422705d5..7a1f79a7b43 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.* @@ -512,7 +513,8 @@ class CoroutineCodegenForLambda private constructor( containingClassInternalName = v.thisName, isForNamedFunction = false, languageVersionSettings = languageVersionSettings, - disableTailCallOptimizationForFunctionReturningUnit = false + disableTailCallOptimizationForFunctionReturningUnit = false, + useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS) ) val maybeWithForInline = if (forInline) SuspendForInlineCopyingMethodVisitor(stateMachineBuilder, access, name, desc, functionCodegen::newMethod) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt index cc4ab1074fa..fbce9478855 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineTransformerMethodVisitor.kt @@ -5,14 +5,10 @@ package org.jetbrains.kotlin.codegen.coroutines -import org.jetbrains.kotlin.codegen.AsmUtil -import org.jetbrains.kotlin.codegen.ClassBuilder -import org.jetbrains.kotlin.codegen.StackValue -import org.jetbrains.kotlin.codegen.TransformationMethodVisitor +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.optimization.common.* import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer -import org.jetbrains.kotlin.codegen.linkWithLabel import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.resolve.jvm.AsmTypes @@ -65,7 +61,9 @@ class CoroutineTransformerMethodVisitor( // May differ from containingClassInternalName in case of DefaultImpls private val internalNameForDispatchReceiver: String? = null, // JVM_IR backend generates $completion, while old backend does not - private val putContinuationParameterToLvt: Boolean = true + private val putContinuationParameterToLvt: Boolean = true, + // New SourceInterpreter-less analyser can be somewhat unstable, disable it + private val useOldSpilledVarTypeAnalysis: Boolean = false ) : TransformationMethodVisitor(delegate, access, name, desc, signature, exceptions) { private val classBuilderForCoroutineState: ClassBuilder by lazy(obtainClassBuilderForCoroutineState) @@ -594,7 +592,10 @@ class CoroutineTransformerMethodVisitor( private fun spillVariables(suspensionPoints: List, methodNode: MethodNode): List> { val instructions = methodNode.instructions - val frames = performSpilledVariableFieldTypesAnalysis(methodNode, containingClassInternalName) + val frames = + if (useOldSpilledVarTypeAnalysis) performRefinedTypeAnalysis(methodNode, containingClassInternalName) + else performSpilledVariableFieldTypesAnalysis(methodNode, containingClassInternalName) + fun AbstractInsnNode.index() = instructions.indexOf(this) // We postpone these actions because they change instruction indices that we use when obtaining frames diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt index 91c67412e6d..4b874723f4b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SpilledVariableFieldTypesAnalysis.kt @@ -12,6 +12,7 @@ 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.* +import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter import org.jetbrains.org.objectweb.asm.tree.analysis.Value @@ -358,4 +359,11 @@ internal fun performSpilledVariableFieldTypesAnalysis( methodNode: MethodNode, thisName: String ): Array?> = - MethodAnalyzer(thisName, methodNode, SpilledVariableFieldTypesInterpreter(methodNode)).analyze() \ No newline at end of file + MethodAnalyzer(thisName, methodNode, SpilledVariableFieldTypesInterpreter(methodNode)).analyze() + +internal val Value.type: Type? + get() = when (this) { + is BasicValue -> type + is SpilledVariableFieldTypeValue -> type + else -> error("Unexpected type of $this") + } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt index d14c2057ed8..e3cc008b3ec 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.inline.addFakeContinuationConstructorCallMar import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.inline.preprocessSuspendMarkers import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings @@ -95,7 +96,8 @@ class SuspendFunctionGenerationStrategy( languageVersionSettings = languageVersionSettings, disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true && originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() && - !originalSuspendDescriptor.allOverriddenFunctionsReturnUnit() + !originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(), + useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS) ) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt index 76c50997380..0da5b5de4ac 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/coroutines/CoroutineTransformer.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer +import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor @@ -95,7 +96,8 @@ class CoroutineTransformer( shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization, containingClassInternalName = classBuilder.thisName, isForNamedFunction = false, - disableTailCallOptimizationForFunctionReturningUnit = false + disableTailCallOptimizationForFunctionReturningUnit = false, + useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS) ) if (generateForInline) @@ -131,7 +133,8 @@ class CoroutineTransformer( needDispatchReceiver = true, internalNameForDispatchReceiver = classBuilder.thisName, disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization, - putContinuationParameterToLvt = !state.isIrBackend + putContinuationParameterToLvt = !state.isIrBackend, + useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS) ) if (generateForInline) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index 4f8aceab819..6c35a2a072a 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -369,6 +369,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { ) var repeatCompileModules: String? by NullableStringFreezableVar(null) + @Argument( + value = "-Xuse-old-spilled-var-type-analysis", + description = "Use old, SourceInterpreter-based analysis for fields, used for spilled variables in coroutines" + ) + var useOldSpilledVarTypeAnalysis: Boolean by FreezableVar(false) + override fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> { val result = super.configureAnalysisFlags(collector) result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt index b155d99aff0..120664b1046 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt @@ -198,6 +198,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage) put(JVMConfigurationKeys.USE_SINGLE_MODULE, arguments.singleModule) + put(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS, arguments.useOldSpilledVarTypeAnalysis) arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) } } diff --git a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 9777a62fdb6..53e6a1b957a 100644 --- a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -122,4 +122,7 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey NO_KOTLIN_NOTHING_VALUE_EXCEPTION = CompilerConfigurationKey.create("Do not use KotlinNothingValueException available since 1.4"); + + public static final CompilerConfigurationKey USE_OLD_SPILLED_VAR_TYPE_ANALYSIS = + CompilerConfigurationKey.create("Use old, SourceInterpreter-based analysis for fields, used for spilled variables in coroutines"); } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index 1dcb90d588d..b8b2eed8681 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME import org.jetbrains.kotlin.codegen.coroutines.SUSPEND_IMPL_NAME_SUFFIX import org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX +import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* @@ -64,7 +65,8 @@ internal fun MethodNode.acceptWithStateMachine( putContinuationParameterToLvt = false, disableTailCallOptimizationForFunctionReturningUnit = irFunction.isSuspend && irFunction.suspendFunctionOriginal().let { it.returnType.isUnit() && it.anyOfOverriddenFunctionsReturnsNonUnit() - } + }, + useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS) ) accept(visitor) } diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index b4c15e620ab..b5404ec6b1c 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -100,6 +100,8 @@ where advanced options include: -Xuse-javac Use javac for Java source and class files analysis -Xuse-old-class-files-reading Use old class files reading implementation. This may slow down the build and cause problems with Groovy interop. Should be used in case of problems with the new implementation + -Xuse-old-spilled-var-type-analysis + Use old, SourceInterpreter-based analysis for fields, used for spilled variables in coroutines -Xuse-type-table Use type table in metadata serialization -Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info -Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type