Ejemplo n.º 1
0
        static void Inherits(VTableConstruction vTbl, VTable baseVTbl)
        {
            foreach (VTableSlot slot in baseVTbl.Slots)
            {
                vTbl.AllSlots.Add(slot);
                // It's possible to have same signature in multiple slots,
                // when a derived type shadow the base type using newslot.
                // In this case, use the derived type's slot in SlotsMap.

                // The derived type's slots are always at a later position
                // than the base type, so it would naturally 'override'
                // their position in SlotsMap.
                vTbl.SlotsMap[slot.Signature] = slot;
            }

            // This is the step 1 of 12.2 algorithm -- copy the base interface implementation.
            foreach (var iface in baseVTbl.InterfaceSlots)
            {
                Debug.Assert(!vTbl.InterfaceSlots.ContainsKey(iface.Key));
                vTbl.InterfaceSlots.Add(iface.Key, iface.Value.ToDictionary(slot => slot.Signature, slot => slot));
            }
        }
Ejemplo n.º 2
0
        static VTable ResolveGenericArgument(TypeDef openType, GenericInstSig genInst, VTable vTable)
        {
            Debug.Assert(new SigComparer().Equals(openType, vTable.Type));
            var ret = new VTable(genInst);

            foreach (VTableSlot slot in vTable.Slots)
            {
                ret.Slots.Add(ResolveSlot(openType, slot, genInst.GenericArguments));
            }
            foreach (var iface in vTable.InterfaceSlots)
            {
                ret.InterfaceSlots.Add(GenericArgumentResolver.Resolve(iface.Key, genInst.GenericArguments),
                                       iface.Value.Select(slot => ResolveSlot(openType, slot, genInst.GenericArguments)).ToList());
            }
            return(ret);
        }
Ejemplo n.º 3
0
        static void Implements(VTableConstruction vTbl, Dictionary <VTableSignature, MethodDef> virtualMethods, VTable ifaceVTbl, TypeSig iface)
        {
            // This is the step 2 of 12.2 algorithm -- use virtual newslot methods for explicit implementation.

            Func <VTableSlot, VTableSlot> implLookup = slot => {
                MethodDef impl;
                if (virtualMethods.TryGetValue(slot.Signature, out impl) &&
                    impl.IsNewSlot && !impl.DeclaringType.IsInterface)
                {
                    // Interface methods cannot implements base interface methods.
                    // The Overrides of interface slots should directly points to the root interface slot
                    var targetSlot = slot;
                    while (targetSlot.Overrides != null && !targetSlot.MethodDef.DeclaringType.IsInterface)
                    {
                        targetSlot = targetSlot.Overrides;
                    }
                    Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface);
                    return(targetSlot.OverridedBy(impl));
                }
                return(slot);
            };

            if (vTbl.InterfaceSlots.ContainsKey(iface))
            {
                vTbl.InterfaceSlots[iface] = vTbl.InterfaceSlots[iface].Values.ToDictionary(
                    slot => slot.Signature, implLookup);
            }
            else
            {
                vTbl.InterfaceSlots.Add(iface, ifaceVTbl.Slots.ToDictionary(
                                            slot => slot.Signature, implLookup));
            }

            foreach (var baseIface in ifaceVTbl.InterfaceSlots)
            {
                if (vTbl.InterfaceSlots.ContainsKey(baseIface.Key))
                {
                    vTbl.InterfaceSlots[baseIface.Key] = vTbl.InterfaceSlots[baseIface.Key].Values.ToDictionary(
                        slot => slot.Signature, implLookup);
                }
                else
                {
                    vTbl.InterfaceSlots.Add(baseIface.Key, baseIface.Value.ToDictionary(
                                                slot => slot.Signature, implLookup));
                }
            }
        }
