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 ?
The specification (Section 12.8.3.1) specifies that the number of bits to shift is masked:
ShiftExpression : ShiftExpression << AdditiveExpression
- Let lref be the result of evaluating ShiftExpression.
- Let lval be
- GetValue(lref).
- ReturnIfAbrupt(lval).
- Let rref be the result of evaluating AdditiveExpression.
- Let rval be GetValue(rref).
- ReturnIfAbrupt(rval).
- Let lnum be ToInt32(lval).
- ReturnIfAbrupt(lnum).
- Let rnum be ToUint32(rval).
- ReturnIfAbrupt(rnum).
- Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
- 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".
The number of bits to shift is capped at 31, i.e.
function shiftLeft(number, numShift) {
return number << (numShift % 32); // equivalent code
}