From 8f8ab99505b329412ef78a4e224922a1dc6f8a4e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 14 Aug 2020 20:11:58 -0700 Subject: [PATCH 1/3] Move emscripten_stack_get_base/end into native code With this change, we no longer need any JavaScript variable to track the state of the stack. The base and max as well as the current stack pointer are all managed in native code. The following JavaScript variable a no longer present in the library code: STACK_BASE -> emscripten_stack_get_base() STACK_MAX -> emscripten_stack_get_end() STACKTOP -> emscripten_stack_get_current() TOTAL_STACK -> emscripten_stack_get_base() - emscripten_stack_get_end() --- ChangeLog.md | 13 ++++ emcc.py | 27 +++++-- emscripten.py | 10 ++- src/library.js | 6 -- src/library_async.js | 11 +-- src/library_pthread.js | 6 +- src/library_pthread_stub.js | 4 +- src/library_stack.js | 10 +-- src/library_trace.js | 6 +- src/memoryprofiler.js | 45 ++++++------ src/postamble.js | 9 +++ src/postamble_minimal.js | 3 +- src/preamble.js | 25 +------ src/preamble_minimal.js | 9 +-- src/runtime_safe_heap.js | 4 +- src/runtime_stack_check.js | 12 +-- src/shell_minimal.js | 3 - src/shell_pthreads.js | 3 +- system/include/emscripten/stack.h | 21 ++++-- .../sanitizer_common/sanitizer_emscripten.cpp | 5 +- system/lib/compiler-rt/stack_limits.S | 73 +++++++++++++++++++ system/lib/compiler-rt/stack_ops.s | 21 ------ system/lib/libc/emscripten_scan_stack.c | 8 ++ system/lib/pthread/library_pthread.c | 10 ++- tests/other/metadce/hello_world.exports | 3 + tests/other/metadce/hello_world.funcs | 3 + tests/other/metadce/minimal.exports | 3 + tests/other/metadce/minimal.funcs | 3 + tests/other/test_proxy_to_pthread_stack.c | 1 + tests/pthread/test_pthread_stack_bounds.cpp | 9 +-- tests/test_browser.py | 2 +- tests/test_core.py | 10 ++- tests/test_other.py | 2 +- tools/system_libs.py | 2 + 34 files changed, 231 insertions(+), 151 deletions(-) create mode 100644 system/lib/compiler-rt/stack_limits.S create mode 100644 system/lib/libc/emscripten_scan_stack.c diff --git a/ChangeLog.md b/ChangeLog.md index fe16e915f870e..29128b6fe0ce6 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -23,6 +23,19 @@ Current Trunk - dlopen, in conformace with the spec, now checks that one of either RTDL_LAZY or RTDL_NOW flags ar set. Previously, it was possible set nether of these without generating an error. +- Support added for INPUT_JS_VERSION and OUTPUT_JS_VERSION settings. These + control is/when we use the closure compiler to transpile the resulting + output. If you use `--closure` compiler today we no longer default to + accepting `EMCASCRIPT_2020`. If you want to use any langueage features + more recent than `ECMASCRIPT5` in your JS library code or inline JS assembly + code then you now need to pass a more recent version on the command line. + e.g. `-sINPUT_JS_VERSION=ECMASCRIPT2015`. See # +- Stack state is no longer stored in JavaScript. The following variables have + been replaced with native functions in ``: + - STACK_BASE + - STACK_MAX + - STACKTOP + - TOTAL_STACK 2.0.8: 10/24/2020 ----------------- diff --git a/emcc.py b/emcc.py index 59f0739300fc5..aedeccda8a89f 100755 --- a/emcc.py +++ b/emcc.py @@ -1351,13 +1351,19 @@ def filter_out_duplicate_dynamic_libs(inputs): shared.Settings.EXPORTED_FUNCTIONS += ['_sbrk'] if shared.Settings.MEMORYPROFILER: - shared.Settings.EXPORTED_FUNCTIONS += ['___heap_base'] + shared.Settings.EXPORTED_FUNCTIONS += ['___heap_base', + '_emscripten_stack_get_base', + '_emscripten_stack_get_end', + '_emscripten_stack_get_current'] if shared.Settings.ASYNCIFY: # See: https://github.com/emscripten-core/emscripten/issues/12065 # See: https://github.com/emscripten-core/emscripten/issues/12066 shared.Settings.USE_LEGACY_DYNCALLS = 1 shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$getDynCaller'] + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_get_base', + '_emscripten_stack_get_end', + '_emscripten_stack_set_limits'] # Reconfigure the cache now that settings have been applied. Some settings # such as LTO and SIDE_MODULE/MAIN_MODULE effect which cache directory we use. @@ -1398,6 +1404,13 @@ def filter_out_duplicate_dynamic_libs(inputs): if shared.Settings.STACK_OVERFLOW_CHECK: shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$abortStackOverflow'] shared.Settings.EXPORTED_RUNTIME_METHODS += ['writeStackCookie', 'checkStackCookie'] + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_get_end', '_emscripten_stack_get_free'] + if shared.Settings.RELOCATABLE: + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_set_limits'] + else: + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_init'] + if shared.Settings.STACK_OVERFLOW_CHECK == 2: + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_get_base'] if shared.Settings.MODULARIZE: assert not options.proxy_to_worker, '-s MODULARIZE=1 is not compatible with --proxy-to-worker (if you want to run in a worker with -s MODULARIZE=1, you likely want to do the worker side setup manually)' @@ -1539,7 +1552,7 @@ def filter_out_duplicate_dynamic_libs(inputs): if shared.Settings.SAFE_HEAP: # SAFE_HEAP check includes calling emscripten_get_sbrk_ptr() from wasm - shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_get_sbrk_ptr'] + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_get_sbrk_ptr', '_emscripten_stack_get_base'] shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$unSign'] if not shared.Settings.DECLARE_ASM_MODULE_EXPORTS: @@ -1568,7 +1581,8 @@ def filter_out_duplicate_dynamic_libs(inputs): shared.Settings.EXPORTED_FUNCTIONS += [ '_emscripten_get_global_libc', '___pthread_tsd_run_dtors', 'registerPthreadPtr', '_pthread_self', - '___emscripten_pthread_data_constructor', '_emscripten_futex_wake'] + '___emscripten_pthread_data_constructor', '_emscripten_futex_wake', + '_emscripten_stack_set_limits'] # set location of worker.js shared.Settings.PTHREAD_WORKER_FILE = unsuffixed(os.path.basename(target)) + '.worker.js' @@ -1641,10 +1655,6 @@ def include_and_export(name): if not shared.Settings.MINIMAL_RUNTIME: shared.Settings.EXPORTED_RUNTIME_METHODS += ['ExitStatus'] - # stack check: - if shared.Settings.STACK_OVERFLOW_CHECK: - shared.Settings.EXPORTED_RUNTIME_METHODS += ['writeStackCookie', 'checkStackCookie'] - if shared.Settings.LINKABLE: exit_with_error('-s LINKABLE=1 is not supported with -s USE_PTHREADS>0!') if shared.Settings.SIDE_MODULE: @@ -1890,6 +1900,9 @@ def include_and_export(name): cflags.append('-D__EMSCRIPTEN_TRACING__=1') if shared.Settings.ALLOW_MEMORY_GROWTH: shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['emscripten_trace_report_memory_layout'] + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_stack_get_current', + '_emscripten_stack_get_base', + '_emscripten_stack_get_end'] if shared.Settings.USE_PTHREADS: newargs.append('-pthread') diff --git a/emscripten.py b/emscripten.py index d22d5b56df7e7..4002ac61a1fc7 100644 --- a/emscripten.py +++ b/emscripten.py @@ -216,10 +216,10 @@ def __init__(self, metadata): def apply_memory(js, memory): # Apply the statically-at-compile-time computed memory locations. # Write it all out - js = js.replace('{{{ STACK_BASE }}}', str(memory.stack_base)) - js = js.replace('{{{ STACK_MAX }}}', str(memory.stack_max)) if shared.Settings.RELOCATABLE: js = js.replace('{{{ HEAP_BASE }}}', str(memory.dynamic_base)) + js = js.replace('{{{ STACK_BASE }}}', str(memory.stack_base)) + js = js.replace('{{{ STACK_MAX }}}', str(memory.stack_max)) logger.debug('stack_base: %d, stack_max: %d, dynamic_base: %d, static bump: %d', memory.stack_base, memory.stack_max, memory.dynamic_base, memory.static_bump) return js @@ -419,6 +419,7 @@ def emscript(infile, outfile_js, memfile, temp_files, DEBUG): pre += '\n' + global_initializers + '\n' pre = apply_memory(pre, memory) + post = apply_memory(post, memory) pre = apply_static_code_hooks(pre) # In regular runtime, atinits etc. exist in the preamble part post = apply_static_code_hooks(post) # In MINIMAL_RUNTIME, atinit exists in the postamble part @@ -771,7 +772,10 @@ def make_export_wrappers(exports, delay_assignment): wrappers = [] for name in exports: mangled = asmjs_mangle(name) - if shared.Settings.ASSERTIONS: + # 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. + if shared.Settings.ASSERTIONS and not name.startswith('emscripten_stack_'): # With assertions enabled we create a wrapper that are calls get routed through, for # the lifetime of the program. if delay_assignment: diff --git a/src/library.js b/src/library.js index 3340bdb8bedc2..2ae663005a4b3 100644 --- a/src/library.js +++ b/src/library.js @@ -3653,12 +3653,6 @@ LibraryManager.library = { // special runtime support - emscripten_scan_stack: function(func) { - var base = STACK_BASE; // TODO verify this is right on pthreads - var end = stackSave(); - {{{ makeDynCall('vii', 'func') }}}(Math.min(base, end), Math.max(base, end)); - }, - // Used by wasm-emscripten-finalize to implement STACK_OVERFLOW_CHECK __handle_stack_overflow: function() { abort('stack overflow') diff --git a/src/library_async.js b/src/library_async.js index b55e7cae84d11..33b4a0eee04ad 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -381,11 +381,12 @@ mergeInto(LibraryManager.library, { * NOTE: This function is the asynchronous part of emscripten_fiber_swap. */ finishContextSwitch: function(newFiber) { - STACK_BASE = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'i32') }}}; - STACK_MAX = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'i32') }}}; + var stack_base = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'i32') }}}; + var stack_max = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'i32') }}}; + _emscripten_stack_set_limits(stack_base, stack_max); #if STACK_OVERFLOW_CHECK >= 2 - Module['___set_stack_limits'](STACK_BASE, STACK_MAX); + Module['___set_stack_limits'](stack_base, stack_max); #endif stackRestore({{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'i32') }}}); @@ -440,8 +441,8 @@ mergeInto(LibraryManager.library, { emscripten_fiber_init_from_current_context__sig: 'vii', emscripten_fiber_init_from_current_context__deps: ['$Asyncify'], emscripten_fiber_init_from_current_context: function(fiber, asyncStack, asyncStackSize) { - {{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'STACK_BASE', 'i32') }}}; - {{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'STACK_MAX', 'i32') }}}; + {{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_base, '_emscripten_stack_get_base()', 'i32') }}}; + {{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_limit, '_emscripten_stack_get_end()', 'i32') }}}; {{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.entry, 0, 'i32') }}}; var asyncifyData = fiber + {{{ C_STRUCTS.emscripten_fiber_s.asyncify_data }}}; diff --git a/src/library_pthread.js b/src/library_pthread.js index 7a84f872940a7..fa4a95fc8f6fc 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1462,11 +1462,9 @@ var LibraryPThread = { }, $establishStackSpace: function(stackTop, stackMax) { - STACK_BASE = STACKTOP = stackTop; - STACK_MAX = stackMax; - + _emscripten_stack_set_limits(stackTop, stackMax); #if STACK_OVERFLOW_CHECK >= 2 - ___set_stack_limits(STACK_BASE, STACK_MAX); + ___set_stack_limits(_emscripten_stack_get_base(), _emscripten_stack_get_end()); #endif // Call inside wasm module to set up the stack frame for this pthread in asm.js/wasm module scope diff --git a/src/library_pthread_stub.js b/src/library_pthread_stub.js index 023d90b416657..36466e1a4639c 100644 --- a/src/library_pthread_stub.js +++ b/src/library_pthread_stub.js @@ -59,8 +59,8 @@ var LibraryPThreadStub = { void **restrict stackaddr, size_t *restrict stacksize); */ /*FIXME: assumes that there is only one thread, and that attr is the current thread*/ - {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}}; - {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}; + {{{ makeSetValue('stackaddr', '0', '_emscripten_stack_get_base()', 'i8*') }}}; + {{{ makeSetValue('stacksize', '0', TOTAL_STACK, 'i32') }}}; return 0; }, pthread_attr_getdetachstate: function(attr, detachstate) { diff --git a/src/library_stack.js b/src/library_stack.js index e87b4046b1a67..b7ceac5e7e879 100644 --- a/src/library_stack.js +++ b/src/library_stack.js @@ -5,16 +5,8 @@ */ mergeInto(LibraryManager.library, { - emscripten_stack_get_base: function() { - return STACK_BASE; - }, - emscripten_stack_get_end: function() { - // TODO(sbc): rename STACK_MAX -> STACK_END? - return STACK_MAX; - }, - $abortStackOverflow__import: true, $abortStackOverflow: function(allocSize) { - abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!'); + abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (_emscripten_stack_get_free() + allocSize) + ' bytes available!'); }, }); diff --git a/src/library_trace.js b/src/library_trace.js index e7ee2a9a2a501..272eb10a3b9aa 100644 --- a/src/library_trace.js +++ b/src/library_trace.js @@ -263,9 +263,9 @@ var LibraryTracing = { if (EmscriptenTrace.postEnabled) { var memory_layout = { 'static_base': {{{ GLOBAL_BASE }}}, - 'stack_base': STACK_BASE, - 'stack_top': STACKTOP, - 'stack_max': STACK_MAX, + 'stack_base': _emscripten_stack_get_base(), + 'stack_top': _emscripten_stack_get_current(), + 'stack_max': _emscripten_stack_get_end(), 'dynamic_top': _sbrk(), 'total_memory': HEAP8.length }; diff --git a/src/memoryprofiler.js b/src/memoryprofiler.js index 0c8587b678ca1..833494e8432e7 100644 --- a/src/memoryprofiler.js +++ b/src/memoryprofiler.js @@ -70,7 +70,7 @@ var emscriptenMemoryProfiler = { totalTimesMallocCalled: 0, totalTimesFreeCalled: 0, - // Tracks the highest seen location of the STACKTOP variable. + // Tracks the highest seen location of the stack pointer. stackTopWatermark: Infinity, // The canvas DOM element to which to draw the allocation map. @@ -161,8 +161,10 @@ var emscriptenMemoryProfiler = { }, recordStackWatermark: function() { - var self = emscriptenMemoryProfiler; - self.stackTopWatermark = Math.min(self.stackTopWatermark, STACKTOP); + if (runtimeInitialized) { + var self = emscriptenMemoryProfiler; + self.stackTopWatermark = Math.min(self.stackTopWatermark, _emscripten_stack_get_current()); + } }, onMalloc: function onMalloc(ptr, size) { @@ -485,28 +487,25 @@ var emscriptenMemoryProfiler = { self.canvas.width = document.documentElement.clientWidth - 32; } + if (!runtimeInitialized) { + return; + } + var stackBase = _emscripten_stack_get_base(); + var stackMax = _emscripten_stack_get_end(); + var stackCurrent = _emscripten_stack_get_current(); var width = (nBits(HEAP8.length) + 3) / 4; // Pointer 'word width' var html = 'Total HEAP size: ' + self.formatBytes(HEAP8.length) + '.'; - html += '
' + colorBar('#202020') + 'STATIC memory area size: ' + self.formatBytes(Math.min(STACK_BASE, STACK_MAX) - {{{ GLOBAL_BASE }}}); + html += '
' + colorBar('#202020') + 'STATIC memory area size: ' + self.formatBytes(stackMax - {{{ GLOBAL_BASE }}}); html += '. {{{ GLOBAL_BASE }}}: ' + toHex({{{ GLOBAL_BASE }}}, width); - html += '
' + colorBar('#FF8080') + 'STACK memory area size: ' + self.formatBytes(Math.abs(STACK_MAX - STACK_BASE)); - html += '. STACK_BASE: ' + toHex(STACK_BASE, width); - html += '. STACKTOP: ' + toHex(STACKTOP, width); - html += '. STACK_MAX: ' + toHex(STACK_MAX, width) + '.'; - html += '
STACK memory area used now (should be zero): ' + self.formatBytes(STACKTOP - STACK_BASE) + '.' + colorBar('#FFFF00') + ' STACK watermark highest seen usage (approximate lower-bound!): ' + self.formatBytes(Math.abs(self.stackTopWatermark - STACK_BASE)); + html += '
' + colorBar('#FF8080') + 'STACK memory area size: ' + self.formatBytes(stackBase - stackMax); + html += '. STACK_BASE: ' + toHex(stackBase, width); + html += '. STACKTOP: ' + toHex(stackCurrent, width); + html += '. STACK_MAX: ' + toHex(stackMax, width) + '.'; + html += '
STACK memory area used now (should be zero): ' + self.formatBytes(stackBase - stackCurrent) + '.' + colorBar('#FFFF00') + ' STACK watermark highest seen usage (approximate lower-bound!): ' + self.formatBytes(stackBase - self.stackTopWatermark); - if (runtimeInitialized) { - // During startup sbrk may not be defined yet. Ideally we should probably - // refactor memoryprofiler so that it only gets here after compiled code is - // ready to be called. For now, if the runtime is not yet initialized, - // assume the brk is right after the stack. - var heap_base = Module['___heap_base']; - var heap_end = _sbrk(); - } else { - var heap_base = STACK_BASE; - var heap_end = STACK_BASE; - } + var heap_base = Module['___heap_base']; + var heap_end = _sbrk(); html += "
DYNAMIC memory area size: " + self.formatBytes(heap_end - heap_base); html += ". start: " + toHex(heap_base, width); html += ". end: " + toHex(heap_end, width) + "."; @@ -525,13 +524,13 @@ var emscriptenMemoryProfiler = { self.drawContext.fillRect(0, 0, self.canvas.width, self.canvas.height); self.drawContext.fillStyle = "#FF8080"; - self.fillLine(STACK_BASE, STACK_MAX); + self.fillLine(stackMax, stackBase); self.drawContext.fillStyle = "#FFFF00"; - self.fillLine(Math.min(STACK_BASE, self.stackTopWatermark), Math.max(STACK_BASE, self.stackTopWatermark)); + self.fillLine(self.stackTopWatermark, stackBase); self.drawContext.fillStyle = "#FF0000"; - self.fillLine(Math.min(STACK_BASE, STACKTOP), Math.max(STACK_BASE, STACKTOP)); + self.fillLine(stackCurrent, stackBase); self.drawContext.fillStyle = "#70FF70"; self.fillLine(heap_base, heap_end); diff --git a/src/postamble.js b/src/postamble.js index d83d2ead0df44..8f0c708138b2b 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -239,6 +239,15 @@ function run(args) { } #if STACK_OVERFLOW_CHECK + // This is normally called automatically during __wasm_call_ctors but need to + // get these values before even running any of the ctors so we call it redundantly + // here. + // TODO(sbc): Move writeStackCookie to native to to avoid this. +#if RELOCATABLE + _emscripten_stack_set_limits({{{ getQuoted('STACK_BASE') }}}, {{{ getQuoted('STACK_MAX') }}}); +#else + _emscripten_stack_init(); +#endif writeStackCookie(); #endif diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 9f999844cf779..03d70a2161011 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -14,7 +14,7 @@ function run() { #endif #if STACK_OVERFLOW_CHECK >= 2 - ___set_stack_limits(STACK_BASE, STACK_MAX); + ___set_stack_limits(_emscripten_stack_get_base(), _emscripten_stack_get_end()); #endif #if PROXY_TO_PTHREAD @@ -77,6 +77,7 @@ function initRuntime(asm) { #endif #if STACK_OVERFLOW_CHECK + _emscripten_stack_init(); writeStackCookie(); #endif diff --git a/src/preamble.js b/src/preamble.js index 9e54d0f811ec4..09b1c2341905b 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -281,17 +281,8 @@ function updateGlobalBufferAndViews(buf) { Module['HEAPF64'] = HEAPF64 = new Float64Array(buf); } -var STACK_BASE = {{{ getQuoted('STACK_BASE') }}}, - STACKTOP = STACK_BASE, - STACK_MAX = {{{ getQuoted('STACK_MAX') }}}; - - -#if ASSERTIONS -assert(STACK_BASE % 16 === 0, 'stack must start aligned'); -#endif - #if RELOCATABLE -var __stack_pointer = new WebAssembly.Global({value: 'i32', mutable: true}, STACK_BASE); +var __stack_pointer = new WebAssembly.Global({value: 'i32', mutable: true}, {{{ getQuoted('STACK_BASE') }}}); // To support such allocations during startup, track them on __heap_base and // then when the main module is loaded it reads that value and uses it to @@ -301,18 +292,6 @@ var __stack_pointer = new WebAssembly.Global({value: 'i32', mutable: true}, STAC Module['___heap_base'] = {{{ getQuoted('HEAP_BASE') }}}; #endif // RELOCATABLE -#if USE_PTHREADS -if (ENVIRONMENT_IS_PTHREAD) { - // At the 'load' stage of Worker startup, we are just loading this script - // but not ready to run yet. At 'run' we receive proper values for the stack - // etc. and can launch a pthread. Set some fake values there meanwhile to - // catch bugs, then set the real values in establishStackSpace later. -#if ASSERTIONS || STACK_OVERFLOW_CHECK >= 2 - STACK_MAX = STACKTOP = STACK_MAX = 0x7FFFFFFF; -#endif -} -#endif - var TOTAL_STACK = {{{ TOTAL_STACK }}}; #if ASSERTIONS if (Module['TOTAL_STACK']) assert(TOTAL_STACK === Module['TOTAL_STACK'], 'the stack size can no longer be determined at runtime') @@ -402,7 +381,7 @@ function initRuntime() { #endif runtimeInitialized = true; #if STACK_OVERFLOW_CHECK >= 2 - Module['___set_stack_limits'](STACK_BASE, STACK_MAX); + Module['___set_stack_limits'](_emscripten_stack_get_base(), _emscripten_stack_get_end()); #endif {{{ getQuoted('ATINITS') }}} callRuntimeCallbacks(__ATINIT__); diff --git a/src/preamble_minimal.js b/src/preamble_minimal.js index 1793d6a27600e..bf3e87ab789d4 100644 --- a/src/preamble_minimal.js +++ b/src/preamble_minimal.js @@ -59,12 +59,6 @@ Module['wasm'] = base64Decode('{{{ getQuoted("WASM_BINARY_DATA") }}}'); if (!ENVIRONMENT_IS_PTHREAD) { #endif -var TOTAL_STACK = {{{ TOTAL_STACK }}}, - STACK_BASE = {{{ getQuoted('STACK_BASE') }}}, - STACKTOP = STACK_BASE, - STACK_MAX = {{{ getQuoted('STACK_MAX') }}} - ; - #if ALLOW_MEMORY_GROWTH && MAXIMUM_MEMORY != -1 var wasmMaximumMemory = {{{ MAXIMUM_MEMORY >>> 16 }}}; #else @@ -96,8 +90,7 @@ var WASM_PAGE_SIZE = {{{ WASM_PAGE_SIZE }}}; #if USE_PTHREADS if (!ENVIRONMENT_IS_PTHREAD) { #endif -assert(STACK_BASE % 16 === 0, 'stack must start aligned to 16 bytes, STACK_BASE==' + STACK_BASE); -assert({{{ INITIAL_MEMORY }}} >= TOTAL_STACK, 'INITIAL_MEMORY should be larger than TOTAL_STACK, was ' + {{{ INITIAL_MEMORY }}} + '! (TOTAL_STACK=' + TOTAL_STACK + ')'); +assert({{{ INITIAL_MEMORY }}} >= {{{ TOTAL_STACK }}}, 'INITIAL_MEMORY should be larger than TOTAL_STACK, was ' + {{{ INITIAL_MEMORY }}} + '! (TOTAL_STACK=' + {{{ TOTAL_STACK }}} + ')'); assert({{{ INITIAL_MEMORY }}} % WASM_PAGE_SIZE === 0); #if MAXIMUM_MEMORY != -1 assert({{{ MAXIMUM_MEMORY }}} % WASM_PAGE_SIZE == 0); diff --git a/src/runtime_safe_heap.js b/src/runtime_safe_heap.js index df648bdb8bdb8..f545b5930402f 100644 --- a/src/runtime_safe_heap.js +++ b/src/runtime_safe_heap.js @@ -111,7 +111,7 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { if (runtimeInitialized) { var brk = _sbrk() >>> 0; if (dest + bytes > brk) abort('segmentation fault, exceeded the top of the available dynamic heap when storing ' + bytes + ' bytes to address ' + dest + '. DYNAMICTOP=' + brk); - assert(brk >= STACK_BASE); // sbrk-managed memory must be above the stack + assert(brk >= _emscripten_stack_get_base()); // sbrk-managed memory must be above the stack assert(brk <= HEAP8.length); } setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); @@ -131,7 +131,7 @@ function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) { if (runtimeInitialized) { var brk = _sbrk() >>> 0; if (dest + bytes > brk) abort('segmentation fault, exceeded the top of the available dynamic heap when loading ' + bytes + ' bytes from address ' + dest + '. DYNAMICTOP=' + brk); - assert(brk >= STACK_BASE); // sbrk-managed memory must be above the stack + assert(brk >= _emscripten_stack_get_base()); // sbrk-managed memory must be above the stack assert(brk <= HEAP8.length); } var type = getSafeHeapType(bytes, isFloat); diff --git a/src/runtime_stack_check.js b/src/runtime_stack_check.js index 97a848cbf0c8e..879b631fb16e1 100644 --- a/src/runtime_stack_check.js +++ b/src/runtime_stack_check.js @@ -7,12 +7,13 @@ #if STACK_OVERFLOW_CHECK // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. function writeStackCookie() { + var max = _emscripten_stack_get_end(); #if ASSERTIONS - assert((STACK_MAX & 3) == 0); + assert((max & 3) == 0); #endif // The stack grows downwards - HEAPU32[(STACK_MAX >> 2)+1] = 0x2135467; - HEAPU32[(STACK_MAX >> 2)+2] = 0x89BACDFE; + HEAPU32[(max >> 2)+1] = 0x2135467; + HEAPU32[(max >> 2)+2] = 0x89BACDFE; #if !USE_ASAN && !SAFE_HEAP // ASan and SAFE_HEAP check address 0 themselves // Also test the global address 0 for integrity. HEAP32[0] = 0x63736d65; /* 'emsc' */ @@ -23,8 +24,9 @@ function checkStackCookie() { #if !MINIMAL_RUNTIME if (ABORT) return; #endif - var cookie1 = HEAPU32[(STACK_MAX >> 2)+1]; - var cookie2 = HEAPU32[(STACK_MAX >> 2)+2]; + var max = _emscripten_stack_get_end(); + var cookie1 = HEAPU32[(max >> 2)+1]; + var cookie2 = HEAPU32[(max >> 2)+2]; if (cookie1 != 0x2135467 || cookie2 != 0x89BACDFE) { abort('Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x' + cookie2.toString(16) + ' ' + cookie1.toString(16)); } diff --git a/src/shell_minimal.js b/src/shell_minimal.js index d132e5906f6cd..2f3597ea712f5 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -143,9 +143,6 @@ var ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_PTHREAD = typeof importScripts === 'f #if MODULARIZE if (ENVIRONMENT_IS_WORKER) { var buffer = {{{EXPORT_NAME}}}.buffer; - var STACK_BASE = {{{EXPORT_NAME}}}.STACK_BASE; - var STACKTOP = {{{EXPORT_NAME}}}.STACKTOP; - var STACK_MAX = {{{EXPORT_NAME}}}.STACK_MAX; } #endif diff --git a/src/shell_pthreads.js b/src/shell_pthreads.js index 16be15eae80d5..e909409d5e842 100644 --- a/src/shell_pthreads.js +++ b/src/shell_pthreads.js @@ -14,7 +14,6 @@ var ENVIRONMENT_IS_PTHREAD = Module['ENVIRONMENT_IS_PTHREAD'] || false; if (ENVIRONMENT_IS_PTHREAD) { // Grab imports from the pthread to local scope. buffer = Module['buffer']; - // Note that not all runtime fields are imported above. Values for STACK_BASE, STACKTOP and STACK_MAX are not yet known at worker.js load time. - // These will be filled in at pthread startup time (the 'run' message for a pthread - pthread start establishes the stack frame) + // Note that not all runtime fields are imported above } diff --git a/system/include/emscripten/stack.h b/system/include/emscripten/stack.h index 03165bcfada22..36060a6c1d40d 100644 --- a/system/include/emscripten/stack.h +++ b/system/include/emscripten/stack.h @@ -7,6 +7,9 @@ #pragma once +#include +#include + // API that gives access to introspecting the Wasm data stack. Build with // -lstack.js to use this API. @@ -26,17 +29,21 @@ uintptr_t emscripten_stack_get_base(void); // emscripten_stack_get_base(). uintptr_t emscripten_stack_get_end(void); +// Setup internal base/end values based on the initial values that were either +// set at compile time (in static linking) or instantiations time (for dynamic +// linking). +void emscripten_stack_init(void); + +// Sets the internal values reported by emscripten_stack_get_base and +// emscripten_stack_get_end. This should only used by low level libraries +// such as asyncify fibres. +void emscripten_stack_set_limits(void* base, void* end); + // Returns the current stack pointer. uintptr_t emscripten_stack_get_current(void); -// Setup internal state such that emscripten_stack_get_free can be used. -// This needed until we can fix: -// https://github.com/emscripten-core/emscripten/issues/11773 -void emscripten_stack_init(void); - // Returns the number of free bytes left on the stack. This is required to be -// fast so that it can be called frequently and requires `emscripten_stack_init` -// to be called before it will return accurate values. +// fast so that it can be called frequently. size_t emscripten_stack_get_free(void); #ifdef __cplusplus diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp index 16a16be9c789f..4c52ff5294db3 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp @@ -22,6 +22,7 @@ #if SANITIZER_EMSCRIPTEN #include +#include namespace __sanitizer { @@ -89,8 +90,8 @@ uptr internal_munmap(void *addr, uptr length) { void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom) { - *stack_top = EM_ASM_INT({ return STACK_BASE; }); - *stack_bottom = EM_ASM_INT({ return STACK_MAX; }); + *stack_top = emscripten_stack_get_base(); + *stack_bottom = emscripten_stack_get_end(); } char *fake_argv[] = {0}; diff --git a/system/lib/compiler-rt/stack_limits.S b/system/lib/compiler-rt/stack_limits.S new file mode 100644 index 0000000000000..e17555b76b686 --- /dev/null +++ b/system/lib/compiler-rt/stack_limits.S @@ -0,0 +1,73 @@ +.globl emscripten_stack_init +.globl emscripten_stack_set_limits +.globl emscripten_stack_get_free +.globl emscripten_stack_get_base +.globl emscripten_stack_get_end + +.globaltype __stack_pointer, i32 + +# TODO(sbc): It would be nice if these we initialized directly +# using i32.const rather than using the `emscripten_stack_init` +.globaltype __stack_end, i32 +__stack_end: +.globaltype __stack_base, i32 +__stack_base: + +emscripten_stack_get_base: + .functype emscripten_stack_get_base () -> (i32) + global.get __stack_base + end_function + +emscripten_stack_get_end: + .functype emscripten_stack_get_end () -> (i32) + global.get __stack_end + end_function + +emscripten_stack_init: + # Initialize __stack_end and __stack_base. + # This must be called before emscripten_stack_get_end, + # emscripten_stack_get_base, or emscripten_stack_get_free are called + .functype emscripten_stack_init () -> () + + # The heap base is where the stack grown down from. +#ifdef __PIC__ + global.get __heap_base@GOT +#else + i32.const __heap_base +#endif + global.set __stack_base + + # The end of stack data is the limit of the stack growth +#ifdef __PIC__ + global.get __data_end@GOT +#else + i32.const __data_end +#endif + # Align up to 16 bytes + i32.const 0xf + i32.add + i32.const -0x10 + i32.and + global.set __stack_end + + end_function + +emscripten_stack_set_limits: + .functype emscripten_stack_set_limits (i32, i32) -> () + local.get 0 + global.set __stack_base + local.get 1 + global.set __stack_end + end_function + +emscripten_stack_get_free: + .functype emscripten_stack_get_free () -> (i32) + global.get __stack_pointer + global.get __stack_end + i32.sub + end_function + +# Add emscripten_stack_init to static ctors +.section .init_array.1,"",@ +.p2align 2 +.int32 emscripten_stack_init diff --git a/system/lib/compiler-rt/stack_ops.s b/system/lib/compiler-rt/stack_ops.s index 6e290bd6b284c..5ac175b55fc1a 100644 --- a/system/lib/compiler-rt/stack_ops.s +++ b/system/lib/compiler-rt/stack_ops.s @@ -1,9 +1,7 @@ .globl stackSave .globl stackRestore .globl stackAlloc -.globl emscripten_stack_init .globl emscripten_stack_get_current -.globl emscripten_stack_get_free .globaltype __stack_pointer, i32 @@ -39,22 +37,3 @@ emscripten_stack_get_current: global.get __stack_pointer end_function -.functype emscripten_stack_get_end () -> (i32) -.functype emscripten_stack_get_base () -> (i32) -.globaltype __stack_end, i32 -__stack_end: - -emscripten_stack_init: - # initialize __stack_end such that future calls to emscripten_stack_get_free - # use the correct value. - .functype emscripten_stack_init () -> () - call emscripten_stack_get_end - global.set __stack_end - end_function - -emscripten_stack_get_free: - .functype emscripten_stack_get_free () -> (i32) - global.get __stack_pointer - global.get __stack_end - i32.sub - end_function diff --git a/system/lib/libc/emscripten_scan_stack.c b/system/lib/libc/emscripten_scan_stack.c new file mode 100644 index 0000000000000..7a7d2d26e49e7 --- /dev/null +++ b/system/lib/libc/emscripten_scan_stack.c @@ -0,0 +1,8 @@ +#include +#include + +void emscripten_scan_stack(em_scan_func func) { + uintptr_t base = emscripten_stack_get_base(); + uintptr_t end = emscripten_stack_get_current(); + func((void*)end, (void*)base); +} diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 09d778b3bc0f0..447aff8ddbc35 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -10,8 +10,6 @@ #include "../internal/pthread_impl.h" #include #include -#include -#include #include #include #include @@ -30,6 +28,10 @@ #include #include +#include +#include +#include + // With LLVM 3.6, C11 is the default compilation mode. // gets() is deprecated under that standard, but emcc // still provides it, so always include it in the build. @@ -938,9 +940,9 @@ int proxy_main(int argc, char** argv) { if (emscripten_has_threading_support()) { pthread_attr_t attr; pthread_attr_init(&attr); - // Use TOTAL_STACK for the stack size, which is the normal size of the stack + // Use the size of the current stack, which is the normal size of the stack // that main() would have without PROXY_TO_PTHREAD. - pthread_attr_setstacksize(&attr, EM_ASM_INT({ return TOTAL_STACK })); + pthread_attr_setstacksize(&attr, emscripten_stack_get_base() - emscripten_stack_get_end()); // Pass special ID -1 to the list of transferred canvases to denote that the thread creation // should instead take a list of canvases that are specified from the command line with // -s OFFSCREENCANVASES_TO_PTHREAD linker flag. diff --git a/tests/other/metadce/hello_world.exports b/tests/other/metadce/hello_world.exports index 5f7cc9d9a168d..7afd5142b4d66 100644 --- a/tests/other/metadce/hello_world.exports +++ b/tests/other/metadce/hello_world.exports @@ -3,6 +3,9 @@ __errno_location __indirect_function_table __wasm_call_ctors dynCall_jiji +emscripten_stack_get_end +emscripten_stack_get_free +emscripten_stack_init fflush main stackAlloc diff --git a/tests/other/metadce/hello_world.funcs b/tests/other/metadce/hello_world.funcs index 0519ab8062648..1f3492f148a0e 100644 --- a/tests/other/metadce/hello_world.funcs +++ b/tests/other/metadce/hello_world.funcs @@ -21,6 +21,9 @@ $__vfprintf_internal $__wasi_syscall_ret $__wasm_call_ctors $dynCall_jiji +$emscripten_stack_get_end +$emscripten_stack_get_free +$emscripten_stack_init $fflush $fmt_fp $fmt_o diff --git a/tests/other/metadce/minimal.exports b/tests/other/metadce/minimal.exports index b3b597a3180a5..36df72eae0232 100644 --- a/tests/other/metadce/minimal.exports +++ b/tests/other/metadce/minimal.exports @@ -3,6 +3,9 @@ __errno_location __indirect_function_table __wasm_call_ctors add +emscripten_stack_get_end +emscripten_stack_get_free +emscripten_stack_init fflush global_val stackAlloc diff --git a/tests/other/metadce/minimal.funcs b/tests/other/metadce/minimal.funcs index 552a4034d2ed3..6bd57c99366d4 100644 --- a/tests/other/metadce/minimal.funcs +++ b/tests/other/metadce/minimal.funcs @@ -8,6 +8,9 @@ $__unlock $__unlockfile $__wasm_call_ctors $add +$emscripten_stack_get_end +$emscripten_stack_get_free +$emscripten_stack_init $fflush $stackAlloc $stackRestore diff --git a/tests/other/test_proxy_to_pthread_stack.c b/tests/other/test_proxy_to_pthread_stack.c index 344a2144eeffb..05d4571a53533 100644 --- a/tests/other/test_proxy_to_pthread_stack.c +++ b/tests/other/test_proxy_to_pthread_stack.c @@ -1,6 +1,7 @@ #include #include #include + int main(void) { int32_t data[64*1024]; EM_ASM({ console.log($0, "success"); }, data); diff --git a/tests/pthread/test_pthread_stack_bounds.cpp b/tests/pthread/test_pthread_stack_bounds.cpp index 0155c6c5b7ed6..255088630ec2e 100644 --- a/tests/pthread/test_pthread_stack_bounds.cpp +++ b/tests/pthread/test_pthread_stack_bounds.cpp @@ -1,16 +1,13 @@ #include #include +#include void thread(void) { bool passed; - size_t stack_base = EM_ASM_INT({ return STACK_BASE; }); - size_t stack_max = EM_ASM_INT({ return STACK_MAX; }); + size_t stack_base = emscripten_stack_get_base(); + size_t stack_max = emscripten_stack_get_end(); size_t current = (size_t) &passed; -#if __asmjs__ - passed = stack_base < current && current < stack_max; -#else passed = stack_base > current && current > stack_max; -#endif #ifdef REPORT_RESULT REPORT_RESULT(passed ? 1 : 0); #endif diff --git a/tests/test_browser.py b/tests/test_browser.py index 71d3f7ce17f51..be11d5399253e 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -3950,7 +3950,7 @@ def test_pthread_utf8_funcs(self): def test_pthread_wake_all(self): self.btest(path_from_root('tests', 'pthread', 'test_futex_wake_all.cpp'), expected='0', args=['-O3', '-s', 'USE_PTHREADS=1', '-s', 'INITIAL_MEMORY=64MB', '-s', 'NO_EXIT_RUNTIME=1'], also_asmjs=True) - # Test that STACK_BASE and STACK_MAX correctly bound the stack on pthreads. + # Test that stack base and max correctly bound the stack on pthreads. @requires_threads def test_pthread_stack_bounds(self): self.btest(path_from_root('tests', 'pthread', 'test_pthread_stack_bounds.cpp'), expected='1', args=['-s', 'USE_PTHREADS']) diff --git a/tests/test_core.py b/tests/test_core.py index 1ff9577272d42..2fe1b834ee9fb 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5088,6 +5088,10 @@ def test_fs_base(self): @also_with_noderawfs @is_slow_test def test_fs_nodefs_rw(self): + # TODO(sbc): This test exposes in issue in the way we run closure compiler and + # causes it to generate non-ES5 output. + # Remove this line once we fix: https://github.com/emscripten-core/emscripten/issues/12628 + self.uses_es6 = True self.emcc_args += ['-lnodefs.js'] self.set_setting('SYSCALL_DEBUG', 1) self.do_runf(path_from_root('tests', 'fs', 'test_nodefs_rw.c'), 'success') @@ -7568,9 +7572,9 @@ def test_memprof_requirements(self): create_test_file('lib.js', ''' mergeInto(LibraryManager.library, { check_memprof_requirements: function() { - if (typeof STACK_BASE === 'number' && - typeof STACK_MAX === 'number' && - typeof STACKTOP === 'number' && + if (typeof _emscripten_stack_get_base === 'function' && + typeof _emscripten_stack_get_end === 'function' && + typeof _emscripten_stack_get_current === 'function' && typeof Module['___heap_base'] === 'number') { out('able to run memprof'); } else { diff --git a/tests/test_other.py b/tests/test_other.py index 4bc6da1ac0494..752fa7a84a6e4 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -6672,7 +6672,7 @@ def strip_numeric_suffixes(funcname): self.assertFileContents(filename, data) @parameterized({ - 'O0': ([], [], ['waka'], 743), # noqa + 'O0': ([], [], ['waka'], 847), # noqa 'O1': (['-O1'], [], ['waka'], 303), # noqa 'O2': (['-O2'], [], ['waka'], 265), # noqa # in -O3, -Os and -Oz we metadce, and they shrink it down to the minimal output we want diff --git a/tools/system_libs.py b/tools/system_libs.py index 6e9fe4bd03c11..960278c6947f8 100755 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -149,6 +149,7 @@ def get_wasm_libc_rt_files(): other_files = files_in_path( path_components=['system', 'lib', 'libc'], filenames=['emscripten_memcpy.c', 'emscripten_memset.c', + 'emscripten_scan_stack.c', 'emscripten_memmove.c']) # Calls to iprintf can be generated during codegen. Ideally we wouldn't # compile these with -O2 like we do the rest of compiler-rt since its @@ -644,6 +645,7 @@ class libcompiler_rt(MTLibrary): src_dir = ['system', 'lib', 'compiler-rt', 'lib', 'builtins'] src_files = glob_in_path(src_dir, '*.c') src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'stack_ops.s')) + src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'stack_limits.S')) src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'emscripten_setjmp.c')) src_files.append(shared.path_from_root('system', 'lib', 'compiler-rt', 'emscripten_exception_builtins.c')) From d089b12072830fc9780bd48ca407b39596e03dc6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 28 Oct 2020 16:07:24 -0700 Subject: [PATCH 2/3] Add copyright. --- ChangeLog.md | 7 ------- system/lib/libc/emscripten_scan_stack.c | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 29128b6fe0ce6..f8e4f84f8a27d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -23,13 +23,6 @@ Current Trunk - dlopen, in conformace with the spec, now checks that one of either RTDL_LAZY or RTDL_NOW flags ar set. Previously, it was possible set nether of these without generating an error. -- Support added for INPUT_JS_VERSION and OUTPUT_JS_VERSION settings. These - control is/when we use the closure compiler to transpile the resulting - output. If you use `--closure` compiler today we no longer default to - accepting `EMCASCRIPT_2020`. If you want to use any langueage features - more recent than `ECMASCRIPT5` in your JS library code or inline JS assembly - code then you now need to pass a more recent version on the command line. - e.g. `-sINPUT_JS_VERSION=ECMASCRIPT2015`. See # - Stack state is no longer stored in JavaScript. The following variables have been replaced with native functions in ``: - STACK_BASE diff --git a/system/lib/libc/emscripten_scan_stack.c b/system/lib/libc/emscripten_scan_stack.c index 7a7d2d26e49e7..c5a4417830c83 100644 --- a/system/lib/libc/emscripten_scan_stack.c +++ b/system/lib/libc/emscripten_scan_stack.c @@ -1,3 +1,10 @@ +/* + * Copyright 2020 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + #include #include From f2179d252c33ce676af846f87743046cf0b68d56 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 28 Oct 2020 18:23:14 -0700 Subject: [PATCH 3/3] . --- emscripten.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/emscripten.py b/emscripten.py index 4002ac61a1fc7..46d9477844673 100644 --- a/emscripten.py +++ b/emscripten.py @@ -216,12 +216,9 @@ def __init__(self, metadata): def apply_memory(js, memory): # Apply the statically-at-compile-time computed memory locations. # Write it all out - if shared.Settings.RELOCATABLE: - js = js.replace('{{{ HEAP_BASE }}}', str(memory.dynamic_base)) - js = js.replace('{{{ STACK_BASE }}}', str(memory.stack_base)) - js = js.replace('{{{ STACK_MAX }}}', str(memory.stack_max)) - - logger.debug('stack_base: %d, stack_max: %d, dynamic_base: %d, static bump: %d', memory.stack_base, memory.stack_max, memory.dynamic_base, memory.static_bump) + js = js.replace('{{{ HEAP_BASE }}}', str(memory.dynamic_base)) + js = js.replace('{{{ STACK_BASE }}}', str(memory.stack_base)) + js = js.replace('{{{ STACK_MAX }}}', str(memory.stack_max)) return js @@ -382,6 +379,7 @@ def emscript(infile, outfile_js, memfile, temp_files, DEBUG): update_settings_glue(metadata, DEBUG) memory = Memory(metadata) + logger.debug('stack_base: %d, stack_max: %d, dynamic_base: %d, static bump: %d', memory.stack_base, memory.stack_max, memory.dynamic_base, memory.static_bump) shared.Settings.LEGACY_DYNAMIC_BASE = memory.dynamic_base if not outfile_js: @@ -418,8 +416,9 @@ def emscript(infile, outfile_js, memfile, temp_files, DEBUG): pre += '\n' + global_initializers + '\n' - pre = apply_memory(pre, memory) - post = apply_memory(post, memory) + if shared.Settings.RELOCATABLE: + pre = apply_memory(pre, memory) + post = apply_memory(post, memory) pre = apply_static_code_hooks(pre) # In regular runtime, atinits etc. exist in the preamble part post = apply_static_code_hooks(post) # In MINIMAL_RUNTIME, atinit exists in the postamble part