Skip to content

Commit 05921c5

Browse files
committed
[wasm64] Fix for bad Memory initial size under firefox
Recent versions of firefox started requiring bigint values for initial and max memory. See WebAssembly/memory64#68 Fixes: #22486
1 parent 8d571ec commit 05921c5

File tree

9 files changed

+56
-22
lines changed

9 files changed

+56
-22
lines changed

.circleci/config.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,10 @@ jobs:
867867
- install-emsdk
868868
- run-tests-firefox:
869869
title: "browser64"
870-
test_targets: "browser64.test_sdl_image"
870+
test_targets: "
871+
browser64.test_sdl_image
872+
browser64.test_dylink_many
873+
"
871874
# TODO(sbc): Re-enable once we figure out why the emrun tests are
872875
# locking up.
873876
#test-browser-chrome-emrun:

src/library.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,41 +1966,42 @@ addToLibrary({
19661966
$setWasmTableEntry__internal: true,
19671967
$setWasmTableEntry__deps: ['$wasmTableMirror', '$wasmTable'],
19681968
$setWasmTableEntry: (idx, func) => {
1969-
wasmTable.set(idx, func);
1969+
wasmTable.set({{{ toIndexType('idx') }}}, func);
19701970
// With ABORT_ON_WASM_EXCEPTIONS wasmTable.get is overridden to return wrapped
19711971
// functions so we need to call it here to retrieve the potential wrapper correctly
19721972
// instead of just storing 'func' directly into wasmTableMirror
1973-
wasmTableMirror[idx] = wasmTable.get(idx);
1973+
wasmTableMirror[idx] = wasmTable.get({{{ toIndexType('idx') }}});
19741974
},
19751975

19761976
$getWasmTableEntry__internal: true,
19771977
$getWasmTableEntry__deps: ['$wasmTableMirror', '$wasmTable'],
19781978
$getWasmTableEntry: (funcPtr) => {
19791979
#if MEMORY64
1980-
// Function pointers are 64-bit, but wasmTable.get() requires a Number.
1980+
// Function pointers should show up as numbers, even under wasm64, but
1981+
// we still have some places where bigint values can flow here.
19811982
// https://github.com/emscripten-core/emscripten/issues/18200
19821983
funcPtr = Number(funcPtr);
19831984
#endif
19841985
var func = wasmTableMirror[funcPtr];
19851986
if (!func) {
19861987
if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1;
1987-
wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr);
1988+
wasmTableMirror[funcPtr] = func = wasmTable.get({{{ toIndexType('funcPtr') }}});
19881989
#if ASYNCIFY == 2
19891990
if (Asyncify.isAsyncExport(func)) {
19901991
wasmTableMirror[funcPtr] = func = Asyncify.makeAsyncFunction(func);
19911992
}
19921993
#endif
19931994
}
19941995
#if ASSERTIONS && ASYNCIFY != 2 // With JSPI the function stored in the table will be a wrapper.
1995-
assert(wasmTable.get(funcPtr) == func, 'JavaScript-side Wasm function table mirror is out of date!');
1996+
assert(wasmTable.get({{{ toIndexType('funcPtr') }}}) == func, 'JavaScript-side Wasm function table mirror is out of date!');
19961997
#endif
19971998
return func;
19981999
},
19992000

20002001
#else
20012002

20022003
$setWasmTableEntry__deps: ['$wasmTable'],
2003-
$setWasmTableEntry: (idx, func) => wasmTable.set(idx, func),
2004+
$setWasmTableEntry: (idx, func) => wasmTable.set({{{ toIndexType('idx') }}}, func),
20042005

20052006
$getWasmTableEntry__deps: ['$wasmTable'],
20062007
$getWasmTableEntry: (funcPtr) => {
@@ -2391,9 +2392,9 @@ addToLibrary({
23912392
#if RELOCATABLE
23922393
// In RELOCATABLE mode we create the table in JS.
23932394
$wasmTable: `=new WebAssembly.Table({
2394-
'initial': {{{ INITIAL_TABLE }}},
2395+
'initial': {{{ toIndexType(INITIAL_TABLE) }}},
23952396
#if !ALLOW_TABLE_GROWTH
2396-
'maximum': {{{ INITIAL_TABLE }}},
2397+
'maximum': {{{ toIndexType(INITIAL_TABLE) }}},
23972398
#endif
23982399
#if MEMORY64 == 1
23992400
'index': 'i64',

src/library_addfunction.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,14 @@ addToLibrary({
151151
}
152152
// Grow the table
153153
try {
154-
wasmTable.grow(1);
154+
wasmTable.grow({{{ toIndexType('1') }}});
155155
} catch (err) {
156156
if (!(err instanceof RangeError)) {
157157
throw err;
158158
}
159159
throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.';
160160
}
161-
return wasmTable.length - 1;
161+
return {{{ from64Expr('wasmTable.length') }}} - 1;
162162
},
163163

164164
$updateTableMap__deps: ['$getWasmTableEntry'],
@@ -179,7 +179,7 @@ addToLibrary({
179179
// First, create the map if this is the first use.
180180
if (!functionsInTableMap) {
181181
functionsInTableMap = new WeakMap();
182-
updateTableMap(0, wasmTable.length);
182+
updateTableMap(0, {{{ from64Expr('wasmTable.length') }}});
183183
}
184184
return functionsInTableMap.get(func) || 0;
185185
},

src/library_dylink.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,10 @@ var LibraryDylink = {
581581
#if DYLINK_DEBUG
582582
$dumpTable__deps: ['$wasmTable'],
583583
$dumpTable: () => {
584-
for (var i = 0; i < wasmTable.length; i++)
584+
var len = wasmTable.length;
585+
for (var i = {{{ toIndexType(0) }}} ; i < len; i++) {
585586
dbg(`table: ${i} : ${wasmTable.get(i)}`);
587+
}
586588
},
587589
#endif
588590

@@ -641,7 +643,7 @@ var LibraryDylink = {
641643
tableBase = {{{ makeGetValue('handle', C_STRUCTS.dso.table_addr, '*') }}};
642644
}
643645

644-
var tableGrowthNeeded = tableBase + metadata.tableSize - wasmTable.length;
646+
var tableGrowthNeeded = tableBase + metadata.tableSize - {{{ from64Expr('wasmTable.length') }}};
645647
if (tableGrowthNeeded > 0) {
646648
#if DYLINK_DEBUG
647649
dbg("loadModule: growing table: " + tableGrowthNeeded);

src/parseTools.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,11 @@ function from64Expr(x, assign = true) {
963963
return `Number(${x})`;
964964
}
965965

966+
function toIndexType(x) {
967+
if (MEMORY64 != 1) return x;
968+
return `toIndexType(${x})`;
969+
}
970+
966971
function to64(x) {
967972
if (!MEMORY64) return x;
968973
return `BigInt(${x})`;
@@ -1153,4 +1158,5 @@ addToCompileTimeContext({
11531158
splitI64,
11541159
storeException,
11551160
to64,
1161+
toIndexType,
11561162
});

src/runtime_init_memory.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ if (!ENVIRONMENT_IS_PTHREAD) {
2727
assert(INITIAL_MEMORY >= {{{STACK_SIZE}}}, 'INITIAL_MEMORY should be larger than STACK_SIZE, was ' + INITIAL_MEMORY + '! (STACK_SIZE=' + {{{STACK_SIZE}}} + ')');
2828
#endif
2929
wasmMemory = new WebAssembly.Memory({
30-
'initial': INITIAL_MEMORY / {{{ WASM_PAGE_SIZE }}},
30+
'initial': {{{ toIndexType(`INITIAL_MEMORY / ${WASM_PAGE_SIZE}`) }}},
3131
#if ALLOW_MEMORY_GROWTH
3232
// In theory we should not need to emit the maximum if we want "unlimited"
3333
// or 4GB of memory, but VMs error on that atm, see
3434
// https://github.com/emscripten-core/emscripten/issues/14130
3535
// And in the pthreads case we definitely need to emit a maximum. So
3636
// always emit one.
37-
'maximum': {{{ MAXIMUM_MEMORY }}} / {{{ WASM_PAGE_SIZE }}},
37+
'maximum': {{{ toIndexType(MAXIMUM_MEMORY / WASM_PAGE_SIZE) }}},
3838
#else
39-
'maximum': INITIAL_MEMORY / {{{ WASM_PAGE_SIZE }}},
39+
'maximum': {{{ toIndexType(`INITIAL_MEMORY / ${WASM_PAGE_SIZE}`) }}},
4040
#endif // ALLOW_MEMORY_GROWTH
4141
#if SHARED_MEMORY
4242
'shared': true,

src/runtime_shared.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,19 @@ function updateMemoryViews() {
4646
{{{ maybeExportHeap('HEAPU64') }}}HEAPU64 = new BigUint64Array(b);
4747
#endif
4848
}
49+
50+
#if MEMORY64 == 1
51+
var toIndexType = (function() {
52+
// Probe for support of bigint bounds with memory64.
53+
// TODO(sbc): Remove this once all browsers start requiring bigint here.
54+
// See https://github.com/WebAssembly/memory64/issues/68
55+
var bigintMemoryBounds = 1;
56+
try {
57+
/** @suppress {checkTypes} */
58+
new WebAssembly.Memory({'initial': 1n, 'index': 'i64'});
59+
} catch (e) {
60+
bigintMemoryBounds = 0;
61+
}
62+
return (i) => bigintMemoryBounds ? BigInt(i) : i;
63+
})();
64+
#endif

test/no_this_in_dyncall.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
addToLibrary({
2-
$classLike: {
3-
fnptr: 0,
2+
$classLike: {
3+
fnptr: 0,
44
call: function(val) {
55
{{{ makeDynCall('vp', 'this.fnptr') }}}(val);
66
}
7-
},
7+
},
88

99
test__deps: ['$classLike'],
1010
test: function(fnptr, val) {

tools/unsafe_optimizations.mjs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,13 @@ function optPassRemoveRedundantOperatorNews(ast) {
7373
// in emscripten with real side effects. For example, see
7474
// loadWasmModuleToWorker which returns a `new Promise` that is never
7575
// referenced (a least in some builds).
76-
if (n.expression.callee.name !== 'Promise') {
76+
//
77+
// Another exception is made for `new WebAssembly.*` since we create and
78+
// unused `WebAssembly.Memory` when probing for wasm64 fatures.
79+
if (
80+
n.expression.callee.name !== 'Promise' &&
81+
n.expression.callee.object?.name !== 'WebAssembly'
82+
) {
7783
nodeArray.splice(i--, 1);
7884
}
7985
}
@@ -217,7 +223,7 @@ function runOnJsText(js, pretty = false) {
217223
const output = terserAst.print_to_string({
218224
wrap_func_args: false,
219225
beautify: pretty,
220-
indent_level: pretty ? 1 : 0,
226+
indent_level: pretty ? 2 : 0,
221227
});
222228

223229
return output;

0 commit comments

Comments
 (0)