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"
|
||||
}
|
||||
|
||||
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
|
||||
get() = !this.isAbstract() && !this.isExternalObjCClass()
|
||||
|
||||
|
||||
+41
-10
@@ -63,6 +63,24 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
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 {
|
||||
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
|
||||
context.ir.symbols.objCPointerHolder.owner
|
||||
@@ -575,28 +593,41 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
|
||||
return codegen.theUnitInstanceRef.llvm
|
||||
}
|
||||
|
||||
val args = mutableListOf<LLVMValueRef>()
|
||||
val objectPtr = codegen.getObjectInstanceStorage(descriptor)
|
||||
args += objectPtr
|
||||
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 objectVal = loadSlot(objectPtr, false)
|
||||
val condition = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
|
||||
condBr(condition, bbExit, bbInit)
|
||||
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
|
||||
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 ctor = codegen.llvmFunction(defaultConstructor)
|
||||
val args = listOf(objectPtr, typeInfo, ctor)
|
||||
args += codegen.typeInfoForAllocation(descriptor)
|
||||
args += codegen.llvmFunction(defaultConstructor)
|
||||
val initFunction = if (shared) context.llvm.initSharedInstanceFunction else context.llvm.initInstanceFunction
|
||||
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
|
||||
val bbInitResult = currentBlock
|
||||
br(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
|
||||
}
|
||||
|
||||
+15
-2
@@ -74,7 +74,7 @@ internal class ClassLlvmDeclarations(
|
||||
val singletonDeclarations: SingletonLlvmDeclarations?,
|
||||
val objCDeclarations: KotlinObjCClassLlvmDeclarations?)
|
||||
|
||||
internal class SingletonLlvmDeclarations(val instanceFieldRef: LLVMValueRef)
|
||||
internal class SingletonLlvmDeclarations(val instanceFieldRef: LLVMValueRef, val instanceShadowFieldRef: LLVMValueRef?)
|
||||
|
||||
internal class KotlinObjCClassLlvmDeclarations(
|
||||
val classPointerGlobal: StaticData.Global,
|
||||
@@ -319,7 +319,20 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
|
||||
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 {
|
||||
|
||||
@@ -1104,12 +1104,14 @@ OBJ_GETTER(InitInstance,
|
||||
}
|
||||
|
||||
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
|
||||
return InitInstance(location, type_info, ctor);
|
||||
#else
|
||||
ObjHeader* value = *localLocation;
|
||||
if (value != nullptr) RETURN_OBJ(value);
|
||||
|
||||
ObjHeader* initializing = reinterpret_cast<ObjHeader*>(1);
|
||||
ObjHeader* value;
|
||||
|
||||
// Spin lock.
|
||||
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);
|
||||
MEMORY_LOG("Calling UpdateRef from InitInstance\n")
|
||||
UpdateRef(location, object);
|
||||
__sync_synchronize();
|
||||
UpdateRef(localLocation, object);
|
||||
#if KONAN_NO_EXCEPTIONS
|
||||
ctor(object);
|
||||
// TODO: uncomment as soon as cycles are correctly handled during freezing.
|
||||
//if (!object->container()->frozen())
|
||||
//ThrowFreezingException();
|
||||
UpdateRef(location, object);
|
||||
__sync_synchronize();
|
||||
return object;
|
||||
#else
|
||||
try {
|
||||
ctor(object);
|
||||
//if (!object->container()->frozen())
|
||||
//ThrowFreezingException();
|
||||
UpdateRef(location, object);
|
||||
__sync_synchronize();
|
||||
return object;
|
||||
} catch (...) {
|
||||
UpdateRef(OBJ_RESULT, nullptr);
|
||||
|
||||
Reference in New Issue
Block a user