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