
Writing a Managed JIT in C# with CoreCLR - benaadams
http://xoofx.com/blog/2018/04/12/writing-managed-jit-in-csharp-with-coreclr/
======
GenericsMotors
Thanks, enjoyed the article! Though on this point:

> As you may know, in .NET CoreCLR (and Mono), the JIT has been entirely
> written in C/C++. That’s sometimes even a joke used by C++ developers to
> remind the enthusiastic C# developer crowd that their ecosystem is being
> actually ran by C++.

The CLR has never been only about C#. While C# may be the most popular
language to target the VM, it will run anything that has been compiled to
valid MSIL (or even emitted at runtime).

~~~
Scarbutt
I hear is pretty bad performance wise compared to the JVM for dynamic
languages.

~~~
pavelbr
What dynamic languages run on the jvm? To my knowledge it doesn't support
dynamic types at all.

~~~
mythz
Clojure, Groovy, JRuby, Jython are popular dynamic languages on the JVM, there
are others:

[https://en.wikipedia.org/wiki/List_of_JVM_languages](https://en.wikipedia.org/wiki/List_of_JVM_languages)

> To my knowledge it doesn't support dynamic types at all.

Not sure where you've got that from or what that's supposed to mean.

~~~
vorg
> Clojure, Groovy, JRuby, Jython are popular dynamic languages on the JVM,
> there are others

Perhaps he meant no dynamic languages have become popular enough on the JVM
that it becomes common knowledge that the JVM can support popular types. None
of those 4 languages you mentioned (Clojure, Apache Groovy, JRuby, Jython) are
popular, whereas alternative JVM languages built from the ground up as static
languages (i.e. Kotlin and Scala) are the ones people are adopting.

~~~
omaranto
My impression was that Clojure's popularity was comparable to Kotlin and
Scala's. Is that not the case?

~~~
vorg
I like programming in Clojure -- it's the language that introduced me to lisp
syntax and immutable values. But Scala has been adopted and Kotlin is being
adopted to a far greater degree than Clojure seems to have been.

------
peoplewindow
Nice! This sort of direction is definitely the way managed runtimes are going
and should go, long term.

Here's a quick comparison vs Graal, which is the same thing but for the
HotSpot JVM.

Java 9+ has Java-side interfaces for extending the compiler called JVMCI. So
you don't need the deep hacking with the C++ vtables and other such mangling,
that I guess could be quite fragile in the face of future changes to the
runtime. There's a clean plugin API to let you write a compiler entirely in
managed code. You can drop it in as a JAR, set some command line flags, and
it'll be used.

HotSpot has an interpreter (written in C++ for now). The CLR never did,
instead it uses a model where all code is compiled on first access. This means
Graal avoids the re-entrancy issues that Alexandre solves with a counter in a
TLS slot. Instead Graal is invoked asynchronously whilst the main program
continues to run. And Graal is itself interpreted until it warms up, at which
point it starts to compile itself.

The ICorJitCompiler interface the .NET JIT has to implement is much simpler
than the HotSpot equivalent:

[http://lafo.ssw.uni-
linz.ac.at/javadoc/graalvm/jdk.internal....](http://lafo.ssw.uni-
linz.ac.at/javadoc/graalvm/jdk.internal.jvmci.compiler/javadoc/)

Whilst the compile method is kind of the same, the CompilationResult structure
is far harder to fill out. That's because HotSpot heavily uses de-optimisation
to make things go fast, so the compiler isn't just responsible for production
of machine code but also de-optimisation metadata. That metadata enables
converting stack frames of optimised code back into interpreter stack frames
and is quite complex to produce, in fact it affects the design of the whole
compiler. It's also required to produce safepoint metadata, GC pointer maps
and more.

[http://lafo.ssw.uni-
linz.ac.at/javadoc/graalvm/jdk.internal....](http://lafo.ssw.uni-
linz.ac.at/javadoc/graalvm/jdk.internal.jvmci.code/javadoc/jdk/internal/jvmci/code/CompilationResult.html?is-
external=true)

There's also an additional reflection API that provides access to things that
the compiler needs, like raw bytecodes.

The author says finally

 _The benefits to have a Managed JIT wouldn’t be visible in short-term or even
medium-term while it could open many possibilities in the long run, but for a
project of the - legacy - size of .NET, this is probably too much to ask._

But is it too much to ask? Java not only has Graal but Project Metropolis, the
goal of which is to explore conversion of HotSpot into Java. HotSpot is older
and more complex than the CLR, but apparently they don't consider it
impossible. And SubstrateVM is the spiritual successor to Jikes; a JVM written
entirely in Java, using magic methods and classes to model pointer arithmetic
for the garbage collector and the compiler in AOT mode to produce the final
binary image.

The real issue is not .NET's size or legacy, but rather, Microsoft's level of
investment in it and/or their strategic choices. The .NET team are paying a
heavy price for the lack of investment into portability in recent years, and
have been frequently distracted by the many re-spins and backwards
compatibility breaks. They have also tended to push complexity and performance
into the C# language rather than the runtime. Perhaps in hindsight the Java
approach has worked out with less tech debt and a better path to the future.

~~~
tybit
I agree that the .NET runtime seems under invested in and the lateness to the
portability game is damaging.

It would also be nice to see more experimentation, e.g as you mention Graal,
Truffle, Substrate VM and Project Metropolis all look amazing and there
doesn’t seem much on the .NET side to compete other than CoreRT.

However I’m skeptical about the claims that complexity has been pushed into C#
and has caused tech debt. What do you mean by that?

To me they seem to have made the right trade offs. Java is getting value types
too because there’s a limit to what run times can do on behalf of developers.
Spans in C# and .NET seem the way languages are moving in general with e.g
slices in Go, views in C++ etc.

There are definitely some pitfalls for high performance areas but they are
actively being worked on as well as ensuring the general case is better, e.g
devirtualization of interfaces and abstract classes where possible in the JIT
IIRC.

~~~
pjmlp
The only technical debt I see on C#, are little things like 3 different ways
of declaring lambdas for example.

As for the rest, my only complaint is that Java and C# designers should have
paid more attention to what was being done in Delphi, Oberon, Component
Pascal, Modula-3, Eiffel, and have offered value types, spans, low level
primitives for high performance code, AOT/JIT compilers since version 1.0.

And in this regard, C# fares much better than Java.

~~~
ygra
I'd argue that copying covariant array conversion from Java was a mistake as
well. Perhaps in both the language and the runtime.

~~~
pjmlp
Actually they copied it from all major OOP languages with common root object
that were already prevalent before Java was designed.

I am thinking about Eiffel, Smalltalk, Sather, Oberon family, Moduls-3, Object
Pascal.

So it was a natural mistake to do.

------
lucasnichele
Is there any problem in using this in applications that verify the code
signature?

~~~
chrisseaton
It's the bytecode (the 'intermediate language' in CLR terminology) that is
verified by signature, not the dynamically generated machine code, so it won't
make any difference.

