diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 7375dd17592..e333c9e9309 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -5051,7 +5051,9 @@ The "returned" value of try expression with no finally is either the last expres return Unit.INSTANCE; } - CodegenUtilKt.generateAsCast(v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings()); + CodegenUtilKt.generateAsCast( + v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings(), state.getUnifiedNullChecks() + ); return Unit.INSTANCE; }); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 9a881a9ce35..1dd5f6162c6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -98,11 +98,12 @@ fun generateAsCast( kotlinType: KotlinType, asmType: Type, isSafe: Boolean, - languageVersionSettings: LanguageVersionSettings + languageVersionSettings: LanguageVersionSettings, + unifiedNullChecks: Boolean, ) { if (!isSafe) { if (!TypeUtils.isNullableType(kotlinType)) { - generateNullCheckForNonSafeAs(v, kotlinType, languageVersionSettings) + generateNullCheckForNonSafeAs(v, kotlinType, unifiedNullChecks) } } else { with(v) { @@ -122,15 +123,13 @@ fun generateAsCast( private fun generateNullCheckForNonSafeAs( v: InstructionAdapter, type: KotlinType, - languageVersionSettings: LanguageVersionSettings + unifiedNullChecks: Boolean, ) { with(v) { dup() val nonnull = Label() ifnonnull(nonnull) - val exceptionClass = - if (languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) "java/lang/NullPointerException" - else "kotlin/TypeCastException" + val exceptionClass = if (unifiedNullChecks) "java/lang/NullPointerException" else "kotlin/TypeCastException" AsmUtil.genThrow( v, exceptionClass, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index 6a45b6bf228..bc4b872df20 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -41,7 +41,10 @@ class PsiInlineCodegen( private val actualDispatchReceiver: Type = methodOwner ) : InlineCodegen( codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler, - ReifiedTypeInliner(typeParameterMappings, PsiInlineIntrinsicsSupport(state), codegen.typeSystem, state.languageVersionSettings), + ReifiedTypeInliner( + typeParameterMappings, PsiInlineIntrinsicsSupport(state), codegen.typeSystem, + state.languageVersionSettings, state.unifiedNullChecks + ), ), CallGenerator { override fun generateAssertFieldIfNeeded(info: RootInliningContext) { if (info.generateAssertField) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 98e4b9be3d8..dcd9b1394f2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -53,7 +53,8 @@ class ReifiedTypeInliner( private val parametersMapping: TypeParameterMappings?, private val intrinsicsSupport: IntrinsicsSupport, private val typeSystem: TypeSystemCommonBackendContext, - private val languageVersionSettings: LanguageVersionSettings + private val languageVersionSettings: LanguageVersionSettings, + private val unifiedNullChecks: Boolean, ) { enum class OperationKind { NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF; @@ -222,7 +223,7 @@ class ReifiedTypeInliner( if (stubCheckcast !is TypeInsnNode) return false val newMethodNode = MethodNode(Opcodes.API_VERSION) - generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, languageVersionSettings) + generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, languageVersionSettings, unifiedNullChecks) instructions.insert(insn, newMethodNode.instructions) // Keep stubCheckcast to avoid VerifyErrors on 1.8+ bytecode, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index f304adba258..8de52025552 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -249,7 +249,9 @@ class GenerationState private constructor( val assertionsMode: JVMAssertionsMode = configuration.get(JVMConfigurationKeys.ASSERTIONS_MODE, JVMAssertionsMode.DEFAULT) val isInlineDisabled: Boolean = configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE) val useTypeTableInSerializer: Boolean = configuration.getBoolean(JVMConfigurationKeys.USE_TYPE_TABLE) - val unifiedNullChecks: Boolean = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 + val unifiedNullChecks: Boolean = + languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 && + !configuration.getBoolean(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS) val functionsWithInlineClassReturnTypesMangled: Boolean = languageVersionSettings.supportsFeature(LanguageFeature.MangleClassMembersReturningInlineClasses) 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 6c35a2a072a..a0dfb96ad65 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 @@ -352,6 +352,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { ) var noKotlinNothingValueException: Boolean by FreezableVar(false) + @Argument( + value = "-Xno-unified-null-checks", + description = "Use pre-1.4 exception types in null checks instead of java.lang.NPE. See KT-22275 for more details" + ) + var noUnifiedNullChecks: Boolean by FreezableVar(false) + @Argument( value = "-Xprofile", valueDescription = "", 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 056412f5188..eac86b26b10 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/jvmArguments.kt @@ -166,6 +166,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr put(JVMConfigurationKeys.EMIT_JVM_TYPE_ANNOTATIONS, arguments.emitJvmTypeAnnotations) put(JVMConfigurationKeys.NO_OPTIMIZED_CALLABLE_REFERENCES, arguments.noOptimizedCallableReferences) put(JVMConfigurationKeys.NO_KOTLIN_NOTHING_VALUE_EXCEPTION, arguments.noKotlinNothingValueException) + put(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS, arguments.noUnifiedNullChecks) if (!JVMConstructorCallNormalizationMode.isSupportedValue(arguments.constructorCallNormalizationMode)) { getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report( 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 53e6a1b957a..4f736403709 100644 --- a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -123,6 +123,9 @@ 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 NO_UNIFIED_NULL_CHECKS = + CompilerConfigurationKey.create("Use pre-1.4 exception types in null checks instead of java.lang.NPE"); + 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/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 7ad80af3b49..39f5fef9b8d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -1201,7 +1201,8 @@ class ExpressionCodegen( mappings, IrInlineIntrinsicsSupport(context, typeMapper), IrTypeCheckerContext(context.irBuiltIns), - state.languageVersionSettings + state.languageVersionSettings, + state.unifiedNullChecks, ) return IrInlineCodegen(this, state, callee, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner) diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index 56b149d7a2f..f8daee15d75 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -73,6 +73,7 @@ where advanced options include: Do not use optimized callable reference superclasses available from 1.4 -Xno-param-assertions Don't generate not-null assertions on parameters of methods accessible from Java -Xno-receiver-assertions Don't generate not-null assertion for extension receiver arguments of platform types + -Xno-unified-null-checks Use pre-1.4 exception types in null checks instead of java.lang.NPE. See KT-22275 for more details -Xno-use-ir Do not use the IR backend. Useful for a custom-built compiler where IR backend is enabled by default -Xprofile= Debug option: Run compiler with async profiler, save snapshots to outputDir, command is passed to async-profiler on start diff --git a/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsKnpe_1_3.kt b/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsKnpe_1_3.kt index 14de0821e57..d562f04c1ee 100644 --- a/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsKnpe_1_3.kt +++ b/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsKnpe_1_3.kt @@ -1,4 +1,4 @@ -// !API_VERSION: 1.3 +// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_UNIFIED_NULL_CHECKS // WITH_RUNTIME // TARGET_BACKEND: JVM diff --git a/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsIse_1_3.kt b/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsIse_1_3.kt index 48bf292116f..d84c87adc7e 100644 --- a/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsIse_1_3.kt +++ b/compiler/testData/codegen/box/nullCheckOptimization/javaNullCheckThrowsIse_1_3.kt @@ -1,4 +1,4 @@ -// !API_VERSION: 1.3 +// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_UNIFIED_NULL_CHECKS // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FILE: A.java diff --git a/compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsIae_1_3.kt b/compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsIae_1_3.kt index 9f9d9daf947..82258a5c33c 100644 --- a/compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsIae_1_3.kt +++ b/compiler/testData/codegen/box/nullCheckOptimization/parameterNullCheckThrowsIae_1_3.kt @@ -1,4 +1,4 @@ -// !API_VERSION: 1.3 +// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_UNIFIED_NULL_CHECKS // TARGET_BACKEND: JVM // FILE: A.java diff --git a/compiler/testData/codegen/boxInline/reified/checkCast/simple_1_3.kt b/compiler/testData/codegen/boxInline/reified/checkCast/simple_1_3.kt index f89bc2d229b..ab0802369aa 100644 --- a/compiler/testData/codegen/boxInline/reified/checkCast/simple_1_3.kt +++ b/compiler/testData/codegen/boxInline/reified/checkCast/simple_1_3.kt @@ -1,4 +1,4 @@ -// !API_VERSION: 1.3 +// KOTLIN_CONFIGURATION_FLAGS: +JVM.NO_UNIFIED_NULL_CHECKS // TARGET_BACKEND: JVM // FILE: 1.kt // WITH_RUNTIME