Skip to content

Instantly share code, notes, and snippets.

@lambdageek
Created May 12, 2022 13:46
Show Gist options
  • Save lambdageek/c694149784b6b7ac1a7ed9e21b006afa to your computer and use it in GitHub Desktop.
Save lambdageek/c694149784b6b7ac1a7ed9e21b006afa to your computer and use it in GitHub Desktop.
Fun with NaN boxing
/// We pack 64-bit integers into the 64 bytes of a double
type PackedInt64 = number;
const doubleView = new Float64Array(1);
const int32View = new Int32Array(doubleView.buffer);
export function pack(lo: number, hi: number): PackedInt64 {
int32View[0] = lo;
int32View[1] = hi;
return doubleView[0];
}
exort function getLo(value: PackedInt64): number {
doubleView[0] = value;
return int32View[0];
}
export function getHi(value: PackedInt64): number {
doubleView[0] = value;
return int32View[1];
}
export function toBigInt(value: PackedInt64): bigint {
return BigInt(getLo(value)) + BigInt(getHi(value)) << BigInt(32);
}
/// And this works in Chrome:
/// > let x = pack (12, 0xffffffff)
/// undefined
/// > x
/// NaN
/// > getLo(x)
/// 12
/// > getHi(x)
/// -1
/// But not in Firefox, because it turns all NaNs into a canonical form so it can use other NaN bitpatterns to store pointers
/// https://brionv.com/log/2018/05/17/javascript-engine-internals-nan-boxing/
///
/// > let x = pack(12,0xffffffff)
/// undefined
/// > x
/// NaN
/// > getLo(x)
/// 0
/// > getHi(x)
/// 2146959360
///
/// > y = pack (1234, 0xffffffff)
// NaN
/// > getLo(y)
/// 0
/// > getHi(y)
/// 2146959360
/// > getLo(x) == getLo(y) && getHi(x) == getHi(y)
/// true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment