public static string LowLevelToString(this RuntimeTypeHandle rtth)
        {
            TypeReferenceHandle typeRefHandle;
            QTypeDefinition     qTypeDefinition;
            MetadataReader      reader;

            // Try to get the name from metadata
            if (TypeLoaderEnvironment.Instance.TryGetMetadataForNamedType(rtth, out qTypeDefinition))
            {
#if ECMA_METADATA_SUPPORT
                string result = EcmaMetadataFullName(qTypeDefinition);
                if (result != null)
                {
                    return(result);
                }
#endif

                reader = qTypeDefinition.NativeFormatReader;
                TypeDefinitionHandle typeDefHandle = qTypeDefinition.NativeFormatHandle;
                return(typeDefHandle.GetFullName(reader));
            }

            // Try to get the name from diagnostic metadata
            if (TypeLoaderEnvironment.TryGetTypeReferenceForNamedType(rtth, out reader, out typeRefHandle))
            {
                return(typeRefHandle.GetFullName(reader));
            }

            // Fallback implementation when no metadata available
            return(LowLevelToStringRawEETypeAddress(rtth));
        }
        public static string LowLevelToString(this RuntimeTypeHandle rtth)
        {
            MetadataReader       reader;
            TypeDefinitionHandle typeDefHandle;
            TypeReferenceHandle  typeRefHandle;

            // Try to get the name from metadata
            if (TypeLoaderEnvironment.Instance.TryGetMetadataForNamedType(rtth, out reader, out typeDefHandle))
            {
                return(typeDefHandle.GetFullName(reader));
            }

            // Try to get the name from diagnostic metadata
            if (TypeLoaderEnvironment.TryGetTypeReferenceForNamedType(rtth, out reader, out typeRefHandle))
            {
                return(typeRefHandle.GetFullName(reader));
            }

            // Fallback implementation when no metadata available
            string prefix = "EEType:0x";

            StringBuilder sb  = new StringBuilder(prefix.Length + IntPtr.Size * 4);
            ulong         num = (ulong)rtth.ToIntPtr();

            int shift = IntPtr.Size * 8;

            while (shift > 0)
            {
                shift -= 4;
                int digit = (int)((num >> shift) & 0xF);
                sb.Append(HexDigits[digit]);
            }

            return(sb.ToString());
        }
Example #3
0
 // Eager initialization called from LibraryInitializer for the assembly.
 internal static void Initialize()
 {
     Instance = new TypeLoaderEnvironment();
     RuntimeAugments.InitializeLookups(new Callbacks());
     s_nativeFormatStrings = new LowLevelDictionary<string, IntPtr>();
     NoStaticsData = (IntPtr)1;
 }
        /// <summary>
        /// Look up module containing given nativesignature and return the appropriate native parser.
        /// </summary>
        /// <param name="signature">Signature to look up</param>
        /// <returns>Native parser for the signature</param>
        internal static NativeParser GetNativeParserForSignature(IntPtr signature)
        {
            IntPtr       moduleHandle = RuntimeAugments.GetModuleFromPointer(signature);
            NativeReader reader       = TypeLoaderEnvironment.GetNativeReaderForBlob(moduleHandle, ReflectionMapBlob.NativeLayoutInfo);

            return(new NativeParser(reader, reader.AddressToOffset(signature)));
        }
Example #5
0
        /// <summary>
        /// Initialize the Reader and LoadContext fields of the native layout info
        /// </summary>
        /// <param name="type"></param>
        /// <param name="nativeLayoutInfo"></param>
        private static void FinishInitNativeLayoutInfo(TypeDesc type, ref NativeLayoutInfo nativeLayoutInfo)
        {
            var nativeLayoutInfoLoadContext = new NativeLayoutInfoLoadContext();

            nativeLayoutInfoLoadContext._typeSystemContext = type.Context;
            nativeLayoutInfoLoadContext._module            = nativeLayoutInfo.Module;

            if (type is DefType)
            {
                nativeLayoutInfoLoadContext._typeArgumentHandles = ((DefType)type).Instantiation;
            }
            else if (type is ArrayType)
            {
                nativeLayoutInfoLoadContext._typeArgumentHandles = new Instantiation(new TypeDesc[] { ((ArrayType)type).ElementType });
            }
            else
            {
                Debug.Assert(false);
            }

            nativeLayoutInfoLoadContext._methodArgumentHandles = new Instantiation(null);

            nativeLayoutInfo.Reader      = TypeLoaderEnvironment.GetNativeLayoutInfoReader(nativeLayoutInfo.Module.Handle);
            nativeLayoutInfo.LoadContext = nativeLayoutInfoLoadContext;
        }
        public static IntPtr NativeLayoutSignature(this RuntimeSignature signature)
        {
            if (!signature.IsNativeLayoutSignature)
                Environment.FailFast("Not a valid native layout signature");

            NativeReader reader = TypeLoaderEnvironment.GetNativeLayoutInfoReader(signature);
            return reader.OffsetToAddress(signature.NativeLayoutOffset);
        }
        /// <summary>
        /// Look up module containing given nativesignature and return the appropriate native parser.
        /// </summary>
        /// <param name="signature">Signature to look up</param>
        /// <returns>Native parser for the signature</param>
        internal static NativeParser GetNativeParserForSignature(RuntimeSignature signature)
        {
            Debug.Assert(signature.IsNativeLayoutSignature);

            NativeReader reader = TypeLoaderEnvironment.GetNativeReaderForBlob(signature.ModuleHandle, ReflectionMapBlob.NativeLayoutInfo);

            return(new NativeParser(reader, signature.NativeLayoutOffset));
        }
Example #8
0
        /// <summary>
        /// Resolve a MethodDesc to a callable method address and unboxing stub address by searching
        /// by searching in the InvokeMaps. This function is a wrapper around TryGetMethodInvokeDataFromInvokeMap
        /// that produces output in the format which matches the code table system.
        /// </summary>
        /// <param name="method">Native metadata method description object</param>
        /// <param name="methodAddress">Resolved method address</param>
        /// <param name="unboxingStubAddress">Resolved unboxing stub address</param>
        /// <param name="foundAddressType">Output - The type of method address match found. A canonical address may require extra parameters to call.</param>
        /// <returns>true when the resolution succeeded, false when not</returns>
        private static bool TryGetMethodAddressFromTypeSystemMethodViaInvokeMap(
            MethodDesc method,
            out IntPtr methodAddress,
            out IntPtr unboxingStubAddress,
            out MethodAddressType foundAddressType)
        {
            methodAddress       = IntPtr.Zero;
            unboxingStubAddress = IntPtr.Zero;
            foundAddressType    = MethodAddressType.None;
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
            NativeFormatMethod nativeFormatMethod = method.GetTypicalMethodDefinition() as NativeFormatMethod;
            if (nativeFormatMethod == null)
            {
                return(false);
            }

            MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer(
                nativeFormatMethod.MetadataReader, nativeFormatMethod.Handle);

            // Try to find a specific canonical match, or if that fails, a universal match
            if (TryGetMethodInvokeDataFromInvokeMap(
                    nativeFormatMethod,
                    method,
                    ref methodSignatureComparer,
                    CanonicalFormKind.Specific,
                    out methodAddress,
                    out foundAddressType) ||

                TryGetMethodInvokeDataFromInvokeMap(
                    nativeFormatMethod,
                    method,
                    ref methodSignatureComparer,
                    CanonicalFormKind.Universal,
                    out methodAddress,
                    out foundAddressType))
            {
                if (method.OwningType.IsValueType && !method.Signature.IsStatic)
                {
                    // In this case the invoke map found an unboxing stub, and we should pull the method address out as well
                    unboxingStubAddress = methodAddress;
                    methodAddress       = RuntimeAugments.GetCodeTarget(unboxingStubAddress);

                    if (!method.HasInstantiation && ((foundAddressType != MethodAddressType.Exact) || method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any)))
                    {
                        IntPtr underlyingTarget; // unboxing and instantiating stub handling
                        if (!TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(methodAddress, out underlyingTarget))
                        {
                            Environment.FailFast("Expected this to be an unboxing and instantiating stub.");
                        }
                        methodAddress = underlyingTarget;
                    }
                }

                return(true);
            }
