Open
Description
dotnet/coreclr#9230 introduced some simple devirtualization. Some areas for future enhancements:
- Devirtualize interface calls. Logic for this is more complex than for virtual calls (see Interface devirt coreclr#10192, Fix several devirtualization issues coreclr#10371).
- Devirtualize calls on struct types. Make sure the right method entry point in invoked; virtual struct methods come in "boxed" and "unboxed" flavors (see JIT: after devirtualization try undoing box and invoking unboxed entry coreclr#14698, which removes the box).
- After calling the unboxed entry point, try and remove the upstream box and copy too (likely requires first-class structs. Some progress in JIT: after devirtualization try undoing box and invoking unboxed entry coreclr#14698 and JIT: remove boxing for interface call to shared generic struct coreclr#17006). Resolved via JIT: more general value class devirtualization #52210.
- If we can't call the unboxed entry point, we may still know that the method called won't allow the the
this
pointer in the call to escape. So we can perhaps stack-allocate the object in its boxed form and pass that. Here we'd be counting on the fact that methods on mutable GC value types should already be using checked write barriers for updates. - Likewise we can consider using "boxed on stack" for some boxed arguments to well known methods.
- Refactor the jit to retain type information for a larger variety of tree nodes. Likely requires carefully breaking the widespread assumption in the jit that class handles are captured only for struct types.
- Do some simplistic type propagation during importation. For instance during
fgFindBasicBlocks
the jit could count how many times each local appears in astarg
orldarga
instruction. If there is just onestarg
(which should be a fairly common case) then at thestarg
the jit can check the type of the value being assigned and use it if more precise than the local's declared type. This in this case it is also safe to propagate the exactness flag. (Some of this now done, see JIT: improve types for single def locals and temps coreclr#10471, Jit: fix a few issues with single def local tracking coreclr#10633, Jit: fix issue with single-def type propagation coreclr#10867, Track single def locals in importer coreclr#21251) - Consolidate tracking of types within the jit for structs and classes. Right now there is a general assumption that the class handle fields in various places (trees, lcl vars) imply struct types.
- Do more ambitious type propagation during optimization, once we have SSA. We should be able to trigger late devirtualization during optimization too.
- Improve the ability of the jit to gather type information from various operations, for instance type tests (see JIT: consider using new temp to capture improved type from an optimized cast #9117, JIT: Update class for Unsafe.As<>() #85954)
- Enable inlining of late devirtualized calls -- at least for those calls devirtualized during inlining (see Consider devirtualizing & inlining Comparer<T>.Default.CompareTo as well. #39873; box cleanup as well, see Devirtualization isn't acting on devirtualizable calls past the first #39519). Now done via JIT: Enable inlining for late devirtualization #110827
- Experiment with guarded devirtualization, by inserting appropriate type checks. Some preliminary work for this is noted in JIT: see if guarded devirtualization for EqualityComparer methods pays off #9028. The basic transformation is now available via Guarded devirtualization foundations coreclr#21270. Now enabled by default via enable TieredPGO by default #86225 (and many other PRs).
- Experiment with speculative devirtualization by considering what is known about overrides at the time a method is jitted.
- Obtain more accurate return types from calls to shared generic methods whose return types are generic. This is typical of many collection types, eg
List<T>.get_Item
returnsT
. In many cases the caller will know the type ofT
exactly, but currently the jit ends up with the shared generic ref type placeholder type__Canon
. There's an example of this in thefromcollections
regression test. See JIT: preliminaries to improve types coreclr#10172 for a partial fix. Fixed by Pass exact context to getMethodInfo #88025. - Likewise, improve types in the inlinee when inlining shared generic methods (inlining effectively unshares the method); this may trigger devirtualization. Right now we may record shared types for inlinee args and locals, when we could potentially record unshared types (see Jit: track ref types for inlinee locals and args coreclr#10432, Compute precise generic context after de-virtualization #38477, Refine field types based on a derived type's generic instantiation of its base class to devirtualize virtual calls #80564, and finally Pass exact context to getMethodInfo #88025).
- Update logic to handle indirection patterns seen during prejit (see notes in Support Encoding devirtualization coreclr#9276)
- Improve test coverage by adding final/sealed to classes in existing test cases, perhaps creating some kind of tooling to experimentally attempt this and decide when it is correct to do so.
- Improve checked build test coverage by enabling jit optimization of loader tests, or else start running release build tests against a checked jit.
- Sharpen types for temps used to pass inlinee args early (issue JIT: refine arg types based on actual types when creating arg temps #8790; pr JIT: refine types when creating arg temps to improve devirtualization coreclr#13530)
- Sharpen return type if all reachable returns have more specialized type than the method's declared return type and there is a return spill temp (System.Threading.Thread - Unable to run as foreground thread. #15766)
- Avoid or propagate improved types through various layers of spill temps (CurlHandler empty header values not being sent in the event of a redirect occuring #15783; some progress in JIT: streamline temp usage for returns coreclr#20640), also JIT: Update type when return temp is freshly created #111948
- See if there is any way to learn about actual types from readonly statics (issue RyuJIT: JIT, readonly static fields and dynamic dispatch #5502; implemented via Allow jit to examine type of initonly static ref typed fields coreclr#20886)
- Enhance inlining heuristics to anticipate when inlining will enable devirtualization (Dns.GetHostEntryAsync(IPAddress.None) succeeds on macOS #17935, also see Final method won't devirt when call-site is "complex" #11711)
- Look into devirtualizing
ldvirtftn
and calls that internally translate toldvirtftn
(Generic virtual method devirtualization does not happen #32129) - (likely rare) if devirtualization results in a call to an intrinsic, expand the intrinsic appropriately
- devirtualize interface calls on arrays (see Array interface method devirtualization #62457) Fixed via JIT: Support for devirtualizing array interface methods #108153 and JIT: enable devirtualization/inlining of other array interface methods #109209
category:cq
theme:devirtualization
skill-level:expert
cost:extra-large
impact:large