Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cdac] Basic ISOSDacInterface::GetMethodDescData #106413

Closed
wants to merge 69 commits into from
Closed
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
601938d
wip: NativeCodePointers and MethodDesc CodeData
lambdageek Jul 19, 2024
5f3599c
checkpoint: PrecodeMachineDescriptor and KnownPrecodeType
lambdageek Jul 23, 2024
2cf8fd4
checkpoint: StubPrecodeData, StubCodePageSize
lambdageek Jul 24, 2024
7ef9016
GetTemporaryEntryPointIfExists
lambdageek Jul 24, 2024
9cf7a7a
wip GetMethodEntryPointIfExists
lambdageek Jul 26, 2024
2d1e34e
add contract
lambdageek Jul 29, 2024
2d4252a
add missing descriptor fields
lambdageek Jul 29, 2024
c83ad25
fix data descriptor reads
lambdageek Jul 29, 2024
c6dae6f
add FixupPrecodeData
lambdageek Jul 29, 2024
43e1748
add size of MethodDesc
lambdageek Jul 29, 2024
72369e3
fix thumb flag logic
lambdageek Jul 29, 2024
93f0a3d
WIP - broken - ExecutionManagerGetCodeMethodDesc
lambdageek Jul 29, 2024
58aa614
fix build
lambdageek Jul 30, 2024
4c211d4
fixup cdac_offsets<> -> cdac_data<>
lambdageek Jul 30, 2024
ce772d9
WIP RangeSectionMap
lambdageek Jul 31, 2024
891f07f
tag ExecutionManager pointers
lambdageek Jul 31, 2024
5717664
Add IJitManager::JitManagerKind
lambdageek Jul 31, 2024
1eeb513
WIP JitCodeToMethodInfo
lambdageek Jul 31, 2024
2a95bda
WIP NibbleMap
lambdageek Aug 2, 2024
ebf76a3
add HeapList
lambdageek Aug 2, 2024
7defaef
fix datadescriptor.h typo
lambdageek Aug 2, 2024
9181f3f
Add StoredSigMethodDesc
lambdageek Aug 5, 2024
86954df
fix bit twiddling
lambdageek Aug 5, 2024
0d0b592
fixup NonValidated.MethodDesc.NativeCodeSlotIndex
lambdageek Aug 5, 2024
63e0334
fixup additional pointers packing index
lambdageek Aug 5, 2024
c177e4d
fix logic typo
lambdageek Aug 5, 2024
3956b06
checkpoint: jitted methods validate
lambdageek Aug 7, 2024
0b91b85
more asserts in legacy GetMethodDescData
lambdageek Aug 7, 2024
d3a8bb0
WIP: native code version
lambdageek Aug 7, 2024
5fcdc60
WIP: native code version
lambdageek Aug 8, 2024
efad4ea
checkpoint start adding NativeCodeVersion operations
lambdageek Aug 9, 2024
6febf72
checkpoint: NativeCodeVersionContract.GetSpecificNativeCodeVersion
lambdageek Aug 9, 2024
dd86095
remove AppDomain.CodeVersionManager from cdac
lambdageek Aug 9, 2024
5b33737
WIP: il code version lookup table
lambdageek Aug 12, 2024
de58ab5
fixup build
lambdageek Aug 12, 2024
0b6f6e4
wip: FindActiveILCodeVersion/FindActiveNativeCodeVersion
lambdageek Aug 12, 2024
502cd31
implement GetModuleLookupMapElement
lambdageek Aug 13, 2024
312f2ce
FindActiveILCodeVersion
lambdageek Aug 13, 2024
c813a78
checkpoint sketch out one working path through GetMethodDescData
lambdageek Aug 14, 2024
f225adb
fixup after rebase
lambdageek Aug 14, 2024
2cb8e86
fixup rebae; remove duplicate global
lambdageek Aug 14, 2024
f4852d2
checkpoint: works on some methods (NO REJIT)
lambdageek Aug 14, 2024
da7065e
remove JitManagerKind in the runtime
lambdageek Aug 14, 2024
818c21c
remove more
lambdageek Aug 14, 2024
1f6a909
whitespace and comments
lambdageek Aug 14, 2024
04f41f6
remove instance field initialization from PrecodeMachineDescriptor
lambdageek Aug 15, 2024
abf9df0
suggestion from code review make m_IsCollectible a const BYTE
lambdageek Aug 15, 2024
71dee34
fixup
lambdageek Aug 15, 2024
2fbc89e
Revert "fixup"
lambdageek Aug 15, 2024
2e3b938
Revert "suggestion from code review make m_IsCollectible a const BYTE"
lambdageek Aug 15, 2024
1776abe
move PrecodeStubs to a separate contract
lambdageek Aug 15, 2024
099b5fa
ExecutionManager contract
lambdageek Aug 15, 2024
50046b8
rename contract NativeCodePointers => CodeVersions
lambdageek Aug 15, 2024
e2d637b
ReJIT contract
lambdageek Aug 15, 2024
7724fa8
formatting, comments and whitespace
lambdageek Aug 16, 2024
a53b3ae
cleanup
lambdageek Aug 16, 2024
124ee6a
"NDirect" -> "PInvoke" in descriptor and contracts
lambdageek Aug 16, 2024
fb1676b
WIP: contract writeups
lambdageek Aug 16, 2024
f1d757e
fix build
lambdageek Aug 16, 2024
f1d7be8
placeholder ExecutionManager contract
lambdageek Aug 16, 2024
ebb4a67
placeholder ExecutionManager contract; updates to RTS and Loader
lambdageek Aug 16, 2024
aac3faf
refactor ExecutionManager
lambdageek Aug 19, 2024
ef51f0e
remove dead method from contract
lambdageek Aug 22, 2024
92764a2
fix typo
lambdageek Aug 22, 2024
4e1a620
Merge remote-tracking branch 'origin/main' into cdac-nativecodeptr
lambdageek Aug 22, 2024
037c349
Apply suggestions from code review
lambdageek Aug 23, 2024
25d8343
Add PrecodeStubs contract writeup
lambdageek Aug 23, 2024
ac0165a
Merge remote-tracking branch 'origin/main' into cdac-nativecodeptr
lambdageek Sep 10, 2024
8f5e98b
Merge remote-tracking branch 'origin/main' into cdac-nativecodeptr
lambdageek Sep 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions docs/design/datacontracts/CodeVersions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Contract CodeVersions

