protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type) { if (type.RetrieveRuntimeTypeHandleIfPossible() && !type.IsGenericDefinition) { // If the type is already constructed, use the NoMetadataRuntimeInterfacesAlgorithm. // its more efficient than loading from native layout or metadata. return s_noMetadataRuntimeInterfacesAlgorithm; } else if (type.HasNativeLayout) { return s_nativeLayoutInterfacesAlgorithm; } else if (type is NoMetadataType) { return s_noMetadataRuntimeInterfacesAlgorithm; } else if (type is MetadataType) { return s_metadataRuntimeInterfacesAlgorithm; } else { Debug.Assert(false); return null; } }
public unsafe override bool ComputeContainsGCPointers(DefType type) { if (type.IsTemplateCanonical()) { return type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->HasGCPointers; } else { if (type.RetrieveRuntimeTypeHandleIfPossible()) { return type.RuntimeTypeHandle.ToEETypePtr()->HasGCPointers; } return type.GetOrCreateTypeBuilderState().InstanceGCLayout != null; } }
public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) { if (type.RetrieveRuntimeTypeHandleIfPossible()) { // If the type is already constructed, use the NoMetadataFieldLayoutAlgorithm. // its more efficient than loading from native layout or metadata. return s_noMetadataFieldLayoutAlgorithm; } if (type.HasNativeLayout) { return s_nativeLayoutFieldAlgorithm; } else if (type is NoMetadataType) { return s_noMetadataFieldLayoutAlgorithm; } else { return s_metadataFieldLayoutAlgorithm; } }
/// <summary> /// Given a type, and vtable slot index, compute either the NativeFormatMethod that defines that vtable slot, /// OR the implementation function pointer if the method doesn't have sufficient metadata to be interesting /// to use the virtual function resolution algorithm on. /// </summary> /// <param name="type">Type on which virtual resolution is to be completed</param> /// <param name="vtableSlotIndex">Virtual slot index which is to be examined</param> /// <param name="functionPointer">If there is no corresponding method defined in metadata, this is /// the function pointer that should be used for calls to this vtable slot</param> /// <returns>MethodDesc of function that defined the slot if possible.</returns> private unsafe static MethodDesc ResolveVTableSlotIndexToMethodDescOrFunctionPointer(DefType type, int vtableSlotIndex, out IntPtr functionPointer) { Debug.Assert(type.RetrieveRuntimeTypeHandleIfPossible()); Debug.Assert(type.RuntimeTypeHandle.ToEETypePtr()->NumVtableSlots > vtableSlotIndex); DefType definingTypeScan = type; DefType previousDefiningType = null; EEType* typePtr = null; DefType definingType = null; functionPointer = IntPtr.Zero; while (true) { definingTypeScan.RetrieveRuntimeTypeHandleIfPossible(); Debug.Assert(!definingTypeScan.RuntimeTypeHandle.IsNull()); typePtr = definingTypeScan.RuntimeTypeHandle.ToEETypePtr(); if (typePtr->NumVtableSlots > vtableSlotIndex) { previousDefiningType = definingTypeScan; definingTypeScan = definingTypeScan.BaseType; // We found a slot on System.Object if (definingTypeScan == null) { definingType = previousDefiningType; break; } } else { // We've gone past the type in the type hierarchy that declared this vtable slot // the defining type is the one we looked at previously definingType = previousDefiningType; break; } } // At this point, we know the type that definined the virtual slot // There are 4 possibilities here // 1. The definingType is a R2R type with full metadata. Compute the MethodDesc, by scanning the list of virtuals present in metadata // 2. The definingType is pregenerated, but we can go from the slot index to metadata via the runtime mapping tables. Do so, then run // normal algorithm // 3. The definingType is pregenerated, but we cannot go from the slot index to metadata via the runtime mapping tables. There is // only 1 pointer in the vtable of the most derived pregenerated type that has the same value. That's the valuable pointer. // 4. The definingType is pregenerated, but we cannot go from the slot index to metadata via the runtime mapping tables. There are // multiple pointers in the vtable of the most derived pregenerated types which have this same value. // - Take that pointer value, and attempt to resolve back to a method from the implementation. If that succeeds, then // treat that as the correct vtable slot. Otherwise, return that function pointer. (This is a very rare scenario.) MethodDesc slotDefiningMethod = null; if (!IsPregeneratedOrTemplateTypeLoaded(definingType)) { // Case 1 MetadataType definingMetadataType = (MetadataType)definingType; int baseTypeSlotCount = 0; if (definingMetadataType.BaseType != null) baseTypeSlotCount = definingMetadataType.BaseType.GetRuntimeTypeHandle().ToEETypePtr()->NumVtableSlots; int slotOnType = vtableSlotIndex - baseTypeSlotCount; Debug.Assert(slotOnType >= 0); // R2R types create new slots only for methods that are marked as NewSlot if (definingMetadataType.ConvertToCanonForm(CanonicalFormKind.Specific) != definingType) { // Deal with the space reserved for the canonical dictionary slotOnType--; } Debug.Assert(slotOnType >= 0); int currentSlot = 0; foreach (MethodDesc method in definingMetadataType.GetMethods()) { if (!MethodDefinesVTableSlot(method)) continue; if (currentSlot == slotOnType) { Debug.Assert(VirtualMethodToSlotIndex(method) == vtableSlotIndex); return method; } else currentSlot++; } Environment.FailFast("Unexpected failure to find virtual function that defined slot"); return null; } else if (TryGetVirtualMethodFromSlot(definingType, vtableSlotIndex, out slotDefiningMethod)) { // Case 2 Debug.Assert(VirtualMethodToSlotIndex(slotDefiningMethod) == vtableSlotIndex); return slotDefiningMethod; } else { TypeDesc mostDerivedPregeneratedType = GetMostDerivedPregeneratedOrTemplateLoadedType(type); EEType* mostDerivedTypeEEType = mostDerivedPregeneratedType.GetRuntimeTypeHandle().ToEETypePtr(); IntPtr* vtableStart = (IntPtr*)(((byte*)mostDerivedTypeEEType) + sizeof(EEType)); IntPtr possibleFunctionPointerReturn = vtableStart[vtableSlotIndex]; int functionPointerMatches = 0; for (int i = 0; i < mostDerivedTypeEEType->NumVtableSlots; i++) { if (vtableStart[i] == possibleFunctionPointerReturn) functionPointerMatches++; } if (functionPointerMatches == 1) { // Case 3 functionPointer = possibleFunctionPointerReturn; return null; } else { // Case 4 // While this case is theoretically possible, it requires MethodImpl to MethodImpl overloading for virtual functions // in the non-ready to run portions of the binary. Given our current shipping plans, as this does not occur in non-obfuscated // code, we will throw NotImplementedException here. // The real implementation would look something like // if (!TryGetNativeFormatMethodFromFunctionPointer(possibleFunctionPointerReturn, out method)) // { // // this method could not have been overriden in dynamically loaded code // functionPointer = possibleFunctionPointerReturn; // return null; // } // else // { // return VirtualFunctionAlgorithm.GetDefiningMethod(method) // } // throw NotImplemented.ByDesign; } } }