4 ms·
Aren't most JS engines able to do this optimization regardless of |0, especially during JIT? The rationale behind the |0 trick in asm.js was the lack of an inte
by qsort 4y ago
Aren't most JS engines able to do this optimization regardless of |0, especially during JIT? The rationale behind the |0 trick in asm.js was the lack of an integer type in pure js, and thus the need to avoid precision errors (which can't happen if you limit yourself to 32 bits since IEEE double-precision floats have 53 bits of mantissa).
This sounds a bit unnecessary given the capabilities of modern engines. I benchmarked some additions on my machine on nodejs and there is no difference between the naive and |0 implementations.
- chrisseaton 4y ago> Aren't most JS engines able to do this optimization regardless of |0 Yes - if you are taking 'after every math operation' literally. JavaScript engines (and other dynamic language engines - nothing special about JavaScript) track types at a finger-grained level than simple generic 'number' or not. They already know if a number is a guaranteed integer, and even in some cases which bits can be set in that number. Sometimes the compiler doesn't want to prove more advanced properties like range when for example a value escapes, due to the overhead of tracking this, and then it's useful to do the trick in this article. Here's a worked example in a Ruby compiler for example https://chrisseaton.com/truffleruby/stamping-out-overflow-checks/ https://chrisseaton.com/truffleruby/stamping-out-overflow-ch.... But the author knows infinitely more than me about JavaScript compilation - they're ex-Google and Meta, including working on both Chromium and WebKit. They could show their working by for example showing some compiler IR for the engines they know about.
- modeless 4y agoAuthor here. I did work on Chromium but not on V8. There are definitely people here in this comments section who know a lot more than me about these topics! It's true that JS engines already optimize code to use integer math extensively, without |0 annotations. There are situations where this is made difficult or impossible due to requirements of the language, and |0 can help in these situations. There's a whole lot more to know about this topic for sure. My article would be a lot better with some examples where |0 gives a benefit and the corresponding IR. This post already took a lot more time to put together than I expected, and I didn't know if that many people would read it. Now that it hit HN, maybe I can justify the extra work.
- hn_throwaway_99 4y agoI think a critical point to is that |0 forces integer arithmetic, beyond just ensuring that integer arithmetic is used to do the calculation. E.g. (1/2) |0 gives a very different result than (1/2), so using |0 ensures that integer arithmetic is used even if you don't know what the operands are.
- qsort 4y agoI mean, no, not really, unless you're appending |0 to everything like a compiler would, i.e. ((a|0) / (b|0))|0. I'm not saying it's useless, asm.js used this trick to great effect. I'm just saying that unless the situation is more complex and doing a bitwise operation actually encodes information (like the &0xff example in a sibling comment, from which the compiler can deduce "this is a uint8"), it's unlikely you're giving the compiler more information than it's already capable of deducing on its own.
- Asraelite 4y ago> unless you're appending |0 to everything like a compiler would, i.e. ((a|0) / (b|0))|0. It effectively does do that though, since earlier in your code `a` and `b` would be defined with `let a = ... |0` so now `a` and `a|0` are equivalent in any subsequent expressions.
- chrisseaton 4y agoYes - local variables are just indirections through a name - in a compiler referring to a and referring to the original ... |0 expression are the same thing. https://twitter.com/ChrisGSeaton/status/1530579735012593665 https://twitter.com/ChrisGSeaton/status/1530579735012593665
- deleted 4y ago[deleted]
- hajile 4y agoThe compiler has to prove that it can use 31-bit integers. By forcing your number into a 31-bit integer, you provide definite type info to work with.
- pizlonator 4y agoNot necessarily. JSC has 32 bit integer fast paths. So it depends on the engine.
- deleted 4y ago[deleted]
- pizlonator 4y agoYes.
- StillBored 4y agoI mean this is covered in the article, right? Its possible until you do division or some other operation where the value needs to be promoted for language correctness. At that point the programmer must constrain the result to assure it stays in an integer. In theory I guess one could be more selective about the |0 and apply it only after operations where the hint is needed.