JVM IR: output stable ABI binaries by default

#KT-43592 Fixed
This commit is contained in:
Alexander Udalov
2020-12-01 18:53:50 +01:00
parent e0593ff70f
commit eef06cded3
39 changed files with 117 additions and 44 deletions
@@ -103,8 +103,10 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
@Argument(
value = "-Xabi-stability",
valueDescription = "{stable|unstable}",
description = "When using unstable compiler features such as FIR or JVM IR, use 'stable' to mark generated class files as stable\n" +
"to prevent diagnostics from stable compilers at the call site.\n"
description = "When using unstable compiler features such as FIR, use 'stable' to mark generated class files as stable\n" +
"to prevent diagnostics from stable compilers at the call site.\n" +
"When using the JVM IR backend, conversely, use 'unstable' to mark generated class files as unstable\n" +
"to force diagnostics to be reported."
)
var abiStability: String? by FreezableVar(null)
@@ -446,7 +448,7 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
result[JvmAnalysisFlags.suppressMissingBuiltinsError] = suppressMissingBuiltinsError
result[JvmAnalysisFlags.irCheckLocalNames] = irCheckLocalNames
result[JvmAnalysisFlags.enableJvmPreview] = enableJvmPreview
result[AnalysisFlags.allowUnstableDependencies] = allowUnstableDependencies || useIR || useFir
result[AnalysisFlags.allowUnstableDependencies] = allowUnstableDependencies || useFir
result[JvmAnalysisFlags.disableUltraLightClasses] = disableUltraLightClasses
return result
}
@@ -182,10 +182,10 @@ class AnalyzerWithCompilerReport(
)
}
if (diagnostics.any { it.factory == Errors.IR_COMPILED_CLASS }) {
if (diagnostics.any { it.factory == Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS }) {
messageCollector.report(
ERROR,
"Classes compiled by a new Kotlin compiler backend were found in dependencies. " +
"Classes compiled by an unstable version of the Kotlin compiler were found in dependencies. " +
"Remove them from the classpath or use '-Xallow-unstable-dependencies' to suppress errors"
)
}
@@ -165,7 +165,8 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
put(JVMConfigurationKeys.PARAMETERS_METADATA, arguments.javaParameters)
put(JVMConfigurationKeys.IR, (arguments.useIR && !arguments.noUseIR) || arguments.useFir)
val useIR = (arguments.useIR && !arguments.noUseIR) || arguments.useFir
put(JVMConfigurationKeys.IR, useIR)
val abiStability = JvmAbiStability.fromStringOrNull(arguments.abiStability)
if (arguments.abiStability != null) {
@@ -174,6 +175,8 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
ERROR,
"Unknown ABI stability mode: ${arguments.abiStability}, supported modes: ${JvmAbiStability.values().map { it.description }}"
)
} else if (!useIR && abiStability == JvmAbiStability.UNSTABLE) {
messageCollector.report(ERROR, "-Xabi-stability=unstable is not supported in the old JVM backend")
} else {
put(JVMConfigurationKeys.ABI_STABILITY, abiStability)
}
@@ -118,7 +118,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, String> MISSING_IMPORTED_SCRIPT_PSI = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> IR_COMPILED_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> IR_WITH_UNSTABLE_ABI_COMPILED_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> FIR_COMPILED_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
@@ -11,7 +11,6 @@ import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.config.LanguageVersion;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.diagnostics.UnboundDiagnostic;
@@ -401,7 +400,7 @@ public class DefaultErrorMessages {
MAP.put(MISSING_IMPORTED_SCRIPT_PSI, "Imported script file ''{0}'' is not loaded. Check your script imports", TO_STRING);
MAP.put(MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS, "Cannot access script provided property class ''{0}''. Check your module classpath for missing or conflicting dependencies", TO_STRING);
MAP.put(PRE_RELEASE_CLASS, "{0} is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler", TO_STRING);
MAP.put(IR_COMPILED_CLASS, "{0} is compiled by a new Kotlin compiler backend and cannot be loaded by the old compiler", TO_STRING);
MAP.put(IR_WITH_UNSTABLE_ABI_COMPILED_CLASS, "{0} is compiled by an unstable version of the Kotlin compiler and cannot be loaded by this compiler", TO_STRING);
MAP.put(FIR_COMPILED_CLASS, "{0} is compiled by the new Kotlin compiler frontend and cannot be loaded by the old compiler", TO_STRING);
MAP.put(INCOMPATIBLE_CLASS,
"{0} was compiled with an incompatible version of Kotlin. {1}",
@@ -63,7 +63,7 @@ object MissingDependencyClassChecker : CallChecker {
return FIR_COMPILED_CLASS.on(reportOn, source.presentableString)
}
if (source.abiStability == DeserializedContainerAbiStability.IR_UNSTABLE) {
return IR_COMPILED_CLASS.on(reportOn, source.presentableString)
return IR_WITH_UNSTABLE_ABI_COMPILED_CLASS.on(reportOn, source.presentableString)
}
}
@@ -33,6 +33,6 @@ interface JvmBackendExtension {
override fun generateMetadataExtraFlags(abiStability: JvmAbiStability?): Int =
JvmAnnotationNames.METADATA_JVM_IR_FLAG or
(if (abiStability == JvmAbiStability.STABLE) JvmAnnotationNames.METADATA_JVM_IR_STABLE_ABI_FLAG else 0)
(if (abiStability != JvmAbiStability.UNSTABLE) JvmAnnotationNames.METADATA_JVM_IR_STABLE_ABI_FLAG else 0)
}
}
@@ -0,0 +1,5 @@
$TESTDATA_DIR$/simple.kt
-d
$TEMP_DIR$
-Xuse-ir
-Xabi-stability=unknown
@@ -0,0 +1,2 @@
error: unknown ABI stability mode: unknown, supported modes: [stable, unstable]
COMPILATION_ERROR
@@ -0,0 +1,4 @@
$TESTDATA_DIR$/simple.kt
-d
$TEMP_DIR$
-Xabi-stability=unstable
@@ -0,0 +1,2 @@
error: -Xabi-stability=unstable is not supported in the old JVM backend
COMPILATION_ERROR
+3 -2
View File
@@ -1,9 +1,10 @@
Usage: kotlinc-jvm <options> <source files>
where advanced options include:
-Xabi-stability={stable|unstable}
When using unstable compiler features such as FIR or JVM IR, use 'stable' to mark generated class files as stable
When using unstable compiler features such as FIR, use 'stable' to mark generated class files as stable
to prevent diagnostics from stable compilers at the call site.
When using the JVM IR backend, conversely, use 'unstable' to mark generated class files as unstable
to force diagnostics to be reported.
-Xadd-modules=<module[,]> Root modules to resolve in addition to the initial modules,
or all modules on the module path if <module> is ALL-MODULE-PATH
-Xallow-no-source-files Allow no source files
@@ -1,8 +0,0 @@
error: classes compiled by a new Kotlin compiler backend were found in dependencies. Remove them from the classpath or use '-Xallow-jvm-ir-dependencies' to suppress errors
compiler/testData/compileKotlinAgainstCustomBinaries/oldAgainstJvmIr/source.kt:4:5: error: class 'lib.AKt' is compiled by a new Kotlin compiler backend and cannot be loaded by the old compiler
get { Box("OK").value }
^
compiler/testData/compileKotlinAgainstCustomBinaries/oldAgainstJvmIr/source.kt:4:11: error: class 'lib.Box' is compiled by a new Kotlin compiler backend and cannot be loaded by the old compiler
get { Box("OK").value }
^
COMPILATION_ERROR
@@ -0,0 +1,8 @@
error: classes compiled by the new Kotlin compiler frontend were found in dependencies. Remove them from the classpath or use '-Xallow-unstable-dependencies' to suppress errors
compiler/testData/compileKotlinAgainstCustomBinaries/oldJvmAgainstFir/source.kt:4:5: error: class 'lib.AKt' is compiled by the new Kotlin compiler frontend and cannot be loaded by the old compiler
get { Box("OK").value }
^
compiler/testData/compileKotlinAgainstCustomBinaries/oldJvmAgainstFir/source.kt:4:11: error: class 'lib.Box' is compiled by the new Kotlin compiler frontend and cannot be loaded by the old compiler
get { Box("OK").value }
^
COMPILATION_ERROR
@@ -0,0 +1,5 @@
package lib
class Box(val value: String)
inline fun <T> get(block: () -> T): T = block()
@@ -0,0 +1,5 @@
import lib.*
fun main() {
get { Box("OK").value }
}
@@ -0,0 +1,5 @@
package lib
class Box(val value: String)
inline fun <T> get(block: () -> T): T = block()
@@ -0,0 +1,8 @@
error: classes compiled by an unstable version of the Kotlin compiler were found in dependencies. Remove them from the classpath or use '-Xallow-unstable-dependencies' to suppress errors
compiler/testData/compileKotlinAgainstCustomBinaries/oldJvmAgainstJvmIrWithUnstableAbi/source.kt:4:5: error: class 'lib.AKt' is compiled by an unstable version of the Kotlin compiler and cannot be loaded by this compiler
get { Box("OK").value }
^
compiler/testData/compileKotlinAgainstCustomBinaries/oldJvmAgainstJvmIrWithUnstableAbi/source.kt:4:11: error: class 'lib.Box' is compiled by an unstable version of the Kotlin compiler and cannot be loaded by this compiler
get { Box("OK").value }
^
COMPILATION_ERROR
@@ -0,0 +1,5 @@
import lib.*
fun main() {
get { Box("OK").value }
}
@@ -27,6 +27,16 @@ public class CliTestGenerated extends AbstractCliTest {
KotlinTestUtils.runTest(this::doJvmTest, this, testDataFilePath);
}
@TestMetadata("abiStabilityIncorrectValue.args")
public void testAbiStabilityIncorrectValue() throws Exception {
runTest("compiler/testData/cli/jvm/abiStabilityIncorrectValue.args");
}
@TestMetadata("abiStabilityUnstableWithOldBackend.args")
public void testAbiStabilityUnstableWithOldBackend() throws Exception {
runTest("compiler/testData/cli/jvm/abiStabilityUnstableWithOldBackend.args");
}
public void testAllFilesPresentInJvm() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/cli/jvm"), Pattern.compile("^(.+)\\.args$"), null, false);
}
@@ -669,28 +669,44 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
classLoader.loadClass("SourceKt").getDeclaredMethod("main").invoke(null)
}
fun testJvmIrAgainstJvmIr() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-ir"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xuse-ir"))
fun testFirAgainstFir() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-fir"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xuse-fir"))
}
fun testJvmIrAgainstOld() {
fun testFirAgainstOldJvm() {
val library = compileLibrary("library")
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xuse-ir"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xuse-fir"))
}
fun testOldAgainstJvmIr() {
fun testOldJvmAgainstJvmIr() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-ir"))
compileKotlin("source.kt", tmpdir, listOf(library))
val library2 = compileLibrary("library", additionalOptions = listOf("-Xuse-ir", "-Xabi-stability=stable"))
compileKotlin("source.kt", tmpdir, listOf(library2))
}
fun testOldJvmAgainstFir() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-fir"))
compileKotlin("source.kt", tmpdir, listOf(library))
val library2 = compileLibrary("library", additionalOptions = listOf("-Xuse-fir", "-Xabi-stability=unstable"))
compileKotlin("source.kt", tmpdir, listOf(library2))
}
fun testOldJvmAgainstJvmIrWithUnstableAbi() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-ir", "-Xabi-stability=unstable"))
compileKotlin("source.kt", tmpdir, listOf(library))
}
fun testOldAgainstJvmIrWithStableAbi() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-ir", "-Xabi-stability=stable"))
fun testOldJvmAgainstFirWithStableAbi() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-fir", "-Xabi-stability=stable"))
compileKotlin("source.kt", tmpdir, listOf(library))
}
fun testOldAgainstJvmIrWithAllowIrDependencies() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-ir"))
fun testOldJvmAgainstFirWithAllowUnstableDependencies() {
val library = compileLibrary("library", additionalOptions = listOf("-Xuse-fir"))
compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-Xallow-unstable-dependencies"))
}
@@ -30,6 +30,9 @@ enum class DeserializedContainerAbiStability {
// The container is unstable because it is compiled with FIR, and this compiler is _not_ configured to ignore that.
FIR_UNSTABLE,
// The container is unstable because it is compiled with unstable JVM IR backend, and this compiler is _not_ configured to ignore that.
// The container is unstable because either:
// 1) it is compiled with JVM IR prior to 1.4.30, or
// 2) it is compiled with JVM IR >= 1.4.30 with the `-Xabi-stability=unstable` compiler option,
// and this compiler is _not_ configured to ignore that.
IR_UNSTABLE,
}
@@ -274,7 +274,7 @@ private class ElementAnnotator(
private fun isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic: Diagnostic): Boolean {
val setting = when (diagnostic.factory) {
Errors.IR_COMPILED_CLASS -> K2JVMCompilerArguments::useIR
Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS -> K2JVMCompilerArguments::useIR
Errors.FIR_COMPILED_CLASS -> K2JVMCompilerArguments::useFir
else -> return false
}
@@ -31,6 +31,7 @@ import com.intellij.testFramework.runInEdtAndWait
import com.sun.jdi.*
import com.sun.jdi.Value
import org.jetbrains.eval4j.*
import org.jetbrains.eval4j.Value as Eval4JValue
import org.jetbrains.eval4j.jdi.JDIEval
import org.jetbrains.eval4j.jdi.asJdiValue
import org.jetbrains.eval4j.jdi.asValue
@@ -45,32 +46,28 @@ import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.util.attachmentByPsiFile
import org.jetbrains.kotlin.idea.core.util.mergeAttachments
import org.jetbrains.kotlin.idea.core.util.runInReadActionWithWriteActionPriorityWithPCE
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils
import org.jetbrains.kotlin.idea.debugger.evaluate.EvaluationStatus.EvaluationContextLanguage
import org.jetbrains.kotlin.idea.debugger.*
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.Companion.compileCodeFragmentCacheAware
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.GENERATED_CLASS_NAME
import org.jetbrains.kotlin.idea.debugger.evaluate.classLoading.GENERATED_FUNCTION_NAME
import org.jetbrains.kotlin.idea.debugger.evaluate.compilation.*
import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.ClassLoadingResult
import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.loadClassesSafely
import org.jetbrains.kotlin.idea.debugger.evaluate.variables.EvaluatorValueConverter
import org.jetbrains.kotlin.idea.debugger.evaluate.variables.VariableFinder
import org.jetbrains.kotlin.idea.debugger.safeLocation
import org.jetbrains.kotlin.idea.debugger.safeMethod
import org.jetbrains.kotlin.idea.debugger.safeVisibleVariableByName
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.AnalyzingUtils
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import org.jetbrains.kotlin.idea.debugger.evaluate.EvaluationStatus.EvaluationContextLanguage
import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.ClassLoadingResult
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import java.util.*
import org.jetbrains.eval4j.Value as Eval4JValue
internal val LOG = Logger.getInstance(KotlinEvaluator::class.java)
@@ -449,7 +446,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi
companion object {
private val IGNORED_DIAGNOSTICS: Set<DiagnosticFactory<*>> = Errors.INVISIBLE_REFERENCE_DIAGNOSTICS +
setOf(
Errors.EXPERIMENTAL_API_USAGE_ERROR, Errors.MISSING_DEPENDENCY_SUPERCLASS, Errors.IR_COMPILED_CLASS,
Errors.EXPERIMENTAL_API_USAGE_ERROR, Errors.MISSING_DEPENDENCY_SUPERCLASS, Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS,
Errors.FIR_COMPILED_CLASS
)