Example #1
0
        private static TypeDesc TryGetTypeTemplate_Internal(TypeDesc concreteType, CanonicalFormKind kind, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken)
        {
            nativeLayoutInfoModule = null;
            nativeLayoutInfoToken  = 0;
            var canonForm = concreteType.ConvertToCanonForm(kind);
            var hashCode  = canonForm.GetHashCode();

            foreach (NativeFormatModuleInfo moduleInfo in ModuleList.EnumerateModules())
            {
                ExternalReferencesTable externalFixupsTable;
                NativeHashtable         typeTemplatesHashtable = LoadHashtable(moduleInfo, ReflectionMapBlob.TypeTemplateMap, out externalFixupsTable);

                if (typeTemplatesHashtable.IsNull)
                {
                    continue;
                }

                var enumerator = typeTemplatesHashtable.Lookup(hashCode);

                NativeParser entryParser;
                while (!(entryParser = enumerator.GetNext()).IsNull)
                {
                    RuntimeTypeHandle candidateTemplateTypeHandle = externalFixupsTable.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
                    TypeDesc          candidateTemplate           = concreteType.Context.ResolveRuntimeTypeHandle(candidateTemplateTypeHandle);

                    if (canonForm == candidateTemplate.ConvertToCanonForm(kind))
                    {
                        TypeLoaderLogger.WriteLine("Found template for type " + concreteType.ToString() + ": " + candidateTemplate.ToString());
                        nativeLayoutInfoToken = entryParser.GetUnsigned();
                        if (nativeLayoutInfoToken == BadTokenFixupValue)
                        {
                            // TODO: once multifile gets fixed up, make this throw a BadImageFormatException
                            TypeLoaderLogger.WriteLine("ERROR: template not fixed up, skipping");
                            continue;
                        }

                        Debug.Assert(
                            (kind != CanonicalFormKind.Universal) ||
                            (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.ConvertToCanonForm(kind)));

                        nativeLayoutInfoModule = moduleInfo;
                        return(candidateTemplate);
                    }
                }
            }

            TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for type " + concreteType.ToString());
            return(null);
        }
Example #2
0
        //
        // Returns the template method for a generic method instantation
        //
        public static InstantiatedMethod TryGetGenericMethodTemplate(InstantiatedMethod concreteMethod, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken)
        {
            // First, see if there is a specific canonical template
            InstantiatedMethod result = TryGetGenericMethodTemplate_Internal(concreteMethod, CanonicalFormKind.Specific, out nativeLayoutInfoModule, out nativeLayoutInfoToken);

            // If not found, see if there's a universal canonical template
            if (result == null)
            {
                result = TryGetGenericMethodTemplate_Internal(concreteMethod, CanonicalFormKind.Universal, out nativeLayoutInfoModule, out nativeLayoutInfoToken);
            }

            return(result);
        }
Example #3
0
 /// <summary>
 /// Initialize ExternalReferencesTable using the CommonFixupsTable metadata blob on a given module.
 /// </summary>
 /// <param name="moduleHandle">Module handle is used to locate the CommonFixupsTable blob</param>
 /// <returns>true when the CommonFixupsTable blob was found in the given module, false when not</returns>
 public bool InitializeCommonFixupsTable(NativeFormatModuleInfo module)
 {
     return(Initialize(module, ReflectionMapBlob.CommonFixupsTable));
 }
