From a7c8fdcbe2e260e5265aaf5121c5987206a676c9 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 26 Jul 2019 17:05:47 +0200 Subject: [PATCH] Use Intrinsics.checkNotNull and throw NPE in !! operator generation This method was introduced in c204e8fc67 "just in case" and was never used. Therefore we're free to change its semantics and use it in all new generated code (with API version >= 1.4), without even worrying that the newly used API will leak from inline functions in stdlib when used with an older API version. Since we agreed to change the type of thrown exceptions to java.lang.NPE in KT-22275, invoke a new method throwJavaNpe now which throws that exception instead of KNPE. Note that the additional method that takes an exception message is still unused and exists just in case we need to use it in the future. The new method throwJavaNpe is public also "just in case" we need to invoke it in the future; currently it's not invoked from the bytecode. #KT-22275 In Progress --- .../kotlin/codegen/ExpressionCodegen.java | 12 ++++-- .../RedundantNullCheckMethodTransformer.kt | 40 +++++++++++++++++-- .../exclExclThrowsNpe_1_4.kt | 14 +++++++ .../deadCodeElimination/arrayConstructor.kt | 1 + .../deadCodeElimination/boxing.kt | 1 + .../boxingNotOptimizable.kt | 1 + .../deadCodeElimination/literal.kt | 1 + .../deadCodeElimination/simpleConstructor.kt | 1 + .../simpleConstructorNotRedundant.kt | 1 + ...leConstructorNotRedundantNotOptimizable.kt | 1 + .../inline/inlineReturnsNothing1.kt | 4 +- .../multipleExclExcl_1_4.kt | 13 ++++++ .../nullCheckAfterExclExcl_1_4.kt | 14 +++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++ .../codegen/BytecodeTextTestGenerated.java | 10 +++++ .../LightAnalysisModeTestGenerated.java | 5 +++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++ .../ir/IrBytecodeTextTestGenerated.java | 10 +++++ .../org/jetbrains/kotlin/config/ApiVersion.kt | 3 ++ .../kotlin/jvm/internal/Intrinsics.java | 17 ++++++-- .../kotlin-stdlib-runtime-merged.txt | 2 + 21 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt create mode 100644 compiler/testData/codegen/bytecodeText/nullCheckOptimization/multipleExclExcl_1_4.kt create mode 100644 compiler/testData/codegen/bytecodeText/nullCheckOptimization/nullCheckAfterExclExcl_1_4.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 73c04def32f..3c11651d2bd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -4022,10 +4022,14 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.operation(base.type, base.kotlinType, v -> { base.put(base.type, base.kotlinType, v); v.dup(); - Label ok = new Label(); - v.ifnonnull(ok); - v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false); - v.mark(ok); + if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_4) >= 0) { + v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkNotNull", "(Ljava/lang/Object;)V", false); + } else { + Label ok = new Label(); + v.ifnonnull(ok); + v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false); + v.mark(ok); + } return null; }); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt index 5ecfe358952..e169dba2e7a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt @@ -38,6 +38,7 @@ import org.jetbrains.org.objectweb.asm.tree.* class RedundantNullCheckMethodTransformer(private val generationState: GenerationState) : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { + @Suppress("ControlFlowWithEmptyBody") while (TransformerPass(internalClassName, methodNode, generationState).run()) { } } @@ -69,6 +70,7 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio val value = when { insn.isInstanceOfOrNullCheck() -> frame.top() + insn.isCheckNotNull() -> frame.top() insn.isCheckExpressionValueIsNotNull() -> frame.peek(1) else -> null } as? StrictBasicValue ?: continue @@ -84,6 +86,7 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio opcode == Opcodes.IFNULL || opcode == Opcodes.IFNONNULL || opcode == Opcodes.INSTANCEOF || + isCheckNotNull() || isCheckExpressionValueIsNotNull() private fun transformTrivialChecks(nullabilityMap: Map) { @@ -95,6 +98,9 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio Opcodes.INSTANCEOF -> transformInstanceOf(insn as TypeInsnNode, nullability, value) Opcodes.INVOKESTATIC -> { + if (insn.isCheckNotNull()) { + transformTrivialCheckNotNull(insn, nullability) + } if (insn.isCheckExpressionValueIsNotNull()) { transformTrivialCheckExpressionValueIsNotNull(insn, nullability) } @@ -134,6 +140,15 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio } } + private fun transformTrivialCheckNotNull(insn: AbstractInsnNode, nullability: Nullability) { + if (nullability != Nullability.NOT_NULL) return + val dupInsn = insn.previous?.takeIf { it.opcode == Opcodes.DUP } ?: return + methodNode.instructions.run { + remove(dupInsn) + remove(insn) + } + } + private fun transformTrivialCheckExpressionValueIsNotNull(insn: AbstractInsnNode, nullability: Nullability) { if (nullability != Nullability.NOT_NULL) return val ldcInsn = insn.previous?.takeIf { it.opcode == Opcodes.LDC } ?: return @@ -168,6 +183,14 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio } } + insn.isCheckNotNull() -> { + val dupInsn = insn.previous ?: continue@insnLoop + if (dupInsn.opcode != Opcodes.DUP) continue@insnLoop + val aLoadInsn = dupInsn.previous ?: continue@insnLoop + if (aLoadInsn.opcode != Opcodes.ALOAD) continue@insnLoop + addDependentCheck(insn, aLoadInsn as VarInsnNode) + } + insn.isCheckParameterIsNotNull() -> { val ldcInsn = insn.previous ?: continue@insnLoop if (ldcInsn.opcode != Opcodes.LDC) continue@insnLoop @@ -198,7 +221,7 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio private fun addDependentCheck(insn: AbstractInsnNode, aLoadInsn: VarInsnNode) { checksDependingOnVariable.getOrPut(aLoadInsn.`var`) { - SmartList() + SmartList() }.add(insn) } @@ -224,8 +247,7 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio injectAssumptionsForNullCheck(varIndex, insn as JumpInsnNode) Opcodes.INVOKESTATIC -> { when { - insn.isCheckParameterIsNotNull() || - insn.isCheckExpressionValueIsNotNull() -> + insn.isCheckNotNull() || insn.isCheckParameterIsNotNull() || insn.isCheckExpressionValueIsNotNull() -> injectAssumptionsForNotNullAssertion(varIndex, insn) insn.isPseudo(PseudoInsn.STORE_NOT_NULL) -> injectCodeForStoreNotNull(insn) @@ -276,6 +298,11 @@ class RedundantNullCheckMethodTransformer(private val generationState: Generatio } private fun NullabilityAssumptions.injectAssumptionsForNotNullAssertion(varIndex: Int, insn: AbstractInsnNode) { + // ALOAD v + // DUP + // INVOKESTATIC checkNotNull + // <...> -- v is not null here (otherwise an exception was thrown) + // ALOAD v // LDC * // INVOKESTATIC checkParameterIsNotNull @@ -396,6 +423,13 @@ internal fun AbstractInsnNode.isInstanceOfOrNullCheck() = opcode == Opcodes.IFNULL || opcode == Opcodes.IFNONNULL +internal fun AbstractInsnNode.isCheckNotNull() = + isInsn(Opcodes.INVOKESTATIC) { + owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && + name == "checkNotNull" && + desc == "(Ljava/lang/Object;)V" + } + internal fun AbstractInsnNode.isCheckParameterIsNotNull() = isInsn(Opcodes.INVOKESTATIC) { owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && diff --git a/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt b/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt new file mode 100644 index 00000000000..b66c5368a9c --- /dev/null +++ b/compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt @@ -0,0 +1,14 @@ +// !API_VERSION: LATEST +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR + +fun box(): String { + val s: String? = null + try { + s!! + return "Fail: NPE should have been thrown" + } catch (e: Throwable) { + if (e::class != NullPointerException::class) return "Fail: exception class should be NPE: ${e::class}" + return "OK" + } +} diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/arrayConstructor.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/arrayConstructor.kt index d171aa9c575..6d1685ec981 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/arrayConstructor.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/arrayConstructor.kt @@ -6,3 +6,4 @@ fun box() { // 0 IFNONNULL // 0 ATHROW // 0 throwNpe +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt index b1b5240cad7..c969b2bead9 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxing.kt @@ -20,3 +20,4 @@ fun box() { // 1 IFNONNULL // 1 throwNpe // 0 ATHROW +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt index 66471397a4f..aa68d3445b7 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/boxingNotOptimizable.kt @@ -19,3 +19,4 @@ fun box(u: Int) { // 1 IFNONNULL // 1 throwNpe // 0 ATHROW +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/literal.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/literal.kt index a3e1485370b..db277ebe35d 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/literal.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/literal.kt @@ -10,3 +10,4 @@ fun box() { // 0 IFNONNULL // 0 throwNpe // 0 ATHROW +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructor.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructor.kt index dfec1f31eba..56e223136b5 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructor.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructor.kt @@ -13,3 +13,4 @@ fun box() { // 0 IFNONNULL // 0 throwNpe // 0 ATHROW +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt index f160e4c4969..426fc06db86 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundant.kt @@ -17,3 +17,4 @@ fun box() { // 1 IFNONNULL // 1 throwNpe // 0 ATHROW +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt index 1c929f8220c..cd2c75cc163 100644 --- a/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt +++ b/compiler/testData/codegen/bytecodeText/deadCodeElimination/simpleConstructorNotRedundantNotOptimizable.kt @@ -16,3 +16,4 @@ fun box(u: Int) { // 1 IFNONNULL // 1 throwNpe // 0 ATHROW +// 0 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing1.kt b/compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing1.kt index 74e36070427..6917d999aea 100644 --- a/compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing1.kt +++ b/compiler/testData/codegen/bytecodeText/inline/inlineReturnsNothing1.kt @@ -1,4 +1,4 @@ -// NB '!!' uses Intrinsics.throwNpe() +// NB '!!' uses Intrinsics.throwNpe/checkNotNull inline fun exit(): Nothing = null!! fun box(): String { @@ -13,4 +13,4 @@ fun box(): String { return a } -// 1 ATHROW \ No newline at end of file +// 1 ATHROW diff --git a/compiler/testData/codegen/bytecodeText/nullCheckOptimization/multipleExclExcl_1_4.kt b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/multipleExclExcl_1_4.kt new file mode 100644 index 00000000000..88cdf076176 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/multipleExclExcl_1_4.kt @@ -0,0 +1,13 @@ +// !API_VERSION: LATEST +// IGNORE_BACKEND: JVM_IR + +fun test(s: String?): Int { + s!! + s!! + s!! + s!! + s!! + return 0 +} + +// 1 checkNotNull diff --git a/compiler/testData/codegen/bytecodeText/nullCheckOptimization/nullCheckAfterExclExcl_1_4.kt b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/nullCheckAfterExclExcl_1_4.kt new file mode 100644 index 00000000000..276a372e2d5 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/nullCheckOptimization/nullCheckAfterExclExcl_1_4.kt @@ -0,0 +1,14 @@ +// !API_VERSION: LATEST +// IGNORE_BACKEND: JVM_IR + +fun test(s: String?): Int { + s!! + if (s == null) { + return 5 + } + return 3 +} + +// 1 checkNotNull +// 0 IFNULL +// 0 IFNONNULL diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 8c6df6b83a6..a0f68d4e142 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -16404,6 +16404,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/nullCheckOptimization"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("exclExclThrowsNpe_1_4.kt") + public void testExclExclThrowsNpe_1_4() throws Exception { + runTest("compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt"); + } + @TestMetadata("isNullable.kt") public void testIsNullable() throws Exception { runTest("compiler/testData/codegen/box/nullCheckOptimization/isNullable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index dcbaa65f0e4..a82c9e29936 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -3266,11 +3266,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/kt12839.kt"); } + @TestMetadata("multipleExclExcl_1_4.kt") + public void testMultipleExclExcl_1_4() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/multipleExclExcl_1_4.kt"); + } + @TestMetadata("notNullAsNotNullable.kt") public void testNotNullAsNotNullable() throws Exception { runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/notNullAsNotNullable.kt"); } + @TestMetadata("nullCheckAfterExclExcl_1_4.kt") + public void testNullCheckAfterExclExcl_1_4() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/nullCheckAfterExclExcl_1_4.kt"); + } + @TestMetadata("primitiveCheck.kt") public void testPrimitiveCheck() throws Exception { runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/primitiveCheck.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index abd0748aec1..e380850bf6d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -16404,6 +16404,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/nullCheckOptimization"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("exclExclThrowsNpe_1_4.kt") + public void testExclExclThrowsNpe_1_4() throws Exception { + runTest("compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt"); + } + @TestMetadata("isNullable.kt") public void testIsNullable() throws Exception { runTest("compiler/testData/codegen/box/nullCheckOptimization/isNullable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 654be2e60cb..f8ddc5cb5ec 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -15289,6 +15289,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/nullCheckOptimization"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("exclExclThrowsNpe_1_4.kt") + public void testExclExclThrowsNpe_1_4() throws Exception { + runTest("compiler/testData/codegen/box/nullCheckOptimization/exclExclThrowsNpe_1_4.kt"); + } + @TestMetadata("isNullable.kt") public void testIsNullable() throws Exception { runTest("compiler/testData/codegen/box/nullCheckOptimization/isNullable.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index a0c364fdca8..24252c08781 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -3236,11 +3236,21 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/kt12839.kt"); } + @TestMetadata("multipleExclExcl_1_4.kt") + public void testMultipleExclExcl_1_4() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/multipleExclExcl_1_4.kt"); + } + @TestMetadata("notNullAsNotNullable.kt") public void testNotNullAsNotNullable() throws Exception { runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/notNullAsNotNullable.kt"); } + @TestMetadata("nullCheckAfterExclExcl_1_4.kt") + public void testNullCheckAfterExclExcl_1_4() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/nullCheckAfterExclExcl_1_4.kt"); + } + @TestMetadata("primitiveCheck.kt") public void testPrimitiveCheck() throws Exception { runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/primitiveCheck.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt b/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt index 7c7dcd9f8df..6ebede19b11 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/ApiVersion.kt @@ -52,6 +52,9 @@ class ApiVersion private constructor( @JvmField val KOTLIN_1_3 = createByLanguageVersion(LanguageVersion.KOTLIN_1_3) + @JvmField + val KOTLIN_1_4 = createByLanguageVersion(LanguageVersion.KOTLIN_1_4) + @JvmField val LATEST: ApiVersion = createByLanguageVersion(LanguageVersion.values().last()) diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java index fb7f5f4a114..84432b4d7f4 100644 --- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java +++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java @@ -10,9 +10,8 @@ import kotlin.SinceKotlin; import kotlin.UninitializedPropertyAccessException; import java.util.Arrays; -import java.util.List; -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "WeakerAccess"}) public class Intrinsics { private Intrinsics() { } @@ -23,13 +22,13 @@ public class Intrinsics { public static void checkNotNull(Object object) { if (object == null) { - throwNpe(); + throwJavaNpe(); } } public static void checkNotNull(Object object, String message) { if (object == null) { - throwNpe(message); + throwJavaNpe(message); } } @@ -41,6 +40,16 @@ public class Intrinsics { throw sanitizeStackTrace(new KotlinNullPointerException(message)); } + @SinceKotlin(version = "1.4") + public static void throwJavaNpe() { + throw sanitizeStackTrace(new NullPointerException()); + } + + @SinceKotlin(version = "1.4") + public static void throwJavaNpe(String message) { + throw sanitizeStackTrace(new NullPointerException(message)); + } + public static void throwUninitializedProperty(String message) { throw sanitizeStackTrace(new UninitializedPropertyAccessException(message)); } diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index d210107d59e..ccb39354064 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -3451,6 +3451,8 @@ public class kotlin/jvm/internal/Intrinsics { public static fun throwIllegalArgument (Ljava/lang/String;)V public static fun throwIllegalState ()V public static fun throwIllegalState (Ljava/lang/String;)V + public static fun throwJavaNpe ()V + public static fun throwJavaNpe (Ljava/lang/String;)V public static fun throwNpe ()V public static fun throwNpe (Ljava/lang/String;)V public static fun throwUndefinedForReified ()V