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

Support asm.js compilation #570

Closed
gyzerok opened this issue Jun 26, 2015 · 16 comments
Closed

Support asm.js compilation #570

gyzerok opened this issue Jun 26, 2015 · 16 comments

Comments

@gyzerok
Copy link
Contributor

gyzerok commented Jun 26, 2015

Is it possible to compile Flow to asm.js? What do you think about this feature?

@Macil
Copy link
Contributor

Macil commented Jun 26, 2015

asm.js is a subset of Javascript that doesn't rely on things like garbage collection, so I don't think compiling the Flow superset of Javascript into it makes sense. (If javascript could be transformed to asm.js efficiently, then browsers that optimized asm.js would just do that, or not even bother making asm.js-specific optimizations.)

@karelbilek
Copy link
Contributor

I am not sure what @gyzerok meant; I think he meant actually the flow typechecker.

It could maybe be possible to compile OCaml itself from source to asm.js, and then somehow run flow on that, but I am not at all sure it would be worth all the trouble.

@Macil
Copy link
Contributor

Macil commented Jun 26, 2015

Oh, compiling the Flow checker itself makes more sense.

It could maybe be possible to compile OCaml itself from source to asm.js, and then somehow run flow on that,

I assume the purpose would be to make it so Flow could be run in pure javascript environments (in browsers, or so it can be installed via NPM without any native dependencies), not to make it so you could use Flow to check itself since it's already written in a typed language.

I'm not very familiar with it, but OCaml is a garbage-collected language, so I think regular javascript is a better compile-target for it than asm.js. It looks like there are already projects for compiling OCaml code to javascript. Flow would probably need some work to make it so it could be compiled to javascript. (I think I saw this mentioned as planned for eventually somewhere?)

@mroch
Copy link
Contributor

mroch commented Jun 27, 2015

the parser is compiled to JS via js_of_ocaml, see flow-parser on npm.

compiling the whole typechecker to JS via js_of_ocaml isn't possible because of a bunch of C dependencies, multi-process stuff, filesystem stuff, etc. i think it'd be pretty hard to break those dependencies out.

what would you use it for? the first thing that comes to mind for me is a faster (maybe? who knows...) version of tryflow.org

@6D65
Copy link

6D65 commented Oct 6, 2015

@mroch I think an installable Atom package that works on Mac, Windows and Linux without any dependencies other than JS would greatly help expand flow's reach. But then again dependencies on C libs doesn't make this very easy. I wonder if the C dependencies could be compiled to asm.js, and linked. Though, it looks like a pain.

@gyzerok
Copy link
Contributor Author

gyzerok commented Oct 6, 2015

I've meant JS code compilation. As I've understood every statically typed language can be compiled to asm.js

@vkurchatkin
Copy link
Contributor

Closing. Flow is a typechecker, it doesn't compile anything to anything.

@jslegers
Copy link

jslegers commented Jun 22, 2017

Personally, I don't see much of a benefit of using Flow or TypeScript instead of JavaScript. Especially now that the ES6 standard also added class-based object-oriented programming to the language, all you'd really get from adopting Flow or TypeScript today would be the addition of static typing... and interfaces. Besides making your code look more like eg. Java code, I really don't see the benefit at all... except when using static typing to optimize the JavaScript code it produces... which is where asm.js comes in.