Example #4
0
        private static InstantiatedMethod TryGetGenericMethodTemplate_Internal(InstantiatedMethod concreteMethod, CanonicalFormKind kind, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken)
        {
            nativeLayoutInfoModule = null;
            nativeLayoutInfoToken  = 0;
            var canonForm = concreteMethod.GetCanonMethodTarget(kind);
            var hashCode  = canonForm.GetHashCode();

            foreach (NativeFormatModuleInfo moduleInfo in ModuleList.EnumerateModules())
            {
                NativeReader nativeLayoutReader = TypeLoaderEnvironment.GetNativeLayoutInfoReader(moduleInfo.Handle);
                if (nativeLayoutReader == null)
                {
                    continue;
                }

                NativeHashtable genericMethodTemplatesHashtable = LoadHashtable(moduleInfo, ReflectionMapBlob.GenericMethodsTemplateMap, out _);

                if (genericMethodTemplatesHashtable.IsNull)
                {
                    continue;
                }

                var context = new NativeLayoutInfoLoadContext
                {
                    _typeSystemContext     = concreteMethod.Context,
                    _typeArgumentHandles   = concreteMethod.OwningType.Instantiation,
                    _methodArgumentHandles = concreteMethod.Instantiation,
                    _module = moduleInfo
                };

                var enumerator = genericMethodTemplatesHashtable.Lookup(hashCode);

                NativeParser entryParser;
                while (!(entryParser = enumerator.GetNext()).IsNull)
                {
                    var methodSignatureParser = new NativeParser(nativeLayoutReader, entryParser.GetUnsigned());

                    // Get the unified generic method holder and convert it to its canonical form
                    var candidateTemplate = (InstantiatedMethod)context.GetMethod(ref methodSignatureParser);
                    Debug.Assert(candidateTemplate.Instantiation.Length > 0);

                    if (canonForm == candidateTemplate.GetCanonMethodTarget(kind))
                    {
                        TypeLoaderLogger.WriteLine("Found template for generic method " + concreteMethod.ToString() + ": " + candidateTemplate.ToString());
                        nativeLayoutInfoModule = moduleInfo;
                        nativeLayoutInfoToken  = entryParser.GetUnsigned();
                        if (nativeLayoutInfoToken == BadTokenFixupValue)
                        {
                            // TODO: once multifile gets fixed up, make this throw a BadImageFormatException
                            TypeLoaderLogger.WriteLine("ERROR: template not fixed up, skipping");
                            continue;
                        }

                        Debug.Assert(
                            (kind != CanonicalFormKind.Universal) ||
                            (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.GetCanonMethodTarget(kind)));

                        return(candidateTemplate);
                    }
                }
            }

            TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for generic method " + concreteMethod.ToString());
            return(null);
        }
Example #5
0
        /// <summary>
        /// Attempt to convert the dispatch cell to a metadata token to a more efficient vtable dispatch or interface/slot dispatch.
        /// Failure to convert is not a correctness issue. We also support performing a dispatch based on metadata token alone.
        /// </summary>
        private static DispatchCellInfo ConvertDispatchCellInfo_Inner(NativeFormatModuleInfo module, DispatchCellInfo cellInfo)
        {
            Debug.Assert(cellInfo.CellType == DispatchCellType.MetadataToken);

            TypeSystemContext context = TypeSystemContextFactory.Create();

            MethodDesc targetMethod = context.ResolveMetadataUnit(module).GetMethod(cellInfo.MetadataToken.AsHandle(), null);

            Debug.Assert(!targetMethod.HasInstantiation); // At this time we do not support generic virtuals through the dispatch mechanism
            Debug.Assert(targetMethod.IsVirtual);
            if (targetMethod.OwningType.IsInterface)
            {
                if (!LazyVTableResolver.TryGetInterfaceSlotNumberFromMethod(targetMethod, out cellInfo.InterfaceSlot))
                {
                    // Unable to resolve interface method. Fail, by not mutating cellInfo
                    return(cellInfo);
                }

                if (!targetMethod.OwningType.RetrieveRuntimeTypeHandleIfPossible())
                {
                    new TypeBuilder().BuildType(targetMethod.OwningType);
                }

                cellInfo.CellType      = DispatchCellType.InterfaceAndSlot;
                cellInfo.InterfaceType = targetMethod.OwningType.RuntimeTypeHandle.ToIntPtr();
                cellInfo.MetadataToken = 0;
            }
            else
            {
                // Virtual function case, attempt to resolve to a VTable slot offset.
                // If the offset is less than 4096 update the cellInfo
#if DEBUG
                // The path of resolving a metadata token at dispatch time is relatively rare in practice.
                // Force it to occur in debug builds with much more regularity
                if ((s_ConvertDispatchCellInfoCounter % 16) == 0)
                {
                    s_ConvertDispatchCellInfoCounter++;
                    TypeSystemContextFactory.Recycle(context);
                    return(cellInfo);
                }
                s_ConvertDispatchCellInfoCounter++;
#endif

                int slotIndexOfMethod = LazyVTableResolver.VirtualMethodToSlotIndex(targetMethod);
                int vtableOffset      = -1;
                if (slotIndexOfMethod >= 0)
                {
                    vtableOffset = LazyVTableResolver.SlotIndexToEETypeVTableOffset(slotIndexOfMethod);
                }
                if ((vtableOffset < 4096) && (vtableOffset != -1))
                {
                    cellInfo.CellType      = DispatchCellType.VTableOffset;
                    cellInfo.VTableOffset  = checked ((uint)vtableOffset);
                    cellInfo.MetadataToken = 0;
                }
                // Otherwise, do nothing, and resolve with a metadata dispatch later
            }

            TypeSystemContextFactory.Recycle(context);
            return(cellInfo);
        }