This contract encapsulates support for [code versioning](../features/code-versioning.md) in the runtime.

## APIs of contract

```csharp
internal struct NativeCodeVersionHandle
{
// no public constructors
internal readonly TargetPointer MethodDescAddress;
internal readonly TargetPointer CodeVersionNodeAddress;
internal NativeCodeVersionHandle(TargetPointer methodDescAddress, TargetPointer codeVersionNodeAddress)
{
if (methodDescAddress != TargetPointer.Null && codeVersionNodeAddress != TargetPointer.Null)
{
throw new ArgumentException("Only one of methodDescAddress and codeVersionNodeAddress can be non-null");
}
MethodDescAddress = methodDescAddress;
CodeVersionNodeAddress = codeVersionNodeAddress;
}

internal static NativeCodeVersionHandle Invalid => new(TargetPointer.Null, TargetPointer.Null);
public bool Valid => MethodDescAddress != TargetPointer.Null || CodeVersionNodeAddress != TargetPointer.Null;
}
```

```csharp
// Return a handle to the version of the native code that includes the given instruction pointer
public virtual NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip) => throw new NotImplementedException();
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
// Return a handle to the active version of the native code for a given method descriptor
public virtual NativeCodeVersionHandle GetActiveNativeCodeVersion(TargetPointer methodDesc) => throw new NotImplementedException();

// returns true if the given method descriptor supports multiple code versions
public virtual bool CodeVersionManagerSupportsMethod(TargetPointer methodDesc) => throw new NotImplementedException();

// Return the instruction pointer corresponding to the start of the given native code version
public virtual TargetCodePointer GetNativeCode(NativeCodeVersionHandle codeVersionHandle) => throw new NotImplementedException();
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| MethodDescVersioningState | ? | ? |
| NativeCodeVersionNode | ? | ? |
| ILCodeVersioningState | ? | ? |


Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |

Contracts used:
| Contract Name |
| --- |
| ExecutionManager |
| Loader |
| RuntimeTypeSystem |

### Finding the start of a specific native code version

```csharp
NativeCodeVersionHandle GetSpecificNativeCodeVersion(TargetCodePointer ip)
{
Contracts.IExecutionManager executionManager = _target.Contracts.ExecutionManager;
EECodeInfoHandle? info = executionManager.GetEECodeInfoHandle(ip);
if (!info.HasValue)
{
return NativeCodeVersionHandle.Invalid;
}
TargetPointer methodDescAddress = executionManager.GetMethodDesc(info.Value);
if (methodDescAddress == TargetPointer.Null)
{
return NativeCodeVersionHandle.Invalid;
}
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
MethodDescHandle md = rts.GetMethodDescHandle(methodDescAddress);
if (!rts.IsVersionable(md))
{
return new NativeCodeVersionHandle(methodDescAddress, codeVersionNodeAddress: TargetPointer.Null);
}
else
{
TargetCodePointer startAddress = executionManager.GetStartAddress(info.Value);
return GetSpecificNativeCodeVersion(md, startAddress);
}
}

