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

Will there be a JS -> WASM compiler? #219

Closed
bguiz opened this issue Jun 23, 2015 · 94 comments
Closed

Will there be a JS -> WASM compiler? #219

bguiz opened this issue Jun 23, 2015 · 94 comments

Comments

@bguiz
Copy link

bguiz commented Jun 23, 2015

After scrutinizing the design docs, I was able to find a mention of a polyfill that would transpile WASM -> JS. I was also able to find mention of a C++ -> WASM compiler.

However, I was unable to find any mention of a JS -> WASM compiler.

The majority web developers are fluent in Javascript, and thus a JS -> WASM compiler would be ideal. Web developers will want to continue writing their websites using Javascript, instead of writing them using C++. Thus I am not sure what to make of the MVP, nor the post-MVP sections making no mention of a JS -> WASM compiler. What is happening here?

@creationix
Copy link

Browsers will still have native JavaScript VM along-side wasm. There is no reason to compile JS to wasm because you would have to also include a whole javascript vm. The resulting code would be huge and slower than the JS VM natively provided.

There is a task post MVP for adding things like adding access to the GC from wasm code so that scripting languages can be implemented for wasm.

@jfbastien
Copy link
Member

JS → wasm will only really make sense once wasm supports GC, and most likely JIT compilation too, which is still quite a while away. This would basically be equivalent to implementing the JS engine in wasm! I mentioned this recently and @BrendanEich accused me of having been taken over by horse_js.

To be clear, wasm's goal isn't to replace JavaScript, it's to supplement it. It's therefore not really a goal at the moment to support JS → wasm, but the features we want to implement will make it possible. I'm not sure it'll be that useful from a developer's perspective, though. You may get some size reduction, but that's about it. From a browser's perspective it may be interesting to have the JS engine implemented in wasm from a pure security perspective.

@creationix
Copy link

@jfbastien I beat you by 2 seconds ;)

But your answer is better. I'm excited for GC and JIT in wasm. I love creating my own languages and running them on the web.

@bguiz
Copy link
Author

bguiz commented Jun 23, 2015

And how about supporting variants such as asm.js or TypeScript/ES7? These
flavours of Javascript promise some level of type guarantees.

I'd imagine the need for JIT would be less so, but GC still very much
needed for these languages. Would having a {typed flavour JS} -> WASM make
this any more feasible?

W: http://bguiz.com

On 24 June 2015 at 09:44, Tim Caswell notifications@github.com wrote:

@jfbastien https://github.com/jfbastien you beat me by 2 seconds :P


Reply to this email directly or view it on GitHub
#219 (comment).

@titzer
Copy link

titzer commented Jun 24, 2015

Yes, an asm.js -> wasm translator is a high priority, and Luke already did
work on a compressor that might serve as a good starting point.

On Wed, Jun 24, 2015 at 1:59 AM, Brendan Graetz notifications@github.com
wrote:

And how about supporting variants such as asm.js or TypeScript/ES7? These
flavours of Javascript promise some level of type guarantees.

I'd imagine the need for JIT would be less so, but GC still very much
needed for these languages. Would having a {typed flavour JS} -> WASM make
this any more feasible?

W: http://bguiz.com

On 24 June 2015 at 09:44, Tim Caswell notifications@github.com wrote:

@jfbastien https://github.com/jfbastien you beat me by 2 seconds :P


Reply to this email directly or view it on GitHub
<#219 (comment)
.


Reply to this email directly or view it on GitHub
#219 (comment).

@MikeHolman
Copy link
Member

We have spoken with the TypeScript team about this possibility and they have shown interest, but it seems like progress there is currently gated on adding typed objects into JS.

@BrendanEich
Copy link