Example #6
0
 /// <summary>
 /// Initialize ExternalReferencesTable using the NativeStatics metadata blob on a given module.
 /// </summary>
 /// <param name="moduleHandle">Module handle is used to locate the NativeStatics blob</param>
 /// <returns>true when the NativeStatics blob was found in the given module, false when not</returns>
 public bool InitializeNativeStatics(NativeFormatModuleInfo module)
 {
     return(Initialize(module, ReflectionMapBlob.NativeStatics));
 }
Example #7
0
        private bool CompareMethodSigs(NativeParser parser1, NativeFormatModuleInfo moduleHandle1, NativeParser parser2, NativeFormatModuleInfo moduleHandle2)
        {
            MethodCallingConvention callingConvention1 = (MethodCallingConvention)parser1.GetUnsigned();
            MethodCallingConvention callingConvention2 = (MethodCallingConvention)parser2.GetUnsigned();

            if (callingConvention1 != callingConvention2)
            {
                return(false);
            }

            if ((callingConvention1 & MethodCallingConvention.Generic) == MethodCallingConvention.Generic)
            {
                if (parser1.GetUnsigned() != parser2.GetUnsigned())
                {
                    return(false);
                }
            }

            uint parameterCount1 = parser1.GetUnsigned();
            uint parameterCount2 = parser2.GetUnsigned();

            if (parameterCount1 != parameterCount2)
            {
                return(false);
            }

            // Compare one extra parameter to account for the return type
            for (uint i = 0; i <= parameterCount1; i++)
            {
                if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2))
                {
                    return(false);
                }
            }

            return(true);
        }
Example #8
0
        private bool CompareTypeSigs(ref NativeParser parser1, NativeFormatModuleInfo moduleHandle1, ref NativeParser parser2, NativeFormatModuleInfo moduleHandle2)
        {
            // startOffset lets us backtrack to the TypeSignatureKind for external types since the TypeLoader
            // expects to read it in.
            uint data1;
            uint startOffset1       = parser1.Offset;
            var  typeSignatureKind1 = parser1.GetTypeSignatureKind(out data1);

            // If the parser is at a lookback type, get a new parser for it and recurse.
            // Since we haven't read the element type of parser2 yet, we just pass it in unchanged
            if (typeSignatureKind1 == TypeSignatureKind.Lookback)
            {
                NativeParser lookbackParser1 = parser1.GetLookbackParser(data1);
                return(CompareTypeSigs(ref lookbackParser1, moduleHandle1, ref parser2, moduleHandle2));
            }

            uint data2;
            uint startOffset2       = parser2.Offset;
            var  typeSignatureKind2 = parser2.GetTypeSignatureKind(out data2);

            // If parser2 is a lookback type, we need to rewind parser1 to its startOffset1
            // before recursing.
            if (typeSignatureKind2 == TypeSignatureKind.Lookback)
            {
                NativeParser lookbackParser2 = parser2.GetLookbackParser(data2);
                parser1 = new NativeParser(parser1.Reader, startOffset1);
                return(CompareTypeSigs(ref parser1, moduleHandle1, ref lookbackParser2, moduleHandle2));
            }

            if (typeSignatureKind1 != typeSignatureKind2)
            {
                return(false);
            }

            switch (typeSignatureKind1)
            {
            case TypeSignatureKind.Lookback:
            {
                //  Recursion above better have removed all lookbacks
                Debug.Assert(false, "Unexpected lookback type");
                return(false);
            }

            case TypeSignatureKind.Modifier:
            {
                // Ensure the modifier kind (vector, pointer, byref) is the same
                if (data1 != data2)
                {
                    return(false);
                }
                return(CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2));
            }

            case TypeSignatureKind.Variable:
            {
                // variable index is in data
                if (data1 != data2)
                {
                    return(false);
                }
                break;
            }

            case TypeSignatureKind.MultiDimArray:
            {
                // rank is in data
                if (data1 != data2)
                {
                    return(false);
                }

                if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2))
                {
                    return(false);
                }

                uint boundCount1 = parser1.GetUnsigned();
                uint boundCount2 = parser2.GetUnsigned();
                if (boundCount1 != boundCount2)
                {
                    return(false);
                }

                for (uint i = 0; i < boundCount1; i++)
                {
                    if (parser1.GetUnsigned() != parser2.GetUnsigned())
                    {
                        return(false);
                    }
                }

                uint lowerBoundCount1 = parser1.GetUnsigned();
                uint lowerBoundCount2 = parser2.GetUnsigned();
                if (lowerBoundCount1 != lowerBoundCount2)
                {
                    return(false);
                }

                for (uint i = 0; i < lowerBoundCount1; i++)
                {
                    if (parser1.GetUnsigned() != parser2.GetUnsigned())
                    {
                        return(false);
                    }
                }
                break;
            }

            case TypeSignatureKind.FunctionPointer:
            {
                // callingConvention is in data
                if (data1 != data2)
                {
                    return(false);
                }
                uint argCount1 = parser1.GetUnsigned();
                uint argCount2 = parser2.GetUnsigned();
                if (argCount1 != argCount2)
                {
                    return(false);
                }
                for (uint i = 0; i < argCount1; i++)
                {
                    if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2))
                    {
                        return(false);
                    }
                }
                break;
            }

            case TypeSignatureKind.Instantiation:
            {
                // Type parameter count is in data
                if (data1 != data2)
                {
                    return(false);
                }

                if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2))
                {
                    return(false);
                }

                for (uint i = 0; i < data1; i++)
                {
                    if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2))
                    {
                        return(false);
                    }
                }
                break;
            }

            case TypeSignatureKind.External:
            {
                RuntimeTypeHandle typeHandle1 = GetExternalTypeHandle(moduleHandle1, data1);
                RuntimeTypeHandle typeHandle2 = GetExternalTypeHandle(moduleHandle2, data2);
                if (!typeHandle1.Equals(typeHandle2))
                {
                    return(false);
                }

                break;
            }

            default:
                return(false);
            }
            return(true);
        }
