diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 9e39ca54dae..7a421644f0c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -835,7 +835,10 @@ public class AsmUtil { } public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) { - int size = type.getSize(); + dup(v, type.getSize()); + } + + private static void dup(@NotNull InstructionAdapter v, int size) { if (size == 2) { v.dup2(); } @@ -847,6 +850,36 @@ public class AsmUtil { } } + public static void dup(@NotNull InstructionAdapter v, @NotNull Type topOfStack, @NotNull Type afterTop) { + if (topOfStack.getSize() == 0 && afterTop.getSize() == 0) { + return; + } + + if (topOfStack.getSize() == 0) { + dup(v, afterTop); + } + else if (afterTop.getSize() == 0) { + dup(v, topOfStack); + } + else if (afterTop.getSize() == 1) { + if (topOfStack.getSize() == 1) { + dup(v, 2); + } + else { + v.dup2X1(); + v.pop2(); + v.dupX2(); + v.dupX2(); + v.pop(); + v.dup2X1(); + } + } + else { + //Note: it's possible to write dup3 and dup4 + throw new UnsupportedOperationException("Don't know how generate dup3/dup4 for: " + topOfStack + " and " + afterTop); + } + } + public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull GenerationState state) { AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(KOTLIN_SYNTHETIC_CLASS), true); JvmCodegenUtil.writeAbiVersion(av); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 875d3d24bbd..03ff9b57ef6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -771,12 +771,12 @@ public abstract class StackValue { private final boolean isGetter; private final ExpressionCodegen codegen; private final ArgumentGenerator argumentGenerator; - final List valueArguments; + private final List valueArguments; private final FrameMap frame; private final StackValue receiver; private final ResolvedCall resolvedGetCall; private final ResolvedCall resolvedSetCall; - DefaultCallMask mask; + private DefaultCallMask mask; public CollectionElementReceiver( @NotNull Callable callable, @@ -1424,6 +1424,11 @@ public abstract class StackValue { currentExtensionReceiver .moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize()); } + + @Override + public void dup(@NotNull InstructionAdapter v, boolean withReceiver) { + AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type); + } } public abstract static class StackValueWithSimpleReceiver extends StackValue { diff --git a/compiler/testData/codegen/box/extensionProperties/kt9897.kt b/compiler/testData/codegen/box/extensionProperties/kt9897.kt new file mode 100644 index 00000000000..728323b1c64 --- /dev/null +++ b/compiler/testData/codegen/box/extensionProperties/kt9897.kt @@ -0,0 +1,41 @@ +object Test { + var z = "0" + var l = 0L + + fun changeObject(): String { + "1".someProperty += 1 + return z + } + + fun changeLong(): Long { + 2L.someProperty -= 1 + return l + } + + var String.someProperty: Int + get() { + return this.length + } + set(left) { + z += this + left + } + + var Long.someProperty: Long + get() { + return l + } + set(left) { + l += this + left + } + +} + +fun box(): String { + val changeObject = Test.changeObject() + if (changeObject != "012") return "fail 1: $changeObject" + + val changeLong = Test.changeLong() + if (changeLong != 1L) return "fail 1: $changeLong" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/extensionProperties/kt9897_topLevel.kt b/compiler/testData/codegen/box/extensionProperties/kt9897_topLevel.kt new file mode 100644 index 00000000000..9ff0dd42c22 --- /dev/null +++ b/compiler/testData/codegen/box/extensionProperties/kt9897_topLevel.kt @@ -0,0 +1,38 @@ +var z = "0" +var l = 0L + +fun changeObject(): String { + "1".someProperty += 1 + return z +} + +fun changeLong(): Long { + 2L.someProperty -= 1 + return l +} + +var String.someProperty: Int + get() { + return this.length + } + set(left) { + z += this + left + } + +var Long.someProperty: Long + get() { + return l + } + set(left) { + l += this + left + } + +fun box(): String { + val changeObject = changeObject() + if (changeObject != "012") return "fail 1: $changeObject" + + val changeLong = changeLong() + if (changeLong != 1L) return "fail 1: $changeLong" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/jvmStatic/kt9897_static.kt b/compiler/testData/codegen/boxWithStdlib/jvmStatic/kt9897_static.kt new file mode 100644 index 00000000000..66559576b7b --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/jvmStatic/kt9897_static.kt @@ -0,0 +1,41 @@ +object Test { + var z = "0" + var l = 0L + + fun changeObject(): String { + "1".someProperty += 1 + return z + } + + fun changeLong(): Long { + 2L.someProperty -= 1 + return l + } + + @JvmStatic var String.someProperty: Int + get() { + return this.length + } + set(left) { + z += this + left + } + + @JvmStatic var Long.someProperty: Long + get() { + return l + } + set(left) { + l += this + left + } + +} + +fun box(): String { + val changeObject = Test.changeObject() + if (changeObject != "012") return "fail 1: $changeObject" + + val changeLong = Test.changeLong() + if (changeLong != 1L) return "fail 1: $changeLong" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index f9b23efc1bf..982367afb32 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -3883,6 +3883,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt9897.kt") + public void testKt9897() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionProperties/kt9897.kt"); + doTest(fileName); + } + + @TestMetadata("kt9897_topLevel.kt") + public void testKt9897_topLevel() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionProperties/kt9897_topLevel.kt"); + doTest(fileName); + } + @TestMetadata("topLevel.kt") public void testTopLevel() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/extensionProperties/topLevel.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 18c59b62789..1ae3240bb9d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2299,6 +2299,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("kt9897_static.kt") + public void testKt9897_static() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmStatic/kt9897_static.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("postfixInc.kt") public void testPostfixInc() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/jvmStatic/postfixInc.kt");