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()); }
// 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))); }
/// <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)); }
/// <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)); }
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); }
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); }
// 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; }
/// <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); }
/// <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); }
/// <summary> /// Get the virtual slot index of a given virtual method. (This is only valid for non-interface virtuals) /// </summary> /// <param name="virtualMethod">virtual method to get slot index of</param> /// <returns>slot index, or -1</returns> public static int VirtualMethodToSlotIndex(MethodDesc virtualMethod) { Debug.Assert(virtualMethod.IsVirtual); Debug.Assert(!virtualMethod.OwningType.IsInterface); MethodDesc definingMethod = virtualMethod; // If not newslot, make sure we've got the defining method here if (!definingMethod.IsNewSlot) { definingMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(definingMethod); } TypeDesc definingType = definingMethod.OwningType; // Two possible cases for determining slot index that will work // 1. The definingType is a R2R type with full metadata. Compute the MethodDesc, by scanning the list of virtuals present in metadata. Its possible to not get a slot index. In that case return -1 // 2. The definingType is pregenerated, but we can go from metadata to slot index via the runtime mapping tables. if (!IsPregeneratedOrTemplateTypeLoaded(definingType)) { // Case 1 MetadataType definingMetadataType = (MetadataType)definingType; int baseTypeSlotCount = 0; if (definingMetadataType.BaseType != null) { unsafe { if (definingMetadataType.BaseType.RetrieveRuntimeTypeHandleIfPossible()) { baseTypeSlotCount = definingMetadataType.BaseType.GetRuntimeTypeHandle().ToEETypePtr()->NumVtableSlots; } else { baseTypeSlotCount = definingMetadataType.BaseType.GetOrCreateTypeBuilderState().NumVTableSlots; } } } int currentSlot = baseTypeSlotCount; if (definingMetadataType.ConvertToCanonForm(CanonicalFormKind.Specific).IsCanonicalSubtype(CanonicalFormKind.Specific)) { // Deal with the space reserved for the canonical dictionary currentSlot++; } foreach (MethodDesc method in definingMetadataType.GetMethods()) { if (!MethodDefinesVTableSlot(method)) { continue; } if (method == definingMethod) { return(currentSlot); } else { currentSlot++; } } // No slot index defined. return(-1); } else { // Case 2, pregenerated type TypeSystem.NativeFormat.NativeFormatMethod definingMethodOpenType = (TypeSystem.NativeFormat.NativeFormatMethod)definingMethod.GetTypicalMethodDefinition(); MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer( definingMethodOpenType.MetadataReader, definingMethodOpenType.Handle); if (!definingType.RetrieveRuntimeTypeHandleIfPossible()) { new TypeBuilder().BuildType(definingType); } TypeSystem.NativeFormat.NativeFormatType definingNativeFormatType = (TypeSystem.NativeFormat.NativeFormatType)definingType.GetTypeDefinition(); NativeFormatModuleInfo moduleToLookIn = definingNativeFormatType.MetadataUnit.RuntimeModuleInfo; TypeLoaderEnvironment.VirtualResolveDataResult virtualSlotInfo; if (!TypeLoaderEnvironment.TryGetVirtualResolveData(moduleToLookIn, definingType.RuntimeTypeHandle, Array.Empty <RuntimeTypeHandle>(), ref methodSignatureComparer, out virtualSlotInfo)) { return(-1); } Debug.Assert(!virtualSlotInfo.IsGVM); return(virtualSlotInfo.SlotIndex); } }
private 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; }
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); }
static TypeLoaderEnvironment() { Instance = new TypeLoaderEnvironment(); RuntimeAugments.InitializeLookups(new Callbacks()); }
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(); } } }
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); } } } }
public override IntPtr ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(IntPtr unboxingFunctionPointer, RuntimeTypeHandle declaringType) { return TypeLoaderEnvironment.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(unboxingFunctionPointer, declaringType); }
/// <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); }