#endif
            return(false);
        }
        /// <summary>
        /// Look up module containing given nativesignature and return the appropriate native parser.
        /// </summary>
        /// <param name="signature">Signature to look up</param>
        /// <returns>Native parser for the signature</returns>
        internal static NativeParser GetNativeParserForSignature(RuntimeSignature signature)
        {
            Debug.Assert(signature.IsNativeLayoutSignature);
            NativeFormatModuleInfo module = ModuleList.Instance.GetModuleInfoByHandle(new TypeManagerHandle(signature.ModuleHandle));

            NativeReader reader = TypeLoaderEnvironment.GetNativeReaderForBlob(module, ReflectionMapBlob.NativeLayoutInfo);

            return(new NativeParser(reader, signature.NativeLayoutOffset));
        }
Example #10
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 #11
0
        public static IntPtr ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(IntPtr unboxingFunctionPointer, RuntimeTypeHandle declaringType)
        {
            if (FunctionPointerOps.IsGenericMethodPointer(unboxingFunctionPointer))
            {
                // Handle shared generic methods
                unsafe
                {
                    GenericMethodDescriptor *functionPointerDescriptor = FunctionPointerOps.ConvertToGenericDescriptor(unboxingFunctionPointer);
                    IntPtr nonUnboxingTarget = RuntimeAugments.GetCodeTarget(functionPointerDescriptor->MethodFunctionPointer);
                    Debug.Assert(nonUnboxingTarget != functionPointerDescriptor->MethodFunctionPointer);
                    Debug.Assert(nonUnboxingTarget == RuntimeAugments.GetCodeTarget(nonUnboxingTarget));
                    return(FunctionPointerOps.GetGenericMethodFunctionPointer(nonUnboxingTarget, functionPointerDescriptor->InstantiationArgument));
                }
            }

            // GetCodeTarget will look through simple unboxing stubs (ones that consist of adjusting the this pointer and then
            // jumping to the target.
            IntPtr exactTarget = RuntimeAugments.GetCodeTarget(unboxingFunctionPointer);

            if (RuntimeAugments.IsGenericType(declaringType))
            {
                IntPtr fatFunctionPointerTarget;

                // This check looks for unboxing and instantiating stubs generated via the compiler backend
                if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(exactTarget, out fatFunctionPointerTarget))
                {
                    // If this is an unboxing and instantiating stub, use separate table, find target, and create fat function pointer
                    exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(fatFunctionPointerTarget,
                                                                                     declaringType.ToIntPtr());
                }
#if FEATURE_UNIVERSAL_GENERICS
                else
                {
                    IntPtr newExactTarget;
                    // This check looks for unboxing and instantiating stubs generated dynamically as thunks in the calling convention converter
                    if (CallConverterThunk.TryGetNonUnboxingFunctionPointerFromUnboxingAndInstantiatingStub(exactTarget,
                                                                                                            declaringType, out newExactTarget))
                    {
                        // CallingConventionConverter determined non-unboxing stub
                        exactTarget = newExactTarget;
                    }
                    else
                    {
                        // Target method was a method on a generic, but it wasn't a shared generic, and thus none of the above
                        // complex unboxing stub digging logic was necessary. Do nothing, and use exactTarget as discovered
                        // from GetCodeTarget
                    }
                }
#endif
            }

            return(exactTarget);
        }
Example #12
0
            // Resolve a constrained call in case where the call is an MDIL constrained call directly through a function pointer located in the generic dictionary
            // This can only happen if there is a call from shared generic code to a structure which implements multiple of the same generic interface, and which instantiation
            // is decided by the exact type of the caller. For instance
            //
            // interface IFunc<T>
            // {
            //    void M();
            // }
            //
            // struct UnusualCase : IFunc<object>, IFunc<string>
            // {
            //    void IFunc<object>.M() { Console.WriteLine("In IFunc<object>");}
            //    void IFunc<string>.M() { Console.WriteLine("In IFunc<object>");}
            // }
            // class Caller<T,U> where T : IFunc<U>
            // {
            //    void Call(T c)
            //    {
            //        c.M();
            //    }
            // }
            //
            // If Caller is instantiated as Caller<UnusualCase,object>, or Caller<UnusualCase,string> we will generate code for Caller<UnusualCase,__Canon>.Call(UnusualCase)
            // However, that code will not be able to exactly specify the target of the call. It will need to use the generic dictionary.
            unsafe private static IntPtr ResolveDirectConstrainedCall(IntPtr callerTransitionBlockParam, IntPtr callDescIntPtr)
            {
                NonGenericConstrainedCallDesc* callDesc = (NonGenericConstrainedCallDesc*)callDescIntPtr;
                Debug.Assert(RuntimeAugments.IsInterface(callDesc->_constrainedMethodType));
                IntPtr targetOnTypeVtable = RuntimeAugments.ResolveDispatchOnType(callDesc->_constraintType, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot);
                IntPtr exactTarget = RuntimeAugments.GetCodeTarget(targetOnTypeVtable);
                IntPtr underlyingTargetIfUnboxingAndInstantiatingStub;
                if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(exactTarget, out underlyingTargetIfUnboxingAndInstantiatingStub))
                {
                    // If this is an unboxing and instantiating stub, get the underlying pointer. The caller of this function is required to have already setup the 
                    // instantiation argument
                    exactTarget = underlyingTargetIfUnboxingAndInstantiatingStub;
                }

                callDesc->_exactTarget = exactTarget;
                return exactTarget;
            }
Example #13
0
        /// <summary>
        /// Get an address that can go into a vtable from a method desc
        /// Based on the structure of our code, these functions are always Instance, non-generic methods
        /// and therefore, we don't need to be concerned about an extra generic dictionary parameter
        /// </summary>
        private static bool TryGetVTableCallableAddress(MethodDesc method, out IntPtr result)
        {
            TypeLoaderEnvironment.MethodAddressType dummy;
            IntPtr methodAddressNonUnboxing;
            IntPtr unboxingMethodAddress;

            if (TypeLoaderEnvironment.TryGetMethodAddressFromMethodDesc(method, out methodAddressNonUnboxing, out unboxingMethodAddress, out dummy))
            {
                if (unboxingMethodAddress != IntPtr.Zero)
                {
                    result = unboxingMethodAddress;
                }
                else
                {
                    result = methodAddressNonUnboxing;
                }
                return(true);
            }

            result = IntPtr.Zero;
            return(false);
        }
        internal MethodDesc GetMethod(ref NativeParser parser, out RuntimeSignature methodNameSig, out RuntimeSignature methodSig)
        {
            MethodFlags flags = (MethodFlags)parser.GetUnsigned();

            IntPtr functionPointer = IntPtr.Zero;

            if ((flags & MethodFlags.HasFunctionPointer) != 0)
            {
                functionPointer = GetExternalReferencePointer(parser.GetUnsigned());
            }

            DefType containingType = (DefType)GetType(ref parser);
            MethodNameAndSignature nameAndSignature = TypeLoaderEnvironment.GetMethodNameAndSignature(ref parser, _module.Handle, out methodNameSig, out methodSig);

            bool unboxingStub = (flags & MethodFlags.IsUnboxingStub) != 0;

            MethodDesc retVal;

            if ((flags & MethodFlags.HasInstantiation) != 0)
            {
                TypeDesc[] typeArguments = GetTypeSequence(ref parser);
                Debug.Assert(typeArguments.Length > 0);
                retVal = this._typeSystemContext.ResolveGenericMethodInstantiation(unboxingStub, containingType, nameAndSignature, new Instantiation(typeArguments), functionPointer, (flags & MethodFlags.FunctionPointerIsUSG) != 0);
            }
            else
            {
                retVal = this._typeSystemContext.ResolveRuntimeMethod(unboxingStub, containingType, nameAndSignature, functionPointer, (flags & MethodFlags.FunctionPointerIsUSG) != 0);
            }

            if ((flags & MethodFlags.FunctionPointerIsUSG) != 0)
            {
                // TODO, consider a change such that if a USG function pointer is passed in, but we have
                // a way to get a non-usg pointer, that may be preferable
                Debug.Assert(retVal.UsgFunctionPointer != IntPtr.Zero);
            }

            return(retVal);
        }
