private void Inherits(VTable baseVTbl) { foreach (VTableSlot slot in baseVTbl.Slots) { _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. _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(!_interfaceSlots.ContainsKey(iface.Key)); _interfaceSlots.Add(iface.Key, iface.Value.ToDictionary(slot => ((VTableSlot)slot).Signature, slot => (VTableSlot)slot)); } }
static VTable ResolveGenericArgument(TypeDef openType, GenericInstSig genInst, VTable vTable) { Debug.Assert(new SigComparer().Equals(openType, vTable.Type)); return(new VTable(genInst, vTable.Slots.Select(slot => ResolveSlot(openType, (VTableSlot)slot, genInst.GenericArguments)) .ToList(), vTable.InterfaceSlots.ToDictionary( iface => GenericArgumentResolver.Resolve(iface.Key, genInst.GenericArguments), iface => (IReadOnlyList <IVTableSlot>)iface.Value .Select(slot => ResolveSlot(openType, (VTableSlot)slot, genInst.GenericArguments)).ToList()) )); }
public VTable Build() { // Inherits base type's slots var baseVTbl = (VTable)_storage.GetVTable(_typeDef.GetBaseTypeThrow()); if (baseVTbl != null) { Inherits(baseVTbl); } var virtualMethods = _typeDef.Methods .Where(method => method.IsVirtual) .ToDictionary( VTableSignature.FromMethod, method => method ); if (_typeDef.FullName.Contains("SubjectBase")) { } // Explicit interface implementation foreach (var iface in _typeDef.Interfaces) { var ifaceVTbl = (VTable)_storage.GetVTable(iface.Interface); if (ifaceVTbl != null) { Implements(virtualMethods, ifaceVTbl, iface.Interface.ToTypeSig()); } } // Normal interface implementation if (!_typeDef.IsInterface) { // Interface methods cannot implements base interface methods. foreach (var iface in _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. if (virtualMethods.TryGetValue(entry.Key, out var impl)) { iface[entry.Key] = OverridenBy(entry.Value, impl); } else if (_slotsMap.TryGetValue(entry.Key, out var implSlot)) { iface[entry.Key] = OverridenBy(entry.Value, 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 (_slotsMap.TryGetValue(method.Key, out slot)) { Debug.Assert(!slot.MethodDef.IsFinal); slot = OverridenBy(slot, method.Value); } else { slot = new VTableSlot(method.Value, _typeDef.ToTypeSig(), method.Key); } _slotsMap[method.Key] = slot; _allSlots.Add(slot); } // MethodImpls foreach (var method in virtualMethods) { foreach (var impl in method.Value.Overrides) { Debug.Assert(impl.MethodBody == method.Value); var targetMethod = impl.MethodDeclaration.ResolveMethodDefThrow(); if (targetMethod.DeclaringType.IsInterface) { var iface = impl.MethodDeclaration.DeclaringType.ToTypeSig(); var ifaceVTbl = _interfaceSlots[iface]; var signature = VTableSignature.FromMethod(impl.MethodDeclaration); var targetSlot = ifaceVTbl[signature]; // The Overrides of interface slots should directly points to the root interface slot while (targetSlot.Parent != null) { targetSlot = (VTableSlot)targetSlot.Parent; } Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface); ifaceVTbl[targetSlot.Signature] = OverridenBy(targetSlot, method.Value); } else { var targetSlot = _allSlots.Single(slot => slot.MethodDef == targetMethod); targetSlot = _slotsMap[targetSlot.Signature]; // Use the most derived slot // Maybe implemented by above processes --- this process should take priority while (targetSlot.MethodDef.DeclaringType == _typeDef) { targetSlot = (VTableSlot)targetSlot.Parent; } _slotsMap[targetSlot.Signature] = OverridenBy(targetSlot, method.Value); } } } var ret = new VTable(_typeDef.ToTypeSig(), _allSlots, _interfaceSlots.ToDictionary( kvp => kvp.Key, kvp => (IReadOnlyList <IVTableSlot>)kvp.Value.Values.ToList())); return(ret); }
private void Implements(Dictionary <VTableSignature, MethodDef> virtualMethods, VTable ifaceVTbl, TypeSig iface) { // This is the step 2 of 12.2 algorithm -- use virtual newslot methods for explicit implementation. VTableSlot ImplLookup(IVTableSlot slot) { if (virtualMethods.TryGetValue(((VTableSlot)slot).Signature, out var 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.Parent != null && !targetSlot.MethodDef.DeclaringType.IsInterface) { targetSlot = (VTableSlot)targetSlot.Parent; } Debug.Assert(targetSlot.MethodDef.DeclaringType.IsInterface); return(OverridenBy((VTableSlot)targetSlot, impl)); } return((VTableSlot)slot); } if (_interfaceSlots.ContainsKey(iface)) { _interfaceSlots[iface] = _interfaceSlots[iface].Values.ToDictionary(slot => slot.Signature, ImplLookup); } else { _interfaceSlots.Add(iface, ifaceVTbl.Slots.ToDictionary(slot => ((VTableSlot)slot).Signature, ImplLookup)); } foreach (var baseIface in ifaceVTbl.InterfaceSlots) { if (_interfaceSlots.ContainsKey(baseIface.Key)) { _interfaceSlots[baseIface.Key] = _interfaceSlots[baseIface.Key].Values.ToDictionary( slot => slot.Signature, ImplLookup); } else { _interfaceSlots.Add(baseIface.Key, baseIface.Value.ToDictionary( slot => ((VTableSlot)slot).Signature, ImplLookup)); } } }