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] Handle no method def token when trying to get the IL version state #110449

Merged
merged 3 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ internal interface IRuntimeTypeSystem : IContract
#region TypeHandle inspection APIs
public virtual TypeHandle GetTypeHandle(TargetPointer address) => throw new NotImplementedException();
public virtual TargetPointer GetModule(TypeHandle typeHandle) => throw new NotImplementedException();

// 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(TypeHandle typeHandle) => throw new NotImplementedException();
Expand Down Expand Up @@ -130,7 +131,7 @@ internal interface IRuntimeTypeSystem : IContract
public virtual bool IsGenericMethodDefinition(MethodDescHandle methodDesc) => throw new NotImplementedException();
public virtual ReadOnlySpan<TypeHandle> GetGenericMethodInstantiation(MethodDescHandle methodDesc) => throw new NotImplementedException();

// Return mdTokenNil (0x06000000) if the method doesn't have a token, otherwise return the token of the method
// Return mdtMethodDef (0x06000000) if the method doesn't have a token, otherwise return the token of the method
public virtual uint GetMethodToken(MethodDescHandle methodDesc) => throw new NotImplementedException();

// Return true if a MethodDesc represents an array method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ internal static class Globals
internal const string HashMapSlotsPerBucket = nameof(HashMapSlotsPerBucket);
internal const string HashMapValueMask = nameof(HashMapValueMask);
}

