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)); } }
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); }
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)); } } }
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); }