Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile to WebAssembly #1177

Closed
puffnfresh opened this issue Jun 17, 2015 · 20 comments
Closed

Compile to WebAssembly #1177

puffnfresh opened this issue Jun 17, 2015 · 20 comments
Milestone

Comments

@puffnfresh
Copy link
Contributor

https://brendaneich.com/2015/06/from-asm-js-to-webassembly/

Are there any benefits to doing so?

I guess we'd need this first:

https://github.com/WebAssembly/design/blob/master/FutureFeatures.md#gcdom-integration

@ghost
Copy link

ghost commented Jun 17, 2015

I'm not familiar with WebAssembly yet but if it's similar enough to asm.js then I suspect purescript won't benefit from it much without significant changes to the compilation model and FFI. From my experiments trying to use asm.jswith purescript, there is often worse performance apparently due to way the VMs handle the transition between the asm.js and non-asm.js code.

@ghost
Copy link

ghost commented Jun 17, 2015

Another possibility here though would be to compile to asm.js via emscripten from the output of the C++ backend. I think that approach definitely could yield some significant performance improvements for certain types of code.

@robotlolita
Copy link

I don't think there's much of a benefit until WebAssembly adds at least PTC and better tooling(?). WebAssembly is targeting C/C++ today, and they're still iterating over the design. Should be interesting to consider it in the future though, as they're planning to diverge from JS's semantics in order to be a better compilation target for languages that aren't close to JS semantically (though PureScript kinda is).

As an additional note, compiling to WebAssembly would allow PS to control the memory layout, flow layout and allocations. This is good because we can get rid of a lot of overhead (intermediate data structures, native closure invocation, unnecessary wrapping, branching instead of jumping), but it's also quite a bit more of work. They'll also allow you to define how to deal with exceptions (so your language has access to the stack unwinding and introspection stuff), which should be cool if PS ever plans to provide its own tooling in the browser.

And I'm not sure the FFI between this language and JS is clearly defined yet. At least you can't share objects from WebAssembly directly with JS right now. And in the future, I'm not sure how that would work, so that's something to consider as well.

@paf31 paf31 added this to the Ideas milestone Jun 20, 2015
@pierrebeaucamp
Copy link

I don't think Web Assembly will be ready to use anytime soon. At least not until they implement some sort of garbage collection, which will only be worked on after the MVP is done (see design/GC.md).

However, I think integrating asm.js is an interesting option. @freebroccolo, I haven't run any tests myself, but don't know why a VM would need to switch from asm.js to non-asm.js code.

I'm thinking of implementing only some of the asm.js features, like the bit operations on integers for example. So purescript doesn't need to be 100% asm.js compliant, but would benefit from the increased performance nevertheless.

@ghost
Copy link

ghost commented Dec 15, 2015

@pierrebeaucamp it's been awhile since I messed with it so I don't fully recall the details but I believe it has to do with the way the asm.js heap gets handled, i.e., when you enter a section of code that makes use of asm.js there is some setup and cleanup that needs to happen to play nicely with the rest of javascript. If this happens in a loop or every time you call an inexpensive function, it kills your performance and you end up worse off than if you had just not bothered in the first place.

So in order to get some actual benefit, you need to structure your code so that you have tasks that run long enough to outweigh the initial penalty or you need to have a compilation strategy that runs everything in asm.js to begin with.

Bit twiddling was one of the things I was actually interested in doing in asm.js with purescript (for a "native" bignum lib) but performance was bad (or at least not better) for the above reasons. I was able to get some benefit by writing larger chunks of code in the FFI but at that point there wasn't really a reason to use purescript anymore. Even writing pure javascript with hand-rolled asm.js was no match for emscripten compiled javascript though (and Odinmonkey showed the biggest performance increase at that point IIRC).

It's possible the situation has improved depending on what has happened with VMs in the meantime so it might be worth another shot but I wouldn't expect much.

@pierrebeaucamp
Copy link

Hm, wouldn't this be related to the asm validation? I.e. if you don't validate / flag the code as asm, the VM would just interpret it as normal code...

@ghost
Copy link

ghost commented Dec 16, 2015

@pierrebeaucamp well, sort of. You can write asm conformant code and it shouldn't cause any real problems anywhere. It may even be slightly faster. However, if you do actually get the VM to recognize and execute it as asm, there is some overhead in switching into asm mode. There was a blog post describing this by one of the mozilla people awhile back but I don't remember where anymore. In any case, the post described why asm.js wasn't always faster or was only barely faster in some cases and it basically had to do with this. Things may have changed since then though so maybe someone should do some tests.

I suspect it's still the case that calling individual inexpensive functions written in asm style from purescript via the FFI will probably not make much difference if the VM even executes it in asm mode. You'd need to write a longer running piece of code in a loop or something to really see anything. This is fine if you're writing a renderer or doing some sort of numerical stuff but not very useful if you just want to write a library, which is why I doubt purescript can see much benefit from asm.js in its current form.

