| File: Internal\Runtime\ThreadStatics.cs | Web Access |
| Project: src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\System.Private.CoreLib.csproj (System.Private.CoreLib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.Runtime.CompilerHelpers; using Debug = System.Diagnostics.Debug; namespace Internal.Runtime { /// <summary> /// This class is used by ReadyToRun helpers to get access to thread static fields of a type /// and to allocate required TLS memory. /// </summary> internal static class ThreadStatics { [ThreadStatic] private static object t_inlinedThreadStaticBase; /// <summary> /// This method is called from a ReadyToRun helper to get base address of thread /// static storage for the given type. /// </summary> internal static unsafe object GetThreadStaticBaseForType(TypeManagerSlot* pModuleData, int typeTlsIndex) { if (typeTlsIndex < 0) return t_inlinedThreadStaticBase; return GetUninlinedThreadStaticBaseForType(pModuleData, typeTlsIndex); } internal static unsafe object GetInlinedThreadStaticBaseSlow(ref object? threadStorage) { Debug.Assert(threadStorage == null); // Allocate an object that will represent a memory block for all thread static fields TypeManagerHandle typeManager = MethodTable.Of<object>()->TypeManager; object threadStaticBase = AllocateThreadStaticStorageForType(typeManager, 0); // register the storage location with the thread for GC reporting. RuntimeImports.RhRegisterInlinedThreadStaticRoot(ref threadStorage, typeManager); // assign the storage block to the storage variable and return threadStorage = threadStaticBase; t_inlinedThreadStaticBase = threadStaticBase; return threadStaticBase; } internal static unsafe object GetUninlinedThreadStaticBaseForType(TypeManagerSlot* pModuleData, int typeTlsIndex) { Debug.Assert(typeTlsIndex >= 0); int moduleIndex = pModuleData->ModuleIndex; Debug.Assert(moduleIndex >= 0); object[][] perThreadStorage = RuntimeImports.RhGetThreadStaticStorage(); if (perThreadStorage != null && perThreadStorage.Length > moduleIndex) { object[] perModuleStorage = perThreadStorage[moduleIndex]; if (perModuleStorage != null && perModuleStorage.Length > typeTlsIndex) { object threadStaticBase = perModuleStorage[typeTlsIndex]; if (threadStaticBase != null) { return threadStaticBase; } } } return GetUninlinedThreadStaticBaseForTypeSlow(pModuleData, typeTlsIndex); } [MethodImpl(MethodImplOptions.NoInlining)] internal static unsafe object GetUninlinedThreadStaticBaseForTypeSlow(TypeManagerSlot* pModuleData, int typeTlsIndex) { Debug.Assert(typeTlsIndex >= 0); int moduleIndex = pModuleData->ModuleIndex; Debug.Assert(moduleIndex >= 0); // Get the array that holds thread statics for the current thread, if none present // allocate a new one big enough to hold the current module data ref object[][] threadStorage = ref RuntimeImports.RhGetThreadStaticStorage(); if (threadStorage == null) { threadStorage = new object[moduleIndex + 1][]; } else if (moduleIndex >= threadStorage.Length) { Array.Resize(ref threadStorage, moduleIndex + 1); } // Get the array that holds thread static memory blocks for each type in the given module ref object[] moduleStorage = ref threadStorage[moduleIndex]; if (moduleStorage == null) { moduleStorage = new object[typeTlsIndex + 1]; } else if (typeTlsIndex >= moduleStorage.Length) { // typeTlsIndex could have a big range, we do not want to reallocate every time we see +1 index // so we double up from previous size to guarantee a worst case linear complexity int newSize = Math.Max(typeTlsIndex + 1, moduleStorage.Length * 2); Array.Resize(ref moduleStorage, newSize); } // Allocate an object that will represent a memory block for all thread static fields of the type object threadStaticBase = AllocateThreadStaticStorageForType(pModuleData->TypeManager, typeTlsIndex); Debug.Assert(moduleStorage[typeTlsIndex] == null); moduleStorage[typeTlsIndex] = threadStaticBase; return threadStaticBase; } /// <summary> /// This method allocates an object that represents a memory block for all thread static fields of the type /// that corresponds to the specified TLS index. /// </summary> private static unsafe object AllocateThreadStaticStorageForType(TypeManagerHandle typeManager, int typeTlsIndex) { int length; IntPtr* threadStaticRegion; // Get a pointer to the beginning of the module's Thread Static section. Then get a pointer // to the MethodTable that represents a memory map for thread statics storage. threadStaticRegion = (IntPtr*)RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.ThreadStaticRegion, out length); IntPtr gcDesc; if (typeTlsIndex < (length / IntPtr.Size)) { gcDesc = threadStaticRegion[typeTlsIndex]; } else { gcDesc = Internal.Runtime.Augments.RuntimeAugments.TypeLoaderCallbacks.GetThreadStaticGCDescForDynamicType(typeManager, typeTlsIndex); } return RuntimeImports.RhNewObject((MethodTable*)gcDesc); } } }