Skip to content

Commit

Permalink
make_export_wrappers: Limit module exports to EXPORTED_FUNCTIONS
Browse files Browse the repository at this point in the history
This is code size win in pretty much all cases since thee are always
a few wasm exports that don't need to be set on the module object.
  • Loading branch information
sbc100 committed Jan 20, 2023
1 parent a290909 commit b70e491
Show file tree
Hide file tree
Showing 36 changed files with 154 additions and 61 deletions.
5 changes: 5 additions & 0 deletions ChangeLog.md
Expand Up @@ -20,6 +20,11 @@ See docs/process.md for more on how version tagging works.

3.1.31 (in development)
-----------------------
- Symbols that were previously exported from native code, but only for internal
reasons, are no longer exported on the `Module` object by default. For
example, previously if you were using `Module._malloc` but not explicitly
including `_malloc` in `EXPORTED_FUNCTIONS` if might have been exported anyway
due to internal using of `malloc` within the JS library code. (#18564)
- The `STACK_SIZE`, `STACK_ALIGN`, `POINTER_SIZE`, and `ASSERTIONS` JavaScript
globals were removed by default. In debug builds a clear error is shown if
you try to use these. (#18503)
Expand Down
40 changes: 20 additions & 20 deletions emscripten.py
Expand Up @@ -315,6 +315,9 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile):
if settings.RELOCATABLE and settings.MEMORY64 == 2:
metadata.imports += ['__memory_base32']

if settings.ASYNCIFY:
metadata.exports += ['asyncify_start_unwind', 'asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind']

update_settings_glue(out_wasm, metadata)

if not settings.WASM_BIGINT and metadata.emJsFuncs:
Expand Down Expand Up @@ -391,9 +394,6 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile):

exports = metadata.exports

if settings.ASYNCIFY:
exports += ['asyncify_start_unwind', 'asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind']

report_missing_symbols(forwarded_json['librarySymbols'])

if not outfile_js:
Expand Down Expand Up @@ -696,6 +696,15 @@ def make_export_wrappers(exports, delay_assignment):
if name == '__cpp_exception':
continue
mangled = asmjs_mangle(name)
wrapper = '/** @type {function(...*):?} */\nvar %s = ' % mangled

# TODO(sbc): Can we avoid exporting the dynCall_ functions on the module.
if mangled in settings.EXPORTED_FUNCTIONS or name.startswith('dynCall_'):
exported = 'Module["%s"] = ' % mangled
else:
exported = ''
wrapper += exported

