Skip to content

Runtime support for static interface methods #50129

Closed
@trylek

Description

@trylek

This issue tracks the runtime core team part of work on static interface methods. The broader implementation of this feature spanning other parts of the stack (JIT, Roslyn, libraries) are tracked separately. (Reference needed)

  • Update the ECMA addendum to cover static interface methods, their behavior and resolution;
  • Define positive and negative testing scenarios for the feature to run as CoreCLR IL-based tests (Roslyn support doesn't yet exist);
  • Coordinate with the JIT team regarding the new behavior of .constrained call / .constrained ldftn instruction;
  • Implement runtime changes to the typesystem and JIT interface to support compilation and runtime resolution of static interface methods;
    • Basic Functionality
    • Adjust JIT processing for the ldftn and call instructions to permit them to work with a constrained. prefix and pass the constrained type to the getCallInfo function.
    • Write a function to perform a static resolution given an implementing type, and an interface static method. Place this method into the MethodTable codebase. Call it MethodTable::ResolveStaticVirtualMethod(MethodDesc interfaceMethod)
      • This function shall process MethodImpls walking the type hierarchy. Be sure to properly handle covariant returns.
    • Adjust getCallInfo to have special handling for constrained ldftn and constrained call instructions.
      • If the constrained type is sufficiently well known to resolve to exactly one target method using MethodTable::ResolveStaticVirtualMethod, resolve to that target, and return the appropriate details to call that method directly.
      • If the constrained type is a shared generic which is insufficiently precise to specify only 1 possible target method, follow the path that returns CORINFO_CALL_CODE_POINTER (R2R implementation may be slightly different)
    • Adjust the type loader to allow abstract static methods to exist on interface types. Set a flag (HasStaticVirtualMethods) on the interface type to indicate that these methods exist.
    • Adjust normal MethodImpl processing to ignore MethodImpls which refer to static methods
    • Negative checking
    • In the same place as covariant return processing return type validation, if the type is non-abstract loop through all the interfaces that have the HasStaticVirtualMethods flag set. For each static abstract method on those interfaces, make sure it is implemented. If the interface was implemented on a base type which is also concrete, then this logic may be skipped.
    • In the constraint checker, if the type is abstract verify that interface constraints which have the HasStaticVirtualMethods flag set are fully implemented.
    • Basic optimization
    • Add a hashtable of interface method and constraint type which is filled in as ResolveStaticVirtualMethod is run. Future executions with the same parameters should be able to simply use the value in the hash.
    • Add a hashtable of concrete type, interface type to improve the performance of the constraint checker extra logic.
    • Reflection support
    • The implementation of GetInterfaceMap() will need to handle these new static interface methods.
    • Fix issues around TypeBuild.CreateType so that these new overrides can be implemented
  • Implement changes to the Crossgen2 JIT interface to support CG2 compilation of static interface methods;
    • Crossgen2 constraint checker update
    • R2R format update to handle new case (I'm not sure if its necessary, but we may need a new R2R fixup)
    • Crossgen2 jit interface updates
  • Implement the proposed set of tests and use them to validate the expected compilation / runtime behavior.
    • Test calls between generic contexts (Implement as autogenerator)
      • Generic over reference type
      • Generic over value type
      • Generic over constrained type which is instantiated as a reference type
      • Generic over constrained type which is instantiated as a valuetype
      • Curiously recurring pattern various incarnations thereof
      • Shared generic where the exact constrained type and interface type of the call are both reference types.
    • Test override with various different type hierarchies (Implement as autogenerator)
      • Test MethodBody of MethodImpl on MethodImpl defining type
      • Test MethodBody of MethodImpl on non-generic base type of MethodImpl defining type
      • Test MethodBody of MethodImpl on generic base type of MethodImpl defining type where base type is exactly defined
      • Test MethodBody of MethodImpl on generic base type of MethodImpl defining type where base type is a generic type defined by the generic parameters of MethodImpl defining type
    • Test covariant override (share autogenerator with normal type hierarchy testing)
      • Test covariant override where override is implemented on MethodImpl defining type (non-generic)
      • Test covariant override where override is implemented on MethodImpl defining type (generic over reference type)
      • Test covariant override where override is implemented on MethodImpl defining type (generic over value type)
      • Test covariant override where override is implemented on MethodImpl base type (non-generic)
      • Test covariant override where override is implemented on MethodImpl base type (generic case)
    • Positive Type equivalence test case
    • Positive test case, variant use of interface static method
    • Positive test case, verify that name/sig match static method on derived type has no effect on method dispatch of interface MethodImpl defined on base type
    • ReadyToRun Version resilience test
      • Verify that change in override produces correct result
      • Verify that adding a new override on the most derived class (where there was none before and the MethodImpl was only present on the Base class) works
    • Negative test case MethodBody defined on unrelated type
    • Negative test case, multiple MethodImpl records with same MethodDecl
    • Negative test case, non-abstract static virtual method on interface type
    • Negative test case, abstract virtual method on class type
    • Negative test case, non-abstract virtual method on class type
    • Negative test case, abstract static interface method which violates variance safety rule
    • Negative test case, non-implemented static abstract interface method on non-abstract class
    • Negative test case, non-implemented static abstract interface method on abstract class used concrete instantiation
    • Reflection testing
      • Test behavior of Type.GetInterfaceMap()
      • Test MethodInfo.Invoke on abstract static method -> Should throw
      • Test MethodBase.IsVirtual and MethodBase.IsAbstract -> Should show presence of static interface methods
      • Test PropertyInfo.GetValue/SetValue -> Should throw in presence of static interface methods
    • Reflection.Emit testing
      • Test behavior of TypeBuilder.DefineMethod to allow definition of abstract virtual static method
      • Test behavior of TypeBuilder.DefineMethodOverride to ensure that it works for defining override for method defined on type
      • Test behavior of TypeBuilder.DefineMethodOverride to ensure that it works for defining override for method defined on base type

Metadata

Metadata

Labels

Bottom Up WorkNot part of a theme, epic, or user storyarea-TypeSystem-coreclrtrackingThis issue is tracking the completion of other related issues.

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions