Skip to content

Commit a37d6bc

Browse files
authored
Add a helper cast utility to BigInt that saves code size. (#25308)
1 parent 62d03fb commit a37d6bc

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed

src/parseTools.mjs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,32 @@ function makeInlineCalculation(expression, value, tempVar) {
262262

263263
// XXX Make all i64 parts signed
264264

265+
function castToBigInt(x) {
266+
// Micro-size-optimization: if x is an integer literal, then we can append
267+
// the suffix 'n' instead of casting to BigInt(), to get smaller code size.
268+
var n = Number(x);
269+
if (Number.isInteger(n) && isFinite(n)) {
270+
// NOTE: BigInt(316059037807746200000) != 316059037807746200000n
271+
// i.e. constructing numbers with BigInt()s is subject to rounding, if
272+
// the input value cannot be exactly represented as a 64-bit double.
273+
// Currently the test suite depends on this rounding behavior, so only
274+
// apply this literal optimization to safe integers for now.
275+
if (Math.abs(n) < Number.MAX_SAFE_INTEGER) {
276+
return `${x}n`;
277+
}
278+
}
279+
return `BigInt(${x})`;
280+
}
281+
282+
265283
// Splits a number (an integer in a double, possibly > 32 bits) into an i64
266284
// value, represented by a low and high i32 pair.
267285
// Will suffer from rounding and truncation.
268286
function splitI64(value) {
269287
if (WASM_BIGINT) {
270288
// Nothing to do: just make sure it is a BigInt (as it must be of that
271289
// type, to be sent into wasm).
272-
return `BigInt(${value})`;
290+
return castToBigInt(value);
273291
}
274292

275293
// general idea:
@@ -474,7 +492,7 @@ function makeSetValueImpl(ptr, pos, value, type) {
474492

475493
const slab = getHeapForType(type);
476494
if (slab == 'HEAPU64' || slab == 'HEAP64') {
477-
value = `BigInt(${value})`;
495+
value = castToBigInt(value);
478496
}
479497
return `${slab}[${getHeapOffset(offset, type)}] = ${value}`;
480498
}
@@ -595,7 +613,7 @@ function getHeapForType(type) {
595613

596614
export function makeReturn64(value) {
597615
if (WASM_BIGINT) {
598-
return `BigInt(${value})`;
616+
return castToBigInt(value);
599617
}
600618
const pair = splitI64(value);
601619
// `return (a, b, c)` in JavaScript will execute `a`, and `b` and return the final
@@ -1000,7 +1018,7 @@ function from64Expr(x) {
10001018
// Converts a value to BigInt if building for wasm64, with both 64-bit pointers
10011019
// and 64-bit memory. Used for indices into the memory tables, for example.
10021020
function toIndexType(x) {
1003-
if (MEMORY64 == 1) return `BigInt(${x})`;
1021+
if (MEMORY64 == 1) return castToBigInt(x);
10041022
return x;
10051023
}
10061024

@@ -1010,7 +1028,7 @@ function toIndexType(x) {
10101028
// this conversion before passing them).
10111029
function to64(x) {
10121030
if (!MEMORY64) return x;
1013-
return `BigInt(${x})`;
1031+
return castToBigInt(x);
10141032
}
10151033

10161034
function asyncIf(condition) {

test/other/test_parseTools.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,12 @@ addToLibrary({
9191
{{{ makeSetValue('ptr', '0', 0x12345678AB, 'i64') }}};
9292
_printI64(ptr);
9393

94-
// This value doesn't fit into i64. The current behaviour truncate (i.e.
95-
// ignore the upper bits), in the same way that `BigInt64Array[X] = Y` does.
96-
// (see splitI16 in parseTools.js)
94+
// This value doesn't fit into i64. The current behaviour is
95+
// in unspecified, subject to a double rounding problem. See
96+
// note in castToBigInt() in parseTools.mjs.
97+
// FIXME: Find a way to improve BigInt-enabled case to avoid
98+
// double rounding, and BigInt-disabled case to be at least
99+
// less wrong.
97100
_clearI64(ptr);
98101
{{{ makeSetValue('ptr', '0', 0x1122334455667788AA, 'i64') }}};
99102
_printI64(ptr);

0 commit comments

Comments
 (0)