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); }
/// <summary> /// Get the virtual slot index of a given virtual method. (This is only valid for non-interface virtuals) /// </summary> /// <param name="virtualMethod">virtual method to get slot index of</param> /// <returns>slot index, or -1</returns> public static int VirtualMethodToSlotIndex(MethodDesc virtualMethod) { Debug.Assert(virtualMethod.IsVirtual); Debug.Assert(!virtualMethod.OwningType.IsInterface); MethodDesc definingMethod = virtualMethod; // If not newslot, make sure we've got the defining method here if (!definingMethod.IsNewSlot) { definingMethod = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(definingMethod); } TypeDesc definingType = definingMethod.OwningType; // Two possible cases for determining slot index that will work // 1. The definingType is a R2R type with full metadata. Compute the MethodDesc, by scanning the list of virtuals present in metadata. Its possible to not get a slot index. In that case return -1 // 2. The definingType is pregenerated, but we can go from metadata to slot index via the runtime mapping tables. if (!IsPregeneratedOrTemplateTypeLoaded(definingType)) { // Case 1 MetadataType definingMetadataType = (MetadataType)definingType; int baseTypeSlotCount = 0; if (definingMetadataType.BaseType != null) { unsafe { if (definingMetadataType.BaseType.RetrieveRuntimeTypeHandleIfPossible()) { baseTypeSlotCount = definingMetadataType.BaseType.GetRuntimeTypeHandle().ToEETypePtr()->NumVtableSlots; } else { baseTypeSlotCount = definingMetadataType.BaseType.GetOrCreateTypeBuilderState().NumVTableSlots; } } } int currentSlot = baseTypeSlotCount; if (definingMetadataType.ConvertToCanonForm(CanonicalFormKind.Specific).IsCanonicalSubtype(CanonicalFormKind.Specific)) { // Deal with the space reserved for the canonical dictionary currentSlot++; } foreach (MethodDesc method in definingMetadataType.GetMethods()) { if (!MethodDefinesVTableSlot(method)) { continue; } if (method == definingMethod) { return(currentSlot); } else { currentSlot++; } } // No slot index defined. return(-1); } else { // Case 2, pregenerated type TypeSystem.NativeFormat.NativeFormatMethod definingMethodOpenType = (TypeSystem.NativeFormat.NativeFormatMethod)definingMethod.GetTypicalMethodDefinition(); MethodSignatureComparer methodSignatureComparer = new MethodSignatureComparer( definingMethodOpenType.MetadataReader, definingMethodOpenType.Handle); if (!definingType.RetrieveRuntimeTypeHandleIfPossible()) { new TypeBuilder().BuildType(definingType); } TypeSystem.NativeFormat.NativeFormatType definingNativeFormatType = (TypeSystem.NativeFormat.NativeFormatType)definingType.GetTypeDefinition(); NativeFormatModuleInfo moduleToLookIn = definingNativeFormatType.MetadataUnit.RuntimeModuleInfo; TypeLoaderEnvironment.VirtualResolveDataResult virtualSlotInfo; if (!TypeLoaderEnvironment.TryGetVirtualResolveData(moduleToLookIn, definingType.RuntimeTypeHandle, Array.Empty <RuntimeTypeHandle>(), ref methodSignatureComparer, out virtualSlotInfo)) { return(-1); } Debug.Assert(!virtualSlotInfo.IsGVM); return(virtualSlotInfo.SlotIndex); } }
internal void RegisterDynamicGenericTypesAndMethods(DynamicGenericsRegistrationData registrationData) { using (LockHolder.Hold(_dynamicGenericsLock)) { int registeredTypesCount = 0; int registeredMethodsCount = 0; int nativeFormatTypesRegisteredCount = 0; TypeEntryToRegister[] registeredTypes = null; GenericMethodEntry[] registeredMethods = null; try { if (registrationData.TypesToRegister != null) { registeredTypes = new TypeEntryToRegister[registrationData.TypesToRegisterCount]; foreach (TypeEntryToRegister typeEntry in registrationData.TypesToRegister) { // Keep track of registered type handles so that that we can rollback the registration on exception registeredTypes[registeredTypesCount++] = typeEntry; // Information tracked in these dictionaries is (partially) redundant with information tracked by MRT. // We can save a bit of memory by avoiding the redundancy where possible. For now, we are keeping it simple. // Register type -> components mapping first so that we can use it during rollback below if (typeEntry.GenericTypeEntry != null) { GenericTypeEntry registeredTypeEntry = _dynamicGenericTypes.AddOrGetExisting(typeEntry.GenericTypeEntry); if (registeredTypeEntry != typeEntry.GenericTypeEntry && registeredTypeEntry._isRegisteredSuccessfully) { throw new ArgumentException(SR.Argument_AddingDuplicate); } registeredTypeEntry._instantiatedTypeHandle = typeEntry.GenericTypeEntry._instantiatedTypeHandle; registeredTypeEntry._isRegisteredSuccessfully = true; } else { MetadataType metadataType = typeEntry.MetadataDefinitionType; IntPtr nonGcStaticFields = IntPtr.Zero; IntPtr gcStaticFields = IntPtr.Zero; #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING #if SUPPORTS_R2R_LOADING uint nonGcStaticsRva = 0; uint gcStaticsRva = 0; // For images where statics are directly embedded in the image, store the information about where // to find statics info if (TypeLoaderEnvironment.TryGetStaticsTableEntry(metadataType, out nonGcStaticsRva, out gcStaticsRva)) { ModuleInfo moduleInfo = TypeLoaderEnvironment.GetModuleInfoForType(metadataType); if (nonGcStaticsRva == 0) { nonGcStaticFields = TypeLoaderEnvironment.NoStaticsData; } else { nonGcStaticFields = moduleInfo.Handle + checked ((int)nonGcStaticsRva); } if (gcStaticsRva == 0) { gcStaticFields = TypeLoaderEnvironment.NoStaticsData; } else { gcStaticFields = moduleInfo.Handle + checked ((int)gcStaticsRva); } } #endif TypeSystem.NativeFormat.NativeFormatType nativeFormatType = metadataType as TypeSystem.NativeFormat.NativeFormatType; if (nativeFormatType != null) { RegisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(nativeFormatType.MetadataReader, nativeFormatType.Handle), nativeFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle, nonGcStaticFields, gcStaticFields); } #if ECMA_METADATA_SUPPORT TypeSystem.Ecma.EcmaType ecmaFormatType = metadataType as TypeSystem.Ecma.EcmaType; if (ecmaFormatType != null) { RegisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(ecmaFormatType.MetadataReader, ecmaFormatType.Handle), ecmaFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle, nonGcStaticFields, gcStaticFields); } #endif nativeFormatTypesRegisteredCount++; #else Environment.FailFast("Ready to Run module type?"); #endif } } } Debug.Assert(registeredTypesCount == registrationData.TypesToRegisterCount); if (registrationData.MethodsToRegister != null) { registeredMethods = new GenericMethodEntry[registrationData.MethodsToRegisterCount]; foreach (GenericMethodEntry methodEntry in registrationData.MethodsToRegister) { Debug.Assert(methodEntry._methodDictionary != IntPtr.Zero); // Keep track of registered method dictionaries so that that we can rollback the registration on exception registeredMethods[registeredMethodsCount++] = methodEntry; // Register method dictionary -> components mapping first so that we can use it during rollback below GenericMethodEntry registeredMethodComponentsEntry = _dynamicGenericMethodComponents.AddOrGetExisting(methodEntry); if (registeredMethodComponentsEntry != methodEntry && registeredMethodComponentsEntry._isRegisteredSuccessfully) { throw new ArgumentException(SR.Argument_AddingDuplicate); } GenericMethodEntry registeredMethodEntry = _dynamicGenericMethods.AddOrGetExisting(methodEntry); if (registeredMethodEntry != methodEntry && registeredMethodEntry._isRegisteredSuccessfully) { throw new ArgumentException(SR.Argument_AddingDuplicate); } Debug.Assert(registeredMethodComponentsEntry == registeredMethodEntry); registeredMethodEntry._methodDictionary = methodEntry._methodDictionary; registeredMethodEntry._isRegisteredSuccessfully = true; } } Debug.Assert(registeredMethodsCount == registrationData.MethodsToRegisterCount); } catch { // Catch and rethrow any exceptions instead of using finally block. Otherwise, filters that are run during // the first pass of exception unwind may see partially registered types. // TODO: Convert this to filter for better diagnostics once we switch to Roslyn // Undo types that were registered. There should be no memory allocations or other failure points. try { for (int i = 0; i < registeredTypesCount; i++) { var typeEntry = registeredTypes[i]; // There is no Remove feature in the LockFreeReaderHashtable... if (typeEntry.GenericTypeEntry != null) { GenericTypeEntry failedEntry = _dynamicGenericTypes.GetValueIfExists(typeEntry.GenericTypeEntry); if (failedEntry != null) { failedEntry._isRegisteredSuccessfully = false; } } else { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING TypeSystem.NativeFormat.NativeFormatType nativeFormatType = typeEntry.MetadataDefinitionType as TypeSystem.NativeFormat.NativeFormatType; if (nativeFormatType != null) { UnregisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(nativeFormatType.MetadataReader, nativeFormatType.Handle), nativeFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle); } #if ECMA_METADATA_SUPPORT TypeSystem.Ecma.EcmaType ecmaFormatType = typeEntry.MetadataDefinitionType as TypeSystem.Ecma.EcmaType; if (ecmaFormatType != null) { UnregisterNewNamedTypeRuntimeTypeHandle(new QTypeDefinition(ecmaFormatType.MetadataReader, ecmaFormatType.Handle), ecmaFormatType.GetTypeBuilderState().HalfBakedRuntimeTypeHandle); } #endif #else Environment.FailFast("Ready to Run module type?"); #endif } } for (int i = 0; i < registeredMethodsCount; i++) { // There is no Remove feature in the LockFreeReaderHashtable... GenericMethodEntry failedEntry = _dynamicGenericMethods.GetValueIfExists(registeredMethods[i]); if (failedEntry != null) { failedEntry._isRegisteredSuccessfully = false; } failedEntry = _dynamicGenericMethodComponents.GetValueIfExists(registeredMethods[i]); if (failedEntry != null) { failedEntry._isRegisteredSuccessfully = false; } } } catch (Exception e) { // Catch any exceptions and fail fast just in case Environment.FailFast("Exception during registration rollback", e); } throw; } if (nativeFormatTypesRegisteredCount > 0) { FinishAddingNewNamedTypes(); } } }