From 679f53b449ad886b9079c1805880e54178d5c63f Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 14 Jun 2016 13:03:14 +0300 Subject: [PATCH] Inline get/setValues for local delegated properties --- .../kotlin/codegen/ExpressionCodegen.java | 24 ++--- .../codegen/ImplementationBodyCodegen.java | 2 +- .../jetbrains/kotlin/codegen/StackValue.java | 98 +++++++++++-------- .../{ => local}/capturedLocalVal.kt | 0 .../{ => local}/capturedLocalValNoInline.kt | 0 .../{ => local}/capturedLocalVar.kt | 0 .../{ => local}/capturedLocalVarNoInline.kt | 0 .../delegatedProperty/local/inlineGetValue.kt | 12 +++ .../local/inlineOperators.kt | 19 ++++ .../delegatedProperty/{ => local}/localVal.kt | 0 .../delegatedProperty/{ => local}/localVar.kt | 0 .../codegen/BlackBoxCodegenTestGenerated.java | 84 +++++++++------- 12 files changed, 144 insertions(+), 95 deletions(-) rename compiler/testData/codegen/box/delegatedProperty/{ => local}/capturedLocalVal.kt (100%) rename compiler/testData/codegen/box/delegatedProperty/{ => local}/capturedLocalValNoInline.kt (100%) rename compiler/testData/codegen/box/delegatedProperty/{ => local}/capturedLocalVar.kt (100%) rename compiler/testData/codegen/box/delegatedProperty/{ => local}/capturedLocalVarNoInline.kt (100%) create mode 100644 compiler/testData/codegen/box/delegatedProperty/local/inlineGetValue.kt create mode 100644 compiler/testData/codegen/box/delegatedProperty/local/inlineOperators.kt rename compiler/testData/codegen/box/delegatedProperty/{ => local}/localVal.kt (100%) rename compiler/testData/codegen/box/delegatedProperty/{ => local}/localVar.kt (100%) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index f2fac4bcc05..895e4287589 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2330,16 +2330,17 @@ public class ExpressionCodegen extends KtVisitor impleme return lookupCapturedValueInConstructorParameters(descriptor); } - return lookupInContext(descriptor, StackValue.LOCAL_0, state, false, context); + return lookupInContext(descriptor, StackValue.LOCAL_0, state, false, context, this); } @Nullable - StackValue lookupInContext( + static StackValue lookupInContext( @NotNull DeclarationDescriptor descriptor, @NotNull StackValue prefix, @NotNull GenerationState state, boolean ignoreNoOuter, - @NotNull CodegenContext context + @NotNull CodegenContext context, + @Nullable ExpressionCodegen codegen ) { StackValue value = context.lookupInContext(descriptor, prefix, state, ignoreNoOuter); if(!isDelegatedLocalVariable(descriptor) || value == null) { @@ -2350,7 +2351,9 @@ public class ExpressionCodegen extends KtVisitor impleme VariableDescriptor metadata = getDelegatedLocalVariableMetadata((VariableDescriptor) descriptor, state.getBindingContext()); StackValue metadataValue = context.lookupInContext(metadata, prefix, state, ignoreNoOuter); assert metadataValue != null : "Metadata stack value should be non-null for local delegated property"; - return delegatedVariableValue(value, metadataValue, (VariableDescriptorWithAccessors) descriptor, state.getBindingContext(), + //required for ImplementationBodyCodegen.lookupConstructorExpressionsInClosureIfPresent + if (codegen == null) return null; + return codegen.delegatedVariableValue(value, metadataValue, (VariableDescriptorWithAccessors) descriptor, state.getBindingContext(), state.getTypeMapper()); } @@ -4477,22 +4480,13 @@ The "returned" value of try expression with no finally is either the last expres } @NotNull - private static StackValue.Delegate delegatedVariableValue( + private StackValue.Delegate delegatedVariableValue( @NotNull StackValue delegateValue, @NotNull StackValue metadataValue, @NotNull VariableDescriptorWithAccessors variableDescriptor, @NotNull BindingContext bindingContext, @NotNull KotlinTypeMapper typeMapper ) { - VariableDescriptor delegateVariableDescriptor = bindingContext.get(LOCAL_VARIABLE_DELEGATE, variableDescriptor); - assert delegateVariableDescriptor != null : variableDescriptor; - - VariableAccessorDescriptor getterDescriptor = variableDescriptor.getGetter(); - VariableAccessorDescriptor setterDescriptor = variableDescriptor.getSetter(); - - //noinspection ConstantConditions - CallableMethod getterMethod = typeMapper.mapToCallableMethod(getterDescriptor, false); - CallableMethod setterMethod = setterDescriptor != null ? typeMapper.mapToCallableMethod(setterDescriptor, false) : null; - return StackValue.delegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, getterMethod, setterMethod); + return StackValue.delegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, variableDescriptor, this); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 4d28b1dafae..41cca5bdf6c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1256,7 +1256,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void lookupInContext(@NotNull DeclarationDescriptor toLookup) { - ExpressionCodegen.lookupInContext(toLookup, StackValue.LOCAL_0, state, true, context); + ExpressionCodegen.lookupInContext(toLookup, StackValue.LOCAL_0, state, true, context, null); } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 980895c04ef..5b4bc9f71bf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -35,6 +35,8 @@ import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor; import org.jetbrains.kotlin.psi.KtExpression; +import org.jetbrains.kotlin.psi.ValueArgument; +import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor; import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt; @@ -154,13 +156,13 @@ public abstract class StackValue { @NotNull public static Delegate delegate( - Type type, + @NotNull Type type, @NotNull StackValue delegateValue, @NotNull StackValue metadataValue, - @NotNull CallableMethod getter, - @Nullable CallableMethod setter + @NotNull VariableDescriptorWithAccessors variableDescriptor, + @NotNull ExpressionCodegen codegen ) { - return new Delegate(type, delegateValue, metadataValue, getter, setter); + return new Delegate(type, delegateValue, metadataValue, variableDescriptor, codegen); } @NotNull @@ -660,62 +662,72 @@ public abstract class StackValue { } } - public static class Delegate extends StackValueWithSimpleReceiver { - @NotNull private final StackValue delegateValue; - @NotNull private final StackValue metadataValue; - @NotNull private final CallableMethod getter; - @Nullable private final CallableMethod setter; + public static class Delegate extends StackValue { + @NotNull + private final StackValue delegateValue; + @NotNull + private final StackValue metadataValue; + @NotNull + private final VariableDescriptorWithAccessors variableDescriptor; + @NotNull + private final ExpressionCodegen codegen; private Delegate( - Type type, + @NotNull Type type, @NotNull StackValue delegateValue, @NotNull StackValue metadataValue, - @NotNull CallableMethod getter, - @Nullable CallableMethod setter + @NotNull VariableDescriptorWithAccessors variableDescriptor, + @NotNull ExpressionCodegen codegen ) { - super(type, false, false, new Receiver(OBJECT_TYPE, delegateValue, constant(null, OBJECT_TYPE), metadataValue) { - @Override - public void dup(@NotNull InstructionAdapter v, boolean withReceiver) { - //UGLY HACK - //TODO rethink Receiver/StackValue concept - //We need to make duplication of delegated var, owner (null) and property metadata: dup 3. - //As HACK Type.LONG_TYPE and Type.INT_TYPE passed to dup util to simulate dup 3. - AsmUtil.dup(v, Type.LONG_TYPE, Type.INT_TYPE); - } - }, false); + super(type); this.delegateValue = delegateValue; this.metadataValue = metadataValue; - this.getter = getter; - this.setter = setter; + this.variableDescriptor = variableDescriptor; + this.codegen = codegen; } - @NotNull - public StackValue getMetadataValue() { - return metadataValue; + + private ResolvedCall getResolvedCall(boolean isGetter) { + BindingContext bindingContext = codegen.getState().getBindingContext(); + VariableAccessorDescriptor accessor = isGetter ? variableDescriptor.getGetter(): variableDescriptor.getSetter(); + assert accessor != null : "Accessor descriptor for delegated local property should be present " + variableDescriptor; + ResolvedCall resolvedCall = bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor); + assert resolvedCall != null : "Resolve call should be recorded for delegate call " + variableDescriptor; + return resolvedCall; } @Override public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { - getter.genInvokeInstruction(v); - coerce(getter.getReturnType(), type, v); + ResolvedCall resolvedCall = getResolvedCall(true); + List arguments = resolvedCall.getCall().getValueArguments(); + assert arguments.size() == 2 : "Resolved call for 'getValue' should have 2 arguments, but was " + + arguments.size() + ": " + resolvedCall; + + codegen.tempVariables.put(arguments.get(0).asElement(), StackValue.constant(null, OBJECT_TYPE)); + codegen.tempVariables.put(arguments.get(1).asElement(), metadataValue); + StackValue lastValue = codegen.invokeFunction(resolvedCall, delegateValue); + lastValue.put(type, v); + + codegen.tempVariables.remove(arguments.get(0).asElement()); + codegen.tempVariables.remove(arguments.get(1).asElement()); } @Override - public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) { - assert setter != null : ""; - coerceFrom(topOfStackType, v); - setter.genInvokeInstruction(v); - } + public void store(@NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver) { + ResolvedCall resolvedCall = getResolvedCall(false); + List arguments = resolvedCall.getCall().getValueArguments(); + assert arguments.size() == 3 : "Resolved call for 'setValue' should have 3 arguments, but was " + + arguments.size() + ": " + resolvedCall; - @Override - protected StackValueWithSimpleReceiver changeReceiver(@NotNull StackValue newReceiver) { - StackValue newDelegateValue = delegateValue instanceof StackValueWithSimpleReceiver - ? ((StackValueWithSimpleReceiver) delegateValue).changeReceiver(newReceiver) - : delegateValue; - StackValue newMetadataValue = metadataValue instanceof StackValueWithSimpleReceiver - ? ((StackValueWithSimpleReceiver) metadataValue).changeReceiver(newReceiver) - : metadataValue; - return delegate(type, newDelegateValue, newMetadataValue, getter, setter); + codegen.tempVariables.put(arguments.get(0).asElement(), StackValue.constant(null, OBJECT_TYPE)); + codegen.tempVariables.put(arguments.get(1).asElement(), metadataValue); + codegen.tempVariables.put(arguments.get(2).asElement(), rightSide); + StackValue lastValue = codegen.invokeFunction(resolvedCall, delegateValue); + lastValue.put(Type.VOID_TYPE, v); + + codegen.tempVariables.remove(arguments.get(0).asElement()); + codegen.tempVariables.remove(arguments.get(1).asElement()); + codegen.tempVariables.remove(arguments.get(2).asElement()); } } diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt b/compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVal.kt similarity index 100% rename from compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt rename to compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVal.kt diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt b/compiler/testData/codegen/box/delegatedProperty/local/capturedLocalValNoInline.kt similarity index 100% rename from compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt rename to compiler/testData/codegen/box/delegatedProperty/local/capturedLocalValNoInline.kt diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt b/compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVar.kt similarity index 100% rename from compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt rename to compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVar.kt diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt b/compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVarNoInline.kt similarity index 100% rename from compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt rename to compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVarNoInline.kt diff --git a/compiler/testData/codegen/box/delegatedProperty/local/inlineGetValue.kt b/compiler/testData/codegen/box/delegatedProperty/local/inlineGetValue.kt new file mode 100644 index 00000000000..80a60fd6e61 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/local/inlineGetValue.kt @@ -0,0 +1,12 @@ +package foo + +import kotlin.reflect.KProperty + +class Delegate { + inline operator fun getValue(t: Any?, p: KProperty<*>): String = p.name +} + +fun box(): String { + val OK: String by Delegate() + return OK +} diff --git a/compiler/testData/codegen/box/delegatedProperty/local/inlineOperators.kt b/compiler/testData/codegen/box/delegatedProperty/local/inlineOperators.kt new file mode 100644 index 00000000000..98198d4acd4 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/local/inlineOperators.kt @@ -0,0 +1,19 @@ +package foo + +import kotlin.reflect.KProperty + +class Delegate { + var inner = 1 + inline operator fun getValue(t: Any?, p: KProperty<*>): Int = inner + inline operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { + inner = i + } +} + +fun box(): String { + var prop: Int by Delegate() + if (prop != 1) return "fail get" + prop = 2 + if (prop != 2) return "fail set" + return "OK" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/localVal.kt b/compiler/testData/codegen/box/delegatedProperty/local/localVal.kt similarity index 100% rename from compiler/testData/codegen/box/delegatedProperty/localVal.kt rename to compiler/testData/codegen/box/delegatedProperty/local/localVal.kt diff --git a/compiler/testData/codegen/box/delegatedProperty/localVar.kt b/compiler/testData/codegen/box/delegatedProperty/local/localVar.kt similarity index 100% rename from compiler/testData/codegen/box/delegatedProperty/localVar.kt rename to compiler/testData/codegen/box/delegatedProperty/local/localVar.kt diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index f9a358303e4..ca1db8dd618 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -5032,30 +5032,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("capturedLocalVal.kt") - public void testCapturedLocalVal() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt"); - doTest(fileName); - } - - @TestMetadata("capturedLocalValNoInline.kt") - public void testCapturedLocalValNoInline() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt"); - doTest(fileName); - } - - @TestMetadata("capturedLocalVar.kt") - public void testCapturedLocalVar() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt"); - doTest(fileName); - } - - @TestMetadata("capturedLocalVarNoInline.kt") - public void testCapturedLocalVarNoInline() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt"); - doTest(fileName); - } - @TestMetadata("castGetReturnType.kt") public void testCastGetReturnType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/castGetReturnType.kt"); @@ -5170,18 +5146,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("localVal.kt") - public void testLocalVal() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/localVal.kt"); - doTest(fileName); - } - - @TestMetadata("localVar.kt") - public void testLocalVar() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/localVar.kt"); - doTest(fileName); - } - @TestMetadata("privateSetterKPropertyIsNotMutable.kt") public void testPrivateSetterKPropertyIsNotMutable() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/privateSetterKPropertyIsNotMutable.kt"); @@ -5274,12 +5238,60 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty/local"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("capturedLocalVal.kt") + public void testCapturedLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVal.kt"); + doTest(fileName); + } + + @TestMetadata("capturedLocalValNoInline.kt") + public void testCapturedLocalValNoInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/capturedLocalValNoInline.kt"); + doTest(fileName); + } + + @TestMetadata("capturedLocalVar.kt") + public void testCapturedLocalVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVar.kt"); + doTest(fileName); + } + + @TestMetadata("capturedLocalVarNoInline.kt") + public void testCapturedLocalVarNoInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/capturedLocalVarNoInline.kt"); + doTest(fileName); + } + @TestMetadata("iinc.kt") public void testIinc() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/iinc.kt"); doTest(fileName); } + @TestMetadata("inlineGetValue.kt") + public void testInlineGetValue() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/inlineGetValue.kt"); + doTest(fileName); + } + + @TestMetadata("inlineOperators.kt") + public void testInlineOperators() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/inlineOperators.kt"); + doTest(fileName); + } + + @TestMetadata("localVal.kt") + public void testLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/localVal.kt"); + doTest(fileName); + } + + @TestMetadata("localVar.kt") + public void testLocalVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/localVar.kt"); + doTest(fileName); + } + @TestMetadata("plusAssign.kt") public void testPlusAssign() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/plusAssign.kt");