Refactor ApiVersion.KOTLIN_1_4 usages in relation to unified null checks

This commit is contained in:
Alexander Udalov
2020-03-05 16:40:04 +01:00
parent 98aecbef6b
commit a2b6282d49
8 changed files with 11 additions and 27 deletions
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.codegen.intrinsics.HashCode;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.JvmTarget; import org.jetbrains.kotlin.config.JvmTarget;
import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.config.LanguageVersionSettings; import org.jetbrains.kotlin.config.LanguageVersionSettings;
@@ -1023,9 +1022,7 @@ public class AsmUtil {
} }
value.put(asmType, v); value.put(asmType, v);
v.visitLdcInsn(name); v.visitLdcInsn(name);
String methodName = state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_4) >= 0 String methodName = state.getUnifiedNullChecks() ? "checkNotNullParameter" : "checkParameterIsNotNull";
? "checkNotNullParameter"
: "checkParameterIsNotNull";
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false); v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false);
} }
} }
@@ -1048,9 +1045,7 @@ public class AsmUtil {
if (innerType.getSort() == Type.OBJECT || innerType.getSort() == Type.ARRAY) { if (innerType.getSort() == Type.OBJECT || innerType.getSort() == Type.ARRAY) {
v.dup(); v.dup();
v.visitLdcInsn(runtimeAssertionInfo.getMessage()); v.visitLdcInsn(runtimeAssertionInfo.getMessage());
String methodName = state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_4) >= 0 String methodName = state.getUnifiedNullChecks() ? "checkNotNullExpressionValue" : "checkExpressionValueIsNotNull";
? "checkNotNullExpressionValue"
: "checkExpressionValueIsNotNull";
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false); v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false);
} }
StackValue.coerce(innerType, innerKotlinType, type, kotlinType, v); StackValue.coerce(innerType, innerKotlinType, type, kotlinType, v);
@@ -4250,7 +4250,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return StackValue.operation(base.type, base.kotlinType, v -> { return StackValue.operation(base.type, base.kotlinType, v -> {
base.put(base.type, base.kotlinType, v); base.put(base.type, base.kotlinType, v);
v.dup(); v.dup();
if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_4) >= 0) { if (state.getUnifiedNullChecks()) {
v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkNotNull", "(Ljava/lang/Object;)V", false); v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkNotNull", "(Ljava/lang/Object;)V", false);
} else { } else {
Label ok = new Label(); Label ok = new Label();
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.createFreeFakeLocalPropertyDescriptor
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.* import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -53,6 +52,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
private val classBuilderMode = state.classBuilderMode private val classBuilderMode = state.classBuilderMode
private val languageVersionSettings = state.languageVersionSettings private val languageVersionSettings = state.languageVersionSettings
private val isParamAssertionsDisabled = state.isParamAssertionsDisabled private val isParamAssertionsDisabled = state.isParamAssertionsDisabled
private val unifiedNullChecks = state.unifiedNullChecks
override val metadataVersion = state.metadataVersion override val metadataVersion = state.metadataVersion
override fun shouldUseTypeTable(): Boolean = useTypeTable override fun shouldUseTypeTable(): Boolean = useTypeTable
@@ -191,7 +191,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
} }
private fun MutableVersionRequirementTable.writeInlineParameterNullCheckRequirement(add: (Int) -> Unit) { private fun MutableVersionRequirementTable.writeInlineParameterNullCheckRequirement(add: (Int) -> Unit) {
if (languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) { if (unifiedNullChecks) {
// Since Kotlin 1.4, we generate a call to Intrinsics.checkNotNullParameter in inline functions which causes older compilers // Since Kotlin 1.4, we generate a call to Intrinsics.checkNotNullParameter in inline functions which causes older compilers
// (earlier than 1.3.50) to crash because a functional parameter in this position can't be inlined // (earlier than 1.3.50) to crash because a functional parameter in this position can't be inlined
add(writeVersionRequirement(1, 3, 50, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, this)) add(writeVersionRequirement(1, 3, 50, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, this))
@@ -242,6 +242,7 @@ class GenerationState private constructor(
val assertionsMode: JVMAssertionsMode = configuration.get(JVMConfigurationKeys.ASSERTIONS_MODE, JVMAssertionsMode.DEFAULT) val assertionsMode: JVMAssertionsMode = configuration.get(JVMConfigurationKeys.ASSERTIONS_MODE, JVMAssertionsMode.DEFAULT)
val isInlineDisabled: Boolean = configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE) val isInlineDisabled: Boolean = configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE)
val useTypeTableInSerializer: Boolean = configuration.getBoolean(JVMConfigurationKeys.USE_TYPE_TABLE) val useTypeTableInSerializer: Boolean = configuration.getBoolean(JVMConfigurationKeys.USE_TYPE_TABLE)
val unifiedNullChecks: Boolean = languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
val rootContext: CodegenContext<*> = RootContext(this) val rootContext: CodegenContext<*> = RootContext(this)
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq import org.jetbrains.kotlin.codegen.pseudoInsns.fakeAlwaysFalseIfeq
import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump import org.jetbrains.kotlin.codegen.pseudoInsns.fixStackAndJump
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
@@ -283,9 +282,7 @@ class ExpressionCodegen(
if (!param.type.unboxInlineClass().isNullable() && !isPrimitive(asmType)) { if (!param.type.unboxInlineClass().isNullable() && !isPrimitive(asmType)) {
mv.load(findLocalIndex(param.symbol), asmType) mv.load(findLocalIndex(param.symbol), asmType)
mv.aconst(param.name.asString()) mv.aconst(param.name.asString())
val methodName = val methodName = if (state.unifiedNullChecks) "checkNotNullParameter" else "checkParameterIsNotNull"
if (state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) "checkNotNullParameter"
else "checkParameterIsNotNull"
mv.invokestatic(IrIntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false) mv.invokestatic(IrIntrinsicMethods.INTRINSICS_CLASS_NAME, methodName, "(Ljava/lang/Object;Ljava/lang/String;)V", false)
} }
} }
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -43,7 +42,7 @@ private class CheckNotNullLowering(private val backendContext: JvmBackendContext
// Starting with Kotlin 1.4 null-checks are lowered to calls to the "checkNotNull" intrinsic, which // Starting with Kotlin 1.4 null-checks are lowered to calls to the "checkNotNull" intrinsic, which
// throws a NullPointerException on failure. Prior to Kotlin 1.4 we instead inline the null-check and // throws a NullPointerException on failure. Prior to Kotlin 1.4 we instead inline the null-check and
// call the "throwNpe" intrinsic on failure which throws a KotlinNullPointerException. // call the "throwNpe" intrinsic on failure which throws a KotlinNullPointerException.
if (backendContext.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) { if (backendContext.state.unifiedNullChecks) {
+irCall(backendContext.ir.symbols.checkNotNull).apply { +irCall(backendContext.ir.symbols.checkNotNull).apply {
putValueArgument(0, irGet(argument)) putValueArgument(0, irGet(argument))
} }
@@ -7,11 +7,8 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.SpecialBridgeMethods import org.jetbrains.kotlin.backend.common.lower.SpecialBridgeMethods
import org.jetbrains.kotlin.backend.common.lower.flattenStringConcatenationPhase
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
@@ -35,7 +32,7 @@ private enum class AssertionScope {
private class JvmArgumentNullabilityAssertionsLowering(context: JvmBackendContext) : FileLoweringPass, IrElementTransformer<AssertionScope> { private class JvmArgumentNullabilityAssertionsLowering(context: JvmBackendContext) : FileLoweringPass, IrElementTransformer<AssertionScope> {
private val isWithUnifiedNullChecks = context.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4 private val isWithUnifiedNullChecks = context.state.unifiedNullChecks
private val isCallAssertionsDisabled = context.state.isCallAssertionsDisabled private val isCallAssertionsDisabled = context.state.isCallAssertionsDisabled
private val isReceiverAssertionsDisabled = context.state.isReceiverAssertionsDisabled private val isReceiverAssertionsDisabled = context.state.isReceiverAssertionsDisabled
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.fileParent import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
@@ -184,18 +183,14 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
private fun sourceViewFor(declaration: IrDeclaration) = private fun sourceViewFor(declaration: IrDeclaration) =
context.psiSourceManager.getKtFile(declaration.fileParent)!!.viewProvider.contents context.psiSourceManager.getKtFile(declaration.fileParent)!!.viewProvider.contents
// Since Kotlin 1.4 we throw NullPointerExceptions instead of more specialized exception classes.
private val useNullPointerExceptions: Boolean
get() = context.state.languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4
private val typeCastException: IrFunctionSymbol = private val typeCastException: IrFunctionSymbol =
if (useNullPointerExceptions) if (context.state.unifiedNullChecks)
context.ir.symbols.ThrowNullPointerException context.ir.symbols.ThrowNullPointerException
else else
context.ir.symbols.ThrowTypeCastException context.ir.symbols.ThrowTypeCastException
private val checkExpressionValueIsNotNull: IrFunctionSymbol = private val checkExpressionValueIsNotNull: IrFunctionSymbol =
if (useNullPointerExceptions) if (context.state.unifiedNullChecks)
context.ir.symbols.checkNotNullExpressionValue context.ir.symbols.checkNotNullExpressionValue
else else
context.ir.symbols.checkExpressionValueIsNotNull context.ir.symbols.checkExpressionValueIsNotNull