Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1216,12 +1216,19 @@ def is_supported_link_flag(f):

link_flags = [f for f in link_flags if is_supported_link_flag(f[1])]

if shared.Settings.MINIMAL_RUNTIME:
# Remove the default exported functions 'memcpy', 'memset', 'malloc', 'free', etc. - those should only be linked in if used
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = []

if shared.Settings.USE_PTHREADS:
# These runtime methods are called from worker.js
shared.Settings.EXPORTED_RUNTIME_METHODS += ['establishStackSpace', 'dynCall_ii']

if shared.Settings.STACK_OVERFLOW_CHECK:
shared.Settings.EXPORTED_RUNTIME_METHODS += ['writeStackCookie', 'checkStackCookie', 'abortStackOverflow']
if shared.Settings.MINIMAL_RUNTIME:
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$abortStackOverflow']
else:
shared.Settings.EXPORTED_RUNTIME_METHODS += ['writeStackCookie', 'checkStackCookie', 'abortStackOverflow']

if shared.Settings.MODULARIZE_INSTANCE:
shared.Settings.MODULARIZE = 1
Expand Down Expand Up @@ -1520,9 +1527,6 @@ def is_supported_link_flag(f):
if options.shell_path == shared.path_from_root('src', 'shell.html'):
options.shell_path = shared.path_from_root('src', 'shell_minimal_runtime.html')

# Remove the default exported functions 'memcpy', 'memset', 'malloc', 'free', etc. - those should only be linked in if used
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = []

if shared.Settings.ASSERTIONS and shared.Settings.MINIMAL_RUNTIME:
# In ASSERTIONS-builds, functions UTF8ArrayToString() and stringToUTF8Array() (which are not JS library functions), both
# use warnOnce(), which in MINIMAL_RUNTIME is a JS library function, so explicitly have to mark dependency to warnOnce()
Expand Down Expand Up @@ -1796,9 +1800,6 @@ def check_human_readable_list(items):
assert not shared.Settings.ALLOW_MEMORY_GROWTH, 'memory growth is not supported with shared asm.js modules'

if shared.Settings.MINIMAL_RUNTIME:
if shared.Settings.ALLOW_MEMORY_GROWTH:
logging.warning('-s ALLOW_MEMORY_GROWTH=1 is not yet supported with -s MINIMAL_RUNTIME=1')

if shared.Settings.EMTERPRETIFY:
exit_with_error('-s EMTERPRETIFY=1 is not supported with -s MINIMAL_RUNTIME=1')

Expand Down Expand Up @@ -1838,10 +1839,6 @@ def check_human_readable_list(items):
if shared.Settings.ALLOW_MEMORY_GROWTH:
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['emscripten_trace_report_memory_layout']

# MINIMAL_RUNTIME always use separate .asm.js file for best performance and memory usage
if shared.Settings.MINIMAL_RUNTIME and not shared.Settings.WASM:
options.separate_asm = True

if shared.Settings.STANDALONE_WASM:
if not shared.Settings.WASM_BACKEND:
exit_with_error('STANDALONE_WASM is only available in the upstream wasm backend path')
Expand Down Expand Up @@ -3499,6 +3496,7 @@ def minify_html(filename, options):
size_before = os.path.getsize(filename)
start_time = time.time()
run_process(shared.NODE_JS + [shared.path_from_root('third_party', 'html-minifier', 'cli.js'), filename, '-o', filename] + opts)

elapsed_time = time.time() - start_time
size_after = os.path.getsize(filename)
delta = size_after - size_before
Expand Down
2 changes: 1 addition & 1 deletion emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -1581,7 +1581,7 @@ def setup_function_pointers(function_table_sigs):

def create_basic_funcs(function_table_sigs, invoke_function_names):
basic_funcs = shared.Settings.RUNTIME_FUNCS_TO_IMPORT
if shared.Settings.STACK_OVERFLOW_CHECK:
if shared.Settings.STACK_OVERFLOW_CHECK and not shared.Settings.MINIMAL_RUNTIME:
basic_funcs += ['abortStackOverflow']
if shared.Settings.EMTERPRETIFY:
basic_funcs += ['abortStackOverflowEmterpreter']
Expand Down
1 change: 1 addition & 0 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ LibraryManager.library = {
},

