diff options
Diffstat (limited to 'src/ILCompiler.Compiler/src/Compiler/VirtualMethodCallHelper.cs')
-rw-r--r-- | src/ILCompiler.Compiler/src/Compiler/VirtualMethodCallHelper.cs | 87 |
1 files changed, 69 insertions, 18 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/VirtualMethodCallHelper.cs b/src/ILCompiler.Compiler/src/Compiler/VirtualMethodCallHelper.cs index 27b1198c6..19da1f6ae 100644 --- a/src/ILCompiler.Compiler/src/Compiler/VirtualMethodCallHelper.cs +++ b/src/ILCompiler.Compiler/src/Compiler/VirtualMethodCallHelper.cs @@ -16,29 +16,74 @@ namespace ILCompiler /// Given a virtual method decl, return its VTable slot if the method is used on its containing type. /// Return -1 if the virtual method is not used. /// </summary> - public static int GetVirtualMethodSlot(NodeFactory factory, MethodDesc method, bool countDictionarySlots = true) + public static int GetVirtualMethodSlot(NodeFactory factory, MethodDesc method, TypeDesc implType, bool countDictionarySlots = true) { - // TODO: More efficient lookup of the slot - TypeDesc owningType = method.OwningType; - int baseSlots = GetNumberOfBaseSlots(factory, owningType, countDictionarySlots); - - // For types that have a generic dictionary, the introduced virtual method slots are - // prefixed with a pointer to the generic dictionary. - if (owningType.HasGenericDictionarySlot() && countDictionarySlots) - baseSlots++; - - IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(owningType).Slots; - int methodSlot = -1; - for (int slot = 0; slot < virtualSlots.Count; slot++) + if (method.CanMethodBeInSealedVTable()) { - if (virtualSlots[slot] == method) + // If the method is a sealed newslot method, it will be put in the sealed vtable instead of the type's vtable. In this + // case, the slot index return should be the index in the sealed vtable, plus the total number of vtable slots. + + // First, make sure we are not attempting to resolve the slot of a sealed vtable method on a special array type, which + // does not get any sealed vtable entries + Debug.Assert(!implType.IsArrayTypeWithoutGenericInterfaces()); + + // Ensure the sealed vtable is built before computing the slot + factory.SealedVTable(implType).BuildSealedVTableSlots(factory, relocsOnly: false /* GetVirtualMethodSlot is called in the final emission phase */); + + int sealedVTableSlot = factory.SealedVTable(implType).ComputeSealedVTableSlot(method); + if (sealedVTableSlot == -1) + return -1; + + // Now compute the total number of vtable slots that would exist on the type + int baseSlots = GetNumberOfBaseSlots(factory, implType, countDictionarySlots); + + // For types that have a generic dictionary, the introduced virtual method slots are + // prefixed with a pointer to the generic dictionary. + if (implType.HasGenericDictionarySlot() && countDictionarySlots) + baseSlots++; + + int numVTableSlots = baseSlots; + IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(implType).Slots; + for (int slot = 0; slot < virtualSlots.Count; slot++) { - methodSlot = slot; - break; + if (virtualSlots[slot].CanMethodBeInSealedVTable()) + continue; + numVTableSlots++; } + + return numVTableSlots + sealedVTableSlot; } + else + { + // TODO: More efficient lookup of the slot + TypeDesc owningType = method.OwningType; + int baseSlots = GetNumberOfBaseSlots(factory, owningType, countDictionarySlots); - return methodSlot == -1 ? -1 : baseSlots + methodSlot; + // For types that have a generic dictionary, the introduced virtual method slots are + // prefixed with a pointer to the generic dictionary. + if (owningType.HasGenericDictionarySlot() && countDictionarySlots) + baseSlots++; + + IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(owningType).Slots; + int methodSlot = -1; + int numSealedVTableEntries = 0; + for (int slot = 0; slot < virtualSlots.Count; slot++) + { + if (virtualSlots[slot].CanMethodBeInSealedVTable()) + { + numSealedVTableEntries++; + continue; + } + + if (virtualSlots[slot] == method) + { + methodSlot = slot; + break; + } + } + + return methodSlot == -1 ? -1 : baseSlots + methodSlot - numSealedVTableEntries; + } } private static int GetNumberOfBaseSlots(NodeFactory factory, TypeDesc owningType, bool countDictionarySlots) @@ -83,7 +128,13 @@ namespace ILCompiler baseSlots++; IReadOnlyList<MethodDesc> baseVirtualSlots = factory.VTable(baseType).Slots; - baseSlots += baseVirtualSlots.Count; + foreach (var vtableMethod in baseVirtualSlots) + { + // Methods in the sealed vtable should be excluded from the count + if (vtableMethod.CanMethodBeInSealedVTable()) + continue; + baseSlots++; + } baseType = baseType.BaseType; templateBaseType = templateBaseType.BaseType; |