diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 1c6cf63be2c..4f55378928d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2048,32 +2048,27 @@ public class ExpressionCodegen extends KtVisitor impleme return genClosure((KtNamedFunction) expression, samType); } - Type asmType = - state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this); + Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this); return StackValue.operation(asmType, v -> { - v.anew(asmType); - v.dup(); + Label afterAll = new Label(); Type functionType = typeMapper.mapType(samType.getKotlinFunctionType()); expression.accept(visitor, StackValue.none()).put(functionType, v); - Label ifNonNull = new Label(); - Label afterAll = new Label(); - v.dup(); - v.ifnonnull(ifNonNull); + v.ifnull(afterAll); - // if null: pop function value and wrapper objects, put null - v.pop(); - v.pop2(); - v.aconst(null); - v.goTo(afterAll); - - v.mark(ifNonNull); + int tmp = myFrameMap.enterTemp(functionType); + v.store(tmp, functionType); + v.anew(asmType); + v.dup(); + v.load(tmp, functionType); v.invokespecial(asmType.getInternalName(), "", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), false); + myFrameMap.leaveTemp(functionType); v.mark(afterAll); + return null; }); } diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt new file mode 100644 index 00000000000..79753dcc970 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// FILE: JFoo.java + +import org.jetbrains.annotations.Nullable; + +public class JFoo { + public static void foo2(@Nullable Runnable h1, @Nullable Runnable h2) { + if (h2 != null) throw new AssertionError(); + h1.run(); + } +} + +// FILE: Test.kt +fun test() { + var i = 0 + JFoo.foo2({ i++ }, null) +} + +// @TestKt.class: +// 1 NEW TestKt\$test\$1 +// 1 NEW kotlin/jvm/internal/Ref\$IntRef +// 2 NEW +// 1 INVOKESPECIAL TestKt\$test\$1. +// 0 IFNONNULL +// 0 IFNULL +// 1 ACONST_NULL \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt new file mode 100644 index 00000000000..1df803ea0ff --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt @@ -0,0 +1,24 @@ +// WITH_RUNTIME +// FILE: JFoo.java + +import org.jetbrains.annotations.Nullable; + +public class JFoo { + public static void foo2(@Nullable Runnable h1, @Nullable Runnable h2) { + if (h2 != null) throw new AssertionError(); + h1.run(); + } +} + +// FILE: Test.kt +fun runnable(): (() -> Unit)? = null + +fun test() { + JFoo.foo2({}, runnable()) +} + +// @TestKt.class: +// 2 NEW +// 0 IFNONNULL +// 1 IFNULL +// 1 ACONST_NULL \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 6333953f1f0..a263a49029c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1920,6 +1920,27 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/sam") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Sam extends AbstractBytecodeTextTest { + public void testAllFilesPresentInSam() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/sam"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("samWrapperForNullInitialization.kt") + public void testSamWrapperForNullInitialization() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullInitialization.kt"); + doTest(fileName); + } + + @TestMetadata("samWrapperForNullableInitialization.kt") + public void testSamWrapperForNullableInitialization() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/sam/samWrapperForNullableInitialization.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/statements") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)