Rust to .NET compiler - end of GSoC, what now?
This is a short-ish update about rustc\_codegen\_clr. As some of you may know, I have participated in Rust GSoC 2024, working on adding support for compiling and running cargo test's inside the .NET runtime.
Well, GSoC is now over, and I have accomplished my original goal and a bit more. The project is now capable of correctly running \~95% of std and core unit tests.
I would like to quickly thank my mentor, the wider Rust compiler team, and GSoC organizers for this amazing opportunity. The help I have received was invaluable, and I would not be able to make so much progress without it.
Since GSoC is over for me, a new question raises: what to do now? I will be still working on the project, like I did for a year before. However, I have some important clean-up / refactors to do.
So, for the next few weeks, I will be focusing solely on refactors and fixing some longstanding bugs / limitations.
While the progress may seem "paused" from the perspective of an outsider, this work is just necessary for the project to move forwards.
The most important tasks are:
- Moving to
cillyv2.cillyis the library I developed to create and modify .NET assemblies. It is a core part of the project, which is very hard to replace. However, my initial design, while quite robust and nice to work with, has some annoying limitations. This format uses a lot of memory, and the intermediate representation occupies a lot of disk space, is hard to optimize, and not well suited to all tasks. At the end of GSoC, I rewrotecillyfrom scratch, using optimization techniques such as interning to reduce disk and memory usage. The size of intermediate files is now 7x smaller, and the memory footprint should also be more reasonable. The new representation is also very friendly for caching, which allows me to reuse a lot of information needed for optimizations, or for emitting semantically correct C source files. The experimental support for compiling Rust to C also had to be temporarily removed, in order to facilitate move tocillyv2. I plan to rewrite the C exporter after this refactor is done. This new rewritten C exporter should produce more "standard" C, and should be of much higher quality. Overall, the new version ofcillyshould greatly improve the project, and enable some other much-needed changes. This move to the new version ofcillyis mostly done. The linker and all the tooling besides the codegen uses only the new representation. The type representation and all the built-ins / intrinsics have also been moved to this new representation. The code handling statics / constant data has also been fully rewritten. There is, of course, more work to do, but the bulk of it is already done. - Splitting the code better. (.NET specific change). Currently, all Rust code is thrown into one single class. The JIT does not like that, which leads to longer startup times - and other issues (if the function count is too large, the JIT will not compile Rust code). Just splitting code between crate-sized classes should do the trick, but there are other options to explore. In theory, each Rust crate could be translated into the separate Assembly. This should improve link and compile times, and allow for some degree of code reuse. This would also enable the .NET JIT to load and compile a crate while the Rust code is already running. E.g. std could be already JIT compiled and running, while something big like
tokiogets compiled in the background. Splitting code into multiple assemblies would be more difficult, but it is an option I am willing to explore. For now, I will probably just split code between classes. - Better initialization of static data. Currently, all static data is initialized all at once, at startup. There are ways to speed that up, tough. If I split those statics up, I can use .NET static initialization rules to my advantage, and lazily Initialize them. NET initializes the statics of a class the first time the class is used, so this difference in initialization will not be observable, but this should still decrease startup times. Startup times are not a very big problem ATM - starting all the tests in
stdtakes less than a second. This time includes the JIT compilation, static initialization, etc. Still - this time could become much more noticeable in the future, and this change is needed anyway for other reasons, so this refactor is also high up on the list. - Following Rust ABI more closely. Currently, the project uses its own, internal ABI. This ABI is "do whatever MIR is doing", which simplified debugging process, since the function signatures and local variables were well-preserved. Since I control both the caller and calle side of things, this is not a problem, because the ABI's on both sides match. However, the "proper" Rust ABI is a bit more complex, with many optimizations, and support for some more obscure features (like
#[track_caller]). Even partially respecting this ABI would make implementing some stuff easier, and could potentially pave the way for some more advanced features in the future. Now, I will never be able to respect the ABI fully (since some details, like the exact offset of values on the stack, are out of my control), which means that the ABI used by Rust programs running in .NET will not be compatible with the ABI used by native code. This has no effect on almost any programs compiled for .NET, and is only relevant for some potential future features, like support for mixed-mode assemblies (mixing native and .NET Rust).
After those important refactors are done, I will focus on adding compiler support for the few remaining Rust features(e.g. async). Currently, the codegen panics 39 times when building the std test suite - due to unsupported features. So, once those are supported, and I fix the remaining warnings, the codegen will be in what I consider "early alpha".
As for the longer articles about the project, I am currently working on one, but I am a bit unsatisfied with its pacing / quality. Would you (the Rust community) be interested in shorter articles(2-5 min), explaining how a certain feature(e.g. unwinds / panics) works under the hood, and goes through my implementation of it?
FAQ:
Q: What is the intended purpose of this project?
A: The main goal is to allow people to use Rust crates as .NET libraries, reducing GC pauses, and improving performance. The project comes bundled together with an interop layer, which allows you to safely interact with C# code. More detailed explanation.
Q: Why are you working on a .NET related project? Doesn't Microsoft own .NET?
A: the .NET runtime is licensed under the permissive MIT license (one of the licenses the rust compiler uses). Yes, Microsoft continues to invest in .NET, but the runtime is managed by the .NET foundation.
Q: why .NET?
A. Simple: I already know .NET well, and it has support for pointers. I am a bit of a runtime / JIT / VM nerd, so this project is exciting for me. However, the project is designed in such a way that adding support for targeting other languages / VMs should be relatively easy.
Q: How far from completion is the project:
A: Hard to say. The codegen is mostly feature complete (besides async), and the only thing preventing it from running more complex code are bugs. If I knew where / how many bugs there are, I would have fixed them already. So, providing any concrete timeline is difficult. I would expect it to take at least half a year more before the project enters alpha.
Q: Can I contribute to the project?
A:Yes! I am currently accepting contributions, and I will try to help you if you want to contribute. Besides bigger contributions, you can help out by refactoring things or helping to find bugs. You can find a bug by building and testing some small crates, or by minimizing some of the problematic tests from this list.
Q: How else can I support the project?
A: If you are willing and able to, you can become my sponsor on Github. Things like starring the project also help a small bit.
This project was a part of Rust GSoC 2024. If you want to see more detailed reports from my work, you can find them on the Rust zulip. While I do not plan to post there daily after GSoC 2024 ended, I will still write about some minor milestones there.
If you have any more questions, feel free to ask me in the comments.