Skip to content

Commit 90dfc04

Browse files
authored
[cdac] Handle non-IL method descs in RuntimeTypeSystem_1.GetMethodClassificationDataType (#110602)
- Add the different method desc types to the data descriptor - We only need their size right now - Add tests for different method desc classifications - Mostly fill-in for things I found we didn't cover - `GetNativeCode_StableEntryPoint_NonVtableSlot` is the one that actually hits the updated code in this change
1 parent c05dbb6 commit 90dfc04

File tree

7 files changed

+355
-18
lines changed

7 files changed

+355
-18
lines changed

src/coreclr/debug/runtimeinfo/datadescriptor.h

+22
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,28 @@ CDAC_TYPE_SIZE(sizeof(DynamicMethodDesc))
373373
CDAC_TYPE_FIELD(DynamicMethodDesc, /*pointer*/, MethodName, cdac_data<DynamicMethodDesc>::MethodName)
374374
CDAC_TYPE_END(DynamicMethodDesc)
375375

376+
CDAC_TYPE_BEGIN(ArrayMethodDesc)
377+
CDAC_TYPE_SIZE(sizeof(ArrayMethodDesc))
378+
CDAC_TYPE_END(ArrayMethodDesc)
379+
380+
CDAC_TYPE_BEGIN(FCallMethodDesc)
381+
CDAC_TYPE_SIZE(sizeof(FCallMethodDesc))
382+
CDAC_TYPE_END(FCallMethodDesc)
383+
384+
CDAC_TYPE_BEGIN(PInvokeMethodDesc)
385+
CDAC_TYPE_SIZE(sizeof(NDirectMethodDesc))
386+
CDAC_TYPE_END(PInvokeMethodDesc)
387+
388+
CDAC_TYPE_BEGIN(EEImplMethodDesc)
389+
CDAC_TYPE_SIZE(sizeof(EEImplMethodDesc))
390+
CDAC_TYPE_END(EEImplMethodDesc)
391+
392+
#ifdef FEATURE_COMINTEROP
393+
CDAC_TYPE_BEGIN(CLRToCOMCallMethodDesc)
394+
CDAC_TYPE_SIZE(sizeof(CLRToCOMCallMethodDesc))
395+
CDAC_TYPE_END(CLRToCOMCallMethodDesc)
396+
#endif // FEATURE_COMINTEROP
397+
376398
CDAC_TYPE_BEGIN(CodePointer)
377399
CDAC_TYPE_SIZE(sizeof(PCODE))
378400
CDAC_TYPE_END(CodePointer)

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Abstractions/DataType.cs

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ public enum DataType
5757
InstantiatedMethodDesc,
5858
DynamicMethodDesc,
5959
StoredSigMethodDesc,
60+
ArrayMethodDesc,
61+
FCallMethodDesc,
62+
PInvokeMethodDesc,
63+
EEImplMethodDesc,
64+
CLRToCOMCallMethodDesc,
6065
RangeSectionMap,
6166
RangeSectionFragment,
6267
RangeSection,

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodClassification.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers;
66

7+
// See MethodClassification in src/coreclr/vm/method.hpp
78
internal enum MethodClassification
89
{
910
IL = 0, // IL
@@ -12,7 +13,7 @@ internal enum MethodClassification
1213
EEImpl = 3, // special method; implementation provided by EE (like Delegate Invoke)
1314
Array = 4, // Array ECall
1415
Instantiated = 5, // Instantiated generic methods, including descriptors
15-
// for both shared and unshared code (see InstantiatedMethodDesc)
16+
// for both shared and unshared code (see InstantiatedMethodDesc)
1617
ComInterop = 6,
1718
Dynamic = 7, // for method desc with no metadata behind
1819
}

src/native/managed/cdacreader/Microsoft.Diagnostics.DataContractReader.Contracts/RuntimeTypeSystemHelpers/MethodDescOptionalSlots.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ private static uint StartOffset(MethodClassification classification, Target targ
4646
DataType type = classification switch
4747
{
4848
MethodClassification.IL => DataType.MethodDesc,
49-
MethodClassification.FCall => throw new NotImplementedException(), //TODO[cdac]:
50-
MethodClassification.PInvoke => throw new NotImplementedException(), //TODO[cdac]:
51-
MethodClassification.EEImpl => throw new NotImplementedException(), //TODO[cdac]:
52-
MethodClassification.Array => throw new NotImplementedException(), //TODO[cdac]:
49+
MethodClassification.FCall => DataType.FCallMethodDesc,
50+
MethodClassification.PInvoke => DataType.PInvokeMethodDesc,
51+
MethodClassification.EEImpl => DataType.EEImplMethodDesc,
52+
MethodClassification.Array => DataType.ArrayMethodDesc,
5353
MethodClassification.Instantiated => DataType.InstantiatedMethodDesc,
54-
MethodClassification.ComInterop => throw new NotImplementedException(), //TODO[cdac]:
54+
MethodClassification.ComInterop => DataType.CLRToCOMCallMethodDesc,
5555
MethodClassification.Dynamic => DataType.DynamicMethodDesc,
5656
_ => throw new InvalidOperationException($"Unexpected method classification 0x{classification:x2} for MethodDesc")
5757
};

src/native/managed/cdacreader/tests/MethodDescTests.cs

+246-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
6+
using System.Linq;
57
using Microsoft.Diagnostics.DataContractReader.Contracts;
68
using Microsoft.Diagnostics.DataContractReader.RuntimeTypeSystemHelpers;
79
using Moq;
@@ -11,20 +13,23 @@ namespace Microsoft.Diagnostics.DataContractReader.Tests;
1113

1214
public class MethodDescTests
1315
{
14-
private static Target CreateTarget(MockDescriptors.MethodDescriptors methodDescBuilder)
16+
private static Target CreateTarget(MockDescriptors.MethodDescriptors methodDescBuilder, Mock<IExecutionManager> mockExecutionManager = null)
1517
{
1618
MockMemorySpace.Builder builder = methodDescBuilder.Builder;
1719
var target = new TestPlaceholderTarget(builder.TargetTestHelpers.Arch, builder.GetReadContext().ReadFromTarget, methodDescBuilder.Types, methodDescBuilder.Globals);
20+
21+
mockExecutionManager ??= new Mock<IExecutionManager>();
1822
target.SetContracts(Mock.Of<ContractRegistry>(
1923
c => c.RuntimeTypeSystem == ((IContractFactory<IRuntimeTypeSystem>)new RuntimeTypeSystemFactory()).CreateContract(target, 1)
2024
&& c.Loader == ((IContractFactory<ILoader>)new LoaderFactory()).CreateContract(target, 1)
21-
&& c.PlatformMetadata == new Mock<Contracts.IPlatformMetadata>().Object));
25+
&& c.PlatformMetadata == new Mock<IPlatformMetadata>().Object
26+
&& c.ExecutionManager == mockExecutionManager.Object));
2227
return target;
2328
}
2429

2530
[Theory]
2631
[ClassData(typeof(MockTarget.StdArch))]
27-
public void MethodDescGetMethodDescTokenOk(MockTarget.Architecture arch)
32+
public void GetMethodDescHandle_ILMethod_GetBasicData(MockTarget.Architecture arch)
2833
{
2934
TargetTestHelpers helpers = new(arch);
3035
MockMemorySpace.Builder builder = new(helpers);
@@ -69,6 +74,163 @@ public void MethodDescGetMethodDescTokenOk(MockTarget.Architecture arch)
6974
Assert.False(isCollectible);
7075
TargetPointer versioning = rts.GetMethodDescVersioningState(handle);
7176
Assert.Equal(TargetPointer.Null, versioning);
77+
78+
// Method classification - IL method
79+
Assert.False(rts.IsStoredSigMethodDesc(handle, out _));
80+
Assert.False(rts.IsNoMetadataMethod(handle, out _));
81+
Assert.False(rts.IsDynamicMethod(handle));
82+
Assert.False(rts.IsILStub(handle));
83+
Assert.False(rts.IsArrayMethod(handle, out _));
84+
}
85+
86+
[Theory]
87+
[ClassData(typeof(MockTarget.StdArch))]
88+
public void IsArrayMethod(MockTarget.Architecture arch)
89+
{
90+
TargetTestHelpers helpers = new(arch);
91+
MockMemorySpace.Builder builder = new(helpers);
92+
MockDescriptors.RuntimeTypeSystem rtsBuilder = new(builder);
93+
MockDescriptors.Loader loaderBuilder = new(builder);
94+
MockDescriptors.MethodDescriptors methodDescBuilder = new(rtsBuilder, loaderBuilder);
95+
96+
ushort numVirtuals = 1;
97+
TargetPointer methodTable = AddMethodTable(rtsBuilder, numVirtuals);
98+
99+
byte count = 5;
100+
uint methodDescSize = methodDescBuilder.Types[DataType.ArrayMethodDesc].Size.Value;
101+
uint methodDescSizeByAlignment = methodDescSize / methodDescBuilder.MethodDescAlignment;
102+
byte chunkSize = (byte)(count * methodDescSizeByAlignment);
103+
TargetPointer chunk = methodDescBuilder.AddMethodDescChunk(methodTable, string.Empty, count, chunkSize, tokenRange: 0);
104+
105+
TargetPointer[] arrayMethods = new TargetPointer[count];
106+
for (byte i = 0; i < count; i++)
107+
{
108+
// Add the array methods by setting the appropriate slot number
109+
// Array vtable is:
110+
// <base class vtables>
111+
// Get
112+
// Set
113+
// Address
114+
// .ctor
115+
// [optionally other constructors]
116+
byte index = (byte)(i * methodDescSizeByAlignment);
117+
ushort slotNum = (ushort)(numVirtuals + i);
118+
ushort flags = (ushort)MethodClassification.Array | (ushort)MethodDescFlags_1.MethodDescFlags.HasNonVtableSlot;
119+
arrayMethods[i] = methodDescBuilder.SetMethodDesc(chunk, index, slotNum, flags, tokenRemainder: 0);
120+
}
121+
122+
Target target = CreateTarget(methodDescBuilder);
123+
IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
124+
125+
for (byte i = 0; i < count; i++)
126+
{
127+
MethodDescHandle handle = rts.GetMethodDescHandle(arrayMethods[i]);
128+
Assert.NotEqual(TargetPointer.Null, handle.Address);
129+
Assert.True(rts.IsStoredSigMethodDesc(handle, out _));
130+
Assert.True(rts.IsArrayMethod(handle, out ArrayFunctionType functionType));
131+
132+
ArrayFunctionType expectedFunctionType = i <= (byte)ArrayFunctionType.Constructor
133+
? (ArrayFunctionType)i
134+
: ArrayFunctionType.Constructor;
135+
Assert.Equal(expectedFunctionType, functionType);
136+
}
137+
}
138+
139+
[Theory]
140+
[ClassData(typeof(MockTarget.StdArch))]
141+
public void IsDynamicMethod(MockTarget.Architecture arch)
142+
{
143+
TargetTestHelpers helpers = new(arch);
144+
MockMemorySpace.Builder builder = new(helpers);
145+
MockDescriptors.RuntimeTypeSystem rtsBuilder = new(builder);
146+
MockDescriptors.Loader loaderBuilder = new(builder);
147+
MockDescriptors.MethodDescriptors methodDescBuilder = new(rtsBuilder, loaderBuilder);
148+
149+
TargetPointer methodTable = AddMethodTable(rtsBuilder);
150+
151+
byte count = 2;
152+
uint methodDescSize = methodDescBuilder.Types[DataType.DynamicMethodDesc].Size.Value;
153+
uint methodDescSizeByAlignment = methodDescSize / methodDescBuilder.MethodDescAlignment;
154+
byte chunkSize = (byte)(count * methodDescSizeByAlignment);
155+
TargetPointer chunk = methodDescBuilder.AddMethodDescChunk(methodTable, string.Empty, count, chunkSize, tokenRange: 0);
156+
157+
ushort flags = (ushort)MethodClassification.Dynamic;
158+
TargetPointer dynamicMethod = methodDescBuilder.SetMethodDesc(chunk, index: 0, slotNum: 0, flags, tokenRemainder: 0);
159+
methodDescBuilder.SetDynamicMethodDesc(dynamicMethod, (uint)RuntimeTypeSystem_1.DynamicMethodDescExtendedFlags.IsLCGMethod);
160+
TargetPointer ilStubMethod = methodDescBuilder.SetMethodDesc(chunk, index: (byte)methodDescSizeByAlignment, slotNum: 1, flags, tokenRemainder: 0);
161+
methodDescBuilder.SetDynamicMethodDesc(ilStubMethod, (uint)RuntimeTypeSystem_1.DynamicMethodDescExtendedFlags.IsILStub);
162+
163+
Target target = CreateTarget(methodDescBuilder);
164+
IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
165+
166+
{
167+
MethodDescHandle handle = rts.GetMethodDescHandle(dynamicMethod);
168+
Assert.NotEqual(TargetPointer.Null, handle.Address);
169+
Assert.True(rts.IsStoredSigMethodDesc(handle, out _));
170+
Assert.True(rts.IsNoMetadataMethod(handle, out _));
171+
Assert.True(rts.IsDynamicMethod(handle));
172+
Assert.False(rts.IsILStub(handle));
173+
}
174+
{
175+
MethodDescHandle handle = rts.GetMethodDescHandle(ilStubMethod);
176+
Assert.NotEqual(TargetPointer.Null, handle.Address);
177+
Assert.True(rts.IsStoredSigMethodDesc(handle, out _));
178+
Assert.True(rts.IsNoMetadataMethod(handle, out _));
179+
Assert.False(rts.IsDynamicMethod(handle));
180+
Assert.True(rts.IsILStub(handle));
181+
}
182+
}
183+
184+
[Theory]
185+
[ClassData(typeof(MockTarget.StdArch))]
186+
public void IsGenericMethodDefinition(MockTarget.Architecture arch)
187+
{
188+
TargetTestHelpers helpers = new(arch);
189+
MockMemorySpace.Builder builder = new(helpers);
190+
MockDescriptors.RuntimeTypeSystem rtsBuilder = new(builder);
191+
MockDescriptors.Loader loaderBuilder = new(builder);
192+
MockDescriptors.MethodDescriptors methodDescBuilder = new(rtsBuilder, loaderBuilder);
193+
194+
TargetPointer methodTable = AddMethodTable(rtsBuilder);
195+
196+
byte count = 2;
197+
uint methodDescSize = methodDescBuilder.Types[DataType.InstantiatedMethodDesc].Size.Value;
198+
uint methodDescSizeByAlignment = methodDescSize / methodDescBuilder.MethodDescAlignment;
199+
byte chunkSize = (byte)(count * methodDescSizeByAlignment);
200+
TargetPointer chunk = methodDescBuilder.AddMethodDescChunk(methodTable, string.Empty, count, chunkSize, tokenRange: 0);
201+
202+
ushort flags = (ushort)MethodClassification.Instantiated;
203+
TargetPointer genericMethodDef = methodDescBuilder.SetMethodDesc(chunk, index: 0, slotNum: 0, flags, tokenRemainder: 0);
204+
methodDescBuilder.SetInstantiatedMethodDesc(genericMethodDef, (ushort)RuntimeTypeSystem_1.InstantiatedMethodDescFlags2.GenericMethodDefinition, []);
205+
TargetPointer[] typeArgsRawAddrs = [0x1000, 0x2000, 0x3000];
206+
TargetPointer[] typeArgsHandles = typeArgsRawAddrs.Select(a => GetTypeDescHandlePointer(a)).ToArray();
207+
208+
TargetPointer genericWithInst = methodDescBuilder.SetMethodDesc(chunk, index: (byte)methodDescSizeByAlignment, slotNum: 1, flags, tokenRemainder: 0);
209+
methodDescBuilder.SetInstantiatedMethodDesc(genericWithInst, (ushort)RuntimeTypeSystem_1.InstantiatedMethodDescFlags2.GenericMethodDefinition, typeArgsHandles);
210+
211+
Target target = CreateTarget(methodDescBuilder);
212+
IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
213+
214+
{
215+
MethodDescHandle handle = rts.GetMethodDescHandle(genericMethodDef);
216+
Assert.NotEqual(TargetPointer.Null, handle.Address);
217+
Assert.True(rts.IsGenericMethodDefinition(handle));
218+
ReadOnlySpan<TypeHandle> instantiation = rts.GetGenericMethodInstantiation(handle);
219+
Assert.Equal(0, instantiation.Length);
220+
}
221+
222+
{
223+
MethodDescHandle handle = rts.GetMethodDescHandle(genericWithInst);
224+
Assert.NotEqual(TargetPointer.Null, handle.Address);
225+
Assert.True(rts.IsGenericMethodDefinition(handle));
226+
ReadOnlySpan<TypeHandle> instantiation = rts.GetGenericMethodInstantiation(handle);
227+
Assert.Equal(typeArgsRawAddrs.Length, instantiation.Length);
228+
for (int i = 0; i < typeArgsRawAddrs.Length; i++)
229+
{
230+
Assert.Equal(typeArgsHandles[i], instantiation[i].Address);
231+
Assert.Equal(typeArgsRawAddrs[i], instantiation[i].TypeDescAddress());
232+
}
233+
}
72234
}
73235

74236
public static IEnumerable<object[]> StdArchOptionalSlotsData()
@@ -98,12 +260,7 @@ public void GetAddressOfNativeCodeSlot_OptionalSlots(MockTarget.Architecture arc
98260
MockDescriptors.MethodDescriptors methodDescBuilder = new(rtsBuilder, loaderBuilder);
99261

100262
MethodDescFlags_1.MethodDescFlags flags = (MethodDescFlags_1.MethodDescFlags)flagsValue;
101-
ushort numVirtuals = 1;
102-
TargetPointer eeClass = rtsBuilder.AddEEClass(string.Empty, 0, 2, 1);
103-
TargetPointer methodTable = rtsBuilder.AddMethodTable(string.Empty,
104-
mtflags: default, mtflags2: default, baseSize: helpers.ObjectBaseSize,
105-
module: TargetPointer.Null, parentMethodTable: TargetPointer.Null, numInterfaces: 0, numVirtuals: numVirtuals);
106-
rtsBuilder.SetEEClassAndCanonMTRefs(eeClass, methodTable);
263+
TargetPointer methodTable = AddMethodTable(rtsBuilder);
107264

108265
uint methodDescSize = methodDescBuilder.Types[DataType.MethodDesc].Size.Value;
109266
if (flags.HasFlag(MethodDescFlags_1.MethodDescFlags.HasNonVtableSlot))
@@ -135,4 +292,84 @@ public void GetAddressOfNativeCodeSlot_OptionalSlots(MockTarget.Architecture arc
135292
Assert.Equal(expectedCodeSlotAddr, actualNativeCodeSlotAddr);
136293
}
137294
}
295+
296+
public static IEnumerable<object[]> StdArchMethodDescTypeData()
297+
{
298+
foreach (object[] arr in new MockTarget.StdArch())
299+
{
300+
MockTarget.Architecture arch = (MockTarget.Architecture)arr[0];
301+
yield return new object[] { arch, DataType.MethodDesc };
302+
yield return new object[] { arch, DataType.FCallMethodDesc };
303+
yield return new object[] { arch, DataType.PInvokeMethodDesc };
304+
yield return new object[] { arch, DataType.EEImplMethodDesc };
305+
yield return new object[] { arch, DataType.ArrayMethodDesc };
306+
yield return new object[] { arch, DataType.InstantiatedMethodDesc };
307+
yield return new object[] { arch, DataType.CLRToCOMCallMethodDesc };
308+
yield return new object[] { arch, DataType.DynamicMethodDesc };
309+
}
310+
}
311+
312+
[Theory]
313+
[MemberData(nameof(StdArchMethodDescTypeData))]
314+
public void GetNativeCode_StableEntryPoint_NonVtableSlot(MockTarget.Architecture arch, DataType methodDescType)
315+
{
316+
TargetTestHelpers helpers = new(arch);
317+
MockMemorySpace.Builder builder = new(helpers);
318+
MockDescriptors.RuntimeTypeSystem rtsBuilder = new(builder);
319+
MockDescriptors.Loader loaderBuilder = new(builder);
320+
MockDescriptors.MethodDescriptors methodDescBuilder = new(rtsBuilder, loaderBuilder);
321+
322+
TargetPointer methodTable = AddMethodTable(rtsBuilder);
323+
MethodClassification classification = methodDescType switch
324+
{
325+
DataType.MethodDesc => MethodClassification.IL,
326+
DataType.FCallMethodDesc => MethodClassification.FCall,
327+
DataType.PInvokeMethodDesc => MethodClassification.PInvoke,
328+
DataType.EEImplMethodDesc => MethodClassification.EEImpl,
329+
DataType.ArrayMethodDesc => MethodClassification.Array,
330+
DataType.InstantiatedMethodDesc => MethodClassification.Instantiated,
331+
DataType.CLRToCOMCallMethodDesc => MethodClassification.ComInterop,
332+
DataType.DynamicMethodDesc => MethodClassification.Dynamic,
333+
_ => throw new ArgumentOutOfRangeException(nameof(methodDescType))
334+
};
335+
uint methodDescBaseSize = methodDescBuilder.Types[methodDescType].Size.Value;
336+
uint methodDescSize = methodDescBaseSize + methodDescBuilder.Types[DataType.NonVtableSlot].Size!.Value;
337+
byte chunkSize = (byte)(methodDescSize / methodDescBuilder.MethodDescAlignment);
338+
TargetPointer chunk = methodDescBuilder.AddMethodDescChunk(methodTable, string.Empty, count: 1, chunkSize, tokenRange: 0);
339+
340+
ushort flags = (ushort)((ushort)classification | (ushort)MethodDescFlags_1.MethodDescFlags.HasNonVtableSlot);
341+
TargetPointer methodDescAddress = methodDescBuilder.SetMethodDesc(chunk, index: 0, slotNum: 0, flags, tokenRemainder: 0, flags3: (ushort)MethodDescFlags_1.MethodDescFlags3.HasStableEntryPoint);
342+
TargetCodePointer nativeCode = new TargetCodePointer(0x0789_abc0);
343+
helpers.WritePointer(
344+
methodDescBuilder.Builder.BorrowAddressRange(methodDescAddress + methodDescBaseSize, helpers.PointerSize),
345+
nativeCode);
346+
347+
Mock<IExecutionManager> mockExecutionManager = new();
348+
CodeBlockHandle codeBlock = new CodeBlockHandle(methodDescAddress);
349+
mockExecutionManager.Setup(em => em.GetCodeBlockHandle(nativeCode))
350+
.Returns(codeBlock);
351+
mockExecutionManager.Setup(em => em.GetMethodDesc(codeBlock))
352+
.Returns(methodDescAddress);
353+
Target target = CreateTarget(methodDescBuilder, mockExecutionManager);
354+
IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
355+
356+
var handle = rts.GetMethodDescHandle(methodDescAddress);
357+
Assert.NotEqual(TargetPointer.Null, handle.Address);
358+
359+
TargetCodePointer actualNativeCode = rts.GetNativeCode(handle);
360+
Assert.Equal(nativeCode, actualNativeCode);
361+
}
362+
363+
private TargetPointer AddMethodTable(MockDescriptors.RuntimeTypeSystem rtsBuilder, ushort numVirtuals = 5)
364+
{
365+
TargetPointer eeClass = rtsBuilder.AddEEClass(string.Empty, attr: 0, numMethods: 2, numNonVirtualSlots: 1);
366+
TargetPointer methodTable = rtsBuilder.AddMethodTable(string.Empty,
367+
mtflags: default, mtflags2: default, baseSize: rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize,
368+
module: TargetPointer.Null, parentMethodTable: TargetPointer.Null, numInterfaces: 0, numVirtuals);
369+
rtsBuilder.SetEEClassAndCanonMTRefs(eeClass, methodTable);
370+
return methodTable;
371+
}
372+
373+
private static TargetPointer GetTypeDescHandlePointer(TargetPointer addr)
374+
=> addr | (ulong)RuntimeTypeSystem_1.TypeHandleBits.TypeDesc;
138375
}

0 commit comments

Comments
 (0)