Things I've learned about the .NET runtime
The JIT is actually required
(Or, in NativeAOT, other mechanisms that aren’t just what’s in System.Private.CoreLib.)
Some methods are JIT intrinsics, but I had previously thought the JIT was just an optimisation. This is false! For example, Type.TypeHandle throws and must be swapped out by the JIT. I don’t know how this works on NativeAOT.
Console.WriteLine
is incredibly complicated
Console.WriteLine
exercises at least the following:
Top-level no-exception-handler behaviour change in net9
In earlier versions of .NET, finally
blocks and Dispose
methods were liable not to run when an unhandled exception terminates program execution.
This was documented as implementation-defined behaviour in the C# language spec, though it doesn’t appear to be documented elsewhere.
That implementation-defined behaviour means my programs basically all contain this boilerplate:
|
|
However, in .NET 9 (I think) this behaviour appears to have been changed, and now the .NET runtime does the obvious thing - Dispose
methods run and finally
blocks execute even when an exception causes shutdown!
The .NET runtime doesn’t actually model uint32
Neither on the eval stack nor as a CLI intrinsic type are uint32
or uint64
modelled; they’re stored as int32
and int64
with two’s complement.