3 ms·
Very informative. Thanks. > e.g. if ILC can see that only a single type implements an interface, all callsites referring to it are unconditionally devirtualize
by vips7L 2y ago
Very informative. Thanks.
> e.g. if ILC can see that only a single type implements an interface, all callsites referring to it are unconditionally devirtualized).
Just like Java then.
- neonsunset 2y agoYeah, it's in the same area as guarded devirtualization done by HotSpot but there are some differences. ILC is "IL AOT Compiler", it targets the same compiler back-end as JIT but each one has its own set of specific optimizations, on top of the ones that do not care about JIT or AOT conditions. JIT relies on "tiered compilation" and DynamicPGO, which is very similar to HotSpot C1/C2, except it does not have interpreter mode - the code is always compiled and data shows that to have better startup latency than e.g. what Spring Boot applications have. AOT on the other hand relies on "frozen world" optimizations[0] which can be both better and worse than JIT's depending on the exact scenario. JIT currently defaults to a single type devirtualization then fallback (configurable). AOT otoh can devirtualize and/or inline up to 3 variants and doesn't have to emit a fallback when not needed because the exact type hierarchy is statically known. There are other differences that stem from architectural choices made long ago, namely, all method calls in C# are direct except those that are explicitly marked as virtual or interface (there are also delegates but eh), naturally, if a compiler sees the exact type in a local scope, no call will be virtual either. In Java, all calls are virtual by default unless stated or proven by compiler otherwise, interface calls there are also more expensive which is why certain areas of OpenJDK have to be this advanced in terms of devirt, and support de- and re-optimization, that .NET's JIT opted not to do - data shows most callsites are predominantly mono and bi-morphic, and the fallback cost is inexpensive in most situations (virtual calls are pretty much like in C++, interface calls use inline caching style approach). Today, JIT, on average, produces faster application code at the cost of memory and startup latency. It also isn't limited by "can only build for -march=x86-64-v2" unlike AOT. In the future, I hope AOT gets the ability to use higher internal compiler limits and spend more time on optimization passes in a way that isn't viable with JIT as it would mean sacrificing its precious throughput. [0]: https://migeel.sk/blog/2023/11/22/top-3-whole-program-optimizations-for-aot-in-net-8/ https://migeel.sk/blog/2023/11/22/top-3-whole-program-optimi...