Mono's New Code Generation Engine

by Miguel de Icaza

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.

Posted on 20 Jan 2009