Added shadow singleton value to resolve cycles during initialization

This commit is contained in:
Igor Chevdar
2018-03-23 15:45:42 +03:00
parent c1c363b81e
commit 6fa9ca8888
4 changed files with 75 additions and 16 deletions
@@ -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()
@@ -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
}
@@ -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 {
+9 -4
View File
@@ -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);