Example #15
0
        /// <summary>
        /// Try to look up field acccess info for given canon in metadata blobs for all available modules.
        /// </summary>
        /// <param name="metadataReader">Metadata reader for the declaring type</param>
        /// <param name="declaringTypeHandle">Declaring type for the method</param>
        /// <param name="fieldHandle">Field handle</param>
        /// <param name="canonFormKind">Canonical form to use</param>
        /// <param name="fieldAccessMetadata">Output - metadata information for field accessor construction</param>
        /// <returns>true when found, false otherwise</returns>
        private static bool TryGetFieldAccessMetadataFromFieldAccessMap(
            MetadataReader metadataReader,
            RuntimeTypeHandle declaringTypeHandle,
            FieldHandle fieldHandle,
            CanonicalFormKind canonFormKind,
            ref FieldAccessMetadata fieldAccessMetadata)
        {
            CanonicallyEquivalentEntryLocator canonWrapper = new CanonicallyEquivalentEntryLocator(declaringTypeHandle, canonFormKind);
            IntPtr            fieldHandleModule            = ModuleList.Instance.GetModuleForMetadataReader(metadataReader);
            bool              isDynamicType = RuntimeAugments.IsDynamicType(declaringTypeHandle);
            string            fieldName     = null;
            RuntimeTypeHandle declaringTypeHandleDefinition = Instance.GetTypeDefinition(declaringTypeHandle);

            foreach (IntPtr mappingTableModule in ModuleList.Enumerate(RuntimeAugments.GetModuleFromTypeHandle(declaringTypeHandle)))
            {
                NativeReader fieldMapReader;
                if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.FieldAccessMap, out fieldMapReader))
                {
                    continue;
                }

                NativeParser    fieldMapParser = new NativeParser(fieldMapReader, 0);
                NativeHashtable fieldHashtable = new NativeHashtable(fieldMapParser);

                ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
                if (!externalReferences.InitializeCommonFixupsTable(mappingTableModule))
                {
                    continue;
                }

                var lookup = fieldHashtable.Lookup(canonWrapper.LookupHashCode);

                NativeParser entryParser;
                while (!(entryParser = lookup.GetNext()).IsNull)
                {
                    // Grammar of a hash table entry:
                    // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset

                    FieldTableFlags entryFlags = (FieldTableFlags)entryParser.GetUnsigned();

                    if ((canonFormKind == CanonicalFormKind.Universal) != entryFlags.HasFlag(FieldTableFlags.IsUniversalCanonicalEntry))
                    {
                        continue;
                    }

                    RuntimeTypeHandle entryDeclaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
                    if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle) &&
                        !canonWrapper.IsCanonicallyEquivalent(entryDeclaringTypeHandle))
                    {
                        continue;
                    }

                    if (entryFlags.HasFlag(FieldTableFlags.HasMetadataHandle))
                    {
                        Handle entryFieldHandle = (((int)HandleType.Field << 24) | (int)entryParser.GetUnsigned()).AsHandle();
                        if (!fieldHandle.Equals(entryFieldHandle))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (fieldName == null)
                        {
                            MetadataReader       mdReader;
                            TypeDefinitionHandle typeDefHandleUnused;
                            bool success = Instance.TryGetMetadataForNamedType(
                                declaringTypeHandleDefinition,
                                out mdReader,
                                out typeDefHandleUnused);
                            Debug.Assert(success);

                            fieldName = mdReader.GetString(fieldHandle.GetField(mdReader).Name);
                        }

                        string entryFieldName = entryParser.GetString();

                        if (fieldName != entryFieldName)
                        {
                            continue;
                        }
                    }

                    int    cookieOrOffsetOrOrdinal = (int)entryParser.GetUnsigned();
                    int    fieldOffset;
                    IntPtr fieldAddressCookie = IntPtr.Zero;

                    if (canonFormKind == CanonicalFormKind.Universal)
                    {
                        if (!TypeLoaderEnvironment.Instance.TryGetFieldOffset(declaringTypeHandle, (uint)cookieOrOffsetOrOrdinal, out fieldOffset))
                        {
                            Debug.Assert(false);
                            return(false);
                        }
                    }
                    else
                    {
#if CORERT
                        fieldOffset = cookieOrOffsetOrOrdinal;
#else
                        fieldOffset = (int)externalReferences.GetRvaFromIndex((uint)cookieOrOffsetOrOrdinal);
#endif
                    }

                    if ((entryFlags & FieldTableFlags.StorageClass) == FieldTableFlags.ThreadStatic)
                    {
                        if (canonFormKind != CanonicalFormKind.Universal)
                        {
                            fieldAddressCookie = RvaToNonGenericStaticFieldAddress(mappingTableModule, fieldOffset);
                        }

                        if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle))
                        {
                            // In this case we didn't find an exact match, but we did find a canonically equivalent match
                            // We might be in the dynamic type case, or the canonically equivalent, but not the same case.

                            if (!RuntimeAugments.IsDynamicType(declaringTypeHandle))
                            {
                                int offsetToCreateCookieFor = fieldOffset;
                                // We're working with a statically generated type, but we didn't find an exact match in the tables
                                if (canonFormKind != CanonicalFormKind.Universal)
                                {
                                    offsetToCreateCookieFor = checked ((int)TypeLoaderEnvironment.GetThreadStaticTypeOffsetFromThreadStaticCookie(fieldAddressCookie));
                                }

                                fieldAddressCookie = TypeLoaderEnvironment.Instance.TryGetThreadStaticFieldOffsetCookieForTypeAndFieldOffset(declaringTypeHandle, checked ((uint)offsetToCreateCookieFor));
                            }
                        }
                    }

                    fieldAccessMetadata.MappingTableModule = mappingTableModule;
                    fieldAccessMetadata.Cookie             = fieldAddressCookie;
                    fieldAccessMetadata.Flags  = entryFlags;
                    fieldAccessMetadata.Offset = fieldOffset;
                    return(true);
                }
            }

            return(false);
        }
Example #16
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);
            }
        }
Example #17
0
            private unsafe static IntPtr ResolveCallOnValueType(IntPtr unused, IntPtr callDescIntPtr)
#endif
            {
                NonGenericConstrainedCallDesc *callDesc = (NonGenericConstrainedCallDesc *)callDescIntPtr;
                IntPtr exactTarget        = IntPtr.Zero;
                IntPtr targetOnTypeVtable = RuntimeAugments.ResolveDispatchOnType(callDesc->_constraintType, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot);
                bool   decodeUnboxing     = true;

                if (!RuntimeAugments.IsInterface(callDesc->_constrainedMethodType))
                {
                    // Non-interface constrained call on a valuetype to a method that isn't GetHashCode/Equals/ToString?!?!
                    if (callDesc->_constrainedMethodSlot > s_MaxObjectVTableSlot)
                    {
                        throw new NotSupportedException();
                    }

                    RuntimeTypeHandle baseTypeHandle;
                    bool gotBaseType = RuntimeAugments.TryGetBaseType(callDesc->_constraintType, out baseTypeHandle);
                    Debug.Assert(gotBaseType);
                    if (targetOnTypeVtable == RuntimeAugments.ResolveDispatchOnType(baseTypeHandle, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot))
                    {
                        // In this case, the valuetype does not override the base types implementation of ToString(), GetHashCode(), or Equals(object)
                        decodeUnboxing = false;
                    }
                }

                if (decodeUnboxing)
                {
                    exactTarget = RuntimeAugments.GetCodeTarget(targetOnTypeVtable);
                    if (RuntimeAugments.IsGenericType(callDesc->_constraintType))
                    {
                        IntPtr fatFunctionPointerTarget;
                        if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(exactTarget, out fatFunctionPointerTarget))
                        {
                            // If this is an unboxing and instantiating stub, use seperate table, find target, and create fat function pointer
                            exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(fatFunctionPointerTarget,
                                                                                             callDesc->_constraintType.ToIntPtr());
                        }
                        else
                        {
                            IntPtr newExactTarget;
                            if (CallConverterThunk.TryGetNonUnboxingFunctionPointerFromUnboxingAndInstantiatingStub(exactTarget,
                                                                                                                    callDesc->_constraintType, out newExactTarget))
                            {
                                // CallingConventionConverter determined non-unboxing stub
                                exactTarget = newExactTarget;
                            }
                            else
                            {
                                // Target method was a method on a generic, but it wasn't a shared generic, and thus none of the above
                                // complex unboxing stub digging logic was necessary. Do nothing, and use exactTarget as discovered
                                // from GetCodeTarget
                            }
                        }
                    }
                }
                else
                {
                    // Create a fat function pointer, where the instantiation argument is ConstraintType, and the target is BoxAndToString, BoxAndGetHashCode, or BoxAndEquals
                    IntPtr realTarget;

                    switch (callDesc->_constrainedMethodSlot)
                    {
                    case s_ToStringSlot:
                        realTarget = s_boxAndToStringFuncPtr;
                        break;

                    case s_GetHashCodeSlot:
                        realTarget = s_boxAndGetHashCodeFuncPtr;
                        break;

                    case s_EqualsSlot:
                        realTarget = s_boxAndEqualsFuncPtr;
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(realTarget, callDesc->_constraintType.ToIntPtr());
                }

                // Ensure that all threads will have their function pointers completely published before updating callDesc.
                // as the ExactTarget is read from callDesc by binder generated code without a barrier, we need a barrier here
                // to ensure that the new function pointer data is valid on all threads
                Interlocked.MemoryBarrier();

                // Its possible for multiple threads to race to set exact target. Check to see we always set the same value
                if (callDesc->_exactTarget != IntPtr.Zero)
                {
                    Debug.Assert(callDesc->_exactTarget == exactTarget);
                }

                callDesc->_exactTarget = exactTarget;
                return(exactTarget);
            }
 // Eager initialization called from LibraryInitializer for the assembly.
 internal static void Initialize()
 {
     Instance = new TypeLoaderEnvironment();
     RuntimeAugments.InitializeLookups(new Callbacks());
     NoStaticsData = (IntPtr)1;
 }
