Skip to content

Commit c2462cd

Browse files
authored
Create memory in wasm binaryn by default (#12790)
There are some cases where we want to create the memory in JS but for most programs exporting the memory from wasm makes more sense and is more compact and reliable. The new EXTERNAL_MEMORY setting can be used to override this behaviour.
1 parent 47dc32a commit c2462cd

File tree

76 files changed

+193
-195
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+193
-195
lines changed

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ See docs/process.md for more on how version tagging works.
2020

2121
Current Trunk
2222
-------------
23+
- The WebAssembly memory used by emscripten programs is now, by default, created
24+
in the wasm file and exported to JavaScript. Previously we could create the
25+
memory in JavaScript and import it into the wasm file. The new
26+
`IMPORTED_MEMORY` setting can be used to revert to the old behaviour.
27+
Breaking change: This new setting is required if you provide a runtime
28+
value for `wasmMemory` or `INITIAL_MEMORY` on the Module object.
2329

2430
2.0.9: 11/16/2020
2531
-----------------

emcc.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,10 @@ def include_and_export(name):
17411741
# requires JS legalization
17421742
shared.Settings.LEGALIZE_JS_FFI = 0
17431743

1744+
# TODO(sbc): Remove WASM2JS here once the size regression it would introduce has been fixed.
1745+
if shared.Settings.USE_PTHREADS or shared.Settings.RELOCATABLE or shared.Settings.ASYNCIFY_LAZY_LOAD_CODE or shared.Settings.WASM2JS:
1746+
shared.Settings.IMPORTED_MEMORY = 1
1747+
17441748
if shared.Settings.WASM_BIGINT:
17451749
shared.Settings.LEGALIZE_JS_FFI = 0
17461750

emscripten.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -536,10 +536,7 @@ def create_em_js(forwarded_json, metadata):
536536

537537

538538
def add_standard_wasm_imports(send_items_map):
539-
# Normally we import these into the wasm (so that JS could use them even
540-
# before the wasm loads), while in standalone mode we do not depend
541-
# on JS to create them, but create them in the wasm and export them.
542-
if not shared.Settings.STANDALONE_WASM:
539+
if shared.Settings.IMPORTED_MEMORY:
543540
memory_import = 'wasmMemory'
544541
if shared.Settings.MODULARIZE and shared.Settings.USE_PTHREADS:
545542
# Pthreads assign wasmMemory in their worker startup. In MODULARIZE mode, they cannot assign inside the

src/postamble.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
{{{ exportRuntime() }}}
1010

11-
#if MEM_INIT_IN_WASM == 0
11+
#if !MEM_INIT_IN_WASM
12+
function runMemoryInitializer() {
1213
#if USE_PTHREADS
13-
if (memoryInitializer && !ENVIRONMENT_IS_PTHREAD) {
14+
if (!memoryInitializer || ENVIRONMENT_IS_PTHREAD) return;
1415
#else
15-
if (memoryInitializer) {
16+
if (!memoryInitializer) return
1617
#endif
1718
if (!isDataURI(memoryInitializer)) {
1819
memoryInitializer = locateFile(memoryInitializer);

src/postamble_minimal.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ WebAssembly.instantiate(Module['wasm'], imports).then(function(output) {
204204
/*** ASM_MODULE_EXPORTS ***/
205205
#endif
206206
wasmTable = asm['__indirect_function_table'];
207+
#if ASSERTIONS
208+
assert(wasmTable);
209+
#endif
210+
211+
#if !IMPORTED_MEMORY
212+
wasmMemory = asm['memory'];
213+
#if ASSERTIONS
214+
assert(wasmMemory);
215+
assert(wasmMemory.buffer.byteLength === {{{ INITIAL_MEMORY }}});
216+
#endif
217+
updateGlobalBufferAndViews(wasmMemory.buffer);
218+
#endif
219+
220+
#if MEM_INIT_METHOD == 1 && !MEM_INIT_IN_WASM && !SINGLE_FILE
221+
#if ASSERTIONS
222+
if (!Module['mem']) throw 'Must load memory initializer as an ArrayBuffer in to variable Module.mem before adding compiled output .js script to the DOM';
223+
#endif
224+
HEAPU8.set(new Uint8Array(Module['mem']), {{{ GLOBAL_BASE }}});
225+
#endif
207226

208227
initRuntime(asm);
209228
#if USE_PTHREADS && PTHREAD_POOL_SIZE

src/preamble.js

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -325,15 +325,16 @@ if (typeof SharedArrayBuffer === 'undefined' || typeof Atomics === 'undefined')
325325
#endif
326326
#endif
327327

328-
#if STANDALONE_WASM
329-
#if ASSERTIONS
330-
// In standalone mode, the wasm creates the memory, and the user can't provide it.
331-
assert(!Module['wasmMemory']);
332-
#endif // ASSERTIONS
333-
#else // !STANDALONE_WASM
328+
#if IMPORTED_MEMORY
334329
// In non-standalone/normal mode, we create the memory here.
335330
#include "runtime_init_memory.js"
336-
#endif // !STANDALONE_WASM
331+
#else // IMPORTED_MEMORY
332+
#if ASSERTIONS
333+
// If memory is defined in wasm, the user can't provide it.
334+
assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -s IMPORTED_MEMORY to define wasmMemory externally');
335+
assert(INITIAL_MEMORY == {{{INITIAL_MEMORY}}}, 'Detected runtime INITIAL_MEMORY setting. Use -s IMPORTED_MEMORY to define wasmMemory dynamically');
336+
#endif // ASSERTIONS
337+
#endif // IMPORTED_MEMORY
337338

338339
#include "runtime_init_table.js"
339340
#include "runtime_stack_check.js"
@@ -833,6 +834,21 @@ function createWasm() {
833834

834835
Module['asm'] = exports;
835836

837+
#if !IMPORTED_MEMORY
838+
wasmMemory = Module['asm']['memory'];
839+
#if ASSERTIONS
840+
assert(wasmMemory, "memory not found in wasm exports");
841+
// This assertion doesn't hold when emscripten is run in --post-link
842+
// mode.
843+
// TODO(sbc): Read INITIAL_MEMORY out of the wasm file in post-link mode.
844+
//assert(wasmMemory.buffer.byteLength === {{{ INITIAL_MEMORY }}});
845+
#endif
846+
updateGlobalBufferAndViews(wasmMemory.buffer);
847+
#endif
848+
#if !MEM_INIT_IN_WASM
849+
runMemoryInitializer();
850+
#endif
851+
836852
#if !RELOCATABLE
837853
wasmTable = Module['asm']['__indirect_function_table'];
838854
#if ASSERTIONS && !PURE_WASI
@@ -849,19 +865,6 @@ function createWasm() {
849865
// is in charge of programatically exporting them on the global object.
850866
exportAsmFunctions(exports);
851867
#endif
852-
#if STANDALONE_WASM
853-
// In pure wasm mode the memory is created in the wasm (not imported), and
854-
// then exported.
855-
// TODO: do not create a Memory earlier in JS
856-
wasmMemory = exports['memory'];
857-
#if ASSERTIONS
858-
assert(wasmMemory, "memory not found in wasm exports");
859-
#endif
860-
updateGlobalBufferAndViews(wasmMemory.buffer);
861-
#if STACK_OVERFLOW_CHECK
862-
writeStackCookie();
863-
#endif
864-
#endif
865868
#if USE_PTHREADS
866869
// We now have the Wasm module loaded up, keep a reference to the compiled module so we can post it to the workers.
867870
wasmModule = module;

src/preamble_minimal.js

Lines changed: 30 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -55,52 +55,13 @@ Module['wasm'] = base64Decode('{{{ getQuoted("WASM_BINARY_DATA") }}}');
5555
#include "runtime_functions.js"
5656
#include "runtime_strings.js"
5757

58-
#if USE_PTHREADS
59-
if (!ENVIRONMENT_IS_PTHREAD) {
60-
#endif
61-
62-
#if ALLOW_MEMORY_GROWTH && MAXIMUM_MEMORY != -1
63-
var wasmMaximumMemory = {{{ MAXIMUM_MEMORY >>> 16 }}};
64-
#else
65-
var wasmMaximumMemory = {{{ INITIAL_MEMORY >>> 16}}};
66-
#endif
67-
68-
var wasmMemory = new WebAssembly.Memory({
69-
'initial': {{{ INITIAL_MEMORY >>> 16 }}}
70-
#if USE_PTHREADS || !ALLOW_MEMORY_GROWTH || MAXIMUM_MEMORY != -1
71-
, 'maximum': wasmMaximumMemory
72-
#endif
73-
#if USE_PTHREADS
74-
, 'shared': true
75-
#endif
76-
});
77-
78-
var wasmTable;
79-
var buffer = wasmMemory.buffer;
80-
81-
#if USE_PTHREADS
82-
}
83-
#if ASSERTIONS
84-
assert(buffer instanceof SharedArrayBuffer, 'requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag');
85-
#endif
86-
#endif
87-
88-
#if ASSERTIONS
89-
#if USE_PTHREADS
90-
if (!ENVIRONMENT_IS_PTHREAD) {
91-
#endif
92-
assert(buffer.byteLength === {{{ INITIAL_MEMORY }}});
93-
#if USE_PTHREADS
94-
}
95-
#endif
96-
#endif // ASSERTIONS
97-
98-
#if ALLOW_MEMORY_GROWTH
99-
// In ALLOW_MEMORY_GROWTH, we need to be able to re-initialize the
100-
// typed array buffer and heap views to the buffer whenever the heap
101-
// is resized.
10258
var HEAP8, HEAP16, HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32, HEAPF64;
59+
var wasmMemory, buffer, wasmTable;
60+
10361
function updateGlobalBufferAndViews(b) {
62+
#if ASSERTIONS && USE_PTHREADS
63+
assert(b instanceof SharedArrayBuffer, 'requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag');
64+
#endif
10465
buffer = b;
10566
HEAP8 = new Int8Array(b);
10667
HEAP16 = new Int16Array(b);
@@ -111,34 +72,36 @@ function updateGlobalBufferAndViews(b) {
11172
HEAPF32 = new Float32Array(b);
11273
HEAPF64 = new Float64Array(b);
11374
}
114-
updateGlobalBufferAndViews(buffer);
115-
#else
116-
// In non-ALLOW_MEMORY_GROWTH scenario, we only need to initialize
117-
// the heap once, so optimize code size to do it statically here.
118-
var HEAP8 = new Int8Array(buffer);
119-
var HEAP16 = new Int16Array(buffer);
120-
var HEAP32 = new Int32Array(buffer);
121-
var HEAPU8 = new Uint8Array(buffer);
122-
var HEAPU16 = new Uint16Array(buffer);
123-
var HEAPU32 = new Uint32Array(buffer);
124-
var HEAPF32 = new Float32Array(buffer);
125-
var HEAPF64 = new Float64Array(buffer);
126-
#endif
127-
128-
#if USE_PTHREADS && ((MEM_INIT_METHOD == 1 && !MEM_INIT_IN_WASM && !SINGLE_FILE) || USES_DYNAMIC_ALLOC)
75+
76+
#if IMPORTED_MEMORY
77+
#if USE_PTHREADS
12978
if (!ENVIRONMENT_IS_PTHREAD) {
13079
#endif
131-
132-
#if MEM_INIT_METHOD == 1 && !MEM_INIT_IN_WASM && !SINGLE_FILE
133-
#if ASSERTIONS
134-
if (!Module['mem']) throw 'Must load memory initializer as an ArrayBuffer in to variable Module.mem before adding compiled output .js script to the DOM';
80+
#if ALLOW_MEMORY_GROWTH && MAXIMUM_MEMORY != -1
81+
var wasmMaximumMemory = {{{ MAXIMUM_MEMORY >>> 16 }}};
82+
#else
83+
var wasmMaximumMemory = {{{ INITIAL_MEMORY >>> 16}}};
13584
#endif
136-
HEAPU8.set(new Uint8Array(Module['mem']), {{{ GLOBAL_BASE }}});
85+
wasmMemory = new WebAssembly.Memory({
86+
'initial': {{{ INITIAL_MEMORY >>> 16 }}}
87+
#if USE_PTHREADS || !ALLOW_MEMORY_GROWTH || MAXIMUM_MEMORY != -1
88+
, 'maximum': wasmMaximumMemory
13789
#endif
138-
139-
#if USE_PTHREADS && ((MEM_INIT_METHOD == 1 && !MEM_INIT_IN_WASM && !SINGLE_FILE) || USES_DYNAMIC_ALLOC)
140-
}
90+
#if USE_PTHREADS
91+
, 'shared': true
14192
#endif
93+
});
94+
updateGlobalBufferAndViews(wasmMemory.buffer);
95+
#if USE_PTHREADS
96+
} else {
97+
#if MODULARIZE
98+
updateGlobalBufferAndViews({{{EXPORT_NAME}}}.buffer);
99+
#else
100+
updateGlobalBufferAndViews(wasmMemory.buffer);
101+
#endif
102+
}
103+
#endif // USE_PTHREADS
104+
#endif // IMPORTED_MEMORY
142105

143106
#include "runtime_stack_check.js"
144107
#include "runtime_assertions.js"

src/runtime_init_memory.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
* SPDX-License-Identifier: MIT
55
*/
66

7-
// Create the main memory. (Note: this isn't used in STANDALONE_WASM mode since the wasm
8-
// memory is created in the wasm, not in JS.)
7+
// Create the wasm memory. (Note: this only applies if IMPORTED_MEMORY is defined)
8+
#if !IMPORTED_MEMORY
9+
{{{ throw "this file should not be be included when IMPORTED_MEMORY is set"; }}}
10+
#endif
11+
912
#if USE_PTHREADS
1013
if (ENVIRONMENT_IS_PTHREAD) {
1114
wasmMemory = Module['wasmMemory'];

src/settings.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,17 @@ var ABORT_ON_WASM_EXCEPTIONS = 0;
16361636
// Implies STANDALONE_WASM.
16371637
var PURE_WASI = 0;
16381638

1639+
// Set to 1 to define the WebAssembly.Memory object outside of the wasm
1640+
// module. By default the wasm module defines the memory and exports
1641+
// it to JavaScript.
1642+
// Use of the following settings will enable this settings since they
1643+
// depend on being able to define the memory in JavaScript:
1644+
// - USE_PTHREADS
1645+
// - RELOCATABLE
1646+
// - ASYNCIFY_LAZY_LOAD_CODE
1647+
// - WASM2JS (WASM=0)
1648+
var IMPORTED_MEMORY = 0;
1649+
16391650
//===========================================
16401651
// Internal, used for testing only, from here
16411652
//===========================================

src/shell_minimal.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,6 @@ var _scriptDir = (typeof document !== 'undefined' && document.currentScript) ? d
140140
// coincide.
141141
var ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_PTHREAD = typeof importScripts === 'function';
142142

143-
#if MODULARIZE
144-
if (ENVIRONMENT_IS_WORKER) {
145-
var buffer = {{{EXPORT_NAME}}}.buffer;
146-
}
147-
#endif
148-
149143
var currentScriptUrl = typeof _scriptDir !== 'undefined' ? _scriptDir : ((typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined);
150144
#endif // USE_PTHREADS
151145

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 563,
33
"a.html.gz": 377,
4-
"a.js": 4957,
5-
"a.js.gz": 2373,
6-
"a.wasm": 10893,
7-
"a.wasm.gz": 6923,
8-
"total": 16413,
9-
"total_gz": 9673
4+
"a.js": 4927,
5+
"a.js.gz": 2352,
6+
"a.wasm": 10895,
7+
"a.wasm.gz": 6927,
8+
"total": 16385,
9+
"total_gz": 9656
1010
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 588,
33
"a.html.gz": 386,
4-
"a.js": 21297,
5-
"a.js.gz": 8263,
4+
"a.js": 21317,
5+
"a.js.gz": 8276,
66
"a.mem": 3171,
77
"a.mem.gz": 2715,
8-
"total": 25056,
9-
"total_gz": 11364
8+
"total": 25076,
9+
"total_gz": 11377
1010
}

tests/code_size/hello_webgl_wasm.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 563,
33
"a.html.gz": 377,
4-
"a.js": 4444,
5-
"a.js.gz": 2199,
6-
"a.wasm": 10893,
7-
"a.wasm.gz": 6923,
8-
"total": 15900,
9-
"total_gz": 9499
4+
"a.js": 4410,
5+
"a.js.gz": 2172,
6+
"a.wasm": 10895,
7+
"a.wasm.gz": 6927,
8+
"total": 15868,
9+
"total_gz": 9476
1010
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 588,
33
"a.html.gz": 386,
4-
"a.js": 20785,
5-
"a.js.gz": 8102,
4+
"a.js": 20801,
5+
"a.js.gz": 8114,
66
"a.mem": 3171,
77
"a.mem.gz": 2715,
8-
"total": 24544,
9-
"total_gz": 11203
8+
"total": 24560,
9+
"total_gz": 11215
1010
}

tests/code_size/hello_world_wasm.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"a.html": 665,
33
"a.html.gz": 427,
4-
"a.js": 360,
5-
"a.js.gz": 281,
6-
"a.wasm": 102,
7-
"a.wasm.gz": 114,
8-
"total": 1127,
9-
"total_gz": 822
4+
"a.js": 322,
5+
"a.js.gz": 259,
6+
"a.wasm": 104,
7+
"a.wasm.gz": 112,
8+
"total": 1091,
9+
"total_gz": 798
1010
}

0 commit comments

Comments
 (0)