Added shadow singleton value to resolve cycles during initialization
This commit is contained in:
+10
@@ -281,6 +281,16 @@ internal val ClassDescriptor.objectInstanceFieldSymbolName: String
|
|||||||
return "kobjref:$fqNameSafe"
|
return "kobjref:$fqNameSafe"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String
|
||||||
|
get() {
|
||||||
|
assert (this.isExported())
|
||||||
|
assert (this.kind.isSingleton)
|
||||||
|
assert (!this.isUnit())
|
||||||
|
assert (this.symbol.objectIsShared)
|
||||||
|
|
||||||
|
return "kshadowobjref:$fqNameSafe"
|
||||||
|
}
|
||||||
|
|
||||||
internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean
|
internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean
|
||||||
get() = !this.isAbstract() && !this.isExternalObjCClass()
|
get() = !this.isAbstract() && !this.isExternalObjCClass()
|
||||||
|
|
||||||
|
|||||||
+41
-10
@@ -63,6 +63,24 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
return llvmGlobal
|
return llvmGlobal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getObjectInstanceShadowStorage(descriptor: ClassDescriptor): LLVMValueRef {
|
||||||
|
assert (!descriptor.isUnit())
|
||||||
|
assert (descriptor.symbol.objectIsShared)
|
||||||
|
val llvmGlobal = if (!isExternal(descriptor)) {
|
||||||
|
context.llvmDeclarations.forSingleton(descriptor).instanceShadowFieldRef!!
|
||||||
|
} else {
|
||||||
|
val llvmType = getLLVMType(descriptor.defaultType)
|
||||||
|
importGlobal(
|
||||||
|
descriptor.objectInstanceShadowFieldSymbolName,
|
||||||
|
llvmType,
|
||||||
|
origin = descriptor.llvmSymbolOrigin,
|
||||||
|
threadLocal = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
context.llvm.objects += llvmGlobal
|
||||||
|
return llvmGlobal
|
||||||
|
}
|
||||||
|
|
||||||
fun typeInfoForAllocation(constructedClass: ClassDescriptor): LLVMValueRef {
|
fun typeInfoForAllocation(constructedClass: ClassDescriptor): LLVMValueRef {
|
||||||
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
|
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
|
||||||
context.ir.symbols.objCPointerHolder.owner
|
context.ir.symbols.objCPointerHolder.owner
|
||||||
@@ -575,28 +593,41 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
|||||||
return codegen.theUnitInstanceRef.llvm
|
return codegen.theUnitInstanceRef.llvm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val args = mutableListOf<LLVMValueRef>()
|
||||||
val objectPtr = codegen.getObjectInstanceStorage(descriptor)
|
val objectPtr = codegen.getObjectInstanceStorage(descriptor)
|
||||||
|
args += objectPtr
|
||||||
val bbCurrent = currentBlock
|
val bbCurrent = currentBlock
|
||||||
val bbInit = basicBlock("label_init", locationInfo)
|
val bbFirstCheck = basicBlock(if (shared) "label_check_shadow" else "label_init", locationInfo)
|
||||||
val bbExit = basicBlock("label_continue", locationInfo)
|
val bbExit = basicBlock("label_continue", locationInfo)
|
||||||
val objectVal = loadSlot(objectPtr, false)
|
val objectVal = loadSlot(objectPtr, false)
|
||||||
val condition = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
|
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
|
||||||
condBr(condition, bbExit, bbInit)
|
condBr(objectInitialized, bbExit, bbFirstCheck)
|
||||||
|
|
||||||
|
positionAtEnd(bbExit)
|
||||||
|
val valuePhi = phi(codegen.getLLVMType(descriptor.defaultType))
|
||||||
|
|
||||||
|
positionAtEnd(bbFirstCheck)
|
||||||
|
if (shared) {
|
||||||
|
val shadowObjectPtr = codegen.getObjectInstanceShadowStorage(descriptor)
|
||||||
|
args += shadowObjectPtr
|
||||||
|
val shadowObjectVal = loadSlot(shadowObjectPtr, false)
|
||||||
|
val shadowNotNull = icmpNe(bitcast(int8TypePtr, shadowObjectVal), kNullInt8Ptr)
|
||||||
|
val bbInit = basicBlock("label_init", locationInfo)
|
||||||
|
condBr(shadowNotNull, bbExit, bbInit)
|
||||||
|
addPhiIncoming(valuePhi, bbFirstCheck to shadowObjectVal)
|
||||||
|
positionAtEnd(bbInit)
|
||||||
|
}
|
||||||
|
|
||||||
positionAtEnd(bbInit)
|
|
||||||
val typeInfo = codegen.typeInfoForAllocation(descriptor)
|
|
||||||
val defaultConstructor = descriptor.constructors.first { it.valueParameters.size == 0 }
|
val defaultConstructor = descriptor.constructors.first { it.valueParameters.size == 0 }
|
||||||
val ctor = codegen.llvmFunction(defaultConstructor)
|
args += codegen.typeInfoForAllocation(descriptor)
|
||||||
val args = listOf(objectPtr, typeInfo, ctor)
|
args += codegen.llvmFunction(defaultConstructor)
|
||||||
val initFunction = if (shared) context.llvm.initSharedInstanceFunction else context.llvm.initInstanceFunction
|
val initFunction = if (shared) context.llvm.initSharedInstanceFunction else context.llvm.initInstanceFunction
|
||||||
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
||||||
val bbInitResult = currentBlock
|
val bbInitResult = currentBlock
|
||||||
br(bbExit)
|
br(bbExit)
|
||||||
|
|
||||||
positionAtEnd(bbExit)
|
positionAtEnd(bbExit)
|
||||||
val valuePhi = phi(codegen.getLLVMType(descriptor.defaultType))
|
addPhiIncoming(valuePhi, bbCurrent to objectVal, bbInitResult to newValue)
|
||||||
addPhiIncoming(valuePhi,
|
|
||||||
bbCurrent to objectVal, bbInitResult to newValue)
|
|
||||||
|
|
||||||
return valuePhi
|
return valuePhi
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-2
@@ -74,7 +74,7 @@ internal class ClassLlvmDeclarations(
|
|||||||
val singletonDeclarations: SingletonLlvmDeclarations?,
|
val singletonDeclarations: SingletonLlvmDeclarations?,
|
||||||
val objCDeclarations: KotlinObjCClassLlvmDeclarations?)
|
val objCDeclarations: KotlinObjCClassLlvmDeclarations?)
|
||||||
|
|
||||||
internal class SingletonLlvmDeclarations(val instanceFieldRef: LLVMValueRef)
|
internal class SingletonLlvmDeclarations(val instanceFieldRef: LLVMValueRef, val instanceShadowFieldRef: LLVMValueRef?)
|
||||||
|
|
||||||
internal class KotlinObjCClassLlvmDeclarations(
|
internal class KotlinObjCClassLlvmDeclarations(
|
||||||
val classPointerGlobal: StaticData.Global,
|
val classPointerGlobal: StaticData.Global,
|
||||||
@@ -319,7 +319,20 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
|
|
||||||
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
|
LLVMSetInitializer(instanceFieldRef, kNullObjHeaderPtr)
|
||||||
|
|
||||||
return SingletonLlvmDeclarations(instanceFieldRef)
|
val instanceShadowFieldRef =
|
||||||
|
if (threadLocal) null
|
||||||
|
else {
|
||||||
|
val shadowSymbolName = if (isExported) {
|
||||||
|
descriptor.objectInstanceShadowFieldSymbolName
|
||||||
|
} else {
|
||||||
|
"kshadowobjref:" + qualifyInternalName(descriptor)
|
||||||
|
}
|
||||||
|
addGlobal(shadowSymbolName, getLLVMType(descriptor.defaultType), isExported = isExported, threadLocal = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceShadowFieldRef?.let { LLVMSetInitializer(it, kNullObjHeaderPtr) }
|
||||||
|
|
||||||
|
return SingletonLlvmDeclarations(instanceFieldRef, instanceShadowFieldRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKotlinObjCClassDeclarations(descriptor: ClassDescriptor): KotlinObjCClassLlvmDeclarations {
|
private fun createKotlinObjCClassDeclarations(descriptor: ClassDescriptor): KotlinObjCClassLlvmDeclarations {
|
||||||
|
|||||||
@@ -1104,12 +1104,14 @@ OBJ_GETTER(InitInstance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(InitSharedInstance,
|
OBJ_GETTER(InitSharedInstance,
|
||||||
ObjHeader** location, const TypeInfo* type_info, void (*ctor)(ObjHeader*)) {
|
ObjHeader** location, ObjHeader** localLocation, const TypeInfo* type_info, void (*ctor)(ObjHeader*)) {
|
||||||
#if KONAN_NO_THREADS
|
#if KONAN_NO_THREADS
|
||||||
return InitInstance(location, type_info, ctor);
|
return InitInstance(location, type_info, ctor);
|
||||||
#else
|
#else
|
||||||
|
ObjHeader* value = *localLocation;
|
||||||
|
if (value != nullptr) RETURN_OBJ(value);
|
||||||
|
|
||||||
ObjHeader* initializing = reinterpret_cast<ObjHeader*>(1);
|
ObjHeader* initializing = reinterpret_cast<ObjHeader*>(1);
|
||||||
ObjHeader* value;
|
|
||||||
|
|
||||||
// Spin lock.
|
// Spin lock.
|
||||||
while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing);
|
while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing);
|
||||||
@@ -1120,19 +1122,22 @@ OBJ_GETTER(InitSharedInstance,
|
|||||||
|
|
||||||
ObjHeader* object = AllocInstance(type_info, OBJ_RESULT);
|
ObjHeader* object = AllocInstance(type_info, OBJ_RESULT);
|
||||||
MEMORY_LOG("Calling UpdateRef from InitInstance\n")
|
MEMORY_LOG("Calling UpdateRef from InitInstance\n")
|
||||||
UpdateRef(location, object);
|
UpdateRef(localLocation, object);
|
||||||
__sync_synchronize();
|
|
||||||
#if KONAN_NO_EXCEPTIONS
|
#if KONAN_NO_EXCEPTIONS
|
||||||
ctor(object);
|
ctor(object);
|
||||||
// TODO: uncomment as soon as cycles are correctly handled during freezing.
|
// TODO: uncomment as soon as cycles are correctly handled during freezing.
|
||||||
//if (!object->container()->frozen())
|
//if (!object->container()->frozen())
|
||||||
//ThrowFreezingException();
|
//ThrowFreezingException();
|
||||||
|
UpdateRef(location, object);
|
||||||
|
__sync_synchronize();
|
||||||
return object;
|
return object;
|
||||||
#else
|
#else
|
||||||
try {
|
try {
|
||||||
ctor(object);
|
ctor(object);
|
||||||
//if (!object->container()->frozen())
|
//if (!object->container()->frozen())
|
||||||
//ThrowFreezingException();
|
//ThrowFreezingException();
|
||||||
|
UpdateRef(location, object);
|
||||||
|
__sync_synchronize();
|
||||||
return object;
|
return object;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
UpdateRef(OBJ_RESULT, nullptr);
|
UpdateRef(OBJ_RESULT, nullptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user