Rework const val generation in multifile classes

Do not query MultifileClassCodegen#classBuilder early on: this causes the class
file for the facade to be prematurely dumped to the disk in some cases, when
that class file is not yet completely generated. Instead fork the logic in
PropertyCodegen#generateSyntheticMethodIfNeeded: save metadata in parts,
generate method in the facade
This commit is contained in:
Alexander Udalov
2016-03-28 15:56:08 +03:00
parent f31dca32a4
commit 4a533168d9
9 changed files with 52 additions and 55 deletions
@@ -73,7 +73,7 @@ class MultifileClassCodegen(
private fun getDeserializedCallables(compiledPackageFragment: PackageFragmentDescriptor) =
compiledPackageFragment.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CALLABLES, MemberScope.ALL_NAME_FILTER).filterIsInstance<DeserializedCallableMemberDescriptor>()
val classBuilder = ClassBuilderOnDemand {
private val classBuilder = ClassBuilderOnDemand {
val originFile = files.firstOrNull()
val actualPackageFragment = packageFragment ?:
compiledPackageFragment ?:
@@ -163,7 +163,7 @@ class MultifileClassCodegen(
var generatePart = false
val partClassInfo = state.fileClassesProvider.getFileClassInfo(file)
val partType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partClassInfo.fileClassFqName)
val partContext = state.rootContext.intoMultifileClassPart(this, packageFragment, facadeClassType, partType, file)
val partContext = state.rootContext.intoMultifileClassPart(packageFragment, facadeClassType, partType, file)
for (declaration in file.declarations) {
when (declaration) {
@@ -119,11 +119,8 @@ public class PropertyCodegen {
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
if (CodegenContextUtil.isImplClassOwner(context)) {
assert declaration != null : "Declaration is null for different context: " + context;
genBackingFieldAndAnnotations(declaration, descriptor, false);
}
assert declaration != null : "Declaration is null: " + descriptor + " (context=" + context + ")";
genBackingFieldAndAnnotations(declaration, descriptor, false);
if (isAccessorNeeded(declaration, descriptor, getter)) {
generateGetter(declaration, descriptor, getter);
@@ -134,9 +131,6 @@ public class PropertyCodegen {
}
private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) {
ClassBuilder builder = getCorrectClassBuilder(descriptor);
if (builder == null) return;
boolean hasBackingField = hasBackingField(declaration, descriptor);
boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate();
@@ -145,21 +139,23 @@ public class PropertyCodegen {
descriptor.getAnnotations(),
AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField, hasDelegate));
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
generateBackingField(builder, declaration, descriptor, fieldAnnotations, delegateAnnotations);
generateSyntheticMethodIfNeeded(builder, descriptor, propertyAnnotations);
}
// Fields and '$annotations' methods for const properties are generated in the multi-file facade
boolean isBackingFieldOwner =
descriptor.isConst() ? !(context instanceof MultifileClassPartContext) : CodegenContextUtil.isImplClassOwner(context);
@Nullable
private ClassBuilder getCorrectClassBuilder(@NotNull PropertyDescriptor descriptor) {
if (descriptor.isConst() && context instanceof MultifileClassPartContext) {
return ((MultifileClassPartContext) context).getMultifileClassCodegen().getClassBuilder();
if (isBackingFieldOwner) {
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations);
generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations);
}
return this.v;
if (!propertyAnnotations.getAllAnnotations().isEmpty() && kind != OwnerKind.DEFAULT_IMPLS &&
CodegenContextUtil.isImplClassOwner(context)) {
v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, getSyntheticMethodSignature(descriptor));
}
}
/**
@@ -245,7 +241,6 @@ public class PropertyCodegen {
}
private boolean generateBackingField(
@NotNull ClassBuilder builder,
@NotNull KtNamedDeclaration p,
@NotNull PropertyDescriptor descriptor,
@NotNull Annotations backingFieldAnnotations,
@@ -256,10 +251,10 @@ public class PropertyCodegen {
}
if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
generatePropertyDelegateAccess(builder, (KtProperty) p, descriptor, delegateAnnotations);
generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations);
}
else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
generateBackingFieldAccess(builder, p, descriptor, backingFieldAnnotations);
generateBackingFieldAccess(p, descriptor, backingFieldAnnotations);
}
else {
return false;
@@ -269,29 +264,20 @@ public class PropertyCodegen {
// Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
// accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
private void generateSyntheticMethodIfNeeded(
@NotNull ClassBuilder builder,
@NotNull PropertyDescriptor descriptor,
@NotNull Annotations annotations
) {
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, @NotNull Annotations annotations) {
if (annotations.getAllAnnotations().isEmpty()) return;
Method syntheticMethod = getSyntheticMethodSignature(descriptor);
if (!isInterface(context.getContextDescriptor()) || kind == OwnerKind.DEFAULT_IMPLS) {
int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
MethodVisitor mv = builder.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
syntheticMethod.getDescriptor(), null, null);
Method syntheticMethod = getSyntheticMethodSignature(descriptor);
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
syntheticMethod.getDescriptor(), null, null);
AnnotationCodegen.forMethod(mv, typeMapper)
.genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
if (kind != OwnerKind.DEFAULT_IMPLS) {
v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, syntheticMethod);
}
}
@NotNull
@@ -303,7 +289,6 @@ public class PropertyCodegen {
}
private void generateBackingField(
ClassBuilder builder,
KtNamedDeclaration element,
PropertyDescriptor propertyDescriptor,
boolean isDelegate,
@@ -333,6 +318,8 @@ public class PropertyCodegen {
Type type = typeMapper.mapType(kotlinType);
ClassBuilder builder = v;
FieldOwnerContext backingFieldContext = context;
if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
modifiers |= ACC_STATIC;
@@ -365,7 +352,6 @@ public class PropertyCodegen {
}
private void generatePropertyDelegateAccess(
@NotNull ClassBuilder builder,
@NotNull KtProperty p,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations
@@ -377,11 +363,10 @@ public class PropertyCodegen {
delegateType = ErrorUtils.createErrorType("Delegate type");
}
generateBackingField(builder, p, propertyDescriptor, true, delegateType, null, annotations);
generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations);
}
private void generateBackingFieldAccess(
@NotNull ClassBuilder builder,
@NotNull KtNamedDeclaration p,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations
@@ -395,7 +380,7 @@ public class PropertyCodegen {
}
}
generateBackingField(builder, p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations);
generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations);
}
private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
@@ -251,13 +251,12 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
@NotNull
public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClassPart(
@NotNull MultifileClassCodegen codegen,
@NotNull PackageFragmentDescriptor descriptor,
@NotNull Type multifileClassType,
@NotNull Type filePartType,
@NotNull KtFile sourceFile
) {
return new MultifileClassPartContext(codegen, descriptor, this, multifileClassType, filePartType, sourceFile);
return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType, sourceFile);
}
@NotNull
@@ -18,17 +18,14 @@ package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.MultifileClassCodegen;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.org.objectweb.asm.Type;
public class MultifileClassPartContext extends MultifileClassContextBase implements DelegatingToPartContext, FacadePartWithSourceFile {
private final KtFile sourceFile;
private final MultifileClassCodegen codegen;
public MultifileClassPartContext(
@NotNull MultifileClassCodegen codegen,
PackageFragmentDescriptor descriptor,
CodegenContext parent,
Type multifileClassType,
@@ -37,7 +34,6 @@ public class MultifileClassPartContext extends MultifileClassContextBase impleme
) {
super(descriptor, parent, multifileClassType, filePartType);
this.sourceFile = sourceFile;
this.codegen = codegen;
}
@Nullable
@@ -51,9 +47,4 @@ public class MultifileClassPartContext extends MultifileClassContextBase impleme
public KtFile getSourceFile() {
return sourceFile;
}
@NotNull
public MultifileClassCodegen getMultifileClassCodegen() {
return codegen;
}
}
@@ -42,12 +42,11 @@
"declaration": "package-fragment ",
"class": "MultifileFacade",
"members": [
{"visibility": "public", "declaration": "const val publicConst: kotlin.Int", "name": "publicConst", "desc": "I"},
{"visibility": "internal", "declaration": "const val internalConst: kotlin.Int", "name": "internalConst", "desc": "I"},
{"visibility": "private", "declaration": "const val privateConst: kotlin.Int", "name": "privateConst", "desc": "I"},
{"visibility": "internal", "declaration": "fun <get-internalVal>(): kotlin.Long", "name": "getInternalVal", "desc": "()J"},
{"visibility": "internal", "declaration": "fun <get-internalVar>(): kotlin.Long", "name": "getInternalVar", "desc": "()J"},
{"visibility": "internal", "declaration": "fun <set-internalVar>(<set-?>: kotlin.Long): kotlin.Unit", "name": "setInternalVar", "desc": "(J)V"},
{"visibility": "public", "declaration": "const val publicConst: kotlin.Int", "name": "publicConst", "desc": "I"},
{"visibility": "public", "declaration": "fun <get-publicVal>(): kotlin.Int", "name": "getPublicVal", "desc": "()I"},
{"visibility": "public", "declaration": "fun <get-publicVar>(): kotlin.Int", "name": "getPublicVar", "desc": "()I"},
{"visibility": "public", "declaration": "fun <set-publicVar>(<set-?>: kotlin.Int): kotlin.Unit", "name": "setPublicVar", "desc": "(I)V"},
@@ -11,6 +11,8 @@ public fun fn1b(): kotlin.Unit { /* compiled code */ }
public fun kotlin.String.fn2b(): kotlin.Unit { /* compiled code */ }
@kotlin.Deprecated public const val annotatedConstVal: kotlin.Int /* compiled code */
public val val1a: kotlin.Int /* compiled code */
private val kotlin.String.val2a: kotlin.Int /* compiled code */
@@ -9,3 +9,6 @@ public fun String.fn2a() {}
class ShouldNotBeVisible1
interface ShouldNotBeVisible2
@Deprecated("deprecated")
const val annotatedConstVal = 42
@@ -5,6 +5,10 @@ fun p1Fun() {}
fun String.p1ExtFun() {}
fun p1ExprFun(): Int = 0
fun p1FunWithParams(x: Int): Int { return x }
val p1Val: Int = 0
val String.p1ExtVal: Int get() = 0
var p1Var: Int = 0
var p1Var: Int = 0
@Deprecated("deprecated")
const val annotatedConstVal = 42
@@ -2,6 +2,20 @@ PsiJetFileStubImpl[package=test]
PACKAGE_DIRECTIVE:
REFERENCE_EXPRESSION:[referencedName=test]
IMPORT_LIST:
PROPERTY:[fqName=test.annotatedConstVal, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=true, isVar=false, name=annotatedConstVal]
MODIFIER_LIST:[public const]
ANNOTATION_ENTRY:[hasValueArguments=false, shortName=Deprecated]
CONSTRUCTOR_CALLEE:
TYPE_REFERENCE:
USER_TYPE:[isAbsoluteInRootPackage=false]
USER_TYPE:[isAbsoluteInRootPackage=false]
REFERENCE_EXPRESSION:[referencedName=kotlin]
REFERENCE_EXPRESSION:[referencedName=Deprecated]
TYPE_REFERENCE:
USER_TYPE:[isAbsoluteInRootPackage=false]
USER_TYPE:[isAbsoluteInRootPackage=false]
REFERENCE_EXPRESSION:[referencedName=kotlin]
REFERENCE_EXPRESSION:[referencedName=Int]
PROPERTY:[fqName=test.p1Val, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=true, isVar=false, name=p1Val]
MODIFIER_LIST:[public]
TYPE_REFERENCE: