Example #1
0
        private static bool TryGetVirtualMethodFromSlot(TypeDesc definingType, int vtableSlotIndex, out MethodDesc slotDefiningMethod)
        {
            MethodNameAndSignature methodNameAndSig;
            bool success = TypeLoaderEnvironment.TryGetMethodMethodNameAndSigFromVTableSlotForPregeneratedOrTemplateType
                               (definingType.Context, definingType.GetRuntimeTypeHandle(), vtableSlotIndex, out methodNameAndSig);

            if (!success)
            {
                slotDefiningMethod = null;
                return(false);
            }

            TypeSystem.NativeFormat.NativeFormatType metadataDefiningType = definingType.GetClosestDefType().GetTypeDefinition() as TypeSystem.NativeFormat.NativeFormatType;

            // We're working with a NoMetadataType, or an ArrayType, neither of which have full metadata
            if (metadataDefiningType == null)
            {
                slotDefiningMethod = null;
                return(false);
            }

            // TryGetMethodMethodNameAndSigFromVTableSlotForPregeneratedOrTemplateType is expected to only return methodNameAndSig with NativeLayoutSignatures in them.
            // If we start hitting the more general case, we can improve this algorithm.
            Debug.Assert(methodNameAndSig.Signature.IsNativeLayoutSignature);

            foreach (TypeSystem.NativeFormat.NativeFormatMethod method in metadataDefiningType.GetMethods())
            {
                if (!method.IsVirtual)
                {
                    continue;
                }

                if (method.HasInstantiation)
                {
                    continue;
                }

                if (!method.Name.Equals(methodNameAndSig.Name))
                {
                    continue;
                }

                MethodSignatureComparer sigComparer = new MethodSignatureComparer(method.MetadataReader, method.Handle);
                if (!sigComparer.IsMatchingNativeLayoutMethodNameAndSignature(methodNameAndSig.Name, methodNameAndSig.Signature))
                {
                    continue;
                }

                // At this point we've matched
                slotDefiningMethod = method;
                return(true);
            }

            // Didn't find the method
            slotDefiningMethod = null;
            return(false);
        }
