HN user

andyayers

41 karma

I currently work on the .NET JIT.

Before that I worked on the Phoenix Compiler Framework at Microsoft and the High Level Optimizer at HP.

Posts0
Comments20
View on HN
No posts found.

.NET JIT developer here.

What else would we call it? It is what it is.

I believe there are some differences between what .NET does and what mainstream Java does. For instance, objects can be stack allocated even if they can't be turned into collections of scalars. This allows the JIT to stack allocate small known-sized arrays.

There indeed is a regression if the method is only called a few times. But not if it is called frequently.

With BenchmarkDotNet it may not be obvious which scenario you intend to measure and which one you end up measuring. BDN runs the benchmark method enough times to exceed some overall "goal" time for measuring (250 ms I think). This may require many calls or may just require one.

Long-running methods (like the one here) transition mid-execution to more optimized versions, via on-stack replacement (OSR), after roughly 50K iterations. So you end up running optimized code either if the method is called a lot or loops frequently.

The OSR transition happens here, but between .net8 and .net9 some aspects of loop optimizations in OSR code regressed.

In .NET, even in optimized methods, there can be "untracked" lifetimes where a stack slot is reported live to GC throughout the extent of a method, so presumably these can lead to the "over-reporting" cases mentioned.

The number of trackable lifetimes was 64 in .NET Framework but has been steadily increased in modern .NET and is now 1024, so it's rarely a capacity issue; but there are cases where we can't effectively reason about lifetimes.

For us another big drawback to conservative scanning is that any object referred to by a conservative reference cannot be relocated, since the reference might be live and is not guaranteed to be a GC reference; these objects are (in our parlance) effectively pinned, and this causes additional overhead.

Galois Theory 2 years ago

There are a few interesting places where Galois Theory touches on compilation/programming.

Abstract interpretation models a potentially infinite set of program behaviors onto a simpler (often finite) model that is (soundly) approximate and easier to reason about (via Galois connections); here the analogy is to Galois Theory connecting infinite fields with finite groups. I often think about this when working on Value Numbering for instance.

Also (perhaps a bit of stretch) it's interesting to think of extending a computational domain (say integers) with additional values (say an error value) as a kind of field extension, and as with field extensions, sometimes (perhaps unexpectedly) complications arise (eg loss of unique factorization :: LLVM's poison & undef, or NaNs).

Something closer to a "pure codegen/runtime" example perhaps: I have data showing Roslyn (the C# compiler, itself written in C#) speeds up between ~2x and ~3x running on .NET 8 vs .NET 4.7.1. Roslyn is built so that it can run either against full framework or core, so it's largely the same application IL.

Compiler Explorer 4 years ago

IIRC with .NET 7 we will be able to improve this as we can now dump the jit-generated assembly from official builds.

.NET 7 will be officially released in a month or so.

Currently C#/F#/VB support in Compiler Explorer relies on prejitting which has various issues.