Search code examples
javascriptv8javascriptcore

Are bitwise left shifts in JavaScript ES6 (<<) cyclical above a shift of 63?


My understanding of the << bitwise left operator in JS (ES6) is that the void to the right is filled with zeros.

Empirically, however, I notice that in both V8 and JSC, the set bits seem to suddenly reappear if we shift by 64 or more.

(255 << 64).toString(2)
//-> "11111111" 

This is counter to my expectation, which was that larger shifts would indefinitely produce only zeros at right.

I don't immediately see this behaviour defined in the EcmaScript 2016 pages on << – am I missing something, or is the behaviour perhaps undefined for larger shifts ?


Solution

  • The specification (Section 12.8.3.1) specifies that the number of bits to shift is masked:

    ShiftExpression : ShiftExpression << AdditiveExpression

    1. Let lref be the result of evaluating ShiftExpression.
    2. Let lval be
    3. GetValue(lref).
    4. ReturnIfAbrupt(lval).
    5. Let rref be the result of evaluating AdditiveExpression.
    6. Let rval be GetValue(rref).
    7. ReturnIfAbrupt(rval).
    8. Let lnum be ToInt32(lval).
    9. ReturnIfAbrupt(lnum).
    10. Let rnum be ToUint32(rval).
    11. ReturnIfAbrupt(rnum).
    12. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
    13. Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.

    Since 64 & 0x1F is 0, it means "no shifting" and that is why the bits are "reappearing".

    tl;dr

    The number of bits to shift is capped at 31, i.e.

    function shiftLeft(number, numShift) {
        return number << (numShift % 32);  // equivalent code
    }