Example #2
0
        /// <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);
            }
        }
        internal void RegisterDynamicGenericTypesAndMethods(DynamicGenericsRegistrationData registrationData)
        {
            using (LockHolder.Hold(_dynamicGenericsLock))
            {
                int registeredTypesCount                = 0;
                int registeredMethodsCount              = 0;
                int nativeFormatTypesRegisteredCount    = 0;
                TypeEntryToRegister[] registeredTypes   = null;
                GenericMethodEntry[]  registeredMethods = null;

                try
                {
                    if (registrationData.TypesToRegister != null)
                    {
                        registeredTypes = new TypeEntryToRegister[registrationData.TypesToRegisterCount];

                        foreach (TypeEntryToRegister typeEntry in registrationData.TypesToRegister)
                        {
                            // Keep track of registered type handles so that that we can rollback the registration on exception
                            registeredTypes[registeredTypesCount++] = typeEntry;

                            // Information tracked in these dictionaries is (partially) redundant with information tracked by MRT.
                            // We can save a bit of memory by avoiding the redundancy where possible. For now, we are keeping it simple.

                            // Register type -> components mapping first so that we can use it during rollback below
                            if (typeEntry.GenericTypeEntry != null)
                            {
                                GenericTypeEntry registeredTypeEntry = _dynamicGenericTypes.AddOrGetExisting(typeEntry.GenericTypeEntry);
                                if (registeredTypeEntry != typeEntry.GenericTypeEntry && registeredTypeEntry._isRegisteredSuccessfully)
                                {
                                    throw new ArgumentException(SR.Argument_AddingDuplicate);
                                }

                                registeredTypeEntry._instantiatedTypeHandle   = typeEntry.GenericTypeEntry._instantiatedTypeHandle;
                                registeredTypeEntry._isRegisteredSuccessfully = true;
                            }
                            else
                            {
                                MetadataType metadataType      = typeEntry.MetadataDefinitionType;
                                IntPtr       nonGcStaticFields = IntPtr.Zero;
                                IntPtr       gcStaticFields    = IntPtr.Zero;
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
#if SUPPORTS_R2R_LOADING
                                uint nonGcStaticsRva = 0;
                                uint gcStaticsRva    = 0;

                                // For images where statics are directly embedded in the image, store the information about where
                                // to find statics info
                                if (TypeLoaderEnvironment.TryGetStaticsTableEntry(metadataType, out nonGcStaticsRva, out gcStaticsRva))
                                {
                                    ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(metadataType);

                                    if (nonGcStaticsRva == 0)
                                    {
                                        nonGcStaticFields = TypeLoaderEnvironment.NoStaticsData;
                                    }
                                    else
                                    {
                                        nonGcStaticFields = moduleInfo.Handle + checked ((int)nonGcStaticsRva);
                                    }

                                    if (gcStaticsRva == 0)
                                    {
                                        gcStaticFields = TypeLoaderEnvironment.NoStaticsData;
                                    }
                                    else
                                    {
                                        gcStaticFields = moduleInfo.Handle + checked ((int)gcStaticsRva);
                                    }
                                }
#endif

                                TypeSystem.NativeFormat.NativeFormatType nativeFormatType = metadataType as TypeSystem.NativeFormat.NativeFormatType;
                                if (nativeFormatType != null)
                                {
                                    RegisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(nativeFormatType.MetadataReader,
                                                                                              nativeFormatType.Handle),
                                                                          nativeFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle,
                                                                          nonGcStaticFields,
                                                                          gcStaticFields);
                                }
#if ECMA_METADATA_SUPPORT
                                TypeSystem.Ecma.EcmaType ecmaFormatType = metadataType as TypeSystem.Ecma.EcmaType;
                                if (ecmaFormatType != null)
                                {
                                    RegisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(ecmaFormatType.MetadataReader,
                                                                                              ecmaFormatType.Handle),
                                                                          ecmaFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle,
                                                                          nonGcStaticFields,
                                                                          gcStaticFields);
                                }
#endif

                                nativeFormatTypesRegisteredCount++;
#else
                                Environment.FailFast("Ready to Run module type?");
#endif
                            }
                        }
                    }
                    Debug.Assert(registeredTypesCount == registrationData.TypesToRegisterCount);

                    if (registrationData.MethodsToRegister != null)
                    {
                        registeredMethods = new GenericMethodEntry[registrationData.MethodsToRegisterCount];

                        foreach (GenericMethodEntry methodEntry in registrationData.MethodsToRegister)
                        {
                            Debug.Assert(methodEntry._methodDictionary != IntPtr.Zero);

                            // Keep track of registered method dictionaries so that that we can rollback the registration on exception
                            registeredMethods[registeredMethodsCount++] = methodEntry;

                            // Register method dictionary -> components mapping first so that we can use it during rollback below
                            GenericMethodEntry registeredMethodComponentsEntry = _dynamicGenericMethodComponents.AddOrGetExisting(methodEntry);
                            if (registeredMethodComponentsEntry != methodEntry && registeredMethodComponentsEntry._isRegisteredSuccessfully)
                            {
                                throw new ArgumentException(SR.Argument_AddingDuplicate);
                            }

                            GenericMethodEntry registeredMethodEntry = _dynamicGenericMethods.AddOrGetExisting(methodEntry);
                            if (registeredMethodEntry != methodEntry && registeredMethodEntry._isRegisteredSuccessfully)
                            {
                                throw new ArgumentException(SR.Argument_AddingDuplicate);
                            }

                            Debug.Assert(registeredMethodComponentsEntry == registeredMethodEntry);
                            registeredMethodEntry._methodDictionary         = methodEntry._methodDictionary;
                            registeredMethodEntry._isRegisteredSuccessfully = true;
                        }
                    }
                    Debug.Assert(registeredMethodsCount == registrationData.MethodsToRegisterCount);
                }
                catch
                {
                    // Catch and rethrow any exceptions instead of using finally block. Otherwise, filters that are run during
                    // the first pass of exception unwind may see partially registered types.

                    // TODO: Convert this to filter for better diagnostics once we switch to Roslyn

                    // Undo types that were registered. There should be no memory allocations or other failure points.
                    try
                    {
                        for (int i = 0; i < registeredTypesCount; i++)
                        {
                            var typeEntry = registeredTypes[i];
                            // There is no Remove feature in the LockFreeReaderHashtable...
                            if (typeEntry.GenericTypeEntry != null)
                            {
                                GenericTypeEntry failedEntry = _dynamicGenericTypes.GetValueIfExists(typeEntry.GenericTypeEntry);
                                if (failedEntry != null)
                                {
                                    failedEntry._isRegisteredSuccessfully = false;
                                }
                            }
                            else
                            {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                                TypeSystem.NativeFormat.NativeFormatType nativeFormatType = typeEntry.MetadataDefinitionType as TypeSystem.NativeFormat.NativeFormatType;
                                if (nativeFormatType != null)
                                {
                                    UnregisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(nativeFormatType.MetadataReader,
                                                                                                nativeFormatType.Handle),
                                                                            nativeFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle);
                                }
#if ECMA_METADATA_SUPPORT
                                TypeSystem.Ecma.EcmaType ecmaFormatType = typeEntry.MetadataDefinitionType as TypeSystem.Ecma.EcmaType;
                                if (ecmaFormatType != null)
                                {
                                    UnregisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(ecmaFormatType.MetadataReader,
                                                                                                ecmaFormatType.Handle),
                                                                            ecmaFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle);
                                }
#endif
#else
                                Environment.FailFast("Ready to Run module type?");
#endif
                            }
                        }
                        for (int i = 0; i < registeredMethodsCount; i++)
                        {
                            // There is no Remove feature in the LockFreeReaderHashtable...
                            GenericMethodEntry failedEntry = _dynamicGenericMethods.GetValueIfExists(registeredMethods[i]);
                            if (failedEntry != null)
                            {
                                failedEntry._isRegisteredSuccessfully = false;
                            }

                            failedEntry = _dynamicGenericMethodComponents.GetValueIfExists(registeredMethods[i]);
                            if (failedEntry != null)
                            {
                                failedEntry._isRegisteredSuccessfully = false;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // Catch any exceptions and fail fast just in case
                        Environment.FailFast("Exception during registration rollback", e);
                    }

                    throw;
                }

                if (nativeFormatTypesRegisteredCount > 0)
                {
                    FinishAddingNewNamedTypes();
                }
            }
        }