public bool ConversionToCanonFormIsAChange(RuntimeTypeHandle[] genericArgHandles, CanonicalFormKind kind) { // Todo: support for universal canon type? TypeSystemContext context = TypeSystemContextFactory.Create(); Instantiation genericArgs = context.ResolveRuntimeTypeHandles(genericArgHandles); bool result; context.ConvertInstantiationToCanonForm(genericArgs, kind, out result); TypeSystemContextFactory.Recycle(context); return result; }
/// <summary> /// Compute the canonical instantiation of a dynamic invoke thunk needed to invoke a method /// This algorithm is shared with the runtime, so if a thunk requires generic instantiation /// to be used, it must match this algorithm, and cannot be different with different MetadataManagers /// NOTE: This function may return null in cases where an exact instantiation does not exist. (Universal Generics) /// </summary> protected MethodDesc InstantiateCanonicalDynamicInvokeMethodForMethod(MethodDesc thunk, MethodDesc method) { if (thunk.Instantiation.Length == 0) { // nothing to instantiate return(thunk); } MethodSignature sig = method.Signature; TypeSystemContext context = method.Context; // // Instantiate the generic thunk over the parameters and the return type of the target method // TypeDesc[] instantiation = Internal.IL.Stubs.DynamicInvokeMethodThunk.GetThunkInstantiationForMethod(method); Debug.Assert(thunk.Instantiation.Length == instantiation.Length); // Check if at least one of the instantiation arguments is a universal canonical type, and if so, we // won't create a dynamic invoker instantiation. The arguments will be interpreted at runtime by the // calling convention converter during the dynamic invocation foreach (TypeDesc type in instantiation) { if (type.IsCanonicalSubtype(CanonicalFormKind.Universal)) { return(null); } } // If the thunk ends up being shared code, return the canonical method body. // The concrete dictionary for the thunk will be built at runtime and is not interesting for the compiler. Instantiation canonInstantiation = context.ConvertInstantiationToCanonForm(new Instantiation(instantiation), CanonicalFormKind.Specific); MethodDesc instantiatedDynamicInvokeMethod = thunk.Context.GetInstantiatedMethod(thunk, canonInstantiation); return(instantiatedDynamicInvokeMethod); }
/// <summary> /// Compute the canonical instantiation of a dynamic invoke thunk needed to invoke a method /// This algorithm is shared with the runtime, so if a thunk requires generic instantiation /// to be used, it must match this algorithm, and cannot be different with different MetadataManagers /// NOTE: This function may return null in cases where an exact instantiation does not exist. (Universal Generics) /// </summary> protected MethodDesc InstantiateCanonicalDynamicInvokeMethodForMethod(MethodDesc thunk, MethodDesc method) { if (thunk.Instantiation.Length == 0) { // nothing to instantiate return(thunk); } MethodSignature sig = method.Signature; TypeSystemContext context = method.Context; // // Instantiate the generic thunk over the parameters and the return type of the target method // ParameterMetadata[] paramMetadata = null; TypeDesc[] instantiation = new TypeDesc[sig.ReturnType.IsVoid ? sig.Length : sig.Length + 1]; Debug.Assert(thunk.Instantiation.Length == instantiation.Length); for (int i = 0; i < sig.Length; i++) { TypeDesc parameterType = sig[i]; if (parameterType.IsByRef) { // strip ByRefType off the parameter (the method already has ByRef in the signature) parameterType = ((ByRefType)parameterType).ParameterType; Debug.Assert(!parameterType.IsPointer); // TODO: support for methods returning pointer types - https://github.com/dotnet/corert/issues/2113 } else if (parameterType.IsPointer || parameterType.IsFunctionPointer) { // For pointer typed parameters, instantiate the method over IntPtr parameterType = context.GetWellKnownType(WellKnownType.IntPtr); } else if (parameterType.IsEnum) { // If the invoke method takes an enum as an input parameter and there is no default value for // that paramter, we don't need to specialize on the exact enum type (we only need to specialize // on the underlying integral type of the enum.) if (paramMetadata == null) { paramMetadata = method.GetParameterMetadata(); } bool hasDefaultValue = false; foreach (var p in paramMetadata) { // Parameter metadata indexes are 1-based (0 is reserved for return "parameter") if (p.Index == (i + 1) && p.HasDefault) { hasDefaultValue = true; break; } } if (!hasDefaultValue) { parameterType = parameterType.UnderlyingType; } } instantiation[i] = parameterType; } if (!sig.ReturnType.IsVoid) { TypeDesc returnType = sig.ReturnType; Debug.Assert(!returnType.IsByRef); // If the invoke method return an object reference, we don't need to specialize on the // exact type of the object reference, as the behavior is not different. if ((returnType.IsDefType && !returnType.IsValueType) || returnType.IsArray) { returnType = context.GetWellKnownType(WellKnownType.Object); } instantiation[sig.Length] = returnType; } Debug.Assert(thunk.Instantiation.Length == instantiation.Length); // Check if at least one of the instantiation arguments is a universal canonical type, and if so, we // won't create a dynamic invoker instantiation. The arguments will be interpreted at runtime by the // calling convention converter during the dynamic invocation foreach (TypeDesc type in instantiation) { if (type.IsCanonicalSubtype(CanonicalFormKind.Universal)) { return(null); } } // If the thunk ends up being shared code, return the canonical method body. // The concrete dictionary for the thunk will be built at runtime and is not interesting for the compiler. Instantiation canonInstantiation = context.ConvertInstantiationToCanonForm(new Instantiation(instantiation), CanonicalFormKind.Specific); MethodDesc instantiatedDynamicInvokeMethod = thunk.Context.GetInstantiatedMethod(thunk, canonInstantiation); return(instantiatedDynamicInvokeMethod); }