示例#1
0
        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));
        }