From 97e4c097ba269ea811adbcc3cf66314817099f6f Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 27 Aug 2015 16:42:52 +0300 Subject: [PATCH] Split annotations lazily --- .../kotlin/codegen/PropertyCodegen.java | 23 ++--- .../kotlin/resolve/DescriptorResolver.java | 32 +++--- .../kotlin/util/AnnotationSplitter.kt | 99 ++++++++++++++----- 3 files changed, 109 insertions(+), 45 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 9c899851958..62262a989a0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations; +import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; @@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; +import org.jetbrains.kotlin.storage.LockBasedStorageManager; import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.util.AnnotationSplitter; @@ -49,7 +51,9 @@ 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.HashSet; import java.util.List; +import java.util.Set; import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface; @@ -117,8 +121,8 @@ public class PropertyCodegen { boolean hasBackingField = hasBackingField(declaration, descriptor); - AnnotationSplitter annotationSplitter = AnnotationSplitter.create( - descriptor.getAnnotations(), false, hasBackingField, descriptor.isVar()); + AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS, + descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(false, descriptor.isVar(), hasBackingField)); Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); @@ -170,8 +174,8 @@ public class PropertyCodegen { } public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) { - AnnotationSplitter annotationSplitter = AnnotationSplitter.create( - descriptor.getAnnotations(), true, hasBackingField(p, descriptor), descriptor.isVar()); + AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS, + descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(true, descriptor.isVar(), hasBackingField(p, descriptor))); Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); @@ -212,12 +216,9 @@ public class PropertyCodegen { } private boolean hasBackingField(@NotNull JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor) { - if (isInterface(descriptor.getContainingDeclaration()) || - kind == OwnerKind.TRAIT_IMPL || - Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) { - return false; - } - else return true; + return !isInterface(descriptor.getContainingDeclaration()) && + kind != OwnerKind.TRAIT_IMPL && + !Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor)); } private boolean generateBackingField( @@ -254,7 +255,7 @@ public class PropertyCodegen { int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC; MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, name, desc, null, null); AnnotationCodegen.forMethod(mv, typeMapper) - .genAnnotations(new AnnotatedImpl(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY); + .genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY); mv.visitCode(); mv.visitInsn(Opcodes.RETURN); mv.visitEnd(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 6d55381a438..a92414c6e01 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -342,7 +342,8 @@ public class DescriptorResolver { if (modifierList != null) { if (valueParameter.hasValOrVar()) { - AnnotationSplitter annotationSplitter = new AnnotationSplitter(allAnnotations, KotlinPackage.setOf(CONSTRUCTOR_PARAMETER)); + AnnotationSplitter annotationSplitter = AnnotationSplitter.create( + storageManager, allAnnotations, KotlinPackage.setOf(CONSTRUCTOR_PARAMETER)); valueParameterAnnotations = annotationSplitter.getAnnotationsForTarget(CONSTRUCTOR_PARAMETER); } else { @@ -702,7 +703,7 @@ public class DescriptorResolver { @NotNull DeclarationDescriptor containingDeclaration, @NotNull LexicalScope scope, @NotNull JetProperty property, - @NotNull BindingTrace trace, + @NotNull final BindingTrace trace, @NotNull DataFlowInfo dataFlowInfo ) { JetModifierList modifierList = property.getModifierList(); @@ -714,15 +715,16 @@ public class DescriptorResolver { ? resolveModalityFromModifiers(property, getDefaultModality(containingDeclaration, visibility, hasBody)) : Modality.FINAL; - JetPropertyAccessor propertyGetter = property.getGetter(); - - boolean hasBackingField = modality != Modality.ABSTRACT - && property.hasDelegateExpressionOrInitializer() - && (propertyGetter == null || !propertyGetter.hasBody()); + final AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper(); Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace); - AnnotationSplitter annotationSplitter = AnnotationSplitter.create(allAnnotations, - /*parameter =*/ false, /*hasBackingField =*/ hasBackingField, /*isMutable =*/ isVar); + AnnotationSplitter annotationSplitter = + new AnnotationSplitter(storageManager, allAnnotations, new Function0>() { + @Override + public Set invoke() { + return AnnotationSplitter.getTargetSet(false, trace.getBindingContext(), wrapper); + } + }); Annotations propertyAnnotations = new CompositeAnnotations(KotlinPackage.listOf( annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD), @@ -738,6 +740,7 @@ public class DescriptorResolver { CallableMemberDescriptor.Kind.DECLARATION, toSourceElement(property) ); + wrapper.setProperty(propertyDescriptor); List typeParameterDescriptors; LexicalScope scopeWithTypeParameters; @@ -1087,9 +1090,15 @@ public class DescriptorResolver { } } + final AnnotationSplitter.PropertyWrapper propertyWrapper = new AnnotationSplitter.PropertyWrapper(); Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, parameter.getModifierList(), trace); - AnnotationSplitter annotationSplitter = AnnotationSplitter.create(allAnnotations, - /*parameter =*/ true, /*hasBackingField =*/ true, /*isMutable =*/ isMutable); + AnnotationSplitter annotationSplitter = + new AnnotationSplitter(storageManager, allAnnotations, new Function0>() { + @Override + public Set invoke() { + return AnnotationSplitter.getTargetSet(true, trace.getBindingContext(), propertyWrapper); + } + }); Annotations propertyAnnotations = new CompositeAnnotations( annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD), @@ -1105,6 +1114,7 @@ public class DescriptorResolver { CallableMemberDescriptor.Kind.DECLARATION, toSourceElement(parameter) ); + propertyWrapper.setProperty(propertyDescriptor); propertyDescriptor.setType(type, Collections.emptyList(), getDispatchReceiverParameterIfNeeded(classDescriptor), (ReceiverParameterDescriptor) null); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/util/AnnotationSplitter.kt b/compiler/frontend/src/org/jetbrains/kotlin/util/AnnotationSplitter.kt index c174a34d1dc..c5b3e60055d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/util/AnnotationSplitter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/util/AnnotationSplitter.kt @@ -16,20 +16,71 @@ package org.jetbrains.kotlin.util +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.annotations.* import org.jetbrains.kotlin.resolve.AnnotationChecker import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.storage.StorageManager import kotlin.platform.platformStatic -public class AnnotationSplitter(original: Annotations, applicableTargets: Set) { - private val annotations: Map> - public val otherAnnotations: Annotations +/* + This class lazily splits Annotations into several different Annotations according to declaration site target priority on property. + Basically you pass an original Annotations and a list of targets applicable for your declaration. - init { + Example: Annotations = [@property:P1, @field:F1, F2, P2, T], + F2, P2, T are annotations with declaration site targets 'field', 'property' and 'type', respectively. + + Annotations will be split as: + FIELD -> [F1, F2], (even if F2 is applicable to PROPERTY because of target priority) + PROPERTY -> [P1, P2], + other -> [T]. + */ + +public class AnnotationSplitter( + storageManager: StorageManager, + allAnnotations: Annotations, + applicableTargetsLazy: () -> Set +) { + public companion object { + private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, FIELD, PROPERTY, PROPERTY_SETTER, PROPERTY_GETTER) + + @platformStatic + public fun create( + storageManager: StorageManager, + annotations: Annotations, + targets: Set + ): AnnotationSplitter { + return AnnotationSplitter(storageManager, annotations, { targets }) + } + + @platformStatic + public fun getTargetSet(parameter: Boolean, context: BindingContext, wrapper: PropertyWrapper): Set { + val property = wrapper.property + assert(property != null) + val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, property] ?: false + return getTargetSet(parameter, property!!.isVar, hasBackingField) + } + + @platformStatic + public fun getTargetSet(parameter: Boolean, isVar: Boolean, hasBackingField: Boolean): Set { + return hashSetOf(PROPERTY, PROPERTY_GETTER).apply { + if (parameter) add(CONSTRUCTOR_PARAMETER) + if (hasBackingField) add(FIELD) + if (isVar) add(PROPERTY_SETTER) + } + } + } + + public class PropertyWrapper(public var property: PropertyDescriptor? = null) + + private val splitAnnotations = storageManager.createLazyValue { val map = hashMapOf>() val other = arrayListOf() + val applicableTargets = applicableTargetsLazy() - outer@ for (annotationWithTarget in original.getAllAnnotations()) { + outer@ for (annotationWithTarget in allAnnotations.getAllAnnotations()) { val useSiteTarget = annotationWithTarget.target if (useSiteTarget != null) { if (useSiteTarget in applicableTargets) @@ -45,9 +96,8 @@ public class AnnotationSplitter(original: Annotations, applicableTargets: Set