private NativeCodeVersionHandle GetSpecificNativeCodeVersion(MethodDescHandle md, TargetCodePointer startAddress)
{
TargetPointer methodDescVersioningStateAddress = target.Contracts.RuntimeTypeSystem.GetMethodDescVersioningState(md);
if (methodDescVersioningStateAddress == TargetPointer.Null)
{
return NativeCodeVersionHandle.Invalid;
}
Data.MethodDescVersioningState methodDescVersioningStateData = _target.ProcessedData.GetOrAdd<Data.MethodDescVersioningState>(methodDescVersioningStateAddress);
// CodeVersionManager::GetNativeCodeVersion(PTR_MethodDesc, PCODE startAddress)
return FindFirstCodeVersion(methodDescVersioningStateData, (codeVersion) =>
{
return codeVersion.MethodDesc == md.Address && codeVersion.NativeCode == startAddress;
});
}

private NativeCodeVersionHandle FindFirstCodeVersion(Data.MethodDescVersioningState versioningState, Func<Data.NativeCodeVersionNode, bool> predicate)
{
// NativeCodeVersion::Next, heavily inlined
TargetPointer currentAddress = versioningState.NativeCodeVersionNode;
while (currentAddress != TargetPointer.Null)
{
Data.NativeCodeVersionNode current = _target.ProcessedData.GetOrAdd<Data.NativeCodeVersionNode>(currentAddress);
if (predicate(current))
{
return new NativeCodeVersionHandle(methodDescAddress: TargetPointer.Null, currentAddress);
}
currentAddress = current.Next;
}
return NativeCodeVersionHandle.Invalid;
}
```

### Finding the active native code version of a method descriptor

```csharp
NativeCodeVersionHandle ICodeVersions.GetActiveNativeCodeVersion(TargetPointer methodDesc)
{
// CodeVersionManager::GetActiveILCodeVersion
// then ILCodeVersion::GetActiveNativeCodeVersion
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
MethodDescHandle md = rts.GetMethodDescHandle(methodDesc);
TargetPointer mtAddr = rts.GetMethodTable(md);
TypeHandle typeHandle = rts.GetTypeHandle(mtAddr);
TargetPointer module = rts.GetModule(typeHandle);
uint methodDefToken = rts.GetMethodToken(md);
ILCodeVersionHandle methodDefActiveVersion = FindActiveILCodeVersion(module, methodDefToken);
if (!methodDefActiveVersion.IsValid)
{
return NativeCodeVersionHandle.Invalid;
}
return FindActiveNativeCodeVersion(methodDefActiveVersion, methodDesc);
}
```

**FIXME**

### Determining whether a method descriptor supports code versioning

**TODO**
57 changes: 57 additions & 0 deletions docs/design/datacontracts/ExecutionManager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Contract ExecutionManager

This contract


## APIs of contract

```csharp
internal struct EECodeInfoHandle
{
// no public constructor
public readonly TargetPointer Address;
internal EECodeInfoHandle(TargetPointer address) => Address = address;
}
```

```csharp
// Collect execution engine info for a code block that includes the given instruction pointer.
// Return a handle for the information, or null if an owning code block cannot be found.
EECodeInfoHandle? GetEECodeInfoHandle(TargetCodePointer ip);
// Get the method descriptor corresponding to the given code block
TargetPointer GetMethodDesc(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException();
// Get the instruction pointer address of the start of the code block
TargetCodePointer GetStartAddress(EECodeInfoHandle codeInfoHandle) => throw new NotImplementedException();
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| RangeSectionMap | TopLevelData | pointer to the outermost RangeSection |
| RangeSectionFragment| ? | ? |
| RangeSection | ? | ? |
| RealCodeHeader | ? | ? |
| HeapList | ? | ? |



Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
| ExecutionManagerCodeRangeMapAddress | TargetPointer | Pointer to the global RangeSectionMap
| StubCodeBlockLast | uint8 | Maximum sentinel code header value indentifying a stub code block

Contracts used:
| Contract Name |
| --- |

```csharp
```

**TODO** Methods

### NibbleMap

**TODO**
9 changes: 9 additions & 0 deletions docs/design/datacontracts/Loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ TargetPointer GetLoaderAllocator(ModuleHandle handle);
TargetPointer GetThunkHeap(ModuleHandle handle);
TargetPointer GetILBase(ModuleHandle handle);
ModuleLookupTables GetLookupTables(ModuleHandle handle);
TargetPointer GetModuleLookupMapElement(TargetPointer table, uint rid, out TargetNUInt flags);
bool IsCollectibleLoaderAllocator(ModuleHandle handle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll want to have a LoaderAllocator contract. There is a bunch of ... stuff... on there, and I feel like we'll likely need something there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this particular API (checking if the module is collectible), it seems like it should cut out the LoaderAllocator concept? Since once you're at the Module (instead of a MethodDesc), the module's IsCollectible should match the module's loader allocator's IsCollectible.


```

## Version 1
Expand All @@ -58,6 +61,10 @@ Data descriptors used:
| `Module` | `TypeDefToMethodTableMap` | Mapping table |
| `Module` | `TypeRefToMethodTableMap` | Mapping table |
| `ModuleLookupMap` | `TableData` | Start of the mapping table's data |
| `ModuleLookupMap` | `SupportedFlagsMask` | Mask for flag bits on lookup map entries |
| `ModuleLookupMap` | `Count` | Number of TargetPointer sized entries in this section of the map |
| `ModuleLookupMap` | `Next` | Pointer to next ModuleLookupMap segment for this map
| `LoaderAllocator` | `IsCollectible` | Flag indicating if this is loader allocator may be collected

``` csharp
ModuleHandle GetModuleHandle(TargetPointer modulePointer)
Expand Down Expand Up @@ -110,3 +117,5 @@ ModuleLookupTables GetLookupTables(ModuleHandle handle)
Module::MethodDefToILCodeVersioningState */));
}
```

**TODO* pseudocode for IsCollectibleLoaderAllocator and LookupTableMap element lookup
37 changes: 37 additions & 0 deletions docs/design/datacontracts/ReJIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Contract ReJIT

This contract encapsulates support for [ReJIT](../features/code-versioning.md) in the runtime.

## APIs of contract

```csharp
bool IsEnabled();
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| ProfControlBlock | GlobalEventMask | an `ICorProfiler` `COR_PRF_MONITOR` value |

Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
|ProfilerControlBlock | TargetPointer | pointer to the `ProfControlBlock` |

