diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt index 0840084bf3c..3aabc6dbebe 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt @@ -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() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index ea87da39212..b784a1c8890 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -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() 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 } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt index a1383b9f944..595b93e5128 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt @@ -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 { diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index ca05e29cc88..c948a792f61 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -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(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);