Refactor generation of metadata for delegated properties

In CodegenAnnotatingVisitor, store all delegated properties whose
metadata should be generated in each class (identified by ASM Type).
Use the stored information later, both in the $$delegatedProperties
array generation and in the access to it from property's accessor
methods, instead of an heuristical indexOfDelegatedProperty()
This commit is contained in:
Alexander Udalov
2017-06-08 21:52:15 +03:00
parent b97589b33e
commit 728de91140
4 changed files with 53 additions and 79 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper;
import org.jetbrains.kotlin.codegen.inline.NameGenerator;
@@ -47,7 +48,6 @@ import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
@@ -69,7 +69,10 @@ import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceWithDefaultsMember;
@@ -524,11 +527,8 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
StackValue provideDelegateReceiver = codegen.gen(initializer);
int indexOfDelegatedProperty = PropertyCodegen.indexOfDelegatedProperty(property);
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethodWithReceiver(
codegen, typeMapper, provideDelegateResolvedCall, indexOfDelegatedProperty, 1,
provideDelegateReceiver, propertyDescriptor
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethod(
codegen, typeMapper, provideDelegateResolvedCall, provideDelegateReceiver, propertyDescriptor
);
propValue.store(delegateValue, codegen.v);
@@ -608,16 +608,8 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
}
protected void generatePropertyMetadataArrayFieldIfNeeded(@NotNull Type thisAsmType) {
List<KtProperty> delegatedProperties = new ArrayList<>();
for (KtDeclaration declaration : ((KtDeclarationContainer) element).getDeclarations()) {
if (declaration instanceof KtProperty) {
KtProperty property = (KtProperty) declaration;
if (property.hasDelegate()) {
delegatedProperties.add(property);
}
}
}
if (delegatedProperties.isEmpty()) return;
List<VariableDescriptorWithAccessors> delegatedProperties = bindingContext.get(CodegenBinding.DELEGATED_PROPERTIES, thisAsmType);
if (delegatedProperties == null || delegatedProperties.isEmpty()) return;
v.newField(NO_ORIGIN, ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
"[" + K_PROPERTY_TYPE, null, null);
@@ -629,8 +621,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
iv.newarray(K_PROPERTY_TYPE);
for (int i = 0, size = delegatedProperties.size(); i < size; i++) {
PropertyDescriptor property =
(PropertyDescriptor) BindingContextUtils.getNotNull(bindingContext, VARIABLE, delegatedProperties.get(i));
VariableDescriptorWithAccessors property = delegatedProperties.get(i);
iv.dup();
iv.iconst(i);
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorFactory;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
@@ -60,6 +59,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.getDeprecatedAccessFlag;
import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.DELEGATED_PROPERTIES;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
@@ -478,7 +478,7 @@ public class PropertyCodegen {
FunctionGenerationStrategy strategy;
if (accessor == null || !accessor.hasBody()) {
if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((KtProperty) p));
strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor);
}
else {
strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor);
@@ -491,39 +491,9 @@ public class PropertyCodegen {
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), accessorDescriptor, strategy);
}
public static int indexOfDelegatedProperty(@NotNull KtProperty property) {
PsiElement parent = property.getParent();
KtDeclarationContainer container;
if (parent instanceof KtClassBody) {
container = ((KtClassOrObject) parent.getParent());
}
else if (parent instanceof KtFile) {
container = (KtFile) parent;
}
else if (KtPsiUtil.isScriptDeclaration(property)) {
container = KtPsiUtil.getScript(property);
assert container != null : "Script declaration for property '" + property.getText() + "' should be not null!";
}
else {
throw new UnsupportedOperationException("Unknown delegated property container: " + parent);
}
int index = 0;
for (KtDeclaration declaration : container.getDeclarations()) {
if (declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate()) {
if (declaration == property) {
return index;
}
index++;
}
}
throw new IllegalStateException("Delegated property not found in its parent: " + PsiUtilsKt.getElementTextWithContext(property));
}
private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
super(state);
propertyAccessorDescriptor = descriptor;
@@ -561,26 +531,9 @@ public class PropertyCodegen {
}
public static StackValue invokeDelegatedPropertyConventionMethod(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull ExpressionCodegen codegen,
@NotNull KotlinTypeMapper typeMapper,
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
int indexInPropertyMetadataArray,
int propertyMetadataArgumentIndex
) {
StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
return invokeDelegatedPropertyConventionMethodWithReceiver(
codegen, typeMapper, resolvedCall, indexInPropertyMetadataArray, propertyMetadataArgumentIndex,
receiver, propertyDescriptor
);
}
public static StackValue invokeDelegatedPropertyConventionMethodWithReceiver(
@NotNull ExpressionCodegen codegen,
@NotNull KotlinTypeMapper typeMapper,
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
int indexInPropertyMetadataArray,
int propertyMetadataArgumentIndex,
@Nullable StackValue receiver,
@NotNull PropertyDescriptor propertyDescriptor
) {
@@ -589,16 +542,29 @@ public class PropertyCodegen {
getDelegatedPropertyMetadataOwner(codegen, typeMapper);
codegen.tempVariables.put(
resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
resolvedCall.getCall().getValueArguments().get(1).asElement(),
new StackValue(K_PROPERTY_TYPE) {
@Override
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
Field array = StackValue.field(
Type.getType("[" + K_PROPERTY_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true, StackValue.none()
);
StackValue.arrayElement(
K_PROPERTY_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE)
).put(type, v);
int index = findDelegatedProperty(typeMapper.getBindingContext(), owner, propertyDescriptor);
StackValue.arrayElement(K_PROPERTY_TYPE, array, StackValue.constant(index, Type.INT_TYPE)).put(type, v);
}
private int findDelegatedProperty(
@NotNull BindingContext bindingContext,
@NotNull Type owner,
@NotNull PropertyDescriptor propertyDescriptor
) {
List<VariableDescriptorWithAccessors> allDelegatedProperties = bindingContext.get(DELEGATED_PROPERTIES, owner);
int result = allDelegatedProperties == null ? -1 : allDelegatedProperties.indexOf(propertyDescriptor);
if (result < 0) {
throw new AssertionError("Delegated property not found in " + owner + ": " + propertyDescriptor);
}
return result;
}
}
);
@@ -623,13 +589,11 @@ public class PropertyCodegen {
}
private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
private final int index;
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) {
public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
super(state);
this.index = index;
propertyAccessorDescriptor = descriptor;
this.propertyAccessorDescriptor = descriptor;
}
@Override
@@ -641,8 +605,10 @@ public class PropertyCodegen {
bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, propertyAccessorDescriptor);
assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
StackValue lastValue = invokeDelegatedPropertyConventionMethod(propertyAccessorDescriptor.getCorrespondingProperty(),
codegen, state.getTypeMapper(), resolvedCall, index, 1);
PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty();
StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
StackValue lastValue =
invokeDelegatedPropertyConventionMethod(codegen, state.getTypeMapper(), resolvedCall, receiver, propertyDescriptor);
Type asmType = signature.getReturnType();
lastValue.put(asmType, v);
v.areturn(asmType);
@@ -417,6 +417,20 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
runtimeTypes.getSupertypeForPropertyReference(variableDescriptor, variableDescriptor.isVar(), /* bound = */ false);
ClassDescriptor classDescriptor = recordClassForCallable(delegate, variableDescriptor, Collections.singleton(supertype), name);
recordClosure(classDescriptor, name);
if (!(variableDescriptor instanceof LocalVariableDescriptor)) {
ClassDescriptor containerClass = peekFromStack(classStack);
Type containerType =
containerClass != null
? CodegenBinding.getAsmType(bindingContext, containerClass)
: Type.getObjectType(FileClasses.getFileClassInternalName(fileClassesProvider, property.getContainingKtFile()));
List<VariableDescriptorWithAccessors> descriptors = bindingTrace.get(DELEGATED_PROPERTIES, containerType);
if (descriptors == null) {
descriptors = new ArrayList<>(1);
bindingTrace.record(DELEGATED_PROPERTIES, containerType, descriptors);
}
descriptors.add(variableDescriptor);
}
}
super.visitProperty(property);
@@ -69,6 +69,9 @@ public class CodegenBinding {
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
Slices.createSimpleSlice();
public static final WritableSlice<Type, List<VariableDescriptorWithAccessors>> DELEGATED_PROPERTIES =
Slices.createSimpleSlice();
static {
BasicWritableSlice.initSliceDebugNames(CodegenBinding.class);
}