internal enum CorTokenType : uint
{
mdtMethodDef = 0x06000000
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ ILCodeVersionHandle ICodeVersions.GetActiveILCodeVersion(TargetPointer methodDes

ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module);
TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState;
TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _);
TargetPointer ilVersionStateAddress = methodDefToken == (uint)Constants.CorTokenType.mdtMethodDef
? TargetPointer.Null // no token - for example, special runtime methods like array methods
: _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _);
if (ilVersionStateAddress == TargetPointer.Null)
{
return ILCodeVersionHandle.CreateSynthetic(module, methodDefToken);
Expand Down Expand Up @@ -75,7 +77,9 @@ IEnumerable<ILCodeVersionHandle> ICodeVersions.GetILCodeVersions(TargetPointer m

ModuleHandle moduleHandle = _target.Contracts.Loader.GetModuleHandle(module);
TargetPointer ilCodeVersionTable = _target.Contracts.Loader.GetLookupTables(moduleHandle).MethodDefToILCodeVersioningState;
TargetPointer ilVersionStateAddress = _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _);
TargetPointer ilVersionStateAddress = methodDefToken == (uint)Constants.CorTokenType.mdtMethodDef
? TargetPointer.Null // no token - for example, special runtime methods like array methods
: _target.Contracts.Loader.GetModuleLookupMapElement(ilCodeVersionTable, methodDefToken, out var _);
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved

// always add the synthetic version
yield return ILCodeVersionHandle.CreateSynthetic(module, methodDefToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly Dictionary<TargetPointer, MethodTable> _methodTables = new();
private readonly Dictionary<TargetPointer, MethodDesc> _methodDescs = new();


internal struct MethodTable
{
internal MethodTableFlags_1 Flags { get; }
Expand Down Expand Up @@ -127,7 +126,7 @@ private static uint ComputeToken(Target target, Data.MethodDesc desc, Data.Metho
uint tokenRemainder = (uint)(desc.Flags3AndTokenRemainder & tokenRemainderMask);
uint tokenRange = ((uint)(chunk.FlagsAndTokenRange & tokenRangeMask)) << tokenRemainderBitCount;

return 0x06000000 | tokenRange | tokenRemainder;
return (uint)Constants.CorTokenType.mdtMethodDef | tokenRange | tokenRemainder;
elinor-fung marked this conversation as resolved.
Show resolved Hide resolved
}

public MethodClassification Classification => (MethodClassification)((int)_desc.Flags & (int)MethodDescFlags_1.MethodDescFlags.ClassificationMask);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ internal static class EcmaMetadataUtils
internal static uint GetRowId(uint token) => token & RIDMask;

internal static uint MakeToken(uint rid, uint table) => rid | (table << RowIdBitCount);

}
42 changes: 27 additions & 15 deletions src/native/managed/cdacreader/tests/CodeVersionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal class MockMethodDesc
public bool IsVersionable { get; private set; }

public uint RowId { get; set; }
public uint MethodToken => 0x06000000 | RowId;
public uint MethodToken => (uint)Constants.CorTokenType.mdtMethodDef | RowId;

// n.b. in the real RuntimeTypeSystem_1 this is more complex
public TargetCodePointer NativeCode { get; private set; }
Expand Down Expand Up @@ -342,9 +342,10 @@ public void GetActiveNativeCodeVersion_DefaultCase(MockTarget.Architecture arch)
{
uint methodRowId = 0x25; // arbitrary
TargetCodePointer expectedNativeCodePointer = new TargetCodePointer(0x0700_abc0);
uint methodDefToken = 0x06000000 | methodRowId;
uint methodDefToken = (uint)Constants.CorTokenType.mdtMethodDef | methodRowId;
var builder = new MockCodeVersions(arch);
var methodDescAddress = new TargetPointer(0x00aa_aa00);
var methodDescNilTokenAddress = new TargetPointer(0x00aa_bb00);
var moduleAddress = new TargetPointer(0x00ca_ca00);

TargetPointer versioningState = builder.AddILCodeVersioningState(
Expand All @@ -353,34 +354,45 @@ public void GetActiveNativeCodeVersion_DefaultCase(MockTarget.Architecture arch)
activeVersionModule: moduleAddress,
activeVersionMethodDef: methodDefToken,
firstVersionNode: TargetPointer.Null);
var oneModule = new MockModule() {
var module = new MockModule() {
Address = moduleAddress,
MethodDefToILCodeVersioningStateAddress = new TargetPointer(0x00da_da00),
MethodDefToILCodeVersioningStateTable = new Dictionary<uint, TargetPointer>() {
{ methodRowId, versioningState}
},
};
var oneMethodTable = new MockMethodTable() {
var methodTable = new MockMethodTable() {
Address = new TargetPointer(0x00ba_ba00),
Module = oneModule,
Module = module,
};
var oneMethod = MockMethodDesc.CreateVersionable(selfAddress: methodDescAddress, methodDescVersioningState: TargetPointer.Null, nativeCode: expectedNativeCodePointer);
oneMethod.MethodTable = oneMethodTable;
oneMethod.RowId = methodRowId;
var method = MockMethodDesc.CreateVersionable(selfAddress: methodDescAddress, methodDescVersioningState: TargetPointer.Null, nativeCode: expectedNativeCodePointer);
method.MethodTable = methodTable;
method.RowId = methodRowId;

var methodNilToken = MockMethodDesc.CreateVersionable(selfAddress: methodDescNilTokenAddress, methodDescVersioningState: TargetPointer.Null, nativeCode: expectedNativeCodePointer);
methodNilToken.MethodTable = methodTable;

var target = CreateTarget(arch, [oneMethod], [oneMethodTable], [], [oneModule], builder);
var target = CreateTarget(arch, [method, methodNilToken], [methodTable], [], [module], builder);

// TEST

var codeVersions = target.Contracts.CodeVersions;

Assert.NotNull(codeVersions);

NativeCodeVersionHandle handle = codeVersions.GetActiveNativeCodeVersion(methodDescAddress);
Assert.True(handle.Valid);
Assert.Equal(methodDescAddress, handle.MethodDescAddress);
var actualCodeAddress = codeVersions.GetNativeCode(handle);
Assert.Equal(expectedNativeCodePointer, actualCodeAddress);
{
NativeCodeVersionHandle handle = codeVersions.GetActiveNativeCodeVersion(methodDescAddress);
Assert.True(handle.Valid);
Assert.Equal(methodDescAddress, handle.MethodDescAddress);
var actualCodeAddress = codeVersions.GetNativeCode(handle);
Assert.Equal(expectedNativeCodePointer, actualCodeAddress);
}
{
NativeCodeVersionHandle handle = codeVersions.GetActiveNativeCodeVersion(methodDescNilTokenAddress);
Assert.True(handle.Valid);
Assert.Equal(methodDescNilTokenAddress, handle.MethodDescAddress);
var actualCodeAddress = codeVersions.GetNativeCode(handle);
Assert.Equal(expectedNativeCodePointer, actualCodeAddress);
}
}

[Theory]
Expand Down
Loading