HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.05k stars 649 forks source link

Emscripten/ASM.js Style Type Hints #10179

Open indolering opened 3 years ago

indolering commented 3 years ago

Emscripten has a funky way of annotating JS that enables the JIT to skip dynamic type checking:

function increment(int) {
  int = int|0;
  return (int + 1)|0;
}

This style evolved organically in response to benchmarking and was later formalized into ASM.js and then WASM. There is a prior ticket proposing an ASM.js target, which was closed because ASM.js forbids the use of garbage collection. However, I'm not suggesting adopting the full ASM.js standard, just an option to add these type hints to the JS target's output.

The suggestion to add ASM.js type hints has been brought up before in another ticket, but didn't go anywhere because they weren't sure if there would be a speed boost. However, it should help: Chrome initially declined to add an ASM.js specific pass in part because their engine was already pretty good at leveraging the annotations directly (and I think they were busy building TurboFan). These types of annotations might also benefit other targets as well....

Aurel300 commented 3 years ago

In the long term, I would rather we support WASM output, although for that to happen, we either need to write a garbage collector for it or wait until a garbage collector becomes a part of WASM (if it ever does?). I got the feeling that ASM.js sort of went nowhere – are there any benchmarks showing that these type hints actually do cause a performance improvement?

These types of annotations might also benefit other targets as well....

Might they? It could only happen in dynamic targets, this | 0 things is a very hacky afterthought in JS specifically.

indolering commented 3 years ago

I would rather we support WASM output, although for that to happen, we either need to write a garbage collector for it or wait until a garbage collector becomes a part of WASM (if it ever does?).

WASM will add support for garbage collection eventually, but I actually wrote this ticket because I was thinking Cap'n Proto would be a good use case for Haxe. The benefit of a zero-copy protocol is lost when copying data over a FFI. So a zero-copy protocol will be one of the few instances where a transpilation would be better than using a FFI + binding generators.

I got the feeling that ASM.js sort of went nowhere

It was very successful. Emscripten and Mandreel converged on these performance optimizations independently. Initially, ASM.js just formalized it into a spec, but then it added a "use asm.js" pragma which further strengthens the contract. All the major browsers eventually added a dedicated pass to get the full benefit. Eventually, they reached the conclusion that some optimizations would be best handled via a dedicated bytecode format and WASM was born.

But none of that negates the performance benefits Emscripten got by adding these annotation in the first place.

– are there any benchmarks showing that these type hints actually do cause a performance improvement?

Not in isolation from a dedicated ASM.js pass, which we don't want. There were benchmarks at the time, but it's been so long that much of it has fallen off of Google. As I said earlier, Google initially declined to implement asm.js specific optimizations because their engine was already pretty good at picking up on Emscripten's type hints.

Might they? It could only happen in dynamic targets, this | 0 things is a very hacky afterthought in JS specifically.

I saw a mention of this in some Emscripten slide deck, but I might be misinterpreting it.

haxiomic commented 3 years ago

These annotations already happen in haxe, Int in haxe isn't explicitly defined as 32-bits so it would be incorrect to emit | 0 for those, however when you use the explicit haxe.Int32 type, you get the | 0 annotation in the appropriate places

For example: https://try.haxe.org/#01b25618

(I think there's nothing to do here so closing)

indolering commented 3 years ago

These annotations already happen in haxe, Int in haxe isn't explicitly defined as 32-bits so it would be incorrect to emit | 0 for those,

Based on random Googling, I think what you want is intish.

when you use the explicit haxe.Int32 type, you get the | 0 annotation in the appropriate places

There is more to ASM.js than just integer math, it supports ~11 value types and their typed collections. The standard library also has a large number of associated utility functions.

(I think there's nothing to do here so closing)

When I tried using Float, the output didn't have any of the annotations associated with ASM.js' Double or Float types.