1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 17:44:48 +09:00

Make normal statics simpler (#99183)

This change makes access to statics much simpler to document and also removes some performance penalties that we've had for a long time due to the old model. Most statics access should be equivalent or faster.

This change converts static variables from a model where statics are associated with the module that defined the metadata of the static to a model where each individual type allocates its statics independently. In addition, it moves the flags that indicate whether or not a type is initialized, and whether or not its statics have been allocated to the `MethodTable` structures instead of storing them in a `DomainLocalModule` as was done before.

# Particularly notable changes
- All statics are now considered "dynamic" statics.
- Statics for collectible assemblies now have an identical path for lookup of the static variable addresses as compared to statics for non-collectible assemblies. It is now reasonable for the process of reading static variables to be inlined into shared generic code, although this PR does not attempt to do so.
- Lifetime management for collectible non-thread local statics is managed via a combination of a `LOADERHANDLE` to keep the static alive, and a new handle type called a `HNDTYPE_WEAK_INTERIOR_POINTER` which will keep the pointers to managed objects in the `MethodTable` structures up to date with the latest addresses of the static variables.
- Each individual type in thread statics has a unique object holding the statics for the type. This means that each type has a separate object[](for gc statics), and/or double[](for non-gc statics) per thread for TLS statics. This isn't necessarily ideal for non-collectible types, but its not terrible either.
- Thread statics for collectible types are reported directly to the GC instead of being handled via a GCHandle. While needed to avoid complex lifetime rules for collectible types, this may not be ideal for non-collectable types.
- Since the `DomainLocalModule` no longer exists, the `ISOSDacInterface` has been augmented with a new api called `ISOSDacInterface14` which adds the ability to query for the static base/initialization status of an individual type directly.
- Significant changes for generated code include
  - All the helpers are renamed
  - The statics of generics which have not yet been initialized can now be referenced using a single constant pointer + a helper call instead of needing a pair of pointers. In practice, this was a rare condition in perf-critical code due to the presence of tiered compilation, so this is not a significant change to optimized code.
  - The pre-initialization of statics can now occur for types which have non-primitive valuetype statics as long as the type does not have a class constructor.
  - Thread static non-gc statics are now returned as byrefs. (It turns out that for collectible assemblies, there is currently a small GC hole if a function returns the address of a non-gc threadstatic. CoreCLR at this time does not attempt to keep the collectible assembly alive if that is the only live pointer to the collectible static in the system)

With this change, the pointers to normal static data are located at a fixed offset from the start of the `MethodTableAuxiliaryData`, and indices for Thread Static variables are stored also stored in such a fixed offset. Concepts such as the `DomainLocalModule` , `ThreadLocalModule`, `ModuleId` and `ModuleIndex` no longer exist.

# Lifetime management for collectible statics
- For normal collectible statics, each type will allocate a separate object[] for the GC statics and a double[] for the non-GC statics. A pointer to the data of these arrays will be stored in the `DynamicStaticsInfo` structure, and when relocation occurs, if the collectible types managed `LoaderAllocator` is still alive, the static field address will be relocated if the object moves. This is done by means of the new Weak Interior Pointer GC handle type. 
- For collectible thread-local statics, the lifetime management is substantially more complicated due the issue that it is possible for either a thread or a collectible type to be collected first. Thus the collection algorithm is as follows.
  - The system shall maintain a global mapping of TLS indices to MethodTable structures
  - When a native `LoaderAllocator` is being cleaned up, before the WeakTrackResurrection GCHandle that points at the the managed `LoaderAllocator` object is destroyed, the mapping from TLS indices to collectible `LoaderAllocator` structures shall be cleared of all relevant entries (and the current GC index shall be stored in the TLS to MethodTable mapping)
  - When a GC promotion or collection scan occurs, for every TLS index which was freed to point at a GC index the relevant entry in the TLS table shall be set to NULL in preparation for that entry in the table being reused in the future. In addition, if the TLS index refers to a `MethodTable` which is in a collectible assembly, and the associated `LoaderAllocator` has been freed, then set the relevant entry to NULL.
  - When allocating new entries from the TLS mapping table for new collectible thread local structures, do not re-use an entry in the table until at least 2 GCs have occurred. This is to allow every thread to have NULL'd out the relevant entry in its thread local table.
  - When allocating new TLS entries for collectible TLS statics on a per-thread basis allocate a `LOADERHANDLE` for each object allocated, and associate it with the TLS index on that thread.
  - When cleaning up a thread, for each collectible thread static which is still allocated, we will have a `LOADERHANDLE`. If the collectible type still has a live managed `LoaderAllocator` free the `LOADERHANDLE`.

# Expected cost model for extra GC interactions associated with this change
This change adds 3 possible ways in which the GC may have to perform additional work beyond what it used to do.
1. For normal statics on collectible types, it uses the a weak interior pointer GC handle for each of these that is allocated. This is purely pay for play and trades off performance of accessing collectible statics at runtime to the cost of maintaining a GCHandle in the GC. As the number of statics increases, this could in theory become a performance problem, but given the typical usages of collectible assemblies, we do not expect this to be significant.
2. For non-collectible thread statics, there is 1 GC pointer that is unconditionally reported for each thread. Usage of this removes a single indirection from every non-collectible thread local access. Given that this pointer is reported unconditionally, and is only a single pointer, this is not expected to be a significant cost.
3. For collectible thread statics, there is a complex protocol to keep thread statics alive for just long enough, and to clean them up as needed. This is expected to be completely pay for play with regard to usage of thread local variables in collectible assemblies, and while slightly more expensive to run than the current logic, will reduce the cost of creation/destruction of threads by a much more significant factor. In addition, if there are no collectible thread statics used on the thread, the cost of this is only a few branches per lookup.

# Perf impact of this change
I've run the .NET Microbenchmark suite as well as a variety of ASP.NET Benchmarks. (Unfortunately the publicly visible infrastructure for running tests is incompatible with this change, so results are not public). The results are generally quite hard to interpret. ASP.NET Benchmarks are generally (very) slightly better, and the microbenchmarks are generally equivalent in performance, although there is variability in some tests that had not previously shown variability, and the differences in performance are contained within the margin of error in our perf testing for tests with any significant amount of code. When performance differences have been examined in detail, they tend to be in code which has not changed in any way due to this change, and when run in isolation the performance deltas have disappeared in all cases that I have examined. Thus, I assume they are caching side effect changes. Performance testing has led me to add a change such that all NonGC, NonCollectible statics are allocated in a separate LoaderHeap which appears to have reduced the variability in some of the tests by a small fraction, although results are not consistent enough for me to be extremely confident in that statement.
This commit is contained in:
David Wrighton 2024-06-12 20:54:31 -07:00 committed by GitHub
parent bfb028b80f
commit eb8f54d92b
Signed by: github
GPG key ID: B5690EEEBB952194
106 changed files with 3551 additions and 6140 deletions

View file

@ -193,19 +193,143 @@ This is enforced via an extensive and complicated set of enforcements within the
- **ISSUE:** The signature walks performed are done with the normal signature walking code. This code is designed to load types as it walks the signature, but in this case the type load functionality is used with the assumption that no type load will actually be triggered.
- **ISSUE:** Stackwalker requirements require support from not just the type system, but also the assembly loader. The Loader has had a number of issues meeting the needs of the type system here.
Type System and NGEN
--------------------
## Static variables
The type system data structures are a core part of what is saved into NGEN images. Unfortunately, these data structures logically have pointers within them that point to other NGEN images. In order to handle this situation, the type system data structures implement a concept known as restoration.
Static variables in CoreCLR are handled by a combination of getting the "static base", and then adjusting it by an offset to get a pointer to the actual value.
We define the statics base as either non-gc or gc for each field.
Currently non-gc statics are any statics which are represented by primitive types (byte, sbyte, char, int, uint, long, ulong, float, double, pointers of various forms), and enums.
GC statics are any statics which are represented by classes or by non-primitive valuetypes.
For valuetype statics which are GC statics, the static variable is actually a pointer to a boxed instance of the valuetype.
In restoration, when a type system data structure is first needed, the data structure is fixed up with correct pointers. This is tied into the type loading levels described in the [Type Loader](type-loader.md) Book of the Runtime chapter.
### Per type static variable information
As of .NET 9, the static variable bases are now all associated with their particular type.
As you can see from this diagram, the data for statics can be acquired by starting at a `MethodTable` and then getting either the `DynamicStaticsInfo` to get a statics pointer, or by getting a `ThreadStaticsInfo` to get a TLSIndex, which then can be used with the thread static variable system to get the actual thread static base.
There also exists the concept of pre-restored data structures. This means that the data structure is sufficiently correct at NGEN image load time (after intra-module pointer fixups and eager load type fixups), that the data structure may be used as is. This optimization requires that the NGEN image be "hard bound" to its dependent assemblies. See NGEN documentation for further details.
```mermaid
classDiagram
MethodTable : MethodTableAuxiliaryData* m_pAuxData
MethodTable --> MethodTableAuxiliaryData
MethodTableAuxiliaryData --> DynamicStaticsInfo : If has static variables
MethodTableAuxiliaryData --> GenericStaticsInfo : If is generic and has static variables
MethodTableAuxiliaryData --> ThreadStaticsInfo : If has thread local static variables
Type System and Domain Neutral Loading
--------------------------------------
DynamicStaticsInfo : StaticsPointer m_pGCStatics
DynamicStaticsInfo : StaticsPointer m_pNonGCStatics
The type system is a core part of the implementation of domain neutral loading. This is exposed to customers through the LoaderOptimization options available at AppDomain creation. Mscorlib is always loaded as domain neutral. The core requirement of this feature is that the type system data structures must not require pointers to domain specific state. Primarily this manifests itself in requirements around static fields and class constructors. In particular, whether or not a class constructor has been run is not a part of the core MethodTable data structure for this reason, and there is a mechanism for storing static data attached to the DomainFile data structure instead of the MethodTable data structure.
GenericStaticsInfo : FieldDesc* m_pFieldDescs
ThreadStaticsInfo : TLSIndex NonGCTlsIndex
ThreadStaticsInfo : TLSIndex GCTlsIndex
```
```mermaid
classDiagram
note for StaticsPointer "StaticsPointer is a pointer sized integer"
StaticsPointer : void* PointerToStaticBase
StaticsPointer : bool HasClassConstructorBeenRun
note for TLSIndex "TLSIndex is a 32bit integer"
TLSIndex : TLSIndexType indexType
TLSIndex : 24bit int indexOffset
```
In the above diagram, you can see that we have separate fields for non-gc and gc statics, as well as thread and normal statics.
For normal statics, we use a single pointer sized field, which also happens to encode whether or not the class constructor has been run.
This is done to allow lock free atomic access to both get the static field address as well as determine if the class constructor needs to be triggered.
For TLS statics, handling of detecting whether or not the class constructor has been run is a more complex process described as part of the thread statics infrastructure.
The `DynamicStaticsInfo` and `ThreadStaticsInfo` structures are accessed without any locks, so it is important to ensure that access to fields on these structures can be done with a single memory access, to avoid memory order tearing issues.
Also, notably, for generic types, each field has a `FieldDesc` which is allocated per type instance, and is not shared by multiple canonical instances.
#### Lifetime management for collectible statics
Finally we have a concept of collectible assemblies in the CoreCLR runtime, so we need to handle lifetime management for static variables.
The approach chosen was to build a special GC handle type which will allow the runtime to have a pointer in the runtime data structures to the interior of a managed object on the GC heap.
The requirement of behavior here is that a static variable cannot keep its own collectible assembly alive, and so collectible statics have the peculiar property that they can exist and be finalized before the collectible assembly is finally collected.
If there is some resurrection scenario, this can lead to very surprising behavior.
### Thread Statics
Thread statics are static variables which have a lifetime which is defined to be the shorter of the lifetime of the type containing the static, and the lifetime of the thread on which the static variable is accessed.
They are created by having a static variable on a type which is attributed with `[System.Runtime.CompilerServices.ThreadStaticAttribute]`.
The general scheme of how this works is to assign an "index" to the type which is the same on all threads, and then on each thread hold a data structure which is efficiently accessed by means of this index.
However, we have a few peculiarities in our approach.
1. We segregate collectible and non-collectible thread statics (`TLSIndexType::NonCollectible` and `TLSIndexType::Collectible`)
2. We provide an ability to share a non-gc thread static between native CoreCLR code and managed code (Subset of `TLSIndexType::DirectOnThreadLocalData`)
3. We provide an extremely efficient means to access a small number of non-gc thread statics. (The rest of the usage of `TLSIndexType::DirectOnThreadLocalData`)
#### Per-Thread Statics Data structures
```mermaid
classDiagram
note for ThreadLocalInfo "There is 1 of these per thread, and it is managed by the C++ compiler/OS using standard mechanisms.
It can be found as the t_ThreadStatics variable in a C++ compiler, and is also pointed at by the native Thread class."
ThreadLocalInfo : int cNonCollectibleTlsData
ThreadLocalInfo : void** pNonCollectibleTlsArrayData
ThreadLocalInfo : int cCollectibleTlsData
ThreadLocalInfo : void** pCollectibleTlsArrayData
ThreadLocalInfo : InFlightTLSData *pInFightData
ThreadLocalInfo : Thread* pThread
ThreadLocalInfo : Special Thread Statics Shared Between Native and Managed code
ThreadLocalInfo : byte[N] ExtendedDirectThreadLocalTLSData
InFlightTLSData : InFlightTLSData* pNext
InFlightTLSData : TLSIndex tlsIndex
InFlightTLSData : OBJECTHANDLE hTLSData
ThreadLocalInfo --> InFlightTLSData : For TLS statics which have their memory allocated, but have not been accessed since the class finished running its class constructor
InFlightTLSData --> InFlightTLSData : linked list
```
#### Access patterns for getting the thread statics address
This is the pattern that the JIT will use to access a thread static which is not `DirectOnThreadLocalData`.
0. Get the TLS index somehow
1. Get TLS pointer to OS managed TLS block for the current thread ie. `pThreadLocalData = &t_ThreadStatics`
2. Read 1 integer value `pThreadLocalData->cCollectibleTlsData OR pThreadLocalData->cNonCollectibleTlsData`
3. Compare cTlsData against the index we're looking up `if (cTlsData < index.GetIndexOffset())`
4. If the index is not within range, jump to step 11.
5. Read 1 pointer value from TLS block `pThreadLocalData->pCollectibleTlsArrayData` OR `pThreadLocalData->pNonCollectibleTlsArrayData`
6. Read 1 pointer from within the TLS Array. `pTLSBaseAddress = *(intptr_t*)(((uint8_t*)pTlsArrayData) + index.GetIndexOffset()`
7. If pointer is NULL jump to step 11 `if pTLSBaseAddress == NULL`
8. If TLS index not a Collectible index, return pTLSBaseAddress
9. if `ObjectFromHandle((OBJECTHANDLE)pTLSBaseAddress)` is NULL, jump to step 11
10. Return `ObjectFromHandle((OBJECTHANDLE)pTLSBaseAddress)`
11. Tail-call a helper `return GetThreadLocalStaticBase(index)`
This is the pattern that the JIT will use to access a thread static which is on `DirectOnThreadLocalData`
0. Get the TLS index somehow
1. Get TLS pointer to OS managed TLS block for the current thread ie. `pThreadLocalData = &t_ThreadStatics`
2. Add the index offset to the start of the ThreadLocalData structure `pTLSBaseAddress = ((uint8_t*)pThreadLocalData) + index.GetIndexOffset()`
#### Lifetime management for thread static variables
We distinguish between collectible and non-collectible thread static variables for efficiency purposes.
A non-collectible thread static is a thread static defined on a type which cannot be collected by the runtime.
This describes most thread statics in actual observed practice.
The `DirectOnThreadLocalData` statics are a subset of this category which has a speical optimized form and does not need any GC reporting.
For non-collectible thread statics, the pointer (`pNonCollectibleTlsArrayData`) in the `ThreadLocalData` is a pointer to a managed `object[]` which points at either `object[]`, `byte[]`, or `double[]` arrays.
At GC scan time, the pointer to the initial object[] is the only detail which needs to be reported to the GC.
A collectible thread static is a thread static which can be collected by the runtime.
This describes the static variables defined on types which can be collected by the runtime.
The pointer (`pCollectibleTlsArrayData`) in the `ThreadLocalData` is a pointer to a chunk of memory allocated via `malloc`, and holds pointers to `object[]`, `byte[]`, or `double[]` arrays.
At GC scan time, each managed object must individually be kept alive only if the type and thread is still alive. This requires properly handling several situations.
1. If a collectible assembly becomes unreferenced, but a thread static variable associated with it has a finalizer, the object must move to the finalization queue.
2. If a thread static variable associated with a collectible assembly refers to the collectible assembly `LoaderAllocator` via a series of object references, it must not provide a reason for the collectible assembly to be considered referenced.
3. If a collectible assembly is collected, then the associated static variables no longer exist, and the TLSIndex values associated with that collectible assembly becomes re-useable.
4. If a thread is no longer executing, then all thread statics associated with that thread are no longer kept alive.
The approach chosen is to use a pair of different handle types.
For efficient access, the handle type stored in the dynamically adjusted array is a WeakTrackResurrection GCHandle.
This handle instance is associated with the slot in the TLS data, not with the exact instantiation, so it can be re-used when the if the associated collectible assembly is collected, and then the slot is re-used.
In addition, each slot that is in use will have a `LOADERHANDLE` which will keep the object alive until the `LoaderAllocator` is freed.
This `LOADERHANDLE` will be abandoned if the `LoaderAllocator` is collected, but that's ok, as `LOADERHANDLE` only needs to be cleaned up if the `LoaderAllocator` isn't collected.
On thread destroy, for each collectible slot in the tls array, we will explicitly free the `LOADERHANDLE` on the correct `LoaderAllocator`.
Physical Architecture
=====================
@ -221,6 +345,7 @@ Major parts of the type system are found in:
- Array Code for handling the special cases required for array processing
- VirtualStubDispatch.cpp/h/inl Code for virtual stub dispatch
- VirtualCallStubCpu.hpp Processor specific code for virtual stub dispatch.
- threadstatics.cpp/h - Handling for thread static variables.
Major entry points are BuildMethodTable, LoadTypeHandleThrowing, CanCastTo\*, GetMethodDescFromMemberDefOrRefOrSpecThrowing, GetFieldDescFromMemberRefThrowing, CompareSigs, and VirtualCallStubManager::ResolveWorkerStatic.

View file

@ -693,8 +693,8 @@ namespace System.Runtime.CompilerServices
[FieldOffset(0)]
private uint Flags;
private const uint enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0001; // Is any field type or sub field type overrode Equals or GetHashCode
private const uint enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x0002; // Whether we have checked the overridden Equals or GetHashCode
private const uint enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0004; // Is any field type or sub field type overridden Equals or GetHashCode
public bool HasCheckedCanCompareBitsOrUseFastGetHashCode => (Flags & enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode) != 0;

View file

@ -1715,8 +1715,8 @@ ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *Module
ModuleData->bIsReflection = pModule->IsReflection();
ModuleData->bIsPEFile = pModule->IsPEFile();
ModuleData->Assembly = HOST_CDADDR(pModule->GetAssembly());
ModuleData->dwModuleID = pModule->GetModuleID();
ModuleData->dwModuleIndex = pModule->GetModuleIndex().m_dwIndex;
ModuleData->dwModuleID = 0; // CoreCLR no longer has this concept
ModuleData->dwModuleIndex = 0; // CoreCLR no longer has this concept
ModuleData->dwTransientFlags = pModule->m_dwTransientFlags;
ModuleData->LoaderAllocator = HOST_CDADDR(pModule->m_loaderAllocator);
ModuleData->ThunkHeap = HOST_CDADDR(pModule->m_pThunkHeap);
@ -3246,47 +3246,16 @@ ClrDataAccess::GetNestedExceptionData(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS
HRESULT
ClrDataAccess::GetDomainLocalModuleData(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData)
{
if (addr == 0 || pLocalModuleData == NULL)
return E_INVALIDARG;
SOSDacEnter();
DomainLocalModule* pLocalModule = PTR_DomainLocalModule(TO_TADDR(addr));
pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
SOSDacLeave();
return hr;
// CoreCLR does not use domain local modules anymore
return E_NOTIMPL;
}
HRESULT
ClrDataAccess::GetDomainLocalModuleDataFromModule(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData)
{
if (addr == 0 || pLocalModuleData == NULL)
return E_INVALIDARG;
SOSDacEnter();
Module* pModule = PTR_Module(TO_TADDR(addr));
DomainLocalModule* pLocalModule = PTR_DomainLocalModule(pModule->GetDomainLocalModule());
if (!pLocalModule)
{
hr = E_INVALIDARG;
}
else
{
pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load());
pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob));
}
SOSDacLeave();
return hr;
// CoreCLR does not use domain local modules anymore
return E_NOTIMPL;
}
HRESULT
@ -3299,31 +3268,8 @@ ClrDataAccess::GetDomainLocalModuleDataFromAppDomain(CLRDATA_ADDRESS appDomainAd
HRESULT
ClrDataAccess::GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int index, struct DacpThreadLocalModuleData *pLocalModuleData)
{
if (pLocalModuleData == NULL)
return E_INVALIDARG;
SOSDacEnter();
pLocalModuleData->threadAddr = thread;
pLocalModuleData->ModuleIndex = index;
PTR_Thread pThread = PTR_Thread(TO_TADDR(thread));
PTR_ThreadLocalBlock pLocalBlock = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pLocalModule = pLocalBlock->GetTLMIfExists(ModuleIndex(index));
if (!pLocalModule)
{
hr = E_INVALIDARG;
}
else
{
pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable);
pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(ThreadLocalModule, pLocalModule, m_pDataBlob));
}
SOSDacLeave();
return hr;
// CoreCLR does not use thread local modules anymore
return E_NOTIMPL;
}
@ -3656,6 +3602,7 @@ static const char *LoaderAllocatorLoaderHeapNames[] =
{
"LowFrequencyHeap",
"HighFrequencyHeap",
"StaticsHeap",
"StubHeap",
"ExecutableHeap",
"FixupPrecodeHeap",
@ -3690,6 +3637,7 @@ HRESULT ClrDataAccess::GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocatorAd
int i = 0;
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetLowFrequencyHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetHighFrequencyHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetStaticsHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetStubHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetExecutableHeap());
pLoaderHeaps[i++] = HOST_CDADDR(pLoaderAllocator->GetFixupPrecodeHeap());

View file

@ -185,7 +185,7 @@ End
Crst DelegateToFPtrHash
End
Crst DomainLocalBlock
Crst GenericDictionaryExpansion
AcquiredBefore PinnedHeapHandleTable IbcProfile LoaderHeap SystemDomainDelayedUnloadList UniqueStack
End
@ -265,7 +265,7 @@ Crst InstMethodHashTable
End
Crst Interop
AcquiredBefore PinnedHeapHandleTable AvailableParamTypes ClassInit DeadlockDetection DomainLocalBlock
AcquiredBefore PinnedHeapHandleTable AvailableParamTypes ClassInit DeadlockDetection GenericDictionaryExpansion
HandleTable InstMethodHashTable InteropData JitGenericHandleCache LoaderHeap SigConvert
StubDispatchCache StubUnwindInfoHeapSegments SyncBlockCache TypeIDMap UnresolvedClassLock
PendingTypeLoadEntry
@ -315,7 +315,7 @@ End
Crst LoaderAllocator
AcquiredBefore PinnedHeapHandleTable HandleTable UniqueStack ThreadStore
AcquiredAfter DomainLocalBlock
AcquiredAfter GenericDictionaryExpansion
End
Crst LoaderAllocatorReferences
@ -364,7 +364,7 @@ End
Crst PendingTypeLoadEntry
AcquiredBefore AppDomainCache PinnedHeapHandleTable AssemblyLoader AvailableClass AvailableParamTypes
BaseDomain ClassInit DeadlockDetection DebuggerController DebuggerJitInfo DebuggerMutex
DomainLocalBlock Exception ExecuteManRangeLock FuncPtrStubs
GenericDictionaryExpansion Exception ExecuteManRangeLock FuncPtrStubs
FusionAppCtx GlobalStrLiteralMap HandleTable IbcProfile
IJWFixupData IJWHash ISymUnmanagedReader Jit JumpStubCache LoaderHeap
Module ModuleLookupTable PEImage
@ -476,6 +476,10 @@ End
Crst SystemDomainDelayedUnloadList
End
Crst ThreadLocalStorageLock
AcquiredBefore ModuleLookupTable
End
Crst ThreadIdDispenser
End
@ -541,7 +545,7 @@ End
Crst EventPipe
AcquiredAfter PendingTypeLoadEntry
AcquiredBefore ThreadIdDispenser ThreadStore DomainLocalBlock InstMethodHashTable
AcquiredBefore ThreadIdDispenser ThreadStore GenericDictionaryExpansion InstMethodHashTable
End
Crst NotifyGdb
@ -574,10 +578,6 @@ Crst PgoData
AcquiredBefore LoaderHeap
End
Crst StaticBoxInit
AcquiredBefore LoaderHeap FrozenObjectHeap AssemblyLoader
End
Crst PerfMap
AcquiredAfter CodeVersioning AssemblyList
End

View file

@ -163,8 +163,6 @@ enum CORCOMPILE_FIXUP_BLOB_KIND
ENCODE_VERIFY_IL_BODY, /* Verify an IL body is defined the same at compile time and runtime. A failed match will cause a hard runtime failure. */
ENCODE_MODULE_HANDLE = 0x50, /* Module token */
ENCODE_MODULE_ID_FOR_GENERIC_STATICS, /* For accessing static fields */
ENCODE_CLASS_ID_FOR_STATICS, /* For accessing static fields */
ENCODE_SYNC_LOCK, /* For synchronizing access to a type */
ENCODE_PROFILING_HANDLE, /* For the method's profiling counter */
ENCODE_VARARGS_METHODDEF, /* For calling a varargs method */

View file

@ -528,28 +528,31 @@ enum CorInfoHelpFunc
// ICorClassInfo::getSharedStaticsOrCCtorHelper to determine which helper to use
// Helpers for regular statics
CORINFO_HELP_GETGENERICS_GCSTATIC_BASE,
CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCSTATIC_BASE,
CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS,
CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS,
// Helper to class initialize shared generic with dynamicclass, but not get static field address
CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS,
CORINFO_HELP_GET_GCSTATIC_BASE,
CORINFO_HELP_GET_NONGCSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE,
CORINFO_HELP_GETPINNED_GCSTATIC_BASE,
CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE,
CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR,
// Helpers for thread statics
CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE,
CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GET_GCTHREADSTATIC_BASE,
CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2,
/* Debugger */
@ -1698,7 +1701,7 @@ struct CORINFO_THREAD_STATIC_BLOCKS_INFO
uint32_t offsetOfThreadLocalStoragePointer; // windows specific
uint32_t offsetOfMaxThreadStaticBlocks;
uint32_t offsetOfThreadStaticBlocks;
uint32_t offsetOfGCDataPointer;
uint32_t offsetOfBaseOfThreadLocalData;
};
//----------------------------------------------------------------------------
@ -2403,18 +2406,20 @@ public:
virtual void* LongLifetimeMalloc(size_t sz) = 0;
virtual void LongLifetimeFree(void* obj) = 0;
virtual size_t getClassModuleIdForStatics (
CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE * pModule,
void ** ppIndirection
) = 0;
virtual bool getIsClassInitedFlagAddress(
CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
int* offset
) = 0;
virtual size_t getClassStaticDynamicInfo (
CORINFO_CLASS_HANDLE cls
) = 0;
virtual size_t getClassThreadStaticDynamicInfo (
CORINFO_CLASS_HANDLE cls
) = 0;
virtual bool getStaticBaseAddress(
CORINFO_CLASS_HANDLE cls,
bool isGc,
@ -2824,8 +2829,7 @@ public:
// Returns the thread static block information like offsets, etc. from current TLS.
virtual void getThreadLocalStaticBlocksInfo (
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo,
bool isGCType
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo
) = 0;
virtual void getThreadLocalStaticInfo_NativeAOT(
@ -3245,12 +3249,6 @@ public:
CORINFO_CALL_INFO *pResult
) = 0;
// Returns the class's domain ID for accessing shared statics
virtual unsigned getClassDomainID (
CORINFO_CLASS_HANDLE cls,
void **ppIndirection = NULL
) = 0;
//------------------------------------------------------------------------------
// getStaticFieldContent: returns true and the actual field's value if the given
// field represents a statically initialized readonly field of any type.

View file

@ -41,20 +41,20 @@ enum CrstType
CrstDebuggerJitInfo = 23,
CrstDebuggerMutex = 24,
CrstDelegateToFPtrHash = 25,
CrstDomainLocalBlock = 26,
CrstDynamicIL = 27,
CrstDynamicMT = 28,
CrstEtwTypeLogHash = 29,
CrstEventPipe = 30,
CrstEventStore = 31,
CrstException = 32,
CrstExecutableAllocatorLock = 33,
CrstExecuteManRangeLock = 34,
CrstFCall = 35,
CrstFrozenObjectHeap = 36,
CrstFuncPtrStubs = 37,
CrstFusionAppCtx = 38,
CrstGCCover = 39,
CrstDynamicIL = 26,
CrstDynamicMT = 27,
CrstEtwTypeLogHash = 28,
CrstEventPipe = 29,
CrstEventStore = 30,
CrstException = 31,
CrstExecutableAllocatorLock = 32,
CrstExecuteManRangeLock = 33,
CrstFCall = 34,
CrstFrozenObjectHeap = 35,
CrstFuncPtrStubs = 36,
CrstFusionAppCtx = 37,
CrstGCCover = 38,
CrstGenericDictionaryExpansion = 39,
CrstGlobalStrLiteralMap = 40,
CrstHandleTable = 41,
CrstIbcProfile = 42,
@ -111,17 +111,17 @@ enum CrstType
CrstSingleUseLock = 93,
CrstSpecialStatics = 94,
CrstStackSampler = 95,
CrstStaticBoxInit = 96,
CrstStressLog = 97,
CrstStubCache = 98,
CrstStubDispatchCache = 99,
CrstStubUnwindInfoHeapSegments = 100,
CrstSyncBlockCache = 101,
CrstSyncHashLock = 102,
CrstSystemBaseDomain = 103,
CrstSystemDomain = 104,
CrstSystemDomainDelayedUnloadList = 105,
CrstThreadIdDispenser = 106,
CrstStressLog = 96,
CrstStubCache = 97,
CrstStubDispatchCache = 98,
CrstStubUnwindInfoHeapSegments = 99,
CrstSyncBlockCache = 100,
CrstSyncHashLock = 101,
CrstSystemBaseDomain = 102,
CrstSystemDomain = 103,
CrstSystemDomainDelayedUnloadList = 104,
CrstThreadIdDispenser = 105,
CrstThreadLocalStorageLock = 106,
CrstThreadStore = 107,
CrstTieredCompilation = 108,
CrstTypeEquivalenceMap = 109,
@ -170,7 +170,6 @@ int g_rgCrstLevelMap[] =
4, // CrstDebuggerJitInfo
13, // CrstDebuggerMutex
0, // CrstDelegateToFPtrHash
18, // CrstDomainLocalBlock
0, // CrstDynamicIL
10, // CrstDynamicMT
0, // CrstEtwTypeLogHash
@ -184,6 +183,7 @@ int g_rgCrstLevelMap[] =
7, // CrstFuncPtrStubs
10, // CrstFusionAppCtx
10, // CrstGCCover
18, // CrstGenericDictionaryExpansion
17, // CrstGlobalStrLiteralMap
1, // CrstHandleTable
0, // CrstIbcProfile
@ -240,7 +240,6 @@ int g_rgCrstLevelMap[] =
5, // CrstSingleUseLock
0, // CrstSpecialStatics
0, // CrstStackSampler
15, // CrstStaticBoxInit
-1, // CrstStressLog
5, // CrstStubCache
0, // CrstStubDispatchCache
@ -251,6 +250,7 @@ int g_rgCrstLevelMap[] =
15, // CrstSystemDomain
0, // CrstSystemDomainDelayedUnloadList
0, // CrstThreadIdDispenser
5, // CrstThreadLocalStorageLock
14, // CrstThreadStore
8, // CrstTieredCompilation
4, // CrstTypeEquivalenceMap
@ -293,7 +293,6 @@ LPCSTR g_rgCrstNameMap[] =
"CrstDebuggerJitInfo",
"CrstDebuggerMutex",
"CrstDelegateToFPtrHash",
"CrstDomainLocalBlock",
"CrstDynamicIL",
"CrstDynamicMT",
"CrstEtwTypeLogHash",
@ -307,6 +306,7 @@ LPCSTR g_rgCrstNameMap[] =
"CrstFuncPtrStubs",
"CrstFusionAppCtx",
"CrstGCCover",
"CrstGenericDictionaryExpansion",
"CrstGlobalStrLiteralMap",
"CrstHandleTable",
"CrstIbcProfile",
@ -363,7 +363,6 @@ LPCSTR g_rgCrstNameMap[] =
"CrstSingleUseLock",
"CrstSpecialStatics",
"CrstStackSampler",
"CrstStaticBoxInit",
"CrstStressLog",
"CrstStubCache",
"CrstStubDispatchCache",
@ -374,6 +373,7 @@ LPCSTR g_rgCrstNameMap[] =
"CrstSystemDomain",
"CrstSystemDomainDelayedUnloadList",
"CrstThreadIdDispenser",
"CrstThreadLocalStorageLock",
"CrstThreadStore",
"CrstTieredCompilation",
"CrstTypeEquivalenceMap",

View file

@ -145,7 +145,6 @@ DEFINE_DACVAR(gc_alloc_context, dac__g_global_alloc_context, ::g_global_alloc_co
DEFINE_DACVAR(IGCHeap, dac__g_pGCHeap, ::g_pGCHeap)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pThinLockThreadIdDispenser, ::g_pThinLockThreadIdDispenser)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pModuleIndexDispenser, ::g_pModuleIndexDispenser)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pObjectClass, ::g_pObjectClass)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pRuntimeTypeClass, ::g_pRuntimeTypeClass)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pCanonMethodTableClass, ::g_pCanonMethodTableClass)

View file

@ -49,4 +49,10 @@ inline auto operator ^= (T& left, T right) -> const decltype(T::support_use_as_f
return left;
}
template <typename T>
inline bool HasFlag(T value, decltype(T::support_use_as_flags) flag)
{
return (value & flag) == flag;
}
#endif /* ENUM_CLASS_FLAGS_OPERATORS */

View file

@ -208,16 +208,17 @@ void* LongLifetimeMalloc(
void LongLifetimeFree(
void* obj) override;
size_t getClassModuleIdForStatics(
CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection) override;
bool getIsClassInitedFlagAddress(
CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
int* offset) override;
size_t getClassThreadStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr) override;
size_t getClassStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr) override;
bool getStaticBaseAddress(
CORINFO_CLASS_HANDLE cls,
bool isGc,
@ -404,8 +405,7 @@ uint32_t getThreadLocalFieldInfo(
bool isGCtype) override;
void getThreadLocalStaticBlocksInfo(
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo,
bool isGCType) override;
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) override;
void getThreadLocalStaticInfo_NativeAOT(
CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) override;
@ -600,10 +600,6 @@ void getCallInfo(
CORINFO_CALLINFO_FLAGS flags,
CORINFO_CALL_INFO* pResult) override;
unsigned getClassDomainID(
CORINFO_CLASS_HANDLE cls,
void** ppIndirection) override;
bool getStaticFieldContent(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,

View file

@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED
constexpr GUID JITEEVersionIdentifier = { /* 6e0b439f-0d18-4836-a486-4962af0cc948 */
0x6e0b439f,
0x0d18,
0x4836,
{0xa4, 0x86, 0x49, 0x62, 0xaf, 0x0c, 0xc9, 0x48}
constexpr GUID JITEEVersionIdentifier = { /* de0cd36d-3094-4110-af7d-31eb36234e46 */
0xde0cd36d,
0x3094,
0x4110,
{0xaf, 0x7d, 0x31, 0xeb, 0x36, 0x23, 0x4e, 0x46}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -177,35 +177,31 @@
JITHELPER(CORINFO_HELP_GETSTATICFIELDADDR, JIT_GetStaticFieldAddr,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSTATICFIELDADDR_TLS, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, JIT_GetGenericsGCStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, JIT_GetGenericsNonGCStaticBase,CORINFO_HELP_SIG_REG_ONLY)
#ifdef TARGET_X86
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, NULL, CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, NULL, CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, NULL, CORINFO_HELP_SIG_REG_ONLY)
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,NULL, CORINFO_HELP_SIG_REG_ONLY)
#else
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
#endif
JITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCStaticBaseDynamicClass,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedNonGCStaticBaseDynamicClass,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS, JIT_ClassInitDynamicClass,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE, JIT_GetGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE, JIT_GetNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETPINNED_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR, JIT_GetGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR, JIT_GetNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR, JIT_GetDynamicGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR, JIT_GetDynamicGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
JITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB)
// Thread statics
JITHELPER(CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, JIT_GetGenericsGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE, JIT_GetGenericsNonGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, JIT_GetSharedGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedNonGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedNonGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE, JIT_GetGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, JIT_GetNonGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE, JIT_GetDynamicGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE, JIT_GetDynamicNonGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetDynamicGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,JIT_GetGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,JIT_GetNonGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2,JIT_GetNonGCThreadStaticBaseOptimized2, CORINFO_HELP_SIG_REG_ONLY)
// Debugger
JITHELPER(CORINFO_HELP_DBG_IS_JUST_MY_CODE, JIT_DbgIsJustMyCode,CORINFO_HELP_SIG_REG_ONLY)

View file

@ -19,10 +19,10 @@
// src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h
// If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION`
// and handle pending work.
#define READYTORUN_MAJOR_VERSION 0x0009
#define READYTORUN_MINOR_VERSION 0x0003
#define READYTORUN_MAJOR_VERSION 10
#define READYTORUN_MINOR_VERSION 0x0000
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x009
#define MINIMUM_READYTORUN_MAJOR_VERSION 10
// R2R Version 2.1 adds the InliningInfo section
// R2R Version 2.2 adds the ProfileDataInfo section
@ -36,6 +36,7 @@
// R2R Version 9.2 adds MemZero and NativeMemSet helpers
// R2R Version 9.3 adds BulkWriteBarrier helper
// uses GCInfo v3, which makes safe points in partially interruptible code interruptible.
// R2R Version 10.0 adds support for the statics being allocated on a per type basis instead of on a per module basis
struct READYTORUN_CORE_HEADER
{

View file

@ -51,10 +51,10 @@ HELPER(READYTORUN_HELPER_NewArray, CORINFO_HELP_NEWARR_1_DIRECT
HELPER(READYTORUN_HELPER_CheckCastAny, CORINFO_HELP_CHKCASTANY, )
HELPER(READYTORUN_HELPER_CheckInstanceAny, CORINFO_HELP_ISINSTANCEOFANY, )
HELPER(READYTORUN_HELPER_GenericGcStaticBase, CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, )
HELPER(READYTORUN_HELPER_GenericNonGcStaticBase, CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, )
HELPER(READYTORUN_HELPER_GenericGcTlsBase, CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, )
HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,)
HELPER(READYTORUN_HELPER_GenericGcStaticBase, CORINFO_HELP_GET_GCSTATIC_BASE, )
HELPER(READYTORUN_HELPER_GenericNonGcStaticBase, CORINFO_HELP_GET_NONGCSTATIC_BASE, )
HELPER(READYTORUN_HELPER_GenericGcTlsBase, CORINFO_HELP_GET_GCTHREADSTATIC_BASE, )
HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, )
HELPER(READYTORUN_HELPER_VirtualFuncPtr, CORINFO_HELP_VIRTUAL_FUNC_PTR, )
HELPER(READYTORUN_HELPER_IsInstanceOfException, CORINFO_HELP_ISINSTANCEOF_EXCEPTION, )

View file

@ -444,7 +444,7 @@ interface ISOSDacInterface8 : IUnknown
// Increment anytime there is a change in the data structures that SOS depends on like
// stress log structs (StressMsg, StressLogChunck, ThreadStressLog, etc), exception
// stack traces (StackTraceElement), the PredefinedTlsSlots enums, etc.
cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 4")
cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 5")
[
object,

View file

@ -50,8 +50,9 @@ DEF_CLR_API(getModuleAssembly)
DEF_CLR_API(getAssemblyName)
DEF_CLR_API(LongLifetimeMalloc)
DEF_CLR_API(LongLifetimeFree)
DEF_CLR_API(getClassModuleIdForStatics)
DEF_CLR_API(getIsClassInitedFlagAddress)
DEF_CLR_API(getClassThreadStaticDynamicInfo)
DEF_CLR_API(getClassStaticDynamicInfo)
DEF_CLR_API(getStaticBaseAddress)
DEF_CLR_API(getClassSize)
DEF_CLR_API(getHeapClassSize)
@ -148,7 +149,6 @@ DEF_CLR_API(canGetCookieForPInvokeCalliSig)
DEF_CLR_API(getJustMyCodeHandle)
DEF_CLR_API(GetProfilingHandle)
DEF_CLR_API(getCallInfo)
DEF_CLR_API(getClassDomainID)
DEF_CLR_API(getStaticFieldContent)
DEF_CLR_API(getObjectContent)
DEF_CLR_API(getStaticFieldCurrentClass)

View file

@ -460,17 +460,6 @@ void WrapICorJitInfo::LongLifetimeFree(
API_LEAVE(LongLifetimeFree);
}
size_t WrapICorJitInfo::getClassModuleIdForStatics(
CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection)
{
API_ENTER(getClassModuleIdForStatics);
size_t temp = wrapHnd->getClassModuleIdForStatics(cls, pModule, ppIndirection);
API_LEAVE(getClassModuleIdForStatics);
return temp;
}
bool WrapICorJitInfo::getIsClassInitedFlagAddress(
CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
@ -482,6 +471,24 @@ bool WrapICorJitInfo::getIsClassInitedFlagAddress(
return temp;
}
size_t WrapICorJitInfo::getClassThreadStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
API_ENTER(getClassThreadStaticDynamicInfo);
size_t temp = wrapHnd->getClassThreadStaticDynamicInfo(clr);
API_LEAVE(getClassThreadStaticDynamicInfo);
return temp;
}
size_t WrapICorJitInfo::getClassStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
API_ENTER(getClassStaticDynamicInfo);
size_t temp = wrapHnd->getClassStaticDynamicInfo(clr);
API_LEAVE(getClassStaticDynamicInfo);
return temp;
}
bool WrapICorJitInfo::getStaticBaseAddress(
CORINFO_CLASS_HANDLE cls,
bool isGc,
@ -953,11 +960,10 @@ uint32_t WrapICorJitInfo::getThreadLocalFieldInfo(
}
void WrapICorJitInfo::getThreadLocalStaticBlocksInfo(
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo,
bool isGCType)
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
API_ENTER(getThreadLocalStaticBlocksInfo);
wrapHnd->getThreadLocalStaticBlocksInfo(pInfo, isGCType);
wrapHnd->getThreadLocalStaticBlocksInfo(pInfo);
API_LEAVE(getThreadLocalStaticBlocksInfo);
}
@ -1419,16 +1425,6 @@ void WrapICorJitInfo::getCallInfo(
API_LEAVE(getCallInfo);
}
unsigned WrapICorJitInfo::getClassDomainID(
CORINFO_CLASS_HANDLE cls,
void** ppIndirection)
{
API_ENTER(getClassDomainID);
unsigned temp = wrapHnd->getClassDomainID(cls, ppIndirection);
API_LEAVE(getClassDomainID);
return temp;
}
bool WrapICorJitInfo::getStaticFieldContent(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,

View file

@ -2000,7 +2000,7 @@ void Compiler::compInit(ArenaAllocator* pAlloc,
// check that HelperCallProperties are initialized
assert(s_helperCallProperties.IsPure(CORINFO_HELP_GETSHARED_GCSTATIC_BASE));
assert(s_helperCallProperties.IsPure(CORINFO_HELP_GET_GCSTATIC_BASE));
assert(!s_helperCallProperties.IsPure(CORINFO_HELP_GETFIELDOBJ)); // quick sanity check
// We start with the flow graph in tree-order

View file

@ -3881,13 +3881,15 @@ inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* is
switch (eeGetHelperNum(tree->AsCall()->gtCallMethHnd))
{
case CORINFO_HELP_READYTORUN_GCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
case CORINFO_HELP_GET_GCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE:
result = true;
gc = true;
retVal = SHRV_STATIC_BASE_PTR;
break;
case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
case CORINFO_HELP_GET_NONGCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE:
result = true;
gc = false;
retVal = SHRV_STATIC_BASE_PTR;
@ -3925,30 +3927,17 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree)
helper == CORINFO_HELP_STRCNS || helper == CORINFO_HELP_BOX ||
// helpers being added to IsSharedStaticHelper
helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS || helper == CORINFO_HELP_GETGENERICS_GCSTATIC_BASE ||
helper == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE || helper == CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE ||
helper == CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE ||
helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS ||
helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE ||
helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS ||
helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS ||
helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE ||
helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE ||
helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED ||
helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED ||
helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS ||
helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS ||
(helper >= CORINFO_HELP_GET_GCSTATIC_BASE &&
helper <= CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2)
#ifdef FEATURE_READYTORUN
helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GCSTATIC_BASE ||
|| helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GCSTATIC_BASE ||
helper == CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE || helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE ||
helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE ||
helper == CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE
#endif
helper == CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
|| helper == CORINFO_HELP_INITCLASS;
#if 0
// See above TODO-Cleanup
bool result2 = s_helperCallProperties.IsPure(helper) && s_helperCallProperties.NonNullReturn(helper);

View file

@ -2833,8 +2833,8 @@ bool emitter::emitNoGChelper(CorInfoHelpFunc helpFunc)
case CORINFO_HELP_CHECKED_ASSIGN_REF:
case CORINFO_HELP_ASSIGN_BYREF:
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_INIT_PINVOKE_FRAME:

View file

@ -679,8 +679,9 @@ bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */)
// cls - The class handle
// helper - The helper function
// typeIndex - The static block type index. Used only for
// CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED or
// CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED to cache
// CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
// CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, or
// CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2 to cache
// the static block in an array at index typeIndex.
//
// Return Value:
@ -696,57 +697,50 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo
// We need the return type.
switch (helper)
{
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
bNeedClassID = false;
FALLTHROUGH;
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
callFlags |= GTF_CALL_HOISTABLE;
FALLTHROUGH;
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GET_GCSTATIC_BASE:
case CORINFO_HELP_GET_NONGCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE:
// type = TYP_BYREF;
break;
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
bNeedClassID = false;
FALLTHROUGH;
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2:
callFlags |= GTF_CALL_HOISTABLE;
FALLTHROUGH;
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE:
type = TYP_I_IMPL;
break;
case CORINFO_HELP_INITCLASS:
type = TYP_VOID;
break;
default:
assert(!"unknown shared statics helper");
break;
}
GenTree* opModuleIDArg;
GenTree* opClassIDArg;
// Get the class ID
unsigned clsID;
size_t moduleID;
void* pclsID;
void* pmoduleID;
clsID = info.compCompHnd->getClassDomainID(cls, &pclsID);
moduleID = info.compCompHnd->getClassModuleIdForStatics(cls, nullptr, &pmoduleID);
if (!(callFlags & GTF_CALL_HOISTABLE))
{
if (info.compCompHnd->getClassAttribs(cls) & CORINFO_FLG_BEFOREFIELDINIT)
@ -755,37 +749,36 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo
}
}
if (pmoduleID)
{
opModuleIDArg = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pmoduleID, GTF_ICON_CIDMID_HDL, true);
}
else
{
opModuleIDArg = gtNewIconNode((size_t)moduleID, TYP_I_IMPL);
}
GenTreeCall* result;
if (bNeedClassID)
{
if (pclsID)
{
opClassIDArg = gtNewIndOfIconHandleNode(TYP_INT, (size_t)pclsID, GTF_ICON_CIDMID_HDL, true);
}
else
{
opClassIDArg = gtNewIconNode(clsID, TYP_INT);
}
result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg);
}
else if ((helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) ||
(helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED))
if ((helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) ||
(helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) ||
(helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2))
{
result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex));
}
else if (helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE ||
helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE)
{
result = gtNewHelperCallNode(helper, type,
gtNewIconNode((size_t)info.compCompHnd->getClassThreadStaticDynamicInfo(cls),
TYP_I_IMPL));
}
else if (helper == CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE || helper == CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE ||
helper == CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETPINNED_GCSTATIC_BASE || helper == CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE ||
helper == CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR ||
helper == CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR)
{
result = gtNewHelperCallNode(helper, type,
gtNewIconNode(info.compCompHnd->getClassStaticDynamicInfo(cls), TYP_I_IMPL));
}
else
{
result = gtNewHelperCallNode(helper, type, opModuleIDArg);
result = gtNewHelperCallNode(helper, type, gtNewIconEmbClsHndNode(cls));
}
if (IsStaticHelperEligibleForExpansion(result))

View file

@ -454,8 +454,9 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock** pBlock, Statement* stm
}
//------------------------------------------------------------------------------
// fgExpandThreadLocalAccess: Inline the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED
// or CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED helper. See
// fgExpandThreadLocalAccess: Inline the CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
// CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, or
// CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2 helper. See
// fgExpandThreadLocalAccessForCall for details.
//
// Returns:
@ -763,8 +764,8 @@ bool Compiler::fgExpandThreadLocalAccessForCallNativeAOT(BasicBlock** pBlock, St
}
//------------------------------------------------------------------------------
// fgExpandThreadLocalAccessForCall : Expand the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED
// or CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, that access fields marked with [ThreadLocal].
// fgExpandThreadLocalAccessForCall : Expand the CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED
// or CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, that access fields marked with [ThreadLocal].
//
// Arguments:
// pBlock - Block containing the helper call to expand. If expansion is performed,
@ -793,11 +794,13 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
CorInfoHelpFunc helper = call->GetHelperNum();
if ((helper != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) &&
(helper != CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED))
if ((helper != CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) &&
(helper != CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) &&
(helper != CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2))
{
return false;
}
assert(!opts.IsReadyToRun());
if (TargetOS::IsUnix)
{
@ -822,15 +825,12 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
DISPTREE(call);
JITDUMP("\n");
bool isGCThreadStatic =
eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo;
memset(&threadStaticBlocksInfo, 0, sizeof(CORINFO_THREAD_STATIC_BLOCKS_INFO));
info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic);
info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo);
JITDUMP("getThreadLocalStaticBlocksInfo (%s)\n:", isGCThreadStatic ? "GC" : "Non-GC");
JITDUMP("getThreadLocalStaticBlocksInfo\n:");
JITDUMP("tlsIndex= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndex.addr));
JITDUMP("tlsGetAddrFtnPtr= %p\n", dspPtr(threadStaticBlocksInfo.tlsGetAddrFtnPtr));
JITDUMP("tlsIndexObject= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndexObject));
@ -839,7 +839,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
dspOffset(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer));
JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks));
JITDUMP("offsetOfThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfThreadStaticBlocks));
JITDUMP("offsetOfGCDataPointer= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfGCDataPointer));
JITDUMP("offsetOfBaseOfThreadLocalData= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfBaseOfThreadLocalData));
assert(call->gtArgs.CountArgs() == 1);
@ -989,7 +989,54 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
// Cache the tls value
tlsValueDef = gtNewStoreLclVarNode(tlsLclNum, tlsValue);
GenTree* tlsLclValueUse = gtNewLclVarNode(tlsLclNum);
GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode();
if (helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2)
{
// In this case we can entirely remove the block which uses the helper call, and just get the TLS pointer
// directly
// prevBb (BBJ_NONE): [weight: 1.0]
// ...
//
// tlsBaseComputeBB (BBJ_COND): [weight: 1.0]
// tlsRoot = [tlsRootAddress]
//
// block (...): [weight: 1.0]
// use(tlsRoot);
// ...
GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode();
GenTree* threadStaticBase =
gtNewOperNode(GT_ADD, TYP_I_IMPL,
gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse),
gtCloneExpr(typeThreadStaticBlockIndexValue)),
gtNewIconNode(threadStaticBlocksInfo.offsetOfBaseOfThreadLocalData, TYP_I_IMPL));
GenTree* tlsStaticBaseStoreLcl = gtNewStoreLclVarNode(threadStaticBlockLclNum, threadStaticBase);
BasicBlock* tlsBaseComputeBB = fgNewBBFromTreeAfter(BBJ_ALWAYS, prevBb, tlsValueDef, debugInfo, true);
fgInsertStmtAfter(tlsBaseComputeBB, tlsBaseComputeBB->firstStmt(), fgNewStmtFromTree(tlsStaticBaseStoreLcl));
//
// Update preds in all new blocks
//
FlowEdge* const newEdge = fgAddRefPred(block, tlsBaseComputeBB);
tlsBaseComputeBB->SetTargetEdge(newEdge);
assert(prevBb->KindIs(BBJ_ALWAYS));
fgRedirectTargetEdge(prevBb, tlsBaseComputeBB);
// Inherit the weights
block->inheritWeight(prevBb);
tlsBaseComputeBB->inheritWeight(prevBb);
// All blocks are expected to be in the same EH region
assert(BasicBlock::sameEHRegion(prevBb, block));
assert(BasicBlock::sameEHRegion(prevBb, tlsBaseComputeBB));
}
else
{
size_t offsetOfThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfThreadStaticBlocks;
size_t offsetOfMaxThreadStaticBlocksVal = threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks;
@ -997,29 +1044,30 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(offsetOfMaxThreadStaticBlocksVal, TYP_I_IMPL);
GenTree* maxThreadStaticBlocksRef =
gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), offsetOfMaxThreadStaticBlocks);
maxThreadStaticBlocksValue = gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
maxThreadStaticBlocksValue =
gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
GenTree* threadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse),
gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL));
threadStaticBlocksValue = gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
threadStaticBlocksValue = gtNewIndir(TYP_REF, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT);
// Create tree for "if (maxThreadStaticBlocks < typeIndex)"
GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode();
GenTree* maxThreadStaticBlocksCond =
gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue));
gtNewOperNode(GT_LE, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue));
maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond);
// Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]"
typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_INT, gtCloneExpr(typeThreadStaticBlockIndexValue),
gtNewIconNode(TARGET_POINTER_SIZE, TYP_INT));
GenTree* typeThreadStaticBlockRef =
gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue);
GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING);
gtNewOperNode(GT_ADD, TYP_BYREF, threadStaticBlocksValue, typeThreadStaticBlockIndexValue);
GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_BYREF, typeThreadStaticBlockRef, GTF_IND_NONFAULTING);
// Cache the threadStaticBlock value
unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access"));
lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL;
GenTree* threadStaticBlockBaseDef = gtNewStoreLclVarNode(threadStaticBlockBaseLclNum, typeThreadStaticBlockValue);
lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_BYREF;
GenTree* threadStaticBlockBaseDef =
gtNewStoreLclVarNode(threadStaticBlockBaseLclNum, typeThreadStaticBlockValue);
GenTree* threadStaticBlockBaseLclValueUse = gtNewLclVarNode(threadStaticBlockBaseLclNum);
// Create tree for "if (threadStaticBlockValue != nullptr)"
@ -1032,7 +1080,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
//
// maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 1.0]
// tlsValue = tls_access_code
// if (maxThreadStaticBlocks < typeIndex)
// if (maxThreadStaticBlocks <= typeIndex)
// goto fallbackBb;
//
// threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0]
@ -1070,17 +1118,6 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
BasicBlock* fallbackBb =
fgNewBBFromTreeAfter(BBJ_ALWAYS, threadStaticBlockNullCondBB, fallbackValueDef, debugInfo, true);
// fastPathBb
if (isGCThreadStatic)
{
// Need to add extra indirection to access the data pointer.
threadStaticBlockBaseLclValueUse = gtNewIndir(callType, threadStaticBlockBaseLclValueUse, GTF_IND_NONFAULTING);
threadStaticBlockBaseLclValueUse =
gtNewOperNode(GT_ADD, callType, threadStaticBlockBaseLclValueUse,
gtNewIconNode(threadStaticBlocksInfo.offsetOfGCDataPointer, TYP_I_IMPL));
}
GenTree* fastPathValueDef =
gtNewStoreLclVarNode(threadStaticBlockLclNum, gtCloneExpr(threadStaticBlockBaseLclValueUse));
BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, fastPathValueDef, debugInfo, true);
@ -1133,6 +1170,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement*
assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB));
assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB));
assert(BasicBlock::sameEHRegion(prevBb, fastPathBb));
}
return true;
}

View file

@ -3798,12 +3798,10 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved
switch (pFieldInfo->helper)
{
case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
type = TYP_I_IMPL;
break;
case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GET_GCSTATIC_BASE:
case CORINFO_HELP_GET_NONGCSTATIC_BASE:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE:
break;
default:
assert(!"unknown generic statics helper");
@ -3813,6 +3811,11 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved
isHoistable = !s_helperCallProperties.MayRunCctor(pFieldInfo->helper) ||
(info.compCompHnd->getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_BEFOREFIELDINIT);
op1 = gtNewHelperCallNode(pFieldInfo->helper, type, op1);
if (IsStaticHelperEligibleForExpansion(op1))
{
// Mark the helper call with the initClsHnd so that rewriting it for expansion can reliably fail
op1->AsCall()->gtInitClsHnd = pResolvedToken->hClass;
}
op1 = gtNewOperNode(GT_ADD, type, op1, gtNewIconNode(pFieldInfo->offset, innerFldSeq));
}
break;
@ -3823,13 +3826,14 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved
if (!opts.IsReadyToRun())
#endif // FEATURE_READYTORUN
{
if (pFieldInfo->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)
if ((pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) ||
(pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2))
{
typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, false);
}
else
{
assert(pFieldInfo->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED);
assert(pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED);
typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, true);
}
}

View file

@ -1691,20 +1691,17 @@ void HelperCallProperties::init()
// Helpers that load the base address for static variables.
// We divide these between those that may and may not invoke
// static class constructors.
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GET_GCSTATIC_BASE:
case CORINFO_HELP_GET_NONGCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GETSTATICFIELDADDR_TLS:
case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
case CORINFO_HELP_READYTORUN_GCSTATIC_BASE:
case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE:
case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE:
@ -1719,12 +1716,25 @@ void HelperCallProperties::init()
mayRunCctor = true;
break;
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
case CORINFO_HELP_INITCLASS:
case CORINFO_HELP_INITINSTCLASS:
isPure = true;
mayRunCctor = true;
break;
case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2:
case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR:
// These do not invoke static class constructors

View file

@ -13189,23 +13189,35 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
vnf = opts.IsReadyToRun() ? VNF_JitReadyToRunNewArr : VNF_JitNewArr;
break;
case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
vnf = VNF_GetgenericsGcstaticBase;
case CORINFO_HELP_GET_GCSTATIC_BASE:
vnf = VNF_GetGcstaticBase;
break;
case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
vnf = VNF_GetgenericsNongcstaticBase;
case CORINFO_HELP_GET_NONGCSTATIC_BASE:
vnf = VNF_GetNongcstaticBase;
break;
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
vnf = VNF_GetsharedGcstaticBase;
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE:
vnf = VNF_GetdynamicGcstaticBase;
break;
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
vnf = VNF_GetsharedNongcstaticBase;
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE:
vnf = VNF_GetdynamicNongcstaticBase;
break;
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
vnf = VNF_GetsharedGcstaticBaseNoctor;
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR:
vnf = VNF_GetdynamicGcstaticBaseNoctor;
break;
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
vnf = VNF_GetsharedNongcstaticBaseNoctor;
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR:
vnf = VNF_GetdynamicNongcstaticBaseNoctor;
break;
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE:
vnf = VNF_GetpinnedGcstaticBase;
break;
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE:
vnf = VNF_GetpinnedNongcstaticBase;
break;
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR:
vnf = VNF_GetpinnedGcstaticBaseNoctor;
break;
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR:
vnf = VNF_GetpinnedNongcstaticBaseNoctor;
break;
case CORINFO_HELP_READYTORUN_GCSTATIC_BASE:
vnf = VNF_ReadyToRunStaticBaseGC;
@ -13225,44 +13237,38 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
case CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
vnf = VNF_ReadyToRunGenericStaticBase;
break;
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
vnf = VNF_GetsharedGcstaticBaseDynamicclass;
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE:
vnf = VNF_GetGcthreadstaticBase;
break;
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
vnf = VNF_GetsharedNongcstaticBaseDynamicclass;
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE:
vnf = VNF_GetNongcthreadstaticBase;
break;
case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
vnf = VNF_ClassinitSharedDynamicclass;
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR:
vnf = VNF_GetGcthreadstaticBaseNoctor;
break;
case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
vnf = VNF_GetgenericsGcthreadstaticBase;
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR:
vnf = VNF_GetNongcthreadstaticBaseNoctor;
break;
case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
vnf = VNF_GetgenericsNongcthreadstaticBase;
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE:
vnf = VNF_GetdynamicGcthreadstaticBase;
break;
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
vnf = VNF_GetsharedGcthreadstaticBase;
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE:
vnf = VNF_GetdynamicNongcthreadstaticBase;
break;
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
vnf = VNF_GetsharedNongcthreadstaticBase;
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR:
vnf = VNF_GetdynamicGcthreadstaticBaseNoctor;
break;
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
vnf = VNF_GetsharedGcthreadstaticBaseNoctor;
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR:
vnf = VNF_GetdynamicNongcthreadstaticBaseNoctor;
break;
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
vnf = VNF_GetsharedGcthreadstaticBaseNoctorOptimized;
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
vnf = VNF_GetdynamicGcthreadstaticBaseNoctorOptimized;
break;
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
vnf = VNF_GetsharedNongcthreadstaticBaseNoctor;
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
vnf = VNF_GetdynamicNongcthreadstaticBaseNoctorOptimized;
break;
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED:
vnf = VNF_GetsharedNongcthreadstaticBaseNoctorOptimized;
break;
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
vnf = VNF_GetsharedGcthreadstaticBaseDynamicclass;
break;
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
vnf = VNF_GetsharedNongcthreadstaticBaseDynamicclass;
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2:
vnf = VNF_GetdynamicNongcthreadstaticBaseNoctorOptimized2;
break;
case CORINFO_HELP_GETSTATICFIELDADDR_TLS:
vnf = VNF_GetStaticAddrTLS;
@ -13450,33 +13456,6 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
break;
}
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
// These all take (Module*, class ID) as parameters.
//
// Strictly speaking the exact possible exception thrown by the
// static constructor depends on heap state too, but given that
// the constructor is only invoked once we can model that for
// the same class the same exceptions are thrown. Downstream
// code like CSE/copy prop that makes use VNs innately need to
// establish some form of dominance around the individual trees
// that makes this ok.
//
vnpExc = vnStore->VNPExcSetSingleton(
vnStore->VNPairForFunc(TYP_REF, VNF_ClassInitExc,
vnStore->VNPNormalPair(
call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair),
vnStore->VNPNormalPair(
call->gtArgs.GetUserArgByIndex(1)->GetNode()->gtVNPair)));
break;
#ifdef FEATURE_READYTORUN
case CORINFO_HELP_READYTORUN_GCSTATIC_BASE:
case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE:
@ -13493,10 +13472,14 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
}
#endif
case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
case CORINFO_HELP_GET_GCSTATIC_BASE:
case CORINFO_HELP_GET_NONGCSTATIC_BASE:
case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR:
// These take class handles as parameters.
vnpExc = vnStore->VNPExcSetSingleton(
vnStore->VNPairForFunc(TYP_REF, VNF_ClassInitGenericExc,
@ -13504,6 +13487,32 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair)));
break;
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR:
// These take DynamicClassInfo handles as parameters.
vnpExc = vnStore->VNPExcSetSingleton(
vnStore->VNPairForFunc(TYP_REF, VNF_DynamicClassInitExc,
vnStore->VNPNormalPair(
call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair)));
break;
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR:
// These take ThreadStaticInfo as parameters.
vnpExc = vnStore->VNPExcSetSingleton(
vnStore->VNPairForFunc(TYP_REF, VNF_ThreadClassInitExc,
vnStore->VNPNormalPair(
call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair)));
break;
case CORINFO_HELP_DIV:
case CORINFO_HELP_LDIV:
vnpExc = fgValueNumberDivisionExceptions(GT_DIV, call->gtArgs.GetUserArgByIndex(0)->GetNode(),

View file

@ -68,9 +68,10 @@ ValueNumFuncDef(IndexOutOfRangeExc, 2, false, false, false, false) // Array boun
ValueNumFuncDef(InvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: handle of type being cast to
ValueNumFuncDef(R2RInvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: entry point of R2R cast helper
ValueNumFuncDef(NewArrOverflowExc, 1, false, false, false, false) // Raises Integer overflow when Arg 0 is negative
ValueNumFuncDef(ClassInitExc, 2, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of module, 1: VN of class ID
ValueNumFuncDef(DynamicClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of DynamicStaticsInfo
ValueNumFuncDef(ThreadClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of ThreadStaticsInfo
ValueNumFuncDef(R2RClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of R2R entry point
ValueNumFuncDef(ClassInitGenericExc, 2, false, false, false, false)// Represents exceptions thrown by static constructor for generic class. Args: 0: VN of class handle
ValueNumFuncDef(ClassInitGenericExc, 2, false, false, false, false)// Represents exceptions thrown by static constructor for class. Args: 0: VN of class handle
ValueNumFuncDef(HelperOpaqueExc, 1, false, false, false, false) // Represents opaque exceptions could be thrown by a JIT helper.
// Args: 0: Input to helper that uniquely determines exceptions thrown.
@ -114,32 +115,34 @@ ValueNumFuncDef(Truncate, 1, false, false, false, false)
ValueNumFuncDef(ManagedThreadId, 0, false, false, false, false)
ValueNumFuncDef(ObjGetType, 1, false, true, false, false)
ValueNumFuncDef(GetgenericsGcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetgenericsNongcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetsharedGcstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetsharedNongcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetGcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetNongcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicGcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicNongcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicGcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicNongcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseGC, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseNonGC, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseThread, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseThreadNoctor, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseThreadNonGC, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunGenericStaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetgenericsGcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctorOptimized, 1, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 1, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetpinnedGcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetpinnedNongcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetpinnedGcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetpinnedNongcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetGcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetNongcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetGcthreadstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetNongcthreadstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicGcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicNongcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicGcthreadstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicGcthreadstaticBaseNoctorOptimized, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctorOptimized, 1, false, true, true, false)
ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctorOptimized2, 1, false, true, true, false)
ValueNumFuncDef(ClassinitSharedDynamicclass, 2, false, false, false, false)
ValueNumFuncDef(RuntimeHandleMethod, 2, false, true, false, false)
ValueNumFuncDef(RuntimeHandleClass, 2, false, true, false, false)
ValueNumFuncDef(ReadyToRunGenericHandle, 2, false, true, false, false)

View file

@ -11,8 +11,8 @@ struct ReadyToRunHeaderConstants
{
static const uint32_t Signature = 0x00525452; // 'RTR'
static const uint32_t CurrentMajorVersion = 9;
static const uint32_t CurrentMinorVersion = 3;
static const uint32_t CurrentMajorVersion = 10;
static const uint32_t CurrentMinorVersion = 0;
};
struct ReadyToRunHeader

View file

@ -2802,7 +2802,7 @@ EXTERN_C const IID IID_ISOSDacInterface8;
/* interface __MIDL_itf_sospriv_0000_0012 */
/* [local] */
#define SOS_BREAKING_CHANGE_VERSION 4
#define SOS_BREAKING_CHANGE_VERSION 5
extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0012_v0_0_c_ifspec;

View file

@ -15,8 +15,8 @@ namespace Internal.Runtime
{
public const uint Signature = 0x00525452; // 'RTR'
public const ushort CurrentMajorVersion = 9;
public const ushort CurrentMinorVersion = 3;
public const ushort CurrentMajorVersion = 10;
public const ushort CurrentMinorVersion = 0;
}
#if READYTORUN
#pragma warning disable 0169

View file

@ -170,29 +170,31 @@ namespace Internal.JitInterface
// ICorClassInfo::getSharedStaticsOrCCtorHelper to determine which helper to use
// Helpers for regular statics
CORINFO_HELP_GETGENERICS_GCSTATIC_BASE,
CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCSTATIC_BASE,
CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS,
CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS,
// Helper to class initialize shared generic with dynamicclass, but not get static field address
CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS,
CORINFO_HELP_GET_GCSTATIC_BASE,
CORINFO_HELP_GET_NONGCSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE,
CORINFO_HELP_GETPINNED_GCSTATIC_BASE,
CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE,
CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR,
// Helpers for thread statics
CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE,
CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS,
CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GET_GCTHREADSTATIC_BASE,
CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE,
CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR,
CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,
CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2,
/* Debugger */
CORINFO_HELP_DBG_IS_JUST_MY_CODE, // Check if this is "JustMyCode" and needs to be stepped through.

View file

@ -2118,8 +2118,10 @@ namespace Internal.JitInterface
Marshal.FreeCoTaskMem((IntPtr)obj);
}
private UIntPtr getClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection)
{ throw new NotImplementedException("getClassModuleIdForStatics"); }
private UIntPtr getClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassStaticDynamicInfo"); }
private UIntPtr getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassThreadStaticDynamicInfo"); }
private uint getClassSize(CORINFO_CLASS_STRUCT_* cls)
{
@ -2632,17 +2634,15 @@ namespace Internal.JitInterface
MethodDesc md = method == null ? MethodBeingCompiled : HandleToObject(method);
TypeDesc type = fd != null ? fd.OwningType : typeFromContext(context);
#if !READYTORUN
if (
#if READYTORUN
IsClassPreInited(type)
#else
_isFallbackBodyCompilation ||
!_compilation.HasLazyStaticConstructor(type)
#endif
)
{
return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED;
}
#endif
MetadataType typeToInit = (MetadataType)type;
@ -3069,7 +3069,7 @@ namespace Internal.JitInterface
}
#pragma warning disable CA1822 // Mark members as static
private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
#pragma warning restore CA1822 // Mark members as static
{
// Implemented for JIT only for now.
@ -3568,9 +3568,6 @@ namespace Internal.JitInterface
return constLookup;
}
private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection)
{ throw new NotImplementedException("getClassDomainID"); }
private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative)
{
if (pIsSpeculative != null)

View file

@ -688,12 +688,12 @@ namespace Internal.JitInterface
}
[UnmanagedCallersOnly]
private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection)
private static byte _getIsClassInitedFlagAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset)
{
var _this = GetThis(thisHandle);
try
{
return _this.getClassModuleIdForStatics(cls, pModule, ppIndirection);
return _this.getIsClassInitedFlagAddress(cls, ref *addr, ref *offset) ? (byte)1 : (byte)0;
}
catch (Exception ex)
{
@ -703,12 +703,27 @@ namespace Internal.JitInterface
}
[UnmanagedCallersOnly]
private static byte _getIsClassInitedFlagAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset)
private static UIntPtr _getClassThreadStaticDynamicInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clr)
{
var _this = GetThis(thisHandle);
try
{
return _this.getIsClassInitedFlagAddress(cls, ref *addr, ref *offset) ? (byte)1 : (byte)0;
return _this.getClassThreadStaticDynamicInfo(clr);
}
catch (Exception ex)
{
*ppException = _this.AllocException(ex);
return default;
}
}
[UnmanagedCallersOnly]
private static UIntPtr _getClassStaticDynamicInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clr)
{
var _this = GetThis(thisHandle);
try
{
return _this.getClassStaticDynamicInfo(clr);
}
catch (Exception ex)
{
@ -1435,12 +1450,12 @@ namespace Internal.JitInterface
}
[UnmanagedCallersOnly]
private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, byte isGCType)
private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
var _this = GetThis(thisHandle);
try
{
_this.getThreadLocalStaticBlocksInfo(pInfo, isGCType != 0);
_this.getThreadLocalStaticBlocksInfo(pInfo);
}
catch (Exception ex)
{
@ -2136,21 +2151,6 @@ namespace Internal.JitInterface
}
}
[UnmanagedCallersOnly]
private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, void** ppIndirection)
{
var _this = GetThis(thisHandle);
try
{
return _this.getClassDomainID(cls, ref *ppIndirection);
}
catch (Exception ex)
{
*ppException = _this.AllocException(ex);
return default;
}
}
[UnmanagedCallersOnly]
private static byte _getStaticFieldContent(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, byte ignoreMovableObjects)
{
@ -2642,105 +2642,105 @@ namespace Internal.JitInterface
callbacks[43] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ASSEMBLY_STRUCT_*, byte*>)&_getAssemblyName;
callbacks[44] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_LongLifetimeMalloc;
callbacks[45] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_LongLifetimeFree;
callbacks[46] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_MODULE_STRUCT_**, void**, UIntPtr>)&_getClassModuleIdForStatics;
callbacks[47] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CONST_LOOKUP*, int*, byte>)&_getIsClassInitedFlagAddress;
callbacks[48] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, byte>)&_getStaticBaseAddress;
callbacks[49] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getClassSize;
callbacks[50] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getHeapClassSize;
callbacks[51] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_canAllocateOnStack;
callbacks[52] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte, uint>)&_getClassAlignmentRequirement;
callbacks[53] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte*, uint>)&_getClassGClayout;
callbacks[54] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getClassNumInstanceFields;
callbacks[55] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_FIELD_STRUCT_*>)&_getFieldInClass;
callbacks[56] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_TYPE_LAYOUT_NODE*, UIntPtr*, GetTypeLayoutResult>)&_getTypeLayout;
callbacks[57] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte*, byte, byte>)&_checkMethodModifier;
callbacks[58] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, bool*, CorInfoHelpFunc>)&_getNewHelper;
callbacks[59] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getNewArrHelper;
callbacks[60] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CorInfoHelpFunc>)&_getCastingHelper;
callbacks[61] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getSharedCCtorHelper;
callbacks[62] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getTypeForBox;
callbacks[63] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getBoxHelper;
callbacks[64] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getUnBoxHelper;
callbacks[65] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_OBJECT_STRUCT_*>)&_getRuntimeTypePointer;
callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, byte>)&_isObjectImmutable;
callbacks[67] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, int, ushort*, byte>)&_getStringChar;
callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getObjectType;
callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
callbacks[70] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
callbacks[71] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
callbacks[72] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
callbacks[73] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoClassId, CORINFO_CLASS_STRUCT_*>)&_getBuiltinClass;
callbacks[74] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveValueClass;
callbacks[75] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveNumericClass;
callbacks[76] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canCast;
callbacks[77] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForCast;
callbacks[78] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality;
callbacks[79] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType;
callbacks[80] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isExactType;
callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_isNullableType;
callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, TypeCompareState>)&_isEnum;
callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType;
callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType;
callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray;
callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank;
callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID;
callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData;
callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass;
callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, UIntPtr, UIntPtr*, UIntPtr>)&_printFieldName;
callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass;
callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType;
callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset;
callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo;
callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte, uint>)&_getThreadLocalFieldInfo;
callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_THREAD_STATIC_BLOCKS_INFO*, byte, void>)&_getThreadLocalStaticBlocksInfo;
callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_THREAD_STATIC_INFO_NATIVEAOT*, void>)&_getThreadLocalStaticInfo_NativeAOT;
callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic;
callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, int>)&_getArrayOrStringLength;
callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries;
callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries;
callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars;
callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars;
callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings;
callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, void*, UIntPtr, void>)&_reportMetadata;
callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray;
callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray;
callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext;
callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType;
callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses;
callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass;
callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType;
callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap;
callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap;
callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo;
callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename;
callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod;
callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte*, UIntPtr, UIntPtr*, UIntPtr>)&_printMethodName;
callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata;
callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash;
callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor;
callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_SWIFT_LOWERING*, void>)&_getSwiftLowering;
callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags;
callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getRISCV64PassStructInRegisterFlags;
callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex;
callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal;
callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn;
callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint;
callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint;
callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync;
callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper;
callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle;
callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle;
callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle;
callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle;
callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_METHOD_STRUCT_*, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle;
callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType;
callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget;
callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig;
callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig;
callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle;
callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle;
callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo;
callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, uint>)&_getClassDomainID;
callbacks[46] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CONST_LOOKUP*, int*, byte>)&_getIsClassInitedFlagAddress;
callbacks[47] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, UIntPtr>)&_getClassThreadStaticDynamicInfo;
callbacks[48] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, UIntPtr>)&_getClassStaticDynamicInfo;
callbacks[49] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, byte>)&_getStaticBaseAddress;
callbacks[50] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getClassSize;
callbacks[51] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getHeapClassSize;
callbacks[52] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_canAllocateOnStack;
callbacks[53] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte, uint>)&_getClassAlignmentRequirement;
callbacks[54] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte*, uint>)&_getClassGClayout;
callbacks[55] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getClassNumInstanceFields;
callbacks[56] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_FIELD_STRUCT_*>)&_getFieldInClass;
callbacks[57] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_TYPE_LAYOUT_NODE*, UIntPtr*, GetTypeLayoutResult>)&_getTypeLayout;
callbacks[58] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte*, byte, byte>)&_checkMethodModifier;
callbacks[59] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, bool*, CorInfoHelpFunc>)&_getNewHelper;
callbacks[60] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getNewArrHelper;
callbacks[61] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CorInfoHelpFunc>)&_getCastingHelper;
callbacks[62] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getSharedCCtorHelper;
callbacks[63] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getTypeForBox;
callbacks[64] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getBoxHelper;
callbacks[65] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHelpFunc>)&_getUnBoxHelper;
callbacks[66] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_OBJECT_STRUCT_*>)&_getRuntimeTypePointer;
callbacks[67] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, byte>)&_isObjectImmutable;
callbacks[68] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, int, ushort*, byte>)&_getStringChar;
callbacks[69] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getObjectType;
callbacks[70] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_LOOKUP_KIND*, CorInfoHelpFunc, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, byte>)&_getReadyToRunHelper;
callbacks[71] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, mdToken, CORINFO_CLASS_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP*, void>)&_getReadyToRunDelegateCtorHelper;
callbacks[72] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CORINFO_CONTEXT_STRUCT*, CorInfoInitClassResult>)&_initClass;
callbacks[73] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void>)&_classMustBeLoadedBeforeCodeIsRun;
callbacks[74] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoClassId, CORINFO_CLASS_STRUCT_*>)&_getBuiltinClass;
callbacks[75] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveValueClass;
callbacks[76] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getTypeForPrimitiveNumericClass;
callbacks[77] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_canCast;
callbacks[78] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForCast;
callbacks[79] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_compareTypesForEquality;
callbacks[80] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*, byte>)&_isMoreSpecificType;
callbacks[81] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isExactType;
callbacks[82] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, TypeCompareState>)&_isNullableType;
callbacks[83] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, TypeCompareState>)&_isEnum;
callbacks[84] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getParentType;
callbacks[85] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoType>)&_getChildType;
callbacks[86] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, byte>)&_isSDArray;
callbacks[87] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getArrayRank;
callbacks[88] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CorInfoArrayIntrinsic>)&_getArrayIntrinsicID;
callbacks[89] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint, void*>)&_getArrayInitializationData;
callbacks[90] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_HELPER_DESC*, CorInfoIsAccessAllowedResult>)&_canAccessClass;
callbacks[91] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, UIntPtr, UIntPtr*, UIntPtr>)&_printFieldName;
callbacks[92] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getFieldClass;
callbacks[93] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, CORINFO_CLASS_STRUCT_**, CORINFO_CLASS_STRUCT_*, CorInfoType>)&_getFieldType;
callbacks[94] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, uint>)&_getFieldOffset;
callbacks[95] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_ACCESS_FLAGS, CORINFO_FIELD_INFO*, void>)&_getFieldInfo;
callbacks[96] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte, uint>)&_getThreadLocalFieldInfo;
callbacks[97] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_THREAD_STATIC_BLOCKS_INFO*, void>)&_getThreadLocalStaticBlocksInfo;
callbacks[98] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_THREAD_STATIC_INFO_NATIVEAOT*, void>)&_getThreadLocalStaticInfo_NativeAOT;
callbacks[99] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte>)&_isFieldStatic;
callbacks[100] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, int>)&_getArrayOrStringLength;
callbacks[101] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, uint**, BoundaryTypes*, void>)&_getBoundaries;
callbacks[102] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, OffsetMapping*, void>)&_setBoundaries;
callbacks[103] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint*, ILVarInfo**, bool*, void>)&_getVars;
callbacks[104] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint, NativeVarInfo*, void>)&_setVars;
callbacks[105] = (delegate* unmanaged<IntPtr, IntPtr*, InlineTreeNode*, uint, RichOffsetMapping*, uint, void>)&_reportRichMappings;
callbacks[106] = (delegate* unmanaged<IntPtr, IntPtr*, byte*, void*, UIntPtr, void>)&_reportMetadata;
callbacks[107] = (delegate* unmanaged<IntPtr, IntPtr*, UIntPtr, void*>)&_allocateArray;
callbacks[108] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void>)&_freeArray;
callbacks[109] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_ARG_LIST_STRUCT_*>)&_getArgNext;
callbacks[110] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_**, CorInfoTypeWithMod>)&_getArgType;
callbacks[111] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, int, CORINFO_CLASS_STRUCT_**, int>)&_getExactClasses;
callbacks[112] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, CORINFO_ARG_LIST_STRUCT_*, CORINFO_CLASS_STRUCT_*>)&_getArgClass;
callbacks[113] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CorInfoHFAElemType>)&_getHFAType;
callbacks[114] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithErrorTrap;
callbacks[115] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, byte>)&_runWithSPMIErrorTrap;
callbacks[116] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_EE_INFO*, void>)&_getEEInfo;
callbacks[117] = (delegate* unmanaged<IntPtr, IntPtr*, char*>)&_getJitTimeLogFilename;
callbacks[118] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, mdToken>)&_getMethodDefFromMethod;
callbacks[119] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte*, UIntPtr, UIntPtr*, UIntPtr>)&_printMethodName;
callbacks[120] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte**, byte**, byte**, byte*>)&_getMethodNameFromMetadata;
callbacks[121] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodHash;
callbacks[122] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR*, byte>)&_getSystemVAmd64PassStructInRegisterDescriptor;
callbacks[123] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_SWIFT_LOWERING*, void>)&_getSwiftLowering;
callbacks[124] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getLoongArch64PassStructInRegisterFlags;
callbacks[125] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, uint>)&_getRISCV64PassStructInRegisterFlags;
callbacks[126] = (delegate* unmanaged<IntPtr, IntPtr*, void**, uint>)&_getThreadTLSIndex;
callbacks[127] = (delegate* unmanaged<IntPtr, IntPtr*, void**, int*>)&_getAddrOfCaptureThreadGlobal;
callbacks[128] = (delegate* unmanaged<IntPtr, IntPtr*, CorInfoHelpFunc, void**, void*>)&_getHelperFtn;
callbacks[129] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, CORINFO_ACCESS_FLAGS, void>)&_getFunctionEntryPoint;
callbacks[130] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte, CORINFO_CONST_LOOKUP*, void>)&_getFunctionFixedEntryPoint;
callbacks[131] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, void*>)&_getMethodSync;
callbacks[132] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, CorInfoHelpFunc>)&_getLazyStringLiteralHelper;
callbacks[133] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_MODULE_STRUCT_*, void**, CORINFO_MODULE_STRUCT_*>)&_embedModuleHandle;
callbacks[134] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, void**, CORINFO_CLASS_STRUCT_*>)&_embedClassHandle;
callbacks[135] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, void**, CORINFO_METHOD_STRUCT_*>)&_embedMethodHandle;
callbacks[136] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, void**, CORINFO_FIELD_STRUCT_*>)&_embedFieldHandle;
callbacks[137] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, byte, CORINFO_METHOD_STRUCT_*, CORINFO_GENERICHANDLE_RESULT*, void>)&_embedGenericHandle;
callbacks[138] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_LOOKUP_KIND*, void>)&_getLocationOfThisType;
callbacks[139] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CONST_LOOKUP*, void>)&_getAddressOfPInvokeTarget;
callbacks[140] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, void**, void*>)&_GetCookieForPInvokeCalliSig;
callbacks[141] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_SIG_INFO*, byte>)&_canGetCookieForPInvokeCalliSig;
callbacks[142] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_JUST_MY_CODE_HANDLE_**, CORINFO_JUST_MY_CODE_HANDLE_*>)&_getJustMyCodeHandle;
callbacks[143] = (delegate* unmanaged<IntPtr, IntPtr*, bool*, void**, bool*, void>)&_GetProfilingHandle;
callbacks[144] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_RESOLVED_TOKEN*, CORINFO_RESOLVED_TOKEN*, CORINFO_METHOD_STRUCT_*, CORINFO_CALLINFO_FLAGS, CORINFO_CALL_INFO*, void>)&_getCallInfo;
callbacks[145] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, int, int, byte, byte>)&_getStaticFieldContent;
callbacks[146] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_OBJECT_STRUCT_*, byte*, int, int, byte>)&_getObjectContent;
callbacks[147] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_FIELD_STRUCT_*, byte*, CORINFO_CLASS_STRUCT_*>)&_getStaticFieldCurrentClass;

View file

@ -1162,7 +1162,7 @@ namespace Internal.JitInterface
public uint offsetOfThreadLocalStoragePointer;
public uint offsetOfMaxThreadStaticBlocks;
public uint offsetOfThreadStaticBlocks;
public uint offsetOfGCDataPointer;
public uint offsetOfBaseOfThreadLocalData;
};

View file

@ -209,8 +209,9 @@ FUNCTIONS
const char* getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem)
void* LongLifetimeMalloc(size_t sz)
void LongLifetimeFree(void* obj)
size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection)
bool getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset)
size_t getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE clr)
size_t getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE clr)
bool getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr)
unsigned getClassSize(CORINFO_CLASS_HANDLE cls)
unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls)
@ -259,7 +260,7 @@ FUNCTIONS
unsigned getFieldOffset(CORINFO_FIELD_HANDLE field)
void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult)
uint32_t getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCtype)
void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo)
bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd)
@ -307,7 +308,6 @@ FUNCTIONS
CORINFO_JUST_MY_CODE_HANDLE getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE**ppIndirection);
void GetProfilingHandle(bool* pbHookFunction, void **pProfilerHandle, bool* pbIndirectedHandles);
void getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN_PTR pConstrainedResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO *pResult);
unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection);
bool getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects);
bool getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t *buffer, int bufferSize, int valueOffset);
CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative);

View file

@ -57,27 +57,8 @@ namespace ILCompiler
{
// ECMA types are the only ones that can have statics
ModuleFieldLayout moduleFieldLayout = _moduleFieldLayoutMap.GetOrCreateValue(ecmaType.EcmaModule);
layout.GcStatics = moduleFieldLayout.GcStatics;
layout.NonGcStatics = moduleFieldLayout.NonGcStatics;
layout.ThreadGcStatics = moduleFieldLayout.ThreadGcStatics;
layout.ThreadNonGcStatics = moduleFieldLayout.ThreadNonGcStatics;
if (defType is EcmaType nonGenericType)
{
OffsetsForType offsetsForType;
if (moduleFieldLayout.TypeOffsets.TryGetValue(nonGenericType.Handle, out offsetsForType))
{
layout.Offsets = _moduleFieldLayoutMap.CalculateTypeLayout(defType, moduleFieldLayout.Module, offsetsForType);
}
}
else if (defType is InstantiatedType instantiatedType)
{
layout.Offsets = _moduleFieldLayoutMap.GetOrAddDynamicLayout(defType, moduleFieldLayout);
}
else
{
throw new NotImplementedException();
}
}
return layout;
}
@ -86,46 +67,6 @@ namespace ILCompiler
/// </summary>
private class ModuleFieldLayoutMap : LockFreeReaderHashtable<EcmaModule, ModuleFieldLayout>
{
/// <summary>
/// CoreCLR DomainLocalModule::OffsetOfDataBlob() / sizeof(void *)
/// </summary>
private const int DomainLocalModuleDataBlobOffsetAsIntPtrCount = 6;
/// <summary>
/// CoreCLR ThreadLocalModule::OffsetOfDataBlob() / sizeof(void *)
/// </summary>
private const int ThreadLocalModuleDataBlobOffsetAsIntPtrCount = 3;
/// <summary>
/// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for X86
/// </summary>
private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobX86 = 4;
/// <summary>
/// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for Amd64
/// </summary>
private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobAmd64 = 8;
/// <summary>
/// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for Arm64
/// </summary>
private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm64 = 8;
/// <summary>
/// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for Arm
/// </summary>
private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm = 8;
/// <summary>
/// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for LoongArch64
/// </summary>
private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobLoongArch64 = 8;
/// <summary>
/// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for RISCV64
/// </summary>
private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobRISCV64 = 8;
protected override bool CompareKeyToValue(EcmaModule key, ModuleFieldLayout value)
{
return key == value.Module;
@ -138,107 +79,7 @@ namespace ILCompiler
protected override ModuleFieldLayout CreateValueFromKey(EcmaModule module)
{
int typeCountInModule = module.MetadataReader.GetTableRowCount(TableIndex.TypeDef);
int pointerSize = module.Context.Target.PointerSize;
// 0 corresponds to "normal" statics, 1 to thread-local statics
LayoutInt[] gcStatics = new LayoutInt[StaticIndex.Count]
{
LayoutInt.Zero,
LayoutInt.Zero
};
LayoutInt[] nonGcStatics = new LayoutInt[StaticIndex.Count]
{
new LayoutInt(DomainLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule),
new LayoutInt(ThreadLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule),
};
Dictionary<TypeDefinitionHandle, OffsetsForType> typeOffsets = new Dictionary<TypeDefinitionHandle, OffsetsForType>();
foreach (TypeDefinitionHandle typeDefHandle in module.MetadataReader.TypeDefinitions)
{
TypeDefinition typeDef = module.MetadataReader.GetTypeDefinition(typeDefHandle);
if (typeDef.GetGenericParameters().Count != 0)
{
// Generic types are exempt from the static field layout algorithm, see
// <a href="https://github.com/dotnet/runtime/blob/17154bd7b8f21d6d8d6fca71b89d7dcb705ec32b/src/coreclr/vm/ceeload.cpp#L931">this check</a>.
continue;
}
// 0 corresponds to "normal" statics, 1 to thread-local statics
int[] nonGcAlignment = new int[StaticIndex.Count] { 1, 1, };
int[] nonGcBytes = new int[StaticIndex.Count] { 0, 0, };
int[] gcBytes = new int[StaticIndex.Count] { 0, 0, };
foreach (FieldDefinitionHandle fieldDefHandle in typeDef.GetFields())
{
FieldDefinition fieldDef = module.MetadataReader.GetFieldDefinition(fieldDefHandle);
if ((fieldDef.Attributes & (FieldAttributes.Static | FieldAttributes.Literal)) == FieldAttributes.Static)
{
// Static RVA fields are included when approximating offsets and sizes for the module field layout, see
// <a href="https://github.com/dotnet/runtime/blob/17154bd7b8f21d6d8d6fca71b89d7dcb705ec32b/src/coreclr/vm/ceeload.cpp#L939">this loop</a>.
int index = (IsFieldThreadStatic(in fieldDef, module.MetadataReader) ? StaticIndex.ThreadLocal : StaticIndex.Regular);
int alignment;
int size;
bool isGcPointerField;
bool isGcBoxedField;
CorElementType corElementType;
EntityHandle valueTypeHandle;
GetFieldElementTypeAndValueTypeHandle(in fieldDef, module.MetadataReader, out corElementType, out valueTypeHandle);
FieldDesc fieldDesc = module.GetField(fieldDefHandle);
GetElementTypeInfo(module, fieldDesc, valueTypeHandle, corElementType, pointerSize, moduleLayout: true,
out alignment, out size, out isGcPointerField, out isGcBoxedField);
if (size != 0)
{
nonGcBytes[index] += size;
nonGcAlignment[index] = Math.Max(nonGcAlignment[index], alignment);
}
if (isGcPointerField || isGcBoxedField)
{
gcBytes[index] += pointerSize;
}
}
}
if (nonGcBytes[StaticIndex.Regular] != 0 ||
nonGcBytes[StaticIndex.ThreadLocal] != 0 ||
gcBytes[StaticIndex.Regular] != 0 ||
gcBytes[StaticIndex.ThreadLocal] != 0)
{
OffsetsForType offsetsForType = new OffsetsForType(LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate);
for (int staticIndex = 0; staticIndex < StaticIndex.Count; staticIndex++)
{
if (nonGcBytes[staticIndex] != 0)
{
offsetsForType.NonGcOffsets[staticIndex] = LayoutInt.AlignUp(nonGcStatics[staticIndex], new LayoutInt(nonGcAlignment[staticIndex]), module.Context.Target);
nonGcStatics[staticIndex] = offsetsForType.NonGcOffsets[staticIndex] + new LayoutInt(nonGcBytes[staticIndex]);
}
if (gcBytes[staticIndex] != 0)
{
offsetsForType.GcOffsets[staticIndex] = gcStatics[staticIndex];
gcStatics[staticIndex] += new LayoutInt(gcBytes[staticIndex]);
}
}
typeOffsets.Add(typeDefHandle, offsetsForType);
}
}
LayoutInt blockAlignment = new LayoutInt(TargetDetails.MaximumPrimitiveSize);
return new ModuleFieldLayout(
module,
gcStatics: new StaticsBlock() { Size = gcStatics[StaticIndex.Regular], LargestAlignment = blockAlignment },
nonGcStatics: new StaticsBlock() { Size = nonGcStatics[StaticIndex.Regular], LargestAlignment = blockAlignment },
threadGcStatics: new StaticsBlock() { Size = gcStatics[StaticIndex.ThreadLocal], LargestAlignment = blockAlignment },
threadNonGcStatics: new StaticsBlock() { Size = nonGcStatics[StaticIndex.ThreadLocal], LargestAlignment = blockAlignment },
typeOffsets: typeOffsets);
return new ModuleFieldLayout(module);
}
private void GetElementTypeInfoGeneric(
@ -405,42 +246,11 @@ namespace ILCompiler
FieldAndOffset[] fieldsForType;
if (!moduleFieldLayout.TryGetDynamicLayout(defType, out fieldsForType))
{
int nonGcOffset;
switch (moduleFieldLayout.Module.Context.Target.Architecture)
{
case TargetArchitecture.X86:
nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobX86;
break;
case TargetArchitecture.X64:
nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobAmd64;
break;
case TargetArchitecture.ARM64:
nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm64;
break;
case TargetArchitecture.ARM:
nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm;
break;
case TargetArchitecture.LoongArch64:
nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobLoongArch64;
break;
case TargetArchitecture.RiscV64:
nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobRISCV64;
break;
default:
throw new NotImplementedException();
}
OffsetsForType offsetsForType = new OffsetsForType(
nonGcOffset: new LayoutInt(nonGcOffset),
tlsNonGcOffset: new LayoutInt(nonGcOffset),
nonGcOffset: LayoutInt.Zero,
tlsNonGcOffset: new LayoutInt(2 * defType.Context.Target.PointerSize),
gcOffset: LayoutInt.Zero,
tlsGcOffset: LayoutInt.Zero);
tlsGcOffset: new LayoutInt(2 * defType.Context.Target.PointerSize));
fieldsForType = moduleFieldLayout.GetOrAddDynamicLayout(
defType,
@ -773,44 +583,24 @@ namespace ILCompiler
{
public EcmaModule Module { get; }
public StaticsBlock GcStatics { get; }
public StaticsBlock NonGcStatics { get; }
public StaticsBlock ThreadGcStatics { get; }
public StaticsBlock ThreadNonGcStatics { get; }
public IReadOnlyDictionary<TypeDefinitionHandle, OffsetsForType> TypeOffsets { get; }
private ConcurrentDictionary<DefType, FieldAndOffset[]> _genericTypeToFieldMap;
private ConcurrentDictionary<DefType, FieldAndOffset[]> _typeToFieldMap;
public ModuleFieldLayout(
EcmaModule module,
StaticsBlock gcStatics,
StaticsBlock nonGcStatics,
StaticsBlock threadGcStatics,
StaticsBlock threadNonGcStatics,
IReadOnlyDictionary<TypeDefinitionHandle, OffsetsForType> typeOffsets)
EcmaModule module)
{
Module = module;
GcStatics = gcStatics;
NonGcStatics = nonGcStatics;
ThreadGcStatics = threadGcStatics;
ThreadNonGcStatics = threadNonGcStatics;
TypeOffsets = typeOffsets;
_genericTypeToFieldMap = new ConcurrentDictionary<DefType, FieldAndOffset[]>();
_typeToFieldMap = new ConcurrentDictionary<DefType, FieldAndOffset[]>();
}
public bool TryGetDynamicLayout(DefType instantiatedType, out FieldAndOffset[] fieldMap)
{
return _genericTypeToFieldMap.TryGetValue(instantiatedType, out fieldMap);
return _typeToFieldMap.TryGetValue(instantiatedType, out fieldMap);
}
public FieldAndOffset[] GetOrAddDynamicLayout(DefType instantiatedType, FieldAndOffset[] fieldMap)
{
return _genericTypeToFieldMap.GetOrAdd(instantiatedType, fieldMap);
return _typeToFieldMap.GetOrAdd(instantiatedType, fieldMap);
}
}

View file

@ -1012,19 +1012,19 @@ namespace Internal.JitInterface
break;
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
case CorInfoHelpFunc.CORINFO_HELP_GET_GCSTATIC_BASE:
id = ReadyToRunHelper.GenericGcStaticBase;
break;
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
case CorInfoHelpFunc.CORINFO_HELP_GET_NONGCSTATIC_BASE:
id = ReadyToRunHelper.GenericNonGcStaticBase;
break;
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
case CorInfoHelpFunc.CORINFO_HELP_GET_GCTHREADSTATIC_BASE:
id = ReadyToRunHelper.GenericGcTlsBase;
break;
case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
case CorInfoHelpFunc.CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE:
id = ReadyToRunHelper.GenericNonGcTlsBase;
break;
@ -1714,14 +1714,14 @@ namespace Internal.JitInterface
if (field.IsThreadStatic)
{
pResult->helper = (field.HasGCStaticBase ?
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE :
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE);
CorInfoHelpFunc.CORINFO_HELP_GET_GCTHREADSTATIC_BASE :
CorInfoHelpFunc.CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE);
}
else
{
pResult->helper = (field.HasGCStaticBase ?
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE :
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE);
CorInfoHelpFunc.CORINFO_HELP_GET_GCSTATIC_BASE :
CorInfoHelpFunc.CORINFO_HELP_GET_NONGCSTATIC_BASE);
}
if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && (fieldOffset <= FieldFixupSignature.MaxCheckableOffset))

View file

@ -57,8 +57,9 @@ struct JitInterfaceCallbacks
const char* (* getAssemblyName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_ASSEMBLY_HANDLE assem);
void* (* LongLifetimeMalloc)(void * thisHandle, CorInfoExceptionClass** ppException, size_t sz);
void (* LongLifetimeFree)(void * thisHandle, CorInfoExceptionClass** ppException, void* obj);
size_t (* getClassModuleIdForStatics)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection);
bool (* getIsClassInitedFlagAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset);
size_t (* getClassThreadStaticDynamicInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE clr);
size_t (* getClassStaticDynamicInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE clr);
bool (* getStaticBaseAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr);
unsigned (* getClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls);
unsigned (* getHeapClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls);
@ -107,7 +108,7 @@ struct JitInterfaceCallbacks
unsigned (* getFieldOffset)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field);
void (* getFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult);
uint32_t (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool isGCtype);
void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType);
void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo);
void (* getThreadLocalStaticInfo_NativeAOT)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo);
bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd);
int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd);
@ -155,7 +156,6 @@ struct JitInterfaceCallbacks
CORINFO_JUST_MY_CODE_HANDLE (* getJustMyCodeHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE** ppIndirection);
void (* GetProfilingHandle)(void * thisHandle, CorInfoExceptionClass** ppException, bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles);
void (* getCallInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult);
unsigned (* getClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, void** ppIndirection);
bool (* getStaticFieldContent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects);
bool (* getObjectContent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset);
CORINFO_CLASS_HANDLE (* getStaticFieldCurrentClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool* pIsSpeculative);
@ -649,17 +649,6 @@ public:
if (pException != nullptr) throw pException;
}
virtual size_t getClassModuleIdForStatics(
CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection)
{
CorInfoExceptionClass* pException = nullptr;
size_t temp = _callbacks->getClassModuleIdForStatics(_thisHandle, &pException, cls, pModule, ppIndirection);
if (pException != nullptr) throw pException;
return temp;
}
virtual bool getIsClassInitedFlagAddress(
CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
@ -671,6 +660,24 @@ public:
return temp;
}
virtual size_t getClassThreadStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
CorInfoExceptionClass* pException = nullptr;
size_t temp = _callbacks->getClassThreadStaticDynamicInfo(_thisHandle, &pException, clr);
if (pException != nullptr) throw pException;
return temp;
}
virtual size_t getClassStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
CorInfoExceptionClass* pException = nullptr;
size_t temp = _callbacks->getClassStaticDynamicInfo(_thisHandle, &pException, clr);
if (pException != nullptr) throw pException;
return temp;
}
virtual bool getStaticBaseAddress(
CORINFO_CLASS_HANDLE cls,
bool isGc,
@ -1142,11 +1149,10 @@ public:
}
virtual void getThreadLocalStaticBlocksInfo(
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo,
bool isGCType)
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
CorInfoExceptionClass* pException = nullptr;
_callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo, isGCType);
_callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo);
if (pException != nullptr) throw pException;
}
@ -1596,16 +1602,6 @@ public:
if (pException != nullptr) throw pException;
}
virtual unsigned getClassDomainID(
CORINFO_CLASS_HANDLE cls,
void** ppIndirection)
{
CorInfoExceptionClass* pException = nullptr;
unsigned temp = _callbacks->getClassDomainID(_thisHandle, &pException, cls, ppIndirection);
if (pException != nullptr) throw pException;
return temp;
}
virtual bool getStaticFieldContent(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,

View file

@ -541,7 +541,7 @@ struct Agnostic_GetThreadLocalStaticBlocksInfo
DWORD offsetOfThreadLocalStoragePointer;
DWORD offsetOfMaxThreadStaticBlocks;
DWORD offsetOfThreadStaticBlocks;
DWORD offsetOfGCDataPointer;
DWORD offsetOfBaseOfThreadLocalData;
};
struct Agnostic_GetThreadStaticInfo_NativeAOT

View file

@ -60,7 +60,8 @@ LWM(GetCastingHelper, Agnostic_GetCastingHelper, DWORD)
LWM(GetChildType, DWORDLONG, DLD)
LWM(GetClassAlignmentRequirement, DLD, DWORD)
LWM(GetClassAttribs, DWORDLONG, DWORD)
LWM(GetClassDomainID, DWORDLONG, DLD)
LWM(GetClassStaticDynamicInfo, DWORDLONG, DLD)
LWM(GetClassThreadStaticDynamicInfo, DWORDLONG, DLD)
LWM(GetClassGClayout, DWORDLONG, Agnostic_GetClassGClayout)
LWM(GetClassModuleIdForStatics, DWORDLONG, Agnostic_GetClassModuleIdForStatics)
LWM(GetIsClassInitedFlagAddress, DWORDLONG, Agnostic_GetIsClassInitedFlagAddress)

View file

@ -3620,7 +3620,7 @@ uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, b
return value;
}
void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
if (GetThreadLocalStaticBlocksInfo == nullptr)
GetThreadLocalStaticBlocksInfo = new LightWeightMap<DWORD, Agnostic_GetThreadLocalStaticBlocksInfo>();
@ -3635,10 +3635,10 @@ void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC
value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer;
value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks;
value.offsetOfThreadStaticBlocks = pInfo->offsetOfThreadStaticBlocks;
value.offsetOfGCDataPointer = pInfo->offsetOfGCDataPointer;
value.offsetOfBaseOfThreadLocalData = pInfo->offsetOfBaseOfThreadLocalData;
// This data is same for entire process, so just add it against key '0'.
DWORD key = isGCType ? 0 : 1;
DWORD key = 0;
GetThreadLocalStaticBlocksInfo->Add(key, value);
DEBUG_REC(dmpGetThreadLocalStaticBlocksInfo(key, value));
}
@ -3648,16 +3648,18 @@ void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_
printf("GetThreadLocalStaticBlocksInfo key %u, tlsIndex-%s, "
", tlsGetAddrFtnPtr-%016" PRIX64 ", tlsIndexObject - %016" PRIX64
", threadVarsSection - %016" PRIX64
", offsetOfThreadLocalStoragePointer-%u, offsetOfMaxThreadStaticBlocks-%u"
", offsetOfThreadStaticBlocks-%u, offsetOfGCDataPointer-%u",
", offsetOfThreadLocalStoragePointer-%u"
", offsetOfMaxThreadStaticBlocks-%u"
", offsetOfThreadStaticBlocks-%u"
", offsetOfBaseOfThreadLocalData-%u",
key, SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndex).c_str(), value.tlsGetAddrFtnPtr,
value.tlsIndexObject, value.threadVarsSection, value.offsetOfThreadLocalStoragePointer,
value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfGCDataPointer);
value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfBaseOfThreadLocalData);
}
void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
int key = isGCType ? 0 : 1;
int key = 0;
Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key %u", key);
DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(key, value));
@ -3669,7 +3671,7 @@ void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC
pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer;
pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks;
pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks;
pInfo->offsetOfGCDataPointer = value.offsetOfGCDataPointer;
pInfo->offsetOfBaseOfThreadLocalData = value.offsetOfBaseOfThreadLocalData;
}
void MethodContext::recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo)
@ -4647,37 +4649,60 @@ int32_t* MethodContext::repGetAddrOfCaptureThreadGlobal(void** ppIndirection)
return (int32_t*)value.B;
}
void MethodContext::recGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection, unsigned result)
void MethodContext::recGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result)
{
if (GetClassDomainID == nullptr)
GetClassDomainID = new LightWeightMap<DWORDLONG, DLD>();
if (GetClassStaticDynamicInfo == nullptr)
GetClassStaticDynamicInfo = new LightWeightMap<DWORDLONG, DLD>();
DLD value;
if (ppIndirection != nullptr)
value.A = CastPointer(*ppIndirection);
else
value.A = 0;
value.B = (DWORD)result;
value.A = result;
value.B = 0;
DWORDLONG key = CastHandle(cls);
GetClassDomainID->Add(key, value);
DEBUG_REC(dmpGetClassDomainID(key, value));
GetClassStaticDynamicInfo->Add(key, value);
DEBUG_REC(dmpGetClassStaticDynamicInfo(key, value));
}
void MethodContext::dmpGetClassDomainID(DWORDLONG key, DLD value)
void MethodContext::dmpGetClassStaticDynamicInfo(DWORDLONG key, DLD value)
{
printf("GetClassDomainID key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B);
printf("GetClassStaticDynamicInfo key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B);
}
unsigned MethodContext::repGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection)
size_t MethodContext::repGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
DWORDLONG key = CastHandle(cls);
DLD value = LookupByKeyOrMiss(GetClassDomainID, key, ": key %016" PRIX64 "", key);
DLD value = LookupByKeyOrMiss(GetClassStaticDynamicInfo, key, ": key %016" PRIX64 "", key);
DEBUG_REP(dmpGetClassDomainID(key, value));
DEBUG_REP(dmpGetClassStaticDynamicInfo(key, value));
if (ppIndirection != nullptr)
*ppIndirection = (void*)value.A;
return (unsigned)value.B;
return (size_t)value.A;
}
void MethodContext::recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result)
{
if (GetClassThreadStaticDynamicInfo == nullptr)
GetClassThreadStaticDynamicInfo = new LightWeightMap<DWORDLONG, DLD>();
DLD value;
value.A = result;
value.B = 0;
DWORDLONG key = CastHandle(cls);
GetClassThreadStaticDynamicInfo->Add(key, value);
DEBUG_REC(dmpGetClassThreadStaticDynamicInfo(key, value));
}
void MethodContext::dmpGetClassThreadStaticDynamicInfo(DWORDLONG key, DLD value)
{
printf("GetClassThreadStaticDynamicInfo key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B);
}
size_t MethodContext::repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
DWORDLONG key = CastHandle(cls);
DLD value = LookupByKeyOrMiss(GetClassThreadStaticDynamicInfo, key, ": key %016" PRIX64 "", key);
DEBUG_REP(dmpGetClassThreadStaticDynamicInfo(key, value));
return (size_t)value.A;
}
void MethodContext::recGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* result)

View file

@ -484,9 +484,9 @@ public:
void dmpGetThreadLocalFieldInfo(DLD key, DWORD value);
uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType);
void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType);
void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo);
void dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value);
void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType);
void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo);
void recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo);
void dmpGetThreadLocalStaticInfo_NativeAOT(DWORDLONG key, const Agnostic_GetThreadStaticInfo_NativeAOT& value);
@ -592,9 +592,13 @@ public:
void dmpGetAddrOfCaptureThreadGlobal(DWORD key, DLDL value);
int32_t* repGetAddrOfCaptureThreadGlobal(void** ppIndirection);
void recGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection, unsigned result);
void dmpGetClassDomainID(DWORDLONG key, DLD value);
unsigned repGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection);
void recGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result);
void dmpGetClassStaticDynamicInfo(DWORDLONG key, DLD value);
size_t repGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls);
void recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result);
void dmpGetClassThreadStaticDynamicInfo(DWORDLONG key, DLD value);
size_t repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls);
void recGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* result);
void dmpGetLocationOfThisType(DWORDLONG key, const Agnostic_CORINFO_LOOKUP_KIND& value);
@ -998,7 +1002,7 @@ enum mcPackets
Packet_GetChildType = 39,
Packet_GetClassAlignmentRequirement = 40,
Packet_GetClassAttribs = 41,
Packet_GetClassDomainID = 42,
//Packet_GetClassDomainID = 42,
Packet_GetClassGClayout = 43,
Packet_GetClassModuleIdForStatics = 44,
Packet_GetClassName = 45,
@ -1170,6 +1174,8 @@ enum mcPackets
Packet_IsExactType = 215,
Packet_GetSwiftLowering = 216,
Packet_IsNullableType = 217,
Packet_GetClassStaticDynamicInfo = 218,
Packet_GetClassThreadStaticDynamicInfo = 219,
};
void SetDebugDumpVariables();

View file

@ -530,15 +530,6 @@ void interceptor_ICJI::LongLifetimeFree(void* obj)
original_ICorJitInfo->LongLifetimeFree(obj);
}
size_t interceptor_ICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection)
{
mc->cr->AddCall("getClassModuleIdForStatics");
size_t temp = original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection);
mc->recGetClassModuleIdForStatics(cls, pModule, ppIndirection, temp);
return temp;
}
bool interceptor_ICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
@ -1082,11 +1073,11 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, b
return result;
}
void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
mc->cr->AddCall("getThreadLocalStaticBlocksInfo");
original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType);
mc->recGetThreadLocalStaticBlocksInfo(pInfo, isGCType);
original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo);
mc->recGetThreadLocalStaticBlocksInfo(pInfo);
}
void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo)
@ -1640,12 +1631,19 @@ void interceptor_ICJI::getCallInfo(
});
}
// returns the class's domain ID for accessing shared statics
unsigned interceptor_ICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection)
size_t interceptor_ICJI::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
mc->cr->AddCall("getClassDomainID");
unsigned temp = original_ICorJitInfo->getClassDomainID(cls, ppIndirection);
mc->recGetClassDomainID(cls, ppIndirection, temp);
mc->cr->AddCall("getClassStaticDynamicInfo");
size_t temp = original_ICorJitInfo->getClassStaticDynamicInfo(cls);
mc->recGetClassStaticDynamicInfo(cls, temp);
return temp;
}
size_t interceptor_ICJI::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
mc->cr->AddCall("getClassThreadStaticDynamicInfo");
size_t temp = original_ICorJitInfo->getClassThreadStaticDynamicInfo(cls);
mc->recGetClassThreadStaticDynamicInfo(cls, temp);
return temp;
}

View file

@ -383,15 +383,6 @@ void interceptor_ICJI::LongLifetimeFree(
original_ICorJitInfo->LongLifetimeFree(obj);
}
size_t interceptor_ICJI::getClassModuleIdForStatics(
CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection)
{
mcs->AddCall("getClassModuleIdForStatics");
return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection);
}
bool interceptor_ICJI::getIsClassInitedFlagAddress(
CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
@ -401,6 +392,20 @@ bool interceptor_ICJI::getIsClassInitedFlagAddress(
return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset);
}
size_t interceptor_ICJI::getClassThreadStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
mcs->AddCall("getClassThreadStaticDynamicInfo");
return original_ICorJitInfo->getClassThreadStaticDynamicInfo(clr);
}
size_t interceptor_ICJI::getClassStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
mcs->AddCall("getClassStaticDynamicInfo");
return original_ICorJitInfo->getClassStaticDynamicInfo(clr);
}
bool interceptor_ICJI::getStaticBaseAddress(
CORINFO_CLASS_HANDLE cls,
bool isGc,
@ -779,11 +784,10 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo(
}
void interceptor_ICJI::getThreadLocalStaticBlocksInfo(
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo,
bool isGCType)
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
mcs->AddCall("getThreadLocalStaticBlocksInfo");
original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType);
original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo);
}
void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT(
@ -1167,14 +1171,6 @@ void interceptor_ICJI::getCallInfo(
original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult);
}
unsigned interceptor_ICJI::getClassDomainID(
CORINFO_CLASS_HANDLE cls,
void** ppIndirection)
{
mcs->AddCall("getClassDomainID");
return original_ICorJitInfo->getClassDomainID(cls, ppIndirection);
}
bool interceptor_ICJI::getStaticFieldContent(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,

View file

@ -337,14 +337,6 @@ void interceptor_ICJI::LongLifetimeFree(
original_ICorJitInfo->LongLifetimeFree(obj);
}
size_t interceptor_ICJI::getClassModuleIdForStatics(
CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection)
{
return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection);
}
bool interceptor_ICJI::getIsClassInitedFlagAddress(
CORINFO_CLASS_HANDLE cls,
CORINFO_CONST_LOOKUP* addr,
@ -353,6 +345,18 @@ bool interceptor_ICJI::getIsClassInitedFlagAddress(
return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset);
}
size_t interceptor_ICJI::getClassThreadStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
return original_ICorJitInfo->getClassThreadStaticDynamicInfo(clr);
}
size_t interceptor_ICJI::getClassStaticDynamicInfo(
CORINFO_CLASS_HANDLE clr)
{
return original_ICorJitInfo->getClassStaticDynamicInfo(clr);
}
bool interceptor_ICJI::getStaticBaseAddress(
CORINFO_CLASS_HANDLE cls,
bool isGc,
@ -683,10 +687,9 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo(
}
void interceptor_ICJI::getThreadLocalStaticBlocksInfo(
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo,
bool isGCType)
CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType);
original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo);
}
void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT(
@ -1023,13 +1026,6 @@ void interceptor_ICJI::getCallInfo(
original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult);
}
unsigned interceptor_ICJI::getClassDomainID(
CORINFO_CLASS_HANDLE cls,
void** ppIndirection)
{
return original_ICorJitInfo->getClassDomainID(cls, ppIndirection);
}
bool interceptor_ICJI::getStaticFieldContent(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,

View file

@ -455,12 +455,16 @@ void MyICJI::LongLifetimeFree(void* obj)
DebugBreakorAV(33);
}
size_t MyICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls,
CORINFO_MODULE_HANDLE* pModule,
void** ppIndirection)
size_t MyICJI::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
jitInstance->mc->cr->AddCall("getClassModuleIdForStatics");
return jitInstance->mc->repGetClassModuleIdForStatics(cls, pModule, ppIndirection);
jitInstance->mc->cr->AddCall("getClassThreadStaticDynamicInfo");
return jitInstance->mc->repGetClassThreadStaticDynamicInfo(cls);
}
size_t MyICJI::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
jitInstance->mc->cr->AddCall("getClassStaticDynamicInfo");
return jitInstance->mc->repGetClassStaticDynamicInfo(cls);
}
bool MyICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls,
@ -898,10 +902,10 @@ uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCTy
return jitInstance->mc->repGetThreadLocalFieldInfo(field, isGCType);
}
void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
jitInstance->mc->cr->AddCall("getThreadLocalStaticBlocksInfo");
jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo, isGCType);
jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo);
}
void MyICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo)
@ -1433,13 +1437,6 @@ void MyICJI::getCallInfo(
ThrowRecordedException(exceptionCode);
}
// returns the class's domain ID for accessing shared statics
unsigned MyICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection)
{
jitInstance->mc->cr->AddCall("getClassDomainID");
return jitInstance->mc->repGetClassDomainID(cls, ppIndirection);
}
bool MyICJI::getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects)
{
jitInstance->mc->cr->AddCall("getStaticFieldContent");

View file

@ -3,9 +3,6 @@
; ***********************************************************************
; File: JitHelpers_SingleAppDomain.asm
;
; Notes: JIT Static access helpers when coreclr host specifies single
; appdomain flag
; ***********************************************************************
include AsmMacros.inc
@ -14,45 +11,34 @@ include asmconstants.inc
; Min amount of stack space that a nested function should allocate.
MIN_SIZE equ 28h
extern JIT_GetSharedNonGCStaticBase_Helper:proc
extern JIT_GetSharedGCStaticBase_Helper:proc
extern JIT_GetDynamicNonGCStaticBase_Portable:proc
extern JIT_GetDynamicGCStaticBase_Portable:proc
LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT
; If class is not initialized, bail to C++ helper
test byte ptr [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1
jz CallHelper
mov rax, rcx
mov rax, [rcx + OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics]
test al, 1
jnz CallHelper
REPRET
align 16
CallHelper:
; Tail call JIT_GetSharedNonGCStaticBase_Helper
jmp JIT_GetSharedNonGCStaticBase_Helper
LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
; Tail call JIT_GetDynamicNonGCStaticBase_Portable
jmp JIT_GetDynamicNonGCStaticBase_Portable
LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
mov rax, rcx
ret
LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT
; If class is not initialized, bail to C++ helper
test byte ptr [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1
jz CallHelper
mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics]
mov rax, [rcx + OFFSETOF__DynamicStaticsInfo__m_pGCStatics]
test al, 1
jnz CallHelper
REPRET
align 16
CallHelper:
; Tail call Jit_GetSharedGCStaticBase_Helper
jmp JIT_GetSharedGCStaticBase_Helper
LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics]
ret
LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
; Tail call JIT_GetDynamicGCStaticBase_Portable
jmp JIT_GetDynamicGCStaticBase_Portable
LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT
end

View file

@ -55,9 +55,6 @@ extern g_pStringClass:QWORD
extern FramedAllocateString:proc
extern JIT_NewArr1:proc
extern JIT_GetSharedNonGCStaticBase_Helper:proc
extern JIT_GetSharedGCStaticBase_Helper:proc
extern JIT_InternalThrow:proc
ifdef _DEBUG

View file

@ -194,22 +194,15 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__InterfaceInfo_t__m_pMethodTable
ASMCONSTANTS_C_ASSERT(SIZEOF__InterfaceInfo_t
== sizeof(InterfaceInfo_t));
#define OFFSETOF__DomainLocalModule__m_pDataBlob 0x030
ASMCONSTANTS_C_ASSERT(OFFSETOF__DomainLocalModule__m_pDataBlob
== offsetof(DomainLocalModule, m_pDataBlob));
ASMCONSTANTS_C_ASSERT(MethodTableAuxiliaryData::enum_flag_Initialized == 0x1);
// If this changes then we can't just test one bit in the assembly code.
ASMCONSTANTS_C_ASSERT(ClassInitFlags::INITIALIZED_FLAG == 1);
#define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8
ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics
== offsetof(DynamicStaticsInfo, m_pNonGCStatics));
// End for JIT_GetSharedNonGCStaticBaseWorker
// For JIT_GetSharedGCStaticBaseWorker
#define OFFSETOF__DomainLocalModule__m_pGCStatics 0x020
ASMCONSTANTS_C_ASSERT(OFFSETOF__DomainLocalModule__m_pGCStatics
== offsetof(DomainLocalModule, m_pGCStatics));
// End for JIT_GetSharedGCStaticBaseWorker
#define OFFSETOF__DynamicStaticsInfo__m_pGCStatics 0
ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pGCStatics
== offsetof(DynamicStaticsInfo, m_pGCStatics));
#define CORINFO_NullReferenceException_ASM 0
ASMCONSTANTS_C_ASSERT( CORINFO_NullReferenceException_ASM

View file

@ -609,11 +609,7 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool
//
// Create alias for optimized implementations of helpers provided on this platform
//
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_SingleAppDomain
#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_SingleAppDomain
#endif // __cgencpu_h__

View file

@ -10,39 +10,29 @@
// appdomain flag
//
LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
test byte ptr [rdi + OFFSETOF__DomainLocalModule__m_pDataBlob + rsi], 1
jz CallHelper
mov rax, rdi
mov rax, [rdi + OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics]
test al, 1
jnz CallHelper
rep ret
.balign 16
CallHelper:
// Tail call JIT_GetSharedNonGCStaticBase_Helper
jmp C_FUNC(JIT_GetSharedNonGCStaticBase_Helper)
LEAF_END_MARKED JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
jmp C_FUNC(JIT_GetDynamicNonGCStaticBase_Portable)
LEAF_END_MARKED JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
mov rax, rdi
ret
LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
test byte ptr [rdi + OFFSETOF__DomainLocalModule__m_pDataBlob + rsi], 1
jz CallHelper1
mov rax, [rdi + OFFSETOF__DomainLocalModule__m_pGCStatics]
mov rax, [rdi + OFFSETOF__DynamicStaticsInfo__m_pGCStatics]
test al, 1
jnz CallHelper1
rep ret
.balign 16
CallHelper1:
// Tail call Jit_GetSharedGCStaticBase_Helper
jmp C_FUNC(JIT_GetSharedGCStaticBase_Helper)
LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
jmp C_FUNC(JIT_GetDynamicGCStaticBase_Portable)
LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
mov rax, [rdi + OFFSETOF__DomainLocalModule__m_pGCStatics]
ret
LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT

View file

@ -439,118 +439,6 @@ void PinnedHeapHandleTable::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
}
}
// Constructor for the ThreadStaticHandleBucket class.
ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
: m_pNext(pNext)
, m_ArraySize(Size)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
PRECONDITION(CheckPointer(pDomain));
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACTL_END;
PTRARRAYREF HandleArrayObj;
// Allocate the array on the GC heap.
OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass);
// Store the array in a strong handle to keep it alive.
m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
}
// Destructor for the ThreadStaticHandleBucket class.
ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
}
CONTRACTL_END;
if (m_hndHandleArray)
{
DestroyStrongHandle(m_hndHandleArray);
m_hndHandleArray = NULL;
}
}
// Allocate handles from the bucket.
OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
}
CONTRACTL_END;
return m_hndHandleArray;
}
// Constructor for the ThreadStaticHandleTable class.
ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
: m_pHead(NULL)
, m_pDomain(pDomain)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
PRECONDITION(CheckPointer(pDomain));
}
CONTRACTL_END;
}
// Destructor for the ThreadStaticHandleTable class.
ThreadStaticHandleTable::~ThreadStaticHandleTable()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;
// Delete the buckets.
while (m_pHead)
{
ThreadStaticHandleBucket *pOld = m_pHead;
m_pHead = pOld->GetNext();
delete pOld;
}
}
// Allocate handles from the large heap handle table.
OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
PRECONDITION(nRequested > 0);
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACTL_END;
// create a new bucket for this allocation
m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
return m_pHead->GetHandles();
}
//*****************************************************************************
// BaseDomain
//*****************************************************************************
@ -612,7 +500,7 @@ void BaseDomain::Init()
m_DomainCrst.Init(CrstBaseDomain);
m_DomainCacheCrst.Init(CrstAppDomainCache);
m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
m_crstGenericDictionaryExpansionLock.Init(CrstGenericDictionaryExpansion);
// NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
// If you remove this flag, we will switch to preemptive mode when entering
@ -637,7 +525,6 @@ void BaseDomain::Init()
m_NativeTypeLoadLock.Init(CrstInteropData, CrstFlags(CRST_REENTRANCY), TRUE);
m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
m_crstStaticBoxInitLock.Init(CrstStaticBoxInit);
// Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
@ -665,14 +552,6 @@ void BaseDomain::InitVSD()
GetLoaderAllocator()->InitVirtualCallStubManager(this);
}
void BaseDomain::InitThreadStaticBlockTypeMap()
{
STANDARD_VM_CONTRACT;
m_NonGCThreadStaticBlockTypeIDMap.Init();
m_GCThreadStaticBlockTypeIDMap.Init();
}
void BaseDomain::ClearBinderContext()
{
CONTRACTL
@ -793,7 +672,7 @@ void AppDomain::SetNativeDllSearchDirectories(LPCWSTR wszNativeDllSearchDirector
}
}
OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate)
OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, DynamicStaticsInfo* pStaticsInfo, MethodTable *pMTToFillWithStaticBoxes)
{
CONTRACTL
{
@ -805,10 +684,10 @@ OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF*
}
CONTRACTL_END;
if (ppLazyAllocate && *ppLazyAllocate)
if (pStaticsInfo && pStaticsInfo->GetGCStaticsPointer() != NULL)
{
// Allocation already happened
return *ppLazyAllocate;
return pStaticsInfo->GetGCStaticsPointer();
}
GCX_COOP();
@ -819,15 +698,21 @@ OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF*
// Allocate the handles.
OBJECTREF* result = m_pPinnedHeapHandleTable->AllocateHandles(nRequested);
if (ppLazyAllocate)
if (pMTToFillWithStaticBoxes != NULL)
{
GCPROTECT_BEGININTERIOR(result);
pMTToFillWithStaticBoxes->AllocateRegularStaticBoxes(&result);
GCPROTECT_END();
}
if (pStaticsInfo)
{
// race with other threads that might be doing the same concurrent allocation
if (InterlockedCompareExchangeT<OBJECTREF*>(ppLazyAllocate, result, NULL) != NULL)
if (!pStaticsInfo->InterlockedUpdateStaticsPointer(/*isGCPointer*/ true, (TADDR)result))
{
// we lost the race, release our handles and use the handles from the
// winning thread
m_pPinnedHeapHandleTable->ReleaseHandles(result, nRequested);
result = *ppLazyAllocate;
result = pStaticsInfo->GetGCStaticsPointer();
}
}
@ -970,9 +855,6 @@ void SystemDomain::Attach()
m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
// Initialize the ID dispenser that is used for domain neutral module IDs
g_pModuleIndexDispenser = new IdDispenser();
// Create the global SystemDomain and initialize it.
m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
// No way it can fail since g_pSystemDomainMemory is a static array.
@ -1329,9 +1211,6 @@ void SystemDomain::LoadBaseSystemClasses()
// Load the Object array class.
g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass));
// We have delayed allocation of CoreLib's static handles until we load the object class
CoreLibBinder::GetModule()->AllocateRegularStaticHandles();
// Boolean has to be loaded first to break cycle in IComparisonOperations and IEqualityOperators
CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_BOOLEAN);
@ -1776,9 +1655,6 @@ void AppDomain::Create()
// allocate a Virtual Call Stub Manager for the default domain
pDomain->InitVSD();
// allocate a thread static block to index map
pDomain->InitThreadStaticBlockTypeMap();
pDomain->SetStage(AppDomain::STAGE_OPEN);
pDomain->CreateDefaultBinder();
@ -3057,18 +2933,16 @@ void AppDomain::SetupSharedStatics()
// Because we are allocating/referencing objects, need to be in cooperative mode
GCX_COOP();
DomainLocalModule *pLocalModule = CoreLibBinder::GetModule()->GetDomainLocalModule();
// This is a convenient place to initialize String.Empty.
// It is treated as intrinsic by the JIT as so the static constructor would never run.
// Leaving it uninitialized would confuse debuggers.
// String should not have any static constructors.
_ASSERTE(g_pStringClass->IsClassPreInited());
// String should not have any static constructors, so this should be safe. It will just ensure that statics are allocated
g_pStringClass->CheckRunClassInitThrowing();
FieldDesc * pEmptyStringFD = CoreLibBinder::GetField(FIELD__STRING__EMPTY);
OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
((TADDR)g_pStringClass->GetDynamicStaticsInfo()->m_pGCStatics+pEmptyStringFD->GetOffset());
SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString());
}
@ -4082,284 +3956,8 @@ void AppDomain::ExceptionUnwind(Frame *pFrame)
#endif // !DACCESS_COMPILE
DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
} CONTRACTL_END;
{
CONSISTENCY_CHECK(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics());
}
if (pMT->IsDynamicStatics())
{
_ASSERTE(!pMT->ContainsGenericVariables());
DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
if(m_aDynamicEntries <= dynamicClassID)
return FALSE;
return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
}
else
{
if (iClassIndex == (DWORD)-1)
iClassIndex = pMT->GetClassIndex();
return GetPrecomputedStaticsClassData()[iClassIndex];
}
}
#ifndef DACCESS_COMPILE
void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
BaseDomain::DomainLocalBlockLockHolder lh(AppDomain::GetCurrentDomain());
_ASSERTE(!IsClassInitialized(pMT));
_ASSERTE(!IsClassInitError(pMT));
SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
}
void DomainLocalModule::SetClassInitError(MethodTable* pMT)
{
WRAPPER_NO_CONTRACT;
BaseDomain::DomainLocalBlockLockHolder lh(AppDomain::GetCurrentDomain());
SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
}
void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
PRECONDITION(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics());
// Assumes BaseDomain::DomainLocalBlockLockHolder is taken
PRECONDITION(AppDomain::GetCurrentDomain()->OwnDomainLocalBlockLock());
} CONTRACTL_END;
if (pMT->IsDynamicStatics())
{
_ASSERTE(!pMT->ContainsGenericVariables());
DWORD dwID = pMT->GetModuleDynamicEntryID();
EnsureDynamicClassIndex(dwID);
m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
}
else
{
GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
}
}
void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
INJECT_FAULT(COMPlusThrowOM(););
// Assumes BaseDomain::DomainLocalBlockLockHolder is taken
PRECONDITION(AppDomain::GetCurrentDomain()->OwnDomainLocalBlockLock());
}
CONTRACTL_END;
SIZE_T oldDynamicEntries = m_aDynamicEntries.Load();
if (dwID < oldDynamicEntries)
{
_ASSERTE(m_pDynamicClassTable.Load() != NULL);
return;
}
SIZE_T aDynamicEntries = max<SIZE_T>(16, oldDynamicEntries);
while (aDynamicEntries <= dwID)
{
aDynamicEntries *= 2;
}
DynamicClassInfo* pNewDynamicClassTable;
pNewDynamicClassTable = (DynamicClassInfo*)
(void*)GetDomainAssembly()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
if (oldDynamicEntries != 0)
{
memcpy((void*)pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * oldDynamicEntries);
}
// Note: Memory allocated on loader heap is zero filled
// memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
_ASSERTE(m_aDynamicEntries%2 == 0);
// Commit new dynamic table. The lock-free helpers depend on the order.
MemoryBarrier();
m_pDynamicClassTable = pNewDynamicClassTable;
MemoryBarrier();
m_aDynamicEntries = aDynamicEntries;
}
void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
// Assumes BaseDomain::DomainLocalBlockLockHolder is taken
PRECONDITION(AppDomain::GetCurrentDomain()->OwnDomainLocalBlockLock());
}
CONTRACTL_END;
_ASSERTE(!pMT->ContainsGenericVariables());
_ASSERTE(!pMT->IsSharedByGenericInstantiations());
_ASSERTE(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics());
_ASSERTE(pMT->IsDynamicStatics());
DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
EnsureDynamicClassIndex(dynamicEntryIDIndex);
_ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
EEClass *pClass = pMT->GetClass();
DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
_ASSERTE(!IsClassAllocated(pMT));
_ASSERTE(!IsClassInitialized(pMT));
_ASSERTE(!IsClassInitError(pMT));
DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
// We need this check because maybe a class had a cctor but no statics
if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
{
if (pDynamicStatics == NULL)
{
LoaderHeap * pLoaderAllocator = GetDomainAssembly()->GetLoaderAllocator()->GetHighFrequencyHeap();
if (pMT->Collectible())
{
pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
}
else
{
SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
#ifdef FEATURE_64BIT_ALIGNMENT
// Allocate memory with extra alignment only if it is really necessary
if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
{
static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
}
else
#endif
pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
}
// Note: Memory allocated on loader heap is zero filled
m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
}
if (pMT->Collectible() && (dwStaticBytes != 0))
{
GCX_COOP();
OBJECTREF nongcStaticsArray = NULL;
GCPROTECT_BEGIN(nongcStaticsArray);
#ifdef FEATURE_64BIT_ALIGNMENT
// Allocate memory with extra alignment only if it is really necessary
if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
else
#endif
nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
GCPROTECT_END();
}
if (dwNumHandleStatics > 0)
{
if (!pMT->Collectible())
{
GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
&((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
}
else
{
GCX_COOP();
OBJECTREF gcStaticsArray = NULL;
GCPROTECT_BEGIN(gcStaticsArray);
gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
GCPROTECT_END();
}
}
}
}
void DomainLocalModule::PopulateClass(MethodTable *pMT)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
}
CONTRACTL_END;
_ASSERTE(!pMT->ContainsGenericVariables());
// <todo> the only work actually done here for non-dynamics is the freezing related work.
// See if we can eliminate this and make this a dynamic-only path </todo>
DWORD iClassIndex = pMT->GetClassIndex();
if (!IsClassAllocated(pMT, iClassIndex))
{
BaseDomain::DomainLocalBlockLockHolder lh(AppDomain::GetCurrentDomain());
if (!IsClassAllocated(pMT, iClassIndex))
{
// Allocate dynamic space if necessary
if (pMT->IsDynamicStatics())
AllocateDynamicClass(pMT);
// determine flags to set on the statics block
DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
{
_ASSERTE(!IsClassInitialized(pMT));
_ASSERTE(!IsClassInitError(pMT));
dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
}
if (pMT->Collectible())
{
dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
}
// Set all flags at the same time to avoid races
SetClassFlags(pMT, dwFlags);
}
}
return;
}
DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
{
CONTRACTL
@ -4660,55 +4258,6 @@ PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
return pMT;
}
//------------------------------------------------------------------------
UINT32 BaseDomain::GetNonGCThreadStaticTypeIndex(PTR_MethodTable pMT)
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
} CONTRACTL_END;
return m_NonGCThreadStaticBlockTypeIDMap.GetTypeID(pMT, false);
}
//------------------------------------------------------------------------
PTR_MethodTable BaseDomain::LookupNonGCThreadStaticBlockType(UINT32 id) {
CONTRACTL {
NOTHROW;
WRAPPER(GC_TRIGGERS);
CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
} CONTRACTL_END;
PTR_MethodTable pMT = m_NonGCThreadStaticBlockTypeIDMap.LookupType(id);
CONSISTENCY_CHECK(CheckPointer(pMT));
return pMT;
}
//------------------------------------------------------------------------
UINT32 BaseDomain::GetGCThreadStaticTypeIndex(PTR_MethodTable pMT)
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
} CONTRACTL_END;
return m_GCThreadStaticBlockTypeIDMap.GetTypeID(pMT, false);
}
//------------------------------------------------------------------------
PTR_MethodTable BaseDomain::LookupGCThreadStaticBlockType(UINT32 id) {
CONTRACTL {
NOTHROW;
WRAPPER(GC_TRIGGERS);
CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
} CONTRACTL_END;
PTR_MethodTable pMT = m_GCThreadStaticBlockTypeIDMap.LookupType(id);
CONSISTENCY_CHECK(CheckPointer(pMT));
return pMT;
}
#ifndef DACCESS_COMPILE
//---------------------------------------------------------------------------------------
void BaseDomain::RemoveTypesFromTypeIDMap(LoaderAllocator* pLoaderAllocator)
@ -5113,40 +4662,6 @@ size_t AppDomain::EstimateSize()
#ifdef DACCESS_COMPILE
void
DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
SUPPORTS_DAC;
// Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
// sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
// "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
// all of the ClassInit flags and non-GC statics.
// sizeof(DomainLocalModule) == 0x28
DAC_ENUM_DTHIS();
if (m_pDomainAssembly.IsValid())
{
m_pDomainAssembly->EnumMemoryRegions(flags);
}
if (m_pDynamicClassTable.Load().IsValid())
{
DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
m_aDynamicEntries * sizeof(DynamicClassInfo));
for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
{
PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
if (entry.IsValid())
{
// sizeof(DomainLocalModule::DynamicEntry) == 8
entry.EnumMem();
}
}
}
}
void
AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis)
{

View file

@ -58,406 +58,6 @@ class RCWRefCache;
#endif
GPTR_DECL(IdDispenser, g_pModuleIndexDispenser);
// We would like *ALLOCATECLASS_FLAG to AV (in order to catch errors), so don't change it
struct ClassInitFlags {
enum
{
INITIALIZED_FLAG_BIT = 0,
INITIALIZED_FLAG = 1<<INITIALIZED_FLAG_BIT,
ERROR_FLAG_BIT = 1,
ERROR_FLAG = 1<<ERROR_FLAG_BIT,
ALLOCATECLASS_FLAG_BIT = 2, // Bit to avoid racing for InstantiateStaticHandles
ALLOCATECLASS_FLAG = 1<<ALLOCATECLASS_FLAG_BIT,
COLLECTIBLE_FLAG_BIT = 3,
COLLECTIBLE_FLAG = 1<<COLLECTIBLE_FLAG_BIT
};
};
struct DomainLocalModule
{
friend class ClrDataAccess;
friend class CheckAsmOffsets;
friend struct ThreadLocalModule;
// After these macros complete, they may have returned an interior pointer into a gc object. This pointer will have been cast to a byte pointer
// It is critically important that no GC is allowed to occur before this pointer is used.
#define GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pGCStatics) \
{\
DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry.Load()); \
if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
{\
PTRARRAYREF objArray;\
objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
(dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hGCStatics);\
*(pGCStatics) = dac_cast<PTR_BYTE>(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\
}\
else\
{\
*(pGCStatics) = (dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry))->GetGCStaticsBasePointer();\
}\
}\
#define GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \
{\
DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry.Load()); \
if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
{\
if ((dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics != 0) \
{ \
U1ARRAYREF objArray;\
objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
(dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics);\
*(pNonGCStatics) = dac_cast<PTR_BYTE>(PTR_READ( \
PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \
objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \
} else (*pNonGCStatics) = NULL; \
}\
else\
{\
*(pNonGCStatics) = dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry)->GetNonGCStaticsBasePointer();\
}\
}\
struct DynamicEntry
{
static DWORD GetOffsetOfDataBlob();
};
typedef DPTR(DynamicEntry) PTR_DynamicEntry;
struct CollectibleDynamicEntry : public DynamicEntry
{
LOADERHANDLE m_hGCStatics;
LOADERHANDLE m_hNonGCStatics;
};
typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry;
struct NormalDynamicEntry : public DynamicEntry
{
PTR_OBJECTREF m_pGCStatics;
#ifdef FEATURE_64BIT_ALIGNMENT
// Padding to make m_pDataBlob aligned at MAX_PRIMITIVE_FIELD_SIZE
// code:MethodTableBuilder::PlaceRegularStaticFields assumes that the start of the data blob is aligned
SIZE_T m_padding;
#endif
BYTE m_pDataBlob[0];
inline PTR_BYTE GetGCStaticsBasePointer()
{
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
return dac_cast<PTR_BYTE>(m_pGCStatics);
}
inline PTR_BYTE GetNonGCStaticsBasePointer()
{
LIMITED_METHOD_CONTRACT
SUPPORTS_DAC;
return dac_cast<PTR_BYTE>(this);
}
};
typedef DPTR(NormalDynamicEntry) PTR_NormalDynamicEntry;
struct DynamicClassInfo
{
VolatilePtr<DynamicEntry, PTR_DynamicEntry> m_pDynamicEntry;
Volatile<DWORD> m_dwFlags;
};
typedef DPTR(DynamicClassInfo) PTR_DynamicClassInfo;
inline UMEntryThunk * GetADThunkTable()
{
LIMITED_METHOD_CONTRACT
return m_pADThunkTable;
}
inline void SetADThunkTable(UMEntryThunk* pADThunkTable)
{
LIMITED_METHOD_CONTRACT
InterlockedCompareExchangeT(m_pADThunkTable.GetPointer(), pADThunkTable, NULL);
}
// Note the difference between:
//
// GetPrecomputedNonGCStaticsBasePointer() and
// GetPrecomputedStaticsClassData()
//
// GetPrecomputedNonGCStaticsBasePointer returns the pointer that should be added to field offsets to retrieve statics
// GetPrecomputedStaticsClassData returns a pointer to the first byte of the precomputed statics block
inline TADDR GetPrecomputedNonGCStaticsBasePointer()
{
LIMITED_METHOD_CONTRACT
return dac_cast<TADDR>(this);
}
inline PTR_BYTE GetPrecomputedStaticsClassData()
{
LIMITED_METHOD_CONTRACT
return dac_cast<PTR_BYTE>(this) + offsetof(DomainLocalModule, m_pDataBlob);
}
static SIZE_T GetOffsetOfDataBlob() { return offsetof(DomainLocalModule, m_pDataBlob); }
static SIZE_T GetOffsetOfGCStaticPointer() { return offsetof(DomainLocalModule, m_pGCStatics); }
inline DomainAssembly* GetDomainAssembly()
{
LIMITED_METHOD_CONTRACT
SUPPORTS_DAC;
return m_pDomainAssembly;
}
#ifndef DACCESS_COMPILE
inline void SetDomainAssembly(DomainAssembly* pDomainAssembly)
{
LIMITED_METHOD_CONTRACT
m_pDomainAssembly = pDomainAssembly;
}
#endif
inline PTR_OBJECTREF GetPrecomputedGCStaticsBasePointer()
{
LIMITED_METHOD_CONTRACT
return m_pGCStatics;
}
inline PTR_OBJECTREF * GetPrecomputedGCStaticsBasePointerAddress()
{
LIMITED_METHOD_CONTRACT
return &m_pGCStatics;
}
// Returns bytes so we can add offsets
inline PTR_BYTE GetGCStaticsBasePointer(MethodTable * pMT)
{
WRAPPER_NO_CONTRACT
SUPPORTS_DAC;
if (pMT->IsDynamicStatics())
{
_ASSERTE(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics());
return GetDynamicEntryGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
}
else
{
return dac_cast<PTR_BYTE>(m_pGCStatics);
}
}
inline PTR_BYTE GetNonGCStaticsBasePointer(MethodTable * pMT)
{
WRAPPER_NO_CONTRACT
SUPPORTS_DAC;
if (pMT->IsDynamicStatics())
{
_ASSERTE(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics());
return GetDynamicEntryNonGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
}
else
{
return dac_cast<PTR_BYTE>(this);
}
}
inline DynamicClassInfo* GetDynamicClassInfo(DWORD n)
{
LIMITED_METHOD_CONTRACT
SUPPORTS_DAC;
_ASSERTE(m_pDynamicClassTable.Load() && m_aDynamicEntries > n);
dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[n].m_pDynamicEntry.Load());
return &m_pDynamicClassTable[n];
}
// These helpers can now return null, as the debugger may do queries on a type
// before the calls to PopulateClass happen
inline PTR_BYTE GetDynamicEntryGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
SUPPORTS_DAC;
}
CONTRACTL_END;
if (n >= m_aDynamicEntries)
{
return NULL;
}
DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
if (!pClassInfo->m_pDynamicEntry)
{
return NULL;
}
PTR_BYTE retval = NULL;
GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
return retval;
}
inline PTR_BYTE GetDynamicEntryNonGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
SUPPORTS_DAC;
}
CONTRACTL_END;
if (n >= m_aDynamicEntries)
{
return NULL;
}
DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
if (!pClassInfo->m_pDynamicEntry)
{
return NULL;
}
PTR_BYTE retval = NULL;
GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
return retval;
}
FORCEINLINE PTR_DynamicClassInfo GetDynamicClassInfoIfInitialized(DWORD n)
{
WRAPPER_NO_CONTRACT;
// m_aDynamicEntries is set last, it needs to be checked first
if (n >= m_aDynamicEntries)
{
return NULL;
}
_ASSERTE(m_pDynamicClassTable.Load() != NULL);
PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable.Load() + n);
// INITIALIZED_FLAG is set last, it needs to be checked first
if ((pDynamicClassInfo->m_dwFlags & ClassInitFlags::INITIALIZED_FLAG) == 0)
{
return NULL;
}
PREFIX_ASSUME(pDynamicClassInfo != NULL);
return pDynamicClassInfo;
}
// iClassIndex is slightly expensive to compute, so if we already know
// it, we can use this helper
inline BOOL IsClassInitialized(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
{
WRAPPER_NO_CONTRACT;
return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::INITIALIZED_FLAG) != 0;
}
inline BOOL IsPrecomputedClassInitialized(DWORD classID)
{
return GetPrecomputedStaticsClassData()[classID] & ClassInitFlags::INITIALIZED_FLAG;
}
inline BOOL IsClassAllocated(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
{
WRAPPER_NO_CONTRACT;
return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ALLOCATECLASS_FLAG) != 0;
}
BOOL IsClassInitError(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
{
WRAPPER_NO_CONTRACT;
return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ERROR_FLAG) != 0;
}
void SetClassInitialized(MethodTable* pMT);
void SetClassInitError(MethodTable* pMT);
void EnsureDynamicClassIndex(DWORD dwID);
void AllocateDynamicClass(MethodTable *pMT);
void PopulateClass(MethodTable *pMT);
#ifdef DACCESS_COMPILE
void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
static DWORD OffsetOfDataBlob()
{
LIMITED_METHOD_CONTRACT;
return offsetof(DomainLocalModule, m_pDataBlob);
}
FORCEINLINE MethodTable * GetMethodTableFromClassDomainID(DWORD dwClassDomainID)
{
DWORD rid = (DWORD)(dwClassDomainID) + 1;
TypeHandle th = GetDomainAssembly()->GetModule()->LookupTypeDef(TokenFromRid(rid, mdtTypeDef));
_ASSERTE(!th.IsNull());
MethodTable * pMT = th.AsMethodTable();
PREFIX_ASSUME(pMT != NULL);
return pMT;
}
private:
friend void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck);
void SetClassFlags(MethodTable* pMT, DWORD dwFlags);
DWORD GetClassFlags(MethodTable* pMT, DWORD iClassIndex);
PTR_DomainAssembly m_pDomainAssembly;
VolatilePtr<DynamicClassInfo, PTR_DynamicClassInfo> m_pDynamicClassTable; // used for generics and reflection.emit in memory
Volatile<SIZE_T> m_aDynamicEntries; // number of entries in dynamic table
VolatilePtr<UMEntryThunk> m_pADThunkTable;
PTR_OBJECTREF m_pGCStatics; // Handle to GC statics of the module
// In addition to storing the ModuleIndex in the Module class, we also
// keep a copy of the ModuleIndex in the DomainLocalModule class. This
// allows the thread static JIT helpers to quickly convert a pointer to
// a DomainLocalModule into a ModuleIndex.
ModuleIndex m_ModuleIndex;
// Note that the static offset calculation in code:Module::BuildStaticsOffsets takes the offset m_pDataBlob
// into consideration for alignment so we do not need any padding to ensure that the start of the data blob is aligned
BYTE m_pDataBlob[0]; // First byte of the statics blob
// Layout of m_pDataBlob is:
// ClassInit bytes (hold flags for cctor run, cctor error, etc)
// Non GC Statics
public:
// The Module class need to be able to initialized ModuleIndex,
// so for now I will make it a friend..
friend class Module;
FORCEINLINE ModuleIndex GetModuleIndex()
{
LIMITED_METHOD_DAC_CONTRACT;
return m_ModuleIndex;
}
}; // struct DomainLocalModule
#define OFFSETOF__DomainLocalModule__m_pDataBlob_ (6 * TARGET_POINTER_SIZE)
#ifdef FEATURE_64BIT_ALIGNMENT
#define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob (TARGET_POINTER_SIZE /* m_pGCStatics */ + TARGET_POINTER_SIZE /* m_padding */)
#else
#define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob TARGET_POINTER_SIZE /* m_pGCStatics */
#endif
#ifdef _MSC_VER
#pragma warning(pop)
#endif
@ -604,60 +204,6 @@ FORCEINLINE void PinnedHeapHandleBlockHolder__StaticFree(PinnedHeapHandleBlockH
pHolder->FreeData();
};
// The large heap handle bucket class is used to contain handles allocated
// from an array contained in the large heap.
class ThreadStaticHandleBucket
{
public:
// Constructor and desctructor.
ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain);
~ThreadStaticHandleBucket();
// This returns the next bucket.
ThreadStaticHandleBucket *GetNext()
{
LIMITED_METHOD_CONTRACT;
return m_pNext;
}
// Allocate handles from the bucket.
OBJECTHANDLE GetHandles();
private:
ThreadStaticHandleBucket *m_pNext;
int m_ArraySize;
OBJECTHANDLE m_hndHandleArray;
};
// The large heap handle table is used to allocate handles that are pointers
// to objects stored in an array in the large object heap.
class ThreadStaticHandleTable
{
public:
// Constructor and desctructor.
ThreadStaticHandleTable(BaseDomain *pDomain);
~ThreadStaticHandleTable();
// Allocate handles from the large heap handle table.
OBJECTHANDLE AllocateHandles(DWORD nRequested);
private:
// The buckets of object handles.
ThreadStaticHandleBucket *m_pHead;
// We need to know the containing domain so we know where to allocate handles
BaseDomain *m_pDomain;
};
//--------------------------------------------------------------------------------------
// Base class for domains. It provides an abstract way of finding the first assembly and
// for creating assemblies in the domain. The system domain only has one assembly, it
@ -675,12 +221,15 @@ private:
#define LOW_FREQUENCY_HEAP_RESERVE_SIZE (3 * GetOsPageSize())
#define LOW_FREQUENCY_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
#define HIGH_FREQUENCY_HEAP_RESERVE_SIZE (10 * GetOsPageSize())
#define HIGH_FREQUENCY_HEAP_RESERVE_SIZE (8 * GetOsPageSize())
#define HIGH_FREQUENCY_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
#define STUB_HEAP_RESERVE_SIZE (3 * GetOsPageSize())
#define STUB_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
#define STATIC_FIELD_HEAP_RESERVE_SIZE (2 * GetOsPageSize())
#define STATIC_FIELD_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
// --------------------------------------------------------------------------------
// PE File List lock - for creating list locks on PE files
// --------------------------------------------------------------------------------
@ -938,15 +487,6 @@ public:
return m_pMngStdInterfacesInfo;
}
#endif // FEATURE_COMINTEROP
#ifdef _DEBUG
BOOL OwnDomainLocalBlockLock()
{
WRAPPER_NO_CONTRACT;
return m_DomainLocalBlockCrst.OwnedByCurrentThread();
}
#endif
//****************************************************************************************
// Get the class init lock. The method is limited to friends because inappropriate use
// will cause deadlocks in the system
@ -980,9 +520,9 @@ public:
// Returns an array of OBJECTREF* that can be used to store domain specific data.
// Statics and reflection info (Types, MemberInfo,..) are stored this way
// If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation
// If pStaticsInfo != 0, allocation will only take place if GC statics in the DynamicStaticsInfo are NULL (and the allocation
// will be properly serialized)
OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate = NULL);
OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, DynamicStaticsInfo* pStaticsInfo = NULL, MethodTable *pMTToFillWithStaticBoxes = NULL);
//****************************************************************************************
// Handles
@ -1085,10 +625,10 @@ public:
return &m_crstLoaderAllocatorReferences;
}
CrstExplicitInit* GetStaticBoxInitLock()
CrstExplicitInit* GetGenericDictionaryExpansionLock()
{
LIMITED_METHOD_CONTRACT;
return &m_crstStaticBoxInitLock;
return &m_crstGenericDictionaryExpansionLock;
}
static CrstStatic* GetMethodTableExposedClassObjectLock()
@ -1112,10 +652,9 @@ protected:
PEFileListLock m_FileLoadLock; // Protects the list of assemblies in the domain
CrstExplicitInit m_DomainCrst; // General Protection for the Domain
CrstExplicitInit m_DomainCacheCrst; // Protects the Assembly and Unmanaged caches
CrstExplicitInit m_DomainLocalBlockCrst;
// Used to protect the reference lists in the collectible loader allocators attached to this appdomain
CrstExplicitInit m_crstLoaderAllocatorReferences;
CrstExplicitInit m_crstStaticBoxInitLock;
CrstExplicitInit m_crstGenericDictionaryExpansionLock;
//#AssemblyListLock
// Used to protect the assembly list. Taken also by GC or debugger thread, therefore we have to avoid
@ -1184,17 +723,6 @@ public:
}
};
class DomainLocalBlockLockHolder : public CrstHolder
{
public:
DomainLocalBlockLockHolder(BaseDomain *pD)
: CrstHolder(&pD->m_DomainLocalBlockCrst)
{
WRAPPER_NO_CONTRACT;
}
};
friend class DomainLocalBlockLockHolder;
class LoadLockHolder : public PEFileListLockHolder
{
public:
@ -1218,21 +746,8 @@ public:
private:
TypeIDMap m_typeIDMap;
// MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen.
// During execution corresponding thread static data blocks are stored in `t_NonGCThreadStaticBlocks`
// and `t_GCThreadStaticBlocks` array at the `typeIndex`.
TypeIDMap m_NonGCThreadStaticBlockTypeIDMap;
TypeIDMap m_GCThreadStaticBlockTypeIDMap;
public:
void InitThreadStaticBlockTypeMap();
UINT32 GetNonGCThreadStaticTypeIndex(PTR_MethodTable pMT);
UINT32 GetGCThreadStaticTypeIndex(PTR_MethodTable pMT);
PTR_MethodTable LookupNonGCThreadStaticBlockType(UINT32 id);
PTR_MethodTable LookupGCThreadStaticBlockType(UINT32 id);
UINT32 GetTypeID(PTR_MethodTable pMT);
UINT32 LookupTypeID(PTR_MethodTable pMT);
@ -1921,11 +1436,11 @@ public:
#endif // DEBUGGING_SUPPORTED
#ifndef DACCESS_COMPILE
OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested)
{
WRAPPER_NO_CONTRACT;
return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate);
return AllocateObjRefPtrsInLargeTable(nRequested);
}
#endif // DACCESS_COMPILE

View file

@ -78,14 +78,5 @@ inline PTR_LoaderHeap AppDomain::GetStubHeap()
return GetLoaderAllocator()->GetStubHeap();
}
/* static */
inline DWORD DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(DWORD(offsetof(NormalDynamicEntry, m_pDataBlob)) == offsetof(NormalDynamicEntry, m_pDataBlob));
return (DWORD)offsetof(NormalDynamicEntry, m_pDataBlob);
}
#endif // _APPDOMAIN_I

View file

@ -142,13 +142,6 @@ ASMCONSTANTS_C_ASSERT(Thread__m_fPreemptiveGCDisabled == offsetof(Thread, m_fPre
ASMCONSTANTS_C_ASSERT(Thread__m_pFrame == offsetof(Thread, m_pFrame));
#define Thread_m_pFrame Thread__m_pFrame
#define DomainLocalModule__m_pDataBlob 0x18
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob));
#define DomainLocalModule__m_pGCStatics 0x10
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics));
#define ASM__VTABLE_SLOTS_PER_CHUNK 8
ASMCONSTANTS_C_ASSERT(ASM__VTABLE_SLOTS_PER_CHUNK == VTABLE_SLOTS_PER_CHUNK)

View file

@ -586,71 +586,6 @@ LOCAL_LABEL(stackProbe_loop):
NESTED_END JIT_RareDisableHelper, _TEXT
#ifdef FEATURE_CORECLR
//
// JIT Static access helpers for single appdomain case
//
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
add r2, r0, #DomainLocalModule__m_pDataBlob
ldrb r2, [r2, r1]
tst r2, #1
beq LOCAL_LABEL(CallCppHelper1)
bx lr
LOCAL_LABEL(CallCppHelper1):
// Tail call JIT_GetSharedNonGCStaticBase_Helper
b C_FUNC(JIT_GetSharedNonGCStaticBase_Helper)
LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
bx lr
LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
add r2, r0, #DomainLocalModule__m_pDataBlob
ldrb r2, [r2, r1]
tst r2, #1
beq LOCAL_LABEL(CallCppHelper3)
ldr r0, [r0, #DomainLocalModule__m_pGCStatics]
bx lr
LOCAL_LABEL(CallCppHelper3):
// Tail call Jit_GetSharedGCStaticBase_Helper
b C_FUNC(JIT_GetSharedGCStaticBase_Helper)
LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
ldr r0, [r0, #DomainLocalModule__m_pGCStatics]
bx lr
LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
#endif
#define __wbScratch r3
#define pShadow r7

View file

@ -1023,11 +1023,6 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool
//
// Create alias for optimized implementations of helpers provided on this platform
//
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
//------------------------------------------------------------------------
//

View file

@ -191,11 +191,13 @@ ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT)
ASMCONSTANTS_C_ASSERT(ResolveCacheElem__target == offsetof(ResolveCacheElem, target));
ASMCONSTANTS_C_ASSERT(ResolveCacheElem__pNext == offsetof(ResolveCacheElem, pNext));
#define DomainLocalModule__m_pDataBlob 0x30
#define DomainLocalModule__m_pGCStatics 0x20
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob));
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics));
#define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8
ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics
== offsetof(DynamicStaticsInfo, m_pNonGCStatics));
#define OFFSETOF__DynamicStaticsInfo__m_pGCStatics 0
ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pGCStatics
== offsetof(DynamicStaticsInfo, m_pGCStatics));
// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
#define Frame__m_Next 0x08

View file

@ -659,58 +659,34 @@ DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_Object
//
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
// void* JIT_GetDynamicNonGCStaticBase(DynamicStaticsInfo* pStaticsInfo)
LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
add x2, x0, #DomainLocalModule__m_pDataBlob
ldrb w2, [x2, w1, UXTW]
tst w2, #1
beq LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper)
ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics]
tbnz x1, #0, LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper)
mov x0, x1
ret lr
LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper):
// Tail call JIT_GetSharedNonGCStaticBase_Helper
b C_FUNC(JIT_GetSharedNonGCStaticBase_Helper)
LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper):
// Tail call JIT_GetDynamicNonGCStaticBase_Portable
b C_FUNC(JIT_GetDynamicNonGCStaticBase_Portable)
LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
// void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo* pStaticsInfo)
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
ret lr
LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
add x2, x0, #DomainLocalModule__m_pDataBlob
ldrb w2, [x2, w1, UXTW]
tst w2, #1
beq LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper)
ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pGCStatics]
tbnz x1, #0, LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper)
mov x0, x1
ret lr
LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper):
// Tail call Jit_GetSharedGCStaticBase_Helper
b C_FUNC(JIT_GetSharedGCStaticBase_Helper)
LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
ret lr
LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper):
// Tail call JIT_GetDynamicGCStaticBase_Portable
b C_FUNC(JIT_GetDynamicGCStaticBase_Portable)
LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT
#ifdef PROFILING_SUPPORTED

View file

@ -46,8 +46,8 @@
IMPORT $g_GCShadowEnd
#endif // WRITE_BARRIER_CHECK
IMPORT JIT_GetSharedNonGCStaticBase_Helper
IMPORT JIT_GetSharedGCStaticBase_Helper
IMPORT JIT_GetDynamicNonGCStaticBase_Portable
IMPORT JIT_GetDynamicGCStaticBase_Portable
#ifdef FEATURE_COMINTEROP
IMPORT CLRToCOMWorker
@ -1026,59 +1026,35 @@ Fail
;
; ------------------------------------------------------------------
; void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain
; void* JIT_GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicInfo)
LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain
; If class is not initialized, bail to C++ helper
add x2, x0, #DomainLocalModule__m_pDataBlob
ldrb w2, [x2, w1]
tst w2, #1
beq CallHelper1
ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics]
tbnz x1, #0, CallHelper1
mov x0, x1
ret lr
CallHelper1
; Tail call JIT_GetSharedNonGCStaticBase_Helper
b JIT_GetSharedNonGCStaticBase_Helper
; Tail call JIT_GetDynamicNonGCStaticBase_Portable
b JIT_GetDynamicNonGCStaticBase_Portable
LEAF_END
; void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicInfo)
; ------------------------------------------------------------------
; void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
ret lr
LEAF_END
; ------------------------------------------------------------------
; void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain
LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain
; If class is not initialized, bail to C++ helper
add x2, x0, #DomainLocalModule__m_pDataBlob
ldrb w2, [x2, w1]
tst w2, #1
beq CallHelper2
ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pGCStatics]
tbnz x1, #0, CallHelper2
mov x0, x1
ret lr
CallHelper2
; Tail call Jit_GetSharedGCStaticBase_Helper
b JIT_GetSharedGCStaticBase_Helper
; Tail call JIT_GetDynamicGCStaticBase_Portable
b JIT_GetDynamicGCStaticBase_Portable
LEAF_END
; ------------------------------------------------------------------
; void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
ldr x0, [x0, #DomainLocalModule__m_pGCStatics]
ret lr
LEAF_END
; ------------------------------------------------------------------
; __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val)
LEAF_ENTRY JIT_WriteBarrier_Callable

View file

@ -131,10 +131,8 @@ inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatH
//
// Create alias for optimized implementations of helpers provided on this platform
//
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_SingleAppDomain
#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_SingleAppDomain
//**********************************************************************
// Frames

View file

@ -334,7 +334,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
MethodTable* pMT = (MethodTable *) pMTHead;
// Allocate the private data block ("private" during runtime in the ngen'ed case).
pMT->AllocateAuxiliaryData(pAllocator, this, pamTracker, false, static_cast<WORD>(numNonVirtualSlots));
pMT->AllocateAuxiliaryData(pAllocator, this, pamTracker, MethodTableStaticsFlags::None, static_cast<WORD>(numNonVirtualSlots));
pMT->SetLoaderAllocator(pAllocator);
pMT->SetModule(elemTypeHnd.GetModule());
@ -406,7 +406,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
}
#endif // FEATURE_TYPEEQUIVALENCE
_ASSERTE(pMT->IsClassPreInited());
pMT->SetClassInited();
// Set BaseSize to be size of non-data portion of the array
DWORD baseSize = ARRAYBASE_BASESIZE;

View file

@ -421,7 +421,6 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
m_FixupCrst.Init(CrstModuleFixup, (CrstFlags)(CRST_HOST_BREAKABLE|CRST_REENTRANCY));
m_InstMethodHashTableCrst.Init(CrstInstMethodHashTable, CRST_REENTRANCY);
m_ISymUnmanagedReaderCrst.Init(CrstISymUnmanagedReader, CRST_DEBUGGER_THREAD);
m_DictionaryCrst.Init(CrstDomainLocalBlock);
AllocateMaps();
m_dwTransientFlags &= ~((DWORD)CLASSES_FREED); // Set flag indicating LookupMaps are now in a consistent and destructable state
@ -473,19 +472,12 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker);
}
// this will be initialized a bit later.
m_ModuleID = NULL;
m_ModuleIndex.m_dwIndex = (SIZE_T)-1;
// These will be initialized in NotifyProfilerLoadFinished, set them to
// a safe initial value now.
m_dwTypeCount = 0;
m_dwExportedTypeCount = 0;
m_dwCustomAttributeCount = 0;
// Prepare statics that are known at module load time
AllocateStatics(pamTracker);
if (m_AssemblyRefByNameTable == NULL)
{
Module::CreateAssemblyRefByNameTable(pamTracker);
@ -765,10 +757,6 @@ void Module::Destruct()
#if defined(PROFILING_SUPPORTED)
delete m_pJitInlinerTrackingMap;
#endif
// If this module was loaded as domain-specific, then
// we must free its ModuleIndex so that it can be reused
FreeModuleIndex();
}
bool Module::NeedsGlobalMethodTable()
@ -853,365 +841,12 @@ DomainAssembly* Module::GetDomainAssembly()
{
LIMITED_METHOD_DAC_CONTRACT;
return dac_cast<PTR_DomainAssembly>(m_ModuleID->GetDomainAssembly());
return m_pDomainAssembly;
}
#ifndef DACCESS_COMPILE
#include "staticallocationhelpers.inl"
// Parses metadata and initializes offsets of per-class static blocks.
void Module::BuildStaticsOffsets(AllocMemTracker *pamTracker)
{
STANDARD_VM_CONTRACT;
// Trade off here. We want a slot for each type. That way we can get to 2 bits per class and
// index directly and not need a mapping from ClassID to MethodTable (we will use the RID
// as the mapping)
IMDInternalImport *pImport = GetMDImport();
DWORD * pRegularStaticOffsets = NULL;
DWORD * pThreadStaticOffsets = NULL;
// Get the number of types/classes defined in this module. Add 1 to count the module itself
DWORD dwNumTypes = pImport->GetCountWithTokenKind(mdtTypeDef) + 1; // +1 for module type
// [0] covers regular statics, [1] covers thread statics
DWORD dwGCHandles[2] = { 0, 0 };
// Organization in memory of the static block
//
//
// | GC Statics |
// |
// |
// | Class Data (one byte per class) | pointer to gc statics | primitive type statics |
//
//
#ifndef CROSSBITNESS_COMPILE
// The assertions must hold in every non-crossbitness scenario
_ASSERTE(OFFSETOF__DomainLocalModule__m_pDataBlob_ == DomainLocalModule::OffsetOfDataBlob());
_ASSERTE(OFFSETOF__ThreadLocalModule__m_pDataBlob == ThreadLocalModule::OffsetOfDataBlob());
#endif
DWORD dwNonGCBytes[2] = {
DomainLocalModule::OffsetOfDataBlob() + (DWORD)(sizeof(BYTE)*dwNumTypes),
ThreadLocalModule::OffsetOfDataBlob() + (DWORD)(sizeof(BYTE)*dwNumTypes)
};
HENUMInternalHolder hTypeEnum(pImport);
hTypeEnum.EnumAllInit(mdtTypeDef);
mdTypeDef type;
// Parse each type of the class
while (pImport->EnumNext(&hTypeEnum, &type))
{
// Set offset for this type
DWORD dwIndex = RidFromToken(type) - 1;
// [0] covers regular statics, [1] covers thread statics
DWORD dwAlignment[2] = { 1, 1 };
DWORD dwClassNonGCBytes[2] = { 0, 0 };
DWORD dwClassGCHandles[2] = { 0, 0 };
// need to check if the type is generic and if so exclude it from iteration as we don't know the size
if (!m_pTypeGenericInfoMap->IsGeneric(type, pImport))
{
HENUMInternalHolder hFieldEnum(pImport);
hFieldEnum.EnumInit(mdtFieldDef, type);
mdFieldDef field;
// Parse each field of the type
while (pImport->EnumNext(&hFieldEnum, &field))
{
BOOL fSkip = FALSE;
CorElementType ElementType = ELEMENT_TYPE_END;
mdToken tkValueTypeToken = 0;
int kk; // Use one set of variables for regular statics, and the other set for thread statics
fSkip = GetStaticFieldElementTypeForFieldDef(this, pImport, field, &ElementType, &tkValueTypeToken, &kk);
if (fSkip)
continue;
// We account for "regular statics" and "thread statics" separately.
// Currently we are lumping RVA into "regular statics",
// but we probably shouldn't.
switch (ElementType)
{
case ELEMENT_TYPE_I1:
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_BOOLEAN:
dwClassNonGCBytes[kk] += 1;
break;
case ELEMENT_TYPE_I2:
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_CHAR:
dwAlignment[kk] = max<DWORD>(2, dwAlignment[kk]);
dwClassNonGCBytes[kk] += 2;
break;
case ELEMENT_TYPE_I4:
case ELEMENT_TYPE_U4:
case ELEMENT_TYPE_R4:
dwAlignment[kk] = max<DWORD>(4, dwAlignment[kk]);
dwClassNonGCBytes[kk] += 4;
break;
case ELEMENT_TYPE_FNPTR:
case ELEMENT_TYPE_PTR:
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_U:
dwAlignment[kk] = max<DWORD>((1 << LOG2_PTRSIZE), dwAlignment[kk]);
dwClassNonGCBytes[kk] += (1 << LOG2_PTRSIZE);
break;
case ELEMENT_TYPE_I8:
case ELEMENT_TYPE_U8:
case ELEMENT_TYPE_R8:
dwAlignment[kk] = max<DWORD>(8, dwAlignment[kk]);
dwClassNonGCBytes[kk] += 8;
break;
case ELEMENT_TYPE_VAR:
case ELEMENT_TYPE_MVAR:
case ELEMENT_TYPE_STRING:
case ELEMENT_TYPE_SZARRAY:
case ELEMENT_TYPE_ARRAY:
case ELEMENT_TYPE_CLASS:
case ELEMENT_TYPE_OBJECT:
dwClassGCHandles[kk] += 1;
break;
case ELEMENT_TYPE_VALUETYPE:
// Statics for valuetypes where the valuetype is defined in this module are handled here. Other valuetype statics utilize the pessimistic model below.
dwClassGCHandles[kk] += 1;
break;
case ELEMENT_TYPE_END:
default:
// The actual element type was ELEMENT_TYPE_VALUETYPE, but the as we don't want to load additional assemblies
// to determine these static offsets, we've fallen back to a pessimistic model.
if (tkValueTypeToken != 0)
{
// We'll have to be pessimistic here
dwClassNonGCBytes[kk] += MAX_PRIMITIVE_FIELD_SIZE;
dwAlignment[kk] = max<DWORD>(MAX_PRIMITIVE_FIELD_SIZE, dwAlignment[kk]);
dwClassGCHandles[kk] += 1;
break;
}
else
{
// field has an unexpected type
ThrowHR(VER_E_FIELD_SIG);
break;
}
}
}
if (pRegularStaticOffsets == NULL && (dwClassGCHandles[0] != 0 || dwClassNonGCBytes[0] != 0))
{
// Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
pRegularStaticOffsets = (PTR_DWORD)pamTracker->Track(
GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
(S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
for (DWORD i = 0; i < dwIndex; i++) {
pRegularStaticOffsets[i * 2 ] = dwGCHandles[0]*TARGET_POINTER_SIZE;
pRegularStaticOffsets[i * 2 + 1] = dwNonGCBytes[0];
}
}
if (pThreadStaticOffsets == NULL && (dwClassGCHandles[1] != 0 || dwClassNonGCBytes[1] != 0))
{
// Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
pThreadStaticOffsets = (PTR_DWORD)pamTracker->Track(
GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
(S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
for (DWORD i = 0; i < dwIndex; i++) {
pThreadStaticOffsets[i * 2 ] = dwGCHandles[1]*TARGET_POINTER_SIZE;
pThreadStaticOffsets[i * 2 + 1] = dwNonGCBytes[1];
}
}
}
if (pRegularStaticOffsets != NULL)
{
// Align the offset of non gc statics
dwNonGCBytes[0] = (DWORD) ALIGN_UP(dwNonGCBytes[0], dwAlignment[0]);
// Save current offsets
pRegularStaticOffsets[dwIndex*2] = dwGCHandles[0]*TARGET_POINTER_SIZE;
pRegularStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[0];
// Increment for next class
dwGCHandles[0] += dwClassGCHandles[0];
dwNonGCBytes[0] += dwClassNonGCBytes[0];
}
if (pThreadStaticOffsets != NULL)
{
// Align the offset of non gc statics
dwNonGCBytes[1] = (DWORD) ALIGN_UP(dwNonGCBytes[1], dwAlignment[1]);
// Save current offsets
pThreadStaticOffsets[dwIndex*2] = dwGCHandles[1]*TARGET_POINTER_SIZE;
pThreadStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[1];
// Increment for next class
dwGCHandles[1] += dwClassGCHandles[1];
dwNonGCBytes[1] += dwClassNonGCBytes[1];
}
}
m_maxTypeRidStaticsAllocated = dwNumTypes;
if (pRegularStaticOffsets != NULL)
{
pRegularStaticOffsets[dwNumTypes*2] = dwGCHandles[0]*TARGET_POINTER_SIZE;
pRegularStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[0];
}
if (pThreadStaticOffsets != NULL)
{
pThreadStaticOffsets[dwNumTypes*2] = dwGCHandles[1]*TARGET_POINTER_SIZE;
pThreadStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[1];
}
m_pRegularStaticOffsets = pRegularStaticOffsets;
m_pThreadStaticOffsets = pThreadStaticOffsets;
m_dwMaxGCRegularStaticHandles = dwGCHandles[0];
m_dwMaxGCThreadStaticHandles = dwGCHandles[1];
m_dwRegularStaticsBlockSize = dwNonGCBytes[0];
m_dwThreadStaticsBlockSize = dwNonGCBytes[1];
}
void Module::GetOffsetsForRegularStaticData(
mdToken cl,
BOOL bDynamic, DWORD dwGCStaticHandles,
DWORD dwNonGCStaticBytes,
DWORD * pOutStaticHandleOffset,
DWORD * pOutNonGCStaticOffset)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END
*pOutStaticHandleOffset = 0;
*pOutNonGCStaticOffset = 0;
if (!dwGCStaticHandles && !dwNonGCStaticBytes)
{
return;
}
#ifndef CROSSBITNESS_COMPILE
_ASSERTE(OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob == DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob());
#endif
// Statics for instantiated types are allocated dynamically per-instantiation
if (bDynamic)
{
// Non GC statics are embedded in the Dynamic Entry.
*pOutNonGCStaticOffset = OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob;
return;
}
if (m_pRegularStaticOffsets == NULL)
{
THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
}
_ASSERTE(m_pRegularStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
// We allocate in the big blob.
DWORD index = RidFromToken(cl) - 1;
*pOutStaticHandleOffset = m_pRegularStaticOffsets[index*2];
*pOutNonGCStaticOffset = m_pRegularStaticOffsets[index*2 + 1];
#ifdef CROSSBITNESS_COMPILE
*pOutNonGCStaticOffset += OFFSETOF__DomainLocalModule__m_pDataBlob_ - DomainLocalModule::OffsetOfDataBlob();
#endif
// Check we didnt go out of what we predicted we would need for the class
if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles >
m_pRegularStaticOffsets[(index+1)*2] ||
*pOutNonGCStaticOffset + dwNonGCStaticBytes >
m_pRegularStaticOffsets[(index+1)*2 + 1])
{ // It's most likely that this is due to bad metadata, thus the exception. However, the
// previous comments for this bit of code mentioned that this could be a corner case bug
// with static field size estimation, though this is entirely unlikely since the code has
// been this way for at least two releases.
THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
}
}
void Module::GetOffsetsForThreadStaticData(
mdToken cl,
BOOL bDynamic, DWORD dwGCStaticHandles,
DWORD dwNonGCStaticBytes,
DWORD * pOutStaticHandleOffset,
DWORD * pOutNonGCStaticOffset)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END
*pOutStaticHandleOffset = 0;
*pOutNonGCStaticOffset = 0;
if (!dwGCStaticHandles && !dwNonGCStaticBytes)
{
return;
}
#ifndef CROSSBITNESS_COMPILE
_ASSERTE(OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob == ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob());
#endif
// Statics for instantiated types are allocated dynamically per-instantiation
if (bDynamic)
{
// Non GC thread statics are embedded in the Dynamic Entry.
*pOutNonGCStaticOffset = OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob;
return;
}
if (m_pThreadStaticOffsets == NULL)
{
THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
}
_ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
// We allocate in the big blob.
DWORD index = RidFromToken(cl) - 1;
*pOutStaticHandleOffset = m_pThreadStaticOffsets[index*2];
*pOutNonGCStaticOffset = m_pThreadStaticOffsets[index*2 + 1];
#ifdef CROSSBITNESS_COMPILE
*pOutNonGCStaticOffset += OFFSETOF__ThreadLocalModule__m_pDataBlob - ThreadLocalModule::GetOffsetOfDataBlob();
#endif
// Check we didnt go out of what we predicted we would need for the class
if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles >
m_pThreadStaticOffsets[(index+1)*2] ||
*pOutNonGCStaticOffset + dwNonGCStaticBytes >
m_pThreadStaticOffsets[(index+1)*2 + 1])
{
// It's most likely that this is due to bad metadata, thus the exception. However, the
// previous comments for this bit of code mentioned that this could be a corner case bug
// with static field size estimation, though this is entirely unlikely since the code has
// been this way for at least two releases.
THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
}
}
// initialize Crst controlling the Dynamic IL hashtable
void Module::InitializeDynamicILCrst()
{
@ -1514,240 +1149,11 @@ BOOL Module::IsRuntimeMarshallingEnabled()
return hr != S_OK;
}
DWORD Module::AllocateDynamicEntry(MethodTable *pMT)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
PRECONDITION(pMT->GetModuleForStatics() == this);
PRECONDITION(pMT->IsDynamicStatics());
PRECONDITION(!pMT->ContainsGenericVariables());
}
CONTRACTL_END;
CrstHolder ch(&m_Crst);
DWORD newId = (LONG)m_cDynamicEntries++;
if (newId >= m_maxDynamicEntries)
{
SIZE_T maxDynamicEntries = max<SIZE_T>(16, m_maxDynamicEntries);
while (maxDynamicEntries <= newId)
{
maxDynamicEntries *= 2;
}
DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*)
(void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries));
if (m_pDynamicStaticsInfo)
memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries);
VolatileStore(&m_pDynamicStaticsInfo, pNewDynamicStaticsInfo);
m_maxDynamicEntries = maxDynamicEntries;
}
m_pDynamicStaticsInfo[newId].pEnclosingMT = pMT;
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Assigned dynamic ID %d to %s\n", newId, pMT->GetDebugClassName()));
return newId;
}
void Module::FreeModuleIndex()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
if (m_ModuleID != NULL)
{
_ASSERTE(m_ModuleIndex == m_ModuleID->GetModuleIndex());
if (IsCollectible())
{
ThreadStoreLockHolder tsLock;
Thread *pThread = NULL;
while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
{
pThread->DeleteThreadStaticData(m_ModuleIndex);
}
}
// Get the ModuleIndex from the DLM and free it
Module::FreeModuleIndex(m_ModuleIndex);
}
else
{
// This was an empty, short-lived Module object that
// was never assigned a ModuleIndex...
}
}
ModuleIndex Module::AllocateModuleIndex()
{
DWORD val;
g_pModuleIndexDispenser->NewId(NULL, val);
// For various reasons, the IDs issued by the IdDispenser start at 1.
// Domain neutral module IDs have historically started at 0, and we
// have always assigned ID 0 to CoreLib. Thus, to make it so that
// domain neutral module IDs start at 0, we will subtract 1 from the
// ID that we got back from the ID dispenser.
ModuleIndex index((SIZE_T)(val-1));
return index;
}
void Module::FreeModuleIndex(ModuleIndex index)
{
WRAPPER_NO_CONTRACT;
// We subtracted 1 after we allocated this ID, so we need to
// add 1 before we free it.
SIZE_T val = index.m_dwIndex + 1;
_ASSERTE(val <= MAXDWORD);
g_pModuleIndexDispenser->DisposeId((DWORD)val);
}
void Module::AllocateRegularStaticHandles()
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
}
CONTRACTL_END;
// Allocate the handles we will need. Note that AllocateStaticFieldObjRefPtrs will only
// allocate if pModuleData->GetGCStaticsBasePointerAddress(pMT) != 0, avoiding creating
// handles more than once for a given MT or module
DomainLocalModule *pModuleData = GetDomainLocalModule();
_ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointerAddress() != NULL);
if (this->m_dwMaxGCRegularStaticHandles > 0)
{
AppDomain::GetCurrentDomain()->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles,
pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
// We should throw if we fail to allocate and never hit this assert
_ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() != NULL);
}
}
BOOL Module::IsStaticStoragePrepared(mdTypeDef tkType)
void Module::SetDomainAssembly(DomainAssembly *pDomainAssembly)
{
LIMITED_METHOD_CONTRACT;
// Right now the design is that we do one static allocation pass during NGEN,
// and a 2nd pass for it at module init time for modules that weren't NGENed or the NGEN
// pass was unsuccessful. If we are loading types after that then we must use dynamic
// static storage. These dynamic statics require an additional indirection so they
// don't perform quite as well.
//
// This check was created for the scenario where a profiler adds additional types
// however it seems likely this check would also accurately handle other dynamic
// scenarios such as ref.emit and EnC as long as they are adding new types and
// not new statics to existing types.
_ASSERTE(TypeFromToken(tkType) == mdtTypeDef);
return m_maxTypeRidStaticsAllocated >= RidFromToken(tkType);
}
void Module::AllocateStatics(AllocMemTracker *pamTracker)
{
STANDARD_VM_CONTRACT;
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Allocating statics for module %s\n", GetSimpleName()));
// Build the offset table, which will tell us what the offsets for the statics of each class are (one offset for gc handles, one offset
// for non gc types)
BuildStaticsOffsets(pamTracker);
}
void Module::SetDomainAssembly(DomainAssembly *pDomainAssembly)
{
CONTRACTL
{
INSTANCE_CHECK;
PRECONDITION(CheckPointer(pDomainAssembly));
PRECONDITION(IsManifest());
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
DomainLocalModule* pModuleData = 0;
// Do we need to allocate memory for the non GC statics?
if (m_ModuleID == NULL)
{
// Allocate memory for the module statics.
LoaderAllocator *pLoaderAllocator = NULL;
if (GetAssembly()->IsCollectible())
{
pLoaderAllocator = GetAssembly()->GetLoaderAllocator();
}
else
{
pLoaderAllocator = AppDomain::GetCurrentDomain()->GetLoaderAllocator();
}
SIZE_T size = GetDomainLocalModuleSize();
LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocating %zi bytes for precomputed statics in module %s in LoaderAllocator %p\n",
size, this->GetDebugName(), pLoaderAllocator));
// We guarantee alignment for 64-bit regular statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons.
_ASSERTE(size >= DomainLocalModule::OffsetOfDataBlob());
pModuleData = (DomainLocalModule*)(void*)
pLoaderAllocator->GetHighFrequencyHeap()->AllocAlignedMem(
size, MAX_PRIMITIVE_FIELD_SIZE);
// Note: Memory allocated on loader heap is zero filled
// memset(pModuleData, 0, size);
// Verify that the space is really zero initialized
_ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() == NULL);
// If the module was loaded as domain-specific, then we need to assign
// this module a domain-neutral module ID.
pModuleData->m_ModuleIndex = Module::AllocateModuleIndex();
m_ModuleIndex = pModuleData->m_ModuleIndex;
}
else
{
pModuleData = this->m_ModuleID;
LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocation not needed for ngened non shared module %s in Appdomain %08x\n"));
}
// Non shared case, module points directly to the statics. In ngen case
// m_pDomainModule is already set for the non shared case
if (m_ModuleID == NULL)
{
m_ModuleID = pModuleData;
}
m_ModuleID->SetDomainAssembly(pDomainAssembly);
// Allocate static handles now.
// NOTE: Bootstrapping issue with CoreLib - we will manually allocate later
// If the assembly is collectible, we don't initialize static handles for them
// as it is currently initialized through the DomainLocalModule::PopulateClass in MethodTable::CheckRunClassInitThrowing
// (If we don't do this, it would allocate here unused regular static handles that will be overridden later)
if (g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] != NULL && !GetAssembly()->IsCollectible())
AllocateRegularStaticHandles();
m_pDomainAssembly = pDomainAssembly;
}
OBJECTREF Module::GetExposedObject()
@ -5099,10 +4505,9 @@ void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
EMEM_OUT(("MEM: %p Module\n", dac_cast<TADDR>(this)));
}
//Save module id data only if it a real pointer, not a tagged sugestion to use ModuleIndex.
if (m_ModuleID.IsValid())
if (m_pDomainAssembly.IsValid())
{
m_ModuleID->EnumMemoryRegions(flags);
m_pDomainAssembly->EnumMemoryRegions(flags);
}
if (m_pPEAssembly.IsValid())
{

View file

@ -57,7 +57,6 @@ class Assembly;
class BaseDomain;
class AppDomain;
class DomainModule;
struct DomainLocalModule;
class SystemDomain;
class Module;
class SString;
@ -426,8 +425,6 @@ typedef DPTR(DynamicILBlobTable) PTR_DynamicILBlobTable;
typedef DPTR(class ReadyToRunInfo) PTR_ReadyToRunInfo;
#endif
struct ThreadLocalModule;
// A ModuleBase represents the ability to reference code via tokens
// This abstraction exists to allow the R2R manifest metadata to have
// tokens which can be resolved at runtime.
@ -1508,73 +1505,11 @@ public:
InstrumentedILOffsetMapping GetInstrumentedILOffsetMapping(mdMethodDef token);
public:
// This helper returns to offsets for the slots/bytes/handles. They return the offset in bytes from the beginning
// of the 1st GC pointer in the statics block for the module.
void GetOffsetsForRegularStaticData(
mdTypeDef cl,
BOOL bDynamic,
DWORD dwGCStaticHandles,
DWORD dwNonGCStaticBytes,
DWORD * pOutStaticHandleOffset,
DWORD * pOutNonGCStaticOffset);
void GetOffsetsForThreadStaticData(
mdTypeDef cl,
BOOL bDynamic,
DWORD dwGCStaticHandles,
DWORD dwNonGCStaticBytes,
DWORD * pOutStaticHandleOffset,
DWORD * pOutNonGCStaticOffset);
BOOL IsStaticStoragePrepared(mdTypeDef tkType);
DWORD GetNumGCThreadStaticHandles()
{
return m_dwMaxGCThreadStaticHandles;;
}
CrstBase* GetFixupCrst()
{
return &m_FixupCrst;
}
void AllocateRegularStaticHandles();
void FreeModuleIndex();
DWORD GetDomainLocalModuleSize()
{
return m_dwRegularStaticsBlockSize;
}
DWORD GetThreadLocalModuleSize()
{
return m_dwThreadStaticsBlockSize;
}
DWORD AllocateDynamicEntry(MethodTable *pMT);
// We need this for the jitted shared case,
inline MethodTable* GetDynamicClassMT(DWORD dynamicClassID);
static ModuleIndex AllocateModuleIndex();
static void FreeModuleIndex(ModuleIndex index);
ModuleIndex GetModuleIndex()
{
LIMITED_METHOD_DAC_CONTRACT;
return m_ModuleIndex;
}
SIZE_T GetModuleID()
{
LIMITED_METHOD_DAC_CONTRACT;
return dac_cast<TADDR>(m_ModuleID);
}
PTR_DomainLocalModule GetDomainLocalModule();
// LoaderHeap for storing IJW thunks
PTR_LoaderHeap m_pThunkHeap;
@ -1588,46 +1523,7 @@ public:
protected:
void BuildStaticsOffsets (AllocMemTracker *pamTracker);
void AllocateStatics (AllocMemTracker *pamTracker);
// ModuleID is quite ugly. We should try to switch to using ModuleIndex instead
// where appropriate, and we should clean up code that uses ModuleID
PTR_DomainLocalModule m_ModuleID; // MultiDomain case: tagged (low bit 1) ModuleIndex
// SingleDomain case: pointer to domain local module
ModuleIndex m_ModuleIndex;
// reusing the statics area of a method table to store
// these for the non domain neutral case, but they're now unified
// it so that we don't have different code paths for this.
PTR_DWORD m_pRegularStaticOffsets; // Offset of statics in each class
PTR_DWORD m_pThreadStaticOffsets; // Offset of ThreadStatics in each class
// All types with RID <= this value have static storage allocated within the module by AllocateStatics
// If AllocateStatics hasn't run yet, the value is 0
RID m_maxTypeRidStaticsAllocated;
// @NICE: see if we can remove these fields
DWORD m_dwMaxGCRegularStaticHandles; // Max number of handles we can have.
DWORD m_dwMaxGCThreadStaticHandles;
// Size of the precomputed statics block. This includes class init bytes, gc handles and non gc statics
DWORD m_dwRegularStaticsBlockSize;
DWORD m_dwThreadStaticsBlockSize;
// For 'dynamic' statics (Reflection and generics)
SIZE_T m_cDynamicEntries; // Number of used entries in DynamicStaticsInfo table
SIZE_T m_maxDynamicEntries; // Size of table itself, including unused entries
// Info we need for dynamic statics that we can store per-module (ie, no need for it to be duplicated
// per appdomain)
struct DynamicStaticsInfo
{
MethodTable* pEnclosingMT; // Enclosing type; necessarily in this loader module
};
DynamicStaticsInfo* m_pDynamicStaticsInfo; // Table with entry for each dynamic ID
PTR_DomainAssembly m_pDomainAssembly;
public:
//-----------------------------------------------------------------------------------------
@ -1742,9 +1638,6 @@ public:
uint32_t GetNativeMetadataAssemblyCount();
#endif // !defined(DACCESS_COMPILE)
// For protecting dictionary layout slot expansions
CrstExplicitInit m_DictionaryCrst;
};
//

View file

@ -337,14 +337,6 @@ inline mdAssemblyRef Module::FindAssemblyRef(Assembly *targetAssembly)
#endif //DACCESS_COMPILE
FORCEINLINE PTR_DomainLocalModule Module::GetDomainLocalModule()
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
return m_ModuleID;
}
#include "nibblestream.h"
FORCEINLINE BOOL Module::FixupDelayList(TADDR pFixupList, BOOL mayUsePrecompiledNDirectMethods)
@ -475,13 +467,6 @@ BOOL Module::FixupDelayListAux(TADDR pFixupList,
return TRUE;
}
inline MethodTable* Module::GetDynamicClassMT(DWORD dynamicClassID)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(m_cDynamicEntries > dynamicClassID);
return VolatileLoadWithoutBarrier(&m_pDynamicStaticsInfo)[dynamicClassID].pEnclosingMT;
}
#ifdef FEATURE_CODE_VERSIONING
inline CodeVersionManager * Module::GetCodeVersionManager()
{

View file

@ -933,6 +933,8 @@ void EEStartupHelper()
SystemDomain::System()->DefaultDomain()->SetupSharedStatics();
InitializeThreadStaticData();
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
// retrieve configured max size for the mini-metadata buffer (defaults to 64KB)
g_MiniMetaDataBuffMaxSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MiniMdBufferCapacity);
@ -1720,10 +1722,27 @@ struct TlsDestructionMonitor
thread->m_pFrame = FRAME_TOP;
GCX_COOP_NO_DTOR_END();
}
#ifdef _DEBUG
BOOL oldGCOnTransitionsOK = thread->m_GCOnTransitionsOK;
thread->m_GCOnTransitionsOK = FALSE;
#endif
if (!IsAtProcessExit() && !g_fEEShutDown)
{
GCX_COOP_NO_DTOR();
FreeThreadStaticData(&t_ThreadStatics, thread);
GCX_COOP_NO_DTOR_END();
}
#ifdef _DEBUG
thread->m_GCOnTransitionsOK = oldGCOnTransitionsOK;
#endif
thread->DetachThread(TRUE);
}
else
{
// Since we don't actually cleanup the TLS data along this path, verify that it is already cleaned up
AssertThreadStaticDataFreed(&t_ThreadStatics);
}
DeleteThreadLocalMemory();
ThreadDetaching();
}
}
@ -1738,30 +1757,6 @@ void EnsureTlsDestructionMonitor()
tls_destructionMonitor.Activate();
}
#ifdef _MSC_VER
__declspec(thread) ThreadStaticBlockInfo t_ThreadStatics;
#else
__thread ThreadStaticBlockInfo t_ThreadStatics;
#endif // _MSC_VER
// Delete the thread local memory only if we the current thread
// is the one executing this code. If we do not guard it, it will
// end up deleting the thread local memory of the calling thread.
void DeleteThreadLocalMemory()
{
t_NonGCThreadStaticBlocksSize = 0;
t_GCThreadStaticBlocksSize = 0;
t_ThreadStatics.NonGCMaxThreadStaticBlocks = 0;
t_ThreadStatics.GCMaxThreadStaticBlocks = 0;
delete[] t_ThreadStatics.NonGCThreadStaticBlocks;
t_ThreadStatics.NonGCThreadStaticBlocks = nullptr;
delete[] t_ThreadStatics.GCThreadStaticBlocks;
t_ThreadStatics.GCThreadStaticBlocks = nullptr;
}
#ifdef DEBUGGING_SUPPORTED
//
// InitializeDebugger initialized the Runtime-side COM+ Debugging Services

View file

@ -47,8 +47,6 @@ void ThreadDetaching();
void EnsureTlsDestructionMonitor();
void DeleteThreadLocalMemory();
void SetLatchedExitCode (INT32 code);
INT32 GetLatchedExitCode (void);

View file

@ -590,9 +590,6 @@ class EEClassOptionalFields
// MISC FIELDS
//
#define MODULE_NON_DYNAMIC_STATICS ((DWORD)-1)
DWORD m_cbModuleDynamicID;
#if defined(UNIX_AMD64_ABI)
// Number of eightBytes in the following arrays
int m_numberEightBytes;
@ -905,22 +902,6 @@ public:
m_NumThreadStaticFields = wNumThreadStaticFields;
}
// Statics are stored in a big chunk inside the module
inline DWORD GetModuleDynamicID()
{
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
return HasOptionalFields() ? GetOptionalFields()->m_cbModuleDynamicID : MODULE_NON_DYNAMIC_STATICS;
}
inline void SetModuleDynamicID(DWORD cbModuleDynamicID)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(HasOptionalFields());
GetOptionalFields()->m_cbModuleDynamicID = cbModuleDynamicID;
}
/*
* Difference between the InterfaceMap ptr and Vtable in the
* MethodTable used to indicate the number of static bytes

View file

@ -28,7 +28,6 @@ inline void EEClassOptionalFields::Init()
m_pClassFactory = NULL;
#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
#endif // FEATURE_COMINTEROP
m_cbModuleDynamicID = MODULE_NON_DYNAMIC_STATICS;
#if defined(UNIX_AMD64_ABI)
m_numberEightBytes = 0;
#endif // UNIX_AMD64_ABI

View file

@ -119,7 +119,6 @@ typedef DPTR(struct FailedAssembly) PTR_FailedAssembly;
typedef VPTR(class EditAndContinueModule) PTR_EditAndContinueModule;
typedef DPTR(class EEClass) PTR_EEClass;
typedef DPTR(class DelegateEEClass) PTR_DelegateEEClass;
typedef DPTR(struct DomainLocalModule) PTR_DomainLocalModule;
typedef VPTR(class EECodeManager) PTR_EECodeManager;
typedef DPTR(class RangeSectionMap) PTR_RangeSectionMap;
typedef DPTR(class EEConfig) PTR_EEConfig;

View file

@ -509,6 +509,7 @@ void BulkStaticsLogger::LogAllStatics()
CONTRACTL_END;
{
// TODO: This code does not appear to find all generic instantiations of types, and thus does not log ALL statics
AppDomain *domain = ::GetAppDomain(); // There is only 1 AppDomain, so no iterator here.
AppDomain::AssemblyIterator assemblyIter = domain->IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded|kIncludeExecution));
@ -533,10 +534,6 @@ void BulkStaticsLogger::LogAllStatics()
if (!domainAssembly->IsActive())
continue;
DomainLocalModule *domainModule = module->GetDomainLocalModule();
if (domainModule == NULL)
continue;
// Now iterate all types with
LookupMap<PTR_MethodTable>::Iterator mtIter = module->EnumerateTypeDefs();
while (mtIter.Next())
@ -566,7 +563,7 @@ void BulkStaticsLogger::LogAllStatics()
if (fieldType != ELEMENT_TYPE_CLASS && fieldType != ELEMENT_TYPE_VALUETYPE)
continue;
BYTE *base = field->GetBaseInDomainLocalModule(domainModule);
BYTE *base = field->GetBase();
if (base == NULL)
continue;

View file

@ -392,20 +392,6 @@ public:
return GetApproxEnclosingMethodTable()->GetNumGenericArgs();
}
PTR_BYTE GetBaseInDomainLocalModule(DomainLocalModule * pLocalModule)
{
WRAPPER_NO_CONTRACT;
if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
return pLocalModule->GetGCStaticsBasePointer(GetEnclosingMethodTable());
}
else
{
return pLocalModule->GetNonGCStaticsBasePointer(GetEnclosingMethodTable());
}
}
PTR_BYTE GetBase()
{
CONTRACTL
@ -417,7 +403,14 @@ public:
MethodTable *pMT = GetEnclosingMethodTable();
return GetBaseInDomainLocalModule(pMT->GetDomainLocalModule());
if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
return pMT->GetGCStaticsBasePointer();
}
else
{
return pMT->GetNonGCStaticsBasePointer();
}
}
// returns the address of the field
@ -521,7 +514,10 @@ public:
else {
PTR_BYTE base = 0;
if (!IsRVA()) // for RVA the base is ignored
{
GetEnclosingMethodTable()->EnsureStaticDataAllocated();
base = GetBase();
}
return GetStaticAddress((void *)dac_cast<TADDR>(base));
}
}

View file

@ -302,6 +302,7 @@ void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen,
#endif // FEATURE_EVENT_TRACE
ScanStackRoots(pThread, fn, sc);
ScanTailCallArgBufferRoots(pThread, fn, sc);
ScanThreadStaticRoots(pThread, fn, sc);
#ifdef FEATURE_EVENT_TRACE
sc->dwEtwRootKind = kEtwGCRootKindOther;
#endif // FEATURE_EVENT_TRACE
@ -620,6 +621,7 @@ void GcScanRootsForProfilerAndETW(promote_func* fn, int condemned, int max_gen,
#endif // FEATURE_EVENT_TRACE
ScanStackRoots(pThread, fn, sc);
ScanTailCallArgBufferRoots(pThread, fn, sc);
ScanThreadStaticRoots(pThread, fn, sc);
#ifdef FEATURE_EVENT_TRACE
sc->dwEtwRootKind = kEtwGCRootKindOther;
#endif // FEATURE_EVENT_TRACE

View file

@ -48,6 +48,14 @@ inline OBJECTREF ObjectFromHandle(OBJECTHANDLE handle)
return UNCHECKED_OBJECTREF_TO_OBJECTREF(*PTR_UNCHECKED_OBJECTREF(handle));
}
// Given a handle, returns an OBJECTREF for the object it refers to.
inline _UNCHECKED_OBJECTREF ObjectFromHandleUnchecked(OBJECTHANDLE handle)
{
_ASSERTE(handle);
return (*PTR_UNCHECKED_OBJECTREF(handle));
}
// Quick inline check for whether a handle is null
inline BOOL IsHandleNullUnchecked(OBJECTHANDLE handle)
{

View file

@ -233,7 +233,7 @@ BOOL DictionaryLayout::FindTokenWorker(LoaderAllocator* pAllocat
}
// A lock should be taken by FindToken before being allowed to use an empty slot in the layout
_ASSERT(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread());
_ASSERT(GetAppDomain()->GetGenericDictionaryExpansionLock()->OwnedByCurrentThread());
PVOID pResultSignature = pSigBuilder == NULL ? pSig : CreateSignatureWithSlotData(pSigBuilder, pAllocator, slot);
pDictLayout->m_slots[iSlot].m_signature = pResultSignature;
@ -270,7 +270,7 @@ DictionaryLayout* DictionaryLayout::ExpandDictionaryLayout(LoaderAllocator*
{
STANDARD_VM_CHECK;
INJECT_FAULT(ThrowOutOfMemory(););
PRECONDITION(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread());
PRECONDITION(GetAppDomain()->GetGenericDictionaryExpansionLock()->OwnedByCurrentThread());
PRECONDITION(CheckPointer(pResult) && CheckPointer(pSlotOut));
}
CONTRACTL_END
@ -337,7 +337,7 @@ BOOL DictionaryLayout::FindToken(MethodTable* pMT,
if (FindTokenWorker(pAllocator, pMT->GetNumGenericArgs(), pMT->GetClass()->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, 0, FALSE))
return TRUE;
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock());
{
// Try again under lock in case another thread already expanded the dictionaries or filled an empty slot
if (FindTokenWorker(pMT->GetLoaderAllocator(), pMT->GetNumGenericArgs(), pMT->GetClass()->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, *pSlotOut, TRUE))
@ -384,7 +384,7 @@ BOOL DictionaryLayout::FindToken(MethodDesc* pMD,
if (FindTokenWorker(pAllocator, pMD->GetNumGenericMethodArgs(), pMD->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, 0, FALSE))
return TRUE;
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock());
{
// Try again under lock in case another thread already expanded the dictionaries or filled an empty slot
if (FindTokenWorker(pAllocator, pMD->GetNumGenericMethodArgs(), pMD->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, *pSlotOut, TRUE))
@ -502,7 +502,7 @@ Dictionary* Dictionary::GetMethodDictionaryWithSizeCheck(MethodDesc* pMD, ULONG
// Only expand the dictionary if the current slot we're trying to use is beyond the size of the dictionary
// Take lock and check for size again, just in case another thread already resized the dictionary
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock());
pDictionary = pMD->GetMethodDictionary();
currentDictionarySize = pDictionary->GetDictionarySlotsSize(numGenericArgs);
@ -560,7 +560,7 @@ Dictionary* Dictionary::GetTypeDictionaryWithSizeCheck(MethodTable* pMT, ULONG s
// Only expand the dictionary if the current slot we're trying to use is beyond the size of the dictionary
// Take lock and check for size again, just in case another thread already resized the dictionary
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock());
pDictionary = pMT->GetDictionary();
currentDictionarySize = pDictionary->GetDictionarySlotsSize(numGenericArgs);
@ -783,7 +783,7 @@ Dictionary::PopulateEntry(
#if _DEBUG
// Lock is needed because dictionary pointers can get updated during dictionary size expansion
CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst);
CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock());
// MethodTable is expected to be normalized
Dictionary* pDictionary = pMT->GetDictionary();

View file

@ -278,7 +278,13 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
memcpy((BYTE*)pMT - cbGC, (BYTE*) pOldMT - cbGC, cbGC);
// Allocate the private data block
pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, fHasGenericsStaticsInfo);
MethodTableStaticsFlags staticsFlags = MethodTableStaticsFlags::None;
if (fHasGenericsStaticsInfo)
staticsFlags |= MethodTableStaticsFlags::Generic | MethodTableStaticsFlags::Present;
if (pOldMT->GetNumThreadStaticFields() > 0)
staticsFlags |= MethodTableStaticsFlags::Thread;
pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, staticsFlags);
pMT->SetModule(pOldMT->GetModule());
pMT->GetAuxiliaryDataForWrite()->SetIsNotFullyLoadedForBuildMethodTable();
@ -334,15 +340,16 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
if (fContainsGenericVariables)
pMT->SetContainsGenericVariables();
if (fHasGenericsStaticsInfo)
pMT->SetDynamicStatics(TRUE);
// Since we are fabricating a new MT based on an existing one, the per-inst info should
// be non-null
_ASSERTE(pOldMT->HasPerInstInfo());
// Fill in per-inst map pointer (which points to the array of generic dictionary pointers)
pMT->SetPerInstInfo((MethodTable::PerInstInfoElem_t *) (pMemory + cbMT + cbOptional + cbIMap + sizeof(GenericsDictInfo)));
if (fHasGenericsStaticsInfo)
pMT->SetDynamicStatics();
_ASSERTE(FitsIn<WORD>(pOldMT->GetNumDicts()));
_ASSERTE(FitsIn<WORD>(pOldMT->GetNumGenericArgs()));
pMT->SetDictInfo(static_cast<WORD>(pOldMT->GetNumDicts()), static_cast<WORD>(pOldMT->GetNumGenericArgs()));

View file

@ -770,113 +770,6 @@ void *JIT_TrialAlloc::GenAllocString(Flags flags)
return (void *)pStub->GetEntryPoint();
}
// For this helper,
// If bCCtorCheck == true
// ECX contains the domain neutral module ID
// EDX contains the class domain ID, and the
// else
// ECX contains the domain neutral module ID
// EDX is junk
// shared static base is returned in EAX.
// "init" should be the address of a routine which takes an argument of
// the module domain ID, the class domain ID, and returns the static base pointer
void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck, bool bGCStatic)
{
STANDARD_VM_CONTRACT;
CodeLabel *DoInit = 0;
if (bCCtorCheck)
{
DoInit = psl->NewCodeLabel();
}
// mov eax, ecx
psl->Emit8(0x89);
psl->Emit8(0xc8);
if (bCCtorCheck)
{
// test [eax + edx + offsetof(DomainLocalModule, m_pDataBlob], ClassInitFlags::INITIALIZED_FLAG // Is class inited
_ASSERTE(FitsInI1(ClassInitFlags::INITIALIZED_FLAG));
_ASSERTE(FitsInI1(DomainLocalModule::GetOffsetOfDataBlob()));
BYTE testClassInit[] = { 0xF6, 0x44, 0x10,
(BYTE) DomainLocalModule::GetOffsetOfDataBlob(), (BYTE)ClassInitFlags::INITIALIZED_FLAG };
psl->EmitBytes(testClassInit, sizeof(testClassInit));
// jz init // no, init it
psl->X86EmitCondJump(DoInit, X86CondCode::kJZ);
}
if (bGCStatic)
{
// Indirect to get the pointer to the first GC Static
psl->X86EmitIndexRegLoad(kEAX, kEAX, (int32_t) DomainLocalModule::GetOffsetOfGCStaticPointer());
}
// ret
psl->X86EmitReturn(0);
if (bCCtorCheck)
{
// DoInit:
psl->EmitLabel(DoInit);
psl->X86EmitPushEBPframe();
#ifdef UNIX_X86_ABI
#define STACK_ALIGN_PADDING 4
// sub esp, STACK_ALIGN_PADDING; to align the stack
psl->X86EmitSubEsp(STACK_ALIGN_PADDING);
#endif // UNIX_X86_ABI
// push edx (must be preserved)
psl->X86EmitPushReg(kEDX);
// call init
psl->X86EmitCall(init, 0);
// pop edx
psl->X86EmitPopReg(kEDX);
#ifdef UNIX_X86_ABI
// add esp, STACK_ALIGN_PADDING
psl->X86EmitAddEsp(STACK_ALIGN_PADDING);
#undef STACK_ALIGN_PADDING
#endif // UNIX_X86_ABI
psl->X86EmitPopReg(kEBP);
// ret
psl->X86EmitReturn(0);
}
}
void *GenFastGetSharedStaticBase(bool bCheckCCtor, bool bGCStatic)
{
STANDARD_VM_CONTRACT;
CPUSTUBLINKER sl;
CodeLabel *init;
if (bGCStatic)
{
init = sl.NewExternalCodeLabel((LPVOID)JIT_GetSharedGCStaticBase);
}
else
{
init = sl.NewExternalCodeLabel((LPVOID)JIT_GetSharedNonGCStaticBase);
}
EmitFastGetSharedStaticBase(&sl, init, bCheckCCtor, bGCStatic);
Stub *pStub = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap());
return (void*) pStub->GetEntryPoint();
}
#define NUM_WRITE_BARRIERS 6
@ -969,16 +862,6 @@ void InitJITHelpers1()
ECall::DynamicallyAssignFCallImpl((PCODE) JIT_TrialAlloc::GenAllocString(flags), ECall::FastAllocateString);
}
// Replace static helpers with faster assembly versions
pMethodAddresses[6] = GenFastGetSharedStaticBase(true, true);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, pMethodAddresses[6]);
pMethodAddresses[7] = GenFastGetSharedStaticBase(true, false);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, pMethodAddresses[7]);
pMethodAddresses[8] = GenFastGetSharedStaticBase(false, true);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, pMethodAddresses[8]);
pMethodAddresses[9] = GenFastGetSharedStaticBase(false, false);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, pMethodAddresses[9]);
ETW::MethodLog::StubsInitialized(pMethodAddresses, (PVOID *)pHelperNames, ETW_NUM_JIT_HELPERS);
// All write barrier helpers should fit into one page.

View file

@ -1017,9 +1017,8 @@ HCIMPL1(void, JIT_InitClass, CORINFO_CLASS_HANDLE typeHnd_)
TypeHandle typeHnd(typeHnd_);
MethodTable *pMT = typeHnd.AsMethodTable();
_ASSERTE(!pMT->IsClassPreInited());
if (pMT->GetDomainLocalModule()->IsClassInitialized(pMT))
if (pMT->IsClassInited())
return;
// Tailcall to the slow helper
@ -1070,57 +1069,107 @@ HCIMPLEND
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedNonGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwClassDomainID)
HCIMPL1(void*, JIT_GetNonGCStaticBase_Portable, MethodTable* pMT)
{
FCALL_CONTRACT;
// If type doesn't have a class constructor, the contents of this if statement may
// still get executed. JIT_GetSharedNonGCStaticBaseNoCtor should be used in this case.
if (pLocalModule->IsPrecomputedClassInitialized(dwClassDomainID))
PTR_BYTE pBase;
if (pMT->GetDynamicStaticsInfo()->GetIsInitedAndNonGCStaticsPointerIfInited(&pBase))
{
return (void*)pLocalModule->GetPrecomputedNonGCStaticsBasePointer();
return pBase;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL2(JIT_GetSharedNonGCStaticBase_Helper, pLocalModule, dwClassDomainID);
return HCCALL1(JIT_GetNonGCStaticBase_Helper, pMT);
}
HCIMPLEND
HCIMPL1(void*, JIT_GetDynamicNonGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo)
{
FCALL_CONTRACT;
PTR_BYTE pBase;
if (pStaticsInfo->GetIsInitedAndNonGCStaticsPointerIfInited(&pBase))
{
return pBase;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetNonGCStaticBase_Helper, pStaticsInfo->GetMethodTable());
}
HCIMPLEND
// No constructor version of JIT_GetSharedNonGCStaticBase. Does not check if class has
// been initialized.
HCIMPL1(void*, JIT_GetNonGCStaticBaseNoCtor_Portable, MethodTable* pMT)
{
FCALL_CONTRACT;
return pMT->GetDynamicStaticsInfo()->GetNonGCStaticsPointerAssumeIsInited();
}
HCIMPLEND
// No constructor version of JIT_GetSharedNonGCStaticBase. Does not check if class has
// been initialized.
HCIMPL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule)
HCIMPL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pDynamicStaticsInfo)
{
FCALL_CONTRACT;
return (void*)pLocalModule->GetPrecomputedNonGCStaticsBasePointer();
return pDynamicStaticsInfo->GetNonGCStaticsPointerAssumeIsInited();
}
HCIMPLEND
HCIMPL2(void*, JIT_GetSharedGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwClassDomainID)
HCIMPL1(void*, JIT_GetGCStaticBase_Portable, MethodTable* pMT)
{
FCALL_CONTRACT;
// If type doesn't have a class constructor, the contents of this if statement may
// still get executed. JIT_GetSharedGCStaticBaseNoCtor should be used in this case.
if (pLocalModule->IsPrecomputedClassInitialized(dwClassDomainID))
PTR_OBJECTREF pBase;
if (pMT->GetDynamicStaticsInfo()->GetIsInitedAndGCStaticsPointerIfInited(&pBase))
{
return (void*)pLocalModule->GetPrecomputedGCStaticsBasePointer();
return pBase;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL2(JIT_GetSharedGCStaticBase_Helper, pLocalModule, dwClassDomainID);
return HCCALL1(JIT_GetGCStaticBase_Helper, pMT);
}
HCIMPLEND
HCIMPL1(void*, JIT_GetDynamicGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo)
{
FCALL_CONTRACT;
PTR_OBJECTREF pBase;
if (pStaticsInfo->GetIsInitedAndGCStaticsPointerIfInited(&pBase))
{
return pBase;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetGCStaticBase_Helper, pStaticsInfo->GetMethodTable());
}
HCIMPLEND
// No constructor version of JIT_GetSharedGCStaticBase. Does not check if class has been
// initialized.
HCIMPL1(void*, JIT_GetSharedGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule)
HCIMPL1(void*, JIT_GetGCStaticBaseNoCtor_Portable, MethodTable* pMT)
{
FCALL_CONTRACT;
return (void*)pLocalModule->GetPrecomputedGCStaticsBasePointer();
return pMT->GetDynamicStaticsInfo()->GetGCStaticsPointerAssumeIsInited();
}
HCIMPLEND
// No constructor version of JIT_GetSharedGCStaticBase. Does not check if class has been
// initialized.
HCIMPL1(void*, JIT_GetDynamicGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pDynamicStaticsInfo)
{
FCALL_CONTRACT;
return pDynamicStaticsInfo->GetGCStaticsPointerAssumeIsInited();
}
HCIMPLEND
@ -1129,309 +1178,86 @@ HCIMPLEND
// The following two functions can be tail called from platform dependent versions of
// JIT_GetSharedGCStaticBase and JIT_GetShareNonGCStaticBase
HCIMPL2(void*, JIT_GetSharedNonGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID)
HCIMPL1(void*, JIT_GetNonGCStaticBase_Helper, MethodTable* pMT)
{
FCALL_CONTRACT;
HELPER_METHOD_FRAME_BEGIN_RET_0();
// Obtain Method table
MethodTable * pMT = pLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID);
PREFIX_ASSUME(pMT != NULL);
pMT->CheckRunClassInitThrowing();
HELPER_METHOD_FRAME_END();
return (void*)pLocalModule->GetPrecomputedNonGCStaticsBasePointer();
return (void*)pMT->GetDynamicStaticsInfo()->GetNonGCStaticsPointer();
}
HCIMPLEND
HCIMPL2(void*, JIT_GetSharedGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID)
HCIMPL1(void*, JIT_GetGCStaticBase_Helper, MethodTable* pMT)
{
FCALL_CONTRACT;
HELPER_METHOD_FRAME_BEGIN_RET_0();
// Obtain Method table
MethodTable * pMT = pLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID);
PREFIX_ASSUME(pMT != NULL);
pMT->CheckRunClassInitThrowing();
HELPER_METHOD_FRAME_END();
return (void*)pLocalModule->GetPrecomputedGCStaticsBasePointer();
return (void*)pMT->GetDynamicStaticsInfo()->GetGCStaticsPointer();
}
HCIMPLEND
/*********************************************************************/
// Slow helper to tail call from the fast one
HCIMPL2(void*, JIT_GetSharedNonGCStaticBaseDynamicClass_Helper, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
void* result = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0();
MethodTable *pMT = pLocalModule->GetDomainAssembly()->GetModule()->GetDynamicClassMT(dwDynamicClassDomainID);
_ASSERTE(pMT);
pMT->CheckRunClassInitThrowing();
result = (void*)pLocalModule->GetDynamicEntryNonGCStaticsBasePointer(dwDynamicClassDomainID, pMT->GetLoaderAllocator());
HELPER_METHOD_FRAME_END();
return result;
}
HCIMPLEND
/*************************************************************/
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedNonGCStaticBaseDynamicClass, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL2(JIT_GetSharedNonGCStaticBaseDynamicClass_Helper, pLocalModule, dwDynamicClassDomainID);
}
HCIMPLEND
#include <optdefault.h>
/*************************************************************/
// Slow helper to tail call from the fast one
HCIMPL2(void, JIT_ClassInitDynamicClass_Helper, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
HELPER_METHOD_FRAME_BEGIN_0();
MethodTable *pMT = pLocalModule->GetDomainAssembly()->GetModule()->GetDynamicClassMT(dwDynamicClassDomainID);
_ASSERTE(pMT);
pMT->CheckRunClassInitThrowing();
HELPER_METHOD_FRAME_END();
return;
}
HCIMPLEND
#include <optsmallperfcritical.h>
HCIMPL2(void, JIT_ClassInitDynamicClass, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
return;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL2(JIT_ClassInitDynamicClass_Helper, pLocalModule, dwDynamicClassDomainID);
}
HCIMPLEND
#include <optdefault.h>
/*************************************************************/
// Slow helper to tail call from the fast one
HCIMPL2(void*, JIT_GetSharedGCStaticBaseDynamicClass_Helper, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
void* result = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0();
MethodTable *pMT = pLocalModule->GetDomainAssembly()->GetModule()->GetDynamicClassMT(dwDynamicClassDomainID);
_ASSERTE(pMT);
pMT->CheckRunClassInitThrowing();
result = (void*)pLocalModule->GetDynamicEntryGCStaticsBasePointer(dwDynamicClassDomainID, pMT->GetLoaderAllocator());
HELPER_METHOD_FRAME_END();
return result;
}
HCIMPLEND
/*************************************************************/
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedGCStaticBaseDynamicClass, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL2(JIT_GetSharedGCStaticBaseDynamicClass_Helper, pLocalModule, dwDynamicClassDomainID);
}
HCIMPLEND
#include <optdefault.h>
/*********************************************************************/
// Slow helper to tail call from the fast one
NOINLINE HCIMPL1(void*, JIT_GetGenericsGCStaticBase_Framed, MethodTable *pMT)
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(pMT->HasGenericsStaticsInfo());
} CONTRACTL_END;
void* base = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0();
_ASSERTE(pMT->IsFullyLoaded());
pMT->CheckRunClassInitThrowing();
base = (void*) pMT->GetGCStaticsBasePointer();
CONSISTENCY_CHECK(base != NULL);
HELPER_METHOD_FRAME_END();
return base;
}
HCIMPLEND
/*********************************************************************/
#include <optsmallperfcritical.h>
HCIMPL1(void*, JIT_GetGenericsGCStaticBase, MethodTable *pMT)
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(pMT->HasGenericsStaticsInfo());
} CONTRACTL_END;
DWORD dwDynamicClassDomainID;
PTR_Module pModuleForStatics = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID);
DomainLocalModule *pLocalModule = pModuleForStatics->GetDomainLocalModule();
_ASSERTE(pLocalModule);
DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetGenericsGCStaticBase_Framed, pMT);
}
HCIMPLEND
#include <optdefault.h>
/*********************************************************************/
// Slow helper to tail call from the fast one
NOINLINE HCIMPL1(void*, JIT_GetGenericsNonGCStaticBase_Framed, MethodTable *pMT)
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(pMT->HasGenericsStaticsInfo());
} CONTRACTL_END;
void* base = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0();
_ASSERTE(pMT->IsFullyLoaded());
// If pMT refers to a method table that requires some initialization work,
// then pMT cannot to a method table that is shared by generic instantiations,
// because method tables that are shared by generic instantiations do not have
// a base for statics to live in.
_ASSERTE(pMT->IsClassPreInited() || !pMT->IsSharedByGenericInstantiations());
pMT->CheckRunClassInitThrowing();
// We could just return null here instead of returning base when this helper is called just to trigger the cctor
base = (void*) pMT->GetNonGCStaticsBasePointer();
HELPER_METHOD_FRAME_END();
return base;
}
HCIMPLEND
/*********************************************************************/
#include <optsmallperfcritical.h>
HCIMPL1(void*, JIT_GetGenericsNonGCStaticBase, MethodTable *pMT)
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(pMT->HasGenericsStaticsInfo());
} CONTRACTL_END;
// This fast path will typically always be taken once the slow framed path below
// has executed once. Sometimes the slow path will be executed more than once,
// e.g. if static fields are accessed during the call to CheckRunClassInitThrowing()
// in the slow path.
DWORD dwDynamicClassDomainID;
PTR_Module pModuleForStatics = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID);
DomainLocalModule *pLocalModule = pModuleForStatics->GetDomainLocalModule();
_ASSERTE(pLocalModule);
DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetGenericsNonGCStaticBase_Framed, pMT);
}
HCIMPLEND
#include <optdefault.h>
//========================================================================
//
// THREAD STATIC FIELD HELPERS
//
//========================================================================
// Define the t_ThreadStatics variable here, so that these helpers can use
// the most optimal TLS access pattern for the platform when inlining the
// GetThreadLocalStaticBaseIfExistsAndInitialized function
#ifdef _MSC_VER
__declspec(selectany) __declspec(thread) ThreadLocalData t_ThreadStatics;
#else
__thread ThreadLocalData t_ThreadStatics;
#endif // _MSC_VER
// This is the routine used by the JIT helpers for the fast path. It is not used by the JIT for the slow path, or by the EE for any path.
// This is inlined in the header to improve code gen quality
FORCEINLINE void* GetThreadLocalStaticBaseIfExistsAndInitialized(TLSIndex index)
{
LIMITED_METHOD_CONTRACT;
TADDR pTLSBaseAddress = (TADDR)NULL;
if (index.GetTLSIndexType() == TLSIndexType::NonCollectible)
{
PTRARRAYREF tlsArray = (PTRARRAYREF)UNCHECKED_OBJECTREF_TO_OBJECTREF(t_ThreadStatics.pNonCollectibleTlsArrayData);
if (t_ThreadStatics.cNonCollectibleTlsData <= index.GetIndexOffset())
{
return NULL;
}
pTLSBaseAddress = (TADDR)OBJECTREFToObject(tlsArray->GetAt(index.GetIndexOffset() - NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY));
}
else if (index.GetTLSIndexType() == TLSIndexType::DirectOnThreadLocalData)
{
return ((BYTE*)&t_ThreadStatics) + index.GetIndexOffset();
}
else
{
int32_t cCollectibleTlsData = t_ThreadStatics.cCollectibleTlsData;
if (cCollectibleTlsData <= index.GetIndexOffset())
{
return NULL;
}
OBJECTHANDLE* pCollectibleTlsArrayData = t_ThreadStatics.pCollectibleTlsArrayData;
pCollectibleTlsArrayData += index.GetIndexOffset();
OBJECTHANDLE objHandle = *pCollectibleTlsArrayData;
if (IsHandleNullUnchecked(objHandle))
return NULL;
pTLSBaseAddress = dac_cast<TADDR>(OBJECTREFToObject(ObjectFromHandle(objHandle)));
}
return reinterpret_cast<void*>(pTLSBaseAddress);
}
// *** These framed helpers get called if allocation needs to occur or
// if the class constructor needs to run
@ -1447,14 +1273,8 @@ HCIMPL1(void*, JIT_GetNonGCThreadStaticBase_Helper, MethodTable * pMT)
HELPER_METHOD_FRAME_BEGIN_RET_0();
_ASSERTE(pMT->IsFullyLoaded());
// Get the TLM
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT);
_ASSERTE(pThreadLocalModule != NULL);
// Check if the class constructor needs to be run
pThreadLocalModule->CheckRunClassInitThrowing(pMT);
pMT->CheckRunClassInitThrowing();
// Lookup the non-GC statics base pointer
base = (void*) pMT->GetNonGCThreadStaticsBasePointer();
@ -1477,14 +1297,8 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT)
HELPER_METHOD_FRAME_BEGIN_RET_0();
_ASSERTE(pMT->IsFullyLoaded());
// Get the TLM
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT);
_ASSERTE(pThreadLocalModule != NULL);
// Check if the class constructor needs to be run
pThreadLocalModule->CheckRunClassInitThrowing(pMT);
pMT->CheckRunClassInitThrowing();
// Lookup the GC statics base pointer
base = (void*) pMT->GetGCThreadStaticsBasePointer();
@ -1496,14 +1310,6 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT)
}
HCIMPLEND
#ifdef _MSC_VER
__declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize;
__declspec(thread) uint32_t t_GCThreadStaticBlocksSize;
#else
__thread uint32_t t_NonGCThreadStaticBlocksSize;
__thread uint32_t t_GCThreadStaticBlocksSize;
#endif // !_MSC_VER
// *** This helper corresponds to both CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE and
// CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR. Even though we always check
// if the class constructor has been run, we have a separate helper ID for the "no ctor"
@ -1511,90 +1317,69 @@ __thread uint32_t t_GCThreadStaticBlocksSize;
// possible.
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID)
HCIMPL1(void*, JIT_GetNonGCThreadStaticBase, MethodTable *pMT)
{
FCALL_CONTRACT;
// Get the ModuleIndex
ModuleIndex index = pDomainLocalModule->GetModuleIndex();
// Get the relevant ThreadLocalModule
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
// If the TLM has been allocated and the class has been marked as initialized,
// get the pointer to the non-GC statics base and return
if (pThreadLocalModule != NULL && pThreadLocalModule->IsPrecomputedClassInitialized(dwClassDomainID))
return (void*)pThreadLocalModule->GetPrecomputedNonGCStaticsBasePointer();
// If the TLM was not allocated or if the class was not marked as initialized
// then we have to go through the slow path
// Obtain the MethodTable
MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID);
_ASSERTE(!pMT->HasGenericsStaticsInfo());
void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pMT->GetThreadStaticsInfo()->NonGCTlsIndex);
if (pThreadStaticBase != NULL)
{
return pThreadStaticBase;
}
ENDFORBIDGC();
return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT);
}
HCIMPLEND
HCIMPL1(void*, JIT_GetDynamicNonGCThreadStaticBase, ThreadStaticsInfo *pThreadStaticsInfo)
{
FCALL_CONTRACT;
void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pThreadStaticsInfo->NonGCTlsIndex);
if (pThreadStaticBase != NULL)
{
return pThreadStaticBase;
}
ENDFORBIDGC();
return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pThreadStaticsInfo->m_genericStatics.m_DynamicStatics.GetMethodTable());
}
HCIMPLEND
// *** This helper corresponds CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED.
// Even though we always check if the class constructor has been run, we have a separate
// helper ID for the "no ctor" version because it allows the JIT to do some reordering that
// otherwise wouldn't be possible.
HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex)
HCIMPL1(void*, JIT_GetNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex)
{
void* staticBlock = nullptr;
FCALL_CONTRACT;
HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame
MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupNonGCThreadStaticBlockType(staticBlockIndex);
_ASSERTE(!pMT->HasGenericsStaticsInfo());
// Get the TLM
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT);
_ASSERTE(pThreadLocalModule != NULL);
TLSIndex tlsIndex(staticBlockIndex);
// Check if the class constructor needs to be run
pThreadLocalModule->CheckRunClassInitThrowing(pMT);
MethodTable *pMT = LookupMethodTableForThreadStaticKnownToBeAllocated(tlsIndex);
pMT->CheckRunClassInitThrowing();
// Lookup the non-GC statics base pointer
staticBlock = (void*) pMT->GetNonGCThreadStaticsBasePointer();
CONSISTENCY_CHECK(staticBlock != NULL);
if (t_NonGCThreadStaticBlocksSize <= staticBlockIndex)
{
UINT32 newThreadStaticBlocksSize = max(2 * t_NonGCThreadStaticBlocksSize, staticBlockIndex + 1);
void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)];
memset(newThreadStaticBlocks + t_NonGCThreadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_NonGCThreadStaticBlocksSize) * sizeof(PTR_BYTE));
if (t_NonGCThreadStaticBlocksSize > 0)
{
memcpy(newThreadStaticBlocks, t_ThreadStatics.NonGCThreadStaticBlocks, t_NonGCThreadStaticBlocksSize * sizeof(PTR_BYTE));
delete[] t_ThreadStatics.NonGCThreadStaticBlocks;
}
t_NonGCThreadStaticBlocksSize = newThreadStaticBlocksSize;
t_ThreadStatics.NonGCThreadStaticBlocks = newThreadStaticBlocks;
}
void* currentEntry = t_ThreadStatics.NonGCThreadStaticBlocks[staticBlockIndex];
// We could be coming here 2nd time after running the ctor when we try to get the static block.
// In such case, just avoid adding the same entry.
if (currentEntry != staticBlock)
{
_ASSERTE(currentEntry == nullptr);
t_ThreadStatics.NonGCThreadStaticBlocks[staticBlockIndex] = staticBlock;
t_ThreadStatics.NonGCMaxThreadStaticBlocks = max(t_ThreadStatics.NonGCMaxThreadStaticBlocks, staticBlockIndex);
}
HELPER_METHOD_FRAME_END();
return staticBlock;
}
HCIMPLEND
// *** This helper corresponds CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2.
HCIMPL1(void*, JIT_GetNonGCThreadStaticBaseOptimized2, UINT32 staticBlockIndex)
{
FCALL_CONTRACT;
return ((BYTE*)&t_ThreadStatics) + staticBlockIndex;
}
HCIMPLEND
#include <optdefault.h>
// *** This helper corresponds to both CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE and
@ -1604,39 +1389,43 @@ HCIMPLEND
// possible.
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID)
HCIMPL1(void*, JIT_GetGCThreadStaticBase, MethodTable *pMT)
{
FCALL_CONTRACT;
// Get the ModuleIndex
ModuleIndex index = pDomainLocalModule->GetModuleIndex();
// Get the relevant ThreadLocalModule
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
// If the TLM has been allocated and the class has been marked as initialized,
// get the pointer to the GC statics base and return
if (pThreadLocalModule != NULL && pThreadLocalModule->IsPrecomputedClassInitialized(dwClassDomainID))
return (void*)pThreadLocalModule->GetPrecomputedGCStaticsBasePointer();
// If the TLM was not allocated or if the class was not marked as initialized
// then we have to go through the slow path
// Obtain the MethodTable
MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID);
_ASSERTE(!pMT->HasGenericsStaticsInfo());
void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pMT->GetThreadStaticsInfo()->GCTlsIndex);
if (pThreadStaticBase != NULL)
{
return pThreadStaticBase;
}
ENDFORBIDGC();
return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT);
}
HCIMPLEND
HCIMPL1(void*, JIT_GetDynamicGCThreadStaticBase, ThreadStaticsInfo *pThreadStaticsInfo)
{
FCALL_CONTRACT;
void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pThreadStaticsInfo->GCTlsIndex);
if (pThreadStaticBase != NULL)
{
return pThreadStaticBase;
}
ENDFORBIDGC();
return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pThreadStaticsInfo->m_genericStatics.m_DynamicStatics.GetMethodTable());
}
HCIMPLEND
#include <optdefault.h>
// *** This helper corresponds CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED.
// Even though we always check if the class constructor has been run, we have a separate
// helper ID for the "no ctor" version because it allows the JIT to do some reordering that
// otherwise wouldn't be possible.
HCIMPL1(void*, JIT_GetSharedGCThreadStaticBaseOptimized, UINT32 staticBlockIndex)
HCIMPL1(void*, JIT_GetGCThreadStaticBaseOptimized, UINT32 staticBlockIndex)
{
void* staticBlock = nullptr;
@ -1644,254 +1433,19 @@ HCIMPL1(void*, JIT_GetSharedGCThreadStaticBaseOptimized, UINT32 staticBlockIndex
HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame
MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupGCThreadStaticBlockType(staticBlockIndex);
_ASSERTE(!pMT->HasGenericsStaticsInfo());
// Get the TLM
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT);
_ASSERTE(pThreadLocalModule != NULL);
TLSIndex tlsIndex(staticBlockIndex);
// Check if the class constructor needs to be run
pThreadLocalModule->CheckRunClassInitThrowing(pMT);
MethodTable *pMT = LookupMethodTableForThreadStaticKnownToBeAllocated(tlsIndex);
pMT->CheckRunClassInitThrowing();
// Lookup the GC statics base handle and cache it
staticBlock = (void*) pMT->GetGCThreadStaticsBaseHandle();
CONSISTENCY_CHECK(staticBlock != NULL);
if (t_GCThreadStaticBlocksSize <= staticBlockIndex)
{
UINT32 newThreadStaticBlocksSize = max(2 * t_GCThreadStaticBlocksSize, staticBlockIndex + 1);
void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)];
memset(newThreadStaticBlocks + t_GCThreadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_GCThreadStaticBlocksSize) * sizeof(PTR_BYTE));
if (t_GCThreadStaticBlocksSize > 0)
{
memcpy(newThreadStaticBlocks, t_ThreadStatics.GCThreadStaticBlocks, t_GCThreadStaticBlocksSize * sizeof(PTR_BYTE));
delete[] t_ThreadStatics.GCThreadStaticBlocks;
}
t_GCThreadStaticBlocksSize = newThreadStaticBlocksSize;
t_ThreadStatics.GCThreadStaticBlocks = newThreadStaticBlocks;
}
void* currentEntry = t_ThreadStatics.GCThreadStaticBlocks[staticBlockIndex];
// We could be coming here 2nd time after running the ctor when we try to get the static block.
// In such case, just avoid adding the same entry.
if (currentEntry != staticBlock)
{
_ASSERTE(currentEntry == nullptr);
t_ThreadStatics.GCThreadStaticBlocks[staticBlockIndex] = staticBlock;
t_ThreadStatics.GCMaxThreadStaticBlocks = max(t_ThreadStatics.GCMaxThreadStaticBlocks, staticBlockIndex);
}
// Get the data pointer of static block
// Lookup the non-GC statics base pointer
staticBlock = (void*) pMT->GetGCThreadStaticsBasePointer();
HELPER_METHOD_FRAME_END();
return staticBlock;
}
HCIMPLEND
// *** This helper corresponds to CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBaseDynamicClass, DomainLocalModule *pDomainLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
// Get the ModuleIndex
ModuleIndex index = pDomainLocalModule->GetModuleIndex();
// Get the relevant ThreadLocalModule
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
// If the TLM has been allocated and the class has been marked as initialized,
// get the pointer to the non-GC statics base and return
if (pThreadLocalModule != NULL)
{
ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_NONGCTHREADSTATICS_BASEPOINTER(pDomainLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
}
// If the TLM was not allocated or if the class was not marked as initialized
// then we have to go through the slow path
// Obtain the Module
Module * pModule = pDomainLocalModule->GetDomainAssembly()->GetModule();
// Obtain the MethodTable
MethodTable * pMT = pModule->GetDynamicClassMT(dwDynamicClassDomainID);
_ASSERTE(pMT != NULL);
_ASSERTE(!pMT->IsSharedByGenericInstantiations());
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT);
}
HCIMPLEND
#include <optdefault.h>
// *** This helper corresponds to CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
#include <optsmallperfcritical.h>
HCIMPL2(void*, JIT_GetSharedGCThreadStaticBaseDynamicClass, DomainLocalModule *pDomainLocalModule, DWORD dwDynamicClassDomainID)
{
FCALL_CONTRACT;
// Get the ModuleIndex
ModuleIndex index = pDomainLocalModule->GetModuleIndex();
// Get the relevant ThreadLocalModule
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
// If the TLM has been allocated and the class has been marked as initialized,
// get the pointer to the GC statics base and return
if (pThreadLocalModule != NULL)
{
ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_GCTHREADSTATICS_BASEPOINTER(pDomainLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
}
// If the TLM was not allocated or if the class was not marked as initialized
// then we have to go through the slow path
// Obtain the Module
Module * pModule = pDomainLocalModule->GetDomainAssembly()->GetModule();
// Obtain the MethodTable
MethodTable * pMT = pModule->GetDynamicClassMT(dwDynamicClassDomainID);
_ASSERTE(pMT != NULL);
_ASSERTE(!pMT->IsSharedByGenericInstantiations());
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT);
}
HCIMPLEND
#include <optdefault.h>
// *** This helper corresponds to CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
#include <optsmallperfcritical.h>
HCIMPL1(void*, JIT_GetGenericsNonGCThreadStaticBase, MethodTable *pMT)
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(pMT->HasGenericsStaticsInfo());
} CONTRACTL_END;
// This fast path will typically always be taken once the slow framed path below
// has executed once. Sometimes the slow path will be executed more than once,
// e.g. if static fields are accessed during the call to CheckRunClassInitThrowing()
// in the slow path.
// Get the Module and dynamic class ID
DWORD dwDynamicClassDomainID;
PTR_Module pModule = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID);
// Get ModuleIndex
ModuleIndex index = pModule->GetModuleIndex();
// Get the relevant ThreadLocalModule
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
// If the TLM has been allocated and the class has been marked as initialized,
// get the pointer to the non-GC statics base and return
if (pThreadLocalModule != NULL)
{
ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
}
// If the TLM was not allocated or if the class was not marked as initialized
// then we have to go through the slow path
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT);
}
HCIMPLEND
#include <optdefault.h>
// *** This helper corresponds to CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE
#include <optsmallperfcritical.h>
HCIMPL1(void*, JIT_GetGenericsGCThreadStaticBase, MethodTable *pMT)
{
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(pMT->HasGenericsStaticsInfo());
} CONTRACTL_END;
// This fast path will typically always be taken once the slow framed path below
// has executed once. Sometimes the slow path will be executed more than once,
// e.g. if static fields are accessed during the call to CheckRunClassInitThrowing()
// in the slow path.
// Get the Module and dynamic class ID
DWORD dwDynamicClassDomainID;
PTR_Module pModule = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID);
// Get ModuleIndex
ModuleIndex index = pModule->GetModuleIndex();
// Get the relevant ThreadLocalModule
ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index);
// If the TLM has been allocated and the class has been marked as initialized,
// get the pointer to the GC statics base and return
if (pThreadLocalModule != NULL)
{
ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID);
if (pLocalInfo != NULL)
{
PTR_BYTE retval;
GET_DYNAMICENTRY_GCTHREADSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(),
pLocalInfo,
&retval);
return retval;
}
}
// If the TLM was not allocated or if the class was not marked as initialized
// then we have to go through the slow path
// Tailcall to the slow helper
ENDFORBIDGC();
return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT);
}
HCIMPLEND
#include <optdefault.h>
//========================================================================
//
// STATIC FIELD DYNAMIC HELPERS
@ -1903,7 +1457,7 @@ HCIMPL1_RAW(TADDR, JIT_StaticFieldAddress_Dynamic, StaticFieldAddressArgs * pArg
{
FCALL_CONTRACT;
TADDR base = HCCALL2(pArgs->staticBaseHelper, pArgs->arg0, pArgs->arg1);
TADDR base = HCCALL1(pArgs->staticBaseHelper, pArgs->arg0);
return base + pArgs->offset;
}
HCIMPLEND_RAW
@ -1914,7 +1468,7 @@ HCIMPL1_RAW(TADDR, JIT_StaticFieldAddressUnbox_Dynamic, StaticFieldAddressArgs *
{
FCALL_CONTRACT;
TADDR base = HCCALL2(pArgs->staticBaseHelper, pArgs->arg0, pArgs->arg1);
TADDR base = HCCALL1(pArgs->staticBaseHelper, pArgs->arg0);
return *(TADDR *)(base + pArgs->offset) + Object::GetOffsetOfFirstField();
}
HCIMPLEND_RAW

View file

@ -65,14 +65,6 @@
#include "tailcallhelp.h"
#ifdef TARGET_WINDOWS
EXTERN_C uint32_t _tls_index;
#endif
#ifndef _MSC_VER
extern "C" void* __tls_get_addr(void* ti);
#endif // !_MSC_VER
// The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
//
@ -1153,78 +1145,137 @@ static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
{
STANDARD_VM_CONTRACT;
int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
int helper = CORINFO_HELP_GET_NONGCSTATIC_BASE;
if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
helper = CORINFO_HELP_GET_GCSTATIC_BASE;
}
if (pField->IsThreadStatic())
{
const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
== CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
if (helper == CORINFO_HELP_GET_NONGCSTATIC_BASE)
helper = CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE;
else
helper = CORINFO_HELP_GET_GCTHREADSTATIC_BASE;
}
return (CorInfoHelpFunc)helper;
}
size_t CEEInfo::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
} CONTRACTL_END;
size_t result;
JIT_TO_EE_TRANSITION_LEAF();
TypeHandle clsTypeHandle(cls);
PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
result = (size_t)pMT->GetThreadStaticsInfo();
EE_TO_JIT_TRANSITION_LEAF();
return result;
}
size_t CEEInfo::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
} CONTRACTL_END;
size_t result;
JIT_TO_EE_TRANSITION_LEAF();
TypeHandle clsTypeHandle(cls);
PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
result = (size_t)pMT->GetDynamicStaticsInfo();
EE_TO_JIT_TRANSITION_LEAF();
return result;
}
CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
{
STANDARD_VM_CONTRACT;
int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
pFieldMT->AttemptToPreinit();
bool GCStatic = (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE);
bool noCtor = pFieldMT->IsClassInited();
bool threadStatic = pField->IsThreadStatic();
bool isInexactMT = pFieldMT->IsSharedByGenericInstantiations();
bool isCollectible = pFieldMT->Collectible();
_ASSERTE(!isInexactMT);
CorInfoHelpFunc helper;
if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
if (threadStatic)
{
helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
}
if (pFieldMT->IsDynamicStatics())
if (GCStatic)
{
const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
== CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
helper += delta;
if (noCtor)
helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE;
}
else
if ((!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics()) || pFieldMT->IsClassInited())
{
const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
== CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
helper += delta;
if (noCtor)
helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE;
}
}
else
{
if (GCStatic)
{
if (noCtor)
{
if (isCollectible)
helper = CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR;
}
else
{
if (isCollectible)
helper = CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE;
else
helper = CORINFO_HELP_GETPINNED_GCSTATIC_BASE;
}
}
else
{
if (noCtor)
{
if (isCollectible)
helper = CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR;
}
else
{
if (isCollectible)
helper = CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE;
else
helper = CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE;
}
}
}
if (pField->IsThreadStatic())
{
const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
== CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
== CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
== CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
== CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
== CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
helper += delta;
}
return (CorInfoHelpFunc)helper;
return helper;
}
static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
@ -1313,14 +1364,16 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isG
FieldDesc* fieldDesc = (FieldDesc*)field;
_ASSERTE(fieldDesc->IsThreadStatic());
MethodTable *pMT = fieldDesc->GetEnclosingMethodTable();
pMT->EnsureTlsIndexAllocated();
if (isGCType)
{
typeIndex = AppDomain::GetCurrentDomain()->GetGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable());
typeIndex = MethodTableAuxiliaryData::GetThreadStaticsInfo(pMT->GetAuxiliaryData())->GCTlsIndex.GetIndexOffset();
}
else
{
typeIndex = AppDomain::GetCurrentDomain()->GetNonGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable());
typeIndex = MethodTableAuxiliaryData::GetThreadStaticsInfo(pMT->GetAuxiliaryData())->NonGCTlsIndex.GetIndexOffset();
}
assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID);
@ -1329,144 +1382,17 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isG
return typeIndex;
}
#if defined(TARGET_WINDOWS)
/*********************************************************************/
static uint32_t ThreadLocalOffset(void* p)
{
PTEB Teb = NtCurrentTeb();
uint8_t** pTls = (uint8_t**)Teb->ThreadLocalStoragePointer;
uint8_t* pOurTls = pTls[_tls_index];
return (uint32_t)((uint8_t*)p - pOurTls);
}
#elif defined(TARGET_OSX)
extern "C" void* GetThreadVarsAddress();
static void* GetThreadVarsSectionAddressFromDesc(uint8_t* p)
{
_ASSERT(p[0] == 0x48 && p[1] == 0x8d && p[2] == 0x3d);
// At this point, `p` contains the instruction pointer and is pointing to the above opcodes.
// These opcodes are patched by the dynamic linker.
// Move beyond the opcodes that we have already checked above.
p += 3;
// The descriptor address is located at *p at this point.
// (p + 4) below skips the descriptor address bytes embedded in the instruction and
// add it to the `instruction pointer` to find out the address.
return *(uint32_t*)p + (p + 4);
}
static void* GetThreadVarsSectionAddress()
{
#ifdef TARGET_AMD64
// On x64, the address is related to rip, so, disassemble the function,
// read the offset, and then relative to the IP, find the final address of
// __thread_vars section.
uint8_t* p = reinterpret_cast<uint8_t*>(&GetThreadVarsAddress);
return GetThreadVarsSectionAddressFromDesc(p);
#else
return GetThreadVarsAddress();
#endif // TARGET_AMD64
}
#else
// Linux
#ifdef TARGET_AMD64
extern "C" void* GetTlsIndexObjectDescOffset();
static void* GetThreadStaticDescriptor(uint8_t* p)
{
if (!(p[0] == 0x66 && p[1] == 0x48 && p[2] == 0x8d && p[3] == 0x3d))
{
// The optimization is disabled if coreclr is not compiled in .so format.
_ASSERTE(false && "Unexpected code sequence");
return nullptr;
}
// At this point, `p` contains the instruction pointer and is pointing to the above opcodes.
// These opcodes are patched by the dynamic linker.
// Move beyond the opcodes that we have already checked above.
p += 4;
// The descriptor address is located at *p at this point. Read that and add
// it to the instruction pointer to locate the address of `ti` that will be used
// to pass to __tls_get_addr during execution.
// (p + 4) below skips the descriptor address bytes embedded in the instruction and
// add it to the `instruction pointer` to find out the address.
return *(uint32_t*)p + (p + 4);
}
static void* GetTlsIndexObjectAddress()
{
uint8_t* p = reinterpret_cast<uint8_t*>(&GetTlsIndexObjectDescOffset);
return GetThreadStaticDescriptor(p);
}
#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
extern "C" size_t GetThreadStaticsVariableOffset();
#endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
#endif // TARGET_WINDOWS
void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
THROWS;
GC_TRIGGERS;
MODE_PREEMPTIVE;
} CONTRACTL_END;
JIT_TO_EE_TRANSITION_LEAF();
size_t threadStaticBaseOffset = 0;
#if defined(TARGET_WINDOWS)
pInfo->tlsIndex.addr = (void*)static_cast<uintptr_t>(_tls_index);
pInfo->tlsIndex.accessType = IAT_VALUE;
pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer);
threadStaticBaseOffset = ThreadLocalOffset(&t_ThreadStatics);
#elif defined(TARGET_OSX)
pInfo->threadVarsSection = GetThreadVarsSectionAddress();
#elif defined(TARGET_AMD64)
// For Linux/x64, get the address of tls_get_addr system method and the base address
// of struct that we will pass to it.
pInfo->tlsGetAddrFtnPtr = reinterpret_cast<void*>(&__tls_get_addr);
pInfo->tlsIndexObject = GetTlsIndexObjectAddress();
#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
// For Linux arm64/loongarch64/riscv64, just get the offset of thread static variable, and during execution,
// this offset, arm64 taken from trpid_elp0 system register gives back the thread variable address.
// this offset, loongarch64 taken from $tp register gives back the thread variable address.
threadStaticBaseOffset = GetThreadStaticsVariableOffset();
#else
_ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
#endif // TARGET_WINDOWS
if (isGCType)
{
pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCMaxThreadStaticBlocks));
pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCThreadStaticBlocks));
}
else
{
pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCMaxThreadStaticBlocks));
pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCThreadStaticBlocks));
}
pInfo->offsetOfGCDataPointer = static_cast<uint32_t>(PtrArray::GetDataOffset());
EE_TO_JIT_TRANSITION_LEAF();
JIT_TO_EE_TRANSITION();
GetThreadLocalStaticBlocksInfo(pInfo);
EE_TO_JIT_TRANSITION();
}
/*********************************************************************/
@ -1573,42 +1499,35 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
#if defined(TARGET_ARM)
// Optimization is disabled for linux/windows arm
#elif !defined(TARGET_WINDOWS) && defined(TARGET_X86)
// Optimization is disabled for linux/x86
#elif defined(TARGET_LINUX_MUSL) && defined(TARGET_ARM64)
// Optimization is disabled for linux musl arm64
#elif defined(TARGET_FREEBSD) && defined(TARGET_ARM64)
// Optimization is disabled for FreeBSD/arm64
#else
bool optimizeThreadStaticAccess = true;
#if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_AMD64)
// For linux/x64, check if compiled coreclr as .so file and not single file.
// For single file, the `tls_index` might not be accurate.
// Do not perform this optimization in such case.
optimizeThreadStaticAccess = GetTlsIndexObjectAddress() != nullptr;
#endif // !TARGET_OSX && TARGET_UNIX && TARGET_AMD64
if (optimizeThreadStaticAccess)
if (CanJITOptimizeTLSAccess())
{
// For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64:
// We convert the TLS access to the optimized helper where we will store
// the static blocks in TLS directly and access them via inline code.
if ((pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) ||
(pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE))
if ((pResult->helper == CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR) ||
(pResult->helper == CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE) ||
(pResult->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR) ||
(pResult->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE))
{
fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED;
pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
// Check for highly optimized DirectOnThreadLocalData case
pFieldMT->EnsureTlsIndexAllocated();
if (pFieldMT->GetThreadStaticsInfo()->NonGCTlsIndex.GetTLSIndexType() == TLSIndexType::DirectOnThreadLocalData)
{
pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2;
}
else if ((pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR) ||
(pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE))
}
else if ((pResult->helper == CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR) ||
(pResult->helper == CORINFO_HELP_GET_GCTHREADSTATIC_BASE) ||
(pResult->helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR) ||
(pResult->helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE))
{
fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED;
pResult->helper = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
pResult->helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
}
}
#endif // TARGET_ARM
}
else
{
@ -1616,8 +1535,8 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
// Allocate space for the local class if necessary, but don't trigger
// class construction.
DomainLocalModule* pLocalModule = pFieldMT->GetDomainLocalModule();
pLocalModule->PopulateClass(pFieldMT);
pFieldMT->EnsureStaticDataAllocated();
pFieldMT->AttemptToPreinit();
// We are not going through a helper. The constructor has to be triggered explicitly.
if (!pFieldMT->IsClassInited())
@ -1632,14 +1551,6 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
if (fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP)
{
Object* frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr);
if (frozenObj == nullptr)
{
// Boxed static is not yet set, allocate it
pFieldMT->AllocateRegularStaticBox(pField, (Object**)pResult->fieldLookup.addr);
frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr);
}
_ASSERT(frozenObj != nullptr);
// ContainsPointers here is unnecessary but it's cheaper than IsInFrozenSegment
@ -3725,37 +3636,6 @@ void CEEInfo::LongLifetimeFree(void* obj)
EE_TO_JIT_TRANSITION_LEAF();
}
/*********************************************************************/
size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
MODE_PREEMPTIVE;
} CONTRACTL_END;
size_t result = 0;
JIT_TO_EE_TRANSITION_LEAF();
TypeHandle VMClsHnd(clsHnd);
Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
if (ppIndirection != NULL)
*ppIndirection = NULL;
// The zapper needs the module handle. The jit should not use it at all.
if (pModuleHandle)
*pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
result = pModule->GetModuleID();
_ASSERTE(result);
EE_TO_JIT_TRANSITION_LEAF();
return result;
}
/*********************************************************************/
bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset)
@ -3767,54 +3647,63 @@ bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONS
} CONTRACTL_END;
_ASSERTE(addr);
bool result;
JIT_TO_EE_TRANSITION_LEAF();
TypeHandle clsTypeHandle(cls);
PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
// Impl is based on IsPrecomputedClassInitialized()
UINT32 clsIndex = 0;
if (pMT->IsDynamicStatics())
if (pMT->IsSharedByGenericInstantiations())
{
clsIndex = (UINT32)pMT->GetModuleDynamicEntryID();
// If the MT is shared by generic instantiations, then we don't have an exact flag to check
result = false;
}
else
{
clsIndex = (UINT32)pMT->GetClassIndex();
}
size_t moduleId = pMT->GetModuleForStatics()->GetModuleID();
addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex;
addr->addr = (UINT8*)pMT->getIsClassInitedFlagAddress();
addr->accessType = IAT_VALUE;
*offset = 0;
result = true;
}
EE_TO_JIT_TRANSITION_LEAF();
return true;
return result;
}
/*********************************************************************/
bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
THROWS;
GC_TRIGGERS;
MODE_PREEMPTIVE;
} CONTRACTL_END;
JIT_TO_EE_TRANSITION_LEAF();
bool result = false;
JIT_TO_EE_TRANSITION();
TypeHandle clsTypeHandle(cls);
PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
if (pMT->IsSharedByGenericInstantiations())
{
// If the MT is shared by generic instantiations, then we don't have an exact flag to check
result = false;
}
else
{
GCX_COOP();
pMT->EnsureStaticDataAllocated();
addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer();
addr->accessType = IAT_VALUE;
result = true;
}
EE_TO_JIT_TRANSITION_LEAF();
EE_TO_JIT_TRANSITION();
return true;
return result;
}
/*********************************************************************/
@ -3981,6 +3870,7 @@ CorInfoInitClassResult CEEInfo::initClass(
MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
pTypeToInitMT->AttemptToPreinit();
if (pTypeToInitMT->IsClassInited())
{
// If the type is initialized there really is nothing to do.
@ -4094,8 +3984,7 @@ CorInfoInitClassResult CEEInfo::initClass(
// Allocate space for the local class if necessary, but don't trigger
// class construction.
DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
pModule->PopulateClass(pTypeToInitMT);
pTypeToInitMT->EnsureStaticDataAllocated();
if (pTypeToInitMT->IsClassInited())
{
@ -5767,39 +5656,6 @@ void CEEInfo::getCallInfo(
}
/***********************************************************************/
unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
void **ppIndirection)
{
CONTRACTL {
THROWS;
GC_TRIGGERS;
MODE_PREEMPTIVE;
} CONTRACTL_END;
unsigned result = 0;
if (ppIndirection != NULL)
*ppIndirection = NULL;
JIT_TO_EE_TRANSITION();
TypeHandle VMClsHnd(clsHnd);
if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
{
result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
}
else
{
result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
}
EE_TO_JIT_TRANSITION();
return result;
}
//---------------------------------------------------------------------------------------
//
// Used by the JIT to determine whether the profiler is tracking object
@ -6153,22 +6009,20 @@ CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
MODE_PREEMPTIVE;
} CONTRACTL_END;
CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
TypeHandle VMClsHnd(clsHnd);
JIT_TO_EE_TRANSITION_LEAF();
TypeHandle cls(clsHnd);
MethodTable* pMT = cls.AsMethodTable();
if (pMT->IsDynamicStatics())
CorInfoHelpFunc result;
if (VMClsHnd.GetMethodTable()->IsDynamicStatics())
{
_ASSERTE(!cls.ContainsGenericVariables());
_ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
if (VMClsHnd.GetMethodTable()->GetClass()->GetNonGCRegularStaticFieldBytes() > 0)
result = CORINFO_HELP_GET_NONGCSTATIC_BASE;
else if (VMClsHnd.GetMethodTable()->GetClass()->GetNumHandleRegularStatics() > 0)
result = CORINFO_HELP_GET_GCSTATIC_BASE;
else
result = CORINFO_HELP_INITCLASS;
}
EE_TO_JIT_TRANSITION_LEAF();
else
result = CORINFO_HELP_INITCLASS;
return result;
}
@ -11772,8 +11626,7 @@ bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buff
// Allocate space for the local class if necessary, but don't trigger
// class construction.
DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
pLocalModule->PopulateClass(pEnclosingMT);
pEnclosingMT->EnsureStaticDataAllocated();
if (!field->IsThreadStatic() && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
{
@ -11955,8 +11808,7 @@ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE
{
// Allocate space for the local class if necessary, but don't trigger
// class construction.
DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule();
pLocalModule->PopulateClass(pEnclosingMT);
pEnclosingMT->EnsureStaticDataAllocated();
GCX_COOP();
@ -13700,33 +13552,6 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
result = pMgr->GetCallStub(ownerType, slot);
}
break;
case ENCODE_CLASS_ID_FOR_STATICS:
{
TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
MethodTable * pMT = th.AsMethodTable();
if (pMT->IsDynamicStatics())
{
result = pMT->GetModuleDynamicEntryID();
}
else
{
result = pMT->GetClassIndex();
}
}
break;
case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
{
TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
MethodTable * pMT = th.AsMethodTable();
result = pMT->GetModuleForStatics()->GetModuleID();
}
break;
#ifdef FEATURE_READYTORUN
case ENCODE_READYTORUN_HELPER:
{

View file

@ -101,26 +101,6 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
#endif // TARGET_X86
// thread local struct to store the "thread static blocks"
struct ThreadStaticBlockInfo
{
uint32_t NonGCMaxThreadStaticBlocks;
void** NonGCThreadStaticBlocks;
uint32_t GCMaxThreadStaticBlocks;
void** GCThreadStaticBlocks;
};
#ifdef _MSC_VER
EXTERN_C __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics;
EXTERN_C __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize;
EXTERN_C __declspec(thread) uint32_t t_GCThreadStaticBlocksSize;
#else
EXTERN_C __thread ThreadStaticBlockInfo t_ThreadStatics;
EXTERN_C __thread uint32_t t_NonGCThreadStaticBlocksSize;
EXTERN_C __thread uint32_t t_GCThreadStaticBlocksSize;
#endif // _MSC_VER
//
// JIT HELPER ALIASING FOR PORTABILITY.
//
@ -175,30 +155,53 @@ EXTERN_C FCDECL_MONHELPER(JIT_MonEnterStatic_Portable, AwareLock *lock);
EXTERN_C FCDECL_MONHELPER(JIT_MonExitStatic, AwareLock *lock);
EXTERN_C FCDECL_MONHELPER(JIT_MonExitStatic_Portable, AwareLock *lock);
#ifndef JIT_GetSharedGCStaticBase
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_Portable
#ifndef JIT_GetGCStaticBase
#define JIT_GetGCStaticBase JIT_GetGCStaticBase_Portable
#endif
EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase, MethodTable *pMT);
EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase_Portable, MethodTable *pMT);
#ifndef JIT_GetSharedNonGCStaticBase
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_Portable
#ifndef JIT_GetNonGCStaticBase
#define JIT_GetNonGCStaticBase JIT_GetNonGCStaticBase_Portable
#endif
EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwModuleClassID);
EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase, MethodTable *pMT);
EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase_Portable, MethodTable *pMT);
#ifndef JIT_GetSharedGCStaticBaseNoCtor
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_Portable
#ifndef JIT_GetGCStaticBaseNoCtor
#define JIT_GetGCStaticBaseNoCtor JIT_GetGCStaticBaseNoCtor_Portable
#endif
EXTERN_C FCDECL1(void*, JIT_GetSharedGCStaticBaseNoCtor, DomainLocalModule *pLocalModule);
EXTERN_C FCDECL1(void*, JIT_GetSharedGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule);
EXTERN_C FCDECL1(void*, JIT_GetGCStaticBaseNoCtor, MethodTable *pMT);
EXTERN_C FCDECL1(void*, JIT_GetGCStaticBaseNoCtor_Portable, MethodTable *pMT);
#ifndef JIT_GetSharedNonGCStaticBaseNoCtor
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_Portable
#ifndef JIT_GetNonGCStaticBaseNoCtor
#define JIT_GetNonGCStaticBaseNoCtor JIT_GetNonGCStaticBaseNoCtor_Portable
#endif
EXTERN_C FCDECL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor, DomainLocalModule *pLocalModule);
EXTERN_C FCDECL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule);
EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBaseNoCtor, MethodTable *pMT);
EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBaseNoCtor_Portable, MethodTable *pMT);
#ifndef JIT_GetDynamicGCStaticBase
#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_Portable
#endif
EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBase, DynamicStaticsInfo* pStaticsInfo);
EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo);
#ifndef JIT_GetDynamicNonGCStaticBase
#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_Portable
#endif
EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBase, DynamicStaticsInfo* pStaticsInfo);
EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo);
#ifndef JIT_GetDynamicGCStaticBaseNoCtor
#define JIT_GetDynamicGCStaticBaseNoCtor JIT_GetDynamicGCStaticBaseNoCtor_Portable
#endif
EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBaseNoCtor, DynamicStaticsInfo* pStaticsInfo);
EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pStaticsInfo);
#ifndef JIT_GetDynamicNonGCStaticBaseNoCtor
#define JIT_GetDynamicNonGCStaticBaseNoCtor JIT_GetDynamicNonGCStaticBaseNoCtor_Portable
#endif
EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor, DynamicStaticsInfo* pStaticsInfo);
EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pStaticsInfo);
extern FCDECL1(Object*, JIT_NewS_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_);
extern FCDECL1(Object*, JIT_New, CORINFO_CLASS_HANDLE typeHnd_);
@ -219,8 +222,8 @@ EXTERN_C FCDECL_MONHELPER(JITutil_MonSignal, AwareLock* lock);
EXTERN_C FCDECL_MONHELPER(JITutil_MonContention, AwareLock* awarelock);
EXTERN_C FCDECL2(void, JITutil_MonReliableContention, AwareLock* awarelock, BYTE* pbLockTaken);
EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID);
EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID);
EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase_Helper, MethodTable *pMT);
EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase_Helper, MethodTable *pMT);
EXTERN_C void DoJITFailFast ();
EXTERN_C FCDECL0(void, JIT_FailFast);
@ -1098,13 +1101,12 @@ struct VirtualFunctionPointerArgs
FCDECL2(CORINFO_MethodPtr, JIT_VirtualFunctionPointer_Dynamic, Object * objectUNSAFE, VirtualFunctionPointerArgs * pArgs);
typedef HCCALL2_PTR(TADDR, FnStaticBaseHelper, TADDR arg0, TADDR arg1);
typedef HCCALL1_PTR(TADDR, FnStaticBaseHelper, TADDR arg0);
struct StaticFieldAddressArgs
{
FnStaticBaseHelper staticBaseHelper;
TADDR arg0;
TADDR arg1;
SIZE_T offset;
};

View file

@ -1078,6 +1078,7 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
DWORD dwLowFrequencyHeapReserveSize;
DWORD dwHighFrequencyHeapReserveSize;
DWORD dwStaticsHeapReserveSize;
DWORD dwStubHeapReserveSize;
DWORD dwExecutableHeapReserveSize;
DWORD dwCodeHeapReserveSize;
@ -1092,12 +1093,14 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
dwStubHeapReserveSize = COLLECTIBLE_STUB_HEAP_SIZE;
dwCodeHeapReserveSize = COLLECTIBLE_CODEHEAP_SIZE;
dwVSDHeapReserveSize = COLLECTIBLE_VIRTUALSTUBDISPATCH_HEAP_SPACE;
dwStaticsHeapReserveSize = 0;
}
else
{
dwLowFrequencyHeapReserveSize = LOW_FREQUENCY_HEAP_RESERVE_SIZE;
dwHighFrequencyHeapReserveSize = HIGH_FREQUENCY_HEAP_RESERVE_SIZE;
dwStubHeapReserveSize = STUB_HEAP_RESERVE_SIZE;
dwStaticsHeapReserveSize = STATIC_FIELD_HEAP_RESERVE_SIZE;
// Non-collectible assemblies do not reserve space for these heaps.
dwCodeHeapReserveSize = 0;
@ -1116,6 +1119,7 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
DWORD dwTotalReserveMemSize = dwLowFrequencyHeapReserveSize
+ dwHighFrequencyHeapReserveSize
+ dwStaticsHeapReserveSize
+ dwStubHeapReserveSize
+ dwCodeHeapReserveSize
+ dwVSDHeapReserveSize
@ -1181,6 +1185,20 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
m_pHighFrequencyHeap->m_fPermitStubsWithUnwindInfo = TRUE;
#endif
if (dwStaticsHeapReserveSize != 0)
{
m_pStaticsHeap = new (&m_StaticsHeapInstance) LoaderHeap(STATIC_FIELD_HEAP_RESERVE_SIZE,
STATIC_FIELD_HEAP_COMMIT_SIZE,
initReservedMem,
dwStaticsHeapReserveSize);
initReservedMem += dwStaticsHeapReserveSize;
}
else
{
_ASSERTE(m_pHighFrequencyHeap != NULL);
m_pStaticsHeap = m_pHighFrequencyHeap;
}
m_pStubHeap = new (&m_StubHeapInstance) LoaderHeap(STUB_HEAP_RESERVE_SIZE,
STUB_HEAP_COMMIT_SIZE,
initReservedMem,
@ -1368,6 +1386,12 @@ void LoaderAllocator::Terminate()
m_pLowFrequencyHeap = NULL;
}
if ((m_pStaticsHeap != NULL) && (m_pStaticsHeap != m_pHighFrequencyHeap))
{
m_pStaticsHeap->~LoaderHeap();
m_pStaticsHeap = NULL;
}
if (m_pHighFrequencyHeap != NULL)
{
#ifdef STUBLINKER_GENERATES_UNWIND_INFO
@ -1462,6 +1486,10 @@ void LoaderAllocator::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
m_pHighFrequencyHeap->EnumMemoryRegions(flags);
}
if (m_pStaticsHeap.IsValid())
{
m_pStaticsHeap->EnumMemoryRegions(flags);
}
if (m_pStubHeap.IsValid())
{
m_pStubHeap->EnumMemoryRegions(flags);
@ -1501,6 +1529,8 @@ SIZE_T LoaderAllocator::EstimateSize()
SIZE_T retval=0;
if(m_pHighFrequencyHeap)
retval+=m_pHighFrequencyHeap->GetSize();
if(m_pStaticsHeap)
retval+=m_pStaticsHeap->GetSize();
if(m_pLowFrequencyHeap)
retval+=m_pLowFrequencyHeap->GetSize();
if(m_pStubHeap)
@ -1906,6 +1936,12 @@ void AssemblyLoaderAllocator::CleanupHandles()
_ASSERTE(GetDomain()->IsAppDomain());
if (m_hLoaderAllocatorObjectHandle != NULL)
{
GCX_COOP();
FreeTLSIndicesForLoaderAllocator(this);
}
// This method doesn't take a lock around RemoveHead because it's supposed to
// be called only from Terminate
while (!m_handleCleanupList.IsEmpty())
@ -2217,6 +2253,140 @@ PTR_OnStackReplacementManager LoaderAllocator::GetOnStackReplacementManager()
#endif //
#endif // FEATURE_ON_STACK_REPLACEMENT
#ifndef DACCESS_COMPILE
void LoaderAllocator::AllocateBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cbMem)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
if (cbMem == 0)
return;
if (IsCollectible())
{
GCX_COOP();
uint32_t doubleSlots = AlignUp(cbMem, sizeof(double)) / sizeof(double);
BASEARRAYREF ptrArray = (BASEARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_R8, doubleSlots);
GCPROTECT_BEGIN(ptrArray);
// Keep this allocation alive till the LoaderAllocator is collected
AllocateHandle(ptrArray);
CrstHolder cs(&m_crstLoaderAllocator);
{
if (pStaticsInfo->GetNonGCStaticsPointer() == NULL)
{
GCX_FORBID();
// Allocating a weak interior handle is a tricky thing.
// 1. If there are multiple weak interior handles that point at a given interior pointer location, there will be heap corruption
// 2. If the interior handle is created, but not registered for cleanup, it is a memory leak
// 3. Since the weak interior handle doesn't actually keep the object alive, it needs to be kept alive by some other means
//
// We work around these details by the following means
// 1. We use a LOADERHANDLE to keep the object alive until the LoaderAllocator is freed.
// 2. We hold the crstLoaderAllocatorLock, and double check to wnsure that the data is ready to be filled in
// 3. We create the weak interior handle, and register it for cleanup (which can fail with an OOM) before updating the statics data to have the pointer
// 4. Registration for cleanup cannot trigger a GC
// 5. We then unconditionally set the statics pointer.
WeakInteriorHandleHolder weakHandleHolder = GetAppDomain()->CreateWeakInteriorHandle(ptrArray, &pStaticsInfo->m_pNonGCStatics);
RegisterHandleForCleanupLocked(weakHandleHolder.GetValue());
weakHandleHolder.SuppressRelease();
bool didUpdateStaticsPointer = pStaticsInfo->InterlockedUpdateStaticsPointer(/* isGCPointer */false, (TADDR)ptrArray->GetDataPtr());
_ASSERTE(didUpdateStaticsPointer);
}
}
GCPROTECT_END();
}
else
{
uint32_t initialcbMem = cbMem;
if (initialcbMem >= 8)
{
cbMem = ALIGN_UP(cbMem, sizeof(double));
#ifndef TARGET_64BIT
cbMem += 4; // We need to align the memory to 8 bytes so that static doubles, and static int64's work
// and this allocator doesn't guarantee 8 byte alignment, so allocate 4 bytes extra, and alignup.
// Technically this isn't necessary on X86, but it's simpler to do it unconditionally.
#endif
}
else
{
// Always allocate in multiples of pointer size
cbMem = ALIGN_UP(cbMem, sizeof(TADDR));
}
uint8_t* pbMem = (uint8_t*)(void*)GetStaticsHeap()->AllocMem(S_SIZE_T(cbMem));
#ifndef TARGET_64BIT // Second part of alignment work
if (initialcbMem >= 8)
{
pbMem = (uint8_t*)ALIGN_UP(pbMem, 8);
}
#endif
pStaticsInfo->InterlockedUpdateStaticsPointer(/* isGCPointer */false, (TADDR)pbMem);
}
}
void LoaderAllocator::AllocateGCHandlesBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cSlots, MethodTable* pMTToFillWithStaticBoxes)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
if (cSlots == 0)
return;
if (IsCollectible())
{
GCX_COOP();
BASEARRAYREF ptrArray = (BASEARRAYREF)AllocateObjectArray(cSlots, g_pObjectClass, /* bAllocateInPinnedHeap = */FALSE);
GCPROTECT_BEGIN(ptrArray);
if (pMTToFillWithStaticBoxes != NULL)
{
OBJECTREF* pArray = (OBJECTREF*)ptrArray->GetDataPtr();
GCPROTECT_BEGININTERIOR(pArray);
pMTToFillWithStaticBoxes->AllocateRegularStaticBoxes(&pArray);
GCPROTECT_END();
}
// Keep this allocation alive till the LoaderAllocator is collected
AllocateHandle(ptrArray);
CrstHolder cs(&m_crstLoaderAllocator);
{
if (pStaticsInfo->GetGCStaticsPointer() == NULL)
{
GCX_FORBID();
// Allocating a weak interior handle is a tricky thing.
// 1. If there are multiple weak interior handles that point at a given interior pointer location, there will be heap corruption
// 2. If the interior handle is created, but not registered for cleanup, it is a memory leak
// 3. Since the weak interior handle doesn't actually keep the object alive, it needs to be kept alive by some other means
//
// We work around these details by the following means
// 1. We use a LOADERHANDLE to keep the object alive until the LoaderAllocator is freed.
// 2. We hold the crstLoaderAllocatorLock, and double check to wnsure that the data is ready to be filled in
// 3. We create the weak interior handle, and register it for cleanup (which can fail with an OOM) before updating the statics data to have the pointer
// 4. Registration for cleanup cannot trigger a GC
// 5. We then unconditionally set the statics pointer.
WeakInteriorHandleHolder weakHandleHolder = GetAppDomain()->CreateWeakInteriorHandle(ptrArray, &pStaticsInfo->m_pGCStatics);
RegisterHandleForCleanupLocked(weakHandleHolder.GetValue());
weakHandleHolder.SuppressRelease();
bool didUpdateStaticsPointer = pStaticsInfo->InterlockedUpdateStaticsPointer(/* isGCPointer */true, (TADDR)ptrArray->GetDataPtr());
_ASSERTE(didUpdateStaticsPointer);
}
}
GCPROTECT_END();
}
else
{
GetDomain()->AllocateObjRefPtrsInLargeTable(cSlots, pStaticsInfo, pMTToFillWithStaticBoxes);
}
}
#endif // !DACCESS_COMPILE
#ifndef DACCESS_COMPILE
bool LoaderAllocator::InsertObjectIntoFieldWithLifetimeOfCollectibleLoaderAllocator(OBJECTREF value, Object** pField)

View file

@ -306,8 +306,10 @@ protected:
BYTE m_PrecodeHeapInstance[sizeof(CodeFragmentHeap)];
BYTE m_FixupPrecodeHeapInstance[sizeof(LoaderHeap)];
BYTE m_NewStubPrecodeHeapInstance[sizeof(LoaderHeap)];
BYTE m_StaticsHeapInstance[sizeof(LoaderHeap)];
PTR_LoaderHeap m_pLowFrequencyHeap;
PTR_LoaderHeap m_pHighFrequencyHeap;
PTR_LoaderHeap m_pStaticsHeap;
PTR_LoaderHeap m_pStubHeap; // stubs for PInvoke, remoting, etc
PTR_CodeFragmentHeap m_pPrecodeHeap;
PTR_LoaderHeap m_pExecutableHeap;
@ -349,6 +351,8 @@ protected:
Volatile<PgoManager *> m_pgoManager;
#endif // FEATURE_PGO
SArray<TLSIndex> m_tlsIndices;
public:
BYTE *GetVSDHeapInitialBlock(DWORD *pSize);
BYTE *GetCodeHeapInitialBlock(const BYTE * loAddr, const BYTE * hiAddr, DWORD minimumSize, DWORD *pSize);
@ -389,6 +393,12 @@ protected:
PTR_VirtualCallStubManager m_pVirtualCallStubManager;
public:
SArray<TLSIndex>& GetTLSIndexList()
{
return m_tlsIndices;
}
private:
LoaderAllocatorSet m_LoaderAllocatorReferences;
Volatile<UINT32> m_cReferences;
@ -582,6 +592,12 @@ public:
return m_pHighFrequencyHeap;
}
PTR_LoaderHeap GetStaticsHeap()
{
LIMITED_METHOD_CONTRACT;
return m_pStaticsHeap;
}
PTR_LoaderHeap GetStubHeap()
{
LIMITED_METHOD_CONTRACT;
@ -631,6 +647,7 @@ public:
}
LOADERALLOCATORREF GetExposedObject();
bool IsExposedObjectLive();
#ifndef DACCESS_COMPILE
bool InsertObjectIntoFieldWithLifetimeOfCollectibleLoaderAllocator(OBJECTREF value, Object** pField);
@ -732,6 +749,8 @@ public:
LIMITED_METHOD_CONTRACT;
return m_nGCCount;
}
void AllocateBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cbMem);
void AllocateGCHandlesBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cSlots, MethodTable* pMTWithStaticBoxes);
static BOOL Destroy(QCall::LoaderAllocatorHandle pLoaderAllocator);

View file

@ -16,6 +16,14 @@ inline LOADERALLOCATORREF LoaderAllocator::GetExposedObject()
}
#endif
inline bool LoaderAllocator::IsExposedObjectLive()
{
LIMITED_METHOD_CONTRACT;
if (m_hLoaderAllocatorObjectHandle == 0)
return false;
return !ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle);
}
inline void GlobalLoaderAllocator::Init(BaseDomain *pDomain)
{
LoaderAllocator::Init(pDomain, m_ExecutableHeapInstance);

View file

@ -206,11 +206,6 @@ ASMCONSTANTS_C_ASSERT((1<<FixupPrecode_ALIGNMENT_SHIFT_1) == sizeof(FixupPrecode
ASMCONSTANTS_C_ASSERT(ResolveCacheElem__target == offsetof(ResolveCacheElem, target));
ASMCONSTANTS_C_ASSERT(ResolveCacheElem__pNext == offsetof(ResolveCacheElem, pNext));
#define DomainLocalModule__m_pDataBlob 0x30
#define DomainLocalModule__m_pGCStatics 0x20
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob));
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics));
// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
#define Frame__m_Next 0x08
ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next))

View file

@ -611,26 +611,6 @@ NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
EPILOG_BRANCH_REG $t4
NESTED_END TheUMEntryPrestub, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
addi.d $a2, $a0, DomainLocalModule__m_pDataBlob
add.d $a2, $a2, $a1
ld.b $a2, $a2, 0
andi $t8, $a2, 1
beq $t8, $zero, 1f //LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper)
ld.d $a0, $a0, DomainLocalModule__m_pGCStatics
jirl $r0, $ra, 0
1:
//LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper):
// Tail call JIT_GetSharedGCStaticBase_Helper
bl JIT_GetSharedGCStaticBase_Helper
LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// Make sure the `FaultingExceptionFrame_StackAlloc` is 16-byte aligned.
#define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame + 0x8)
#define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie
@ -793,22 +773,6 @@ NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
EPILOG_BRANCH_REG $t4
NESTED_END ResolveWorkerAsmStub, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
jirl $r0, $ra, 0
LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
ld.d $a0, $a0, DomainLocalModule__m_pGCStatics
jirl $r0, $ra, 0
LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
#ifdef FEATURE_HIJACK
// ------------------------------------------------------------------
// Hijack function for functions which return a scalar type or a struct (value type)

View file

@ -98,11 +98,6 @@ inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatH
//
// Create alias for optimized implementations of helpers provided on this platform
//
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
//**********************************************************************
// Frames

View file

@ -2995,7 +2995,7 @@ public:
LIMITED_METHOD_CONTRACT;
MethodTable * pMT = GetMethodTable();
// Try to avoid touching the EEClass if possible
if (pMT->IsClassPreInited())
if (!pMT->HasClassConstructor())
return FALSE;
return !pMT->GetClass()->IsBeforeFieldInit();
}

View file

@ -367,52 +367,6 @@ BOOL MethodTable::ValidateWithPossibleAV()
}
//==========================================================================================
BOOL MethodTable::IsClassInited()
{
WRAPPER_NO_CONTRACT;
if (IsClassPreInited())
return TRUE;
if (IsSharedByGenericInstantiations())
return FALSE;
PTR_DomainLocalModule pLocalModule = GetDomainLocalModule();
_ASSERTE(pLocalModule != NULL);
return pLocalModule->IsClassInitialized(this);
}
//==========================================================================================
BOOL MethodTable::IsInitError()
{
WRAPPER_NO_CONTRACT;
PTR_DomainLocalModule pLocalModule = GetDomainLocalModule();
_ASSERTE(pLocalModule != NULL);
return pLocalModule->IsClassInitError(this);
}
#ifndef DACCESS_COMPILE
//==========================================================================================
// mark the class as having its .cctor run
void MethodTable::SetClassInited()
{
WRAPPER_NO_CONTRACT;
_ASSERTE(!IsClassPreInited());
GetDomainLocalModule()->SetClassInitialized(this);
}
//==========================================================================================
void MethodTable::SetClassInitError()
{
WRAPPER_NO_CONTRACT;
GetDomainLocalModule()->SetClassInitError(this);
}
//==========================================================================================
// mark as COM object type (System.__ComObject and types deriving from it)
void MethodTable::SetComObjectType()
@ -457,8 +411,6 @@ void MethodTable::SetIsTrackedReferenceWithFinalizer()
SetFlag(enum_flag_IsTrackedReferenceWithFinalizer);
}
#endif // !DACCESS_COMPILE
BOOL MethodTable::IsTrackedReferenceWithFinalizer()
{
LIMITED_METHOD_DAC_CONTRACT;
@ -682,16 +634,30 @@ MethodDesc *MethodTable::GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD,
}
#endif // FEATURE_COMINTEROP
void MethodTable::AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, bool hasGenericStatics, WORD nonVirtualSlots, S_SIZE_T extraAllocation)
void MethodTable::AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, MethodTableStaticsFlags staticsFlags, WORD nonVirtualSlots, S_SIZE_T extraAllocation)
{
S_SIZE_T cbAuxiliaryData = S_SIZE_T(sizeof(MethodTableAuxiliaryData));
size_t prependedAllocationSpace = 0;
size_t prependedAllocationSpace = nonVirtualSlots * sizeof(TADDR);
prependedAllocationSpace = nonVirtualSlots * sizeof(TADDR);
int16_t sizeofStaticsStructure = 0;
if (hasGenericStatics)
prependedAllocationSpace = prependedAllocationSpace + sizeof(GenericsStaticsInfo);
if (HasFlag(staticsFlags, MethodTableStaticsFlags::Thread))
{
_ASSERTE(HasFlag(staticsFlags, MethodTableStaticsFlags::Present));
sizeofStaticsStructure = sizeof(ThreadStaticsInfo);
}
else if (HasFlag(staticsFlags, MethodTableStaticsFlags::Generic))
{
_ASSERTE(HasFlag(staticsFlags, MethodTableStaticsFlags::Present));
sizeofStaticsStructure = sizeof(GenericsStaticsInfo);
}
else if (HasFlag(staticsFlags, MethodTableStaticsFlags::Present))
{
sizeofStaticsStructure = sizeof(DynamicStaticsInfo);
}
prependedAllocationSpace = prependedAllocationSpace + sizeofStaticsStructure;
cbAuxiliaryData = cbAuxiliaryData + S_SIZE_T(prependedAllocationSpace) + extraAllocation;
if (cbAuxiliaryData.IsOverflow())
@ -704,8 +670,32 @@ void MethodTable::AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLo
pMTAuxiliaryData = (MethodTableAuxiliaryData *)(pAuxiliaryDataRegion + prependedAllocationSpace);
pMTAuxiliaryData->SetLoaderModule(pLoaderModule);
pMTAuxiliaryData->SetOffsetToNonVirtualSlots(hasGenericStatics ? -(int16_t)sizeof(GenericsStaticsInfo) : 0);
// NOTE: There is a - sign here making it so that the offset points to BEFORE the MethodTableAuxiliaryData
pMTAuxiliaryData->SetOffsetToNonVirtualSlots(-sizeofStaticsStructure);
m_pAuxiliaryData = pMTAuxiliaryData;
if (HasFlag(staticsFlags, MethodTableStaticsFlags::Present))
{
MethodTableAuxiliaryData::GetDynamicStaticsInfo(pMTAuxiliaryData)->Init(this);
#ifdef _DEBUG
pMTAuxiliaryData->m_debugOnlyDynamicStatics = MethodTableAuxiliaryData::GetDynamicStaticsInfo(pMTAuxiliaryData);
#endif
}
#ifdef _DEBUG
if (HasFlag(staticsFlags, MethodTableStaticsFlags::Generic))
{
pMTAuxiliaryData->m_debugOnlyGenericStatics = MethodTableAuxiliaryData::GetGenericStaticsInfo(pMTAuxiliaryData);
}
#endif
if (HasFlag(staticsFlags, MethodTableStaticsFlags::Thread))
{
MethodTableAuxiliaryData::GetThreadStaticsInfo(pMTAuxiliaryData)->Init();
#ifdef _DEBUG
pMTAuxiliaryData->m_debugOnlyThreadStatics = MethodTableAuxiliaryData::GetThreadStaticsInfo(pMTAuxiliaryData);
#endif
}
}
@ -1048,22 +1038,7 @@ void MethodTable::SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs)
}
CONTRACTL_END;
// No need to generate IDs for open types. Indeed since we don't save them
// in the NGEN image it would be actively incorrect to do so. However
// we still leave the optional member in the MethodTable holding the value -1 for the ID.
GenericsStaticsInfo *pInfo = GetGenericsStaticsInfo();
if (!ContainsGenericVariables() && !IsSharedByGenericInstantiations())
{
Module * pModuleForStatics = GetLoaderModule();
pInfo->m_DynamicTypeID = pModuleForStatics->AllocateDynamicEntry(this);
}
else
{
pInfo->m_DynamicTypeID = (SIZE_T)-1;
}
pInfo->m_pFieldDescs = pStaticFieldDescs;
}
@ -1102,43 +1077,6 @@ void MethodTable::EnumMemoryRegionsForExtraInterfaceInfo()
}
#endif // DACCESS_COMPILE
//==========================================================================================
Module* MethodTable::GetModuleForStatics()
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
if (HasGenericsStaticsInfo())
{
DWORD dwDynamicClassDomainID;
return GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID);
}
else
{
return GetLoaderModule();
}
}
//==========================================================================================
DWORD MethodTable::GetModuleDynamicEntryID()
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
_ASSERTE(IsDynamicStatics() && "Only memory reflection emit types and generics can have a dynamic ID");
if (HasGenericsStaticsInfo())
{
DWORD dwDynamicClassDomainID;
GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID);
return dwDynamicClassDomainID;
}
else
{
return GetClass()->GetModuleDynamicID();
}
}
#ifndef DACCESS_COMPILE
#ifdef FEATURE_TYPEEQUIVALENCE
@ -2027,42 +1965,6 @@ DWORD MethodTable::GetIndexForFieldDesc(FieldDesc *pField)
}
}
//==========================================================================================
#ifdef _MSC_VER
#pragma optimize("t", on)
#endif // _MSC_VER
// compute whether the type can be considered to have had its
// static initialization run without doing anything at all, i.e. whether we know
// immediately that the type requires nothing to do for initialization
//
// If a type used as a representiative during JITting is PreInit then
// any types that it may represent within a code-sharing
// group are also PreInit. For example, if List<object> is PreInit then List<string>
// and List<MyType> are also PreInit. This is because the dynamicStatics, staticRefHandles
// and hasCCtor are all identical given a head type, and weakening the domainNeutrality
// to DomainSpecific only makes more types PreInit.
BOOL MethodTable::IsClassPreInited()
{
LIMITED_METHOD_CONTRACT;
if (ContainsGenericVariables())
return TRUE;
if (HasClassConstructor())
return FALSE;
if (HasBoxedRegularStatics())
return FALSE;
if (IsDynamicStatics())
return FALSE;
return TRUE;
}
#ifdef _MSC_VER
#pragma optimize("", on)
#endif // _MSC_VER
//========================================================================================
namespace
@ -3397,26 +3299,20 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL
#if !defined(DACCESS_COMPILE)
//==========================================================================================
void MethodTable::AllocateRegularStaticBoxes()
void MethodTable::AllocateRegularStaticBoxes(OBJECTREF** ppStaticBase)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
PRECONDITION(!ContainsGenericVariables());
PRECONDITION(HasBoxedRegularStatics());
MODE_ANY;
MODE_COOPERATIVE;
}
CONTRACTL_END;
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Instantiating static handles for %s\n", GetDebugClassName()));
GCX_COOP();
PTR_BYTE pStaticBase = GetGCStaticsBasePointer();
GCPROTECT_BEGININTERIOR(pStaticBase);
if (HasBoxedRegularStatics())
{
FieldDesc *pField = HasGenericsStaticsInfo() ?
GetGenericsStaticFieldDescs() : (GetApproxFieldDescListRaw() + GetNumIntroducedInstanceFields());
@ -3428,13 +3324,12 @@ void MethodTable::AllocateRegularStaticBoxes()
if (!pField->IsSpecialStatic() && pField->IsByValue())
{
AllocateRegularStaticBox(pField, (Object**)(pStaticBase + pField->GetOffset()));
AllocateRegularStaticBox(pField, (Object**)(((PTR_BYTE)*ppStaticBase) + pField->GetOffset()));
}
pField++;
}
}
GCPROTECT_END();
}
void MethodTable::AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStaticHandle)
@ -3451,24 +3346,14 @@ void MethodTable::AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStat
// Static fields are not pinned in collectible types so we need to protect the address
GCPROTECT_BEGININTERIOR(boxedStaticHandle);
if (VolatileLoad(boxedStaticHandle) == nullptr)
{
// Grab field's type handle before we enter lock
MethodTable* pFieldMT = pField->GetFieldTypeHandleThrowing().GetMethodTable();
_ASSERTE(*boxedStaticHandle == nullptr);
MethodTable* pFieldMT = pField->GetFieldTypeHandleThrowing(CLASS_DEPENDENCIES_LOADED).GetMethodTable();
bool hasFixedAddr = HasFixedAddressVTStatics();
// Taking a lock since we might come here from multiple threads/places
CrstHolder crst(GetAppDomain()->GetStaticBoxInitLock());
// double-checked locking
if (VolatileLoad(boxedStaticHandle) == nullptr)
{
LOG((LF_CLASSLOADER, LL_INFO10000, "\tInstantiating static of type %s\n", pFieldMT->GetDebugClassName()));
const bool canBeFrozen = !pFieldMT->ContainsPointers() && !Collectible();
OBJECTREF obj = AllocateStaticBox(pFieldMT, hasFixedAddr, canBeFrozen);
SetObjectReference((OBJECTREF*)(boxedStaticHandle), obj);
}
}
GCPROTECT_END();
}
@ -3728,11 +3613,7 @@ void MethodTable::DoRunClassInitThrowing()
{
if (pEntry->m_hrResultCode == S_FALSE)
{
if (HasBoxedRegularStatics())
{
// First, instantiate any objects needed for value type statics
AllocateRegularStaticBoxes();
}
EnsureStaticDataAllocated();
// Nobody has run the .cctor yet
if (HasClassConstructor())
@ -3802,9 +3683,7 @@ void MethodTable::DoRunClassInitThrowing()
pEntry->m_hrResultCode = S_OK;
// Set the initialization flags in the DLS and on domain-specific types.
// Note we also set the flag for dynamic statics, which use the DynamicStatics part
// of the DLS irrespective of whether the type is domain neutral or not.
// Set the initialization flag
SetClassInited();
}
@ -3867,26 +3746,114 @@ void MethodTable::CheckRunClassInitThrowing()
// To find GC hole easier...
TRIGGERSGC();
if (IsClassPreInited())
return;
// Don't initialize shared generic instantiations (e.g. MyClass<__Canon>)
if (IsSharedByGenericInstantiations())
return;
DomainLocalModule *pLocalModule = GetDomainLocalModule();
_ASSERTE(pLocalModule);
DWORD iClassIndex = GetClassIndex();
// Check to see if we have already run the .cctor for this class.
if (!pLocalModule->IsClassAllocated(this, iClassIndex))
pLocalModule->PopulateClass(this);
if (!pLocalModule->IsClassInitialized(this, iClassIndex))
EnsureStaticDataAllocated();
DoRunClassInitThrowing();
}
void MethodTable::EnsureStaticDataAllocated()
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
PTR_MethodTableAuxiliaryData pAuxiliaryData = GetAuxiliaryDataForWrite();
if (!pAuxiliaryData->IsStaticDataAllocated() && IsDynamicStatics())
{
DynamicStaticsInfo *pDynamicStaticsInfo = GetDynamicStaticsInfo();
// Allocate space for normal statics if we might have them
if (pDynamicStaticsInfo->GetNonGCStaticsPointer() == NULL)
GetLoaderAllocator()->AllocateBytesForStaticVariables(pDynamicStaticsInfo, GetClass()->GetNonGCRegularStaticFieldBytes());
if (pDynamicStaticsInfo->GetGCStaticsPointer() == NULL)
GetLoaderAllocator()->AllocateGCHandlesBytesForStaticVariables(pDynamicStaticsInfo, GetClass()->GetNumHandleRegularStatics(), this->HasBoxedRegularStatics() ? this : NULL);
}
pAuxiliaryData->SetIsStaticDataAllocated();
}
void MethodTable::AttemptToPreinit()
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
if (IsClassInited())
return;
if (HasClassConstructor())
{
// If there is a class constructor, then the class cannot be preinitted.
return;
}
if (GetClass()->GetNonGCRegularStaticFieldBytes() == 0 && GetClass()->GetNumHandleRegularStatics() == 0)
{
// If there are static fields that are not thread statics, then the class is preinitted.
SetClassInited();
return;
}
// At this point, we are looking at a class that has no class constructor, but does have static fields
if (IsSharedByGenericInstantiations())
{
// If we don't know the exact type, we can't pre-allocate the fields
return;
}
// All this class needs to be initialized is to allocate the memory for the static fields. Do so, and mark the type as initialized
EnsureStaticDataAllocated();
SetClassInited();
return;
}
void MethodTable::EnsureTlsIndexAllocated()
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
PTR_MethodTableAuxiliaryData pAuxiliaryData = GetAuxiliaryDataForWrite();
if (!pAuxiliaryData->IsTlsIndexAllocated() && GetNumThreadStaticFields() > 0)
{
ThreadStaticsInfo *pThreadStaticsInfo = MethodTableAuxiliaryData::GetThreadStaticsInfo(GetAuxiliaryDataForWrite());
// Allocate space for normal statics if we might have them
if (!pThreadStaticsInfo->NonGCTlsIndex.IsAllocated())
{
DWORD bytesNeeded = GetClass()->GetNonGCThreadStaticFieldBytes();
if (bytesNeeded > 0)
{
GetTLSIndexForThreadStatic(this, false, &pThreadStaticsInfo->NonGCTlsIndex, bytesNeeded);
}
}
if (!pThreadStaticsInfo->GCTlsIndex.IsAllocated())
{
DWORD bytesNeeded = GetClass()->GetNumHandleThreadStatics() * sizeof(OBJECTREF);
if (bytesNeeded > 0)
{
GetTLSIndexForThreadStatic(this, true, &pThreadStaticsInfo->GCTlsIndex, bytesNeeded);
}
}
}
pAuxiliaryData->SetIsTlsIndexAllocated();
}
//==========================================================================================
void MethodTable::CheckRunClassInitAsIfConstructingThrowing()
{
@ -4439,6 +4406,17 @@ void MethodTable::DoFullyLoad(Generics::RecursionGraph * const pVisited, const
ClassLoader::ValidateMethodsWithCovariantReturnTypes(this);
}
if ((level == CLASS_LOADED) && CORDisableJITOptimizations(this->GetModule()->GetDebuggerInfoBits()) && !HasInstantiation())
{
if (g_fEEStarted)
{
// If the module is DEBUG, then allocate static variable memory now, so that the debugger will always be able to examine
// the static variables of the type. Never do this in the EEStartup path, as it can cause incorrect load orders to happen.
// (This only happens in practice in DEBUG builds of coreclr, or when the profiler disables all optimizations.)
EnsureStaticDataAllocated();
}
}
if (IsArray())
{
Generics::RecursionGraph newVisited(pVisited, TypeHandle(this));
@ -8685,3 +8663,18 @@ PTR_MethodTable MethodTable::InterfaceMapIterator::GetInterface(MethodTable* pMT
RETURN (pResult);
}
#endif // DACCESS_COMPILE
void MethodTable::GetStaticsOffsets(StaticsOffsetType offsetType, bool fGenericStatics, uint32_t *dwGCOffset, uint32_t *dwNonGCOffset)
{
LIMITED_METHOD_CONTRACT;
if (offsetType == StaticsOffsetType::Normal)
{
*dwNonGCOffset = 0;
*dwGCOffset = 0;
}
else
{
*dwNonGCOffset = (uint32_t)sizeof(TADDR) * 2;
*dwGCOffset = (uint32_t)sizeof(TADDR) * 2;
}
}

View file

@ -26,6 +26,7 @@
#include "generics.h"
#include "gcinfotypes.h"
#include "enum_class_flags.h"
#include "threadstatics.h"
/*
* Forward Declarations
@ -68,6 +69,12 @@ struct MethodTableAuxiliaryData;
typedef DPTR(MethodTableAuxiliaryData) PTR_MethodTableAuxiliaryData;
typedef DPTR(MethodTableAuxiliaryData const) PTR_Const_MethodTableAuxiliaryData;
enum class StaticsOffsetType
{
Normal,
ThreadLocal
};
enum class ResolveVirtualStaticMethodFlags
{
None = 0,
@ -90,6 +97,16 @@ enum class FindDefaultInterfaceImplementationFlags
support_use_as_flags // Enable the template functions in enum_class_flags.h
};
enum class MethodTableStaticsFlags
{
None = 0,
Present = 0x1,
Generic = 0x2,
Thread = 0x4,
support_use_as_flags // Enable the template functions in enum_class_flags.h
};
enum class MethodDataComputeOptions
{
NoCache, // Do not place the results of getting the MethodData into the cache, but use it if it is there
@ -279,15 +296,16 @@ struct GenericsDictInfo
}; // struct GenericsDictInfo
typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;
struct GenericsStaticsInfo
{
// Pointer to field descs for statics
PTR_FieldDesc m_pFieldDescs;
// Method table ID for statics
SIZE_T m_DynamicTypeID;
// These various statics structures exist directly before the MethodTableAuxiliaryData
}; // struct GenericsStaticsInfo
// Any MethodTable which has static variables has this structure
struct DynamicStaticsInfo;
struct ThreadStaticsInfo;
struct GenericsStaticsInfo;
typedef DPTR(DynamicStaticsInfo) PTR_DynamicStaticsInfo;
typedef DPTR(ThreadStaticsInfo) PTR_ThreadStaticsInfo;
typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
//
@ -309,20 +327,20 @@ struct MethodTableAuxiliaryData
// TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
// CARRY THE CORRECT INITIAL FLAGS.
enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0001, // Is any field type or sub field type overrode Equals or GetHashCode
enum_flag_Initialized = 0x0001,
enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x0002, // Whether we have checked the overridden Equals or GetHashCode
enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0004, // Is any field type or sub field type overridden Equals or GetHashCode
// enum_unused = 0x0004,
enum_flag_HasApproxParent = 0x0010,
// enum_unused = 0x0020,
enum_flag_IsNotFullyLoaded = 0x0040,
enum_flag_DependenciesLoaded = 0x0080, // class and all dependencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED
enum_flag_MayHaveOpenInterfaceInInterfaceMap = 0x0100,
// enum_unused = 0x0200,
// enum_unused = 0x0400,
// enum_unused = 0x0800,
// enum_unused = 0x1000,
enum_flag_IsInitError = 0x0100,
enum_flag_IsStaticDataAllocated = 0x0200,
// unum_unused = 0x0400,
enum_flag_IsTlsIndexAllocated = 0x0800,
enum_flag_MayHaveOpenInterfaceInInterfaceMap = 0x1000,
// enum_unused = 0x2000,
#ifdef _DEBUG
@ -358,6 +376,10 @@ struct MethodTableAuxiliaryData
DWORD m_dwPadding; // Just to keep the size a multiple of 8
#endif
// These pointers make it easier to examine the various statics structures in the debugger
PTR_DynamicStaticsInfo m_debugOnlyDynamicStatics;
PTR_GenericsStaticsInfo m_debugOnlyGenericStatics;
PTR_ThreadStaticsInfo m_debugOnlyThreadStatics;
#endif
public:
@ -388,6 +410,67 @@ public:
}
#endif
inline BOOL IsInitError() const
{
LIMITED_METHOD_DAC_CONTRACT;
return (VolatileLoad(&m_dwFlags) & enum_flag_IsInitError);
}
#ifndef DACCESS_COMPILE
inline void SetInitError()
{
LIMITED_METHOD_CONTRACT;
InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_IsInitError);
}
#endif
inline BOOL IsTlsIndexAllocated() const
{
LIMITED_METHOD_DAC_CONTRACT;
return (VolatileLoad(&m_dwFlags) & enum_flag_IsTlsIndexAllocated);
}
#ifndef DACCESS_COMPILE
inline void SetIsTlsIndexAllocated()
{
LIMITED_METHOD_CONTRACT;
InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_IsTlsIndexAllocated);
}
#endif
DWORD* getIsClassInitedFlagAddress()
{
LIMITED_METHOD_DAC_CONTRACT;
_ASSERTE(enum_flag_Initialized == 1); // This is an assumption in the JIT and in hand-written assembly at this time.
return &m_dwFlags;
}
inline BOOL IsClassInited() const
{
return VolatileLoad(&m_dwFlags) & enum_flag_Initialized;
}
#ifndef DACCESS_COMPILE
inline void SetClassInited()
{
LIMITED_METHOD_CONTRACT;
InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_Initialized);
}
#endif
inline BOOL IsStaticDataAllocated() const
{
LIMITED_METHOD_DAC_CONTRACT;
return (VolatileLoad(&m_dwFlags) & enum_flag_IsStaticDataAllocated);
}
#ifndef DACCESS_COMPILE
inline void SetIsStaticDataAllocated()
{
LIMITED_METHOD_CONTRACT;
InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_IsStaticDataAllocated);
}
#endif
inline RUNTIMETYPEHANDLE GetExposedClassObjectHandle() const
{
@ -431,6 +514,9 @@ public:
m_offsetToNonVirtualSlots = offset;
}
static inline PTR_DynamicStaticsInfo GetDynamicStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData);
static inline PTR_GenericsStaticsInfo GetGenericStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData);
static inline PTR_ThreadStaticsInfo GetThreadStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData);
inline void SetMayHaveOpenInterfacesInInterfaceMap()
{
LIMITED_METHOD_CONTRACT;
@ -441,12 +527,126 @@ public:
{
return !!(m_dwFlags & MethodTableAuxiliaryData::enum_flag_MayHaveOpenInterfaceInInterfaceMap);
}
}; // struct MethodTableAuxiliaryData
static inline PTR_GenericsStaticsInfo GetGenericStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData)
// All MethodTables which have static variables will have one of these. It contains the pointers necessary to
// find the normal (non-thread) static variables of the type.
struct DynamicStaticsInfo
{
private:
// The detail of whether or not the class has been initialized is stored in the statics pointers as well as in
// its normal flag location. This is done so that when getting the statics base for a class, we can get the statics
// base address and check to see if it is initialized without needing a barrier between reading the flag and reading
// the static field address.
static constexpr TADDR ISCLASSNOTINITED = 1;
static constexpr TADDR ISCLASSNOTINITEDMASK = ISCLASSNOTINITED;
static constexpr TADDR STATICSPOINTERMASK = ~ISCLASSNOTINITEDMASK;
void InterlockedSetClassInited(bool isGC)
{
TADDR oldVal;
TADDR oldValFromInterlockedOp;
TADDR *pAddr = isGC ? &m_pGCStatics : &m_pNonGCStatics;
do
{
oldVal = VolatileLoadWithoutBarrier(pAddr);
// Mask off the ISCLASSNOTINITED bit
oldValFromInterlockedOp = InterlockedCompareExchangeT(pAddr, oldVal & STATICSPOINTERMASK, oldVal);
} while(oldValFromInterlockedOp != oldVal); // We can loop if we happened to allocate the statics pointer in the middle of this operation
}
public:
TADDR m_pGCStatics; // Always access through helper methods to properly handle the ISCLASSNOTINITED bit
TADDR m_pNonGCStatics; // Always access through helper methods to properly handle the ISCLASSNOTINITED bit
PTR_MethodTable m_pMethodTable;
PTR_OBJECTREF GetGCStaticsPointer() { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pGCStatics); return dac_cast<PTR_OBJECTREF>(staticsVal & STATICSPOINTERMASK); }
PTR_BYTE GetNonGCStaticsPointer() { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pNonGCStatics); return dac_cast<PTR_BYTE>(staticsVal & STATICSPOINTERMASK); }
PTR_OBJECTREF GetGCStaticsPointerAssumeIsInited() { TADDR staticsVal = m_pGCStatics; _ASSERTE(staticsVal != 0); _ASSERTE((staticsVal & (ISCLASSNOTINITEDMASK)) == 0); return dac_cast<PTR_OBJECTREF>(staticsVal); }
PTR_BYTE GetNonGCStaticsPointerAssumeIsInited() { TADDR staticsVal = m_pNonGCStatics; _ASSERTE(staticsVal != 0); _ASSERTE((staticsVal & (ISCLASSNOTINITEDMASK)) == 0); return dac_cast<PTR_BYTE>(staticsVal); }
bool GetIsInitedAndGCStaticsPointerIfInited(PTR_OBJECTREF *ptrResult) { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pGCStatics); *ptrResult = dac_cast<PTR_OBJECTREF>(staticsVal); return !(staticsVal & ISCLASSNOTINITED); }
bool GetIsInitedAndNonGCStaticsPointerIfInited(PTR_BYTE *ptrResult) { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pNonGCStatics); *ptrResult = dac_cast<PTR_BYTE>(staticsVal); return !(staticsVal & ISCLASSNOTINITED); }
// This function sets the pointer portion of a statics pointer. It returns false if the statics value was already set.
bool InterlockedUpdateStaticsPointer(bool isGC, TADDR newVal)
{
TADDR oldVal;
TADDR oldValFromInterlockedOp;
TADDR *pAddr = isGC ? &m_pGCStatics : &m_pNonGCStatics;
do
{
oldVal = VolatileLoad(pAddr);
// Check to see if statics value has already been set
if ((oldVal & STATICSPOINTERMASK) != 0)
{
// If it has, then we don't need to do anything
return false;
}
oldValFromInterlockedOp = InterlockedCompareExchangeT(pAddr, newVal | oldVal, oldVal);
} while(oldValFromInterlockedOp != oldVal);
return true;
}
void SetClassInited()
{
InterlockedSetClassInited(true);
InterlockedSetClassInited(false);
}
#ifndef DACCESS_COMPILE
void Init(MethodTable* pMT)
{
m_pGCStatics = ISCLASSNOTINITED;
m_pNonGCStatics = ISCLASSNOTINITED;
m_pMethodTable = pMT;
}
#endif
PTR_MethodTable GetMethodTable() const { return m_pMethodTable; }
};
/* static */ inline PTR_DynamicStaticsInfo MethodTableAuxiliaryData::GetDynamicStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData)
{
return dac_cast<PTR_DynamicStaticsInfo>(dac_cast<TADDR>(pAuxiliaryData) - sizeof(DynamicStaticsInfo));
}
// Any Generic MethodTable which has static variables has this structure. Note that it ends
// with a DynamicStatics structure so that lookups for just DynamicStatics will find that structure
// when looking for statics pointers
// In addition, for simplicity in access, all MethodTables which have a ThreadStaticsInfo have this structure
// but it is unitialized and should not be used if the type is not generic
struct GenericsStaticsInfo
{
// Pointer to field descs for statics
PTR_FieldDesc m_pFieldDescs;
DynamicStaticsInfo m_DynamicStatics;
}; // struct GenericsStaticsInfo
/* static */ inline PTR_GenericsStaticsInfo MethodTableAuxiliaryData::GetGenericStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData)
{
return dac_cast<PTR_GenericsStaticsInfo>(dac_cast<TADDR>(pAuxiliaryData) - sizeof(GenericsStaticsInfo));
}
}; // struct MethodTableAuxiliaryData
// And MethodTable with Thread Statics has this structure. NOTE: This structure includes
// GenericsStatics which may not actually have the m_pFieldDescs filled in if the MethodTable
// is not actually Generic
struct ThreadStaticsInfo
{
TLSIndex NonGCTlsIndex;
TLSIndex GCTlsIndex;
GenericsStaticsInfo m_genericStatics;
void Init()
{
NonGCTlsIndex = TLSIndex::Unallocated();
GCTlsIndex = TLSIndex::Unallocated();
}
};
/* static */ inline PTR_ThreadStaticsInfo MethodTableAuxiliaryData::GetThreadStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData)
{
return dac_cast<PTR_ThreadStaticsInfo>(dac_cast<TADDR>(pAuxiliaryData) - sizeof(ThreadStaticsInfo));
}
#ifdef UNIX_AMD64_ABI_ITF
inline
@ -638,16 +838,11 @@ public:
// is accessed lives in a "loader module". The rule for determining the loader module must ensure
// that a type never outlives its loader module with respect to app-domain unloading
//
// GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that
// statics are attached to.
PTR_Module GetLoaderModule();
PTR_LoaderAllocator GetLoaderAllocator();
void SetLoaderAllocator(LoaderAllocator* pAllocator);
// Get the domain local module - useful for static init checks
PTR_DomainLocalModule GetDomainLocalModule();
MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED);
LPCWSTR GetPathForErrorMessages();
@ -806,14 +1001,6 @@ public:
BOOL HasExplicitOrImplicitPublicDefaultConstructor();
//-------------------------------------------------------------------
// THE CLASS INITIALIZATION CONDITION
// (and related DomainLocalModule storage)
//
// - populate the DomainLocalModule if needed
// - run the cctor
//
public:
// checks whether the class initialiser should be run on this class, and runs it if necessary
@ -851,15 +1038,40 @@ public:
// Init the m_dwFlags field for an array
void SetIsArray(CorElementType arrayType);
BOOL IsClassPreInited();
// mark the class as having its cctor run.
#ifndef DACCESS_COMPILE
void SetClassInited();
void SetClassInitError();
void SetClassInited()
{
GetAuxiliaryDataForWrite()->SetClassInited();
if (IsDynamicStatics())
{
GetDynamicStaticsInfo()->SetClassInited();
}
}
void AttemptToPreinit();
#endif
BOOL IsClassInited()
{
return GetAuxiliaryDataForWrite()->IsClassInited();
}
// Allocate any memory needed for statics, acquire TLSIndex for TLS statics, and check to see if the class can be considered pre-inited, and if so, set the initialized flag
void EnsureStaticDataAllocated();
void EnsureTlsIndexAllocated();
BOOL IsInitError()
{
return GetAuxiliaryData()->IsInitError();
}
#ifndef DACCESS_COMPILE
void SetClassInitError()
{
return GetAuxiliaryDataForWrite()->SetInitError();
}
#endif
BOOL IsClassInited();
BOOL IsInitError();
inline BOOL IsGlobalClass()
{
@ -867,9 +1079,6 @@ public:
return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
}
// uniquely identifes this type in the Domain table
DWORD GetClassIndex();
private:
#if defined(UNIX_AMD64_ABI_ITF)
@ -878,12 +1087,6 @@ private:
bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct, MethodTable** pByValueClassCache);
#endif // defined(UNIX_AMD64_ABI_ITF)
DWORD GetClassIndexFromToken(mdTypeDef typeToken)
{
LIMITED_METHOD_CONTRACT;
return RidFromToken(typeToken) - 1;
}
// called from CheckRunClassInitThrowing(). The type wasn't marked as
// inited while we were there, so let's attempt to do the work.
void DoRunClassInitThrowing();
@ -901,7 +1104,7 @@ public:
void SetHasClassConstructor();
WORD GetClassConstructorSlot();
void AllocateRegularStaticBoxes();
void AllocateRegularStaticBoxes(OBJECTREF** ppStaticBase);
void AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStaticHandle);
static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, bool canBeFrozen = false);
@ -2233,22 +2436,27 @@ public:
#ifndef DACCESS_COMPILE
inline PTR_BYTE GetNonGCThreadStaticsBasePointer();
inline PTR_BYTE GetGCThreadStaticsBasePointer();
inline PTR_BYTE GetGCThreadStaticsBaseHandle();
#endif //!DACCESS_COMPILE
// Do not use except in DAC and profiler scenarios.
// These apis are difficult to use correctly. Users must
// 1. Be aware that a GC may make the address returned invalid
// 2. Be aware that a thread shutdown may make the address returned invalid
// 3. Be aware that a collectible assembly could be collected, thus rendering the address returned invalid
// This is particularly relevant as a problem for profiler developers, but they are given the tools (such as GC events) to be notified of situations where these invariants may not hold
inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread);
inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread);
inline DWORD IsDynamicStatics()
{
LIMITED_METHOD_DAC_CONTRACT;
return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic);
return GetFlag(enum_flag_DynamicStatics);
}
inline void SetDynamicStatics(BOOL fGeneric)
inline void SetDynamicStatics()
{
LIMITED_METHOD_CONTRACT;
SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic);
SetFlag(enum_flag_DynamicStatics);
}
inline void SetHasBoxedRegularStatics()
@ -2292,7 +2500,7 @@ public:
BOOL HasGenericsStaticsInfo()
{
LIMITED_METHOD_DAC_CONTRACT;
return GetFlag(enum_flag_StaticsMask_Generics);
return IsDynamicStatics() && HasInstantiation();
}
PTR_FieldDesc GetGenericsStaticFieldDescs()
@ -2302,24 +2510,8 @@ public:
return GetGenericsStaticsInfo()->m_pFieldDescs;
}
BOOL HasCrossModuleGenericStaticsInfo()
{
LIMITED_METHOD_DAC_CONTRACT;
return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics);
}
PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID);
WORD GetNumHandleRegularStatics();
//-------------------------------------------------------------------
// DYNAMIC ID
//
// Used for generics and reflection emit in memory
DWORD GetModuleDynamicEntryID();
Module* GetModuleForStatics();
//-------------------------------------------------------------------
// GENERICS DICT INFO
//
@ -2681,7 +2873,7 @@ public:
// ------------------------------------------------------------------
#ifndef DACCESS_COMPILE
void AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, bool hasGenericStatics = false, WORD nonVirtualSlots = 0, S_SIZE_T extraAllocation = S_SIZE_T(0));
void AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, MethodTableStaticsFlags staticsFlags = MethodTableStaticsFlags::None, WORD nonVirtualSlots = 0, S_SIZE_T extraAllocation = S_SIZE_T(0));
#endif
inline PTR_Const_MethodTableAuxiliaryData GetAuxiliaryData() const
@ -2696,6 +2888,12 @@ public:
return MethodTable::m_pAuxiliaryData;
}
DWORD* getIsClassInitedFlagAddress()
{
LIMITED_METHOD_DAC_CONTRACT;
return GetAuxiliaryDataForWrite()->getIsClassInitedFlagAddress();
}
//-------------------------------------------------------------------
// The GUID Info
// Used by COM interop to get GUIDs (IIDs and CLSIDs)
@ -3278,12 +3476,6 @@ private:
enum_flag_UNUSED_ComponentSize_1 = 0x00000001,
// GC depends on this bit
enum_flag_HasCriticalFinalizer = 0x00000002, // finalizer must be run on Appdomain Unload
enum_flag_StaticsMask = 0x0000000C,
enum_flag_StaticsMask_NonDynamic = 0x00000000,
enum_flag_StaticsMask_Dynamic = 0x00000008, // dynamic statics (EnC, reflection.emit)
enum_flag_StaticsMask_Generics = 0x00000004, // generics statics
enum_flag_StaticsMask_CrossModuleGenerics = 0x0000000C, // cross module generics statics (NGen)
enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000008, // helper constant to get rid of unnecessary check
enum_flag_GenericsMask = 0x00000030,
@ -3329,7 +3521,6 @@ private:
// to be up to date to reflect the default values of those flags for the
// case where this MethodTable is for a String or Array
enum_flag_StringArrayValues = SET_FALSE(enum_flag_HasCriticalFinalizer) |
SET_TRUE(enum_flag_StaticsMask_NonDynamic) |
SET_FALSE(enum_flag_HasBoxedRegularStatics) |
SET_FALSE(enum_flag_HasBoxedThreadStatics) |
SET_TRUE(enum_flag_GenericsMask_NonGeneric) |
@ -3415,10 +3606,8 @@ private:
// TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
// CARRY THE CORECT FLAGS.
// The following bits describe usage of optional slots. They have to stay
// together because of we index using them into offset arrays.
enum_flag_HasPerInstInfo = 0x0001,
enum_flag_wflags2_unused_1 = 0x0002,
enum_flag_DynamicStatics = 0x0002,
enum_flag_HasDispatchMapSlot = 0x0004,
enum_flag_wflags2_unused_2 = 0x0008,
@ -3570,9 +3759,26 @@ private:
PTR_GenericsStaticsInfo GetGenericsStaticsInfo()
{
PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite();
_ASSERTE(HasGenericsStaticsInfo());
return MethodTableAuxiliaryData::GetGenericStaticsInfo(AuxiliaryData);
}
public:
PTR_DynamicStaticsInfo GetDynamicStaticsInfo()
{
PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite();
_ASSERTE(IsDynamicStatics());
return MethodTableAuxiliaryData::GetDynamicStaticsInfo(AuxiliaryData);
}
PTR_ThreadStaticsInfo GetThreadStaticsInfo()
{
PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite();
_ASSERTE(GetNumThreadStaticFields() > 0);
return MethodTableAuxiliaryData::GetThreadStaticsInfo(AuxiliaryData);
}
private:
// Optional members. These are used for fields in the data structure where
// the fields are (a) known when MT is created and (b) there is a default
// value for the field in the common case. That is, they are normally used
@ -3650,6 +3856,8 @@ private:
public:
BOOL Validate ();
static void GetStaticsOffsets(StaticsOffsetType staticsOffsetType, bool fGenericsStatics, uint32_t *dwGCOffset, uint32_t *dwNonGCOffset);
}; // class MethodTable
#ifndef CROSSBITNESS_COMPILE

View file

@ -1083,68 +1083,45 @@ inline DWORD MethodTable::GetOptionalMembersSize()
inline PTR_BYTE MethodTable::GetNonGCStaticsBasePointer()
{
WRAPPER_NO_CONTRACT;
return GetDomainLocalModule()->GetNonGCStaticsBasePointer(this);
if (!IsDynamicStatics())
{
return NULL;
}
else
{
return GetDynamicStaticsInfo()->GetNonGCStaticsPointer();
}
}
//==========================================================================================
inline PTR_BYTE MethodTable::GetGCStaticsBasePointer()
{
WRAPPER_NO_CONTRACT;
return GetDomainLocalModule()->GetGCStaticsBasePointer(this);
if (!IsDynamicStatics())
{
return NULL;
}
else
{
return (PTR_BYTE)GetDynamicStaticsInfo()->GetGCStaticsPointer();
}
}
#ifndef DACCESS_COMPILE
//==========================================================================================
inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
// Get the current thread
PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread());
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
return NULL;
return pTLM->GetNonGCStaticsBasePointer(this);
}
//==========================================================================================
inline PTR_BYTE MethodTable::GetGCThreadStaticsBaseHandle()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
}
CONTRACTL_END;
// Get the current thread
PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread());
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
return NULL;
return dac_cast<PTR_BYTE>(pTLM->GetPrecomputedGCStaticsBaseHandle());
EnsureTlsIndexAllocated();
TLSIndex tlsIndex = GetThreadStaticsInfo()->NonGCTlsIndex;
return (PTR_BYTE)GetThreadLocalStaticBase(tlsIndex);
}
//==========================================================================================
@ -1152,25 +1129,15 @@ inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
}
CONTRACTL_END;
// Get the current thread
PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread());
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
return NULL;
return pTLM->GetGCStaticsBasePointer(this);
EnsureTlsIndexAllocated();
TLSIndex tlsIndex = GetThreadStaticsInfo()->GCTlsIndex;
return (PTR_BYTE)GetThreadLocalStaticBase(tlsIndex);
}
#endif //!DACCESS_COMPILE
@ -1180,16 +1147,11 @@ inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread
{
LIMITED_METHOD_DAC_CONTRACT;
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
TLSIndex tlsIndex = GetThreadStaticsInfo()->NonGCTlsIndex;
if (!tlsIndex.IsAllocated())
return NULL;
return pTLM->GetNonGCStaticsBasePointer(this);
return (PTR_BYTE)GetThreadLocalStaticBaseNoCreate(pThread, tlsIndex);
}
//==========================================================================================
@ -1197,23 +1159,11 @@ inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread)
{
LIMITED_METHOD_DAC_CONTRACT;
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
TLSIndex tlsIndex = GetThreadStaticsInfo()->GCTlsIndex;
if (!tlsIndex.IsAllocated())
return NULL;
return pTLM->GetGCStaticsBasePointer(this);
}
//==========================================================================================
inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule()
{
WRAPPER_NO_CONTRACT;
return GetModuleForStatics()->GetDomainLocalModule();
return (PTR_BYTE)GetThreadLocalStaticBaseNoCreate(pThread, tlsIndex);
}
//==========================================================================================
@ -1237,13 +1187,6 @@ inline OBJECTREF MethodTable::AllocateNoChecks()
}
//==========================================================================================
inline DWORD MethodTable::GetClassIndex()
{
WRAPPER_NO_CONTRACT;
return GetClassIndexFromToken(GetCl());
}
#ifndef DACCESS_COMPILE
//==========================================================================================
// unbox src into dest, making sure src is of the correct type.
@ -1297,27 +1240,6 @@ inline void MethodTable::UnBoxIntoUnchecked(void *dest, OBJECTREF src)
}
#endif
//==========================================================================================
FORCEINLINE PTR_Module MethodTable::GetGenericsStaticsModuleAndID(DWORD * pID)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
SUPPORTS_DAC;
}
CONTRACTL_END
_ASSERTE(HasGenericsStaticsInfo());
PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite();
PTR_GenericsStaticsInfo staticsInfo = MethodTableAuxiliaryData::GetGenericStaticsInfo(AuxiliaryData);
_ASSERTE(FitsIn<DWORD>(staticsInfo->m_DynamicTypeID) || staticsInfo->m_DynamicTypeID == (SIZE_T)-1);
*pID = (DWORD)staticsInfo->m_DynamicTypeID;
return AuxiliaryData->GetLoaderModule();
}
//==========================================================================================
inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle()
{

View file

@ -1673,21 +1673,10 @@ MethodTableBuilder::BuildMethodTableThrowing(
//
// We decide here if we need a dynamic entry for our statics. We need it here because
// the offsets of our fields will depend on this. For the dynamic case (which requires
// an extra indirection (indirect depending of methodtable) we'll allocate the slot
// in setupmethodtable
if (((pAllocator->IsCollectible() || pModule->IsReflection() || bmtGenerics->HasInstantiation() || !pModule->IsStaticStoragePrepared(cl)) &&
(bmtVT->GetClassCtorSlotIndex() != INVALID_SLOT_INDEX || bmtEnumFields->dwNumStaticFields !=0))
#ifdef FEATURE_METADATA_UPDATER
// Classes in modules that have been edited (would do on class level if there were a
// way to tell if the class had been edited) also have dynamic statics as the number
// of statics might have changed, so can't use the static module-wide storage
|| (pModule->IsEditAndContinueEnabled() &&
((EditAndContinueModule*)pModule)->GetApplyChangesCount() > CorDB_DEFAULT_ENC_FUNCTION_VERSION)
#endif // FEATURE_METADATA_UPDATER
)
// the offsets of our fields will depend on this.
if (bmtEnumFields->dwNumStaticFields != 0)
{
// We will need a dynamic id
// We will need static variables
bmtProp->fDynamicStatics = true;
if (bmtGenerics->HasInstantiation())
@ -1911,15 +1900,6 @@ MethodTableBuilder::BuildMethodTableThrowing(
pMT->SetupGenericsStaticsInfo(pStaticFieldDescs);
}
else
{
// Get an id for the dynamic class. We store it in the class because
// no class that is persisted in ngen should have it (ie, if the class is ngened
// The id is stored in an optional field so we need to ensure an optional field descriptor has
// been allocated for this EEClass instance.
EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, pAllocator->GetLowFrequencyHeap());
SetModuleDynamicID(GetModule()->AllocateDynamicEntry(pMT));
}
}
//
@ -7910,11 +7890,8 @@ VOID MethodTableBuilder::PlaceRegularStaticFields()
// Tell the module to give us the offsets we'll be using and commit space for us
// if necessary
DWORD dwNonGCOffset, dwGCOffset;
GetModule()->GetOffsetsForRegularStaticData(bmtInternal->pType->GetTypeDefToken(),
bmtProp->fDynamicStatics,
GetNumHandleRegularStatics(), dwCumulativeStaticFieldPos,
&dwGCOffset, &dwNonGCOffset);
uint32_t dwNonGCOffset, dwGCOffset;
MethodTable::GetStaticsOffsets(StaticsOffsetType::Normal, bmtProp->fGenericsStatics, &dwGCOffset, &dwNonGCOffset);
// Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
dwCumulativeStaticGCFieldPos = bmtFP->NumRegularStaticGCBoxedFields<<LOG2_PTRSIZE;
@ -7962,17 +7939,9 @@ VOID MethodTableBuilder::PlaceRegularStaticFields()
LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset()));
}
if (bmtProp->fDynamicStatics)
{
_ASSERTE(dwNonGCOffset == 0 || // no statics at all
dwNonGCOffset == OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob); // We need space to point to the GC statics
_ASSERTE(dwNonGCOffset == 0 || (dwNonGCOffset == sizeof(TADDR) * 2));
bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos;
}
else
{
bmtProp->dwNonGCRegularStaticFieldBytes = 0; // Non dynamics shouldnt be using this
}
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCRegularStaticFieldBytes));
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed %i\n", bmtProp->dwNonGCRegularStaticFieldBytes));
}
@ -8024,12 +7993,9 @@ VOID MethodTableBuilder::PlaceThreadStaticFields()
// Tell the module to give us the offsets we'll be using and commit space for us
// if necessary
DWORD dwNonGCOffset, dwGCOffset;
uint32_t dwNonGCOffset, dwGCOffset;
GetModule()->GetOffsetsForThreadStaticData(bmtInternal->pType->GetTypeDefToken(),
bmtProp->fDynamicStatics,
GetNumHandleThreadStatics(), dwCumulativeStaticFieldPos,
&dwGCOffset, &dwNonGCOffset);
MethodTable::GetStaticsOffsets(StaticsOffsetType::ThreadLocal, bmtProp->fGenericsStatics, &dwGCOffset, &dwNonGCOffset);
// Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)")
dwCumulativeStaticGCFieldPos = bmtFP->NumThreadStaticGCBoxedFields<<LOG2_PTRSIZE;
@ -8077,15 +8043,14 @@ VOID MethodTableBuilder::PlaceThreadStaticFields()
LOG((LF_CLASSLOADER, LL_INFO1000000, "Offset of %s: %i\n", pCurField->m_debugName, pCurField->GetOffset()));
}
if (bmtProp->fDynamicStatics)
if (dwCumulativeStaticFieldPos != 0)
{
_ASSERTE(dwNonGCOffset == 0 || // no thread statics at all
dwNonGCOffset == OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob); // We need space to point to the GC statics
_ASSERTE(bmtProp->fDynamicStatics);
bmtProp->dwNonGCThreadStaticFieldBytes = dwCumulativeStaticFieldPos;
}
else
{
bmtProp->dwNonGCThreadStaticFieldBytes = 0; // Non dynamics shouldnt be using this
bmtProp->dwNonGCThreadStaticFieldBytes = 0;
}
LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: ThreadStatic field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCThreadStaticFieldBytes));
}
@ -10272,6 +10237,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT(
BOOL isInterface,
BOOL fDynamicStatics,
BOOL fHasGenericsStaticsInfo,
bool fHasThreadStatics,
BOOL fHasVirtualStaticMethods
#ifdef FEATURE_COMINTEROP
, BOOL fHasDynamicInterfaceMap
@ -10374,7 +10340,20 @@ MethodTable * MethodTableBuilder::AllocateNewMT(
pMT->SetFlag(MethodTable::enum_flag_HasPerInstInfo);
}
pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, fHasGenericsStaticsInfo, static_cast<WORD>(dwNonVirtualSlots), S_SIZE_T(dispatchMapAllocationSize));
MethodTableStaticsFlags staticsFlags = MethodTableStaticsFlags::None;
if (fDynamicStatics)
staticsFlags |= MethodTableStaticsFlags::Present;
if (fHasGenericsStaticsInfo)
{
_ASSERTE(fDynamicStatics);
staticsFlags |= MethodTableStaticsFlags::Generic;
}
if (fHasThreadStatics)
staticsFlags |= MethodTableStaticsFlags::Thread;
pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, staticsFlags, static_cast<WORD>(dwNonVirtualSlots), S_SIZE_T(dispatchMapAllocationSize));
pMT->GetAuxiliaryDataForWrite()->SetIsNotFullyLoadedForBuildMethodTable();
@ -10470,7 +10449,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT(
if (fDynamicStatics)
{
pMT->SetDynamicStatics(fHasGenericsStaticsInfo);
pMT->SetDynamicStatics();
}
// the dictionary pointers follow the interface map
@ -10574,6 +10553,7 @@ MethodTableBuilder::SetupMethodTable2(
IsInterface(),
bmtProp->fDynamicStatics,
bmtProp->fGenericsStatics,
bmtEnumFields->dwNumThreadStaticFields != 0,
bmtProp->fHasVirtualStaticMethods,
#ifdef FEATURE_COMINTEROP
fHasDynamicInterfaceMap,
@ -10663,6 +10643,7 @@ MethodTableBuilder::SetupMethodTable2(
pMT->SetHasClassConstructor();
CONSISTENCY_CHECK(pMT->GetClassConstructorSlot() == bmtVT->pCCtor->GetSlotIndex());
}
if (bmtVT->pDefaultCtor != NULL)
{
pMT->SetHasDefaultConstructor();

View file

@ -206,7 +206,6 @@ private:
void SetUnsafeValueClass() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetUnsafeValueClass(); }
void SetHasFieldsWhichMustBeInited() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetHasFieldsWhichMustBeInited(); }
void SetHasNonPublicFields() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetHasNonPublicFields(); }
void SetModuleDynamicID(DWORD x) { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetModuleDynamicID(x); }
void SetNumHandleRegularStatics(WORD x) { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetNumHandleRegularStatics(x); }
void SetNumHandleThreadStatics(WORD x) { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetNumHandleThreadStatics(x); }
void SetAlign8Candidate() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetAlign8Candidate(); }
@ -2952,6 +2951,7 @@ private:
BOOL isIFace,
BOOL fDynamicStatics,
BOOL fHasGenericsStaticsInfo,
bool fHasThreadStatics,
BOOL fHasVirtualStaticMethods
#ifdef FEATURE_COMINTEROP
, BOOL bHasDynamicInterfaceMap

View file

@ -3497,21 +3497,6 @@ static PCODE getHelperForSharedStatic(Module * pModule, CORCOMPILE_FIXUP_BLOB_KI
CorInfoHelpFunc helpFunc = CEEInfo::getSharedStaticsHelper(pFD, pMT);
TADDR moduleID = pMT->GetModuleForStatics()->GetModuleID();
TADDR classID = 0;
if (helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR && helpFunc != CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR)
{
if (pMT->IsDynamicStatics())
{
classID = pMT->GetModuleDynamicEntryID();
}
else
{
classID = pMT->GetClassIndex();
}
}
bool fUnbox = (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE);
AllocMemTracker amTracker;
@ -3521,8 +3506,31 @@ static PCODE getHelperForSharedStatic(Module * pModule, CORCOMPILE_FIXUP_BLOB_KI
AllocMem(S_SIZE_T(sizeof(StaticFieldAddressArgs))));
pArgs->staticBaseHelper = (FnStaticBaseHelper)CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)helpFunc);
pArgs->arg0 = moduleID;
pArgs->arg1 = classID;
switch(helpFunc)
{
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE:
pArgs->arg0 = (TADDR)pMT->GetThreadStaticsInfo();
break;
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_GCSTATIC_BASE:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR:
case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE:
case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE:
pArgs->arg0 = (TADDR)pMT->GetDynamicStaticsInfo();
break;
default:
_ASSERTE(!"Unexpected shared statics helper CORINFO_HELP_FUNC");
pArgs->arg0 = 0;
break;
}
pArgs->offset = pFD->GetOffset();
PCODE pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), (TADDR)pArgs,
@ -3537,52 +3545,50 @@ static PCODE getHelperForStaticBase(Module * pModule, CORCOMPILE_FIXUP_BLOB_KIND
{
STANDARD_VM_CONTRACT;
int helpFunc = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
pMT->AttemptToPreinit();
bool GCStatic = (kind == ENCODE_STATIC_BASE_GC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER);
bool noCtor = pMT->IsClassInited();
bool threadStatic = (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER);
if (kind == ENCODE_STATIC_BASE_GC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER)
{
helpFunc = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
}
CorInfoHelpFunc helper;
if (pMT->IsDynamicStatics())
if (threadStatic)
{
const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
helpFunc += delta;
if (GCStatic)
{
if (noCtor)
helper = CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GET_GCTHREADSTATIC_BASE;
}
else
if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
{
const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
helpFunc += delta;
if (noCtor)
helper = CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE;
}
if (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER)
}
else
{
const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
helpFunc += delta;
if (GCStatic)
{
if (noCtor)
helper = CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GET_GCSTATIC_BASE;
}
else
{
if (noCtor)
helper = CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR;
else
helper = CORINFO_HELP_GET_NONGCSTATIC_BASE;
}
}
PCODE pHelper;
if (helpFunc == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR || helpFunc == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR)
{
pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), pMT->GetModule()->GetModuleID(), CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)helpFunc));
}
else
{
TADDR moduleID = pMT->GetModuleForStatics()->GetModuleID();
TADDR classID;
if (pMT->IsDynamicStatics())
{
classID = pMT->GetModuleDynamicEntryID();
}
else
{
classID = pMT->GetClassIndex();
}
pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), moduleID, classID, CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)helpFunc));
}
pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), (TADDR)pMT, CEEJitInfo::getHelperFtnStatic(helper));
return pHelper;
}
@ -3800,6 +3806,11 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR
Statics:
th.AsMethodTable()->EnsureInstanceActive();
th.AsMethodTable()->CheckRunClassInitThrowing();
if (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER ||
(kind == ENCODE_FIELD_ADDRESS && pFD->IsThreadStatic()))
{
th.AsMethodTable()->EnsureTlsIndexAllocated();
}
fReliable = true;
break;
@ -4139,11 +4150,9 @@ extern "C" SIZE_T STDCALL DynamicHelperWorker(TransitionBlock * pTransitionBlock
result = (SIZE_T)th.AsMethodTable()->GetGCStaticsBasePointer();
break;
case ENCODE_THREAD_STATIC_BASE_NONGC_HELPER:
ThreadStatics::GetTLM(th.AsMethodTable())->EnsureClassAllocated(th.AsMethodTable());
result = (SIZE_T)th.AsMethodTable()->GetNonGCThreadStaticsBasePointer();
break;
case ENCODE_THREAD_STATIC_BASE_GC_HELPER:
ThreadStatics::GetTLM(th.AsMethodTable())->EnsureClassAllocated(th.AsMethodTable());
result = (SIZE_T)th.AsMethodTable()->GetGCThreadStaticsBasePointer();
break;
case ENCODE_CCTOR_TRIGGER:

View file

@ -143,9 +143,7 @@ inline BOOL IsClassOfMethodTableInited(MethodTable * pMethodTable)
{
LIMITED_METHOD_CONTRACT;
return ((pMethodTable->GetModuleForStatics() != NULL) &&
(pMethodTable->GetDomainLocalModule() != NULL) &&
pMethodTable->IsClassInited());
return pMethodTable->IsClassInited();
}

View file

@ -201,12 +201,6 @@ ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT)
ASMCONSTANTS_C_ASSERT(ResolveCacheElem__target == offsetof(ResolveCacheElem, target));
ASMCONSTANTS_C_ASSERT(ResolveCacheElem__pNext == offsetof(ResolveCacheElem, pNext));
#define DomainLocalModule__m_pDataBlob 0x30
#define DomainLocalModule__m_pGCStatics 0x20
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob));
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics));
// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
#define Frame__m_Next 0x08
ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next))

View file

@ -520,25 +520,6 @@ NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
EPILOG_BRANCH_REG t4
NESTED_END TheUMEntryPrestub, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
addi a2, a0, DomainLocalModule__m_pDataBlob
add a2, a2, a1
lb a2, 0(a2)
andi t5, a2, 1
beq t5, zero, LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper)
ld a0, DomainLocalModule__m_pGCStatics(a0)
ret
LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper):
// Tail call JIT_GetSharedGCStaticBase_Helper
call JIT_GetSharedGCStaticBase_Helper
LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT
// Make sure the `FaultingExceptionFrame_StackAlloc` is 16-byte aligned.
#define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame + 0x8)
#define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie
@ -667,22 +648,6 @@ NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler
EPILOG_BRANCH_REG t4
NESTED_END ResolveWorkerAsmStub, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
ret
LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT
// ------------------------------------------------------------------
// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
ld a0, (DomainLocalModule__m_pGCStatics)(a0)
ret
LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT
#ifdef FEATURE_HIJACK
// ------------------------------------------------------------------
// Hijack function for functions which return a scalar type or a struct (value type)
@ -848,30 +813,6 @@ LEAF_END setFPReturn, _TEXT
#endif // FEATURE_COMINTEROP
//
// JIT Static access helpers when coreclr host specifies single appdomain flag
//
// ------------------------------------------------------------------
// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
// If class is not initialized, bail to C++ helper
// dext a1, a1, 0, 32
addi a2, a0, DomainLocalModule__m_pDataBlob
add a2, a2, a1
lb a2, 0(a2)
andi t4, a2, 1
beq t4, zero, LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper)
ret
LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper):
// Tail call JIT_GetSharedNonGCStaticBase_Helper
tail JIT_GetSharedNonGCStaticBase_Helper
LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT
#ifdef FEATURE_READYTORUN
NESTED_ENTRY DelayLoad_MethodCall_FakeProlog, _TEXT, NoHandler

View file

@ -104,10 +104,6 @@ inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatH
//
// Create alias for optimized implementations of helpers provided on this platform
//
#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
//**********************************************************************
// Frames

View file

@ -85,6 +85,7 @@ void SpinLock::Init(LOCK_TYPE type, bool RequireCoopGC)
#endif
}
#ifndef DACCESS_COMPILE
#ifdef _DEBUG
BOOL SpinLock::OwnedByCurrentThread()
{
@ -398,5 +399,6 @@ void SpinLockProfiler::DumpStatics()
}
#endif // _DEBUG
#endif // !DACCESS_COMPILE
// End of file: spinlock.cpp

View file

@ -134,7 +134,8 @@ enum LOCK_TYPE
#endif
LOCK_REFLECTCACHE = 5,
LOCK_CORMAP = 7,
LOCK_TYPE_DEFAULT = 8
LOCK_TLSDATA = 8,
LOCK_TYPE_DEFAULT = 9
};
//----------------------------------------------------------------------------
@ -204,6 +205,7 @@ public:
static void AcquireLock(SpinLock *s);
static void ReleaseLock(SpinLock *s);
#ifndef DACCESS_COMPILE
class Holder
{
SpinLock * m_pSpinLock;
@ -224,9 +226,10 @@ public:
m_pSpinLock->FreeLock();
}
};
#endif // !DACCESS_COMPILE
};
#ifndef DACCESS_COMPILE
typedef SpinLock::Holder SpinLockHolder;
#define TAKE_SPINLOCK_AND_DONOT_TRIGGER_GC(lock) \
SpinLockHolder __spinLockHolder(lock);\
@ -244,6 +247,8 @@ typedef SpinLock::Holder SpinLockHolder;
SpinLock::ReleaseLock(lock); \
} \
#endif // !DACCESS_COMPILE
__inline BOOL IsOwnerOfSpinLock (LPVOID lock)
{
WRAPPER_NO_CONTRACT;

View file

@ -82,26 +82,26 @@ DebugBlockingItemHolder::DebugBlockingItemHolder(Thread *pThread, DebugBlockingI
}
CONTRACTL_END;
// Try to get the address of the thread-local slot for the managed ThreadBlockingInfo.t_first
m_ppFirstBlockingInfo = (ThreadBlockingInfo**)&t_ThreadStatics.ThreadBlockingInfo_First;
#ifdef _DEBUG
// Try to verify the address of the thread-local slot for the managed ThreadBlockingInfo.t_first matches the address of the native thread static
EX_TRY
{
FieldDesc *pFD = CoreLibBinder::GetField(FIELD__THREAD_BLOCKING_INFO__FIRST);
m_ppFirstBlockingInfo = (ThreadBlockingInfo **)Thread::GetStaticFieldAddress(pFD);
_ASSERTE(m_ppFirstBlockingInfo == (ThreadBlockingInfo **)Thread::GetStaticFieldAddress(pFD));
}
EX_CATCH
{
}
EX_END_CATCH(RethrowTerminalExceptions);
#endif
if (m_ppFirstBlockingInfo != nullptr)
{
// Push info for the managed ThreadBlockingInfo
m_blockingInfo.objectPtr = pItem->pMonitor;
m_blockingInfo.objectKind = (ThreadBlockingInfo::ObjectKind)pItem->type;
m_blockingInfo.timeoutMs = (INT32)pItem->dwTimeout;
m_blockingInfo.next = *m_ppFirstBlockingInfo;
*m_ppFirstBlockingInfo = &m_blockingInfo;
}
pThread->DebugBlockingInfo.PushBlockingItem(pItem);
}
@ -115,14 +115,8 @@ DebugBlockingItemHolder::~DebugBlockingItemHolder()
m_pThread->DebugBlockingInfo.PopBlockingItem();
if (m_ppFirstBlockingInfo != nullptr)
{
// Pop info for the managed ThreadBlockingInfo
_ASSERTE(
m_ppFirstBlockingInfo ==
(void *)m_pThread->GetStaticFieldAddrNoCreate(CoreLibBinder::GetField(FIELD__THREAD_BLOCKING_INFO__FIRST)));
_ASSERTE(*m_ppFirstBlockingInfo == &m_blockingInfo);
*m_ppFirstBlockingInfo = m_blockingInfo.next;
}
}
#endif //DACCESS_COMPILE

View file

@ -111,24 +111,6 @@ BYTE* ThreadStore::s_pOSContextBuffer = NULL;
CLREvent *ThreadStore::s_pWaitForStackCrawlEvent;
PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(ModuleIndex index)
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
if (index.m_dwIndex >= m_TLMTableSize)
return NULL;
return m_pTLMTable[index.m_dwIndex].pTLM;
}
PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(MethodTable* pMT)
{
WRAPPER_NO_CONTRACT;
ModuleIndex index = pMT->GetModuleForStatics()->GetModuleIndex();
return GetTLMIfExists(index);
}
#ifndef DACCESS_COMPILE
BOOL Thread::s_fCleanFinalizedThread = FALSE;
@ -370,6 +352,7 @@ void SetThread(Thread* t)
gCurrentThreadInfo.m_pThread = t;
if (t != NULL)
{
InitializeCurrentThreadsStaticData(t);
EnsureTlsDestructionMonitor();
}
@ -1613,6 +1596,8 @@ Thread::Thread()
m_isInForbidSuspendForDebuggerRegion = false;
m_hasPendingActivation = false;
m_ThreadLocalDataPtr = NULL;
#ifdef _DEBUG
memset(dangerousObjRefs, 0, sizeof(dangerousObjRefs));
#endif // _DEBUG
@ -7482,10 +7467,6 @@ LPVOID Thread::GetStaticFieldAddress(FieldDesc *pFD)
// for static field the MethodTable is exact even for generic classes
MethodTable *pMT = pFD->GetEnclosingMethodTable();
// We need to make sure that the class has been allocated, however
// we should not call the class constructor
ThreadStatics::GetTLM(pMT)->EnsureClassAllocated(pMT);
PTR_BYTE base = NULL;
if (pFD->GetFieldType() == ELEMENT_TYPE_CLASS ||
@ -7643,25 +7624,15 @@ void Thread::DeleteThreadStaticData()
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
}
CONTRACTL_END;
m_ThreadLocalBlock.FreeTable();
}
//+----------------------------------------------------------------------------
//
// Method: Thread::DeleteThreadStaticData public
//
// Synopsis: Delete the static data for the given module. This is called
// when the AssemblyLoadContext unloads.
//
//
//+----------------------------------------------------------------------------
void Thread::DeleteThreadStaticData(ModuleIndex index)
FreeLoaderAllocatorHandlesForTLSData(this);
if (!IsAtProcessExit() && !g_fEEShutDown)
{
m_ThreadLocalBlock.FreeTLM(index.m_dwIndex, FALSE /* isThreadShuttingDown */);
FreeThreadStaticData(m_ThreadLocalDataPtr, this);
}
}
OBJECTREF Thread::GetCulture(BOOL bUICulture)
@ -8214,7 +8185,8 @@ Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
m_ExceptionState.EnumChainMemoryRegions(flags);
m_ThreadLocalBlock.EnumMemoryRegions(flags);
if (GetThreadLocalDataPtr() != NULL)
EnumThreadMemoryRegions(GetThreadLocalDataPtr(), flags);
if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
{

Some files were not shown because too many files have changed in this diff Show more