-
Couldn't load subscription status.
- Fork 5.2k
[cdac] start of RuntimeTypeSystem contract; implement GetMethodTableData SOS method #103444
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
Merged
Merged
Changes from 58 commits
Commits
Show all changes
72 commits
Select commit
Hold shift + click to select a range
b98afa8
Implement GetThreadStoreData in cDAC
elinor-fung 890f9c6
Add placeholder for getting thread data
elinor-fung 41ba95c
Apply suggestions from code review
elinor-fung 29214f0
WIP: Metadata contract
lambdageek 8beced0
Merge remote-tracking branch 'elinor-fung/cdac-threadstore' into cdac…
lambdageek 5213286
fix build
lambdageek 622e01a
WIP: ValidateMethodTable
lambdageek e112416
DataCache.GetOrAdd
elinor-fung ae1eac9
wip
lambdageek 79ea0d4
Merge remote-tracking branch 'elinor-fung/cdac-threadstore' into cdac…
lambdageek 5c696da
checkpoint: ValidateWithPossibleAV
lambdageek 6eaf80f
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek 3a7808d
checkpoint EEClass from MethodTable
lambdageek 66e5476
checkpoint: ValidateMethodTablePointer
lambdageek 95914b8
cp: delegate from legacy dac
lambdageek 2b8fda3
add Metadata to runtime contract descriptor
lambdageek 5c7d2ac
checkpoint: more MethodTable fields
lambdageek 7be5c60
checkpoint GetMethodTableData implemented
lambdageek 30b7b26
checkpoint: same answer as legacy dac
lambdageek 187bcbe
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek f0d1fcb
new flags for statics
lambdageek c53db36
fix GCC build
lambdageek b70bb1d
WIP: opaque MethodTableHandle
lambdageek a65fd50
Add contract accessors for MethodTableHandle
lambdageek 6f844bf
fixup
lambdageek 76e0384
simplify FreeObjectMethodTable handling
lambdageek cdb7543
cleanup
lambdageek 78830ea
fixup
lambdageek fbbd45b
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek 32665b2
[dac] Return canonical MethodTable instead of EEClass
lambdageek acf8436
Delete unreferenced MethodTable flags
lambdageek f246c86
add Metadata contract doc; fixups
lambdageek 8409f3e
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek 08d069a
rename DacpMethodTableData:klass field
lambdageek 674655f
document GetMethodTableData string baseSize adjustment
lambdageek 2ae4625
Apply suggestions from code review
lambdageek e18a2be
fix typo
lambdageek 846e779
rename flag to ContainsGCPointers
lambdageek 383af83
[vm] rename ContainsPointers flag to ContainsGCPointers
lambdageek 0f8c7f1
code style suggestions from code review
lambdageek 7a337c1
BUGFIX: read DwFlags2 from the correct offset
lambdageek a7c8158
hide utility methods
lambdageek f4a3493
remove EEClass_1 struct
lambdageek 10624c7
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek 65cc531
rename data descriptor members to remove prefixes
lambdageek d526087
cleanup the contract docs
lambdageek 0a4112e
remove hungariant notation prefixes from data descriptors
lambdageek 1071ca4
DAC: always set wNumVirtuals and wNumVtableSlots to 0
lambdageek 6c5235c
Remove NumVirtuals and NumVtableSlots from Metadata.md
lambdageek 95b728a
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek 6573e14
"untrusted" -> "non-validated"
lambdageek 8596892
merge fixup
lambdageek 6eabf42
remove #if 0
lambdageek 4d3200d
cleanup
lambdageek 2e66740
pull test target helpers out
lambdageek 8533148
Add one FreeObjectMethodTable unit test
lambdageek 77cf405
clean up the test helpers a bit
lambdageek f9bce4c
validate that a mock system object is a valid method table
lambdageek 3721992
code review feedback and more tests:
lambdageek 1af7c80
Update src/coreclr/gc/env/gcenv.object.h
lambdageek 993ae1d
Update src/native/managed/cdacreader/src/Contracts/Metadata_1.MethodT…
lambdageek f04d880
Address code review feedback
lambdageek 76859d1
move non-validated MethodTable handling to a separate class
lambdageek a12a407
clear up ComponentSize contract spec and impl
lambdageek 9cf4c5a
rename Metadata -> RuntimeTypeSystem
lambdageek 1814848
add validation failure test; change validation to throw InvalidOperat…
lambdageek 89f98a3
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek a0989fa
Update src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_…
lambdageek 617bf62
spellcheck
lambdageek 815ff0d
Merge branch 'cdac-wip' of github.com:lambdageek/runtime into cdac-wip
lambdageek 1ab4f08
Add a generic instance test
lambdageek ee3a362
add array instance test
lambdageek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,217 @@ | ||
| # Contract Metadata | ||
|
|
||
| This contract is for exploring the properties of the metadata of values on the heap or on the stack in a .NET process. | ||
|
|
||
| ## APIs of contract | ||
|
|
||
| A `MethodTable` is the runtime representation of the type information about a value. Given a `TargetPointer` address, the `Metadata` contract provides a `MethodTableHandle` for querying the `MethodTable`. | ||
|
|
||
| ``` csharp | ||
| struct MethodTableHandle | ||
| { | ||
| // no public properties or constructors | ||
|
|
||
| internal TargetPointer Address { get; } | ||
| } | ||
| ``` | ||
|
|
||
| ``` csharp | ||
| #region MethodTable inspection APIs | ||
| public virtual MethodTableHandle GetMethodTableHandle(TargetPointer targetPointer); | ||
|
|
||
| public virtual TargetPointer GetModule(MethodTableHandle methodTable); | ||
| // A canonical method table is either the MethodTable itself, or in the case of a generic instantiation, it is the | ||
| // MethodTable of the prototypical instance. | ||
| public virtual TargetPointer GetCanonicalMethodTable(MethodTableHandle methodTable); | ||
| public virtual TargetPointer GetParentMethodTable(MethodTableHandle methodTable); | ||
|
|
||
| public virtual uint GetBaseSize(MethodTableHandle methodTable); | ||
| // The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes) | ||
| public virtual uint GetComponentSize(MethodTableHandle methodTable); | ||
|
|
||
| // True if the MethodTable is the sentinel value associated with unallocated space in the managed heap | ||
| public virtual bool IsFreeObjectMethodTable(MethodTableHandle methodTable); | ||
| public virtual bool IsString(MethodTableHandle methodTable); | ||
| // True if the MethodTable represents a type that contains managed references | ||
| public virtual bool ContainsGCPointers(MethodTableHandle methodTable); | ||
| public virtual bool IsDynamicStatics(MethodTableHandle methodTable); | ||
| public virtual ushort GetNumMethods(MethodTableHandle methodTable); | ||
| public virtual ushort GetNumInterfaces(MethodTableHandle methodTable); | ||
|
|
||
| // Returns an ECMA-335 TypeDef table token for this type, or for its generic type definition if it is a generic instantiation | ||
| public virtual uint GetTypeDefToken(MethodTableHandle methodTable); | ||
| // Returns the ECMA 335 TypeDef table Flags value (a bitmask of TypeAttributes) for this type, | ||
| // or for its generic type definition if it is a generic instantiation | ||
| public virtual uint GetTypeDefTypeAttributes(MethodTableHandle methodTable); | ||
| #endregion MethodTable inspection APIs | ||
| ``` | ||
|
|
||
| ## Version 1 | ||
|
|
||
| The `MethodTable` inspection APIs are implemented in terms of the following flags on the runtime `MethodTable` structure: | ||
|
|
||
| ``` csharp | ||
| internal partial struct Metadata_1 | ||
| { | ||
| [Flags] | ||
AaronRobinsonMSFT marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| internal enum WFLAGS_LOW : uint | ||
| { | ||
| GenericsMask = 0x00000030, | ||
| GenericsMask_NonGeneric = 0x00000000, // no instantiation | ||
|
|
||
| StringArrayValues = GenericsMask_NonGeneric, | ||
| } | ||
|
|
||
| [Flags] | ||
| internal enum WFLAGS_HIGH : uint | ||
| { | ||
| Category_Mask = 0x000F0000, | ||
| Category_Array = 0x00080000, | ||
| Category_Array_Mask = 0x000C0000, | ||
| Category_Interface = 0x000C0000, | ||
| ContainsPointers = 0x01000000, // Contains object references | ||
| HasComponentSize = 0x80000000, // This is set if component size is used for flags. | ||
| } | ||
|
|
||
| [Flags] | ||
| internal enum WFLAGS2_ENUM : uint | ||
| { | ||
| DynamicStatics = 0x0002, | ||
| } | ||
|
|
||
| // Encapsulates the MethodTable flags v1 uses | ||
| internal struct MethodTableFlags | ||
lambdageek marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| public WFLAGS_LOW GetFlag(WFLAGS_LOW mask) { ... } | ||
| public WFLAGS_HIGH GetFlag(WFLAGS_HIGH mask) { ... } | ||
|
|
||
| public WFLAGS2_ENUM GetFlag(WFLAGS2_ENUM mask) { ... } | ||
| public bool IsInterface => GetFlag(WFLAGS_HIGH.Category_Mask) == WFLAGS_HIGH.Category_Interface; | ||
| public bool IsString => HasComponentSize && !IsArray && RawGetComponentSize() == 2; | ||
|
|
||
| public bool HasComponentSize => GetFlag(WFLAGS_HIGH.HasComponentSize) != 0; | ||
|
|
||
| public bool IsArray => GetFlag(WFLAGS_HIGH.Category_Array_Mask) == WFLAGS_HIGH.Category_Array; | ||
|
|
||
| public bool IsStringOrArray => HasComponentSize; | ||
| public ushort RawGetComponentSize() => (ushort)(MTFlags >> 16); | ||
lambdageek marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| private bool TestFlagWithMask(WFLAGS_LOW mask, WFLAGS_LOW flag) | ||
| { | ||
| if (IsStringOrArray) | ||
| { | ||
| return (WFLAGS_LOW.StringArrayValues & mask) == flag; | ||
| } | ||
| else | ||
| { | ||
| return (FlagsLow & mask) == flag; | ||
| } | ||
| } | ||
|
|
||
| public bool HasInstantiation => !TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_NonGeneric); | ||
|
|
||
| public bool ContainsGCPointers => GetFlag(WFLAGS_HIGH.ContainsGCPointers) != 0; | ||
| } | ||
|
|
||
| [Flags] | ||
| internal enum EEClassOrCanonMTBits | ||
| { | ||
| EEClass = 0, | ||
| CanonMT = 1, | ||
| Mask = 1, | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Internally the contract has a `MethodTable_1` struct that depends on the `MethodTable` data descriptor | ||
|
|
||
| ```csharp | ||
| internal struct MethodTable_1 | ||
| { | ||
| internal Metadata_1.MethodTableFlags Flags { get; } | ||
| internal ushort NumInterfaces { get; } | ||
| internal ushort NumVirtuals { get; } | ||
| internal TargetPointer ParentMethodTable { get; } | ||
| internal TargetPointer Module { get; } | ||
| internal TargetPointer EEClassOrCanonMT { get; } | ||
| internal MethodTable_1(Data.MethodTable data) | ||
| { | ||
| Flags = new Metadata_1.MethodTableFlags | ||
| { | ||
| MTFlags = data.MTFlags, | ||
| MTFlags2 = data.MTFlags2, | ||
| BaseSize = data.BaseSize, | ||
| }; | ||
| NumInterfaces = data.NumInterfaces; | ||
| NumVirtuals = data.NumVirtuals; | ||
| EEClassOrCanonMT = data.EEClassOrCanonMT; | ||
| Module = data.Module; | ||
| ParentMethodTable = data.ParentMethodTable; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The contract depends on the global pointer value `FreeObjectMethodTablePointer`. | ||
| The contract additionally depends on the `EEClass` data descriptor. | ||
|
|
||
| ```csharp | ||
| private readonly Dictionary<TargetPointer, MethodTable_1> _methodTables; | ||
|
|
||
| internal TargetPointer FreeObjectMethodTablePointer {get; } | ||
|
|
||
| public MethodTableHandle GetMethodTableHandle(TargetPointer methodTablePointer) | ||
| { | ||
| ... // validate that methodTablePointer points to something that looks like a MethodTable. | ||
| ... // read Data.MethodTable from methodTablePointer. | ||
| ... // create a MethodTable_1 and add it to _methodTables. | ||
| return MethodTableHandle { Address = methodTablePointer } | ||
| } | ||
|
|
||
| internal static EEClassOrCanonMTBits GetEEClassOrCanonMTBits(TargetPointer eeClassOrCanonMTPtr) | ||
| { | ||
| return (EEClassOrCanonMTBits)(eeClassOrCanonMTPtr & (ulong)EEClassOrCanonMTBits.Mask); | ||
| } | ||
|
|
||
| public uint GetBaseSize(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].Flags.BaseSize; | ||
|
|
||
| public uint GetComponentSize(MethodTableHandle methodTableHandle) => GetComponentSize(_methodTables[methodTableHandle.Address]); | ||
|
|
||
| private TargetPointer GetClassPointer(MethodTableHandle methodTableHandle) | ||
| { | ||
| ... // if the MethodTable stores a pointer to the EEClass, return it | ||
| // otherwise the MethodTable stores a pointer to the canonical MethodTable | ||
| // in that case, return the canonical MethodTable's EEClass. | ||
| // Canonical MethodTables always store an EEClass pointer. | ||
| } | ||
|
|
||
| private Data.EEClass GetClassData(MethodTableHandle methodTableHandle) | ||
| { | ||
| TargetPointer eeClassPtr = GetClassPointer(methodTableHandle); | ||
| ... // read Data.EEClass data from eeClassPtr | ||
| } | ||
|
|
||
|
|
||
| public TargetPointer GetCanonicalMethodTable(MethodTableHandle methodTableHandle) => GetClassData(methodTableHandle).MethodTable; | ||
|
|
||
| public TargetPointer GetModule(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].Module; | ||
| public TargetPointer GetParentMethodTable(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].ParentMethodTable; | ||
|
|
||
| public bool IsFreeObjectMethodTable(MethodTableHandle methodTableHandle) => FreeObjectMethodTablePointer == methodTableHandle.Address; | ||
|
|
||
| public bool IsString(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].Flags.IsString; | ||
| public bool ContainsPointers(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].Flags.ContainsPointers; | ||
|
|
||
| public uint GetTypeDefToken(MethodTableHandle methodTableHandle) | ||
| { | ||
| MethodTable_1 methodTable = _methodTables[methodTableHandle.Address]; | ||
| return (uint)(methodTable.Flags.GetTypeDefRid() | ((int)TableIndex.TypeDef << 24)); | ||
| } | ||
|
|
||
| public ushort GetNumMethods(MethodTableHandle methodTableHandle) => GetClassData(methodTableHandle).NumMethods; | ||
|
|
||
| public ushort GetNumInterfaces(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].NumInterfaces; | ||
|
|
||
| public uint GetTypeDefTypeAttributes(MethodTableHandle methodTableHandle) => GetClassData(methodTableHandle).AttrClass; | ||
|
|
||
| public bool IsDynamicStatics(MethodTableHandle methodTableHandle) => _methodTables[methodTableHandle.Address].Flags.GetFlag(WFLAGS2_ENUM.DynamicStatics) != 0; | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.