Contracts used:
| Contract Name |
| --- |

```csharp
bool IsEnabled()
{
TargetPointer address = target.ReadGlobalPointer("ProfilerControlBlock");
ulong globalEventMask = target.Read<ulong>(address + /* ProfControlBlock::GlobalEventMask offset*/);
bool profEnabledReJIT = (GlobalEventMask & (ulong)COR_PRF_MONITOR.COR_PRF_ENABLE_REJIT) != 0;
bool clrConfigEnabledReJit = /* host process does not have environment variable DOTNET_ProfAPI_ReJitOnAttach set to 0 */;
// See https://github.com/dotnet/runtime/issues/106148
return profEnabledReJIT || clrConfigEnabledReJIT;
}
```
34 changes: 33 additions & 1 deletion docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,28 @@ partial interface IRuntimeTypeSystem : IContract
// Return true if a MethodDesc represents an IL Stub dynamically generated by the runtime
// A IL Stub method is also a StoredSigMethodDesc, and a NoMetadataMethod
public virtual bool IsILStub(MethodDescHandle methodDesc);

// Return true if a MethodDesc is in a collectible module
public virtual bool IsCollectibleMethod(MethodDescHandle methodDesc);

// Return true if a MethodDesc supports mulitiple code versions
public virtual bool IsVersionable(MethodDescHandle methodDesc);

// Return a pointer to the IL versioning state of the MethodDesc
public virtual TargetPointer GetMethodDescVersioningState(MethodDescHandle methodDesc);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to need the ability to walk the list of IL versions, and Native code versions, and query various details about these things. This doesn't feel like the right api. Could you get it onto the CodeVersions contract?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This just extracts the address from the MethodDescCodeData. All the logic for working with the versioning state is in CodeVersions.

It's not that different from

  TargetPointer modAddr =  RuntimeTypeSystem.GetModule(TypeHandle th);
  ModuleHandle mod = Loader.GetModuleHandle(modAddr);

RTS gives you a pointer and Loader turns it into a handle that you can use for queries. Similarly RTS will give a pointer to the versioning state and CodeVersions will consume it in some manner.

Currently the versioning state is consumed entirely internally in the CodeVersions contract, but in the future it could be exposed via a handle or through some data API (see GetSpecificNativeCodeVersion and IsActiveNativeCodeVersion implementations)


// Return the MethodTable slot number of the MethodDesc
public virtual ushort GetSlotNumber(MethodDescHandle methodDesc);

