Refactor accessors for backing fields in JVM back-end

This commit is contained in:
Alexander Udalov
2017-07-14 13:46:27 +03:00
parent 326111aece
commit 27b8b209e3
6 changed files with 49 additions and 98 deletions
@@ -19,13 +19,22 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
abstract class AccessorForPropertyBackingField(property: PropertyDescriptor, class AccessorForPropertyBackingField(
type: KotlinType, property: PropertyDescriptor,
receiverType: KotlinType?, containingDeclaration: DeclarationDescriptor,
dispatchReceiver: ReceiverParameterDescriptor?, delegateType: KotlinType?,
containingDeclaration: DeclarationDescriptor, extensionReceiverParameter: ReceiverParameterDescriptor?,
suffix: String dispatchReceiverParameter: ReceiverParameterDescriptor?,
) : AccessorForPropertyDescriptor(property, type, receiverType, dispatchReceiver, containingDeclaration, null, suffix) nameSuffix: String,
val fieldAccessorKind: FieldAccessorKind
) : AccessorForPropertyDescriptor(
property,
delegateType ?: property.type,
extensionReceiverParameter?.type,
dispatchReceiverParameter,
containingDeclaration,
null,
nameSuffix
)
@@ -1,28 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.DescriptorUtils
class AccessorForPropertyBackingFieldFromLocal(property: PropertyDescriptor,
containingDeclaration: DeclarationDescriptor,
nameSuffix: String
) : AccessorForPropertyBackingField(property, property.type,
DescriptorUtils.getReceiverParameterType(property.extensionReceiverParameter),
property.dispatchReceiverParameter, containingDeclaration, nameSuffix)
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
class AccessorForPropertyBackingFieldInClassCompanion(property: PropertyDescriptor,
containingDeclaration: DeclarationDescriptor,
delegationType: KotlinType?,
nameSuffix: String
) : AccessorForPropertyBackingField(property, delegationType ?: property.type, null, null, containingDeclaration, nameSuffix)
@@ -738,6 +738,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
private final PropertyAccessorDescriptor callableDescriptor; private final PropertyAccessorDescriptor callableDescriptor;
private PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) { private PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) {
super(MemberCodegen.this.state); super(MemberCodegen.this.state);
this.callableDescriptor = callableDescriptor; this.callableDescriptor = callableDescriptor;
@@ -745,7 +746,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
@Override @Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
boolean syntheticBackingField = accessor instanceof AccessorForPropertyBackingFieldFromLocal; boolean syntheticBackingField =
accessor instanceof AccessorForPropertyBackingField &&
((AccessorForPropertyBackingField) accessor).getFieldAccessorKind() == FieldAccessorKind.FIELD_FROM_LOCAL;
boolean forceFieldForCompanionProperty = JvmAbi.isPropertyWithBackingFieldInOuterClass(original) && boolean forceFieldForCompanionProperty = JvmAbi.isPropertyWithBackingFieldInOuterClass(original) &&
!isCompanionObject(accessor.getContainingDeclaration()); !isCompanionObject(accessor.getContainingDeclaration());
boolean forceField = forceFieldForCompanionProperty || boolean forceField = forceFieldForCompanionProperty ||
@@ -434,49 +434,44 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
AccessorKey key = new AccessorKey(descriptor, superCallTarget); AccessorKey key = new AccessorKey(descriptor, superCallTarget);
// NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation) // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key); if (propertyAccessorFactories.containsKey(key)) {
if (propertyAccessorFactory != null) { return (D) propertyAccessorFactories.get(key).getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
} }
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
if (accessor != null) { if (accessors.containsKey(key)) {
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
assert accessorKind == FieldAccessorKind.NORMAL || assert accessorKind == FieldAccessorKind.NORMAL ||
accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context"; accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
return (D) accessor; return (D) accessor;
} }
String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind); String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
AccessorForCallableDescriptor<?> accessor;
if (descriptor instanceof SimpleFunctionDescriptor) { if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor( accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix);
(FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
);
} }
else if (descriptor instanceof ClassConstructorDescriptor) { else if (descriptor instanceof ClassConstructorDescriptor) {
accessor = new AccessorForConstructorDescriptor((ClassConstructorDescriptor) descriptor, contextDescriptor, superCallTarget); accessor = new AccessorForConstructorDescriptor((ClassConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
} }
else if (descriptor instanceof PropertyDescriptor) { else if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
switch (accessorKind) { if (accessorKind == FieldAccessorKind.NORMAL) {
case NORMAL: AccessorForPropertyDescriptorFactory factory =
propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor, new AccessorForPropertyDescriptorFactory(propertyDescriptor, contextDescriptor, superCallTarget, nameSuffix);
superCallTarget, nameSuffix); propertyAccessorFactories.put(key, factory);
propertyAccessorFactories.put(key, propertyAccessorFactory);
// Record worst case accessor for accessor methods generation. // Record worst case accessor for accessor methods generation.
AccessorForPropertyDescriptor accessorWithGetterAndSetter = accessors.put(key, factory.getOrCreateAccessorWithSyntheticGetterAndSetter());
propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
accessors.put(key, accessorWithGetterAndSetter);
PropertyDescriptor accessorDescriptor = return (D) factory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
return (D) accessorDescriptor;
case IN_CLASS_COMPANION:
accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
delegateType, nameSuffix);
break;
case FIELD_FROM_LOCAL:
accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
break;
} }
accessor = new AccessorForPropertyBackingField(
propertyDescriptor, contextDescriptor, delegateType,
accessorKind == FieldAccessorKind.IN_CLASS_COMPANION ? null : propertyDescriptor.getExtensionReceiverParameter(),
accessorKind == FieldAccessorKind.IN_CLASS_COMPANION ? null : propertyDescriptor.getDispatchReceiverParameter(),
nameSuffix, accessorKind
);
} }
else { else {
throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor); throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
@@ -22,23 +22,22 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
enum class FieldAccessorKind(val suffix: String) { enum class FieldAccessorKind(val suffix: String) {
NORMAL("p"), NORMAL("p"),
IN_CLASS_COMPANION("cp"), IN_CLASS_COMPANION("cp"),
FIELD_FROM_LOCAL("lp"); FIELD_FROM_LOCAL("lp"),
override fun toString() = suffix
} }
private fun CallableMemberDescriptor.getJvmName() = private fun CallableMemberDescriptor.getJvmName() =
DescriptorUtils.getJvmName(this) ?: name.asString() DescriptorUtils.getJvmName(this) ?: name.asString()
fun getAccessorNameSuffix(descriptor: CallableMemberDescriptor, superCallDescriptor: ClassDescriptor?, fun getAccessorNameSuffix(
accessorKind: FieldAccessorKind): String { descriptor: CallableMemberDescriptor, superCallDescriptor: ClassDescriptor?, accessorKind: FieldAccessorKind
): String {
val suffix = when (descriptor) { val suffix = when (descriptor) {
is ConstructorDescriptor -> is ConstructorDescriptor ->
return "will be ignored" return "will be ignored"
is SimpleFunctionDescriptor -> is SimpleFunctionDescriptor ->
descriptor.getJvmName() descriptor.getJvmName()
is PropertyDescriptor -> is PropertyDescriptor ->
descriptor.getJvmName() + "$" + accessorKind descriptor.getJvmName() + "$" + accessorKind.suffix
else -> else ->
throw UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor) throw UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor)
} }