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.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.types.KotlinType
abstract class AccessorForPropertyBackingField(property: PropertyDescriptor,
type: KotlinType,
receiverType: KotlinType?,
dispatchReceiver: ReceiverParameterDescriptor?,
containingDeclaration: DeclarationDescriptor,
suffix: String
) : AccessorForPropertyDescriptor(property, type, receiverType, dispatchReceiver, containingDeclaration, null, suffix)
class AccessorForPropertyBackingField(
property: PropertyDescriptor,
containingDeclaration: DeclarationDescriptor,
delegateType: KotlinType?,
extensionReceiverParameter: ReceiverParameterDescriptor?,
dispatchReceiverParameter: ReceiverParameterDescriptor?,
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 {
private final PropertyAccessorDescriptor callableDescriptor;
private PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) {
super(MemberCodegen.this.state);
this.callableDescriptor = callableDescriptor;
@@ -745,7 +746,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
@Override
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) &&
!isCompanionObject(accessor.getContainingDeclaration());
boolean forceField = forceFieldForCompanionProperty ||
@@ -434,49 +434,44 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
AccessorKey key = new AccessorKey(descriptor, superCallTarget);
// NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
if (propertyAccessorFactory != null) {
return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
if (propertyAccessorFactories.containsKey(key)) {
return (D) propertyAccessorFactories.get(key).getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
}
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
if (accessor != null) {
if (accessors.containsKey(key)) {
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
assert accessorKind == FieldAccessorKind.NORMAL ||
accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
return (D) accessor;
}
String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
AccessorForCallableDescriptor<?> accessor;
if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor(
(FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
);
accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix);
}
else if (descriptor instanceof ClassConstructorDescriptor) {
accessor = new AccessorForConstructorDescriptor((ClassConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
}
else if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
switch (accessorKind) {
case NORMAL:
propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
superCallTarget, nameSuffix);
propertyAccessorFactories.put(key, propertyAccessorFactory);
if (accessorKind == FieldAccessorKind.NORMAL) {
AccessorForPropertyDescriptorFactory factory =
new AccessorForPropertyDescriptorFactory(propertyDescriptor, contextDescriptor, superCallTarget, nameSuffix);
propertyAccessorFactories.put(key, factory);
// Record worst case accessor for accessor methods generation.
AccessorForPropertyDescriptor accessorWithGetterAndSetter =
propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
accessors.put(key, accessorWithGetterAndSetter);
// Record worst case accessor for accessor methods generation.
accessors.put(key, factory.getOrCreateAccessorWithSyntheticGetterAndSetter());
PropertyDescriptor accessorDescriptor =
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;
return (D) factory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
}
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 {
throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
@@ -22,26 +22,25 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
enum class FieldAccessorKind(val suffix: String) {
NORMAL("p"),
IN_CLASS_COMPANION("cp"),
FIELD_FROM_LOCAL("lp");
override fun toString() = suffix
FIELD_FROM_LOCAL("lp"),
}
private fun CallableMemberDescriptor.getJvmName() =
DescriptorUtils.getJvmName(this) ?: name.asString()
fun getAccessorNameSuffix(descriptor: CallableMemberDescriptor, superCallDescriptor: ClassDescriptor?,
accessorKind: FieldAccessorKind): String {
fun getAccessorNameSuffix(
descriptor: CallableMemberDescriptor, superCallDescriptor: ClassDescriptor?, accessorKind: FieldAccessorKind
): String {
val suffix = when (descriptor) {
is ConstructorDescriptor ->
return "will be ignored"
is SimpleFunctionDescriptor ->
descriptor.getJvmName()
is PropertyDescriptor ->
descriptor.getJvmName() + "$" + accessorKind
descriptor.getJvmName() + "$" + accessorKind.suffix
else ->
throw UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor)
}
return if (superCallDescriptor == null) suffix else "$suffix\$s${superCallDescriptor.name.asString().hashCode()}"
}
}