@bguiz: JS engine is the wasm engine, and it will continue to support the evolving JS standard language. No worries there (I wasn't sure whether you thought that might go away. Not in any future that I can foresee). OTOH as others note, wasm needs time to evolve GC, JIT support, and other dynamic language features, to be a first-class target for JS. Even when it does evolve these things, I have doubts that JS/wasm engines will drop their JS syntax and built-ins in favor of downloaded JS-in-wasm VMs. We shall see!

/be

@sunfishcode
Copy link
Member

An asm.js-to-WebAssembly translator will also be something we're planning to add to Emscripten.

As for regular JS, I think others have answered the question above.

@alexino2
Copy link

The whole point of JS is easy to code and can do amazing things : dhteumeuleu or codepen.io/ge1doot, but you can see the source and it's easy to hack.

"wasm" is only a way to sell more game and others apps for google, apple an co. The only "evolution" is that there'll be able to control you better with "no install", directly from the big brother server... I'm just surprised they are not afraid of eating each other yet...

@gregtour
Copy link

It's possible with code analysis or code annotations to compile ECMAScript to WebAssembly. This doesn't sound like a priority for the WebAssembly team but it does sound like a great idea for an independent effort.

@evanw
Copy link

evanw commented Mar 27, 2016

I just started experimenting with a toy programming language that might be relevant: https://github.com/evanw/thinscript. It uses TypeScript-style syntax and compiles to WebAssembly. I figured I should mention it because it might be an interesting case study. Also I was pleasantly surprised by how easy WebAssembly was to generate. Nice work everyone!

@sunfishcode
Copy link
Member

I would caution people about using very thin wrappers on top of wasm though, in general. As one example, thumbing through the thinscript code, I see there's a while statement which is lowered to loop { if (!condition) break; }, which will be less efficient than if (condition) loop { ...; br_if condition } on several wasm engines.

To me, the thing that makes wasm more than just a reheated JS is the possibility of a different philosophy: because wasm is a compiler target, compilers can perform optimizations before shipping the code to clients, so we can keep client-side VMs simpler and faster. However, if thin wrappers around wasm become popular, there's a risk that client-side implementations will eventually have to grow bulkier and more complex in order to do the optimizations that aren't being done.

@evanw
Copy link

evanw commented Mar 27, 2016

Yes I agree. One of the things I like most about WebAssembly is its simplicity. I'm planning on adding compiler optimizations and doing benchmarks once the language is more complete. I expect inlining to be one of the bigger wins, for example, and I wouldn't expect WebAssembly to do that for me. I'm also planning on experimenting with a machine code target and I will be using the same optimizations for both targets.

@sunfishcode
Copy link
Member

Sounds very cool! I'll be interested to see where it leads.

@affixalex
Copy link

I'm imagining JS->WASM being more appealing for servers than clients. As a very high-level overview of the architecture that I have in mind...

JavaScript -> WebAssembly -> Tracing Interpreter -> LLVM IR -> Machine Code

In this conception, a clear mapping from WASM to LLVM IR for garbage collection would be very desirable. Promotion from IEEE doubles to integers could be done as an LLVM pass. The notion of separate JITs for warm and hot code could be implemented in terms of LLVM pass managers.

Just some thoughts, please feel free to delete this if it's spurious!

@AlicanC
Copy link

AlicanC commented Oct 13, 2016

Cross environment compatibility is a serious problem in JS ecosystem. Babel tries solves this problem by transpiling down to some more adopted version of ES and I guess we can all say that it is pretty successful.

There is still an issue here though. For example, if you are transpiling your ES 2016 code down to ES5 for compatibility and your code happens to run on an environment with (partial or complete) ES 2016 support, you will be missing out the benefits of having ES 2016 support in your environment.

If everyone is transpiling their code down to ES5, then what is the benefit of having ES 2016 support in an environment in the first place?

A new project called "babel-preset-env" tries to fight this issue by targeting environments by their versions. The idea behind it is that (1) you ask it to target specific versions or "latest X versions" of browsers, (2) it determines the lowest common denominator of features and (3) enables only necessary transpilations. This helps, but sadly can't solve the issue.

We still have the risk of a major vendor not behaving and causing the same issues Microsoft was causing with Internet Explorer for years. The whole ecosystem is in hands of a few vendors, who decide what to implement and when to implement. This is not free nor open.

The only solution is a new compile target for JavaScript which is performant and needs a lot less maintenance (hopefully none) than a JS engine. When environments (browsers, Node.js, etc.) starts supporting such a target, implementing new ES features should become the responsibility of compilers and not engine vendors.

@Simran-B
Copy link

JS -> WASM would be interesting to protect intellectual property by code obfuscation when it comes to on-premise installations of let's say Electron apps on customer servers. It's hard to believe but true, there are many small institutions in Germany with very little or no internet connection, which requires on-premise installations, but giving your entire code in plaintext to them can be scary for software companies.

@ghost
Copy link

ghost commented Oct 20, 2016

@Simran-B Wasm has as a design principle to support a familiar text format. Notably it has a structured control flow design for quick analysis, and is optimized for single use definitions used in stack order so optimized for readable expressions. Thus it is not a 'code obfuscation' target, but developers can emit their own 'code obfuscation' on top of this but should understand that this is expected to have a cost in terms of decreased encoding efficiency and decreased performance.

@Richard87
Copy link

Richard87 commented Nov 13, 2016

Hi all, I just resently discovered WebAssembly, but thinking about the JS -> wasm compiler, I imagined something like Angular2's Ahead-of-Time compilation, jsut way more optimized (I'm thinking machinecode instead of javascript)... Will this ever be possible? Is it worth it?

