internal VTableSlot(TypeSig defDeclType, MethodDef def, TypeSig decl, VTableSignature signature, VTableSlot overrides) { MethodDefDeclType = defDeclType; MethodDef = def; DeclaringType = decl; Signature = signature; Overrides = overrides; }
internal VTableSlot(MethodDef def, TypeSig decl, VTableSignature signature) : this(def.DeclaringType.ToTypeSig(), def, decl, signature, null) { }
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); }