diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index c326d70c176..73b7ece16fa 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -452,9 +452,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, call(context.llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler) } - fun checkMainThread(exceptionHandler: ExceptionHandler) { + fun checkGlobalsAccessible(exceptionHandler: ExceptionHandler) { if (context.memoryModel == MemoryModel.STRICT) - call(context.llvm.checkMainThread, emptyList(), Lifetime.IRRELEVANT, exceptionHandler) + call(context.llvm.checkGlobalsAccessible, emptyList(), Lifetime.IRRELEVANT, exceptionHandler) } private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 894c2b97c2d..15317a1c59c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -521,7 +521,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val mutationCheck = importRtFunction("MutationCheck") val checkLifetimesConstraint = importRtFunction("CheckLifetimesConstraint") val freezeSubgraph = importRtFunction("FreezeSubgraph") - val checkMainThread = importRtFunction("CheckIsMainThread") + val checkGlobalsAccessible = importRtFunction("CheckGlobalsAccessible") val kRefSharedHolderInitLocal = importRtFunction("KRefSharedHolder_initLocal") val kRefSharedHolderInit = importRtFunction("KRefSharedHolder_init") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 8925ef0adef..3f102561879 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -38,8 +38,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.module internal enum class FieldStorageKind { - MAIN_THREAD, - SHARED, + GLOBAL, // In the old memory model these are only accessible from the "main" thread. + SHARED_FROZEN, THREAD_LOCAL } @@ -55,12 +55,12 @@ internal val IrField.storageKind: FieldStorageKind get() { val annotations = correspondingPropertySymbol?.owner?.annotations ?: annotations return when { annotations.hasAnnotation(KonanFqNames.threadLocal) -> FieldStorageKind.THREAD_LOCAL - !isFinal -> FieldStorageKind.MAIN_THREAD - annotations.hasAnnotation(KonanFqNames.sharedImmutable) -> FieldStorageKind.SHARED + !isFinal -> FieldStorageKind.GLOBAL + annotations.hasAnnotation(KonanFqNames.sharedImmutable) -> FieldStorageKind.SHARED_FROZEN // TODO: simplify, once IR types are fully there. (type.classifierOrNull?.owner as? IrAnnotationContainer) - ?.annotations?.hasAnnotation(KonanFqNames.frozen) == true -> FieldStorageKind.SHARED - else -> FieldStorageKind.MAIN_THREAD + ?.annotations?.hasAnnotation(KonanFqNames.frozen) == true -> FieldStorageKind.SHARED_FROZEN + else -> FieldStorageKind.GLOBAL } } @@ -71,9 +71,9 @@ internal fun IrClass.storageKind(context: Context): ObjectStorageKind = when { else -> ObjectStorageKind.SHARED } -val IrField.isMainOnlyNonPrimitive get() = when { +val IrField.isGlobalNonPrimitive get() = when { type.computePrimitiveBinaryTypeOrNull() != null -> false - else -> storageKind == FieldStorageKind.MAIN_THREAD + else -> storageKind == FieldStorageKind.GLOBAL } internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { @@ -423,7 +423,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map) } else { - if (context.config.threadsAreAllowed && value.symbol.owner.isMainOnlyNonPrimitive) { - functionGenerationContext.checkMainThread(currentCodeContext.exceptionHandler) + if (context.config.threadsAreAllowed && value.symbol.owner.isGlobalNonPrimitive) { + functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler) } val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress( functionGenerationContext @@ -1642,9 +1642,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map> initializingSingletons; + bool isMainThread = false; + #if COLLECT_STATISTIC #define CONTAINER_ALLOC_STAT(state, size, container) state->statistic.incAlloc(size, container); #define CONTAINER_DESTROY_STAT(state, container) \ @@ -2007,6 +2009,7 @@ MemoryState* initMemory() { #if USE_CYCLIC_GC cyclicInit(); #endif // USE_CYCLIC_GC + memoryState->isMainThread = true; } return memoryState; } @@ -3608,4 +3611,9 @@ void PerformFullGC() { garbageCollect(::memoryState, true); } +void CheckGlobalsAccessible() { + if (!::memoryState->isMainThread) + ThrowIncorrectDereferenceException(); +} + } // extern "C" diff --git a/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp b/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp index de52a26e227..5263d6df773 100644 --- a/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp +++ b/kotlin-native/runtime/src/main/cpp/CompilerExport.cpp @@ -41,4 +41,5 @@ void EnsureDeclarationsEmitted() { ensureUsed(CheckLifetimesConstraint); ensureUsed(FreezeSubgraph); ensureUsed(FreezeSubgraph); + ensureUsed(CheckGlobalsAccessible); } diff --git a/kotlin-native/runtime/src/main/cpp/Memory.h b/kotlin-native/runtime/src/main/cpp/Memory.h index 57fa71c511f..63c15e49a04 100644 --- a/kotlin-native/runtime/src/main/cpp/Memory.h +++ b/kotlin-native/runtime/src/main/cpp/Memory.h @@ -254,6 +254,8 @@ bool IsForeignRefAccessible(ObjHeader* object, ForeignRefContext context); // and there's nothing else keeping the object alive. void AdoptReferenceFromSharedVariable(ObjHeader* object); +void CheckGlobalsAccessible(); + #ifdef __cplusplus } #endif diff --git a/kotlin-native/runtime/src/main/cpp/Runtime.cpp b/kotlin-native/runtime/src/main/cpp/Runtime.cpp index da49b8973f7..c169a5d2388 100644 --- a/kotlin-native/runtime/src/main/cpp/Runtime.cpp +++ b/kotlin-native/runtime/src/main/cpp/Runtime.cpp @@ -69,7 +69,6 @@ KBoolean g_checkLeakedCleaners = KonanNeedDebugInfo; constexpr RuntimeState* kInvalidRuntime = nullptr; THREAD_LOCAL_VARIABLE RuntimeState* runtimeState = kInvalidRuntime; -THREAD_LOCAL_VARIABLE int isMainThread = 0; inline bool isValidRuntime() { return ::runtimeState != kInvalidRuntime; @@ -88,7 +87,6 @@ RuntimeState* initRuntime() { bool firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1; // Keep global variables in state as well. if (firstRuntime) { - isMainThread = 1; konan::consoleInit(); #if KONAN_OBJC_INTEROP Kotlin_ObjCExport_initialize(); @@ -151,11 +149,6 @@ void Kotlin_deinitRuntimeIfNeeded() { } } -void CheckIsMainThread() { - if (!isMainThread) - ThrowIncorrectDereferenceException(); -} - KInt Konan_Platform_canAccessUnaligned() { #if KONAN_NO_UNALIGNED_ACCESS return 0; diff --git a/kotlin-native/runtime/src/mm/cpp/Stubs.cpp b/kotlin-native/runtime/src/mm/cpp/Stubs.cpp index 9f13af5ede2..e94f82d7b94 100644 --- a/kotlin-native/runtime/src/mm/cpp/Stubs.cpp +++ b/kotlin-native/runtime/src/mm/cpp/Stubs.cpp @@ -234,4 +234,8 @@ void AdoptReferenceFromSharedVariable(ObjHeader* object) { RuntimeCheck(false, "Unimplemented"); } +void CheckGlobalsAccessible() { + // Globals are always accessible. +} + } // extern "C"