EDIT
I'm also thinking, is will there ever be a possibility for the browser to send a flag to the client that it supports wasm, and then we can serve up a precompiled app instead of a javascript file?

Richard

@distransient
Copy link

@Richard87 you could think of webassembly as a platform independent instruction set with its own specialized encoding and calling conventions. There's nothing saying you can't describe a subset of javascript that'd be very easy to transpile to work in webassembly's world of those things, but enforcing that would probably be difficult. The featureset and implementation surface area are forever growing in javascript, and adapting existing libraries and frameworks to work in that subset would likely be difficult, especially given the current lack of garbage collection in webassembly, and you'd essentially lose the benefits of existing javascript code.

With the addition of garbage collection primitives in webassembly, the subset of javascript that would be feasible to transpile without writing a big ol' virtual machine would widen, but it still in my opinion wouldn't be optimal compared to just transpiling from a more suitable language, since your overheads in javascript would only be marginally smaller, the important overheads in web applications (the network!) would widen, and the benefits you'd want to reap from using javascript in the first place would still be out of reach, besides getting to say that it uses something that resembles "javascript" (this is actually a similar boat that Unity is in with UnityScript, except they adapted it somewhat to integrate better with their subsystems and calling conventions in general, besides other whims).

@metacritical
Copy link

I think it is extremely important for some of us who are looking at Browser and Webgl to be faster for gaming. I intent to bring a commercial quality game in webgl but the current tech produces so much garbage that frames skip.
Browser gaming using JS game engines has almost failed and Unity took off. I think C++ => Wasm is an undue advantage for these big Unity like framework makers who could cross compile their code to WASM.
But what about people who write JS by hand using Three JS or Babylon.. Not having a JS/Asm.js => Wasm toolchain would mean large application in Js would be dead and people would use C++ and code generation backends to produce Wasm. More specifically in games and such.
Not having a JS => Wasm backend in unfair to JS Developers. Also EMCC allocates a Big heap when it runs and speeds are evident due to that, but Js Developers who write good js Code still couldnt achieve so much performance due to the complexity of writing such code. There should be some mechanism to reuse most stuff and ability to call gc earlier or at will. Frame skipping when the GC runs causes Webgl to skip frames is a big problem and needs to be resolved. There should be some mechanism to hand tune JS code better than Code generators. like hand written Assembly still produces much smaller and highly aligned code. That should be possible in web-assembly.

@RyanLamansky
Copy link

@metacritical C++ can compile to WASM because many people put a lot of work into the process. The same could happen for JavaScript, but as far as I know, no one is attempting this currently. There is little reason to do so: performance will be unchanged.

Your engine's problem is garbage collection. This problem doesn't go away if you build a garbage collection algorithm that uses linear memory and WASM code... eventually you have to stop the program to see which objects are still alive and delete the ones that are not. The solution is to not create garbage objects, preventing the need for the GC to ever run. You don't need WASM to achieve this, you need to rework your engine.

@metacritical
Copy link

metacritical commented Jan 28, 2017