Now, if an entire purescript program with all the dependencies were compiled to specialized asm style code then I think there would very likely be some non-trivial performance gains for certain kinds of code. But I think probably the best way to do that would still be via emscripten, so that means we'd either need an LLVM backend or we would need to compile to the C++ backend first.

But anyway this is just speculation based on what I observed before.

@andyarvanitis
Copy link
Contributor

@freebroccolo Let me know if you'd like to try out something with one of the C++ backends. Pure14 is faster, but doesn't support rank-N types and is less tested (and behind). Pure11 should support everything, but its use of a custom variant type has a performance cost (no benchmarks yet).

@pierrebeaucamp
Copy link

@freebroccolo So I've done some reading and it turns out that use asm triggers ahead of time compilation of the code. If you omit that line, it runs in the regular JIT VM.

So probably there will be only a small performance benefit (and, therefore, it's not really worth optimizing for).

@0joshuaolson1
Copy link

Came here hoping Purescript would be the first language outside Emscripten to use asm.js. Left hoping one day asm.js doesn't suck as a compile target period.

@paf31
Copy link
Contributor

paf31 commented Sep 25, 2016

Closing, since this should ideally be implemented using the output of --dump-corefn now. In any case, I don't think this would be implemented in the main compiler.

@paf31 paf31 closed this as completed Sep 25, 2016
@rosenk
Copy link

rosenk commented Jun 2, 2017

What is the status of this? Are we tracking this issue somewhere else?

@garyb
Copy link
Member

garyb commented Jun 2, 2017

Nobody is working on it that I'm aware of - it's not being tracked in this repo as it's not going to be implemented in the main compiler in the foreseeable future. Maybe one day 😄

@metasansana
Copy link

Says here WASM aims to target mobile, IoT and 'non-browser embeddings'. I think purescript could benefit a lot from that in terms of portability.

All major browsers now support the format so unless the API design or implementations are horrible, at some point people are going to be shipping WASM code instead of JS. There might be an opportunity to greatly influence the future of Web app development here.

@kritzcreek
Copy link
Member

WASM will not be a viable compilation target until it gets a story for garbage collection.

@Pauan
Copy link

Pauan commented Dec 26, 2017

@kritzcreek Although I agree with you, I want to point out that it is possible to compile a garbage collector to WebAssembly and then use it. That's what many garbage collected languages do right now. The problem is with JavaScript interop, not with the garbage collector per se.

@kentuckyfriedtakahe
Copy link

Experimental gc object support is available in Firefox Nightly behind the javascript.options.wasm_gc flag in about:config. Set https://blog.benj.me/2018/07/04/mozilla-2018-faster-calls-and-anyref/ for more details.

@thewoolleyman
Copy link

Relevant thread: WebAssembly/gc#36

@flip111
Copy link

flip111 commented May 10, 2019

Roadmap for GC: WebAssembly/gc#44

@Pauan what's exactly the problem with JS interop that is stopping from shipping a simple GC? Other languages like Idris also have wasm binding with GC ... i'm not sure how they solve it. But it's just strange that for purescript it's blocking and others just go ahead with it ...

@Pauan
Copy link

Pauan commented May 10, 2019

@flip111 One issue is that the PureScript GC would need to carefully interact with the JavaScript GC in order to avoid memory leaks (e.g. circular references between PureScript and JS).

The PureScript compiler would also have to do some heroics to transform the CommonJS modules into something which can be imported and used by Wasm. This is possible, but it's definitely very tricky!

To give an example of the sort of stuff PureScript would have to do: Wasm does not support JS objects at all, it only supports integers. So in order to communicate between PureScript and JS, everything must be converted into an integer.

The way to do that is to create a heap in JS, and put JS objects into that heap. The index in the heap is the "pointer" to the object. Then JS sends that index to Wasm, and Wasm can use it (since it's just an integer).

Then whenever Wasm wants to do something to the object, it has to send the index back to JS, JS then looks up the index in the heap, does the operation, and then sends the result back to Wasm.

And when Wasm is done using the object, it has to send a message to JS telling JS to remove the object from the heap (so that way it doesn't cause a memory leak). This is complicated by the fact that PureScript would need its own GC to keep track of these pointers.

All of this extra work means that interop between Wasm and JS is multiple orders of magnitude slower than just using JS directly. Which means that Wasm is best in situations where it doesn't need to communicate with JS, and can do everything purely in Wasm.

Wasm will soon have anyref, which avoids the need for a JS heap, but that doesn't really help much, since you now need to deal with Wasm tables instead (which are basically a heap).

I've worked on Rust + JS integration, so I have a good idea of how all this fits together. It's not that difficult, but it's very different from what PureScript currently does, so it would likely require major changes to the FFI system (or heroics on the part of the PureScript compiler). And it would require major changes to the PureScript compiler.

And since PureScript has so much communication with JS, it's likely that a Wasm version of PureScript would actually be slower (and would have dramatically larger file sizes) compared to the JS version of PureScript.

PureScript was designed around JS, so trying to move to Wasm is very complicated, and likely won't give any benefits (compared to the downsides).

This is different from Idris, which was designed to be run natively (and so they have their own GC already), and their FFI with JS is very different from PureScript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests