Congratulations on the progress and getting the engine out there!
One nice thing about interpreters versus JIT compilers is that they can be used in places like iOS without too much fuss (AFAIK you have to bundle all the WASM you will run though, or something like that).
I'm biased since I work on it, but any considerations around adding support for the Component Model? It's more complex than the base spec of course but incredibly robust -- really the present/future of "modern" WebAssembly across languages.
Just to point out, even a P2 implementation is still very useful! P3 is necessarily more complex than P2, but P2 also contains very useful features that are worth implementing. Most language toolchains are centered around p2 today and that will take a while to change.
Also, there is an adapter for automatically taking p1 components to p2, and a p2 to p3 adapter may exist in time, if desire is great enough! IIRC it doesn't exist right now.
WASM seems to be rather poorly documented in general. I used to
think it is only badly documented in Ruby (which it is), but I
have been slowly reading "WebAssembly The Definitive Guide" and
when comparing this to information on the internet, it seems
WebAssembly is years behind e. g. HTML, CSS, or JavaScript in
regards to documentation. Granted, it is not the same user base
(more people will be interested in HTML and CSS simply because
there is a bigger pool of people interested in that, rather than
in WebAssembly), but still - documentation appears to become
really worse in general on the internet. Finding it too.
So in this regard, having more implementations may be useful (more opportunity to improve documentation) - thus while I am in general skeptical, this is good news here, even if I do not use Go myself.
WASM development is really for a "level lower" than HTML, CSS, and JavaScript development. I know this because, being curious about it myself, I tried a year ago to make use of a WASM runtime in Go to run a piece of WASM code (I think I wrote something in V and compiled it to WASM).
It becomes a huge pain in the bum as soon as you have to deal with moving anything more than trivial types around, because you have to manually allocate memory for the WASM runtime and move bytes around. The byte representation needs to be understandable by the source language for your WASM code (the v language in my case). This is why these WASM runtimes use ints in their README examples, it would look and be horrendously complex otherwise.
If one is looking to use WASM for something for plugin development in the backend, I would try and look for something that is not WASM generic, but works with the source language, and where the WASM aspect is an under-the-hood detail.
This is the same in any system where you have two different runtimes/programming languages. The source values need to be serialized to bytes and then deserialized by the target. You could use json for this or flatbuffers. WASI has its own serialization mechanism but I don't know what langugages it supports.
Interesting; I've been using WebAssembly as a compilation target for various projects for the past four years, and have been fairly happy with the state of documentation. I've never heard of that book you mentioned (I should check it out!), and instead I just read the spec directly: https://webassembly.github.io/spec/core/
Or occasionally I Google specific Wasm instructions and find .wat examples for them on MDN.
I'm sure you're right that the documentation is years behind that of HTML and CSS, but is there some specific aspect of Wasm documentation that you find lacking that isn't covered by the spec?
Right. I was able to write custom wasm generation for browsers just going off the binary encoding spec. Started with using wasm as target IL for a Befunge JIT
Do you have any plans to add timeouts or some other mechanism for limiting the amount of CPU a webassembly call can use?
I'm always interested in options for using WebAssembly as a sandbox to run untrusted code, but one of the things I need to protect against is an infinite loop.
I'm working on an embeddable mini VM (RISC-V rather than WASM) and am considering this. In my model, there's something akin to a hardware watchdog where the VM is considered hung if it executes too many instructions without calling a yield() function in the host, then there's the ability to set a maximum number of instructions to execute before returning to the caller.
Lua has hooks, which are callbacks that can be registered for a variety of different events, including every N instructions, and every call can decide to terminate the whole thing with an error. This mechanism can be used for different purposes, including tracing, some kind of performance stats and, of course, cancellation. I always found it to be a nice general solution.
Yes, I am considering using something like https://pkg.go.dev/context for this very purpose, though I need to read a bit more into it first.
Funny that you built a Python wrapper as I originally started this implementation in Python, which was...not a good idea.
Claude hallucinated the acknowledgments section though :D
Limiting the CPU vs protecting against an infinite loop are two different problems. The former is usually solved by sandboxing and using the limiters exposed by it, while the latter can be easily solved by just adding a cancellation timeout, when the function call/process/API call/whatever takes longer than X seconds, cancel it and return an error.
We have two: fuel and epochs. Fuel (analogous to "gas" as it appears in many VM platforms) is a deterministic count and epochs check an always-increasing counter in shared memory meant to be periodically bumped by another thread. In either case, hitting the limit can be configured to either async-yield back to the event loop (in async mode) or to trap/terminate the Wasm instance. Both are based on instrumentation, i.e., extra code inserted during Wasm-to-machine-code compilation to do these checks at the start of loops and at the top of each function. Epoch instrumentation is cheaper because it's checking a mostly-read-only value in memory (so usually cached) while fuel loads and stores that value constantly from the VMContext.
(Core Wasmtime maintainer here, and I built our epochs mechanism when I realized we could do better than fuel if one doesn't need the determinism, only periodic yields)
> What was the reason to create Epsilon as an alternative?
I wanted to build something fun, I did not check for existing implementations on purpose. I ended up putting more effort than I originally expected into this and now it's starting to look like it could be actually useful, almost by accident.
Also what were the goal behind a pure golang solution via wazero + wasm sqlite as you had made?
Was it cross platform support, if so, what are your thoughts on zig, I have seen a project use zig + golang to create cross platform C language support but I think that adding zig into the picture complicates the build process so there are tradeoffs and I am interested to hear your opinions about it!
Started as fun "what if" side project, but kept me interested for 3 years now. Turns out it's actually useful.
It's pretty portable: with some caveats, it works pretty much everywhere Go does. Performance is bad outside amd64/arm64, but for most popular OS/platforms it's fine. See this for an overall picture (these are the platforms I test): https://github.com/ncruces/go-sqlite3/wiki/Support-matrix
I bet you could do the similar with pglite, but this (and helping out with wazero) already consumes all my spare time.
I love sqlite a lot but there is always this idea in my head that maybe some day I might out grow sqlite and require postgres which in my opinion can be just "enough"
Starting out with postgres if done via pglite and similars with golang's sqlite-ish approach can be brilliant I guess and I had this what if idea sort of inspired by yours actually but I don't think I can do that project basically right now but yea
Idk maybe its offtopic and I really love golang but I am interested in converting cli golang awesome applications into android apps but they seem like a nightmare to create android apps in golang, do you know if there is some easier way to create golang android apps (sorry if its offtopic but I am interested to learn sooo much more about golang :p)?
Only tangentially related, asking out of curiosity.
If one wanted to have a JIT compiler from what I understand it would essentially need to be able to get a chunk of memory, generate instructions into it and then jmp there.
Nice! I started building a toy Go WASM VM myself but a few hours in realized I was in way over my head. Seems very readable, I'm going to want to go to school on this!
Seems like a next step would be automatic code generation to map user-supplied (or auto-generated) interface definitions to exported WASM module functions.
Congratulations on the progress and getting the engine out there!
One nice thing about interpreters versus JIT compilers is that they can be used in places like iOS without too much fuss (AFAIK you have to bundle all the WASM you will run though, or something like that).
I'm biased since I work on it, but any considerations around adding support for the Component Model? It's more complex than the base spec of course but incredibly robust -- really the present/future of "modern" WebAssembly across languages.
+1 on Component Model. AFAICT it's not planned for wasip3.
Just to point out, even a P2 implementation is still very useful! P3 is necessarily more complex than P2, but P2 also contains very useful features that are worth implementing. Most language toolchains are centered around p2 today and that will take a while to change.
Also, there is an adapter for automatically taking p1 components to p2, and a p2 to p3 adapter may exist in time, if desire is great enough! IIRC it doesn't exist right now.
You can download the WASM, it just can't materially change the purpose or scope of your app.
WASM seems to be rather poorly documented in general. I used to think it is only badly documented in Ruby (which it is), but I have been slowly reading "WebAssembly The Definitive Guide" and when comparing this to information on the internet, it seems WebAssembly is years behind e. g. HTML, CSS, or JavaScript in regards to documentation. Granted, it is not the same user base (more people will be interested in HTML and CSS simply because there is a bigger pool of people interested in that, rather than in WebAssembly), but still - documentation appears to become really worse in general on the internet. Finding it too.
So in this regard, having more implementations may be useful (more opportunity to improve documentation) - thus while I am in general skeptical, this is good news here, even if I do not use Go myself.
WASM development is really for a "level lower" than HTML, CSS, and JavaScript development. I know this because, being curious about it myself, I tried a year ago to make use of a WASM runtime in Go to run a piece of WASM code (I think I wrote something in V and compiled it to WASM).
It becomes a huge pain in the bum as soon as you have to deal with moving anything more than trivial types around, because you have to manually allocate memory for the WASM runtime and move bytes around. The byte representation needs to be understandable by the source language for your WASM code (the v language in my case). This is why these WASM runtimes use ints in their README examples, it would look and be horrendously complex otherwise.
If one is looking to use WASM for something for plugin development in the backend, I would try and look for something that is not WASM generic, but works with the source language, and where the WASM aspect is an under-the-hood detail.
I'm working with Extism at the moment, It's pretty nice at handling the memory allocations.
I'm not sure how well it carries over to embedded platforms though, but I'm really interested in trying.
This is the same in any system where you have two different runtimes/programming languages. The source values need to be serialized to bytes and then deserialized by the target. You could use json for this or flatbuffers. WASI has its own serialization mechanism but I don't know what langugages it supports.
Interesting; I've been using WebAssembly as a compilation target for various projects for the past four years, and have been fairly happy with the state of documentation. I've never heard of that book you mentioned (I should check it out!), and instead I just read the spec directly: https://webassembly.github.io/spec/core/
Or occasionally I Google specific Wasm instructions and find .wat examples for them on MDN.
I'm sure you're right that the documentation is years behind that of HTML and CSS, but is there some specific aspect of Wasm documentation that you find lacking that isn't covered by the spec?
WASM is also like two decades younger than HTML and CSS and generally useful to a small fraction of the audience.
I wonder if your question relates to WASM or things in the WASM-sphere like WASI et al?
I'm not sure if it's right but I think of WASM as just an ISA and I guess the documentation seems to cover instruction encodings and semantics.
Right. I was able to write custom wasm generation for browsers just going off the binary encoding spec. Started with using wasm as target IL for a Befunge JIT
Do you have any plans to add timeouts or some other mechanism for limiting the amount of CPU a webassembly call can use?
I'm always interested in options for using WebAssembly as a sandbox to run untrusted code, but one of the things I need to protect against is an infinite loop.
(I had Claude knock up an experimental Python binding to try Epsilon out, notes from that here: https://github.com/simonw/research/tree/main/epsilon-python-... )
I'm working on an embeddable mini VM (RISC-V rather than WASM) and am considering this. In my model, there's something akin to a hardware watchdog where the VM is considered hung if it executes too many instructions without calling a yield() function in the host, then there's the ability to set a maximum number of instructions to execute before returning to the caller.
This lets it be handled asynchronously at the pace the host code chooses https://github.com/ringtailsoftware/uvm32
Lua has hooks, which are callbacks that can be registered for a variety of different events, including every N instructions, and every call can decide to terminate the whole thing with an error. This mechanism can be used for different purposes, including tracing, some kind of performance stats and, of course, cancellation. I always found it to be a nice general solution.
wazero has supported context cancellation for a long time :) https://github.com/wazero/wazero/blob/9286448974219ab3be0931...
Yes, I am considering using something like https://pkg.go.dev/context for this very purpose, though I need to read a bit more into it first.
Funny that you built a Python wrapper as I originally started this implementation in Python, which was...not a good idea. Claude hallucinated the acknowledgments section though :D
Limiting the CPU vs protecting against an infinite loop are two different problems. The former is usually solved by sandboxing and using the limiters exposed by it, while the latter can be easily solved by just adding a cancellation timeout, when the function call/process/API call/whatever takes longer than X seconds, cancel it and return an error.
I believe that wasmtime has some sort of mechanism for this called Gas if I'm not mistaken.
We have two: fuel and epochs. Fuel (analogous to "gas" as it appears in many VM platforms) is a deterministic count and epochs check an always-increasing counter in shared memory meant to be periodically bumped by another thread. In either case, hitting the limit can be configured to either async-yield back to the event loop (in async mode) or to trap/terminate the Wasm instance. Both are based on instrumentation, i.e., extra code inserted during Wasm-to-machine-code compilation to do these checks at the start of loops and at the top of each function. Epoch instrumentation is cheaper because it's checking a mostly-read-only value in memory (so usually cached) while fuel loads and stores that value constantly from the VMContext.
(Core Wasmtime maintainer here, and I built our epochs mechanism when I realized we could do better than fuel if one doesn't need the determinism, only periodic yields)
This could have been a Show HN?
Also: would be nice to see wazero (https://github.com/wazero/wazero) mentioned. What was the reason to create Epsilon as an alternative?
> What was the reason to create Epsilon as an alternative?
I wanted to build something fun, I did not check for existing implementations on purpose. I ended up putting more effort than I originally expected into this and now it's starting to look like it could be actually useful, almost by accident.
why so critical? why divert attention? why bother about the title prefix?
Because people filter by it
How does this compare with wazero?
So far, seems interpreter only, lots simpler, etc.
I'd be interested to understand the goal behind it better.
I knew I remember your name working with something of sqlite and golang
https://github.com/ncruces/go-sqlite3
Man I really enjoy golang and cross portability and wazero + sqlite could still be cross portable which is super fascinating
What are your thoughts on https://github.com/electric-sql/pglite (postgres in wasm)?
Also what were the goal behind a pure golang solution via wazero + wasm sqlite as you had made?
Was it cross platform support, if so, what are your thoughts on zig, I have seen a project use zig + golang to create cross platform C language support but I think that adding zig into the picture complicates the build process so there are tradeoffs and I am interested to hear your opinions about it!
Started as fun "what if" side project, but kept me interested for 3 years now. Turns out it's actually useful.
It's pretty portable: with some caveats, it works pretty much everywhere Go does. Performance is bad outside amd64/arm64, but for most popular OS/platforms it's fine. See this for an overall picture (these are the platforms I test): https://github.com/ncruces/go-sqlite3/wiki/Support-matrix
I bet you could do the similar with pglite, but this (and helping out with wazero) already consumes all my spare time.
I love sqlite a lot but there is always this idea in my head that maybe some day I might out grow sqlite and require postgres which in my opinion can be just "enough"
Starting out with postgres if done via pglite and similars with golang's sqlite-ish approach can be brilliant I guess and I had this what if idea sort of inspired by yours actually but I don't think I can do that project basically right now but yea
Idk maybe its offtopic and I really love golang but I am interested in converting cli golang awesome applications into android apps but they seem like a nightmare to create android apps in golang, do you know if there is some easier way to create golang android apps (sorry if its offtopic but I am interested to learn sooo much more about golang :p)?
[dead]
The goal was to see if I could do it :D
Which is how lots of great things start.
But I guess now that it's done, the comparison is obvious, and as a wazero maintainer, I wanted to know what we could learn from your experience.
Only tangentially related, asking out of curiosity.
If one wanted to have a JIT compiler from what I understand it would essentially need to be able to get a chunk of memory, generate instructions into it and then jmp there.
Is creating such a thing possible in just Go?
Yes. You need some syscalls and unsafe, but it's possible.
wazero does this, on amd64 and arm64: https://github.com/wazero/wazero
You can read more about the approach - from the creator - here: https://mathetake.github.io/posts/runtime-code-generation-in...
Okay wow. I could not have gotten a better reply. This one feels like an early Christmas gift, my sincere thanks!
Nice! I started building a toy Go WASM VM myself but a few hours in realized I was in way over my head. Seems very readable, I'm going to want to go to school on this!
Very nice!
Seems like a next step would be automatic code generation to map user-supplied (or auto-generated) interface definitions to exported WASM module functions.
Nice project.!
Is there anything akin to file sockets api for wasm? I see a lot of potential in using them with go channels for ipc between multiple wasm modules.
I can't wait till this will be able to run in WASM on the web. Looks cool.
>with 0 dependencies
>Looks inside
>0 dependencies
Wow. Amazing. Was that a planned feature or did you just manage to write the entire project without stepping out the go std lib?
It was very much the point to build everything from scratch.
Though to be fair, for tests I am relying on https://github.com/WebAssembly/wabt
[flagged]
[flagged]