Ultra pristine Javascript that reuse Arrays and produce low garbage are extremely hard to write. Also i think Plain Js cannot be compiled to WASM. Asm.js or Typescript would be easier to compile to WASM due to availability of type annotations or types in them respectively.

@RyanLamansky
Copy link

@metacritical Difficult, but not impossible. Even in the C++ engines, much of the code is around object lifetime management. Although unconventional, there's no reason you can't do the same in JavaScript.

Plain JS could be compiled to WASM but the compiler would have to add a lot of helper code to enable JavaScript's higher-level features like garbage collection, reflection, properties, and so on. Basically, all the stuff you get for free with the browser's built-in JS engine. TypeScript doesn't help much.

By comparison, ASM.JS would be easy to convert to WASM. The strict subset of JS features allowed by ASM.JS is also 100% covered by WASM. If there were a large volume of code written in ASM.JS, this would be a worthwhile effort, but as far as I know all the major ASM.JS files are produced from C++ source code, which can already directly target WASM.

@kripken
Copy link
Member

kripken commented Jan 28, 2017

By comparison, ASM.JS would be easy to convert to WASM.

Correct, and actually the main way we compile C++ to wasm today is to compile it to asm.js first, then compile that asm.js to wasm using Binaryen's asm2wasm.

@metacritical
Copy link

@kripken Looking at the asm.js specs it seems easy to write handwritten asm.js, which means all is not lost for js programmers, we can still get WASM binaries using the above.

@aruns07
Copy link

aruns07 commented Jan 31, 2017

Wouldn't evolution of JS i.e. strictly typed language, could make it a good candidate for JS -> WASM?
I think TC39 has proposal for typed object. May be more other features could make it possible.

@RyanLamansky
Copy link

@aruns07 The fewer JavaScript features you allow people to use, the easier it would be to compile to WASM, and the more likely people will be unwilling to live with your restrictions due to incompatibility with their favorite libraries.

@metacritical
Copy link

@Kardax @aruns07 People love the convenience of a Dynamic Language. We need strong types occasionally not all the time.

@Steakeye
Copy link

https://github.com/ballercat/walt

@BossLevel
Copy link

BossLevel commented Dec 16, 2017

@Steakeye Very nice :) I shall have a play - many thanks for highlighting :)

@2beers
Copy link

2beers commented Jan 17, 2018

you can compile JS to WebAssembly using NectarJS . Demo: http://nectar-lang.com/ choose from the dropdown WebAssembly

@kripken
Copy link
Member

kripken commented Jan 17, 2018

Interesting, the NectarJS demo uses emscripten, you can see that in the asm.js output. It appears it statically compiles JS into something - likely C or LLVM IR - and then runs that through emscripten.

The wasm output also uses emscripten (can be seen from inspecting the binary), but it seems to use an old version as it emits 0xd wasm binaries, which don't run in modern VMs. It also just sends you the wasm, not the JS, so it's not runnable anyhow. In any case, it's very possible it's just doing the same as for asm.js, just running emscripten with the flag for wasm output flipped on.

The demo has a 300 byte limit on the input, so it's hard to feed it a real-world program to get a feel for how powerful their analysis is, which is the real question with a static approach like this. In general, academic research on this topic suggests skepticism.

@Simran-B
Copy link

Their compiled demos for Windows simply crash for me 🤕

@alexp-sssup
Copy link

I agree with @kripken skepticism here. I believe arbitrary JS cannot be reasonably converted to WebAssembly. Any tool that claims to achieve this is probably working on some tractable subset of the JS language, or giving up execution performance.

JS is an extremely dynamic language. Unpredictable run-time operations can significantly and globally change the semantics of code. This means that an Ahead-Of-Time (or offline) compiler can only assume the worse and generate very inefficient generic code that can handle all the possible cases. For an example take the following JS code:

var a = {prop1: 1};
func(a);

could be converted (in pseudo-wasm) to this

i32.const 42
call $CreateJSValFromStrTable ;; Returns prop1
i32.const 1
call $CreateJSValFromInt
call $CreateJSObj1 ;; Consume a JS string and a JS value to make an object
call $_func

Now, this is a far call from what we can reasonably consider "compile" and it is more similar to unrolling an interpreter. It is of course also possible to run a JS interpreter compiled to Wasm, but that would hardly be a performance win.

JS engines such as V8 and Spidermonkey can run JS code as fast as they do by compiling it Just-In-Time. By doing JIT compilation they can observe what is the real intended semantics for a given piece of JS and generate fast code for that specific case, while of course being careful to detect any change in the environment that could invalidate the current assumptions.

@Simran-B
Copy link

Agreed. I wouldn't mind to use a JavaScript subset however. Or maybe a typed variant, which would probably reduce the dynamism and allow for more efficient code to be generated.

Are there any news on the "strong mode" front BTW?

@rossberg
Copy link
Member

rossberg commented Jan 18, 2018

@Simran-B, we have long abandoned strong mode, for the reasons summarised here. The takeaway is that it is pretty much impossible to tighten JavaScript semantics without losing interop with existing code.

For the same reason I also don't have much hope for the idea of designing a "statically compilable" dialect of JavaScript or TypeScript -- it would be a different language that can't run existing code, so not much point.

@kripken
Copy link
Member

kripken commented Jan 18, 2018

@Simran-B : "I wouldn't mind to use a JavaScript subset however. Or maybe a typed variant"

There is some very interesting work in that space, like AssemblyScript which is a strict subset of TypeScript that compiles to WebAssembly, https://github.com/AssemblyScript/assemblyscript

@rossberg : "I also don't have much hope for the idea of designing a "statically compilable" dialect of JavaScript or TypeScript -- it would be a different language that can't run existing code, so not much point."

I think the big potential with things like AssemblyScript is not about running existing code (I agree with you there, that won't be feasible in general), but that having a friendly and familiar language is a huge deal.

Right now if you are a TypeScript developer and you want to write WebAssembly then you need to use C++ or Rust. Both are good languages but also have downsides. For someone with that background, something like AssemblyScript could be the fastest path to productivity.

@SephReed
Copy link

If AssemblyScript can compile to both JavaScript and Assembly, that would be pretty ideal. Looking forward to these updates.

Also, in the future, unless someone does it first, I'll probably try writing a TypeScript -> Assembly Script converter that goes through the files, asks the questions it needs to ask, and then makes the conversion. Hopefully it works out!

@Pauan
Copy link

Pauan commented Jan 22, 2018

@SephReed Yes it can compile to JavaScript, because there is a WebAssembly -> asm.js compiler, which should work with all WebAssembly code.

See also the "Can WebAssembly be polyfilled?" section of the FAQ.

If you instead meant "is it possible for AssemblyScript to compile to idiomatic JavaScript code?", then I have to ask, why would you want to do that when WebAssembly / asm.js are so much faster than idiomatic JavaScript code?

Though I suppose you should be able to run the AssemblyScript code through the TypeScript compiler. However you will need to keep certain things in mind.

See also this section of the AssemblyScript documentation.

@qm3ster
Copy link

qm3ster commented Mar 1, 2018

Gentlemen, please consider WALT, the JavaScript-like WebAssembly language.

@jerrygreen
Copy link

jerrygreen commented Nov 28, 2019

UPD. Sorry for necroposting

I see a lot of people consider this "JS -> WASM" compiler a good idea.

For those who don't find it useful, like:

I'm not sure it'll be that useful from a developer's perspective, though. You may get some size reduction, but that's about it. From a browser's perspective it may be interesting to have the JS engine implemented in wasm from a pure security perspective.

Please, here's my concrete example of why it's important, and why it's useful, and not just you "get some size reduction, but that's about it". One of the features come with WebAssembly is:

<=XXX «SaNdBoXeD EnViRoNmEnT» XXX=>

WebAssembly isn't just about performance. You may see a good article about plugins from Figma team.

Making a plugin system is quite challenging. You need some good way to run custom code. You need a separate environment, a safe one.

WebAssembly gives you that, - a pure environment without mess like some global variables. AssemblyScript makes it convenient in a way, - you have almost the same TypeScript environment, as your main app's environment, which is quite cool.

But here's the problem, "almost same":

Can I use JS packages from NPM within my safe environment?

No.

Well, this WALT project is some kind of AssemblyScript alternative. It's barely JS-like, - it's typed js. It's more like TS-like. You can't compile/transpile existing js libraries with that.

Can I use TS packages from NPM within my safe environment?

No.

AssemblyScript is TS-like language too. It may compile something written in TS if it's fully covered with types. No exceptions. No any any's. But often people have their configs not strict enough or they have a few @ts-ignore, or even more often, - they write package in js and provide separate types in .d.ts files - in all these cases you won't be able to compile such a package to WASM.

@asilvas
Copy link

asilvas commented Nov 28, 2019

@jerrygreen good points, but on the performance side of things, I actually believe it's a huge misconception that there aren't significant performance benefits beyond saving a few bytes. Folks, including benchmarks, are so obsessed with runtime performance. See how fast it runs 3D games?

Yet the real-world opportunity is actually in startup performance, which benefits virtually all websites. Few seem to talk about how WebAssembly is substantially faster in startup time (per byte), far beyond any runtime benefits. This is why for instance gzip on textual content, such as JavaScript, has little real-world impact on PLT -- it's the size of the compiled code that matters.

Ironically, the industry is obsessed about PLT (Page Load Times), and various visual complete markers, yet no one sees the correlation between WebAssembly and these vectors? JavaScript is responsible for over 30% time spent prior to these critical events, on most websites. In fact, size of pages and bandwidth have far less impact on PLT's compared to that of linear performance factors, namely JavaScript startup times and latency.

With that said, it isn't clear to me the feasibility of JS -> WebAssembly.

@MaxGraey
Copy link

MaxGraey commented Nov 28, 2019

@jerrygreen Figma's approach is very specific case and I guess for most of projects iframes or realms are pretty enough for third-party javascript isolation. For special cases where isolation should be more controlled and performance, size and load time are not so important, you could always compile QuickJS or JavaScriptCore to WebAssembly.

@j-f1
Copy link

j-f1 commented Nov 28, 2019

You could also use Web Workers, and run code before your untrusted code that deletes any APIs you don’t want the untrusted code to have access to. No need for WASM in this case @jerrygreen!

@metacritical
Copy link

Framerate Drops in Three js in a real thing, I am not sure if wasm could help but it sure seems so at least on the surface.

@chpio
Copy link

chpio commented Dec 6, 2019

There is no reason to compile JS to wasm because you would have to also include a whole javascript vm. The resulting code would be huge and slower than the JS VM natively provided.

Couldn't we do all the monomorphisation etc that are done by JS VMs through Profile-Guided Optimization? We would pretty much just do the same thing as the JS VMs do at runtime, but ahead-of-time.

A PGO build consists of two passes: a first pass to build instrumented binaries, then a second pass to re-build optimized binaries using profile information gleaned from running the instrumented binaries.

The first run would provide us with all the type info (which functions get called with which typed-arguments etc), then we build an optimized binary with all variants a function is called with (+ generic one with dynamic args for non profiled code). We wouldn't need the whole JS VM.

@MaxGraey
Copy link

MaxGraey commented Dec 6, 2019

PGO required great test's coverage of your program. It's not always possible. But you could trace some type information during execution in v8. See this doc: https://docs.google.com/document/d/1JY7pUCAk8gegyi6UkIdln6j_AeJqQucZg92advaMJY4/edit#heading=h.xgjl2srtytjt

@Nashorn
Copy link

Nashorn commented Mar 15, 2020

We have spoken with the TypeScript team about this possibility and they have shown interest, but it seems like progress there is currently gated on adding typed objects into JS.

Don't need types

@Zireael07
Copy link

Can QuickJS really be compiled to WASM?

@MaxGraey
Copy link

Yes, Figma use QuickJS for their plugin system for example

@binji
Copy link
Member

binji commented Apr 17, 2020

And it's used in http://numcalc.com/ too.

@HarikrishnanBalagopal
Copy link

Anyone familiar with this project that compiles SpiderMonkey to WASM?
https://github.com/bytecodealliance/spidermonkey-wasm-rs
https://wapm.io/mozilla/spidermonkey

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