-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move static helpers to managed #108167
Merged
davidwrighton
merged 30 commits into
dotnet:main
from
davidwrighton:thread_static_helpers
Oct 30, 2024
Merged
Move static helpers to managed #108167
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
0fbff89
Part1 Of implement InitClass helpers
davidwrighton 7d6a205
Merge branch 'main' of github.com:dotnet/runtime into initclass_managed
davidwrighton 51c69d5
It builds and works
davidwrighton d1fccda
Revert unnecessary changes
davidwrighton 08fe963
Ooops we did need to keep the refactoring that put the debug only Met…
davidwrighton 12c9de2
Merge branch 'initclass_managed' into thread_static_helpers
davidwrighton 2c0cb78
Initial work which does static helpers
davidwrighton 0fb7f4a
Fix build break
davidwrighton 0cb8f78
Thread statics basically implemented...
davidwrighton aacdb2a
Merge branch 'main' of https://github.com/dotnet/runtime into thread_…
davidwrighton 00b6df4
Finish merging in changes from main, and fix up some oopses... and it…
davidwrighton 34ebcaf
Restructure static access so that we don't need a helper call to acce…
davidwrighton f740618
Tweaks for failures noted in PR testing
davidwrighton e2498bb
Fix comments on Unix builds for Arm64 and RISCV
davidwrighton 0d03a51
Tail call the right helper
davidwrighton 367e95b
Force volatile loads for the statics ref, to fix the arm64 statics ra…
davidwrighton ccfafe1
Get rid of extra null check
davidwrighton 5ff66b4
Fix error around fcall class ordering
davidwrighton 0586455
Attempt to fix Unix assembly code, and fix fcall registration
davidwrighton 0f6290a
Properly thread through using the "optimized" helper 2 for thread sta…
davidwrighton 8f5448f
Remove unnecessary changes from the PR
davidwrighton 0d6edfc
Fixing naming
davidwrighton 46fc106
Change GetDynamicStaticsInfo and GetThreadStaticsInfo to be instance …
davidwrighton a08dc02
Merge branch 'thread_static_helpers' of https://github.com/davidwrigh…
davidwrighton 8fb5f22
More code review driven fixes
davidwrighton 4c92dc1
Merge branch 'main' of https://github.com/dotnet/runtime into thread_…
davidwrighton f9d19fa
Fix build issues
davidwrighton 2a89bce
More feedback
davidwrighton 47fc1e5
Address more feedback
davidwrighton 67bc96a
More updates
davidwrighton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/coreclr/System.Private.CoreLib/src/System/Runtime/BypassReadyToRunAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
namespace System.Runtime | ||
{ | ||
// Use to disable ReadyToRun compilation for a method. | ||
internal sealed class BypassReadyToRunAttribute : Attribute | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
278 changes: 278 additions & 0 deletions
278
src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace System.Runtime.CompilerServices | ||
{ | ||
[StackTraceHidden] | ||
[DebuggerStepThrough] | ||
internal static unsafe partial class StaticsHelpers | ||
{ | ||
[LibraryImport(RuntimeHelpers.QCall)] | ||
private static partial void GetThreadStaticsByIndex(ByteRefOnStack result, int index, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); | ||
|
||
[LibraryImport(RuntimeHelpers.QCall)] | ||
private static partial void GetThreadStaticsByMethodTable(ByteRefOnStack result, MethodTable* pMT, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); | ||
|
||
[Intrinsic] | ||
private static ref byte VolatileReadAsByref(ref IntPtr address) => ref VolatileReadAsByref(ref address); | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static ref byte GetNonGCStaticBaseSlow(MethodTable* mt) | ||
{ | ||
InitHelpers.InitClassSlow(mt); | ||
return ref MethodTable.MaskStaticsPointer(ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pNonGCStatics)); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetNonGCStaticBase(MethodTable* mt) | ||
{ | ||
ref byte nonGCStaticBase = ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pNonGCStatics); | ||
|
||
if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) | ||
return ref GetNonGCStaticBaseSlow(mt); | ||
else | ||
return ref nonGCStaticBase; | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) | ||
{ | ||
ref byte nonGCStaticBase = ref VolatileReadAsByref(ref dynamicStaticsInfo->_pNonGCStatics); | ||
|
||
if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) | ||
return ref GetNonGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); | ||
else | ||
return ref nonGCStaticBase; | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static ref byte GetGCStaticBaseSlow(MethodTable* mt) | ||
{ | ||
InitHelpers.InitClassSlow(mt); | ||
return ref MethodTable.MaskStaticsPointer(ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pGCStatics)); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetGCStaticBase(MethodTable* mt) | ||
{ | ||
ref byte gcStaticBase = ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pGCStatics); | ||
|
||
if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) | ||
return ref GetGCStaticBaseSlow(mt); | ||
else | ||
return ref gcStaticBase; | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) | ||
{ | ||
ref byte gcStaticBase = ref VolatileReadAsByref(ref dynamicStaticsInfo->_pGCStatics); | ||
|
||
if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) | ||
return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); | ||
else | ||
return ref gcStaticBase; | ||
} | ||
|
||
// Thread static helpers | ||
|
||
[StructLayout(LayoutKind.Sequential)] | ||
private sealed class RawData | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have RawData and |
||
{ | ||
internal byte _data; | ||
} | ||
|
||
/// <summary> | ||
/// Return beginning of the object as a reference to byte | ||
/// </summary> | ||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private static ref byte GetObjectAsRefByte(object obj) | ||
{ | ||
return ref Unsafe.Subtract(ref Unsafe.As<RawData>(obj)._data, sizeof(MethodTable*)); | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential)] | ||
internal struct ThreadLocalData | ||
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
internal const int NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY = 2; | ||
internal int _cNonCollectibleTlsData; // Size of offset into the non-collectible TLS array which is valid, NOTE: this is relative to the start of the nonCollectibleTlsArrayData object, not the start of the data in the array | ||
internal int _cCollectibleTlsData; // Size of offset into the TLS array which is valid | ||
private IntPtr _nonCollectibleTlsArrayData_private; // This is object[], but using object[] directly causes the structure to be laid out via auto-layout, which is not what we want. | ||
internal IntPtr* _collectibleTlsArrayData; // Points at the Thread local array data. | ||
|
||
internal object[] NonCollectibleTlsArrayData | ||
{ | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
get | ||
{ | ||
return Unsafe.As<IntPtr, object[]>(ref _nonCollectibleTlsArrayData_private); | ||
} | ||
} | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private static int GetIndexOffset(int index) | ||
{ | ||
return index & 0xFFFFFF; | ||
} | ||
|
||
private const int NonCollectibleTLSIndexType = 0; | ||
private const int DirectOnThreadLocalDataTLSIndexType = 2; | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private static int GetIndexType(int index) | ||
{ | ||
return index >> 24; | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private static bool IsIndexAllocated(int index) | ||
{ | ||
return index != -1; | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static ref byte GetNonGCThreadStaticsByIndexSlow(int index) | ||
{ | ||
ByteRef result = default; | ||
GetThreadStaticsByIndex(ByteRefOnStack.Create(ref result), index, false); | ||
return ref result.Get(); | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static ref byte GetGCThreadStaticsByIndexSlow(int index) | ||
{ | ||
ByteRef result = default; | ||
GetThreadStaticsByIndex(ByteRefOnStack.Create(ref result), index, true); | ||
return ref result.Get(); | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static ref byte GetNonGCThreadStaticBaseSlow(MethodTable* mt) | ||
{ | ||
ByteRef result = default; | ||
GetThreadStaticsByMethodTable(ByteRefOnStack.Create(ref result), mt, false); | ||
return ref result.Get(); | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private static ref byte GetGCThreadStaticBaseSlow(MethodTable* mt) | ||
{ | ||
ByteRef result = default; | ||
GetThreadStaticsByMethodTable(ByteRefOnStack.Create(ref result), mt, true); | ||
return ref result.Get(); | ||
} | ||
|
||
[DebuggerHidden] | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatics) | ||
{ | ||
ThreadLocalData *t_ThreadStatics = System.Threading.Thread.GetThreadStaticsBase(); | ||
int indexOffset = GetIndexOffset(index); | ||
if (GetIndexType(index) == NonCollectibleTLSIndexType) | ||
{ | ||
if (t_ThreadStatics->_cNonCollectibleTlsData > GetIndexOffset(index)) | ||
{ | ||
object? threadStaticObjectNonCollectible = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->NonCollectibleTlsArrayData), indexOffset - ThreadLocalData.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY); | ||
if (threadStaticObjectNonCollectible != null) | ||
{ | ||
return ref GetObjectAsRefByte(threadStaticObjectNonCollectible); | ||
} | ||
} | ||
} | ||
else if (GetIndexType(index) == DirectOnThreadLocalDataTLSIndexType) | ||
{ | ||
return ref Unsafe.Add(ref Unsafe.AsRef<byte>(t_ThreadStatics), indexOffset); | ||
} | ||
else | ||
{ | ||
int cCollectibleTlsData = t_ThreadStatics->_cNonCollectibleTlsData; | ||
if (cCollectibleTlsData > indexOffset) | ||
{ | ||
IntPtr* pCollectibleTlsArrayData = t_ThreadStatics->_collectibleTlsArrayData; | ||
|
||
pCollectibleTlsArrayData += indexOffset; | ||
IntPtr objHandle = *pCollectibleTlsArrayData; | ||
if (objHandle != IntPtr.Zero) | ||
{ | ||
object? threadStaticObject = GCHandle.InternalGet(objHandle); | ||
if (threadStaticObject != null) | ||
{ | ||
return ref GetObjectAsRefByte(threadStaticObject); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (gcStatics) | ||
return ref GetGCThreadStaticsByIndexSlow(index); | ||
else | ||
return ref GetNonGCThreadStaticsByIndexSlow(index); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetNonGCThreadStaticBase(MethodTable* mt) | ||
{ | ||
int index = mt->AuxiliaryData->GetThreadStaticsInfo()._nonGCTlsIndex; | ||
if (IsIndexAllocated(index)) | ||
return ref GetThreadLocalStaticBaseByIndex(index, false); | ||
else | ||
return ref GetNonGCThreadStaticBaseSlow(mt); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetGCThreadStaticBase(MethodTable* mt) | ||
{ | ||
int index = mt->AuxiliaryData->GetThreadStaticsInfo()._gcTlsIndex; | ||
if (IsIndexAllocated(index)) | ||
return ref GetThreadLocalStaticBaseByIndex(index, true); | ||
else | ||
return ref GetGCThreadStaticBaseSlow(mt); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetDynamicNonGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) | ||
{ | ||
int index = threadStaticsInfo->_nonGCTlsIndex; | ||
if (IsIndexAllocated(index)) | ||
return ref GetThreadLocalStaticBaseByIndex(index, false); | ||
else | ||
return ref GetNonGCThreadStaticBaseSlow(threadStaticsInfo->_genericStatics._dynamicStatics._methodTable); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetDynamicGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) | ||
{ | ||
int index = threadStaticsInfo->_gcTlsIndex; | ||
if (IsIndexAllocated(index)) | ||
return ref GetThreadLocalStaticBaseByIndex(index, true); | ||
else | ||
return ref GetGCThreadStaticBaseSlow(threadStaticsInfo->_genericStatics._dynamicStatics._methodTable); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetOptimizedNonGCThreadStaticBase(int index) | ||
{ | ||
return ref GetThreadLocalStaticBaseByIndex(index, false); | ||
} | ||
|
||
[DebuggerHidden] | ||
private static ref byte GetOptimizedGCThreadStaticBase(int index) | ||
{ | ||
return ref GetThreadLocalStaticBaseByIndex(index, true); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: This can be private method in StaticsHelpers. It is only used in that type.