Example #19
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);
        }
 static TypeLoaderEnvironment()
 {
     Instance = new TypeLoaderEnvironment();
 }
        private bool CompareTypeSigWithType(ref NativeParser parser, Handle typeHandle)
        {
            while (typeHandle.HandleType == HandleType.TypeSpecification)
            {
                typeHandle = typeHandle
                             .ToTypeSpecificationHandle(_metadataReader)
                             .GetTypeSpecification(_metadataReader)
                             .Signature;
            }

            // startOffset lets us backtrack to the TypeSignatureKind for external types since the TypeLoader
            // expects to read it in.
            uint startOffset = parser.Offset;

            uint data;
            var  typeSignatureKind = parser.GetTypeSignatureKind(out data);

            switch (typeSignatureKind)
            {
            case TypeSignatureKind.Lookback:
            {
                NativeParser lookbackParser = parser.GetLookbackParser(data);
                return(CompareTypeSigWithType(ref lookbackParser, typeHandle));
            }

            case TypeSignatureKind.Modifier:
            {
                // Ensure the modifier kind (vector, pointer, byref) is the same
                TypeModifierKind modifierKind = (TypeModifierKind)data;
                switch (modifierKind)
                {
                case TypeModifierKind.Array:
                    if (typeHandle.HandleType == HandleType.SZArraySignature)
                    {
                        return(CompareTypeSigWithType(ref parser, typeHandle
                                                      .ToSZArraySignatureHandle(_metadataReader)
                                                      .GetSZArraySignature(_metadataReader)
                                                      .ElementType));
                    }
                    return(false);

                case TypeModifierKind.ByRef:
                    if (typeHandle.HandleType == HandleType.ByReferenceSignature)
                    {
                        return(CompareTypeSigWithType(ref parser, typeHandle
                                                      .ToByReferenceSignatureHandle(_metadataReader)
                                                      .GetByReferenceSignature(_metadataReader)
                                                      .Type));
                    }
                    return(false);

                case TypeModifierKind.Pointer:
                    if (typeHandle.HandleType == HandleType.PointerSignature)
                    {
                        return(CompareTypeSigWithType(ref parser, typeHandle
                                                      .ToPointerSignatureHandle(_metadataReader)
                                                      .GetPointerSignature(_metadataReader)
                                                      .Type));
                    }
                    return(false);

                default:
                    Debug.Assert(null == "invalid type modifier kind");
                    return(false);
                }
            }

            case TypeSignatureKind.Variable:
            {
                bool isMethodVar = (data & 0x1) == 1;
                uint index       = data >> 1;

                if (isMethodVar)
                {
                    if (typeHandle.HandleType == HandleType.MethodTypeVariableSignature)
                    {
                        return(index == typeHandle
                               .ToMethodTypeVariableSignatureHandle(_metadataReader)
                               .GetMethodTypeVariableSignature(_metadataReader)
                               .Number);
                    }
                }
                else
                {
                    if (typeHandle.HandleType == HandleType.TypeVariableSignature)
                    {
                        return(index == typeHandle
                               .ToTypeVariableSignatureHandle(_metadataReader)
                               .GetTypeVariableSignature(_metadataReader)
                               .Number);
                    }
                }

                return(false);
            }

            case TypeSignatureKind.MultiDimArray:
            {
                if (typeHandle.HandleType != HandleType.ArraySignature)
                {
                    return(false);
                }

                ArraySignature sig = typeHandle
                                     .ToArraySignatureHandle(_metadataReader)
                                     .GetArraySignature(_metadataReader);

                if (data != sig.Rank)
                {
                    return(false);
                }

                if (!CompareTypeSigWithType(ref parser, sig.ElementType))
                {
                    return(false);
                }

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

                uint lowerBoundCount1 = parser.GetUnsigned();

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

            case TypeSignatureKind.FunctionPointer:
            {
                // callingConvention is in data
                uint argCount1 = parser.GetUnsigned();

                for (uint i = 0; i < argCount1; i++)
                {
                    if (!CompareTypeSigWithType(ref parser, typeHandle))
                    {
                        return(false);
                    }
                }
                return(false);
            }

            case TypeSignatureKind.Instantiation:
            {
                if (typeHandle.HandleType != HandleType.TypeInstantiationSignature)
                {
                    return(false);
                }

                TypeInstantiationSignature sig = typeHandle
                                                 .ToTypeInstantiationSignatureHandle(_metadataReader)
                                                 .GetTypeInstantiationSignature(_metadataReader);

                if (!CompareTypeSigWithType(ref parser, sig.GenericType))
                {
                    return(false);
                }

                uint genericArgIndex = 0;
                foreach (Handle genericArgumentTypeHandle in sig.GenericTypeArguments)
                {
                    if (genericArgIndex >= data)
                    {
                        // The metadata generic has more parameters than the native layour
                        return(false);
                    }
                    if (!CompareTypeSigWithType(ref parser, genericArgumentTypeHandle))
                    {
                        return(false);
                    }
                    genericArgIndex++;
                }
                // Make sure all generic parameters have been matched
                return(genericArgIndex == data);
            }

            case TypeSignatureKind.External:
            {
                RuntimeTypeHandle type2;
                switch (typeHandle.HandleType)
                {
                case HandleType.TypeDefinition:
                    if (!TypeLoaderEnvironment.Instance.TryGetOrCreateNamedTypeForMetadata(
                            _metadataReader, typeHandle.ToTypeDefinitionHandle(_metadataReader), out type2))
                    {
                        return(false);
                    }
                    break;

                case HandleType.TypeReference:
                    if (!TypeLoaderEnvironment.TryGetNamedTypeForTypeReference(
                            _metadataReader, typeHandle.ToTypeReferenceHandle(_metadataReader), out type2))
                    {
                        return(false);
                    }
                    break;

                default:
                    return(false);
                }

                RuntimeTypeHandle type1 = SigParsing.GetTypeFromNativeLayoutSignature(ref parser, startOffset);
                return(type1.Equals(type2));
            }

            default:
                return(false);
            }
            return(true);
        }
Example #22
0
 static TypeLoaderEnvironment()
 {
     Instance = new TypeLoaderEnvironment();
     RuntimeAugments.InitializeLookups(new Callbacks());
 }
 static TypeLoaderEnvironment()
 {
     Instance = new TypeLoaderEnvironment();
 }
Example #24
0
            private static unsafe IntPtr ResolveCallOnValueType(IntPtr unused, IntPtr callDescIntPtr)
#endif
            {
                NonGenericConstrainedCallDesc *callDesc = (NonGenericConstrainedCallDesc *)callDescIntPtr;
                IntPtr exactTarget        = IntPtr.Zero;
                IntPtr targetOnTypeVtable = RuntimeAugments.ResolveDispatchOnType(callDesc->_constraintType, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot);
                bool   decodeUnboxing     = true;

                if (!RuntimeAugments.IsInterface(callDesc->_constrainedMethodType))
                {
                    // Non-interface constrained call on a valuetype to a method that isn't GetHashCode/Equals/ToString?!?!
                    if (callDesc->_constrainedMethodSlot > s_MaxObjectVTableSlot)
                    {
                        throw new NotSupportedException();
                    }

                    RuntimeTypeHandle baseTypeHandle;
                    bool gotBaseType = RuntimeAugments.TryGetBaseType(callDesc->_constraintType, out baseTypeHandle);
                    Debug.Assert(gotBaseType);
                    if (targetOnTypeVtable == RuntimeAugments.ResolveDispatchOnType(baseTypeHandle, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot))
                    {
                        // In this case, the valuetype does not override the base types implementation of ToString(), GetHashCode(), or Equals(object)
                        decodeUnboxing = false;
                    }
                }

                if (decodeUnboxing)
                {
                    exactTarget = TypeLoaderEnvironment.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(targetOnTypeVtable, callDesc->_constraintType);
                }
                else
                {
                    // Create a fat function pointer, where the instantiation argument is ConstraintType, and the target is BoxAndToString, BoxAndGetHashCode, or BoxAndEquals
                    IntPtr realTarget;

                    switch (callDesc->_constrainedMethodSlot)
                    {
                    case s_ToStringSlot:
                        realTarget = s_boxAndToStringFuncPtr;
                        break;

                    case s_GetHashCodeSlot:
                        realTarget = s_boxAndGetHashCodeFuncPtr;
                        break;

                    case s_EqualsSlot:
                        realTarget = s_boxAndEqualsFuncPtr;
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(realTarget, callDesc->_constraintType.ToIntPtr());
                }

                // Ensure that all threads will have their function pointers completely published before updating callDesc.
                // as the ExactTarget is read from callDesc by binder generated code without a barrier, we need a barrier here
                // to ensure that the new function pointer data is valid on all threads
                Interlocked.MemoryBarrier();

                // Its possible for multiple threads to race to set exact target. Check to see we always set the same value
                if (callDesc->_exactTarget != IntPtr.Zero)
                {
                    Debug.Assert(callDesc->_exactTarget == exactTarget);
                }

                callDesc->_exactTarget = exactTarget;
                return(exactTarget);
            }
        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();
                }
            }
        }
