public void EnumerateMethodTableTest() { using (DataTarget dt = TestTargets.AppDomains.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; ulong[] fooObjects = (from obj in heap.EnumerateObjectAddresses() let t = heap.GetObjectType(obj) where t.Name == "Foo" select obj).ToArray(); // There are exactly two Foo objects in the process, one in each app domain. // They will have different method tables. Assert.Equal(2, fooObjects.Length); ClrType fooType = heap.GetObjectType(fooObjects[0]); Assert.NotSame(fooType, heap.GetObjectType(fooObjects[1])); ClrRoot appDomainsFoo = (from root in heap.EnumerateRoots(true) where root.Kind == GCRootKind.StaticVar && root.Type == fooType select root).Single(); ulong nestedExceptionFoo = fooObjects.Where(obj => obj != appDomainsFoo.Object).Single(); ClrType nestedExceptionFooType = heap.GetObjectType(nestedExceptionFoo); Assert.NotSame(nestedExceptionFooType, appDomainsFoo.Type); ulong nestedExceptionFooMethodTable = dt.DataReader.ReadPointerUnsafe(nestedExceptionFoo); ulong appDomainsFooMethodTable = dt.DataReader.ReadPointerUnsafe(appDomainsFoo.Object); // These are in different domains and should have different type handles: Assert.NotEqual(nestedExceptionFooMethodTable, appDomainsFooMethodTable); // The MethodTable returned by ClrType should always be the method table that lives in the "first" // AppDomain (in order of ClrAppDomain.Id). Assert.Equal(appDomainsFooMethodTable, fooType.MethodTable); // Ensure that we enumerate two type handles and that they match the method tables we have above. ulong[] methodTableEnumeration = fooType.EnumerateMethodTables().ToArray(); Assert.Equal(2, methodTableEnumeration.Length); // These also need to be enumerated in ClrAppDomain.Id order Assert.Equal(appDomainsFooMethodTable, methodTableEnumeration[0]); Assert.Equal(nestedExceptionFooMethodTable, methodTableEnumeration[1]); } }
public void GetObjectMethodTableTest() { using (DataTarget dt = TestTargets.AppDomains.LoadFullDump()) { ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime(); ClrHeap heap = runtime.Heap; int i = 0; foreach (ulong obj in heap.EnumerateObjectAddresses()) { i++; ClrType type = heap.GetObjectType(obj); if (type.IsArray) { ulong mt, cmt; bool result = heap.TryGetMethodTable(obj, out mt, out cmt); Assert.True(result); Assert.NotEqual(0ul, mt); Assert.Equal(type.MethodTable, mt); Assert.Same(type, heap.GetTypeByMethodTable(mt, cmt)); } else { ulong mt = heap.GetMethodTable(obj); Assert.NotEqual(0ul, mt); Assert.Contains(mt, type.EnumerateMethodTables()); Assert.Same(type, heap.GetTypeByMethodTable(mt)); Assert.Same(type, heap.GetTypeByMethodTable(mt, 0)); ulong mt2, cmt; bool res = heap.TryGetMethodTable(obj, out mt2, out cmt); Assert.True(res); Assert.Equal(mt, mt2); Assert.Equal(0ul, cmt); } } } }
/// <summary> /// Enumerates all MethodTable for this type in the process. MethodTable /// are unique to an AppDomain/Type pair, so when there are multiple domains /// there may be multiple MethodTable. Note that even if a type could be /// used in an AppDomain, that does not mean we actually have a MethodTable /// if the type hasn't been created yet. /// </summary> /// <returns> /// An enumeration of MethodTable in the process for this given /// type. /// </returns> /// <inheritdoc /> public IEnumerable <ulong> EnumerateMethodTables() => ClrType.EnumerateMethodTables();