Three years ago, in November of 2005 we started a project
to upgrade Mono's code generation engine as the engine started
to age and it became increasingly difficult to improve code
generation and extend the JIT engine in meaningful ways.
The new
code generation engine is based on a linear intermediate
representation as opposed to the tree-based intermediate
representation that we had used up to Mono 2.0.
Switching the code generation engine is a pretty
significant effort and we did not want to switch it shortly
before we had to ship Mono 2.0, so we decided to ship 2.0 with
the engine that had been in wide use.
Shortly after we branched Mono's tree for
the 2.0
release Zoltan merged his work from the linear branch into
the main tree.
We have now shipped all of this as part
of Mono
2.2, you can get
it here.
Some Benchmarks
Mono's new engine generates much better code than the
version found in Mono 2.0.
Speed: The engine will mostly benefit computationally intensive
code, usually between 10% and 30% performance increase, with
some cases going up as high as being 50% faster.
Code size: the new engine generates slimmer code,
typically 12% to 20% smaller code generated.
Check out some of
the benchmark
results.
Debugging the Transition
Although we had our test suite, and we regularly tested the
code against most apps, we were still afraid that something
might go wrong. The new code could miss-compile something,
and it would be hard in a large project to pin point exactly
what went wrong.
For example, the problem might not appear while compiling a
small test program like `hello world', but could appear when
running a web site under heavy load or when running
MonoDevelop.
Zoltan came up with a very interesting solution: for a
period of time Mono had two JIT engines built into it, the new
and the old one. Here is where the clever trick comes in:
an environment variable contained the number of methods that
should be compiled with the new JIT engine. After the Nth
method had been compiled, the engine would switch code
generators.
This was used to bisect regressions and failures.
A couple of months after we had done the switch and both
our unit tests and our system tests passed the old JIT engine
was eliminated from Mono.
SIMD
Using SIMD for accelerating certain floating point
operations had been in the back of our minds for a while.
We looked into implementing that in our old engine, but that
turned out to be very difficult.
With the new engine, Rodrigo was able to put together a
prototype in a weekend (the legend goes that Rodrigo's wife
was busy that weekend).
This prototype was later turned
into Mono.SIMD
an API for accelerating vector operations.
Mono 2.2 is the first release to officially support and
distribute it. To learn more about Mono.SIMD support, you
can
see this
blog entry.
Full Generics Sharing
With this release, the generics code sharing engine has
been completely debugged and is now enabled not only for code
that lives in mscorlib, but for all generics code written by
the user.
The Technical Details
We have
provided A
complete description of Mono's new engine design and the
the various code generation stages.