public EntityHandle GetMethodRef(MethodDesc method) { if (_methodRefs.TryGetValue(method, out var handle)) { return(handle); } EntityHandle methodHandle; if (method.HasInstantiation && (method.GetMethodDefinition() != method)) { EntityHandle uninstantiatedHandle = GetMethodRef(method.GetMethodDefinition()); BlobBuilder methodSpecSig = new BlobBuilder(); BlobEncoder methodSpecEncoder = new BlobEncoder(methodSpecSig); methodSpecEncoder.MethodSpecificationSignature(method.Instantiation.Length); foreach (var type in method.Instantiation) { EncodeType(methodSpecSig, type, EmbeddedSignatureDataEmitter.EmptySingleton); } var methodSpecSigHandle = _metadataBuilder.GetOrAddBlob(methodSpecSig); methodHandle = _metadataBuilder.AddMethodSpecification(uninstantiatedHandle, methodSpecSigHandle); } else { EntityHandle typeHandle = GetTypeRef((MetadataType)method.OwningType); StringHandle methodName = _metadataBuilder.GetOrAddString(method.Name); var sig = method.GetTypicalMethodDefinition().Signature; EmbeddedSignatureDataEmitter signatureDataEmitter; if (sig.HasEmbeddedSignatureData) { signatureDataEmitter = new EmbeddedSignatureDataEmitter(sig.GetEmbeddedSignatureData(), this); } else { signatureDataEmitter = EmbeddedSignatureDataEmitter.EmptySingleton; } BlobBuilder memberRefSig = new BlobBuilder(); EncodeMethodSignature(memberRefSig, sig, signatureDataEmitter); if (!signatureDataEmitter.Complete) { throw new ArgumentException(); } var sigBlob = _metadataBuilder.GetOrAddBlob(memberRefSig); methodHandle = _metadataBuilder.AddMemberReference(typeHandle, methodName, sigBlob); } _methodRefs.Add(method, methodHandle); return(methodHandle); }
public static bool CheckConstraints(this MethodDesc method) { if (!method.OwningType.CheckConstraints()) { return(false); } // Non-generic methods always pass constraints check if (!method.HasInstantiation) { return(true); } MethodDesc uninstantiatedMethod = method.GetMethodDefinition(); for (int i = 0; i < uninstantiatedMethod.Instantiation.Length; i++) { if (!VerifyGenericParamConstraint(method.OwningType.Instantiation, method.Instantiation, (GenericParameterDesc)uninstantiatedMethod.Instantiation[i], method.Instantiation[i])) { return(false); } } return(true); }
public MethodIL GetMethodIL(MethodDesc method) { if (method is EcmaMethod) { // TODO: Workaround: we should special case methods with Intrinsic attribute, but since // CoreLib source is still not in the repo, we have to work with what we have, which is // an MCG attribute on the type itself... if (((MetadataType)method.OwningType).HasCustomAttribute("System.Runtime.InteropServices", "McgIntrinsicsAttribute")) { if (method.Name == "Call") { return CalliIntrinsic.EmitIL(method); } } if (method.IsIntrinsic) { MethodIL result = TryGetIntrinsicMethodIL(method); if (result != null) return result; } if (method.IsPInvoke) { return PInvokeMarshallingILEmitter.EmitIL(method); } return EcmaMethodIL.Create((EcmaMethod)method); } else if (method is MethodForInstantiatedType) { var methodDefinitionIL = GetMethodIL(method.GetTypicalMethodDefinition()); if (methodDefinitionIL == null) return null; return new InstantiatedMethodIL(methodDefinitionIL, method.OwningType.Instantiation, new Instantiation()); } else if (method is InstantiatedMethod) { var methodDefinitionIL = GetMethodIL(method.GetMethodDefinition()); if (methodDefinitionIL == null) return null; return new InstantiatedMethodIL(methodDefinitionIL, new Instantiation(), method.Instantiation); } else if (method is ILStubMethod) { return ((ILStubMethod)method).EmitIL(); } else if (method is ArrayMethod) { return ArrayMethodILEmitter.EmitIL((ArrayMethod)method); } else { return null; } }
/// <summary> /// Try to resolve a given virtual static interface method on a given constrained type and return the resolved method or null when not found. /// </summary> /// <param name="constrainedType">Type to attempt method resolution on</param> /// <param name="interfaceMethod">Method to resolve</param> /// <returns>MethodDesc of the resolved method or null when not found (runtime lookup must be used)</returns> private static MethodDesc TryResolveVirtualStaticMethodOnThisType(MetadataType constrainedType, MethodDesc interfaceMethod) { Debug.Assert(interfaceMethod.Signature.IsStatic); MethodImplRecord[] possibleImpls = constrainedType.FindMethodsImplWithMatchingDeclName(interfaceMethod.Name); if (possibleImpls == null) { return(null); } MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); foreach (MethodImplRecord methodImpl in possibleImpls) { if (methodImpl.Decl == interfaceMethodDefinition) { MethodDesc resolvedMethodImpl = methodImpl.Body; if (interfaceMethod != interfaceMethodDefinition) { resolvedMethodImpl = resolvedMethodImpl.MakeInstantiatedMethod(interfaceMethod.Instantiation); } return(resolvedMethodImpl); } } return(null); }
private void AppendMethodSignature(StringBuilder sb, MethodDesc method) { // If this is an instantiated generic method, the formatted signature should // be uninstantiated (e.g. "void Foo::Bar<int>(!!0 param)", not "void Foo::Bar<int>(int param)") MethodSignature signature = method.GetMethodDefinition().Signature; AppendSignaturePrefix(sb, signature); sb.Append(' '); AppendOwningType(sb, method.OwningType); sb.Append("::"); sb.Append(method.Name); if (method.HasInstantiation) { sb.Append('<'); for (int i = 0; i < method.Instantiation.Length; i++) { if (i != 0) sb.Append(", "); _typeNameFormatter.AppendNameWithValueClassPrefix(sb, method.Instantiation[i]); } sb.Append('>'); } sb.Append('('); AppendSignatureArgumentList(sb, signature); sb.Append(')'); }
/// <summary> /// Resolve a virtual function call (to a virtual method, not an interface method) /// </summary> /// <param name="targetMethod"></param> /// <param name="objectType"></param> /// <returns>The override of the virtual method that should be called</returns> private static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType) { // Step 1, convert objectType to uninstantiated form MetadataType uninstantiatedType = objectType; MethodDesc initialTargetMethod = targetMethod; InstantiatedType initialInstantiatedType = objectType as InstantiatedType; if (initialInstantiatedType != null) { uninstantiatedType = (MetadataType)initialInstantiatedType.GetTypeDefinition(); } // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form targetMethod = targetMethod.GetMethodDefinition(); if (uninstantiatedType != objectType) { targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod); } // Step 3, find unification group of target method UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod)); FindBaseUnificationGroup(uninstantiatedType, group); // Step 4, name/sig match virtual function resolve MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, uninstantiatedType); if (resolutionTarget == null) { return(null); } // Step 5, convert resolution target from uninstantiated form target to objecttype target, // and instantiate as appropriate if (uninstantiatedType != objectType) { resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget); } if (initialTargetMethod.HasInstantiation) { resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation); } return(resolutionTarget); }
public virtual MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) { Instantiation instantiation = Instantiation; TypeDesc[] clone = null; for (int i = 0; i < instantiation.Length; i++) { TypeDesc uninst = instantiation[i]; TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); if (inst != uninst) { if (clone == null) { clone = new TypeDesc[instantiation.Length]; for (int j = 0; j < clone.Length; j++) { clone[j] = instantiation[j]; } } clone[i] = inst; } } MethodDesc method = this; TypeDesc owningType = method.OwningType; TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); if (owningType != instantiatedOwningType) { method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); if (clone == null && instantiation.Length != 0) { return(Context.GetInstantiatedMethod(method, instantiation)); } } return((clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone))); }
public static DefaultInterfaceMethodResolution ResolveVariantInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl) { Debug.Assert(interfaceMethod.Signature.IsStatic); MetadataType interfaceType = (MetadataType)interfaceMethod.OwningType; bool foundInterface = IsInterfaceImplementedOnType(currentType, interfaceType); if (foundInterface) { DefaultInterfaceMethodResolution resolution = ResolveInterfaceMethodToDefaultImplementationOnType(interfaceMethod, currentType, out impl); if (resolution != DefaultInterfaceMethodResolution.None) { return(resolution); } } MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); foreach (TypeDesc iface in currentType.RuntimeInterfaces) { if (iface.HasSameTypeDefinition(interfaceType) && iface.CanCastTo(interfaceType)) { MethodDesc variantMethod = iface.FindMethodOnTypeWithMatchingTypicalMethod(interfaceMethodDefinition); Debug.Assert(variantMethod != null); if (interfaceMethod != interfaceMethodDefinition) { variantMethod = variantMethod.MakeInstantiatedMethod(interfaceMethod.Instantiation); } DefaultInterfaceMethodResolution resolution = ResolveInterfaceMethodToDefaultImplementationOnType(variantMethod, currentType, out impl); if (resolution != DefaultInterfaceMethodResolution.None) { return(resolution); } } } impl = null; return(DefaultInterfaceMethodResolution.None); }
/// <summary> /// Gets the shared runtime determined form of the method. This is a canonical form of the method /// where generic arguments of the method and the owning type have been converted to runtime determined types. /// </summary> public MethodDesc GetSharedRuntimeFormMethodTarget() { MethodDesc result = this; DefType owningType = OwningType as DefType; if (owningType != null) { // First find the method on the shared runtime form of the owning type DefType sharedRuntimeOwningType = owningType.ConvertToSharedRuntimeDeterminedForm(); if (sharedRuntimeOwningType != owningType) { result = Context.GetMethodForInstantiatedType( GetTypicalMethodDefinition(), (InstantiatedType)sharedRuntimeOwningType); } // Now convert the method instantiation to the shared runtime form if (result.HasInstantiation) { MethodDesc uninstantiatedMethod = result.GetMethodDefinition(); bool changed; Instantiation sharedInstantiation = RuntimeDeterminedTypeUtilities.ConvertInstantiationToSharedRuntimeForm( Instantiation, uninstantiatedMethod.Instantiation, out changed); // If either the instantiation changed, or we switched the owning type, we need to find the matching // instantiated method. if (changed || result != this) { result = Context.GetInstantiatedMethod(uninstantiatedMethod, sharedInstantiation); } } } return(result); }
/// <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); }
/// <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> static public MethodDesc TryResolveConstraintMethodApprox(this MetadataType 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; } MetadataType canonMT = constrainedType; 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 = VirtualFunctionResolution.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod, constrainedType); } else if (genInterfaceMethod.IsVirtual) { method = VirtualFunctionResolution.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod, constrainedType); } 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.InstantiateSignature(interfaceType.Instantiation, interfaceMethod.Instantiation); } Debug.Assert(method != null); //assert(!pMD->IsUnboxingStub()); return method; }
private static DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultImplementationOnType(MethodDesc interfaceMethod, MetadataType currentType, out MethodDesc impl) { TypeDesc interfaceMethodOwningType = interfaceMethod.OwningType; MetadataType mostSpecificInterface = null; bool diamondCase = false; impl = null; MethodDesc interfaceMethodDefinition = interfaceMethod.GetMethodDefinition(); DefType[] consideredInterfaces; if (!currentType.IsInterface) { // If this is not an interface, only things on the interface list could provide // default implementations. consideredInterfaces = currentType.RuntimeInterfaces; } else { // If we're asking about an interface, include the interface in the list. consideredInterfaces = new DefType[currentType.RuntimeInterfaces.Length + 1]; Array.Copy(currentType.RuntimeInterfaces, consideredInterfaces, currentType.RuntimeInterfaces.Length); consideredInterfaces[consideredInterfaces.Length - 1] = (DefType)currentType.InstantiateAsOpen(); } foreach (MetadataType runtimeInterface in consideredInterfaces) { if (runtimeInterface == interfaceMethodOwningType) { // Also consider the default interface method implementation on the interface itself // if we don't have anything else yet if (mostSpecificInterface == null && !interfaceMethod.IsAbstract) { mostSpecificInterface = runtimeInterface; impl = interfaceMethodDefinition; } } else if (Array.IndexOf(runtimeInterface.RuntimeInterfaces, interfaceMethodOwningType) != -1) { // This interface might provide a default implementation MethodImplRecord[] possibleImpls = runtimeInterface.FindMethodsImplWithMatchingDeclName(interfaceMethod.Name); if (possibleImpls != null) { foreach (MethodImplRecord implRecord in possibleImpls) { if (implRecord.Decl == interfaceMethodDefinition) { // This interface provides a default implementation. // Is it also most specific? if (mostSpecificInterface == null || Array.IndexOf(runtimeInterface.RuntimeInterfaces, mostSpecificInterface) != -1) { mostSpecificInterface = runtimeInterface; impl = implRecord.Body; diamondCase = false; } else if (Array.IndexOf(mostSpecificInterface.RuntimeInterfaces, runtimeInterface) == -1) { diamondCase = true; } break; } } } } } if (diamondCase) { impl = null; return(DefaultInterfaceMethodResolution.Diamond); } else if (impl == null) { return(DefaultInterfaceMethodResolution.None); } else if (impl.IsAbstract) { impl = null; return(DefaultInterfaceMethodResolution.Reabstraction); } if (interfaceMethod != interfaceMethodDefinition) { impl = impl.MakeInstantiatedMethod(interfaceMethod.Instantiation); } return(DefaultInterfaceMethodResolution.DefaultImplementation); }
/// <summary> /// Replace some of the types in a method's construction with a new set of types. /// Does not replace the open generics that may be instantiated over in this type. /// /// For instance, Given MyType<object, int[]>.Function<short>(), /// an array of types to replace such as {int,short}, and /// an array of replacement types such as {string,char}. /// The result shall be MyType<object, string[]>.Function<char> /// /// This function cannot be used to replace MyType in the above example. /// </summary> public static MethodDesc ReplaceTypesInConstructionOfMethod(this MethodDesc method, TypeDesc[] typesToReplace, TypeDesc[] replacementTypes) { TypeDesc newOwningType = method.OwningType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes); MethodDesc methodOnOwningType = null; bool owningTypeChanged = false; if (newOwningType == method.OwningType) { methodOnOwningType = method.GetMethodDefinition(); } else { methodOnOwningType = TypeSystemHelpers.FindMethodOnExactTypeWithMatchingTypicalMethod(newOwningType, method); owningTypeChanged = true; } MethodDesc result; if (!method.HasInstantiation) { result = methodOnOwningType; } else { Debug.Assert(method is InstantiatedMethod); TypeDesc[] newInstantiation = null; int instantiationIndex = 0; for (; instantiationIndex < method.Instantiation.Length; instantiationIndex++) { TypeDesc oldType = method.Instantiation[instantiationIndex]; TypeDesc newType = oldType.ReplaceTypesInConstructionOfType(typesToReplace, replacementTypes); if ((oldType != newType) || (newInstantiation != null)) { if (newInstantiation == null) { newInstantiation = new TypeDesc[method.Instantiation.Length]; for (int i = 0; i < instantiationIndex; i++) { newInstantiation[i] = method.Instantiation[i]; } } newInstantiation[instantiationIndex] = newType; } } if (newInstantiation != null) { result = method.Context.GetInstantiatedMethod(methodOnOwningType, new Instantiation(newInstantiation)); } else if (owningTypeChanged) { result = method.Context.GetInstantiatedMethod(methodOnOwningType, method.Instantiation); } else { result = method; } } return(result); }