In environments where high performance is essential (eg. 3D rendering in the browser for browser games or GIS web apps), the current approach is to write the core code (that does the heavy lifting) in C/C++ (compiled to asm.js) and everything else in JavaScript. That means you need a really good understanding of both JavaScript (which I do) and C/C++ (which I don't) to be able to write proper code or maintain existing code for such apps, both inside and outside of the the core code.

How great would it be to be able to use one - Flow - codebase for such projects and compile to asm where possible and to regular JavaScript where not possible? Or to put it differently : how great would it be for a JavaScript programmer to be able to program in highly readable superset of JavaScript and have it compiled - where possible - to a highly performance optimized subset of JavaScript?

It seems like a win-win for everyone, really, especially if you leave it optional whether or not to compile to asm.js for developers who don't work in high performance environments and prefer readability to performance.

IMO, compilation of (a subset of) Flow to asm.js would be major improvement over Flow as it exists today. For me, it would totally be a game changer and make the difference between supporting and not supporting the adoptation of Flow - or TypeScript for that matter - at the company I work for...

Anyway, I guess this issue is related to issue #248?

@vkurchatkin
Copy link
Contributor

What makes you think that compiling statically typed javascript to asm.js (or Webassembly) is going to be somehow faster?

@jslegers
Copy link

jslegers commented Jun 22, 2017

Asm.js is a very strict subset of JavaScript, that is optimized for machines rather than humans because it is much closer to machine code than ordinary JavaScript code. In browsers that implemented those optimizations, your code will typically run about 50% of the speed of a C/C++ program that is compiled to machine code.

That means it's fast. It's very fast, in fact, and there's no way to can get this kind of performance when writing "normal" JavaScript.

Now, if you want your browser to interpret certain code as asm.js code, you need to create a module wherein the following conditions apply :

  • all code is fully statically typed and limited to the very restrictive asm.js subset of JavaScript
  • your module starts with the "use asm" pragma

Additionally, an asm.js module allows only up to three optional yet very specific parameters :

  • a standard library object, providing access to a subset of the JavaScript standard libraries
  • a foreign function interface (FFI), providing access to custom external JavaScript functions
  • a heap buffer, providing a single ArrayBuffer to act as the asm.js heap

So, this is what a basic module looks like :

function DiagModule(stdlib, foreign, heap) {
    "use asm";

    // Variable Declarations
    var sqrt = stdlib.Math.sqrt;

    // Function Declarations
    function square(x) {
        x = +x;
        return +(x*x);
    }

    function diag(x, y) {
        x = +x;
        y = +y;
        return +sqrt(square(x) + square(y));
    }

    return { diag: diag };
}

The function parameters of your module allow asm.js to call into external JavaScript and to share its heap buffer with "normal" JavaScript. The exports object returned from the module allows external JavaScript to call into asm.js.

Leave out the "use asm", and your browser will not know that it should interpret your code as an asm.js module. It will treat your code as "ordinary" JavaScript. However, just using "use asm" is not enough for your code to be interpreted as asm.js. Fail to meet any of the other criteria mentioned hereabove, and your code will be also interpreted as "ordinary" JavaScript :

enter image description here

All this makes it very hard for humans to handcode asm.js, which is why basically no one does it beyond small bits of experimental code. Almost all - if not all - major asm.js codes are produced by compiling C/C++. However, any code that's sufficiently like C/C++ can in theory be parsed to C/C++, possibly by first passing through C/C++ as an intermediary step.

In an environment where I can use TypeScript or Flow to write code and any code that can be converted to asm.js is converted to asm.js, I would have the best of both worlds. I would have the readability that comes with human optimized JavaScript (or Flow & TypeScript) but the performance that comes with machine optimized asm.js. And because Flow and TypeScript are more similar to C/C++ - especially when using only static typing - than JavaScript, it makes more sense to compile them to asm.js than compiling ordinary JavaScript to asm.js.

@karelbilek
Copy link
Contributor

Doesn't Flow compile to javascript now? I haven't tried it but isn't flow.org/try/ done on client side with compiled JS?

@vkurchatkin
Copy link
Contributor

C/C++ code compiled to asm.js is fast, that is clear. "Typed javascript compiled to asm.js is fast" is pure conjecture.

@jslegers
Copy link

jslegers commented Jun 22, 2017

C/C++ code compiled to asm.js is fast, that is clear. "Typed javascript compiled to asm.js is fast" is pure conjecture.

From a performance perspective, I don't see why it matters whether asm.js code is created by compiling from C/C++, from Flow, from TypeScript, from LLJS or any from other typed language. What matters is the asm.js JavaScript code that is produced, not the way it is produced.

@jslegers
Copy link

jslegers commented Jun 22, 2017

Those also interested in converting staticly typed variations of JavaScript to asm.js, WebAssembly or C might want to take a look at ThinScript, TurboScript or AssemblyScript.

ThinScript compiles to JavaScript, WebAssembly, and C. TurboScript compiles only to JavaScript and WebAssembly. AssemblyScript compiles to WebAssembly only.

Each of these languages have been inspired by TypeScript, and the latter is a subset of TypeScript.

I'd like to thank @RReverser for pointing me in the direction of these languages.

@vkurchatkin
Copy link
Contributor

From a performance perspective, I don't see why it matters whether asm.js code is created by compiling from C/C++, from Flow, from TypeScript, from LLJS or any from other typed languag

Because a language being typed is not enough to compile it into a performant code ahead of time, among other things.

@jslegers
Copy link

jslegers commented Jun 22, 2017

Because a language being typed is not enough to compile it into a performant code ahead of time, among other things.

I'm not saying that ANY Flow or TypeScript code can be converted to asm.js or WebAssembly. However, there sure are significant subsets of those languages that can. Languages like TurboScript and AssemblyScript demonstrate that. In fact, it looks like TurboScript is heading exactly towards what I would have expected TypeScript or Flow to head towards.

Also, I'm not saying that ANY code that is executed in asm.js or WebAssembly is high performance code per se. In the end, a programming language is only as good as the programmer using it.

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

7 participants