#if MINIMAL_RUNTIME
$abortStackOverflow__deps: ['$stackSave'],
$abortStackOverflow: function(allocSize) {
abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!');
},
Expand Down
2 changes: 2 additions & 0 deletions src/library_trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ var LibraryTracing = {
'stack_base': STACK_BASE,
'stack_top': STACKTOP,
'stack_max': STACK_MAX,
#if !MINIMAL_RUNTIME
'dynamic_base': DYNAMIC_BASE,
#endif
'dynamic_top': HEAP32[DYNAMICTOP_PTR>>2],
'total_memory': HEAP8.length
};
Expand Down
12 changes: 7 additions & 5 deletions src/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,10 +416,6 @@ function exportRuntime() {
'makeBigInt',
'dynCall',
'getCompilerSetting',
'stackSave',
'stackRestore',
'stackAlloc',
'establishStackSpace',
'print',
'printErr',
'getTempRet0',
Expand All @@ -431,12 +427,18 @@ function exportRuntime() {
if (!MINIMAL_RUNTIME) {
runtimeElements.push('Pointer_stringify');
runtimeElements.push('warnOnce');
runtimeElements.push('stackSave');
runtimeElements.push('stackRestore');
runtimeElements.push('stackAlloc');
runtimeElements.push('establishStackSpace');
}

if (STACK_OVERFLOW_CHECK) {
runtimeElements.push('writeStackCookie');
runtimeElements.push('checkStackCookie');
runtimeElements.push('abortStackOverflow');
if (!MINIMAL_RUNTIME) {
runtimeElements.push('abortStackOverflow');
}
}

if (USE_PTHREADS) {
Expand Down
8 changes: 4 additions & 4 deletions src/postamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ var imports = {
#endif
};

#if ASSERTIONS
if (!Module['wasm']) throw 'Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM';
#endif

#if DECLARE_ASM_MODULE_EXPORTS
/*** ASM_MODULE_EXPORTS_DECLARES ***/
#endif

#if ASSERTIONS
// In synchronous Wasm compilation mode, Module['wasm'] should contain a typed array of the Wasm object data.
if (!Module['wasm']) throw 'Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM';
#endif
WebAssembly.instantiate(Module['wasm'], imports).then(function(output) {
var asm = output.instance.exports;
#if DECLARE_ASM_MODULE_EXPORTS == 0
Expand Down
29 changes: 23 additions & 6 deletions src/preamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ function assert(condition, text) {
function abort(what) {
throw what;
}
function abortStackOverflow(allocSize) {
abort('Stack overflow when attempting to allocate ' + allocSize + ' bytes on the stack!');
}

var tempRet0 = 0;
var setTempRet0 = function(value) {
tempRet0 = value;
Expand Down Expand Up @@ -45,9 +43,6 @@ var GLOBAL_BASE = {{{ GLOBAL_BASE }}},
STACK_BASE = {{{ getQuoted('STACK_BASE') }}},
STACKTOP = STACK_BASE,
STACK_MAX = {{{ getQuoted('STACK_MAX') }}}
#if MEMORYPROFILER
, DYNAMIC_BASE = {{{ getQuoted('DYNAMIC_BASE') }}}
#endif
#if USES_DYNAMIC_ALLOC
, DYNAMICTOP_PTR = {{{ DYNAMICTOP_PTR }}};
#endif
Expand Down Expand Up @@ -103,6 +98,26 @@ assert({{{ WASM_MEM_MAX }}} % WASM_PAGE_SIZE == 0);
assert(buffer.byteLength === {{{ TOTAL_MEMORY }}});
#endif // ASSERTIONS

#if ALLOW_MEMORY_GROWTH
// In ALLOW_MEMORY_GROWTH, we need to be able to re-initialize the
// typed array buffer and heap views to the buffer whenever the heap
// is resized.
var HEAP8, HEAP16, HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32, HEAPF64;
function updateGlobalBufferAndViews(b) {
buffer = b;
HEAP8 = new Int8Array(b);
HEAP16 = new Int16Array(b);
HEAP32 = new Int32Array(b);
HEAPU8 = new Uint8Array(b);
HEAPU16 = new Uint16Array(b);
HEAPU32 = new Uint32Array(b);
HEAPF32 = new Float32Array(b);
HEAPF64 = new Float64Array(b);
}
updateGlobalBufferAndViews(buffer);
#else
// In non-ALLOW_MEMORY_GROWTH scenario, we only need to initialize
// the heap once, so optimize code size to do it statically here.
var HEAP8 = new Int8Array(buffer);
var HEAP16 = new Int16Array(buffer);
var HEAP32 = new Int32Array(buffer);
Expand All @@ -111,6 +126,7 @@ var HEAPU16 = new Uint16Array(buffer);
var HEAPU32 = new Uint32Array(buffer);
var HEAPF32 = new Float32Array(buffer);
var HEAPF64 = new Float64Array(buffer);
#endif

#if !WASM
HEAPU8.set(new Uint8Array(Module['mem']), GLOBAL_BASE);
Expand All @@ -135,6 +151,7 @@ var wasmTable = new WebAssembly.Table({
#endif // WASM

#include "runtime_stack_check.js"
#include "runtime_assertions.js"

#if ASSERTIONS
var runtimeInitialized = false;
Expand Down
16 changes: 14 additions & 2 deletions src/shell_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ if (ENVIRONMENT_IS_NODE) {
#if WASM
Module['wasm'] = fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.wasm');
#else
#if SEPARATE_ASM
eval(fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.asm.js')+'');
#endif
#if MEM_INIT_METHOD == 1
Module['mem'] = fs.readFileSync(__dirname + '/{{{ TARGET_BASENAME }}}.mem');
#endif
#endif
}
#endif

Expand Down Expand Up @@ -77,23 +81,31 @@ function ready() {

#if USE_PTHREADS

#if !MODULARIZE
// In MODULARIZE mode _scriptDir needs to be captured already at the very top of the page immediately when the page is parsed, so it is generated there
// before the page load. In non-MODULARIZE modes generate it here.
var _scriptDir = (typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined;
#endif

var ENVIRONMENT_IS_PTHREAD;
if (!ENVIRONMENT_IS_PTHREAD) ENVIRONMENT_IS_PTHREAD = false; // ENVIRONMENT_IS_PTHREAD=true will have been preset in pthread-main.js. Make it false in the main runtime thread.

if (typeof ENVIRONMENT_IS_PTHREAD === 'undefined') {
// ENVIRONMENT_IS_PTHREAD=true will have been preset in pthread-main.js. Make it false in the main runtime thread.
// N.B. this line needs to appear without 'var' keyword to avoid 'var hoisting' from occurring. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var)
ENVIRONMENT_IS_PTHREAD = false;
} else {
}
#if MODULARIZE
else {
var buffer = {{{EXPORT_NAME}}}.buffer;
var tempDoublePtr = {{{EXPORT_NAME}}}.tempDoublePtr;
var STATICTOP = {{{EXPORT_NAME}}}.STATICTOP;
var DYNAMIC_BASE = {{{EXPORT_NAME}}}.DYNAMIC_BASE;
var DYNAMICTOP_PTR = {{{EXPORT_NAME}}}.DYNAMICTOP_PTR;
var STACK_BASE = {{{EXPORT_NAME}}}.STACK_BASE;
var STACKTOP = {{{EXPORT_NAME}}}.STACKTOP;
var STACK_MAX = {{{EXPORT_NAME}}}.STACK_MAX;
}
#endif

var currentScriptUrl = typeof _scriptDir !== 'undefined' ? _scriptDir : ((typeof document !== 'undefined' && document.currentScript) ? document.currentScript.src : undefined);
#endif // USE_PTHREADS
Expand Down
103 changes: 78 additions & 25 deletions src/shell_minimal_runtime.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,98 @@
});
}

#if MODULARIZE
#if WASM
#if !MODULARIZE
var Module = {};
#endif

function revokeURL(url) {
URL.revokeObjectURL(url)
}

// Depending on the build flags that one uses, different files need to be downloaded
// to load the compiled page. What follows is a matrix of all different combinations that
// affect how code is downloaded. When developing your own shell file, you can copy the whole
// matrix, or just focus on a single/specific set of download schemes to use.

#if MODULARIZE && WASM
// Modularize + no streaming wasm compilation, no separate .mem init file
Promise.all([s('{{{ TARGET_BASENAME }}}.js'), b('{{{ TARGET_BASENAME }}}.wasm')]).then((r) => {
r[0]({ wasm: r[1] });
var js = r[0]; // Detour the JS code to a separate variable to avoid instantiating with 'r' as this to avoid strict ECMAScript/Firefox GC problems that cause a leak, see https://bugzilla.mozilla.org/show_bug.cgi?id=1540101
js({ wasm: r[1] });
});
#else
#if MEM_INIT_METHOD == 1
Promise.all([s('{{{ TARGET_BASENAME }}}.js'), s('{{{ TARGET_BASENAME }}}.asm.js'), b('{{{ TARGET_BASENAME }}}.mem')]).then((r) => {
r[0]({ asm: r[1], mem: r[2] });
#endif

#if MODULARIZE && !WASM && !SEPARATE_ASM && MEM_INIT_METHOD == 0
// Modularize + asm.js embedded in main runtime .js file, no separate .mem init file
s('{{{ TARGET_BASENAME }}}.js').then((r) => {
r();
});
#else
#endif

#if MODULARIZE && !WASM && !SEPARATE_ASM && MEM_INIT_METHOD == 1
// Modularize + asm.js embedded in main runtime .js file, separate .mem init file
Promise.all([s('{{{ TARGET_BASENAME }}}.js'), b('{{{ TARGET_BASENAME }}}.mem')]).then((r) => {
var js = r[0]; // Detour the JS code to a separate variable to avoid instantiating with 'r' as this to avoid strict ECMAScript/Firefox GC problems that cause a leak, see https://bugzilla.mozilla.org/show_bug.cgi?id=1540101
js({ mem: r[1] });
});
#endif

#if MODULARIZE && !WASM && SEPARATE_ASM && MEM_INIT_METHOD == 0
// Modularize + asm.js in its own file, no separate .mem init file
Promise.all([s('{{{ TARGET_BASENAME }}}.js'), s('{{{ TARGET_BASENAME }}}.asm.js')]).then((r) => {
r[0]({ asm: r[1] });
var js = r[0]; // Detour the JS code to a separate variable to avoid instantiating with 'r' as this to avoid strict ECMAScript/Firefox GC problems that cause a leak, see https://bugzilla.mozilla.org/show_bug.cgi?id=1540101
js({ asm: r[1] });
});
#endif // MEM_INIT_METHOD
#endif // WASM
#else // MODULARIZE
var Module = {};
#if WASM
#endif

#if MODULARIZE && !WASM && SEPARATE_ASM && MEM_INIT_METHOD == 1
// Modularize + asm.js in its own file, separate .mem init file
Promise.all([s('{{{ TARGET_BASENAME }}}.js'), s('{{{ TARGET_BASENAME }}}.asm.js'), b('{{{ TARGET_BASENAME }}}.mem')]).then((r) => {
var js = r[0]; // Detour the JS code to a separate variable to avoid instantiating with 'r' as this to avoid strict ECMAScript/Firefox GC problems that cause a leak, see https://bugzilla.mozilla.org/show_bug.cgi?id=1540101
js({ asm: r[1], mem: r[2] });
});
#endif

#if !MODULARIZE && WASM
// No modularize, no streaming wasm compilation, no separate .mem init file
Promise.all([b('{{{ TARGET_BASENAME }}}.js'), b('{{{ TARGET_BASENAME }}}.wasm')]).then((r) => {
Module.wasm = r[1];
var url = URL.createObjectURL(new Blob([r[0]], { type: 'application/javascript' }));
s(url).then(() => { URL.revokeObjectURL(url) });
s(url).then(() => { revokeURL(url) });
});
#else
#if MEM_INIT_METHOD == 1
Promise.all([b('{{{ TARGET_BASENAME }}}.js'), s('{{{ TARGET_BASENAME }}}.asm.js'), b('{{{ TARGET_BASENAME }}}.mem')]).then((r) => {
Module.mem = r[2];
#endif

#if !MODULARIZE && !WASM && !SEPARATE_ASM && MEM_INIT_METHOD == 0
// No modularize, asm.js embedded in main runtime .js file, no separate .mem init file
s('{{{ TARGET_BASENAME }}}.js');
#endif

#if !MODULARIZE && !WASM && !SEPARATE_ASM && MEM_INIT_METHOD == 1
// No modularize, asm.js embedded in main runtime .js file, separate .mem init file
Promise.all([b('{{{ TARGET_BASENAME }}}.js'), b('{{{ TARGET_BASENAME }}}.mem')]).then((r) => {
Module.mem = r[1];
var url = URL.createObjectURL(new Blob([r[0]], { type: 'application/javascript' }));
s(url).then(() => { URL.revokeObjectURL(url) });
s(url).then(() => { revokeURL(url) });
});
#else
#endif

#if !MODULARIZE && !WASM && SEPARATE_ASM && MEM_INIT_METHOD == 0
// No modularize, asm.js in its own file, no separate .mem init file
Promise.all([b('{{{ TARGET_BASENAME }}}.js'), s('{{{ TARGET_BASENAME }}}.asm.js')]).then((r) => {
var url = URL.createObjectURL(new Blob([r[0]], { type: 'application/javascript' }));
s(url).then(() => { URL.revokeObjectURL(url) });
s(url).then(() => { revokeURL(url) });
});
#endif

#if !MODULARIZE && !WASM && SEPARATE_ASM && MEM_INIT_METHOD == 1
// No modularize, asm.js in its own file, separate .mem init file
Promise.all([b('{{{ TARGET_BASENAME }}}.js'), s('{{{ TARGET_BASENAME }}}.asm.js'), b('{{{ TARGET_BASENAME }}}.mem')]).then((r) => {
Module.mem = r[2];
var url = URL.createObjectURL(new Blob([r[0]], { type: 'application/javascript' }));
s(url).then(() => { revokeURL(url) });
});
#endif // MEM_INIT_METHOD
#endif // WASM
#endif // MODULARIZE
#endif

</script>
</body>
</html>
Loading