@@ -42,6 +42,8 @@ partial interface IRuntimeTypeSystem : IContract
4242 public virtual TargetPointer GetParentMethodTable (TypeHandle typeHandle );
4343
4444 public virtual TargetPointer GetMethodDescForSlot (TypeHandle typeHandle , ushort slot );
45+ public virtual IEnumerable <TargetPointer > GetIntroducedMethodDescs (TypeHandle methodTable );
46+ public virtual TargetCodePointer GetSlot (TypeHandle typeHandle , uint slot );
4547
4648 public virtual uint GetBaseSize (TypeHandle typeHandle );
4749 // 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)
@@ -57,6 +59,7 @@ partial interface IRuntimeTypeSystem : IContract
5759
5860 // Returns an ECMA-335 TypeDef table token for this type, or for its generic type definition if it is a generic instantiation
5961 public virtual uint GetTypeDefToken (TypeHandle typeHandle );
62+ public virtual ushort GetNumVtableSlots (TypeHandle typeHandle );
6063 public virtual ushort GetNumMethods (TypeHandle typeHandle );
6164 // Returns the ECMA 335 TypeDef table Flags value (a bitmask of TypeAttributes) for this type,
6265 // or for its generic type definition if it is a generic instantiation
@@ -169,8 +172,12 @@ partial interface IRuntimeTypeSystem : IContract
169172 public virtual TargetPointer GetAddressOfNativeCodeSlot (MethodDescHandle methodDesc );
170173
171174 // Get an instruction pointer that can be called to cause the MethodDesc to be executed
175+ // Requires the entry point to be stable
172176 public virtual TargetCodePointer GetNativeCode (MethodDescHandle methodDesc );
173177
178+ // Get an instruction pointer that can be called to cause the MethodDesc to be executed
179+ public virtual TargetCodePointer GetMethodEntryPointIfExists (MethodDescHandle methodDesc );
180+
174181 // Gets the GCStressCodeCopy pointer if available, otherwise returns TargetPointer.Null
175182 public virtual TargetPointer GetGCStressCodeCopy (MethodDescHandle methodDesc );
176183}
@@ -470,6 +477,15 @@ Contracts used:
470477 return (uint )(typeHandle .Flags .GetTypeDefRid () | ((int )TableIndex .TypeDef << 24 ));
471478 }
472479
480+ public ushort GetNumVtableSlots (TypeHandle typeHandle )
481+ {
482+ if (! typeHandle .IsMethodTable ())
483+ return 0 ;
484+ MethodTable methodTable = _methodTables [typeHandle .Address ];
485+ ushort numNonVirtualSlots = methodTable .IsCanonMT ? GetClassData (typeHandle ).NumNonVirtualSlots : (ushort )0 ;
486+ return checked ((ushort )(methodTable .NumVirtuals + numNonVirtualSlots ));
487+ }
488+
473489 public ushort GetNumMethods (TypeHandle TypeHandle ) => ! typeHandle .IsMethodTable () ? 0 : GetClassData (TypeHandle ).NumMethods ;
474490
475491 public uint GetTypeDefTypeAttributes (TypeHandle TypeHandle ) => ! typeHandle .IsMethodTable () ? 0 : GetClassData (TypeHandle ).CorTypeAttr ;
@@ -1302,6 +1318,30 @@ Getting the native code pointer for methods with a NativeCodeSlot or a stable en
13021318
13031319 return GetStableEntryPoint (methodDescHandle .Address , md );
13041320 }
1321+
1322+ public TargetCodePointer IRuntimeTypeSystem .GetMethodEntryPointIfExists (MethodDescHandle methodDescHandle )
1323+ {
1324+ MethodDesc md = _methodDescs [methodDescHandle .Address ];
1325+ return GetMethodEntryPointIfExists (methodDescHandle .Address , md );
1326+ }
1327+ ```
1328+
1329+ Getting the value of a slot of a MethodTable
1330+ ``` csharp
1331+ public TargetCodePointer GetSlot (TypeHandle typeHandle , uint slot )
1332+ {
1333+ // based on MethodTable::GetSlot(uint slotNumber)
1334+ if (! typeHandle .IsMethodTable ())
1335+ throw new ArgumentException ($" {nameof (typeHandle )} is not a MethodTable" );
1336+
1337+ if (slot < GetNumVtableSlots (typeHandle ))
1338+ {
1339+ TargetPointer slotPtr = GetAddressOfSlot (typeHandle , slot );
1340+ return _target .ReadCodePointer (slotPtr );
1341+ }
1342+
1343+ return TargetCodePointer .Null ;
1344+ }
13051345```
13061346
13071347Getting a MethodDesc for a certain slot in a MethodTable
@@ -1353,33 +1393,78 @@ Getting a MethodDesc for a certain slot in a MethodTable
13531393 }
13541394 }
13551395
1356- public TargetPointer GetMethodDescForSlot (TypeHandle methodTable , ushort slot )
1396+ public IEnumerable < TargetPointer > GetIntroducedMethodDescs (TypeHandle typeHandle )
1397+ {
1398+ if (! typeHandle .IsMethodTable ())
1399+ throw new ArgumentException ($" {nameof (typeHandle )} is not a MethodTable" );
1400+
1401+ TypeHandle canonMT = GetTypeHandle (GetCanonicalMethodTable (typeHandle ));
1402+ foreach (MethodDescHandle mdh in GetIntroducedMethods (canonMT ))
1403+ {
1404+ yield return mdh .Address ;
1405+ }
1406+ }
1407+
1408+ // Uses GetMethodDescForVtableSlot if slot is less than the number of vtable slots
1409+ // otherwise looks for the slot in the introduced methods
1410+ public TargetPointer GetMethodDescForSlot (TypeHandle typeHandle , ushort slot )
13571411 {
13581412 if (! typeHandle .IsMethodTable ())
13591413 throw new ArgumentException ($" {nameof (typeHandle )} is not a MethodTable" );
13601414
1415+ TypeHandle canonMT = GetTypeHandle (GetCanonicalMethodTable (typeHandle ));
1416+ if (slot < GetNumVtableSlots (canonMT ))
1417+ {
1418+ return GetMethodDescForVtableSlot (canonMT , slot );
1419+ }
1420+ else
1421+ {
1422+ foreach (MethodDescHandle mdh in GetIntroducedMethods (canonMT ))
1423+ {
1424+ MethodDesc md = _methodDescs [mdh .Address ];
1425+ if (md .Slot == slot )
1426+ {
1427+ return mdh .Address ;
1428+ }
1429+ }
1430+ return TargetPointer .Null ;
1431+ }
1432+ }
1433+
1434+ private TargetPointer GetMethodDescForVtableSlot (TypeHandle methodTable , ushort slot )
1435+ {
1436+ // based on MethodTable::GetMethodDescForSlot_NoThrow
1437+ if (! typeHandle .IsMethodTable ())
1438+ throw new ArgumentException ($" {nameof (typeHandle )} is not a MethodTable" );
1439+
13611440 TargetPointer cannonMTPTr = GetCanonicalMethodTable (typeHandle );
13621441 TypeHandle canonMT = GetTypeHandle (cannonMTPTr );
1442+ if (slot >= GetNumVtableSlots (canonMT ))
1443+ throw new ArgumentException (nameof (slot ), " Slot number is greater than the number of slots" );
1444+
13631445 TargetPointer slotPtr = GetAddressOfSlot (canonMT , slot );
13641446 TargetCodePointer pCode = _target .ReadCodePointer (slotPtr );
13651447
13661448 if (pCode == TargetCodePointer .Null )
13671449 {
1368- // if pCode is null, we iterate through the method descs in the MT
1369- while (true ) // arbitrary limit to avoid infinite loop
1450+ TargetPointer lookupMTPtr = cannonMTPTr ;
1451+ while (lookupMTPtr != TargetPointer . Null )
13701452 {
1371- foreach (MethodDescHandle mdh in GetIntroducedMethods (canonMT ))
1453+ // if pCode is null, we iterate through the method descs in the MT.
1454+ TypeHandle lookupMT = GetTypeHandle (lookupMTPtr );
1455+ foreach (MethodDescHandle mdh in GetIntroducedMethods (lookupMT ))
13721456 {
13731457 MethodDesc md = _methodDescs [mdh .Address ];
1374-
1375- // if a MethodDesc matches the slot, return that MethodDesc
13761458 if (md .Slot == slot )
13771459 {
13781460 return mdh .Address ;
13791461 }
13801462 }
1381- canonMT = GetTypeHandle (GetCanonicalMethodTable (GetTypeHandle (GetParentMethodTable (canonMT ))));
1463+ lookupMTPtr = GetParentMethodTable (lookupMT );
1464+ if (lookupMTPtr != TargetPointer .Null )
1465+ lookupMTPtr = GetCanonicalMethodTable (GetTypeHandle (lookupMTPtr ));
13821466 }
1467+ return TargetPointer .Null ;
13831468 }
13841469
13851470 return GetMethodDescForEntrypoint (pCode );
0 commit comments