Example #26
0
        private static void CreateEETypeWorker(EEType *pTemplateEEType, UInt32 hashCodeOfNewType,
                                               int arity, bool requireVtableSlotMapping, TypeBuilderState state)
        {
            bool           successful            = false;
            IntPtr         eeTypePtrPlusGCDesc   = IntPtr.Zero;
            IntPtr         dynamicDispatchMapPtr = IntPtr.Zero;
            DynamicModule *dynamicModulePtr      = null;

            try
            {
                Debug.Assert((pTemplateEEType != null) || (state.TypeBeingBuilt as MetadataType != null));

                // In some situations involving arrays we can find as a template a dynamically generated type.
                // In that case, the correct template would be the template used to create the dynamic type in the first
                // place.
                if (pTemplateEEType != null && pTemplateEEType->IsDynamicType)
                {
                    pTemplateEEType = pTemplateEEType->DynamicTemplateType;
                }

                ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(state.TypeBeingBuilt);
                dynamicModulePtr = moduleInfo.DynamicModulePtr;
                Debug.Assert(dynamicModulePtr != null);

                bool requiresDynamicDispatchMap = requireVtableSlotMapping && (pTemplateEEType != null) && pTemplateEEType->HasDispatchMap;

                uint valueTypeFieldPaddingEncoded = 0;
                int  baseSize = 0;

                bool   isValueType;
                bool   hasFinalizer;
                bool   isNullable;
                bool   isArray;
                bool   isGeneric;
                ushort componentSize = 0;
                ushort flags;
                ushort runtimeInterfacesLength = 0;
                bool   isGenericEETypeDef      = false;

                if (state.RuntimeInterfaces != null)
                {
                    runtimeInterfacesLength = checked ((ushort)state.RuntimeInterfaces.Length);
                }

                if (pTemplateEEType != null)
                {
                    valueTypeFieldPaddingEncoded = EEType.ComputeValueTypeFieldPaddingFieldValue(
                        pTemplateEEType->ValueTypeFieldPadding,
                        (uint)pTemplateEEType->FieldAlignmentRequirement);
                    baseSize      = (int)pTemplateEEType->BaseSize;
                    isValueType   = pTemplateEEType->IsValueType;
                    hasFinalizer  = pTemplateEEType->IsFinalizable;
                    isNullable    = pTemplateEEType->IsNullable;
                    componentSize = pTemplateEEType->ComponentSize;
                    flags         = pTemplateEEType->Flags;
                    isArray       = pTemplateEEType->IsArray;
                    isGeneric     = pTemplateEEType->IsGeneric;
                    Debug.Assert(pTemplateEEType->NumInterfaces == runtimeInterfacesLength);
                }
                else if (state.TypeBeingBuilt.IsGenericDefinition)
                {
                    flags       = (ushort)EETypeKind.GenericTypeDefEEType;
                    isValueType = state.TypeBeingBuilt.IsValueType;
                    if (isValueType)
                    {
                        flags |= (ushort)EETypeFlags.ValueTypeFlag;
                    }

                    if (state.TypeBeingBuilt.IsInterface)
                    {
                        flags |= (ushort)EETypeFlags.IsInterfaceFlag;
                    }
                    hasFinalizer       = false;
                    isArray            = false;
                    isNullable         = false;
                    isGeneric          = false;
                    isGenericEETypeDef = true;
                    componentSize      = checked ((ushort)state.TypeBeingBuilt.Instantiation.Length);
                    baseSize           = 0;
                }
                else
                {
                    isValueType  = state.TypeBeingBuilt.IsValueType;
                    hasFinalizer = state.TypeBeingBuilt.HasFinalizer;
                    isNullable   = state.TypeBeingBuilt.GetTypeDefinition().IsNullable;
                    flags        = EETypeBuilderHelpers.ComputeFlags(state.TypeBeingBuilt);
                    isArray      = false;
                    isGeneric    = state.TypeBeingBuilt.HasInstantiation;

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        state.GenericVarianceFlags = new int[state.TypeBeingBuilt.Instantiation.Length];
                        int i = 0;

                        foreach (GenericParameterDesc gpd in state.TypeBeingBuilt.GetTypeDefinition().Instantiation)
                        {
                            state.GenericVarianceFlags[i] = (int)gpd.Variance;
                            i++;
                        }
                        Debug.Assert(i == state.GenericVarianceFlags.Length);
                    }
                }

                // TODO! Change to if template is Universal or non-Existent
                if (state.TypeSize.HasValue)
                {
                    baseSize = state.TypeSize.Value;

                    int baseSizeBeforeAlignment = baseSize;

                    baseSize = MemoryHelpers.AlignUp(baseSize, IntPtr.Size);

                    if (isValueType)
                    {
                        // Compute the valuetype padding size based on size before adding the object type pointer field to the size
                        uint cbValueTypeFieldPadding = (uint)(baseSize - baseSizeBeforeAlignment);

                        // Add Object type pointer field to base size
                        baseSize += IntPtr.Size;

                        valueTypeFieldPaddingEncoded = (uint)EEType.ComputeValueTypeFieldPaddingFieldValue(cbValueTypeFieldPadding, (uint)state.FieldAlignment.Value);
                    }

                    // Minimum base size is 3 pointers, and requires us to bump the size of an empty class type
                    if (baseSize <= IntPtr.Size)
                    {
                        // ValueTypes should already have had their size bumped up by the normal type layout process
                        Debug.Assert(!isValueType);
                        baseSize += IntPtr.Size;
                    }

                    // Add sync block skew
                    baseSize += IntPtr.Size;

                    // Minimum basesize is 3 pointers
                    Debug.Assert(baseSize >= (IntPtr.Size * 3));
                }

                // Optional fields encoding
                int cbOptionalFieldsSize;
                OptionalFieldsRuntimeBuilder optionalFields;
                {
                    optionalFields = new OptionalFieldsRuntimeBuilder(pTemplateEEType != null ? pTemplateEEType->OptionalFieldsPtr : null);

                    UInt32 rareFlags = optionalFields.GetFieldValue(EETypeOptionalFieldTag.RareFlags, 0);
                    rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeFlag;           // Set the IsDynamicTypeFlag
                    rareFlags &= ~(uint)EETypeRareFlags.NullableTypeViaIATFlag;     // Remove the NullableTypeViaIATFlag flag
                    rareFlags &= ~(uint)EETypeRareFlags.HasSealedVTableEntriesFlag; // Remove the HasSealedVTableEntriesFlag
                                                                                    // we'll set IsDynamicTypeWithSealedVTableEntriesFlag instead

                    // Set the IsDynamicTypeWithSealedVTableEntriesFlag if needed
                    if (state.NumSealedVTableEntries > 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithSealedVTableEntriesFlag;
                    }

                    if (requiresDynamicDispatchMap)
                    {
                        rareFlags |= (uint)EETypeRareFlags.HasDynamicallyAllocatedDispatchMapFlag;
                    }

                    if (state.NonGcDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithNonGcStatics;
                    }

                    if (state.GcDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithGcStatics;
                    }

                    if (state.ThreadDataSize != 0)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsDynamicTypeWithThreadStatics;
                    }

#if ARM
                    if (state.FieldAlignment == 8)
                    {
                        rareFlags |= (uint)EETypeRareFlags.RequiresAlign8Flag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.RequiresAlign8Flag;
                    }

                    if (state.IsHFA)
                    {
                        rareFlags |= (uint)EETypeRareFlags.IsHFAFlag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.IsHFAFlag;
                    }
#endif
                    if (state.HasStaticConstructor)
                    {
                        rareFlags |= (uint)EETypeRareFlags.HasCctorFlag;
                    }
                    else
                    {
                        rareFlags &= ~(uint)EETypeRareFlags.HasCctorFlag;
                    }

                    rareFlags |= (uint)EETypeRareFlags.HasDynamicModuleFlag;

                    optionalFields.SetFieldValue(EETypeOptionalFieldTag.RareFlags, rareFlags);

                    // Dispatch map is fetched either from template type, or from the dynamically allocated DispatchMap field
                    optionalFields.ClearField(EETypeOptionalFieldTag.DispatchMap);

                    optionalFields.ClearField(EETypeOptionalFieldTag.ValueTypeFieldPadding);

                    if (valueTypeFieldPaddingEncoded != 0)
                    {
                        optionalFields.SetFieldValue(EETypeOptionalFieldTag.ValueTypeFieldPadding, valueTypeFieldPaddingEncoded);
                    }

                    // Compute size of optional fields encoding
                    cbOptionalFieldsSize = optionalFields.Encode();
                    Debug.Assert(cbOptionalFieldsSize > 0);
                }

                // Note: The number of vtable slots on the EEType to create is not necessary equal to the number of
                // vtable slots on the template type for universal generics (see ComputeVTableLayout)
                ushort numVtableSlots = state.NumVTableSlots;

                // Compute the EEType size and allocate it
                EEType *pEEType;
                {
                    // In order to get the size of the EEType to allocate we need the following information
                    // 1) The number of VTable slots (from the TypeBuilderState)
                    // 2) The number of Interfaces (from the template)
                    // 3) Whether or not there is a finalizer (from the template)
                    // 4) Optional fields size
                    // 5) Whether or not the type is nullable (from the template)
                    // 6) Whether or not the type has sealed virtuals (from the TypeBuilderState)
                    int cbEEType = (int)EEType.GetSizeofEEType(
                        numVtableSlots,
                        runtimeInterfacesLength,
                        hasFinalizer,
                        true,
                        isNullable,
                        state.NumSealedVTableEntries > 0,
                        isGeneric,
                        state.NonGcDataSize != 0,
                        state.GcDataSize != 0,
                        state.ThreadDataSize != 0);

                    // Dynamic types have an extra pointer-sized field that contains a pointer to their template type
                    cbEEType += IntPtr.Size;

                    // Check if we need another pointer sized field for a dynamic DispatchMap
                    cbEEType += (requiresDynamicDispatchMap ? IntPtr.Size : 0);

                    // Add another pointer sized field for a DynamicModule
                    cbEEType += IntPtr.Size;

                    int cbGCDesc        = GetInstanceGCDescSize(state, pTemplateEEType, isValueType, isArray);
                    int cbGCDescAligned = MemoryHelpers.AlignUp(cbGCDesc, IntPtr.Size);

                    // Allocate enough space for the EEType + gcDescSize
                    eeTypePtrPlusGCDesc = MemoryHelpers.AllocateMemory(cbGCDescAligned + cbEEType + cbOptionalFieldsSize);

                    // Get the EEType pointer, and the template EEType pointer
                    pEEType = (EEType *)(eeTypePtrPlusGCDesc + cbGCDescAligned);
                    state.HalfBakedRuntimeTypeHandle = pEEType->ToRuntimeTypeHandle();

                    // Set basic EEType fields
                    pEEType->ComponentSize  = componentSize;
                    pEEType->Flags          = flags;
                    pEEType->BaseSize       = (uint)baseSize;
                    pEEType->NumVtableSlots = numVtableSlots;
                    pEEType->NumInterfaces  = runtimeInterfacesLength;
                    pEEType->HashCode       = hashCodeOfNewType;

                    // Write the GCDesc
                    bool isSzArray = isArray ? state.ArrayRank < 1 : false;
                    int  arrayRank = isArray ? state.ArrayRank.Value : 0;
                    CreateInstanceGCDesc(state, pTemplateEEType, pEEType, baseSize, cbGCDesc, isValueType, isArray, isSzArray, arrayRank);
                    Debug.Assert(pEEType->HasGCPointers == (cbGCDesc != 0));

#if GENERICS_FORCE_USG
                    if (state.NonUniversalTemplateType != null)
                    {
                        Debug.Assert(state.NonUniversalInstanceGCDescSize == cbGCDesc, "Non-universal instance GCDesc size not matching with universal GCDesc size!");
                        Debug.Assert(cbGCDesc == 0 || pEEType->HasGCPointers);

                        // The TestGCDescsForEquality helper will compare 2 GCDescs for equality, 4 bytes at a time (GCDesc contents treated as integers), and will read the
                        // GCDesc data in *reverse* order for instance GCDescs (subtracts 4 from the pointer values at each iteration).
                        //    - For the first GCDesc, we use (pEEType - 4) to point to the first 4-byte integer directly preceeding the EEType
                        //    - For the second GCDesc, given that the state.NonUniversalInstanceGCDesc already points to the first byte preceeding the template EEType, we
                        //      subtract 3 to point to the first 4-byte integer directly preceeding the template EEtype
                        TestGCDescsForEquality(new IntPtr((byte *)pEEType - 4), state.NonUniversalInstanceGCDesc - 3, cbGCDesc, true);
                    }
#endif

                    // Copy the encoded optional fields buffer to the newly allocated memory, and update the OptionalFields field on the EEType
                    // It is important to set the optional fields first on the newly created EEType, because all other 'setters'
                    // will assert that the type is dynamic, just to make sure we are not making any changes to statically compiled types
                    pEEType->OptionalFieldsPtr = (byte *)pEEType + cbEEType;
                    optionalFields.WriteToEEType(pEEType, cbOptionalFieldsSize);

#if CORERT
                    pEEType->PointerToTypeManager = PermanentAllocatedMemoryBlobs.GetPointerToIntPtr(moduleInfo.Handle);
#endif
                    pEEType->DynamicModule = dynamicModulePtr;

                    // Copy VTable entries from template type
                    int     numSlotsFilled = 0;
                    IntPtr *pVtable        = (IntPtr *)((byte *)pEEType + sizeof(EEType));
                    if (pTemplateEEType != null)
                    {
                        IntPtr *pTemplateVtable = (IntPtr *)((byte *)pTemplateEEType + sizeof(EEType));
                        for (int i = 0; i < pTemplateEEType->NumVtableSlots; i++)
                        {
                            int vtableSlotInDynamicType = requireVtableSlotMapping ? state.VTableSlotsMapping.GetVTableSlotInTargetType(i) : i;
                            if (vtableSlotInDynamicType != -1)
                            {
                                Debug.Assert(vtableSlotInDynamicType < numVtableSlots);

                                IntPtr dictionaryPtrValue;
                                if (requireVtableSlotMapping && state.VTableSlotsMapping.IsDictionarySlot(i, out dictionaryPtrValue))
                                {
                                    // This must be the dictionary pointer value of one of the base types of the
                                    // current universal generic type being constructed.
                                    pVtable[vtableSlotInDynamicType] = dictionaryPtrValue;

                                    // Assert that the current template vtable slot is also a NULL value since all
                                    // universal generic template types have NULL dictionary slot values in their vtables
                                    Debug.Assert(pTemplateVtable[i] == IntPtr.Zero);
                                }
                                else
                                {
                                    pVtable[vtableSlotInDynamicType] = pTemplateVtable[i];
                                }
                                numSlotsFilled++;
                            }
                        }
                    }
                    else if (isGenericEETypeDef)
                    {
                        // If creating a Generic Type Definition
                        Debug.Assert(pEEType->NumVtableSlots == 0);
                    }
                    else
                    {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                        // Dynamically loaded type

                        // Fill the vtable with vtable resolution thunks in all slots except for
                        // the dictionary slots, which should be filled with dictionary pointers if those
                        // dictionaries are already published.

                        TypeDesc nextTypeToExamineForDictionarySlot = state.TypeBeingBuilt;
                        TypeDesc typeWithDictionary;
                        int      nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);

                        for (int iSlot = pEEType->NumVtableSlots - 1; iSlot >= 0; iSlot--)
                        {
                            bool isDictionary = iSlot == nextDictionarySlot;
                            if (!isDictionary)
                            {
                                pVtable[iSlot] = LazyVTableResolver.GetThunkForSlot(iSlot);
                            }
                            else
                            {
                                if (typeWithDictionary.RetrieveRuntimeTypeHandleIfPossible())
                                {
                                    pVtable[iSlot] = typeWithDictionary.RuntimeTypeHandle.GetDictionary();
                                }
                                nextDictionarySlot = GetMostDerivedDictionarySlot(ref nextTypeToExamineForDictionarySlot, out typeWithDictionary);
                            }
                            numSlotsFilled++;
                        }
#else
                        Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                    }

                    Debug.Assert(numSlotsFilled == numVtableSlots);

                    // Copy Pointer to finalizer method from the template type
                    if (hasFinalizer)
                    {
                        if (pTemplateEEType != null)
                        {
                            pEEType->FinalizerCode = pTemplateEEType->FinalizerCode;
                        }
                        else
                        {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                            pEEType->FinalizerCode = LazyVTableResolver.GetFinalizerThunk();
#else
                            Environment.FailFast("Template type loader is null, but metadata based type loader is not in use");
#endif
                        }
                    }
                }

                // Copy the sealed vtable entries if they exist on the template type
                if (state.NumSealedVTableEntries > 0)
                {
                    state.HalfBakedSealedVTable = MemoryHelpers.AllocateMemory((int)state.NumSealedVTableEntries * IntPtr.Size);

                    UInt32 cbSealedVirtualSlotsTypeOffset = pEEType->GetFieldOffset(EETypeField.ETF_SealedVirtualSlots);
                    *((IntPtr *)((byte *)pEEType + cbSealedVirtualSlotsTypeOffset)) = state.HalfBakedSealedVTable;

                    for (UInt16 i = 0; i < state.NumSealedVTableEntries; i++)
                    {
                        IntPtr value = pTemplateEEType->GetSealedVirtualSlot(i);
                        pEEType->SetSealedVirtualSlot(value, i);
                    }
                }

                // Create a new DispatchMap for the type
                if (requiresDynamicDispatchMap)
                {
                    DispatchMap *pTemplateDispatchMap = (DispatchMap *)RuntimeAugments.GetDispatchMapForType(pTemplateEEType->ToRuntimeTypeHandle());

                    dynamicDispatchMapPtr = MemoryHelpers.AllocateMemory(pTemplateDispatchMap->Size);

                    UInt32 cbDynamicDispatchMapOffset = pEEType->GetFieldOffset(EETypeField.ETF_DynamicDispatchMap);
                    *((IntPtr *)((byte *)pEEType + cbDynamicDispatchMapOffset)) = dynamicDispatchMapPtr;

                    DispatchMap *pDynamicDispatchMap = (DispatchMap *)dynamicDispatchMapPtr;
                    pDynamicDispatchMap->NumEntries = pTemplateDispatchMap->NumEntries;

                    for (int i = 0; i < pTemplateDispatchMap->NumEntries; i++)
                    {
                        DispatchMap.DispatchMapEntry *pTemplateEntry = (*pTemplateDispatchMap)[i];
                        DispatchMap.DispatchMapEntry *pDynamicEntry  = (*pDynamicDispatchMap)[i];

                        pDynamicEntry->_usInterfaceIndex      = pTemplateEntry->_usInterfaceIndex;
                        pDynamicEntry->_usInterfaceMethodSlot = pTemplateEntry->_usInterfaceMethodSlot;
                        if (pTemplateEntry->_usImplMethodSlot < pTemplateEEType->NumVtableSlots)
                        {
                            pDynamicEntry->_usImplMethodSlot = (ushort)state.VTableSlotsMapping.GetVTableSlotInTargetType(pTemplateEntry->_usImplMethodSlot);
                            Debug.Assert(pDynamicEntry->_usImplMethodSlot < numVtableSlots);
                        }
                        else
                        {
                            // This is an entry in the sealed vtable. We need to adjust the slot number based on the number of vtable slots
                            // in the dynamic EEType
                            pDynamicEntry->_usImplMethodSlot = (ushort)(pTemplateEntry->_usImplMethodSlot - pTemplateEEType->NumVtableSlots + numVtableSlots);
                            Debug.Assert(state.NumSealedVTableEntries > 0 &&
                                         pDynamicEntry->_usImplMethodSlot >= numVtableSlots &&
                                         (pDynamicEntry->_usImplMethodSlot - numVtableSlots) < state.NumSealedVTableEntries);
                        }
                    }
                }

                if (pTemplateEEType != null)
                {
                    pEEType->DynamicTemplateType = pTemplateEEType;
                }
                else
                {
                    // Use object as the template type for non-template based EETypes. This will
                    // allow correct Module identification for types.

                    if (state.TypeBeingBuilt.HasVariance)
                    {
                        // TODO! We need to have a variant EEType here if the type has variance, as the
                        // CreateGenericInstanceDescForType requires it. However, this is a ridiculous api surface
                        // When we remove GenericInstanceDescs from the product, get rid of this weird special
                        // case
                        pEEType->DynamicTemplateType = typeof(IEnumerable <int>).TypeHandle.ToEETypePtr();
                    }
                    else
                    {
                        pEEType->DynamicTemplateType = typeof(object).TypeHandle.ToEETypePtr();
                    }
                }

                int nonGCStaticDataOffset = 0;

                if (!isArray && !isGenericEETypeDef)
                {
                    nonGCStaticDataOffset = state.HasStaticConstructor ? -TypeBuilder.ClassConstructorOffset : 0;

                    // create GC desc
                    if (state.GcDataSize != 0 && state.GcStaticDesc == IntPtr.Zero)
                    {
                        int cbStaticGCDesc;
                        state.GcStaticDesc = CreateStaticGCDesc(state.StaticGCLayout, out state.AllocatedStaticGCDesc, out cbStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.GcStaticDesc, state.NonUniversalStaticGCDesc, cbStaticGCDesc, false);
#endif
                    }

                    if (state.ThreadDataSize != 0 && state.ThreadStaticDesc == IntPtr.Zero)
                    {
                        int cbThreadStaticGCDesc;
                        state.ThreadStaticDesc = CreateStaticGCDesc(state.ThreadStaticGCLayout, out state.AllocatedThreadStaticGCDesc, out cbThreadStaticGCDesc);
#if GENERICS_FORCE_USG
                        TestGCDescsForEquality(state.ThreadStaticDesc, state.NonUniversalThreadStaticGCDesc, cbThreadStaticGCDesc, false);
#endif
                    }

                    // If we have a class constructor, our NonGcDataSize MUST be non-zero
                    Debug.Assert(!state.HasStaticConstructor || (state.NonGcDataSize != 0));
                }

                if (isGeneric)
                {
                    if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, arity, state.NonGcDataSize, nonGCStaticDataOffset,
                                                                          state.GcDataSize, (int)state.ThreadStaticOffset, state.GcStaticDesc, state.ThreadStaticDesc, state.GenericVarianceFlags))
                    {
                        throw new OutOfMemoryException();
                    }
                }
                else
                {
                    Debug.Assert(arity == 0 || isGenericEETypeDef);
                    // We don't need to report the non-gc and gc static data regions and allocate them for non-generics,
                    // as we currently place these fields directly into the image
                    if (!isGenericEETypeDef && state.ThreadDataSize != 0)
                    {
                        // Types with thread static fields ALWAYS get a GID. The GID is used to perform GC
                        // and lifetime management of the thread static data. However, these GIDs are only used for that
                        // so the specified GcDataSize, etc are 0
                        if (!RuntimeAugments.CreateGenericInstanceDescForType(*(RuntimeTypeHandle *)&pEEType, 0, 0, 0, 0, (int)state.ThreadStaticOffset, IntPtr.Zero, state.ThreadStaticDesc, null))
                        {
                            throw new OutOfMemoryException();
                        }
                    }
                }

                if (state.Dictionary != null)
                {
                    state.HalfBakedDictionary = state.Dictionary.Allocate();
                }

                Debug.Assert(!state.HalfBakedRuntimeTypeHandle.IsNull());
                Debug.Assert((state.NumSealedVTableEntries == 0 && state.HalfBakedSealedVTable == IntPtr.Zero) || (state.NumSealedVTableEntries > 0 && state.HalfBakedSealedVTable != IntPtr.Zero));
                Debug.Assert((state.Dictionary == null && state.HalfBakedDictionary == IntPtr.Zero) || (state.Dictionary != null && state.HalfBakedDictionary != IntPtr.Zero));

                successful = true;
            }
            finally
            {
                if (!successful)
                {
                    if (eeTypePtrPlusGCDesc != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(eeTypePtrPlusGCDesc);
                    }
                    if (dynamicDispatchMapPtr != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(dynamicDispatchMapPtr);
                    }
                    if (state.HalfBakedSealedVTable != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(state.HalfBakedSealedVTable);
                    }
                    if (state.HalfBakedDictionary != IntPtr.Zero)
                    {
                        MemoryHelpers.FreeMemory(state.HalfBakedDictionary);
                    }
                    if (state.AllocatedStaticGCDesc)
                    {
                        MemoryHelpers.FreeMemory(state.GcStaticDesc);
                    }
                    if (state.AllocatedThreadStaticGCDesc)
                    {
                        MemoryHelpers.FreeMemory(state.ThreadStaticDesc);
                    }
                }
            }
        }
