internal unsafe override void Prepare(TypeBuilder builder) { _methodToUseForInstantiatingParameters = Method; IntPtr exactFunctionPointer; bool canUseRetrieveExactFunctionPointerIfPossible = false; // RetrieveExactFunctionPointerIfPossible always gets the unboxing stub if possible if (Method.UnboxingStub) canUseRetrieveExactFunctionPointerIfPossible = true; else if (!Method.OwningType.IsValueType) // If the owning type isn't a valuetype, concerns about unboxing stubs are moot canUseRetrieveExactFunctionPointerIfPossible = true; else if (TypeLoaderEnvironment.Instance.IsStaticMethodSignature(MethodSignature)) // Static methods don't have unboxing stub concerns canUseRetrieveExactFunctionPointerIfPossible = true; if (canUseRetrieveExactFunctionPointerIfPossible && builder.RetrieveExactFunctionPointerIfPossible(Method, out exactFunctionPointer)) { // If we succeed in finding a non-shareable function pointer for this method, it means // that we found a method body for it that was statically compiled. We'll use that body // instead of the universal canonical method pointer Debug.Assert(exactFunctionPointer != IntPtr.Zero && exactFunctionPointer != Method.FunctionPointer && exactFunctionPointer != Method.UsgFunctionPointer); _exactFunctionPointer = exactFunctionPointer; } else { // There is no exact function pointer available. This means that we'll have to // build a method dictionary for the method instantiation, and use the shared canonical // function pointer that was parsed from native layout. _exactFunctionPointer = IntPtr.Zero; builder.PrepareMethod(Method); // Check whether we have already resolved a canonical or universal match IntPtr addressToUse; TypeLoaderEnvironment.MethodAddressType foundAddressType; if (Method.FunctionPointer != IntPtr.Zero) { addressToUse = Method.FunctionPointer; foundAddressType = TypeLoaderEnvironment.MethodAddressType.Canonical; } else if (Method.UsgFunctionPointer != IntPtr.Zero) { addressToUse = Method.UsgFunctionPointer; foundAddressType = TypeLoaderEnvironment.MethodAddressType.UniversalCanonical; } else { // No previous match, new lookup is needed IntPtr fnptr; IntPtr unboxingStub; MethodDesc searchMethod = Method; if (Method.UnboxingStub) { // Find the function that isn't an unboxing stub, note the first parameter which is false searchMethod = searchMethod.Context.ResolveGenericMethodInstantiation(false, (DefType)Method.OwningType, Method.NameAndSignature, Method.Instantiation, IntPtr.Zero, false); } if (!TypeLoaderEnvironment.TryGetMethodAddressFromMethodDesc(searchMethod, out fnptr, out unboxingStub, out foundAddressType)) { Environment.FailFast("Unable to find method address for method:" + Method.ToString()); } if (Method.UnboxingStub) { addressToUse = unboxingStub; } else { addressToUse = fnptr; } if (foundAddressType == TypeLoaderEnvironment.MethodAddressType.Canonical || foundAddressType == TypeLoaderEnvironment.MethodAddressType.UniversalCanonical) { // Cache the resolved canonical / universal pointer in the MethodDesc // Actually it would simplify matters here if the MethodDesc held just one pointer // and the lookup type enumeration value. Method.SetFunctionPointer( addressToUse, foundAddressType == TypeLoaderEnvironment.MethodAddressType.UniversalCanonical); } } // Look at the resolution type and check whether we can set up the ExactFunctionPointer upfront switch (foundAddressType) { case TypeLoaderEnvironment.MethodAddressType.Exact: _exactFunctionPointer = addressToUse; break; case TypeLoaderEnvironment.MethodAddressType.Canonical: { bool methodRequestedIsCanonical = Method.IsCanonicalMethod(CanonicalFormKind.Specific); bool requestedMethodNeedsDictionaryWhenCalledAsCanonical = NeedsDictionaryParameterToCallCanonicalVersion(Method); if (!requestedMethodNeedsDictionaryWhenCalledAsCanonical || methodRequestedIsCanonical) { _exactFunctionPointer = addressToUse; } break; } case TypeLoaderEnvironment.MethodAddressType.UniversalCanonical: { if (Method.IsCanonicalMethod(CanonicalFormKind.Specific) && !NeedsDictionaryParameterToCallCanonicalVersion(Method) && !TypeLoaderEnvironment.MethodSignatureHasVarsNeedingCallingConventionConverter_MethodSignature( Method.GetTypicalMethodDefinition().Signature)) { _exactFunctionPointer = addressToUse; } break; } default: Environment.FailFast("Unexpected method address type"); return; } if (_exactFunctionPointer == IntPtr.Zero) { // We have exhausted exact resolution options so we must resort to calling // convention conversion. Prepare the type parameters of the method so that // the calling convention converter can have RuntimeTypeHandle's to work with. // For canonical methods, convert paramters to their CanonAlike form // as the Canonical RuntimeTypeHandle's are not permitted to exist. Debug.Assert(!Method.IsCanonicalMethod(CanonicalFormKind.Universal)); bool methodRequestedIsCanonical = Method.IsCanonicalMethod(CanonicalFormKind.Specific); MethodDesc canonAlikeForm; if (methodRequestedIsCanonical) { canonAlikeForm = Method.ReplaceTypesInConstructionOfMethod(Method.Context.CanonTypeArray, Method.Context.CanonAlikeTypeArray); } else { canonAlikeForm = Method; } foreach (TypeDesc t in canonAlikeForm.Instantiation) { builder.PrepareType(t); } foreach (TypeDesc t in canonAlikeForm.OwningType.Instantiation) { builder.PrepareType(t); } if (!(Method.GetTypicalMethodDefinition() is RuntimeMethodDesc)) { // Also, prepare all of the argument types as will be needed by the calling convention converter MethodSignature signature = canonAlikeForm.Signature; for (int i = 0; i < signature.Length; i++) { TypeDesc t = signature[i]; if (t is ByRefType) builder.PrepareType(((ByRefType)t).ParameterType); else builder.PrepareType(t); } if (signature.ReturnType is ByRefType) builder.PrepareType((ByRefType)signature.ReturnType); else builder.PrepareType(signature.ReturnType); } _universalCanonImplementationOfCanonMethod = methodRequestedIsCanonical; _methodToUseForInstantiatingParameters = canonAlikeForm; } } // By the time we reach here, we should always have a function pointer of some form Debug.Assert((_exactFunctionPointer != IntPtr.Zero) || (Method.FunctionPointer != IntPtr.Zero) || (Method.UsgFunctionPointer != IntPtr.Zero)); }