// Return true if the MethodDesc has space associated with it for storing a pointer to a code block
public virtual bool HasNativeCodeSlot(MethodDescHandle methodDesc);

// Return the address of the space that stores a pointer to a code block associated with the MethodDesc
public virtual TargetPointer GetAddressOfNativeCodeSlot(MethodDescHandle methodDesc);

// Get an instruction pointer that can be called to cause the MethodDesc to be executed
public virtual TargetCodePointer GetNativeCode(MethodDescHandle methodDesc);

}
```

Expand Down Expand Up @@ -606,6 +628,7 @@ The version 1 `MethodDesc` APIs depend on the `MethodDescAlignment` global and t
| `MethodDescAlignment` | `MethodDescChunk` trailing data is allocated in multiples of this constant. The size (in bytes) of each `MethodDesc` (or subclass) instance is a multiple of this constant. |
| `MethodDescTokenRemainderBitCount` | Number of bits in the token remainder in `MethodDesc` |

**TODO** MethodDesc code pointers additions

In the runtime a `MethodDesc` implicitly belongs to a single `MethodDescChunk` and some common data is shared between method descriptors that belong to the same chunk. A single method table
will typically have multiple chunks. There are subkinds of MethodDescs at runtime of varying sizes (but the sizes must be mutliples of `MethodDescAlignment`) and each chunk contains method descriptors of the same size.
Expand All @@ -630,6 +653,15 @@ We depend on the following data descriptors:
| `StoredSigMethodDesc` | `ExtendedFlags` | Flags field for the `StoredSigMethodDesc` |
| `DynamicMethodDesc` | `MethodName` | Pointer to Null-terminated UTF8 string describing the Method desc |

**TODO** MethodDesc code pointers additions

The contract depends on the following other contracts

| Contract |
| --- |
| Loader |
| ReJIT |
| CodeVersions |

And the following enumeration definitions

Expand Down Expand Up @@ -820,4 +852,4 @@ And the various apis are implemented with the following algorithms
return ((DynamicMethodDescExtendedFlags)ExtendedFlags).HasFlag(DynamicMethodDescExtendedFlags.IsILStub);
}
```
**TODO(cdac)**
**TODO(cdac)** additional code pointers methods on MethodDesc
12 changes: 11 additions & 1 deletion src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,17 @@ HRESULT ClrDataAccess::GetMethodDescData(
_ASSERTE(methodDescData->wSlotNumber == mdDataLocal.wSlotNumber);
_ASSERTE(methodDescData->NativeCodeAddr == mdDataLocal.NativeCodeAddr);
_ASSERTE(methodDescData->AddressOfNativeCodeSlot == mdDataLocal.AddressOfNativeCodeSlot);
//TODO[cdac]: assert the rest of mdDataLocal contains the same info as methodDescData
_ASSERTE(methodDescData->MethodDescPtr == mdDataLocal.MethodDescPtr);
_ASSERTE(methodDescData->MethodTablePtr == mdDataLocal.MethodTablePtr);
_ASSERTE(methodDescData->ModulePtr == mdDataLocal.ModulePtr);
_ASSERTE(methodDescData->MDToken == mdDataLocal.MDToken);
_ASSERTE(methodDescData->GCInfo == mdDataLocal.GCInfo);
_ASSERTE(methodDescData->GCStressCodeCopy == mdDataLocal.GCStressCodeCopy);
_ASSERTE(methodDescData->managedDynamicMethodObject == mdDataLocal.managedDynamicMethodObject);
_ASSERTE(methodDescData->requestedIP == mdDataLocal.requestedIP);
// TODO[cdac]: cdacreader always returns 0 currently
_ASSERTE(methodDescData->cJittedRejitVersions == 0 || methodDescData->cJittedRejitVersions == mdDataLocal.cJittedRejitVersions);
// TODO[cdac]: compare rejitDataCurrent and rejitDataRequested, too
if (rgRevertedRejitData != NULL)
{
_ASSERTE (cNeededRevertedRejitDataLocal == *pcNeededRevertedRejitData);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/debug/runtimeinfo/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[contracts.jsonc]
indent_size = 2
4 changes: 4 additions & 0 deletions src/coreclr/debug/runtimeinfo/contracts.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
// cdac-build-tool can take multiple "-c contract_file" arguments
// so to conditionally include contracts, put additional contracts in a separate file
{
"CodeVersions": 1,
"DacStreams": 1,
"EcmaMetadata" : 1,
"Exception": 1,
"ExecutionManager": 1,
"Loader": 1,
"Object": 1,
"PrecodeStubs": 1,
"ReJIT": 1,
"RuntimeTypeSystem": 1,
"Thread": 1
}
Loading
Loading