/// <summary> /// Attempts to resolve constrained call to <paramref name="interfaceMethod"/> into a concrete non-unboxing /// method on <paramref name="constrainedType"/>. /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing /// for generic code. /// </summary> /// <returns>The resolved method or null if the constraint couldn't be resolved.</returns> public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup) { forceRuntimeLookup = false; // We can't resolve constraint calls effectively for reference types, and there's // not a lot of perf. benefit in doing it anyway. if (!constrainedType.IsValueType) { return(null); } // Non-virtual methods called through constraints simply resolve to the specified method without constraint resolution. if (!interfaceMethod.IsVirtual) { return(null); } MethodDesc method; MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition(); if (genInterfaceMethod.OwningType.IsInterface) { // Sometimes (when compiling shared generic code) // we don't have enough exact type information at JIT time // even to decide whether we will be able to resolve to an unboxed entry point... // To cope with this case we always go via the helper function if there's any // chance of this happening by checking for all interfaces which might possibly // be compatible with the call (verification will have ensured that // at least one of them will be) // Enumerate all potential interface instantiations // TODO: this code assumes no shared generics Debug.Assert(interfaceType == interfaceMethod.OwningType); method = constrainedType.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod); } else if (genInterfaceMethod.IsVirtual) { method = constrainedType.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod); } else { // The method will be null if calling a non-virtual instance // methods on System.Object, i.e. when these are used as a constraint. method = null; } if (method == null) { // Fall back to VSD return(null); } //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod // Only return a method if the value type itself declares the method, // otherwise we might get a method from Object or System.ValueType if (!method.OwningType.IsValueType) { // Fall back to VSD return(null); } // We've resolved the method, ignoring its generic method arguments // If the method is a generic method then go and get the instantiated descriptor if (interfaceMethod.HasInstantiation) { method = method.MakeInstantiatedMethod(interfaceMethod.Instantiation); } Debug.Assert(method != null); //assert(!pMD->IsUnboxingStub()); return(method); }
private bool CanCompareValueTypeBits(MetadataType type) { Debug.Assert(type.IsValueType); if (type.ContainsGCPointers) { return(false); } if (type.IsGenericDefinition) { return(false); } OverlappingFieldTracker overlappingFieldTracker = new OverlappingFieldTracker(type); bool result = true; foreach (var field in type.GetFields()) { if (field.IsStatic) { continue; } if (!overlappingFieldTracker.TrackField(field)) { // This field overlaps with another field - can't compare memory result = false; break; } TypeDesc fieldType = field.FieldType; if (fieldType.IsPrimitive || fieldType.IsEnum || fieldType.IsPointer || fieldType.IsFunctionPointer) { TypeFlags category = fieldType.UnderlyingType.Category; if (category == TypeFlags.Single || category == TypeFlags.Double) { // Double/Single have weird behaviors around negative/positive zero result = false; break; } } else { // Would be a suprise if this wasn't a valuetype. We checked ContainsGCPointers above. Debug.Assert(fieldType.IsValueType); // If the field overrides Equals, we can't use the fast helper because we need to call the method. if (fieldType.FindVirtualFunctionTargetMethodOnObjectType(_objectEqualsMethod).OwningType == type) { result = false; break; } if (!CanCompareValueTypeBits((MetadataType)fieldType)) { result = false; break; } } } // If there are gaps, we can't memcompare if (result && overlappingFieldTracker.HasGaps) { result = false; } return(result); }