private static TypeDesc TryGetTypeTemplate_Internal(TypeDesc concreteType, CanonicalFormKind kind, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { nativeLayoutInfoModule = null; nativeLayoutInfoToken = 0; var canonForm = concreteType.ConvertToCanonForm(kind); var hashCode = canonForm.GetHashCode(); foreach (NativeFormatModuleInfo moduleInfo in ModuleList.EnumerateModules()) { ExternalReferencesTable externalFixupsTable; NativeHashtable typeTemplatesHashtable = LoadHashtable(moduleInfo, ReflectionMapBlob.TypeTemplateMap, out externalFixupsTable); if (typeTemplatesHashtable.IsNull) { continue; } var enumerator = typeTemplatesHashtable.Lookup(hashCode); NativeParser entryParser; while (!(entryParser = enumerator.GetNext()).IsNull) { RuntimeTypeHandle candidateTemplateTypeHandle = externalFixupsTable.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); TypeDesc candidateTemplate = concreteType.Context.ResolveRuntimeTypeHandle(candidateTemplateTypeHandle); if (canonForm == candidateTemplate.ConvertToCanonForm(kind)) { TypeLoaderLogger.WriteLine("Found template for type " + concreteType.ToString() + ": " + candidateTemplate.ToString()); nativeLayoutInfoToken = entryParser.GetUnsigned(); if (nativeLayoutInfoToken == BadTokenFixupValue) { // TODO: once multifile gets fixed up, make this throw a BadImageFormatException TypeLoaderLogger.WriteLine("ERROR: template not fixed up, skipping"); continue; } Debug.Assert( (kind != CanonicalFormKind.Universal) || (kind == CanonicalFormKind.Universal && candidateTemplate == candidateTemplate.ConvertToCanonForm(kind))); nativeLayoutInfoModule = moduleInfo; return(candidateTemplate); } } } TypeLoaderLogger.WriteLine("ERROR: Cannot find a suitable template for type " + concreteType.ToString()); return(null); }
// // Returns the template method for a generic method instantation // public static InstantiatedMethod TryGetGenericMethodTemplate(InstantiatedMethod concreteMethod, out NativeFormatModuleInfo nativeLayoutInfoModule, out uint nativeLayoutInfoToken) { // First, see if there is a specific canonical template InstantiatedMethod result = TryGetGenericMethodTemplate_Internal(concreteMethod, CanonicalFormKind.Specific, out nativeLayoutInfoModule, out nativeLayoutInfoToken); // If not found, see if there's a universal canonical template if (result == null) { result = TryGetGenericMethodTemplate_Internal(concreteMethod, CanonicalFormKind.Universal, out nativeLayoutInfoModule, out nativeLayoutInfoToken); } return(result); }
/// <summary> /// Initialize ExternalReferencesTable using the CommonFixupsTable metadata blob on a given module. /// </summary> /// <param name="moduleHandle">Module handle is used to locate the CommonFixupsTable blob</param> /// <returns>true when the CommonFixupsTable blob was found in the given module, false when not</returns> public bool InitializeCommonFixupsTable(NativeFormatModuleInfo module) { return(Initialize(module, ReflectionMapBlob.CommonFixupsTable)); }
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); }
/// <summary> /// Attempt to convert the dispatch cell to a metadata token to a more efficient vtable dispatch or interface/slot dispatch. /// Failure to convert is not a correctness issue. We also support performing a dispatch based on metadata token alone. /// </summary> private static DispatchCellInfo ConvertDispatchCellInfo_Inner(NativeFormatModuleInfo module, DispatchCellInfo cellInfo) { Debug.Assert(cellInfo.CellType == DispatchCellType.MetadataToken); TypeSystemContext context = TypeSystemContextFactory.Create(); MethodDesc targetMethod = context.ResolveMetadataUnit(module).GetMethod(cellInfo.MetadataToken.AsHandle(), null); Debug.Assert(!targetMethod.HasInstantiation); // At this time we do not support generic virtuals through the dispatch mechanism Debug.Assert(targetMethod.IsVirtual); if (targetMethod.OwningType.IsInterface) { if (!LazyVTableResolver.TryGetInterfaceSlotNumberFromMethod(targetMethod, out cellInfo.InterfaceSlot)) { // Unable to resolve interface method. Fail, by not mutating cellInfo return(cellInfo); } if (!targetMethod.OwningType.RetrieveRuntimeTypeHandleIfPossible()) { new TypeBuilder().BuildType(targetMethod.OwningType); } cellInfo.CellType = DispatchCellType.InterfaceAndSlot; cellInfo.InterfaceType = targetMethod.OwningType.RuntimeTypeHandle.ToIntPtr(); cellInfo.MetadataToken = 0; } else { // Virtual function case, attempt to resolve to a VTable slot offset. // If the offset is less than 4096 update the cellInfo #if DEBUG // The path of resolving a metadata token at dispatch time is relatively rare in practice. // Force it to occur in debug builds with much more regularity if ((s_ConvertDispatchCellInfoCounter % 16) == 0) { s_ConvertDispatchCellInfoCounter++; TypeSystemContextFactory.Recycle(context); return(cellInfo); } s_ConvertDispatchCellInfoCounter++; #endif int slotIndexOfMethod = LazyVTableResolver.VirtualMethodToSlotIndex(targetMethod); int vtableOffset = -1; if (slotIndexOfMethod >= 0) { vtableOffset = LazyVTableResolver.SlotIndexToEETypeVTableOffset(slotIndexOfMethod); } if ((vtableOffset < 4096) && (vtableOffset != -1)) { cellInfo.CellType = DispatchCellType.VTableOffset; cellInfo.VTableOffset = checked ((uint)vtableOffset); cellInfo.MetadataToken = 0; } // Otherwise, do nothing, and resolve with a metadata dispatch later } TypeSystemContextFactory.Recycle(context); return(cellInfo); }
/// <summary> /// Initialize ExternalReferencesTable using the NativeStatics metadata blob on a given module. /// </summary> /// <param name="moduleHandle">Module handle is used to locate the NativeStatics blob</param> /// <returns>true when the NativeStatics blob was found in the given module, false when not</returns> public bool InitializeNativeStatics(NativeFormatModuleInfo module) { return(Initialize(module, ReflectionMapBlob.NativeStatics)); }
private bool CompareMethodSigs(NativeParser parser1, NativeFormatModuleInfo moduleHandle1, NativeParser parser2, NativeFormatModuleInfo moduleHandle2) { MethodCallingConvention callingConvention1 = (MethodCallingConvention)parser1.GetUnsigned(); MethodCallingConvention callingConvention2 = (MethodCallingConvention)parser2.GetUnsigned(); if (callingConvention1 != callingConvention2) { return(false); } if ((callingConvention1 & MethodCallingConvention.Generic) == MethodCallingConvention.Generic) { if (parser1.GetUnsigned() != parser2.GetUnsigned()) { return(false); } } uint parameterCount1 = parser1.GetUnsigned(); uint parameterCount2 = parser2.GetUnsigned(); if (parameterCount1 != parameterCount2) { return(false); } // Compare one extra parameter to account for the return type for (uint i = 0; i <= parameterCount1; i++) { if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2)) { return(false); } } return(true); }
private bool CompareTypeSigs(ref NativeParser parser1, NativeFormatModuleInfo moduleHandle1, ref NativeParser parser2, NativeFormatModuleInfo moduleHandle2) { // startOffset lets us backtrack to the TypeSignatureKind for external types since the TypeLoader // expects to read it in. uint data1; uint startOffset1 = parser1.Offset; var typeSignatureKind1 = parser1.GetTypeSignatureKind(out data1); // If the parser is at a lookback type, get a new parser for it and recurse. // Since we haven't read the element type of parser2 yet, we just pass it in unchanged if (typeSignatureKind1 == TypeSignatureKind.Lookback) { NativeParser lookbackParser1 = parser1.GetLookbackParser(data1); return(CompareTypeSigs(ref lookbackParser1, moduleHandle1, ref parser2, moduleHandle2)); } uint data2; uint startOffset2 = parser2.Offset; var typeSignatureKind2 = parser2.GetTypeSignatureKind(out data2); // If parser2 is a lookback type, we need to rewind parser1 to its startOffset1 // before recursing. if (typeSignatureKind2 == TypeSignatureKind.Lookback) { NativeParser lookbackParser2 = parser2.GetLookbackParser(data2); parser1 = new NativeParser(parser1.Reader, startOffset1); return(CompareTypeSigs(ref parser1, moduleHandle1, ref lookbackParser2, moduleHandle2)); } if (typeSignatureKind1 != typeSignatureKind2) { return(false); } switch (typeSignatureKind1) { case TypeSignatureKind.Lookback: { // Recursion above better have removed all lookbacks Debug.Assert(false, "Unexpected lookback type"); return(false); } case TypeSignatureKind.Modifier: { // Ensure the modifier kind (vector, pointer, byref) is the same if (data1 != data2) { return(false); } return(CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2)); } case TypeSignatureKind.Variable: { // variable index is in data if (data1 != data2) { return(false); } break; } case TypeSignatureKind.MultiDimArray: { // rank is in data if (data1 != data2) { return(false); } if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2)) { return(false); } uint boundCount1 = parser1.GetUnsigned(); uint boundCount2 = parser2.GetUnsigned(); if (boundCount1 != boundCount2) { return(false); } for (uint i = 0; i < boundCount1; i++) { if (parser1.GetUnsigned() != parser2.GetUnsigned()) { return(false); } } uint lowerBoundCount1 = parser1.GetUnsigned(); uint lowerBoundCount2 = parser2.GetUnsigned(); if (lowerBoundCount1 != lowerBoundCount2) { return(false); } for (uint i = 0; i < lowerBoundCount1; i++) { if (parser1.GetUnsigned() != parser2.GetUnsigned()) { return(false); } } break; } case TypeSignatureKind.FunctionPointer: { // callingConvention is in data if (data1 != data2) { return(false); } uint argCount1 = parser1.GetUnsigned(); uint argCount2 = parser2.GetUnsigned(); if (argCount1 != argCount2) { return(false); } for (uint i = 0; i < argCount1; i++) { if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2)) { return(false); } } break; } case TypeSignatureKind.Instantiation: { // Type parameter count is in data if (data1 != data2) { return(false); } if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2)) { return(false); } for (uint i = 0; i < data1; i++) { if (!CompareTypeSigs(ref parser1, moduleHandle1, ref parser2, moduleHandle2)) { return(false); } } break; } case TypeSignatureKind.External: { RuntimeTypeHandle typeHandle1 = GetExternalTypeHandle(moduleHandle1, data1); RuntimeTypeHandle typeHandle2 = GetExternalTypeHandle(moduleHandle2, data2); if (!typeHandle1.Equals(typeHandle2)) { return(false); } break; } default: return(false); } return(true); }
private bool FindMatchingInterfaceSlot(NativeFormatModuleInfo module, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch) { uint numTargetImplementations = entryParser.GetUnsigned(); for (uint j = 0; j < numTargetImplementations; j++) { uint nameAndSigToken = extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned()); MethodNameAndSignature targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken); RuntimeTypeHandle targetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle)); #endif uint numIfaceImpls = entryParser.GetUnsigned(); for (uint k = 0; k < numIfaceImpls; k++) { RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); uint numIfaceSigs = entryParser.GetUnsigned(); if (!openTargetTypeHandle.Equals(implementingTypeHandle)) { // Skip over signatures data for (uint l = 0; l < numIfaceSigs; l++) { entryParser.GetUnsigned(); } continue; } for (uint l = 0; l < numIfaceSigs; l++) { RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle); NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, extRefs.GetExternalNativeLayoutOffset(entryParser.GetUnsigned())); if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle)) { Debug.Assert(!currentIfaceTypeHandle.IsNull()); if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) || (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle))) { #if REFLECTION_EXECUTION_TRACE ReflectionExecutionLogger.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!"); #endif // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller declaringType = targetTypeHandle; methodNameAndSignature = targetMethodNameAndSignature; return(true); } } } } } return(false); }
/// <summary> /// IF THESE SEMANTICS EVER CHANGE UPDATE THE LOGIC WHICH DEFINES THIS BEHAVIOR IN /// THE DYNAMIC TYPE LOADER AS WELL AS THE COMPILER. /// (There is a version of this in UniversalGenericParameterLayout.cs that must be kept in sync with this.) /// /// Parameter's are considered to have type layout dependent on their generic instantiation /// if the type of the parameter in its signature is a type variable, or if the type is a generic /// structure which meets 2 characteristics: /// 1. Structure size/layout is affected by the size/layout of one or more of its generic parameters /// 2. One or more of the generic parameters is a type variable, or a generic structure which also recursively /// would satisfy constraint 2. (Note, that in the recursion case, whether or not the structure is affected /// by the size/layout of its generic parameters is not investigated.) /// /// Examples parameter types, and behavior. /// /// T = true /// List[T] = false /// StructNotDependentOnArgsForSize[T] = false /// GenStructDependencyOnArgsForSize[T] = true /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[T]] = true /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[List[T]]]] = false /// /// Example non-parameter type behavior /// T = true /// List[T] = false /// StructNotDependentOnArgsForSize[T] = *true* /// GenStructDependencyOnArgsForSize[T] = true /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[T]] = true /// StructNotDependentOnArgsForSize[GenStructDependencyOnArgsForSize[List[T]]]] = false /// </summary> private bool TypeSignatureHasVarsNeedingCallingConventionConverter(ref NativeParser parser, NativeFormatModuleInfo moduleHandle, TypeSystemContext context, HasVarsInvestigationLevel investigationLevel) { uint data; var kind = parser.GetTypeSignatureKind(out data); switch (kind) { case TypeSignatureKind.External: return(false); case TypeSignatureKind.Variable: return(true); case TypeSignatureKind.Lookback: { var lookbackParser = parser.GetLookbackParser(data); return(TypeSignatureHasVarsNeedingCallingConventionConverter(ref lookbackParser, moduleHandle, context, investigationLevel)); } case TypeSignatureKind.Instantiation: { RuntimeTypeHandle genericTypeDef; if (!TryGetTypeFromSimpleTypeSignature(ref parser, moduleHandle, out genericTypeDef)) { Debug.Assert(false); return(true); // Returning true will prevent further reading from the native parser } if (!RuntimeAugments.IsValueType(genericTypeDef)) { // Reference types are treated like pointers. No calling convention conversion needed. Just consume the rest of the signature. for (uint i = 0; i < data; i++) { TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore); } return(false); } else { bool result = false; for (uint i = 0; i < data; i++) { result = TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.NotParameter) || result; } if ((result == true) && (investigationLevel == HasVarsInvestigationLevel.Parameter)) { if (!TryComputeHasInstantiationDeterminedSize(genericTypeDef, context, out result)) { Environment.FailFast("Unable to setup calling convention converter correctly"); } return(result); } return(result); } } case TypeSignatureKind.Modifier: { // Arrays, pointers and byref types signatures are treated as pointers, not requiring calling convention conversion. // Just consume the parameter type from the stream and return false; TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore); return(false); } case TypeSignatureKind.MultiDimArray: { // No need for a calling convention converter for this case. Just consume the signature from the stream. TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore); uint boundCount = parser.GetUnsigned(); for (uint i = 0; i < boundCount; i++) { parser.GetUnsigned(); } uint lowerBoundCount = parser.GetUnsigned(); for (uint i = 0; i < lowerBoundCount; i++) { parser.GetUnsigned(); } } return(false); case TypeSignatureKind.FunctionPointer: { // No need for a calling convention converter for this case. Just consume the signature from the stream. uint argCount = parser.GetUnsigned(); for (uint i = 0; i < argCount; i++) { TypeSignatureHasVarsNeedingCallingConventionConverter(ref parser, moduleHandle, context, HasVarsInvestigationLevel.Ignore); } } return(false); default: parser.ThrowBadImageFormatException(); return(true); } }
/// <summary> /// Get the virtual slot index of a given virtual method. (This is only valid for non-interface virtuals) /// </summary> /// <param name="virtualMethod">virtual method to get slot index of</param> /// <returns>slot index, or -1</returns> public static int VirtualMethodToSlotIndex(MethodDesc virtualMethod) { Debug.Assert(virtualMethod.IsVirtual); Debug.Assert(!virtualMethod.OwningType.IsInterface); MethodDesc definingMethod = virtualMethod; // If not newslot, make sure we've got the defining method here if (!definingMethod.IsNewSlot) { definingMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(definingMethod); } TypeDesc definingType = definingMethod.OwningType; // Two possible cases for determining slot index that will work // 1. The definingType is a R2R type with full metadata. Compute the MethodDesc, by scanning the list of virtuals present in metadata. Its possible to not get a slot index. In that case return -1 // 2. The definingType is pregenerated, but we can go from metadata to slot index via the runtime mapping tables. if (!IsPregeneratedOrTemplateTypeLoaded(definingType)) { // Case 1 MetadataType definingMetadataType = (MetadataType)definingType; int baseTypeSlotCount = 0; if (definingMetadataType.BaseType != null) { unsafe { if (definingMetadataType.BaseType.RetrieveRuntimeTypeHandleIfPossible()) { baseTypeSlotCount = definingMetadataType.BaseType.GetRuntimeTypeHandle().ToEETypePtr()->NumVtableSlots; } else { baseTypeSlotCount = definingMetadataType.BaseType.GetOrCreateTypeBuilderState().NumVTableSlots; } } } int currentSlot = baseTypeSlotCount; if (definingMetadataType.ConvertToCanonForm(CanonicalFormKind.Specific).IsCanonicalSubtype(CanonicalFormKind.Specific)) { // Deal with the space reserved for the canonical dictionary currentSlot++; } foreach (MethodDesc method in definingMetadataType.GetMethods()) { if (!MethodDefinesVTableSlot(method)) { continue; } if (method == definingMethod) { return(currentSlot); } else { currentSlot++; } } // No slot index defined. return(-1); } else { // Case 2, pregenerated type TypeSystem.NativeFormat.NativeFormatMethod definingMethodOpenType = (TypeSystem.NativeFormat.NativeFormatMethod)definingMethod.GetTypicalMethodDefinition(); MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer( definingMethodOpenType.MetadataReader, definingMethodOpenType.Handle); if (!definingType.RetrieveRuntimeTypeHandleIfPossible()) { new TypeBuilder().BuildType(definingType); } TypeSystem.NativeFormat.NativeFormatType definingNativeFormatType = (TypeSystem.NativeFormat.NativeFormatType)definingType.GetTypeDefinition(); NativeFormatModuleInfo moduleToLookIn = definingNativeFormatType.MetadataUnit.RuntimeModuleInfo; TypeLoaderEnvironment.VirtualResolveDataResult virtualSlotInfo; if (!TypeLoaderEnvironment.TryGetVirtualResolveData(moduleToLookIn, definingType.RuntimeTypeHandle, Array.Empty <RuntimeTypeHandle>(), ref methodSignatureComparer, out virtualSlotInfo)) { return(-1); } Debug.Assert(!virtualSlotInfo.IsGVM); return(virtualSlotInfo.SlotIndex); } }
private bool FindMatchingInterfaceSlot(NativeFormatModuleInfo module, NativeReader nativeLayoutReader, ref NativeParser entryParser, ref ExternalReferencesTable extRefs, ref RuntimeTypeHandle declaringType, ref MethodNameAndSignature methodNameAndSignature, RuntimeTypeHandle instanceTypeHandle, RuntimeTypeHandle openTargetTypeHandle, RuntimeTypeHandle[] targetTypeInstantiation, bool variantDispatch, bool defaultMethods) { uint numTargetImplementations = entryParser.GetUnsigned(); #if GVM_RESOLUTION_TRACE Debug.WriteLine(" :: Declaring type = " + GetTypeNameDebug(declaringType)); Debug.WriteLine(" :: Target type = " + GetTypeNameDebug(openTargetTypeHandle)); #endif for (uint j = 0; j < numTargetImplementations; j++) { uint nameAndSigToken = entryParser.GetUnsigned(); MethodNameAndSignature targetMethodNameAndSignature = null; RuntimeTypeHandle targetTypeHandle = default; bool isDefaultInterfaceMethodImplementation; if (nameAndSigToken != SpecialGVMInterfaceEntry.Diamond && nameAndSigToken != SpecialGVMInterfaceEntry.Reabstraction) { targetMethodNameAndSignature = GetMethodNameAndSignatureFromNativeReader(nativeLayoutReader, module.Handle, nameAndSigToken); targetTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); isDefaultInterfaceMethodImplementation = RuntimeAugments.IsInterface(targetTypeHandle); #if GVM_RESOLUTION_TRACE Debug.WriteLine(" Searching for GVM implementation on targe type = " + GetTypeNameDebug(targetTypeHandle)); #endif } else { isDefaultInterfaceMethodImplementation = true; } uint numIfaceImpls = entryParser.GetUnsigned(); for (uint k = 0; k < numIfaceImpls; k++) { RuntimeTypeHandle implementingTypeHandle = extRefs.GetRuntimeTypeHandleFromIndex(entryParser.GetUnsigned()); #if GVM_RESOLUTION_TRACE Debug.WriteLine(" -> Current implementing type = " + GetTypeNameDebug(implementingTypeHandle)); #endif uint numIfaceSigs = entryParser.GetUnsigned(); if (!openTargetTypeHandle.Equals(implementingTypeHandle) || defaultMethods != isDefaultInterfaceMethodImplementation) { // Skip over signatures data for (uint l = 0; l < numIfaceSigs; l++) { entryParser.GetUnsigned(); } continue; } for (uint l = 0; l < numIfaceSigs; l++) { RuntimeTypeHandle currentIfaceTypeHandle = default(RuntimeTypeHandle); NativeParser ifaceSigParser = new NativeParser(nativeLayoutReader, entryParser.GetUnsigned()); if (TypeLoaderEnvironment.Instance.GetTypeFromSignatureAndContext(ref ifaceSigParser, module.Handle, targetTypeInstantiation, null, out currentIfaceTypeHandle)) { #if GVM_RESOLUTION_TRACE Debug.WriteLine(" -> Current interface on type = " + GetTypeNameDebug(currentIfaceTypeHandle)); #endif Debug.Assert(!currentIfaceTypeHandle.IsNull()); if ((!variantDispatch && declaringType.Equals(currentIfaceTypeHandle)) || (variantDispatch && RuntimeAugments.IsAssignableFrom(declaringType, currentIfaceTypeHandle))) { #if GVM_RESOLUTION_TRACE Debug.WriteLine(" " + (declaringType.Equals(currentIfaceTypeHandle) ? "Exact" : "Variant-compatible") + " match found on this target type!"); #endif if (targetMethodNameAndSignature == null) { if (nameAndSigToken == SpecialGVMInterfaceEntry.Diamond) { throw new AmbiguousImplementationException(); } else { Debug.Assert(nameAndSigToken == SpecialGVMInterfaceEntry.Reabstraction); throw new EntryPointNotFoundException(); } } // We found the GVM slot target for the input interface GVM call, so let's update the interface GVM slot and return success to the caller if (!RuntimeAugments.IsInterface(targetTypeHandle) || !RuntimeAugments.IsGenericTypeDefinition(targetTypeHandle)) { // Not a default interface method or default interface method on a non-generic type. // We have a usable type handle. declaringType = targetTypeHandle; } else if (RuntimeAugments.IsGenericType(currentIfaceTypeHandle) && RuntimeAugments.GetGenericDefinition(currentIfaceTypeHandle).Equals(targetTypeHandle)) { // Default interface method implemented on the same type that declared the slot. // Use the instantiation as-is from what we found. declaringType = currentIfaceTypeHandle; } else { declaringType = default; // Default interface method implemented on a different generic interface. // We need to find a usable instantiation. There should be only one match because we // would be dealing with a diamond otherwise. int numInstanceInterfaces = RuntimeAugments.GetInterfaceCount(instanceTypeHandle); for (int instIntfIndex = 0; instIntfIndex < numInstanceInterfaces; instIntfIndex++) { RuntimeTypeHandle instIntf = RuntimeAugments.GetInterface(instanceTypeHandle, instIntfIndex); if (RuntimeAugments.IsGenericType(instIntf) && RuntimeAugments.GetGenericDefinition(instIntf).Equals(targetTypeHandle)) { // Got a potential interface. Check if the implementing interface is in the interface // list. We don't want IsAssignableFrom because we need an exact match. int numIntInterfaces = RuntimeAugments.GetInterfaceCount(instIntf); for (int intIntfIndex = 0; intIntfIndex < numIntInterfaces; intIntfIndex++) { if (RuntimeAugments.GetInterface(instIntf, intIntfIndex).Equals(currentIfaceTypeHandle)) { Debug.Assert(declaringType.IsNull()); declaringType = instIntf; #if !DEBUG break; #endif } } #if !DEBUG if (!declaringType.IsNull()) { break; } #endif } } Debug.Assert(!declaringType.IsNull()); } methodNameAndSignature = targetMethodNameAndSignature; return(true); } } } } } return(false); }
// // Returns the native layout info reader // internal unsafe NativeReader GetNativeLayoutInfoReader(NativeFormatModuleInfo module) { return GetNativeLayoutInfoReader(module.Handle); }
/// <summary> /// Register all modules which were added (Registered) to the runtime and are not already registered with the TypeLoader. /// </summary> /// <param name="moduleType">Type to assign to all new modules.</param> public void RegisterNewModules(ModuleType moduleType) { // prevent multiple threads from registering modules concurrently using (LockHolder.Hold(_moduleRegistrationLock)) { // Fetch modules that have already been registered with the runtime int loadedModuleCount = RuntimeAugments.GetLoadedModules(null); TypeManagerHandle[] loadedModuleHandles = new TypeManagerHandle[loadedModuleCount]; int loadedModuleCountUpdated = RuntimeAugments.GetLoadedModules(loadedModuleHandles); Debug.Assert(loadedModuleCount == loadedModuleCountUpdated); LowLevelList <TypeManagerHandle> newModuleHandles = new LowLevelList <TypeManagerHandle>(loadedModuleHandles.Length); foreach (TypeManagerHandle moduleHandle in loadedModuleHandles) { // Skip already registered modules. int oldModuleIndex; if (_loadedModuleMap.HandleToModuleIndex.TryGetValue(moduleHandle, out oldModuleIndex)) { continue; } newModuleHandles.Add(moduleHandle); } // Copy existing modules to new dictionary int oldModuleCount = _loadedModuleMap.Modules.Length; ModuleInfo[] updatedModules = new ModuleInfo[oldModuleCount + newModuleHandles.Count]; if (oldModuleCount > 0) { Array.Copy(_loadedModuleMap.Modules, 0, updatedModules, 0, oldModuleCount); } for (int newModuleIndex = 0; newModuleIndex < newModuleHandles.Count; newModuleIndex++) { ModuleInfo newModuleInfo; unsafe { byte *pBlob; uint cbBlob; if (RuntimeAugments.FindBlob(newModuleHandles[newModuleIndex], (int)ReflectionMapBlob.EmbeddedMetadata, new IntPtr(&pBlob), new IntPtr(&cbBlob))) { newModuleInfo = new NativeFormatModuleInfo(newModuleHandles[newModuleIndex], moduleType, (IntPtr)pBlob, (int)cbBlob); } else { newModuleInfo = new ModuleInfo(newModuleHandles[newModuleIndex], moduleType); } } updatedModules[oldModuleCount + newModuleIndex] = newModuleInfo; if (_moduleRegistrationCallbacks != null) { _moduleRegistrationCallbacks(newModuleInfo); } } // Atomically update the module map _loadedModuleMap = new ModuleMap(updatedModules); } }
internal bool GetCallingConverterDataFromMethodSignature_NativeLayout_Common( TypeSystemContext context, RuntimeSignature methodSig, Instantiation typeInstantiation, Instantiation methodInstantiation, out bool hasThis, out TypeDesc[] parameters, out bool[] parametersWithGenericDependentLayout, NativeReader nativeReader, ulong[] debuggerPreparedExternalReferences) { bool isNotDebuggerCall = debuggerPreparedExternalReferences == null; hasThis = false; parameters = null; NativeLayoutInfoLoadContext nativeLayoutContext = new NativeLayoutInfoLoadContext(); nativeLayoutContext._module = isNotDebuggerCall ? (NativeFormatModuleInfo)methodSig.GetModuleInfo() : null; nativeLayoutContext._typeSystemContext = context; nativeLayoutContext._typeArgumentHandles = typeInstantiation; nativeLayoutContext._methodArgumentHandles = methodInstantiation; nativeLayoutContext._debuggerPreparedExternalReferences = debuggerPreparedExternalReferences; NativeFormatModuleInfo module = null; NativeReader reader = null; if (isNotDebuggerCall) { reader = GetNativeLayoutInfoReader(methodSig); module = ModuleList.Instance.GetModuleInfoByHandle(new TypeManagerHandle(methodSig.ModuleHandle)); } else { reader = nativeReader; } NativeParser parser = new NativeParser(reader, methodSig.NativeLayoutOffset); MethodCallingConvention callingConvention = (MethodCallingConvention)parser.GetUnsigned(); hasThis = !callingConvention.HasFlag(MethodCallingConvention.Static); uint numGenArgs = callingConvention.HasFlag(MethodCallingConvention.Generic) ? parser.GetUnsigned() : 0; uint parameterCount = parser.GetUnsigned(); parameters = new TypeDesc[parameterCount + 1]; parametersWithGenericDependentLayout = new bool[parameterCount + 1]; // One extra parameter to account for the return type for (uint i = 0; i <= parameterCount; i++) { // NativeParser is a struct, so it can be copied. NativeParser parserCopy = parser; // Parse the signature twice. The first time to find out the exact type of the signature // The second time to identify if the parameter loaded via the signature should be forced to be // passed byref as part of the universal generic calling convention. parameters[i] = GetConstructedTypeFromParserAndNativeLayoutContext(ref parser, nativeLayoutContext); parametersWithGenericDependentLayout[i] = TypeSignatureHasVarsNeedingCallingConventionConverter(ref parserCopy, module, context, HasVarsInvestigationLevel.Parameter); if (parameters[i] == null) { return(false); } } return(true); }