Ejemplo n.º 4
0
        public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage)
        {
            var ret = new VTable(typeDef.ToTypeSig());

            var virtualMethods = typeDef.Methods
                                 .Where(method => method.IsVirtual)
                                 .ToDictionary(
                method => VTableSignature.FromMethod(method),
                method => method
                );

            // See Partition II 12.2 for implementation algorithm
            VTableConstruction vTbl = new VTableConstruction();

            // Inherits base type's slots
            VTable baseVTbl = storage.GetVTable(typeDef.GetBaseTypeThrow());

            if (baseVTbl != null)
            {
                Inherits(vTbl, baseVTbl);
            }

            // Explicit interface implementation
            foreach (InterfaceImpl iface in typeDef.Interfaces)
            {
                VTable ifaceVTbl = storage.GetVTable(iface.Interface);
                if (ifaceVTbl != null)
                {
                    Implements(vTbl, virtualMethods, ifaceVTbl, iface.Interface.ToTypeSig());
                }
            }

            // Normal interface implementation
            if (!typeDef.IsInterface)
            {
                // Interface methods cannot implements base interface methods.
                foreach (var iface in vTbl.InterfaceSlots.Values)
                {
                    foreach (var entry in iface.ToList())
                    {
                        if (!entry.Value.MethodDef.DeclaringType.IsInterface)
                        {
                            continue;
                        }
                        // This is the step 1 of 12.2 algorithm -- find implementation for still empty slots.
                        // Note that it seems we should include newslot methods as well, despite what the standard said.
                        MethodDef  impl;
                        VTableSlot implSlot;
                        if (virtualMethods.TryGetValue(entry.Key, out impl))
                        {
                            iface[entry.Key] = entry.Value.OverridedBy(impl);
                        }
                        else if (vTbl.SlotsMap.TryGetValue(entry.Key, out implSlot))
                        {
                            iface[entry.Key] = entry.Value.OverridedBy(implSlot.MethodDef);
                        }
                    }
                }
            }

            // Normal overrides
            foreach (var method in virtualMethods)
            {
                VTableSlot slot;
                if (method.Value.IsNewSlot)
                {
                    slot = new VTableSlot(method.Value, typeDef.ToTypeSig(), method.Key);
                }
                else
                {
                    if (vTbl.SlotsMap.TryGetValue(method.Key, out slot))
                    {
                        Debug.Assert(!slot.MethodDef.IsFinal);
                        slot = slot.OverridedBy(method.Value);
                    }
                    else
                    {
                        slot = new VTableSlot(method.Value, typeDef.ToTypeSig(), method.Key);
                    }
                }
                vTbl.SlotsMap[method.Key] = slot;
                vTbl.AllSlots.Add(slot);
            }

            // MethodImpls
            foreach (var method in virtualMethods)
            {
                foreach (var impl in method.Value.Overrides)
                {
                    Debug.Assert(impl.MethodBody == method.Value);

                    MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow();
                    if (targetMethod.DeclaringType.IsInterface)
                    {
                        var iface = impl.MethodDeclaration.DeclaringType.ToTypeSig();
                        CheckKeyExist(storage, vTbl.InterfaceSlots, iface, "MethodImpl Iface");
                        var ifaceVTbl = vTbl.InterfaceSlots[iface];

                        var signature = VTableSignature.FromMethod(impl.MethodDeclaration);
                        CheckKeyExist(storage, ifaceVTbl, signature, "MethodImpl Iface Sig");
                        var targetSlot = ifaceVTbl[signature];

                        // The Overrides of interface slots should directly points to the root interface slot
                        while (targetSlot.Overrides != null)
                        {
                            targetSlot = targetSlot.Overrides;
                        }
                        Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface);
                        ifaceVTbl[targetSlot.Signature] = targetSlot.OverridedBy(method.Value);
                    }
                    else
                    {
                        var targetSlot = vTbl.AllSlots.Single(slot => slot.MethodDef == targetMethod);
                        CheckKeyExist(storage, vTbl.SlotsMap, targetSlot.Signature, "MethodImpl Normal Sig");
                        targetSlot = vTbl.SlotsMap[targetSlot.Signature];                         // Use the most derived slot
                        // Maybe implemented by above processes --- this process should take priority
                        while (targetSlot.MethodDef.DeclaringType == typeDef)
                        {
                            targetSlot = targetSlot.Overrides;
                        }
                        vTbl.SlotsMap[targetSlot.Signature] = targetSlot.OverridedBy(method.Value);
                    }
                }
            }

            // Populate result V-table
            ret.InterfaceSlots = vTbl.InterfaceSlots.ToDictionary(
                kvp => kvp.Key, kvp => (IList <VTableSlot>)kvp.Value.Values.ToList());

            foreach (var slot in vTbl.AllSlots)
            {
                ret.Slots.Add(slot);
            }

            return(ret);
        }