From e7f77e9d35483cf3d428f5c9a2eecc98d6cbb3aa Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Sat, 5 Nov 2022 12:12:33 +0100 Subject: [PATCH] Keep track of array types in OptimizationBasicInterpreter Merging array types with different element types, for example `[Lj/l/String;` and `[Lj/l/Object;`, now produces `[Lj/l/Object;` (instead of `Lj/l/Object;`), which allows for more precise tracking of null values because we assume that AALOAD on a non-array typed value is possible only if that value is null. #KT-54802 Fixed --- .../common/OptimizationBasicInterpreter.java | 50 +++++++++++++++---- .../FirBlackBoxCodegenTestGenerated.java | 6 +++ .../testData/codegen/box/casts/kt54707.kt | 4 -- .../testData/codegen/box/casts/kt54802.kt | 14 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../IrBlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 15 ++++-- .../js/test/JsCodegenBoxTestGenerated.java | 6 +++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 6 +++ .../IrCodegenBoxWasmTestGenerated.java | 5 ++ .../NativeCodegenBoxTestGenerated.java | 6 +++ 11 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 compiler/testData/codegen/box/casts/kt54802.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java index 8c52059e38aa4..dbfa154174011 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java @@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.codegen.AsmUtil; +import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.org.objectweb.asm.Handle; import org.jetbrains.org.objectweb.asm.Opcodes; import org.jetbrains.org.objectweb.asm.Type; @@ -152,13 +153,6 @@ public BasicValue binaryOperation( @NotNull BasicValue value1, @NotNull BasicValue value2 ) throws AnalyzerException { - if (insn.getOpcode() == Opcodes.AALOAD) { - Type arrayType = value1.getType(); - if (arrayType != null && arrayType.getSort() == Type.ARRAY) { - return new StrictBasicValue(AsmUtil.correctElementType(arrayType)); - } - } - switch (insn.getOpcode()) { case IALOAD: case BALOAD: @@ -204,7 +198,13 @@ public BasicValue binaryOperation( case DREM: return StrictBasicValue.DOUBLE_VALUE; case AALOAD: - return StrictBasicValue.NULL_VALUE; + Type arrayType = value1.getType(); + if (arrayType != null && arrayType.getSort() == Type.ARRAY) { + return new StrictBasicValue(AsmUtil.correctElementType(arrayType)); + } + else { + return StrictBasicValue.NULL_VALUE; + } case LCMP: case FCMPL: case FCMPG: @@ -359,13 +359,11 @@ public BasicValue merge( return StrictBasicValue.UNINITIALIZED_VALUE; } - // if merge of two references then `lub` is java/lang/Object - // arrays also are BasicValues with reference type's if (isReference(v) && isReference(w)) { if (v == NULL_VALUE) return newValue(w.getType()); if (w == NULL_VALUE) return newValue(v.getType()); - return StrictBasicValue.REFERENCE_VALUE; + return mergeReferenceTypes(w.getType(), v.getType()); } // if merge of something can be stored in int var (int, char, boolean, byte, character) @@ -380,4 +378,34 @@ public BasicValue merge( private static boolean isReference(@NotNull BasicValue v) { return v.getType().getSort() == Type.OBJECT || v.getType().getSort() == Type.ARRAY; } + + // Merge reference types, keeping track of array dimensions. + // See also org.jetbrains.org.objectweb.asm.Frame.merge. + private BasicValue mergeReferenceTypes(@NotNull Type a, @NotNull Type b) { + // Find out the minimal array dimension of both types. + int arrayDimensions = 0; + while (a.getSort() == Type.ARRAY && b.getSort() == Type.ARRAY) { + a = AsmUtil.correctElementType(a); + b = AsmUtil.correctElementType(b); + arrayDimensions++; + } + // Either of the two types is not an array -> result is j/l/Object. + if (arrayDimensions == 0) return REFERENCE_VALUE; + + // Both of the types are arrays, and element type of one or both of them is primitive -> + // result is array of j/l/Object with one fewer dimension. E.g. + // merge([I, [Lj/l/Object;) = Lj/l/Object; + // merge([I, [S) = Lj/l/Object; + // merge([[I, [[Lj/l/Object;) = [Lj/l/Object; + if (AsmUtil.isPrimitive(a) || AsmUtil.isPrimitive(b)) { + arrayDimensions--; + } + + // Result is array of j/l/Object with the computed dimension. + StringBuilder result = new StringBuilder(); + while (arrayDimensions-- > 0) result.append("["); + result.append(AsmTypes.OBJECT_TYPE.getDescriptor()); + return newValue(Type.getType(result.toString())); + } + } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 1337c716cb25c..d2110efa5bdee 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -4769,6 +4769,12 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @Test + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/compiler/testData/codegen/box/casts/kt54707.kt b/compiler/testData/codegen/box/casts/kt54707.kt index bf0f9692a15af..74a48eb592725 100644 --- a/compiler/testData/codegen/box/casts/kt54707.kt +++ b/compiler/testData/codegen/box/casts/kt54707.kt @@ -1,6 +1,3 @@ -// IGNORE_BACKEND: JVM -// IGNORE_LIGHT_ANALYSIS - fun box(): String = g(arrayOf("O")) @@ -12,4 +9,3 @@ inline fun Array.f(lambda: (T) -> T): T = inline fun Array?.orEmpty0(): Array = this ?: (arrayOfNulls(0) as Array) - diff --git a/compiler/testData/codegen/box/casts/kt54802.kt b/compiler/testData/codegen/box/casts/kt54802.kt new file mode 100644 index 0000000000000..dc66bf4243873 --- /dev/null +++ b/compiler/testData/codegen/box/casts/kt54802.kt @@ -0,0 +1,14 @@ +class K { + val x: String = "OK" +} + +inline fun Array.ifEmpty(body: () -> Array): Array = + if (size == 0) body() else this + +inline fun Array.f(p: (T) -> String): String = + p(this[0]) + +fun box(): String = + emptyArray() + .ifEmpty { arrayOf(K()) } + .f(K::x) diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 7332fd2f0ce1d..9d4b7502d434c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -4643,6 +4643,12 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @Test + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 4eaac045980f2..8fe7795a74f44 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -4769,6 +4769,12 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @Test + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e11f6b7278b3e..157411a20abdf 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -3913,11 +3913,6 @@ public void testWithReflect() throws Exception { @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class Casts extends AbstractLightAnalysisModeTest { - @TestMetadata("kt54707.kt") - public void ignoreKt54707() throws Exception { - runTest("compiler/testData/codegen/box/casts/kt54707.kt"); - } - private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -4051,6 +4046,16 @@ public void testKt54581() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54581.kt"); } + @TestMetadata("kt54707.kt") + public void testKt54707() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54707.kt"); + } + + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index 268a45062ba58..08740b24e64d4 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -3395,6 +3395,12 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @Test + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index d6631d602ac9a..42f9233f1613b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -3449,6 +3449,12 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @Test + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 5bf5f2ab2d218..175d21cdcc8e9 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -3046,6 +3046,11 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception { runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index 3d91fcef6d212..4a682c6769978 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -3523,6 +3523,12 @@ public void testKt54707() throws Exception { runTest("compiler/testData/codegen/box/casts/kt54707.kt"); } + @Test + @TestMetadata("kt54802.kt") + public void testKt54802() throws Exception { + runTest("compiler/testData/codegen/box/casts/kt54802.kt"); + } + @Test @TestMetadata("lambdaToUnitCast.kt") public void testLambdaToUnitCast() throws Exception {