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
6 changes: 6 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ 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.
- Stack state is no longer stored in JavaScript. The following variables have
been replaced with native functions in `<emscripten/stack.h>`:
- STACK_BASE
- STACK_MAX
- STACKTOP
- TOTAL_STACK

2.0.8: 10/24/2020
-----------------
Expand Down
27 changes: 20 additions & 7 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)'
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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')
Expand Down
15 changes: 9 additions & 6 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
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))
if shared.Settings.RELOCATABLE:
js = js.replace('{{{ HEAP_BASE }}}', str(memory.dynamic_base))

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


Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -418,7 +416,9 @@ def emscript(infile, outfile_js, memfile, temp_files, DEBUG):

pre += '\n' + global_initializers + '\n'

pre = apply_memory(pre, 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

Expand Down Expand Up @@ -771,7 +771,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_'):
Comment thread
sbc100 marked this conversation as resolved.
# With assertions enabled we create a wrapper that are calls get routed through, for
# the lifetime of the program.
if delay_assignment:
Expand Down
6 changes: 0 additions & 6 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
11 changes: 6 additions & 5 deletions src/library_async.js
Original file line number Diff line number Diff line change
Expand Up @@ -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') }}});
Expand Down Expand Up @@ -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 }}};
Expand Down
6 changes: 2 additions & 4 deletions src/library_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/library_pthread_stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
10 changes: 1 addition & 9 deletions src/library_stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -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!');
},
});
6 changes: 3 additions & 3 deletions src/library_trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down
45 changes: 22 additions & 23 deletions src/memoryprofiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 += '<br />' + colorBar('#202020') + 'STATIC memory area size: ' + self.formatBytes(Math.min(STACK_BASE, STACK_MAX) - {{{ GLOBAL_BASE }}});
html += '<br />' + colorBar('#202020') + 'STATIC memory area size: ' + self.formatBytes(stackMax - {{{ GLOBAL_BASE }}});
html += '. {{{ GLOBAL_BASE }}}: ' + toHex({{{ GLOBAL_BASE }}}, width);

html += '<br />' + 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 += '<br />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 += '<br />' + 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 += '<br />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 += "<br />DYNAMIC memory area size: " + self.formatBytes(heap_end - heap_base);
html += ". start: " + toHex(heap_base, width);
html += ". end: " + toHex(heap_end, width) + ".";
Expand All @@ -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);
Comment thread
sbc100 marked this conversation as resolved.

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);
Expand Down
9 changes: 9 additions & 0 deletions src/postamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion src/postamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -77,6 +77,7 @@ function initRuntime(asm) {
#endif

#if STACK_OVERFLOW_CHECK
_emscripten_stack_init();
writeStackCookie();
#endif

Expand Down
25 changes: 2 additions & 23 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')
Expand Down Expand Up @@ -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__);
Expand Down
Loading