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:
@@ -17,21 +17,19 @@
|
|||||||
package org.jetbrains.kotlin.codegen;
|
package org.jetbrains.kotlin.codegen;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
||||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isNonCompanionObject;
|
||||||
|
|
||||||
public class FieldInfo {
|
public class FieldInfo {
|
||||||
|
|
||||||
@NotNull
|
private static final CompanionObjectMapping COMPANION_OBJECT_MAPPING = new CompanionObjectMapping(JvmPlatform.INSTANCE.getBuiltIns());
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static FieldInfo createForSingleton(@NotNull ClassDescriptor classDescriptor, @NotNull JetTypeMapper typeMapper) {
|
public static FieldInfo createForSingleton(@NotNull ClassDescriptor classDescriptor, @NotNull JetTypeMapper typeMapper) {
|
||||||
@@ -43,6 +41,24 @@ public class FieldInfo {
|
|||||||
if (!classDescriptor.getKind().isSingleton()) {
|
if (!classDescriptor.getKind().isSingleton()) {
|
||||||
throw new UnsupportedOperationException("Can't create singleton field for class: " + classDescriptor);
|
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);
|
Type type = typeMapper.mapType(classDescriptor);
|
||||||
return new FieldInfo(type, type, oldSingleton ? JvmAbi.DEPRECATED_INSTANCE_FIELD : JvmAbi.INSTANCE_FIELD, true);
|
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() {
|
private void generateFieldForSingleton() {
|
||||||
if (isEnumEntry(descriptor)) return;
|
if (isEnumEntry(descriptor)) return;
|
||||||
|
|
||||||
if (isObject(descriptor)) {
|
boolean isCompanionObject = isCompanionObject(descriptor);
|
||||||
StackValue.Field field = StackValue.singleton(descriptor, typeMapper);
|
if (isNonCompanionObject(descriptor) || isCompanionObject) {
|
||||||
v.newField(JvmDeclarationOriginKt.OtherOrigin(myClass), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
|
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)) {
|
if (isNonCompanionObject(descriptor)) {
|
||||||
StackValue.Field oldField = StackValue.oldSingleton(descriptor, typeMapper);
|
StackValue.Field oldField = StackValue.oldSingleton(descriptor, typeMapper);
|
||||||
@@ -845,18 +848,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
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>
|
// Invoke the object constructor but ignore the result because INSTANCE$ will be initialized in the first line of <init>
|
||||||
InstructionAdapter v = createOrGetClInitCodegen().v;
|
InstructionAdapter v = createOrGetClInitCodegen().v;
|
||||||
markLineNumberForSyntheticFunction(element, v);
|
markLineNumberForSyntheticFunction(element, v);
|
||||||
v.anew(classAsmType);
|
v.anew(classAsmType);
|
||||||
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V", false);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,7 +865,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
KtObjectDeclaration companionObject = CollectionsKt.firstOrNull(((KtClass) myClass).getCompanionObjects());
|
KtObjectDeclaration companionObject = CollectionsKt.firstOrNull(((KtClass) myClass).getCompanionObjects());
|
||||||
assert companionObject != null : "Companion object not found: " + myClass.getText();
|
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);
|
v.newField(JvmDeclarationOriginKt.OtherOrigin(companionObject), ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null);
|
||||||
|
|
||||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||||
@@ -927,8 +924,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
|
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
|
||||||
ExpressionCodegen codegen = createOrGetClInitCodegen();
|
ExpressionCodegen codegen = createOrGetClInitCodegen();
|
||||||
StackValue.singletonForCompanion(companionObject, typeMapper)
|
//TODO: uncomment when DEPRECATED INSTANCE is removed
|
||||||
.store(StackValue.singleton(companionObject, typeMapper), codegen.v, true);
|
//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) {
|
private void generatePrimaryConstructor(final DelegationFieldsInfo delegationFieldsInfo) {
|
||||||
@@ -998,7 +1000,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
getDelegationConstructorCall(bindingContext, constructorDescriptor));
|
getDelegationConstructorCall(bindingContext, constructorDescriptor));
|
||||||
|
|
||||||
if (isObject(descriptor)) {
|
if (isObject(descriptor)) {
|
||||||
StackValue.singleton(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
|
StackValue.singletonViaInstance(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
|
||||||
if (isNonCompanionObject(descriptor)) {
|
if (isNonCompanionObject(descriptor)) {
|
||||||
StackValue.oldSingleton(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
|
StackValue.oldSingleton(descriptor, typeMapper).store(StackValue.LOCAL_0, iv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -578,8 +578,8 @@ public abstract class StackValue {
|
|||||||
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper));
|
return field(FieldInfo.createForSingleton(classDescriptor, typeMapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Field singletonForCompanion(ClassDescriptor companionObject, JetTypeMapper typeMapper) {
|
public static Field singletonViaInstance(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
|
||||||
return field(FieldInfo.createForCompanionSingleton(companionObject, typeMapper));
|
return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Field oldSingleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
|
public static Field oldSingleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
|
||||||
|
|||||||
+3
@@ -10,6 +10,9 @@ public final class ClassObjectField {
|
|||||||
public ClassObjectField() { /* compiled code */ }
|
public ClassObjectField() { /* compiled code */ }
|
||||||
|
|
||||||
public static final class Companion {
|
public static final class Companion {
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
public static final ClassObjectField.Companion INSTANCE;
|
public static final ClassObjectField.Companion INSTANCE;
|
||||||
|
|
||||||
@org.jetbrains.annotations.Nullable
|
@org.jetbrains.annotations.Nullable
|
||||||
|
|||||||
+3
@@ -7,6 +7,9 @@ public interface TraitClassObjectField {
|
|||||||
@org.jetbrains.annotations.Nullable
|
@org.jetbrains.annotations.Nullable
|
||||||
public static final java.lang.String x = "";
|
public static final java.lang.String x = "";
|
||||||
private static final java.lang.String y = "";
|
private static final java.lang.String y = "";
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
public static final TraitClassObjectField.Companion INSTANCE;
|
public static final TraitClassObjectField.Companion INSTANCE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ public final class C {
|
|||||||
public C() { /* compiled code */ }
|
public C() { /* compiled code */ }
|
||||||
|
|
||||||
public static final class Companion {
|
public static final class Companion {
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
public static final C.Companion INSTANCE;
|
public static final C.Companion INSTANCE;
|
||||||
|
|
||||||
private Companion() { /* compiled code */ }
|
private Companion() { /* compiled code */ }
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
public class CompanionInitialization {
|
||||||
|
|
||||||
|
public static Object getCompanion() {
|
||||||
|
return ConcreteWithStatic.Companion;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
interface IStatic
|
||||||
|
|
||||||
|
open class Static(x: IStatic) {
|
||||||
|
fun doSth() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConcreteWithStatic : IStatic {
|
||||||
|
companion object : Static(ConcreteWithStatic())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
ConcreteWithStatic.doSth()
|
||||||
|
|
||||||
|
val companion: Any? = CompanionInitialization.getCompanion()
|
||||||
|
if (companion == null) return "fail 1"
|
||||||
|
if (companion != ConcreteWithStatic) return "fail 2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
public class CompanionInitialization {
|
||||||
|
|
||||||
|
public static Object getCompanion() {
|
||||||
|
return IStatic.Companion;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
open class Static(): IStatic {
|
||||||
|
val p = IStatic::class.java.getDeclaredField("const").get(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStatic {
|
||||||
|
fun doSth() {
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : Static() {
|
||||||
|
const val const = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
IStatic.doSth()
|
||||||
|
|
||||||
|
val companion: Any? = CompanionInitialization.getCompanion()
|
||||||
|
if (companion == null) return "fail 1"
|
||||||
|
if (companion != IStatic) return "fail 2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -11,8 +11,8 @@ class B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
One DEPRECATED is for INSTANCE$ temporarily
|
Two DEPRECATED are for INSTANCE$ and INSTANCE temporarily
|
||||||
3 others are for getCONST_VAL
|
3 others are for getCONST_VAL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// 4 DEPRECATED
|
// 5 DEPRECATED
|
||||||
+12
@@ -47,6 +47,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
|||||||
doTestWithJava(fileName);
|
doTestWithJava(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classCompanion")
|
||||||
|
public void testClassCompanion() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/classCompanion/");
|
||||||
|
doTestWithJava(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("classObjectAccessor")
|
@TestMetadata("classObjectAccessor")
|
||||||
public void testClassObjectAccessor() throws Exception {
|
public void testClassObjectAccessor() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/classObjectAccessor/");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/classObjectAccessor/");
|
||||||
@@ -65,6 +71,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
|||||||
doTestWithJava(fileName);
|
doTestWithJava(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("interfaceCompanion")
|
||||||
|
public void testInterfaceCompanion() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/interfaceCompanion/");
|
||||||
|
doTestWithJava(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("interfaceDefaultImpls")
|
@TestMetadata("interfaceDefaultImpls")
|
||||||
public void testInterfaceDefaultImpls() throws Exception {
|
public void testInterfaceDefaultImpls() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/interfaceDefaultImpls/");
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ fwBackingField.kt:38
|
|||||||
fwBackingField.kt:62
|
fwBackingField.kt:62
|
||||||
fwBackingField.kt:45
|
fwBackingField.kt:45
|
||||||
fwBackingField.kt:48
|
fwBackingField.kt:48
|
||||||
fwBackingField.kt:43
|
|
||||||
fwBackingField.kt:62
|
fwBackingField.kt:62
|
||||||
fwBackingField.kt:45
|
fwBackingField.kt:45
|
||||||
fwBackingField.kt:51
|
fwBackingField.kt:51
|
||||||
|
|||||||
Reference in New Issue
Block a user