Example #9
0
        private bool FindMatchingInterfaceSlot(NativeFormatModuleInfo module, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch)
        {
            uint numTargetImplementations = entryParser.GetUnsigned();

            for (uint j = 0; j < numTargetImplementations; j++)
            {
                uint nameAndSigToken = extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned());
                MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken);
                RuntimeTypeHandle      targetTypeHandle             = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());

#if REFLECTION_EXECUTION_TRACE
                ReflectionExecutionLogger.WriteLine("    Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle));
#endif

                uint numIfaceImpls = entryParser.GetUnsigned();

                for (uint k = 0; k < numIfaceImpls; k++)
                {
                    RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());

                    uint numIfaceSigs = entryParser.GetUnsigned();

                    if (!openTargetTypeHandle.Equals(implementingTypeHandle))
                    {
                        // Skip over signatures data
                        for (uint l = 0; l < numIfaceSigs; l++)
                        {
                            entryParser.GetUnsigned();
                        }

                        continue;
                    }

                    for (uint l = 0; l < numIfaceSigs; l++)
                    {
                        RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle);

                        NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned()));

                        if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle))
                        {
                            Debug.Assert(!currentIfaceTypeHandle.IsNull());

                            if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) ||
                                (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle)))
                            {
#if REFLECTION_EXECUTION_TRACE
                                ReflectionExecutionLogger.WriteLine("    " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!");
#endif
                                // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller
                                declaringType          = targetTypeHandle;
                                methodNameAndSignature = targetMethodNameAndSignature;
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Example #10
0
        /// <summary>
        /// IF THESE SEMANTICS EVER CHANGE UPDATE THE LOGIC WHICH DEFINES THIS BEHAVIOR IN
        /// THE DYNAMIC TYPE LOADER AS WELL AS THE COMPILER.
        /// (There is a version of this in UniversalGenericParameterLayout.cs that must be kept in sync with this.)
        ///
        /// Parameter's are considered to have type layout dependent on their generic instantiation
        /// if the type of the parameter in its signature is a type variable, or if the type is a generic
        /// structure which meets 2 characteristics:
        /// 1. Structure size/layout is affected by the size/layout of one or more of its generic parameters
        /// 2. One or more of the generic parameters is a type variable, or a generic structure which also recursively
        ///    would satisfy constraint 2. (Note, that in the recursion case, whether or not the structure is affected
        ///    by the size/layout of its generic parameters is not investigated.)
        ///
        /// Examples parameter types, and behavior.
        ///
        /// T = true
        /// List[T] = false
        /// StructNotDependentOnArgsForSize[T] = false
        /// GenStructDependencyOnArgsForSize[T] = true
        /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[T]] = true
        /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[List[T]]]] = false
        ///
        /// Example non-parameter type behavior
        /// T = true
        /// List[T] = false
        /// StructNotDependentOnArgsForSize[T] = *true*
        /// GenStructDependencyOnArgsForSize[T] = true
        /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[T]] = true
        /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[List[T]]]] = false
        /// </summary>
        private bool TypeSignatureHasVarsNeedingCallingConventionConverter(ref NativeParser parser, NativeFormatModuleInfo moduleHandle, TypeSystemContext context, HasVarsInvestigationLevel investigationLevel)
        {
            uint data;
            var  kind = parser.GetTypeSignatureKind(out data);

            switch (kind)
            {
            case TypeSignatureKind.External: return(false);

            case TypeSignatureKind.Variable: return(true);

            case TypeSignatureKind.Lookback:
            {
                var lookbackParser = parser.GetLookbackParser(data);
                return(TypeSignatureHasVarsNeedingCallingConventionConverter(ref lookbackParser, moduleHandle, context, investigationLevel));
            }

            case TypeSignatureKind.Instantiation:
            {
                RuntimeTypeHandle genericTypeDef;
                if (!TryGetTypeFromSimpleTypeSignature(ref parser, moduleHandle, out genericTypeDef))
                {
                    Debug.Assert(false);
                    return(true);           // Returning true will prevent further reading from the native parser
                }

                if (!RuntimeAugments.IsValueType(genericTypeDef))
                {
                    // Reference types are treated like pointers. No calling convention conversion needed. Just consume the rest of the signature.
                    for (uint i = 0; i < data; i++)
                    {
                        TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore);
                    }
                    return(false);
                }
                else
                {
                    bool result = false;
                    for (uint i = 0; i < data; i++)
                    {
                        result = TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.NotParameter) || result;
                    }

                    if ((result == true) && (investigationLevel == HasVarsInvestigationLevel.Parameter))
                    {
                        if (!TryComputeHasInstantiationDeterminedSize(genericTypeDef, context, out result))
                        {
                            Environment.FailFast("Unable to setup calling convention converter correctly");
                        }

                        return(result);
                    }

                    return(result);
                }
            }

            case TypeSignatureKind.Modifier:
            {
                // Arrays, pointers and byref types signatures are treated as pointers, not requiring calling convention conversion.
                // Just consume the parameter type from the stream and return false;
                TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore);
                return(false);
            }

            case TypeSignatureKind.MultiDimArray:
            {
                // No need for a calling convention converter for this case. Just consume the signature from the stream.

                TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore);

                uint boundCount = parser.GetUnsigned();
                for (uint i = 0; i < boundCount; i++)
                {
                    parser.GetUnsigned();
                }

                uint lowerBoundCount = parser.GetUnsigned();
                for (uint i = 0; i < lowerBoundCount; i++)
                {
                    parser.GetUnsigned();
                }
            }
                return(false);

            case TypeSignatureKind.FunctionPointer:
            {
                // No need for a calling convention converter for this case. Just consume the signature from the stream.

                uint argCount = parser.GetUnsigned();
                for (uint i = 0; i < argCount; i++)
                {
                    TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore);
                }
            }
                return(false);

            default:
                parser.ThrowBadImageFormatException();
                return(true);
            }
        }
        /// <summary>
        /// Get the virtual slot index of a given virtual method. (This is only valid for non-interface virtuals)
        /// </summary>
        /// <param name="virtualMethod">virtual method to get slot index of</param>
        /// <returns>slot index, or -1</returns>
        public static int VirtualMethodToSlotIndex(MethodDesc virtualMethod)
        {
            Debug.Assert(virtualMethod.IsVirtual);
            Debug.Assert(!virtualMethod.OwningType.IsInterface);

            MethodDesc definingMethod = virtualMethod;

            // If not newslot, make sure we've got the defining method here
            if (!definingMethod.IsNewSlot)
            {
                definingMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(definingMethod);
            }
            TypeDesc definingType = definingMethod.OwningType;

            // Two possible cases for determining slot index that will work
            //  1. The definingType is a R2R type with full metadata. Compute the MethodDesc, by scanning the list of virtuals present in metadata. Its possible to not get a slot index. In that case return -1
            //  2. The definingType is pregenerated, but we can go from metadata to slot index via the runtime mapping tables.

            if (!IsPregeneratedOrTemplateTypeLoaded(definingType))
            {
                // Case 1

                MetadataType definingMetadataType = (MetadataType)definingType;
                int          baseTypeSlotCount    = 0;

                if (definingMetadataType.BaseType != null)
                {
                    unsafe
                    {
                        if (definingMetadataType.BaseType.RetrieveRuntimeTypeHandleIfPossible())
                        {
                            baseTypeSlotCount = definingMetadataType.BaseType.GetRuntimeTypeHandle().ToEETypePtr()->NumVtableSlots;
                        }
                        else
                        {
                            baseTypeSlotCount = definingMetadataType.BaseType.GetOrCreateTypeBuilderState().NumVTableSlots;
                        }
                    }
                }

                int currentSlot = baseTypeSlotCount;

                if (definingMetadataType.ConvertToCanonForm(CanonicalFormKind.Specific).IsCanonicalSubtype(CanonicalFormKind.Specific))
                {
                    // Deal with the space reserved for the canonical dictionary
                    currentSlot++;
                }

                foreach (MethodDesc method in definingMetadataType.GetMethods())
                {
                    if (!MethodDefinesVTableSlot(method))
                    {
                        continue;
                    }

                    if (method == definingMethod)
                    {
                        return(currentSlot);
                    }
                    else
                    {
                        currentSlot++;
                    }
                }

                // No slot index defined.
                return(-1);
            }
            else
            {
                // Case 2, pregenerated type
                TypeSystem.NativeFormat.NativeFormatMethod definingMethodOpenType = (TypeSystem.NativeFormat.NativeFormatMethod)definingMethod.GetTypicalMethodDefinition();
                MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer(
                    definingMethodOpenType.MetadataReader, definingMethodOpenType.Handle);

                if (!definingType.RetrieveRuntimeTypeHandleIfPossible())
                {
                    new TypeBuilder().BuildType(definingType);
                }

                TypeSystem.NativeFormat.NativeFormatType definingNativeFormatType = (TypeSystem.NativeFormat.NativeFormatType)definingType.GetTypeDefinition();
                NativeFormatModuleInfo moduleToLookIn = definingNativeFormatType.MetadataUnit.RuntimeModuleInfo;

                TypeLoaderEnvironment.VirtualResolveDataResult virtualSlotInfo;
                if (!TypeLoaderEnvironment.TryGetVirtualResolveData(moduleToLookIn, definingType.RuntimeTypeHandle, Array.Empty <RuntimeTypeHandle>(), ref methodSignatureComparer, out virtualSlotInfo))
                {
                    return(-1);
                }

                Debug.Assert(!virtualSlotInfo.IsGVM);
                return(virtualSlotInfo.SlotIndex);
            }
        }
        private bool FindMatchingInterfaceSlot(NativeFormatModuleInfo module, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle instanceTypeHandle, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch, bool defaultMethods)
        {
            uint numTargetImplementations = entryParser.GetUnsigned();

#if GVM_RESOLUTION_TRACE
            Debug.WriteLine(" :: Declaring type = " + GetTypeNameDebug(declaringType));
            Debug.WriteLine(" :: Target type = " + GetTypeNameDebug(openTargetTypeHandle));
#endif

            for (uint j = 0; j < numTargetImplementations; j++)
            {
                uint nameAndSigToken = entryParser.GetUnsigned();

                MethodNameAndSignature targetMethodNameAndSignature = null;
                RuntimeTypeHandle      targetTypeHandle             = default;
                bool isDefaultInterfaceMethodImplementation;

                if (nameAndSigToken != SpecialGVMInterfaceEntry.Diamond && nameAndSigToken != SpecialGVMInterfaceEntry.Reabstraction)
                {
                    targetMethodNameAndSignature           = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken);
                    targetTypeHandle                       = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
                    isDefaultInterfaceMethodImplementation = RuntimeAugments.IsInterface(targetTypeHandle);
#if GVM_RESOLUTION_TRACE
                    Debug.WriteLine("    Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle));
#endif
                }
                else
                {
                    isDefaultInterfaceMethodImplementation = true;
                }

                uint numIfaceImpls = entryParser.GetUnsigned();

                for (uint k = 0; k < numIfaceImpls; k++)
                {
                    RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());

#if GVM_RESOLUTION_TRACE
                    Debug.WriteLine("      -> Current implementing type = " + GetTypeNameDebug(implementingTypeHandle));
#endif

                    uint numIfaceSigs = entryParser.GetUnsigned();

                    if (!openTargetTypeHandle.Equals(implementingTypeHandle) ||
                        defaultMethods != isDefaultInterfaceMethodImplementation)
                    {
                        // Skip over signatures data
                        for (uint l = 0; l < numIfaceSigs; l++)
                        {
                            entryParser.GetUnsigned();
                        }

                        continue;
                    }

                    for (uint l = 0; l < numIfaceSigs; l++)
                    {
                        RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle);

                        NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, entryParser.GetUnsigned());

                        if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle))
                        {
#if GVM_RESOLUTION_TRACE
                            Debug.WriteLine("         -> Current interface on type = " + GetTypeNameDebug(currentIfaceTypeHandle));
#endif
                            Debug.Assert(!currentIfaceTypeHandle.IsNull());

                            if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) ||
                                (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle)))
                            {
#if GVM_RESOLUTION_TRACE
                                Debug.WriteLine("    " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!");
#endif
                                if (targetMethodNameAndSignature == null)
                                {
                                    if (nameAndSigToken == SpecialGVMInterfaceEntry.Diamond)
                                    {
                                        throw new AmbiguousImplementationException();
                                    }
                                    else
                                    {
                                        Debug.Assert(nameAndSigToken == SpecialGVMInterfaceEntry.Reabstraction);
                                        throw new EntryPointNotFoundException();
                                    }
                                }

                                // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller
                                if (!RuntimeAugments.IsInterface(targetTypeHandle) || !RuntimeAugments.IsGenericTypeDefinition(targetTypeHandle))
                                {
                                    // Not a default interface method or default interface method on a non-generic type.
                                    // We have a usable type handle.
                                    declaringType = targetTypeHandle;
                                }
                                else if (RuntimeAugments.IsGenericType(currentIfaceTypeHandle) && RuntimeAugments.GetGenericDefinition(currentIfaceTypeHandle).Equals(targetTypeHandle))
                                {
                                    // Default interface method implemented on the same type that declared the slot.
                                    // Use the instantiation as-is from what we found.
                                    declaringType = currentIfaceTypeHandle;
                                }
                                else
                                {
                                    declaringType = default;

                                    // Default interface method implemented on a different generic interface.
                                    // We need to find a usable instantiation. There should be only one match because we
                                    // would be dealing with a diamond otherwise.
                                    int numInstanceInterfaces = RuntimeAugments.GetInterfaceCount(instanceTypeHandle);
                                    for (int instIntfIndex = 0; instIntfIndex < numInstanceInterfaces; instIntfIndex++)
                                    {
                                        RuntimeTypeHandle instIntf = RuntimeAugments.GetInterface(instanceTypeHandle, instIntfIndex);
                                        if (RuntimeAugments.IsGenericType(instIntf) &&
                                            RuntimeAugments.GetGenericDefinition(instIntf).Equals(targetTypeHandle))
                                        {
                                            // Got a potential interface. Check if the implementing interface is in the interface
                                            // list. We don't want IsAssignableFrom because we need an exact match.
                                            int numIntInterfaces = RuntimeAugments.GetInterfaceCount(instIntf);
                                            for (int intIntfIndex = 0; intIntfIndex < numIntInterfaces; intIntfIndex++)
                                            {
                                                if (RuntimeAugments.GetInterface(instIntf, intIntfIndex).Equals(currentIfaceTypeHandle))
                                                {
                                                    Debug.Assert(declaringType.IsNull());
                                                    declaringType = instIntf;
#if !DEBUG
                                                    break;
#endif
                                                }
                                            }
#if !DEBUG
                                            if (!declaringType.IsNull())
                                            {
                                                break;
                                            }
#endif
                                        }
                                    }

                                    Debug.Assert(!declaringType.IsNull());
                                }

                                methodNameAndSignature = targetMethodNameAndSignature;
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Example #13
0
 //
 // Returns the native layout info reader
 //
 internal unsafe NativeReader GetNativeLayoutInfoReader(NativeFormatModuleInfo module)
 {
     return GetNativeLayoutInfoReader(module.Handle);
 }
Example #14
0
        /// <summary>
        /// Register all modules which were added (Registered) to the runtime and are not already registered with the TypeLoader.
        /// </summary>
        /// <param name="moduleType">Type to assign to all new modules.</param>
        public void RegisterNewModules(ModuleType moduleType)
        {
            // prevent multiple threads from registering modules concurrently
            using (LockHolder.Hold(_moduleRegistrationLock))
            {
                // Fetch modules that have already been registered with the runtime
                int loadedModuleCount = RuntimeAugments.GetLoadedModules(null);
                TypeManagerHandle[] loadedModuleHandles = new TypeManagerHandle[loadedModuleCount];
                int loadedModuleCountUpdated            = RuntimeAugments.GetLoadedModules(loadedModuleHandles);
                Debug.Assert(loadedModuleCount == loadedModuleCountUpdated);

                LowLevelList <TypeManagerHandle> newModuleHandles = new LowLevelList <TypeManagerHandle>(loadedModuleHandles.Length);
                foreach (TypeManagerHandle moduleHandle in loadedModuleHandles)
                {
                    // Skip already registered modules.
                    int oldModuleIndex;
                    if (_loadedModuleMap.HandleToModuleIndex.TryGetValue(moduleHandle, out oldModuleIndex))
                    {
                        continue;
                    }

                    newModuleHandles.Add(moduleHandle);
                }

                // Copy existing modules to new dictionary
                int          oldModuleCount = _loadedModuleMap.Modules.Length;
                ModuleInfo[] updatedModules = new ModuleInfo[oldModuleCount + newModuleHandles.Count];
                if (oldModuleCount > 0)
                {
                    Array.Copy(_loadedModuleMap.Modules, 0, updatedModules, 0, oldModuleCount);
                }

                for (int newModuleIndex = 0; newModuleIndex < newModuleHandles.Count; newModuleIndex++)
                {
                    ModuleInfo newModuleInfo;

                    unsafe
                    {
                        byte *pBlob;
                        uint  cbBlob;

                        if (RuntimeAugments.FindBlob(newModuleHandles[newModuleIndex], (int)ReflectionMapBlob.EmbeddedMetadata, new IntPtr(&pBlob), new IntPtr(&cbBlob)))
                        {
                            newModuleInfo = new NativeFormatModuleInfo(newModuleHandles[newModuleIndex], moduleType, (IntPtr)pBlob, (int)cbBlob);
                        }
                        else
                        {
                            newModuleInfo = new ModuleInfo(newModuleHandles[newModuleIndex], moduleType);
                        }
                    }

                    updatedModules[oldModuleCount + newModuleIndex] = newModuleInfo;

                    if (_moduleRegistrationCallbacks != null)
                    {
                        _moduleRegistrationCallbacks(newModuleInfo);
                    }
                }

                // Atomically update the module map
                _loadedModuleMap = new ModuleMap(updatedModules);
            }
        }
Example #15
0
        internal bool GetCallingConverterDataFromMethodSignature_NativeLayout_Common(
            TypeSystemContext context,
            RuntimeSignature methodSig,
            Instantiation typeInstantiation,
            Instantiation methodInstantiation,
            out bool hasThis,
            out TypeDesc[] parameters,
            out bool[] parametersWithGenericDependentLayout,
            NativeReader nativeReader,
            ulong[] debuggerPreparedExternalReferences)
        {
            bool isNotDebuggerCall = debuggerPreparedExternalReferences == null;

            hasThis    = false;
            parameters = null;

            NativeLayoutInfoLoadContext nativeLayoutContext = new NativeLayoutInfoLoadContext();

            nativeLayoutContext._module                = isNotDebuggerCall ? (NativeFormatModuleInfo)methodSig.GetModuleInfo() : null;
            nativeLayoutContext._typeSystemContext     = context;
            nativeLayoutContext._typeArgumentHandles   = typeInstantiation;
            nativeLayoutContext._methodArgumentHandles = methodInstantiation;
            nativeLayoutContext._debuggerPreparedExternalReferences = debuggerPreparedExternalReferences;

            NativeFormatModuleInfo module = null;
            NativeReader           reader = null;

            if (isNotDebuggerCall)
            {
                reader = GetNativeLayoutInfoReader(methodSig);
                module = ModuleList.Instance.GetModuleInfoByHandle(new TypeManagerHandle(methodSig.ModuleHandle));
            }
            else
            {
                reader = nativeReader;
            }
            NativeParser parser = new NativeParser(reader, methodSig.NativeLayoutOffset);

            MethodCallingConvention callingConvention = (MethodCallingConvention)parser.GetUnsigned();

            hasThis = !callingConvention.HasFlag(MethodCallingConvention.Static);

            uint numGenArgs = callingConvention.HasFlag(MethodCallingConvention.Generic) ? parser.GetUnsigned() : 0;

            uint parameterCount = parser.GetUnsigned();

            parameters = new TypeDesc[parameterCount + 1];
            parametersWithGenericDependentLayout = new bool[parameterCount + 1];

            // One extra parameter to account for the return type
            for (uint i = 0; i <= parameterCount; i++)
            {
                // NativeParser is a struct, so it can be copied.
                NativeParser parserCopy = parser;

                // Parse the signature twice. The first time to find out the exact type of the signature
                // The second time to identify if the parameter loaded via the signature should be forced to be
                // passed byref as part of the universal generic calling convention.
                parameters[i] = GetConstructedTypeFromParserAndNativeLayoutContext(ref parser, nativeLayoutContext);
                parametersWithGenericDependentLayout[i] = TypeSignatureHasVarsNeedingCallingConventionConverter(ref parserCopy, module, context, HasVarsInvestigationLevel.Parameter);
                if (parameters[i] == null)
                {
                    return(false);
                }
            }

            return(true);
        }