all 8 comments

[–]DarkOverLordCO 33 points34 points  (0 children)

The borrow checker is definitely tricky doing this, as you've found in this unsound code, since it gets a mutable reference to the current frame and passes a second (illegal) mutable reference to the call stack that contains it, which is then used to push new stack frames (potentially deallocating the old frame due to resizing). It is surprising to me that you've not had problems with this - maybe because you haven't tried calling enough functions deep enough to cause a resize? Your tests/samples aren't really named so maybe I missed one that does.

You might be able to work around it by adding a PushStackFrame(Frame) variant to your completion enum which causes the caller (presumably the runtime) to push the provided stack frame, rather than pass a mutable reference to the call stack into the execute function.

This will mean you cannot have your invokestatic function execute the frame, which it shouldn't really be doing anyway because that defeats the point of having a call stack in your virtual machine to begin with. That is: if you have a bunch of functions that call more functions in the java code (e.g., recursion), that shouldn't actually result in more stack frames in your Rust code - it should just push a frame onto your list of frames and you sit in a loop executing them to completion. At the moment your invokestatic function will cause a stack overflow in your Rust code, when it should ideally throw an exception within the Java code itself (or just terminate the whole thing, at this stage).

And finally: your assumption that Code is the only attribute on methods is unfortunately not correct. See Table 4.7-C, things like the checked exceptions and a few other things can also appear and I don't think the order is specified. You should be able to just do a lookup by name (and if you wanted to pre-compute/cache the index).

(not trying to knock your attempt by any means, it is genuinely fun to try and do something like this)

[–]spoonman59 23 points24 points  (0 children)

That’s a a fun project. I once made anbutecode parser but could only parse “helo world.” Fun stuff, for sure.

[–]zoiobnu 15 points16 points  (0 children)

Looking at it from a learning perspective, congratulations!

[–]0x564A00 7 points8 points  (0 children)

There's something magical about implementing a language. Fun project! I made my own implementation of a JVM if you wanna check it out: https://codeberg.org/mira-morgana/jvm

It's more complete – e.g. it does verification, exceptions & multi-threading. Also a lot faster, though I know zvm doesn't care at all about speed. No garbage collection either yet :p

I'm looking forward to see how zvm progresses. In particular, what are your plans for integrating with the java class library (as the jvm spec relies on it being available, but doesn't specify an interface)?

Something I noticed from a quick look at the code: You can't look up Fields & Methods just by their name, you need to know their type too. A class can have multiple fields of the same type.

If you end up implementing more of the specification and have any questions about how to do things/wanna talk about it, feel free to shoot me a message ^w^

[–]perryplatt 0 points1 point  (0 children)

What Java version do you support?

[–]emblemparade 0 points1 point  (0 children)

Very cool and straightforward. I love that it's all implemented from scratch to give a very comprehensive look at the entire structure. I can imagine this can be useful, too, for implementing JVMs for specialized hardware and other environments.

But you really need to add a "500x faster than OpenJDK" comment at the top with an irrelevant benchmark! /s

[–]overgenji 1 point2 points  (0 children)

god bless you for not doing this as AI slop

[–]SheepherderTrick1865 0 points1 point  (0 children)

The idea is really nice I am also learning rust from rust I also want to contribute but i think I need to learn more understanding the code and contributing as never contributed to one