void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) { var entryCountReservation = builder.ReserveShort(); var defaultEntryCountReservation = builder.ReserveShort(); int entryCount = 0; TypeDesc declType = _type.GetClosestDefType(); TypeDesc declTypeDefinition = declType.GetTypeDefinition(); DefType[] declTypeRuntimeInterfaces = declType.RuntimeInterfaces; DefType[] declTypeDefinitionRuntimeInterfaces = declTypeDefinition.RuntimeInterfaces; // Catch any runtime interface collapsing. We shouldn't have any Debug.Assert(declTypeRuntimeInterfaces.Length == declTypeDefinitionRuntimeInterfaces.Length); var defaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot)>(); // Resolve all the interfaces, but only emit non-default implementations for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++) { var interfaceType = declTypeRuntimeInterfaces[interfaceIndex]; var interfaceDefinitionType = declTypeDefinitionRuntimeInterfaces[interfaceIndex]; Debug.Assert(interfaceType.IsInterface); IReadOnlyList <MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots; for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; if (!interfaceType.IsTypeDefinition) { declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType); } var implMethod = declTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface // dispatch will walk the inheritance chain). if (implMethod != null) { TypeDesc implType = declType; while (!implType.HasSameTypeDefinition(implMethod.OwningType)) { implType = implType.BaseType; } MethodDesc targetMethod = implMethod; if (!implType.IsTypeDefinition) { targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType); } builder.EmitShort((short)checked ((ushort)interfaceIndex)); builder.EmitShort((short)checked ((ushort)(interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0)))); builder.EmitShort((short)checked ((ushort)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType))); entryCount++; } else { // Is there a default implementation? int?implSlot = null; DefaultInterfaceMethodResolution result = declTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(declMethod, out implMethod); if (result == DefaultInterfaceMethodResolution.DefaultImplementation) { DefType providingInterfaceDefinitionType = (DefType)implMethod.OwningType; implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty); implSlot = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType); } else if (result == DefaultInterfaceMethodResolution.Reabstraction) { implSlot = SpecialDispatchMapSlot.Reabstraction; } else if (result == DefaultInterfaceMethodResolution.Diamond) { implSlot = SpecialDispatchMapSlot.Diamond; } if (implSlot.HasValue) { defaultImplementations.Add(( interfaceIndex, interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0), implSlot.Value)); } } } } // Now emit the default implementations foreach (var defaultImplementation in defaultImplementations) { builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)defaultImplementation.ImplMethodSlot)); } // Update the header builder.EmitShort(entryCountReservation, (short)checked ((ushort)entryCount)); builder.EmitShort(defaultEntryCountReservation, (short)checked ((ushort)defaultImplementations.Count)); }
void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) { var entryCountReservation = builder.ReserveShort(); var defaultEntryCountReservation = builder.ReserveShort(); var staticEntryCountReservation = builder.ReserveShort(); var defaultStaticEntryCountReservation = builder.ReserveShort(); int entryCount = 0; TypeDesc declType = _type.GetClosestDefType(); TypeDesc declTypeDefinition = declType.GetTypeDefinition(); DefType[] declTypeRuntimeInterfaces = declType.RuntimeInterfaces; DefType[] declTypeDefinitionRuntimeInterfaces = declTypeDefinition.RuntimeInterfaces; // Catch any runtime interface collapsing. We shouldn't have any Debug.Assert(declTypeRuntimeInterfaces.Length == declTypeDefinitionRuntimeInterfaces.Length); var defaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot)>(); var staticImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>(); var staticDefaultImplementations = new List <(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>(); // Resolve all the interfaces, but only emit non-static and non-default implementations for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++) { var interfaceType = declTypeRuntimeInterfaces[interfaceIndex]; var interfaceDefinitionType = declTypeDefinitionRuntimeInterfaces[interfaceIndex]; Debug.Assert(interfaceType.IsInterface); IReadOnlyList <MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots; for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; if (!interfaceType.IsTypeDefinition) { declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType); } var implMethod = declMethod.Signature.IsStatic ? declTypeDefinition.ResolveInterfaceMethodToStaticVirtualMethodOnType(declMethod) : declTypeDefinition.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); // Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface // dispatch will walk the inheritance chain). if (implMethod != null) { TypeDesc implType = declType; while (!implType.HasSameTypeDefinition(implMethod.OwningType)) { implType = implType.BaseType; } MethodDesc targetMethod = implMethod; if (!implType.IsTypeDefinition) { targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType); } int emittedInterfaceSlot = interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0); int emittedImplSlot = VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType); if (targetMethod.Signature.IsStatic) { // If this is a static virtual, also remember whether we need generic context. // The implementation is not callable without the generic context. // Instance methods acquire the generic context from `this` and don't need it. // The pointer to the generic context is stored in the owning type's vtable. int genericContext = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg() ? StaticVirtualMethodContextSource.ContextFromThisClass : StaticVirtualMethodContextSource.None; staticImplementations.Add((interfaceIndex, emittedInterfaceSlot, emittedImplSlot, genericContext)); } else { builder.EmitShort((short)checked ((ushort)interfaceIndex)); builder.EmitShort((short)checked ((ushort)emittedInterfaceSlot)); builder.EmitShort((short)checked ((ushort)emittedImplSlot)); entryCount++; } } else { // Is there a default implementation? int?implSlot = null; DefaultInterfaceMethodResolution result = declTypeDefinition.ResolveInterfaceMethodToDefaultImplementationOnType(declMethod, out implMethod); DefType providingInterfaceDefinitionType = null; if (result == DefaultInterfaceMethodResolution.DefaultImplementation) { providingInterfaceDefinitionType = (DefType)implMethod.OwningType; implMethod = implMethod.InstantiateSignature(declType.Instantiation, Instantiation.Empty); implSlot = VirtualMethodSlotHelper.GetDefaultInterfaceMethodSlot(factory, implMethod, declType, providingInterfaceDefinitionType); } else if (result == DefaultInterfaceMethodResolution.Reabstraction) { implSlot = SpecialDispatchMapSlot.Reabstraction; } else if (result == DefaultInterfaceMethodResolution.Diamond) { implSlot = SpecialDispatchMapSlot.Diamond; } if (implSlot.HasValue) { int emittedInterfaceSlot = interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0); if (declMethod.Signature.IsStatic) { int genericContext = StaticVirtualMethodContextSource.None; if (result == DefaultInterfaceMethodResolution.DefaultImplementation && implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { // If this is a static virtual, also remember whether we need generic context. // The implementation is not callable without the generic context. // Instance methods acquire the generic context from `this` and don't need it. // For default interface methods, the generic context is acquired by indexing // into the interface list of the owning type. Debug.Assert(providingInterfaceDefinitionType != null); int indexOfInterface = Array.IndexOf(declTypeDefinitionRuntimeInterfaces, providingInterfaceDefinitionType); Debug.Assert(indexOfInterface >= 0); genericContext = StaticVirtualMethodContextSource.ContextFromFirstInterface + indexOfInterface; } staticDefaultImplementations.Add(( interfaceIndex, emittedInterfaceSlot, implSlot.Value, genericContext)); } else { defaultImplementations.Add(( interfaceIndex, emittedInterfaceSlot, implSlot.Value)); } } } } } // Now emit the default implementations foreach (var defaultImplementation in defaultImplementations) { builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)defaultImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)defaultImplementation.ImplMethodSlot)); } // Now emit the static implementations foreach (var staticImplementation in staticImplementations) { builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.ImplMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.Context)); } // Now emit the static default implementations foreach (var staticImplementation in staticDefaultImplementations) { builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceIndex)); builder.EmitShort((short)checked ((ushort)staticImplementation.InterfaceMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.ImplMethodSlot)); builder.EmitShort((short)checked ((ushort)staticImplementation.Context)); } // Update the header builder.EmitShort(entryCountReservation, (short)checked ((ushort)entryCount)); builder.EmitShort(defaultEntryCountReservation, (short)checked ((ushort)defaultImplementations.Count)); builder.EmitShort(staticEntryCountReservation, (short)checked ((ushort)staticImplementations.Count)); builder.EmitShort(defaultStaticEntryCountReservation, (short)checked ((ushort)staticDefaultImplementations.Count)); }