Really clever use of the new WASM GC proposal. All the JS -> WASM compilers so far have basically just been shipping a whole JS engine - this is the first one I've seen that actually tries to map JS constructs directly to WASM primitives.
I haven't seen Static Hermes before, I'll take a look, thanks for the link!
With regards to porffor. It's a very good project and people behind it are probably much better at writing interpreters/compilers, but the biggest difference is in what WASM features the projects use. porffor uses only core WASM, which means they have to implement a lot more features themselves. Data types like arrays, structs/objects, garbage collection, exception handling etc. I am using WASM features added in proposals standardized very recently, like WASM GC or exception handling, which means I get a lot of the features almost for free. And I suppose that's also why semantics like scopes/closures are really hard to do for projects like porffor or even AssemblyScript and were relatively easy in Jaws.
The trade off is mainly in support. porffor compiled binaries can run on a lot of different WASM runtimes, I think there are even some runtimes for Core WASM for embedded devices. In case of Jaws, the runtime needs to support the proposals I use. Currently there are only two runtimes, that I know of, supporting both WASM GC and exception handling: V8 and WasmEdge. I believe more runtimes will get there, like for example WasmTime people are working towards exception handling, but it will take some time. Which is not a problem for me, cause it will definitely take a bit to reach any production level JS compatibility - I think the runtimes will have time to catch up with the proposals by then.
I haven't seen Wasmnizer before. This looks like a cool project and I'll be definitely taking a closer look when I have some time, but for now I just took a quick peek.
The main difference is obviously TypeScript vs JavaScript. Because they are not bothering with JavaScript, some stuff is much easier, like for example if a function specifies an argument as `number`, you can statically compile it to use a type representing a number (possibly even without heap allocations) instead of passing something like `anyref` everywhere and doing typechecks.
The second big difference is that they seem to use types imported form the host. This means they can implement part of the types/builtins/methods on the host (which is easier, cause in JavaScript you simply use JavaScript for defining host stuff) at a cost of doing more calls from WASM to the host. And then you need the host to implement those functions (here is an example for JS host: https://github.com/web-devkits/Wasmnizer-ts/blob/main/tools/...). My plan for Jaws is to only rely on WASI, so that you can run your program on any runtime that supports WASI.
I'm also not sure about their approach to semantics. I can't quite grasp how they implement for example scopes. I tried to compile a small TS script that relies on scope, like:
let message: string = 'Hello, World!';
function test() {
console.log(message);
}
test()
And the result was console.log printing null. I'm not sure if I'm doing something wrong or is it expected, but I'll ask them in an issue later.
Do you have any plans to be able to take TypeScript types to do type optimizations? That sounds like a bonus to me to be able to have easier implementation and faster run times.
Yup, that's something that I would definitely like to do. In performance critical applications adding type information can speed up things quite a lot, especially when you think about numbers. At the moment I have to pass numbers as structs with one f64 field, because an argument to a function in Javascript can be any available type. If the type is specified, the signature or return type can use f64 types directly and don't even do heap allocations. But even for heap allocated types it may result in better performance, cause at the moment for each object I have to check what type it is and what path to take in order to proceed.
Good luck! I’m interested in seeing how JS to WASM compilers can speed up edge rendering use cases. WASM opens the possibility of really cheap request isolation, far faster than process forking. But JS interpreters in WASM are currently so much slower that they still lose out performance wise overall.
The article spends a lot of time justifying a syntax that really just papers over Zig's lack of parameter pack support. The same pattern in Rust would just use variadic templates/generics.
reply