Example #27
0
 public override IntPtr ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(IntPtr unboxingFunctionPointer, RuntimeTypeHandle declaringType)
 {
     return TypeLoaderEnvironment.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(unboxingFunctionPointer, declaringType);
 }
Example #28
0
        /// <summary>
        /// Try to look up field access info for given canon in metadata blobs for all available modules.
        /// </summary>
        /// <param name="metadataReader">Metadata reader for the declaring type</param>
        /// <param name="declaringTypeHandle">Declaring type for the method</param>
        /// <param name="fieldHandle">Field handle</param>
        /// <param name="canonFormKind">Canonical form to use</param>
        /// <param name="fieldAccessMetadata">Output - metadata information for field accessor construction</param>
        /// <returns>true when found, false otherwise</returns>
        private static unsafe bool TryGetFieldAccessMetadataFromFieldAccessMap(
            MetadataReader metadataReader,
            RuntimeTypeHandle declaringTypeHandle,
            FieldHandle fieldHandle,
            CanonicalFormKind canonFormKind,
            ref FieldAccessMetadata fieldAccessMetadata)
        {
            CanonicallyEquivalentEntryLocator canonWrapper = new CanonicallyEquivalentEntryLocator(declaringTypeHandle, canonFormKind);
            string            fieldName = null;
            RuntimeTypeHandle declaringTypeHandleDefinition = TypeLoaderEnvironment.GetTypeDefinition(declaringTypeHandle);

            foreach (NativeFormatModuleInfo mappingTableModule in ModuleList.EnumerateModules(RuntimeAugments.GetModuleFromTypeHandle(declaringTypeHandle)))
            {
                NativeReader fieldMapReader;
                if (!TryGetNativeReaderForBlob(mappingTableModule, ReflectionMapBlob.FieldAccessMap, out fieldMapReader))
                {
                    continue;
                }

                NativeParser    fieldMapParser = new NativeParser(fieldMapReader, 0);
                NativeHashtable fieldHashtable = new NativeHashtable(fieldMapParser);

                ExternalReferencesTable externalReferences = default(ExternalReferencesTable);
                if (!externalReferences.InitializeCommonFixupsTable(mappingTableModule))
                {
                    continue;
                }

                var lookup = fieldHashtable.Lookup(canonWrapper.LookupHashCode);

                NativeParser entryParser;
                while (!(entryParser = lookup.GetNext()).IsNull)
                {
                    // Grammar of a hash table entry:
                    // Flags + DeclaringType + MdHandle or Name + Cookie or Ordinal or Offset

                    FieldTableFlags entryFlags = (FieldTableFlags)entryParser.GetUnsigned();

                    if ((canonFormKind == CanonicalFormKind.Universal) != ((entryFlags & FieldTableFlags.IsUniversalCanonicalEntry) != 0))
                    {
                        continue;
                    }

                    RuntimeTypeHandle entryDeclaringTypeHandle = externalReferences.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned());
                    if (!entryDeclaringTypeHandle.Equals(declaringTypeHandle) &&
                        !canonWrapper.IsCanonicallyEquivalent(entryDeclaringTypeHandle))
                    {
                        continue;
                    }

                    if ((entryFlags & FieldTableFlags.HasMetadataHandle) != 0)
                    {
                        Handle entryFieldHandle = (((int)HandleType.Field << 24) | (int)entryParser.GetUnsigned()).AsHandle();
                        if (!fieldHandle.Equals(entryFieldHandle))
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (fieldName == null)
                        {
                            QTypeDefinition qTypeDefinition;

                            bool success = Instance.TryGetMetadataForNamedType(
                                declaringTypeHandleDefinition,
                                out qTypeDefinition);
                            Debug.Assert(success);

                            MetadataReader nativeFormatMetadataReader = qTypeDefinition.NativeFormatReader;

                            fieldName = nativeFormatMetadataReader.GetString(fieldHandle.GetField(nativeFormatMetadataReader).Name);
                        }

                        string entryFieldName = entryParser.GetString();

                        if (fieldName != entryFieldName)
                        {
                            continue;
                        }
                    }

                    int    fieldOffset;
                    IntPtr fieldAddressCookie = IntPtr.Zero;

                    if (canonFormKind == CanonicalFormKind.Universal)
                    {
                        if (!TypeLoaderEnvironment.Instance.TryGetFieldOffset(declaringTypeHandle, entryParser.GetUnsigned() /* field ordinal */, out fieldOffset))
                        {
                            Debug.Assert(false);
                            return(false);
                        }
                    }
                    else
                    {
                        if ((entryFlags & FieldTableFlags.FieldOffsetEncodedDirectly) != 0)
                        {
                            fieldOffset = (int)entryParser.GetUnsigned();
                        }
                        else
                        {
                            fieldOffset        = 0;
                            fieldAddressCookie = externalReferences.GetAddressFromIndex(entryParser.GetUnsigned());

                            FieldTableFlags storageClass = entryFlags & FieldTableFlags.StorageClass;
                            if (storageClass == FieldTableFlags.GCStatic || storageClass == FieldTableFlags.ThreadStatic)
                            {
                                fieldOffset = (int)entryParser.GetUnsigned();
                            }
                        }
                    }

                    fieldAccessMetadata.MappingTableModule = mappingTableModule.Handle;
                    fieldAccessMetadata.Cookie             = fieldAddressCookie;
                    fieldAccessMetadata.Flags  = entryFlags;
                    fieldAccessMetadata.Offset = fieldOffset;
                    return(true);
                }
            }

            return(false);
        }