# The emscripten stack functions are called very early (by writeStackCookie) before
# the runtime is initialized so we can't create these wrappers that check for
# runtimeInitialized.
Expand All @@ -705,29 +714,20 @@ def make_export_wrappers(exports, delay_assignment):
# With assertions enabled we create a wrapper that are calls get routed through, for
# the lifetime of the program.
if delay_assignment:
wrappers.append('''\
/** @type {function(...*):?} */
var %(mangled)s = Module["%(mangled)s"] = createExportWrapper("%(name)s");
''' % {'mangled': mangled, 'name': name})
wrapper += 'createExportWrapper("%s");' % name
else:
wrappers.append('''\
/** @type {function(...*):?} */
var %(mangled)s = Module["%(mangled)s"] = createExportWrapper("%(name)s", asm);
''' % {'mangled': mangled, 'name': name})
wrapper += 'createExportWrapper("%s", asm);' % name
elif delay_assignment:
# With assertions disabled the wrapper will replace the global var and Module var on
# first use.
wrappers.append('''\
/** @type {function(...*):?} */
var %(mangled)s = Module["%(mangled)s"] = function() {
return (%(mangled)s = Module["%(mangled)s"] = Module["asm"]["%(name)s"]).apply(null, arguments);
wrapper += '''function() {
return (%(mangled)s = %(exported)sModule["asm"]["%(name)s"]).apply(null, arguments);
};
''' % {'mangled': mangled, 'name': name})
''' % {'mangled': mangled, 'name': name, 'exported': exported}
else:
wrappers.append('''\
/** @type {function(...*):?} */
var %(mangled)s = Module["%(mangled)s"] = asm["%(name)s"]
''' % {'mangled': mangled, 'name': name})
wrapper += 'asm["%s"]' % name

wrappers.append(wrapper)
return wrappers


Expand Down
4 changes: 2 additions & 2 deletions src/library_browser.js
Expand Up @@ -1379,11 +1379,11 @@ var LibraryBrowser = {
return 0;
},

emscripten_get_preloaded_image_data_from_FILE__deps: ['emscripten_get_preloaded_image_data'],
emscripten_get_preloaded_image_data_from_FILE__deps: ['emscripten_get_preloaded_image_data', 'fileno'],
emscripten_get_preloaded_image_data_from_FILE__proxy: 'sync',
emscripten_get_preloaded_image_data_from_FILE__sig: 'iiii',
emscripten_get_preloaded_image_data_from_FILE: function(file, w, h) {
var fd = Module['_fileno'](file);
var fd = _fileno(file);
var stream = FS.getStream(fd);
if (stream) {
return _emscripten_get_preloaded_image_data(stream.path, w, h);
Expand Down
20 changes: 10 additions & 10 deletions src/library_sdl.js
Expand Up @@ -2262,13 +2262,13 @@ var LibrarySDL = {
}
}
var callStbImage = function(func, params) {
var x = Module['_malloc']({{{ getNativeTypeSize('i32') }}});
var y = Module['_malloc']({{{ getNativeTypeSize('i32') }}});
var comp = Module['_malloc']({{{ getNativeTypeSize('i32') }}});
var x = _malloc({{{ getNativeTypeSize('i32') }}});
var y = _malloc({{{ getNativeTypeSize('i32') }}});
var comp = _malloc({{{ getNativeTypeSize('i32') }}});
addCleanup(function() {
Module['_free'](x);
Module['_free'](y);
Module['_free'](comp);
_free(x);
_free(y);
_free(comp);
if (data) Module['_stbi_image_free'](data);
});
var data = Module['_' + func].apply(null, params.concat([x, y, comp, 0]));
Expand Down Expand Up @@ -2307,10 +2307,10 @@ var LibrarySDL = {
if (raw === null) err('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!');
#if STB_IMAGE
var lengthBytes = lengthBytesUTF8(filename)+1;
var name = Module['_malloc'](lengthBytes);
var name = _malloc(lengthBytes);
stringToUTF8(filename, name, lengthBytes);
addCleanup(function() {
Module['_free'](name);
_free(name);
});
raw = callStbImage('stbi_load', [name]);
if (!raw) return 0;
Expand Down Expand Up @@ -2765,7 +2765,7 @@ var LibrarySDL = {
return 1;
},

Mix_LoadWAV_RW__deps: ['$PATH_FS'],
Mix_LoadWAV_RW__deps: ['$PATH_FS', 'fileno'],
Mix_LoadWAV_RW__proxy: 'sync',
Mix_LoadWAV_RW__sig: 'iii',
Mix_LoadWAV_RW__docs: '/** @param {number|boolean=} freesrc */',
Expand All @@ -2778,7 +2778,7 @@ var LibrarySDL = {

if (type === 2/*SDL_RWOPS_STDFILE*/) {
var fp = {{{ makeGetValue('rwopsID + ' + 28 /*hidden.stdio.fp*/, '0', 'i32') }}};
var fd = Module['_fileno'](fp);
var fd = _fileno(fp);
var stream = FS.getStream(fd);
if (stream) {
rwops = { filename: stream.path };
Expand Down
4 changes: 4 additions & 0 deletions test/optimizer/applyDCEGraphRemovals-output.js
Expand Up @@ -13,6 +13,8 @@ var expD3 = Module["expD3"] = asm["expD3"];

var expD4;

var expD5;

var expI1 = Module["expI1"] = function() {
return (expI1 = Module["expI1"] = Module["asm"]["expI1"]).apply(null, arguments);
};
Expand All @@ -27,6 +29,8 @@ var expI3 = Module["expI3"] = function() {

var expI4;

var expI5;

expD1;

Module["expD2"];
Expand Down
8 changes: 7 additions & 1 deletion test/optimizer/applyDCEGraphRemovals.js
Expand Up @@ -6,6 +6,8 @@ var expD1 = Module['expD1'] = asm['expD1'];
var expD2 = Module['expD2'] = asm['expD2'];
var expD3 = Module['expD3'] = asm['expD3'];
var expD4 = Module['expD4'] = asm['expD4'];
// Like above, but not exported on the Module
var expD5 = asm['expD5'];

// exports gotten indirectly (async compilation
var expI1 = Module['expI1'] = (function() {
Expand All @@ -20,6 +22,10 @@ var expI3 = Module['expI3'] = (function() {
var expI4 = Module['expI4'] = (function() {
return (expI4 = Module['expI4'] = Module['asm']['expI4']).apply(null, arguments);
});
// Like above, but not exported on the Module
var expI5 = (function() {
return (expI5 = Module['asm']['expI5']).apply(null, arguments);
});

// add uses for some of them, leave *4 as non-roots
expD1;
Expand All @@ -30,4 +36,4 @@ expI1;
Module['expI2'];
asm['expI3'];

// EXTRA_INFO: { "unused": ["emcc$import$number", "emcc$import$name", "emcc$import$func", "emcc$export$expD4", "emcc$export$expI4"] }
// EXTRA_INFO: { "unused": ["emcc$import$number", "emcc$import$name", "emcc$import$func", "emcc$export$expD4", "emcc$export$expD5", "emcc$export$expI4", "emcc$export$expI5"] }
10 changes: 10 additions & 0 deletions test/optimizer/emitDCEGraph-output.js
Expand Up @@ -100,6 +100,11 @@
"export": "expD4",
"reaches": []
},
{
"name": "emcc$export$expD5",
"export": "expD5",
"reaches": []
},
{
"name": "emcc$export$expI1",
"export": "expI1",
Expand All @@ -123,6 +128,11 @@
"export": "expI4",
"reaches": []
},
{
"name": "emcc$export$expI5",
"export": "expI5",
"reaches": []
},
{
"name": "emcc$import$rootedFunc1",
"import": [
Expand Down
6 changes: 6 additions & 0 deletions test/optimizer/emitDCEGraph.js
Expand Up @@ -49,6 +49,8 @@ var expD1 = Module['expD1'] = asm['expD1'];
var expD2 = Module['expD2'] = asm['expD2'];
var expD3 = Module['expD3'] = asm['expD3'];
var expD4 = Module['expD4'] = asm['expD4'];
// Same as above but not export on the Module
var expD5 = asm['expD5'];

// exports gotten indirectly (async compilation
var expI1 = Module['expI1'] = function() {
Expand All @@ -63,6 +65,10 @@ var expI3 = Module['expI3'] = function() {
var expI4 = Module['expI4'] = function() {
return (expI4 = Module['expI4'] = Module['asm']['expI4']).apply(null, arguments);
};
// Same as above but not export on the Module.
var expI5 = function() {
return (expI5 = Module['asm']['expI5']).apply(null, arguments);
};

// add uses for some of them
expD1;
Expand Down
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_cxx_ctors1.jssize
@@ -1 +1 @@
26600
26008
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_cxx_ctors2.jssize
@@ -1 +1 @@
26564
25972
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_cxx_except.jssize
@@ -1 +1 @@
31193
30545
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_cxx_except_wasm.jssize
@@ -1 +1 @@
26078
25581
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_cxx_mangle.jssize
@@ -1 +1 @@
31437
30545
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_cxx_noexcept.jssize
@@ -1 +1 @@
26600
26008
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_hello_O0.jssize
@@ -1 +1 @@
26963
26284
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_hello_O1.jssize
@@ -1 +1 @@
9214
8678
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_hello_O2.jssize
@@ -1 +1 @@
6610
6138
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_hello_O3.jssize
@@ -1 +1 @@
6060
5968
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_hello_Os.jssize
@@ -1 +1 @@
6060
5968
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_hello_Oz.jssize
@@ -1 +1 @@
6019
5927
@@ -1 +1 @@
4740
4648
@@ -1 +1 @@
5333
5241
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_mem_O3.jssize
@@ -1 +1 @@
6213
6094
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_mem_O3_grow.jssize
@@ -1 +1 @@
6555
6436
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_O0.jssize
@@ -1 +1 @@
23612
22850
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_O1.jssize
@@ -1 +1 @@
5732
5196
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_O2.jssize
@@ -1 +1 @@
4447
3975
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_O3.jssize
@@ -1 +1 @@
3956
3864
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_Os.jssize
@@ -1 +1 @@
3956
3864
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_Oz.jssize
@@ -1 +1 @@
3956
3864
2 changes: 1 addition & 1 deletion test/other/metadce/test_metadce_minimal_pthreads.jssize
@@ -1 +1 @@
16177
15787
2 changes: 1 addition & 1 deletion test/other/test_unoptimized_code_size.js.size
@@ -1 +1 @@
67096
66571
2 changes: 1 addition & 1 deletion test/other/test_unoptimized_code_size_no_asserts.js.size
@@ -1 +1 @@
38780
38518
2 changes: 1 addition & 1 deletion test/other/test_unoptimized_code_size_strict.js.size
@@ -1 +1 @@
65962
65437
2 changes: 1 addition & 1 deletion test/test_browser.py
Expand Up @@ -4392,7 +4392,7 @@ def test_small_js_flags(self):
size = os.path.getsize('test.js')
print('size:', size)
# Note that this size includes test harness additions (for reporting the result, etc.).
self.assertLess(abs(size - 5169), 100)
self.assertLess(abs(size - 5059), 100)

# Tests that it is possible to initialize and render WebGL content in a pthread by using OffscreenCanvas.
# -DTEST_CHAINED_WEBGL_CONTEXT_PASSING: Tests that it is possible to transfer WebGL canvas in a chain from main thread -> thread 1 -> thread 2 and then init and render WebGL content there.
Expand Down

0 comments on commit b70e491

Please sign in to comment.