Native Compilation – Why JIT when you can CodeGen!
[caption id="attachment_115" align="alignright" width="400"] Typical .NET Compilation, JIT Compilation and Execution Cycle[/caption]
For 15 years, .NET apps are created with a compiler that emits intermediate code (IL). That IL is evaluated by a just-in-time compiler (JIT) that performs a native compilation of your application allowing it to run on the destination operating system that hosts the common language runtime (CLR). Until recently, Microsoft-provided .NET tools only ran on Windows. If we want to shortcut this two-step compilation process and deliver a 100% native application on Windows, Mac, and Linux, we need an alternative to the CLR. The project that is aiming to deliver that solution with an ahead-of-time compilation process is called CoreRT.
CoreRT CodeGen Current and Planned
[caption id="attachment_117" align="alignleft" width="400"] Direct Native-Compilation from .NET Source Code[/caption]
The CoreRT compiler currently has the RyuJIT embedded at its heart to allow current environments where .NET is available to compile directly to native code. You already know some of the places where we have the RyuJIT working nicely: Windows Desktop, Windows Phone, MacOS, and several Linux Desktop distributions all use RyuJIT. But what about those operating systems and environments where we don’t currently have .NET developers invested and working?
If I really want to write some C# code and have it “just work” on a new IoT device, I don’t have any options until the RyuJIT is capable of generating machine code that works with that processor and operating system.
One strategy we are investigating is the ability to transpile .NET code to C++ code that could be compiled with an appropriate C++ compiler for the target platform. This strategy opens doors for hardware development because you would no longer need to wait for a Microsoft engineer to extend our compilers to support some new OS or new hardware in order to allow .NET developers to work with your product.
Progress on CodeGen
Code Generation and Transpilation is not an easy task, and our team is working diligently to solve this problem. In the CoreRT repository on GitHub you can watch the progress the development team is making on the native compilation tools. In particular, we had an interesting bit of progress over the summer as we completed some tasks that allow our C++ CodeGen to interpret .NET interface usage and properly dispatch it to C++. We can now support transpiling interface usage in this baseline scenario:
You can find the source code commit that supports dispatching this type of interface structure on GitHub at: https://github.com/dotnet/corert/commit/c6a2b271f5cc6d5b4c271e1dd9ecb364b5a2743c What makes this interesting is the inspection of the .NET dependency graph and object hierarchy to determine which method calls to actually dispatch from C++.
Interface Challenges Addressed
This seems like a simple step that we have taken, but there are several challenges that we faced when examining the code.
- C++ does not have a 1-to-1 feature mapping to .NET. We need to interpret and determine the appropriate way to map .NET features into C++ calls appropriately.
- Multiple .NET classes may implement the same interface. The transpiler must be smart enough to know which concrete class to instantiate and pass around as an interface.
- It accomplishes this by building supporting data-structures (dispatch calls and a dispatch map) in a prescribed format and passes them to the runtime to figure out which method slot to dispatch on given that a particular interface method will likely live in a different slot on the various implementing concrete classes. In this way, it works the same as the RyuJIT case: we just lay out the structures carefully in the generated C++ so that it is compatible with what the runtime expects.
- The concrete class may implement virtual methods that belong to another interface or superclass. These interactions need to be preserved in C++
We believe that investing in C++ code generation is going to allow the .NET ecosystem to grow and support platforms that have not been invented yet. With this approach, we no longer need to write JIT compilers for every environment, and can rely on the standardized and robust C++ compilers that are commonly available. To learn more about CoreRT and the CodeGen processes being constructed, follow the CodeGen label on the CoreRT issues repository. We’ll have more about CoreRT in the future as this framework progresses.