DotNetAnywhere: An Alternative .NET Runtime
mattwarren.org
mattwarren.org
For all its flaws (and there are quite a few) it was a very interesting learning exercise, and it worked better than I ever really expected ;)
I don't really intend to ever do any more work on it, especially now that there are open source "real" implementations. But it's been nice to see it used in Blazor :)
If you have any questions about it, please ask.
Here's my questions (assuming you can remember from 6+ years ago):
1) What was the hardest part of .NET to understand and/or implement?
2) Were there any surprising things about the .NET runtime/specification that you learnt about along the way?
3) Should JIT.c really be called Interpreter.c :-)
But I'm fairly sure the hardest part to implement was the support for generic types/methods. It made all the code that handles types way more complex (as expected I suppose!), and there's definitely a bug or two remaining. Correctly handling open/closed generic types and construction of types from generic arguments was painful. It didn't help that I initially implemented only non-generic type support, then had to hack generics into it. Were I to start again I'd implement the whole thing in a generic-first way.
The design of classes/structs and they they interact with generics is nice. And the `constained` IL prefix is a really neat optimization to avoid boxing. The use of type-agnostic CIL instructions (e.g. `add` can work on int, float, ...) is also a nice touch.
JIT literally stands for "Just In Time". It doesn't say what it's actually doing just-in-time ;) So (in my opinion) JIT.c is correct. It's translating CIL opcodes to dna-internal opcodes, which it does just-in-time just before a method is executed for the first time. The reason it does this at all is because there are many things to resolve when working from CIL that it's much better to do just once rather than every time a method is executed. A simple example is method references, which are by name in CIL, but are a simple pointer in dna-internal opcodes.
r.e. 'JIT v Interpreted', I should've checked wikipedia, it backs up what you're saying:
> Most often this consists of translation to machine code, which is then executed directly, but can also refer to translation to another format
It's possible some of the other DNA forks mentioned here may be more suitable for production, I'm not sure.
Plus if you were to move it to it's own repo/organization, it would allow the forks to submit their changes upstream and have one master repo instead of multiple forks with their own changes.
But someone else is very welcome to do so :)
https://github.com/nikhilk/scriptsharp was kind of the granddaddy of them all, with no updates since 2013.
https://github.com/bridgedotnet/Bridge Saltarelle was acquired by Bridge.NET mid-2015: https://blog.bridge.net/bridge-net-acquires-saltarelle-c77a9... and seems to be going strong.
https://github.com/SharpKit/SharpKit went the other way and is now open source, but original L/GPL/references to licensing for commercial use may have limited growth; it is now MIT.
http://jsil.org/ mostly demonstrates games, and focuses on translating MSIL bytecode rather than any specific language or runtime.
https://github.com/chrisdunelm/DotNetWebToolkit
It's not complete, certainly not usable for anything remotely real, but could handle quite a bit of C#. And was fun to work on :)
Nice write up, thanks. I wasn't aware of this project, it is very impressive. Does anyone know of similar projects for .net or Java?
The End of IKVM.NET | https://news.ycombinator.com/item?id=14174774 (Apr 2017, 108 comments)
I deliberately didn't start with Benchmarks, pretty much for that reason! Plus I put a huge caveat in before I showed the results.
> This article is right, the DotNetAnywhere code really seems a gem, well worth to study!
Glad you think so as well, that's exactly the reason that I wrote about it. It's relatively unknown and if nothing else it's a really useful resource (whether it's suitable for production is another matter)
I have no idea if it would be compatible with DotNetAnywhere
Which memory issues do you mean? The items that are covered in this section http://mattwarren.org/2017/10/19/DotNetAnywhere-an-Alternati... ('Garbage Collector') or something else?
> Mind you, the whole heap code really needs a rewrite to reduce per-object memory overhead, and to remove the need for the binary tree of allocations. Not really thinking of a generational GC, that would probably add to much code. This was something I vaguely intended to do, but never got around to. The current heap code was just the simplest thing to get GC working quickly. The very initial implementation did no GC at all. It was beautifully fast, but ran out of memory rather too quickly.
At least in the simple tests I did it behaved as expected, but I know that testing a GC for correctness is not a simple task!!
Keeping the code base small is a double edged sword. The trouble with everything going web-based these days is that script kiddies (myself included) should have some awareness of how memory is being managed and when to worry about holding IEnumerables in memory. Your write-up here is interesting and it's the first I've heard of Blazor. This is all very fascinating you have me reading the codebase now.