public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) { if (type.Context.Target.Architecture == TargetArchitecture.ARM) { unsafe { // On ARM, the HFA type is encoded into the EEType directly type.RetrieveRuntimeTypeHandleIfPossible(); Debug.Assert(!type.RuntimeTypeHandle.IsNull()); EEType *eeType = type.RuntimeTypeHandle.ToEETypePtr(); if (eeType->IsHFA) { return(ValueTypeShapeCharacteristics.HomogenousFloatAggregate); } else { return(ValueTypeShapeCharacteristics.None); } } } else { Debug.Assert( type.Context.Target.Architecture == TargetArchitecture.X86 || type.Context.Target.Architecture == TargetArchitecture.X64); return(ValueTypeShapeCharacteristics.None); } }
public static bool IsPregeneratedOrTemplateTypeLoaded(TypeDesc derivedType) { Debug.Assert(!derivedType.IsInterface); DefType defTypeDerived = derivedType as DefType; if (defTypeDerived == null) { return(true); } else { if (!(defTypeDerived is TypeSystem.NoMetadata.NoMetadataType) && !defTypeDerived.HasNativeLayout) { if (!defTypeDerived.RetrieveRuntimeTypeHandleIfPossible()) { return(false); } unsafe { return(!defTypeDerived.RuntimeTypeHandle.ToEETypePtr()->IsDynamicType); } } return(true); } }
public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) { if (type.Context.Target.Architecture == TargetArchitecture.ARM) { unsafe { // On ARM, the HFA type is encoded into the EEType directly type.RetrieveRuntimeTypeHandleIfPossible(); Debug.Assert(!type.RuntimeTypeHandle.IsNull()); EEType *eeType = type.RuntimeTypeHandle.ToEETypePtr(); if (!eeType->IsHFA) { return(null); } if (eeType->RequiresAlign8) { return(type.Context.GetWellKnownType(WellKnownType.Double)); } else { return(type.Context.GetWellKnownType(WellKnownType.Single)); } } } else { Debug.Assert( type.Context.Target.Architecture == TargetArchitecture.X86 || type.Context.Target.Architecture == TargetArchitecture.X64); return(null); } }
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 ComputeIsByRefLike(DefType type) { if (type.RetrieveRuntimeTypeHandleIfPossible()) { return(type.RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); } // Being ByRefLike is a property of the uninstantiated form of a type (so its set on all kinds of templates reliably) return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); }
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 unsafe override bool ComputeIsByRefLike(DefType type) { if (type.IsTemplateCanonical()) { return(type.ComputeTemplate().RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); } else { if (type.RetrieveRuntimeTypeHandleIfPossible()) { return(type.RuntimeTypeHandle.ToEETypePtr()->IsByRefLike); } throw new NotImplementedException(); } }
/// <summary> /// Reads the minimal information about type layout encoded in the /// EEType. That doesn't include field information. /// </summary> public unsafe override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) { // If we need the field information, delegate to the native layout algorithm or metadata algorithm if (layoutKind != InstanceLayoutKind.TypeOnly) { if (type.HasNativeLayout) { return(s_nativeLayoutFieldAlgorithm.ComputeInstanceLayout(type, layoutKind)); } else { return(_metadataFieldLayoutAlgorithm.ComputeInstanceLayout(type, layoutKind)); } } type.RetrieveRuntimeTypeHandleIfPossible(); Debug.Assert(!type.RuntimeTypeHandle.IsNull()); EEType *eeType = type.RuntimeTypeHandle.ToEETypePtr(); ComputedInstanceFieldLayout layout = new ComputedInstanceFieldLayout() { ByteCountAlignment = new LayoutInt(IntPtr.Size), ByteCountUnaligned = new LayoutInt(eeType->IsInterface ? IntPtr.Size : checked ((int)eeType->FieldByteCountNonGCAligned)), FieldAlignment = new LayoutInt(eeType->FieldAlignmentRequirement), Offsets = (layoutKind == InstanceLayoutKind.TypeOnly) ? null : Array.Empty <FieldAndOffset>(), // No fields in EETypes PackValue = 0, // This isn't explicitly encoded, though FieldSize should take it into account // TODO, as we add more metadata handling logic, find out if its necessary. }; if (eeType->IsValueType) { int valueTypeSize = checked ((int)eeType->ValueTypeSize); layout.FieldSize = new LayoutInt(valueTypeSize); } else { layout.FieldSize = new LayoutInt(IntPtr.Size); } if ((eeType->RareFlags & EETypeRareFlags.RequiresAlign8Flag) == EETypeRareFlags.RequiresAlign8Flag) { layout.ByteCountAlignment = new LayoutInt(8); } return(layout); }
public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) { if (type.Context.Target.Architecture == TargetArchitecture.ARM) { unsafe { // On ARM, the HFA type is encoded into the EEType directly type.RetrieveRuntimeTypeHandleIfPossible(); Debug.Assert(!type.RuntimeTypeHandle.IsNull()); EEType *eeType = type.RuntimeTypeHandle.ToEETypePtr(); if (!eeType->IsHFA) { return(null); } if (eeType->RequiresAlign8) { return(type.Context.GetWellKnownType(WellKnownType.Double)); } else { return(type.Context.GetWellKnownType(WellKnownType.Single)); } } } else { // We must delegate to algorithms that can work off of a sort of metadata if (type.HasNativeLayout) { return(s_nativeLayoutFieldAlgorithm.ComputeHomogeneousFloatAggregateElementType(type)); } else if (type is MetadataType) { return(_metadataFieldLayoutAlgorithm.ComputeHomogeneousFloatAggregateElementType(type)); } else { return(null); // If there isn't any form of metadata, it can't matter... as HFA is not part of the ABI except on ARM } } }
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); } }
public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) { if (type.Context.Target.Architecture == TargetArchitecture.ARM) { unsafe { // On ARM, the HFA type is encoded into the EEType directly type.RetrieveRuntimeTypeHandleIfPossible(); Debug.Assert(!type.RuntimeTypeHandle.IsNull()); EEType *eeType = type.RuntimeTypeHandle.ToEETypePtr(); if (eeType->IsHFA) { return(ValueTypeShapeCharacteristics.HomogenousFloatAggregate); } else { return(ValueTypeShapeCharacteristics.None); } } } else { // We must delegate to algorithms that can work off of a sort of metadata if (type.HasNativeLayout) { return(s_nativeLayoutFieldAlgorithm.ComputeValueTypeShapeCharacteristics(type)); } else if (type is MetadataType) { return(_metadataFieldLayoutAlgorithm.ComputeValueTypeShapeCharacteristics(type)); } else { return(ValueTypeShapeCharacteristics.None); // If there isn't any form of metadata, it can't matter... as HFA is not part of the ABI except on ARM } } }
/// <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 static unsafe 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; } } }