INSTANCE field deprecated in companion object

Fix for KT-9692: Deadlock between <clinit> of a class (KtSimpleNameExpressionImpl) and <clinit> of its companion object

 #KT-9692 Fixed
This commit is contained in:
Michael Bogdanov
2015-10-23 12:27:41 +03:00
parent 7927185cc7
commit 18f3eb87e4
13 changed files with 120 additions and 26 deletions
@@ -17,21 +17,19 @@
package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform;
import org.jetbrains.org.objectweb.asm.Type;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isNonCompanionObject;
public class FieldInfo {
@NotNull
public static FieldInfo createForCompanionSingleton(@NotNull ClassDescriptor companionObject, @NotNull JetTypeMapper typeMapper) {
ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(companionObject, ClassDescriptor.class);
assert ownerDescriptor != null : "Owner not found for class: " + companionObject;
Type ownerType = typeMapper.mapType(ownerDescriptor);
return new FieldInfo(ownerType, typeMapper.mapType(companionObject), companionObject.getName().asString(), true);
}
private static final CompanionObjectMapping COMPANION_OBJECT_MAPPING = new CompanionObjectMapping(JvmPlatform.INSTANCE.getBuiltIns());
@NotNull
public static FieldInfo createForSingleton(@NotNull ClassDescriptor classDescriptor, @NotNull JetTypeMapper typeMapper) {
@@ -43,6 +41,24 @@ public class FieldInfo {
if (!classDescriptor.getKind().isSingleton()) {
throw new UnsupportedOperationException("Can't create singleton field for class: " + classDescriptor);
}
if (isNonCompanionObject(classDescriptor) || COMPANION_OBJECT_MAPPING.hasMappingToObject(classDescriptor)) {
return createSingletonViaInstance(classDescriptor, typeMapper, oldSingleton);
}
else {
ClassDescriptor ownerDescriptor = DescriptorUtils.getParentOfType(classDescriptor, ClassDescriptor.class);
assert ownerDescriptor != null : "Owner not found for class: " + classDescriptor;
Type ownerType = typeMapper.mapType(ownerDescriptor);
return new FieldInfo(ownerType, typeMapper.mapType(classDescriptor), classDescriptor.getName().asString(), true);
}
}
@NotNull
public static FieldInfo createSingletonViaInstance(
@NotNull ClassDescriptor classDescriptor,
@NotNull JetTypeMapper typeMapper,
boolean oldSingleton
) {
Type type = typeMapper.mapType(classDescriptor);
return new FieldInfo(type, type, oldSingleton ? JvmAbi.DEPRECATED_INSTANCE_FIELD : JvmAbi.INSTANCE_FIELD, true);
}
@@ -835,9 +835,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateFieldForSingleton() {
if (isEnumEntry(descriptor)) return;
if (isObject(descriptor)) {
StackValue.Field field = StackValue.singleton(descriptor, typeMapper);
v.newField(JvmDeclarationOriginKt.OtherOrigin(myClass), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
boolean isCompanionObject = isCompanionObject(descriptor);
if (isNonCompanionObject(descriptor) || isCompanionObject) {
StackValue.Field field = StackValue.singletonViaInstance(descriptor, typeMapper);
v.newField(JvmDeclarationOriginKt.OtherOrigin(myClass),
ACC_PUBLIC | ACC_STATIC | ACC_FINAL | (isCompanionObject ? ACC_DEPRECATED : 0),
field.name, field.type.getDescriptor(), null, null);
if (isNonCompanionObject(descriptor)) {
StackValue.Field oldField = StackValue.oldSingleton(descriptor, typeMapper);
@@ -845,18 +848,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
// Invoke the object constructor but ignore the result because INSTANCE$ will be initialized in the first line of <init>
InstructionAdapter v = createOrGetClInitCodegen().v;
markLineNumberForSyntheticFunction(element, v);
v.anew(classAsmType);
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
if (isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
//We should load containing class to initialize companion fields
StackValue companion = StackValue.singletonForCompanion(descriptor, typeMapper);
companion.put(companion.type, v);
AsmUtil.pop(v, companion.type);
}
return;
}
@@ -868,7 +865,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
KtObjectDeclaration companionObject = CollectionsKt.firstOrNull(((KtClass) myClass).getCompanionObjects());
assert companionObject != null : "Companion object not found: " + myClass.getText();
StackValue.Field field = StackValue.singletonForCompanion(companionObjectDescriptor, typeMapper);
StackValue.Field field = StackValue.singleton(companionObjectDescriptor, typeMapper);
v.newField(JvmDeclarationOriginKt.OtherOrigin(companionObject), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
@@ -927,8 +924,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
ExpressionCodegen codegen = createOrGetClInitCodegen();
StackValue.singletonForCompanion(companionObject, typeMapper)
.store(StackValue.singleton(companionObject, typeMapper), codegen.v, true);
//TODO: uncomment when DEPRECATED INSTANCE is removed
//FunctionDescriptor constructor = (FunctionDescriptor) context.accessibleDescriptor(
// CollectionsKt.single(companionObject.getConstructors()), /* superCallExpression = */ null
//);
//generateMethodCallTo(constructor, null, codegen.v);
//StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
StackValue.singleton(companionObject, typeMapper).store(StackValue.singletonViaInstance(companionObject, typeMapper), codegen.v, true);
}
private void generatePrimaryConstructor(final DelegationFieldsInfo delegationFieldsInfo) {
@@ -998,7 +1000,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
getDelegationConstructorCall(bindingContext, constructorDescriptor));
if (isObject(descriptor)) {
StackValue.singleton(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
StackValue.singletonViaInstance(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
if (isNonCompanionObject(descriptor)) {
StackValue.oldSingleton(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
}
@@ -578,8 +578,8 @@ public abstract class StackValue {
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper));
}
public static Field singletonForCompanion(ClassDescriptor companionObject, JetTypeMapper typeMapper) {
return field(FieldInfo.createForCompanionSingleton(companionObject, typeMapper));
public static Field singletonViaInstance(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper, false));
}
public static Field oldSingleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {