Repository: dotnet/runtime
File: src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs (C#)

Code before:
                    // We may end up with a method that has subsituted type parameters, so we need to instantiate
                    // on the method definition
                    impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation);
                }

                if (impl != null && (impl != declMethod))
                {
                    MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl.GetMethodDefinition());
                    MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);

                    if (slotDefiningMethodImpl != slotDefiningMethodDecl)
                    {
                        // If the derived method's slot does not match the vtable slot,
                        // bail on devirtualization, as the method was installed into
                        // the vtable slot via an explicit override and even if the
                        // method is final, the slot may not be.
                        //
                        // Note the jit could still safely devirtualize if it had an exact
                        // class, but such cases are likely rare.
                        devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_SLOT;
                        impl = null;
                    }
                }
            }

            if (impl != null && impl.HasInstantiation && originalDeclMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific))
            {
                // We don't support devirtualization of shared generic virtual methods yet.
                devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
                impl = null;
            }

            return impl;
        }

#if !READYTORUN
        public virtual bool IsGenericDefinitionMethodTableReflectionVisible(TypeDesc type) => true;

        /// <summary>
        /// Gets a value indicating whether it might be possible to obtain a constructed type data structure for the given type
        /// in this compilation (i.e. is it possible to reference a constructed MethodTable symbol for this).
        /// </summary>
        public virtual bool CanReferenceConstructedMethodTable(TypeDesc type) => true;

        /// <summary>
        /// Gets a value indicating whether it might be possible to obtain a metadata type data structure for the given type
        /// in this compilation (i.e. is it possible to reference a metadata MethodTable symbol for this).
        /// </summary>
        public virtual bool CanReferenceMetadataMethodTable(TypeDesc type) => true;

        /// <summary>

Review comment (bug):
The check for shared generic virtual methods appears to be checking the wrong method. The condition checks whether `originalDeclMethod` (the declaration method) would be canonical, but it should check whether `impl` (the implementation method that will actually be called after devirtualization) is canonical. The purpose is to bail out when the devirtualized method would be shared (requiring a generic context), so the check should be `impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific)` instead of `originalDeclMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific)`.
```suggestion
            if (impl != null && impl.HasInstantiation && impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific))
```

Code after:
                    // We may end up with a method that has substituted type parameters, so we need to instantiate
                    // on the method definition
                    impl = impl.GetMethodDefinition().MakeInstantiatedMethod(originalDeclMethod.Instantiation);
                }

                if (impl != null && (impl != declMethod))
                {
                    MethodDesc slotDefiningMethodImpl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(impl.GetMethodDefinition());
                    MethodDesc slotDefiningMethodDecl = MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(declMethod);

                    if (slotDefiningMethodImpl != slotDefiningMethodDecl)
                    {
                        // If the derived method's slot does not match the vtable slot,
                        // bail on devirtualization, as the method was installed into
                        // the vtable slot via an explicit override and even if the
                        // method is final, the slot may not be.
                        //
                        // Note the jit could still safely devirtualize if it had an exact
                        // class, but such cases are likely rare.
                        devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_SLOT;
                        impl = null;
                    }
                }
            }

            if (impl != null && impl.HasInstantiation && impl.GetCanonMethodTarget(CanonicalFormKind.Specific).IsCanonicalMethod(CanonicalFormKind.Specific))
            {
                // We don't support devirtualization of shared generic virtual methods yet.
                devirtualizationDetail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_FAILED_CANON;
                impl = null;
            }

            return impl;
        }

#if !READYTORUN
        public virtual bool IsGenericDefinitionMethodTableReflectionVisible(TypeDesc type) => true;

        /// <summary>
        /// Gets a value indicating whether it might be possible to obtain a constructed type data structure for the given type
        /// in this compilation (i.e. is it possible to reference a constructed MethodTable symbol for this).
        /// </summary>
        public virtual bool CanReferenceConstructedMethodTable(TypeDesc type) => true;

        /// <summary>
        /// Gets a value indicating whether it might be possible to obtain a metadata type data structure for the given type
        /// in this compilation (i.e. is it possible to reference a metadata MethodTable symbol for this).
        /// </summary>
        public virtual bool CanReferenceMetadataMethodTable(TypeDesc type) => true;

        /// <summary>