diff --git a/ChangeLog.md b/ChangeLog.md index 910d02247c794..f5cfe3622436f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -17,6 +17,8 @@ See docs/process.md for how version tagging works. Current Trunk ------------- +- Remove `ALLOC_DYNAMIC` and deprecate `dynamicAlloc`. (#12057, which also + removes the internal `DYNAMICTOP_PTR` API.) 2.0.2: 09/02/2020 ----------------- @@ -26,13 +28,13 @@ Current Trunk in chrome), and it made things more complex. The behavior has been changed to be simpler and just leave the browser's error code as it is. - Enable `--no-heap-copy` file packager option by default, and remove the old - defualt behavior entirely. That is the behavior we should have had from the - beginning as it is more memory-efficient. + default behavior entirely. That is the behavior we should have had from the + beginning as it is more memory-efficient. (#12027) - `--no-entry` is now required in `STANDALONE_WASM` mode when building a reactor (application without a main function). Previously exporting a list of functions that didn't include `_main` would imply this. Now the list of `EXPORTED_FUNCTIONS` is not relevant in the deciding the type of application - to build. + to build. (#12020) - Allow polymorphic types to be used without RTTI when using embind. (#10914) - Do not remove `__original_main` using `--inline-main`. We used to do this so that it didn't show up in stack traces (which could be confusing because @@ -43,7 +45,7 @@ Current Trunk to add `__original_main` to there (since you are doing manual fine-tuning of the list of functions, which depends on the wasm's internals). Note that this should not matter in `-O2+` anyhow as normal inlining generally removes - `__original_main`. + `__original_main`. (#11995) 2.0.1: 08/21/2020 ----------------- diff --git a/emcc.py b/emcc.py index 527854ba83ec4..758e12972d7b7 100755 --- a/emcc.py +++ b/emcc.py @@ -1264,6 +1264,14 @@ def check(input_file): if shared.Settings.RELOCATABLE: shared.Settings.ALLOW_TABLE_GROWTH = 1 + # various settings require sbrk() access + if shared.Settings.DETERMINISTIC or \ + shared.Settings.EMSCRIPTEN_TRACING or \ + shared.Settings.MALLOC == 'emmalloc' or \ + shared.Settings.SAFE_HEAP or \ + shared.Settings.MEMORYPROFILER: + shared.Settings.EXPORTED_FUNCTIONS += ['_sbrk'] + if shared.Settings.ASYNCIFY: # See: https://github.com/emscripten-core/emscripten/issues/12065 # See: https://github.com/emscripten-core/emscripten/issues/12066 @@ -1466,8 +1474,9 @@ def check(input_file): shared.Settings.GLOBAL_BASE = 1024 if shared.Settings.SAFE_HEAP: - # SAFE_HEAP check includes calling emscripten_get_sbrk_ptr(). - shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['emscripten_get_sbrk_ptr', '$unSign'] + # SAFE_HEAP check includes calling emscripten_get_sbrk_ptr() from wasm + shared.Settings.EXPORTED_FUNCTIONS += ['_emscripten_get_sbrk_ptr'] + shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$unSign'] if not shared.Settings.DECLARE_ASM_MODULE_EXPORTS: shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$exportAsmFunctions'] @@ -1520,7 +1529,6 @@ def check(input_file): ] shared.Settings.EXPORTED_RUNTIME_METHODS += [ - 'getMemory', 'addRunDependency', 'removeRunDependency', ] @@ -2595,20 +2603,6 @@ def do_binaryen(target, asm_target, options, memfile, wasm_binary_target, intermediate_debug_info = bool(debug_info or options.emit_symbol_map or shared.Settings.ASYNCIFY_ONLY or shared.Settings.ASYNCIFY_REMOVE or shared.Settings.ASYNCIFY_ADD) if options.binaryen_passes: - if '--post-emscripten' in options.binaryen_passes and not shared.Settings.SIDE_MODULE: - if not shared.Settings.RELOCATABLE: - # With the wasm backend stack point value is baked in at link time. However, emscripten's - # JS compiler can allocate more static data which then shifts the stack pointer. - # See `makeStaticAlloc` in the JS compiler. - options.binaryen_passes += ['--pass-arg=stack-pointer@%d' % shared.Settings.STACK_BASE] - # the value of the sbrk pointer has been computed by the JS compiler, and we can apply it in the wasm - # (we can't add this value when we placed post-emscripten in the proper position in the list of - # passes because that was before the value was computed) - # note that we don't pass this for a side module, as the value can't be applied - it must be - # imported - options.binaryen_passes += ['--pass-arg=emscripten-sbrk-ptr@%d' % shared.Settings.DYNAMICTOP_PTR] - if shared.Settings.STANDALONE_WASM: - options.binaryen_passes += ['--pass-arg=emscripten-sbrk-val@%d' % shared.Settings.DYNAMIC_BASE] # note that wasm-ld can strip DWARF info for us too (--strip-debug), but it # also strips the Names section. so to emit just the Names section we don't # tell wasm-ld to strip anything, and we do it here. diff --git a/emscripten.py b/emscripten.py index 1735e07eda759..e9cb7ba610c35 100644 --- a/emscripten.py +++ b/emscripten.py @@ -120,6 +120,7 @@ def align_memory(addr): def align_static_bump(metadata): + # TODO: remove static bump entirely metadata['staticBump'] = align_memory(metadata['staticBump']) return metadata['staticBump'] @@ -191,7 +192,6 @@ def apply_forwarded_data(forwarded_data): forwarded_json = json.loads(forwarded_data) # Be aware of JS static allocations shared.Settings.STATIC_BUMP = forwarded_json['STATIC_BUMP'] - shared.Settings.DYNAMICTOP_PTR = forwarded_json['DYNAMICTOP_PTR'] # Be aware of JS static code hooks StaticCodeHooks.atinits = str(forwarded_json['ATINITS']) StaticCodeHooks.atmains = str(forwarded_json['ATMAINS']) diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index e3a274a081ccc..9204d9bb1445a 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -404,7 +404,7 @@ The :ref:`emscripten-memory-model` uses a typed array buffer (``ArrayBuffer``) t .. COMMENT (not rendered) : The following methods are explicitly not part of the public API and not documented. Note that in some case referred to by function name, other cases by Module assignment. function allocate(slab, types, allocator, ptr) — Internal and use is discouraged. Documentation can remain in source code but not here. - associated constants ALLOC_NORMAL, ALLOC_STACK, ALLOC_DYNAMIC, ALLOC_NONE + associated constants ALLOC_NORMAL, ALLOC_STACK, ALLOC_NONE function addOnPreRun function addOnInit @@ -413,7 +413,6 @@ The :ref:`emscripten-memory-model` uses a typed array buffer (``ArrayBuffer``) t function addOnPostRun Module['ALLOC_NORMAL'] = ALLOC_NORMAL; Module['ALLOC_STACK'] = ALLOC_STACK; - Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC; Module['ALLOC_NONE'] = ALLOC_NONE; Module['HEAP'] = HEAP; Module['IHEAP'] = IHEAP; diff --git a/src/deterministic.js b/src/deterministic.js index eba1597a0c6eb..a0cf42a6d7a00 100644 --- a/src/deterministic.js +++ b/src/deterministic.js @@ -21,7 +21,7 @@ Module['thisProgram'] = 'thisProgram'; // for consistency between different buil function hashMemory(id) { var ret = 0; - var len = HEAP32[DYNAMICTOP_PTR>>2]; + var len = _sbrk(); for (var i = 0; i < len; i++) { ret = (ret*17 + HEAPU8[i])|0; } diff --git a/src/library.js b/src/library.js index 87d5e4bca8202..da8fa46a669a8 100644 --- a/src/library.js +++ b/src/library.js @@ -444,12 +444,6 @@ LibraryManager.library = { return HEAPU8.length; }, - emscripten_get_sbrk_ptr__asm: true, - emscripten_get_sbrk_ptr__sig: 'i', - emscripten_get_sbrk_ptr: function() { - return {{{ DYNAMICTOP_PTR }}}; - }, - #if ABORTING_MALLOC $abortOnCannotGrowMemory: function(requestedSize) { #if ASSERTIONS diff --git a/src/library_emmalloc.js b/src/library_emmalloc.js index 8d782cd53451e..58b10cba370e6 100644 --- a/src/library_emmalloc.js +++ b/src/library_emmalloc.js @@ -5,9 +5,8 @@ */ mergeInto(LibraryManager.library, { - emmalloc_unclaimed_heap_memory__deps: ['emscripten_get_sbrk_ptr'], emmalloc_unclaimed_heap_memory: function() { - var dynamicTop = HEAPU32[_emscripten_get_sbrk_ptr()>>2]; + var dynamicTop = _sbrk(); #if ALLOW_MEMORY_GROWTH #if WASM #if MAXIMUM_MEMORY != -1 diff --git a/src/library_pthread.js b/src/library_pthread.js index 1f43053726570..3c0296f7581ea 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -415,9 +415,8 @@ var LibraryPThread = { 'asmJsUrlOrBlob': Module["asmJsUrlOrBlob"], #endif #if !MINIMAL_RUNTIME - 'DYNAMIC_BASE': DYNAMIC_BASE, + 'DYNAMIC_BASE': DYNAMIC_BASE #endif - 'DYNAMICTOP_PTR': DYNAMICTOP_PTR }); }, diff --git a/src/library_trace.js b/src/library_trace.js index d38470c0550f7..103092313ed79 100644 --- a/src/library_trace.js +++ b/src/library_trace.js @@ -269,7 +269,7 @@ var LibraryTracing = { #if !MINIMAL_RUNTIME 'dynamic_base': DYNAMIC_BASE, #endif - 'dynamic_top': HEAP32[DYNAMICTOP_PTR>>2], + 'dynamic_top': _sbrk(), 'total_memory': HEAP8.length }; var now = EmscriptenTrace.now(); diff --git a/src/memoryprofiler.js b/src/memoryprofiler.js index 21b917e299bfc..e60e2f129d1dc 100644 --- a/src/memoryprofiler.js +++ b/src/memoryprofiler.js @@ -486,7 +486,11 @@ var emscriptenMemoryProfiler = { 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)); var DYNAMIC_BASE = {{{ getQuoted('DYNAMIC_BASE') }}}; - var DYNAMICTOP = HEAP32[DYNAMICTOP_PTR>>2]; + // 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 DYNAMICTOP = runtimeInitialized ? _sbrk() : STACK_BASE; html += "
DYNAMIC memory area size: " + self.formatBytes(DYNAMICTOP - DYNAMIC_BASE); html += ". DYNAMIC_BASE: " + toHex(DYNAMIC_BASE, width); html += ". DYNAMICTOP: " + toHex(DYNAMICTOP, width) + "."; diff --git a/src/modules.js b/src/modules.js index f0009dd06efbf..920cde8c7f890 100644 --- a/src/modules.js +++ b/src/modules.js @@ -522,7 +522,6 @@ function exportRuntime() { var runtimeNumbers = [ 'ALLOC_NORMAL', 'ALLOC_STACK', - 'ALLOC_DYNAMIC', 'ALLOC_NONE', ]; if (ASSERTIONS) { @@ -547,7 +546,6 @@ var PassManager = { Functions: Functions, EXPORTED_FUNCTIONS: EXPORTED_FUNCTIONS, STATIC_BUMP: STATIC_BUMP, // updated with info from JS - DYNAMICTOP_PTR: DYNAMICTOP_PTR, ATINITS: ATINITS.join('\n'), ATMAINS: ATMAINS.join('\n'), ATEXITS: ATEXITS.join('\n'), diff --git a/src/preamble.js b/src/preamble.js index e3658f6cb896d..9bb966270f49d 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -189,8 +189,7 @@ function cwrap(ident, returnType, argTypes, opts) { var ALLOC_NORMAL = 0; // Tries to use _malloc() var ALLOC_STACK = 1; // Lives for the duration of the current function call -var ALLOC_DYNAMIC = 2; // Cannot be freed except through sbrk -var ALLOC_NONE = 3; // Do not allocate +var ALLOC_NONE = 2; // Do not allocate // allocate(): This is for internal use. You can use it yourself as well, but the interface // is a little tricky (see docs right below). The reason is that it is optimized @@ -228,7 +227,7 @@ function allocate(slab, types, allocator, ptr) { #else typeof stackAlloc !== 'undefined' ? stackAlloc : null, #endif - dynamicAlloc][allocator](Math.max(size, singleType ? 1 : types.length)); + ][allocator](Math.max(size, singleType ? 1 : types.length)); } if (zeroinit) { @@ -283,12 +282,6 @@ function allocate(slab, types, allocator, ptr) { return ret; } -// Allocate memory during any stage of startup - static memory early on, dynamic memory later, malloc when ready -function getMemory(size) { - if (!runtimeInitialized) return dynamicAlloc(size); - return _malloc(size); -} - #include "runtime_strings.js" #include "runtime_strings_extra.js" @@ -340,17 +333,51 @@ var STATIC_BASE = {{{ GLOBAL_BASE }}}, STACK_BASE = {{{ getQuoted('STACK_BASE') }}}, STACKTOP = STACK_BASE, STACK_MAX = {{{ getQuoted('STACK_MAX') }}}, - DYNAMIC_BASE = {{{ getQuoted('DYNAMIC_BASE') }}}, - DYNAMICTOP_PTR = {{{ DYNAMICTOP_PTR }}}; + DYNAMIC_BASE = {{{ getQuoted('DYNAMIC_BASE') }}}; #if ASSERTIONS assert(STACK_BASE % 16 === 0, 'stack must start aligned'); assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned'); #endif +#if RELOCATABLE +// We support some amount of allocation during startup in the case of +// dynamic linking, which needs to allocate memory for dynamic libraries that +// are loaded. That has to happen before the main program can start to run, +// because the main program needs those linked in before it runs (so we can't +// use normally malloc from the main program to do these allocations). + +// Allocate memory no even if malloc isn't ready yet. +function getMemory(size) { + if (!runtimeInitialized) return dynamicAlloc(size); + return _malloc(size); +} + +// 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 +// initialize sbrk (the main module is relocatable itself, and so it does not +// have __heap_base hardcoded into it - it receives it from JS as an extern +// global, basically). +Module['___heap_base'] = DYNAMIC_BASE; + +function dynamicAlloc(size) { + // After the runtime is initialized, we must only use sbrk() normally. + assert(!runtimeInitialized); +#if USE_PTHREADS + assert(!ENVIRONMENT_IS_PTHREAD); // this function is not thread-safe +#endif + var ret = Module['___heap_base']; + var end = (ret + size + 15) & -16; +#if ASSERTIONS + assert(end <= HEAP8.length, 'failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly or increase INITIAL_MEMORY'); +#endif + Module['___heap_base'] = end; + return ret; +} +#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 @@ -359,7 +386,6 @@ if (ENVIRONMENT_IS_PTHREAD) { STACK_MAX = STACKTOP = STACK_MAX = 0x7FFFFFFF; #endif // TODO DYNAMIC_BASE = Module['DYNAMIC_BASE']; - // TODO DYNAMICTOP_PTR = Module['DYNAMICTOP_PTR']; } #endif diff --git a/src/preamble_minimal.js b/src/preamble_minimal.js index 59db69c2a15ab..21daca0864fb4 100644 --- a/src/preamble_minimal.js +++ b/src/preamble_minimal.js @@ -70,9 +70,6 @@ var GLOBAL_BASE = {{{ GLOBAL_BASE }}}, STACK_BASE = {{{ getQuoted('STACK_BASE') }}}, STACKTOP = STACK_BASE, STACK_MAX = {{{ getQuoted('STACK_MAX') }}} -#if USES_DYNAMIC_ALLOC - , DYNAMICTOP_PTR = {{{ DYNAMICTOP_PTR }}}; -#endif ; #if WASM @@ -179,10 +176,6 @@ HEAPU8.set(new Uint8Array(Module['mem']), GLOBAL_BASE); #endif -#if USES_DYNAMIC_ALLOC - HEAP32[DYNAMICTOP_PTR>>2] = {{{ getQuoted('DYNAMIC_BASE') }}}; -#endif - #if USE_PTHREADS && ((MEM_INIT_METHOD == 1 && !MEM_INIT_IN_WASM && !SINGLE_FILE) || USES_DYNAMIC_ALLOC) } #endif diff --git a/src/runtime.js b/src/runtime.js index c7419a9fcfabd..83410d0e5f1c1 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -64,10 +64,6 @@ var Runtime = { // Additional runtime elements, that need preprocessing -// Allocated here in JS, after we have the runtime etc. prepared. -// This constant is emitted into the JS or wasm code. -var DYNAMICTOP_PTR = makeStaticAlloc(4); - // "Process info" for syscalls is static and cannot change, so define it using // some fixed values var PROCINFO = { diff --git a/src/runtime_init_memory.js b/src/runtime_init_memory.js index b650332770fad..7c5a9e925ea39 100644 --- a/src/runtime_init_memory.js +++ b/src/runtime_init_memory.js @@ -85,9 +85,6 @@ updateGlobalBufferAndViews(buffer); #if USE_PTHREADS if (!ENVIRONMENT_IS_PTHREAD) { // Pthreads have already initialized these variables in src/worker.js, where they were passed to the thread worker at startup time #endif -#if !STANDALONE_WASM // in standalone mode the value is in the wasm -HEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE; -#endif // !STANDALONE_WASM #if USE_PTHREADS } #endif diff --git a/src/runtime_safe_heap.js b/src/runtime_safe_heap.js index a6b234b649b0e..de336bc606977 100644 --- a/src/runtime_safe_heap.js +++ b/src/runtime_safe_heap.js @@ -106,11 +106,12 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { #if SAFE_HEAP_LOG out('SAFE_HEAP store: ' + [dest, value, bytes, isFloat, SAFE_HEAP_COUNTER++]); #endif + var brk = _sbrk() >>> 0; if (dest <= 0) abort('segmentation fault storing ' + bytes + ' bytes to address ' + dest); if (dest % bytes !== 0) abort('alignment error storing to address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes); - if (dest + bytes > HEAPU32[DYNAMICTOP_PTR>>2]) abort('segmentation fault, exceeded the top of the available dynamic heap when storing ' + bytes + ' bytes to address ' + dest + '. DYNAMICTOP=' + HEAP32[DYNAMICTOP_PTR>>2]); - assert(DYNAMICTOP_PTR); - assert(HEAP32[DYNAMICTOP_PTR>>2] <= HEAP8.length); + 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 <= HEAP8.length); setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); } function SAFE_HEAP_STORE_D(dest, value, bytes) { @@ -122,11 +123,12 @@ function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) { #if CAN_ADDRESS_2GB dest >>>= 0; #endif + var brk = _sbrk() >>> 0; if (dest <= 0) abort('segmentation fault loading ' + bytes + ' bytes from address ' + dest); if (dest % bytes !== 0) abort('alignment error loading from address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes); - if (dest + bytes > HEAPU32[DYNAMICTOP_PTR>>2]) abort('segmentation fault, exceeded the top of the available dynamic heap when loading ' + bytes + ' bytes from address ' + dest + '. DYNAMICTOP=' + HEAP32[DYNAMICTOP_PTR>>2]); - assert(DYNAMICTOP_PTR); - assert(HEAP32[DYNAMICTOP_PTR>>2] <= HEAP8.length); + 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 <= HEAP8.length); var type = getSafeHeapType(bytes, isFloat); var ret = getValue(dest, type, 1); if (unsigned) ret = unSign(ret, parseInt(type.substr(1), 10)); diff --git a/src/settings_internal.js b/src/settings_internal.js index 6fb20d17b9455..4a5e65962e59e 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -62,9 +62,6 @@ var EMBIND = 0; // Whether the main() function reads the argc/argv parameters. var MAIN_READS_PARAMS = 1; -// The computed location of the pointer to the sbrk position. -var DYNAMICTOP_PTR = -1; - // The computed initial value of the program break (the sbrk position), which // is called DYNAMIC_BASE as it is the start of dynamically-allocated memory. var DYNAMIC_BASE = -1; diff --git a/src/shell_minimal.js b/src/shell_minimal.js index 7dc1e250f5468..3786dd107a3f4 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -152,7 +152,6 @@ var ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_PTHREAD = typeof importScripts === 'f if (ENVIRONMENT_IS_WORKER) { var buffer = {{{EXPORT_NAME}}}.buffer; var STATICTOP = {{{EXPORT_NAME}}}.STATICTOP; - 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; diff --git a/src/shell_pthreads.js b/src/shell_pthreads.js index 8ddb9769fe2d4..35cddd89f74fe 100644 --- a/src/shell_pthreads.js +++ b/src/shell_pthreads.js @@ -15,7 +15,6 @@ if (ENVIRONMENT_IS_PTHREAD) { // Grab imports from the pthread to local scope. buffer = Module['buffer']; DYNAMIC_BASE = Module['DYNAMIC_BASE']; - DYNAMICTOP_PTR = Module['DYNAMICTOP_PTR']; // 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) } diff --git a/src/support.js b/src/support.js index 09e798b052090..3a167d7709ed0 100644 --- a/src/support.js +++ b/src/support.js @@ -8,22 +8,6 @@ var STACK_ALIGN = {{{ STACK_ALIGN }}}; -function dynamicAlloc(size) { -#if ASSERTIONS - assert(DYNAMICTOP_PTR); -#if USE_PTHREADS - assert(!ENVIRONMENT_IS_PTHREAD); // this function is not thread-safe -#endif -#endif - var ret = HEAP32[DYNAMICTOP_PTR>>2]; - var end = (ret + size + 15) & -16; -#if ASSERTIONS - assert(end <= HEAP8.length, 'failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly'); -#endif - HEAP32[DYNAMICTOP_PTR>>2] = end; - return ret; -} - {{{ alignMemory }}} {{{ getNativeTypeSize }}} diff --git a/src/worker.js b/src/worker.js index 34ee7bb8d7e46..61b53a1e48871 100644 --- a/src/worker.js +++ b/src/worker.js @@ -77,10 +77,6 @@ this.onmessage = function(e) { Module['DYNAMIC_BASE'] = e.data.DYNAMIC_BASE; #endif -#if USES_DYNAMIC_ALLOC - {{{ makeAsmImportsAccessInPthread('DYNAMICTOP_PTR') }}} = e.data.DYNAMICTOP_PTR; -#endif - #if WASM // Module and memory were sent from main thread #if MINIMAL_RUNTIME diff --git a/system/include/emscripten/heap.h b/system/include/emscripten/heap.h index 784767c3f417c..2869283fc5376 100644 --- a/system/include/emscripten/heap.h +++ b/system/include/emscripten/heap.h @@ -18,7 +18,7 @@ extern "C" { // Returns a pointer to a memory location that contains the heap DYNAMICTOP // variable (the end of the dynamic memory region) -intptr_t *emscripten_get_sbrk_ptr(void) EM_IMPORT(emscripten_get_sbrk_ptr); +intptr_t *emscripten_get_sbrk_ptr(void); // Attempts to geometrically or linearly increase the heap so that it // grows by at least requested_growth_bytes new bytes. The heap size may diff --git a/system/lib/emmalloc.cpp b/system/lib/emmalloc.cpp index d2bf581f82ca9..bddc0eb380329 100644 --- a/system/lib/emmalloc.cpp +++ b/system/lib/emmalloc.cpp @@ -1207,7 +1207,7 @@ struct mallinfo emmalloc_mallinfo() struct mallinfo info; // Non-mmapped space allocated (bytes): For emmalloc, // let's define this as the difference between heap size and dynamic top end. - info.arena = emscripten_get_heap_size() - (size_t)*emscripten_get_sbrk_ptr(); + info.arena = emscripten_get_heap_size() - (size_t)sbrk(0); // Number of "ordinary" blocks. Let's define this as the number of highest // size blocks. (subtract one from each, since there is a sentinel node in each list) info.ordblks = count_linked_list_size(&freeRegionBuckets[NUM_FREE_BUCKETS-1])-1; @@ -1360,7 +1360,7 @@ emmalloc.c: int emmalloc_shrink_heap() { MALLOC_ACQUIRE(); - size_t sbrkTop = (size_t)*emscripten_get_sbrk_ptr(); + size_t sbrkTop = (size_t)sbrk(0); size_t heapSize = emscripten_get_heap_size(); assert(heapSize >= sbrkTop); int success = 0; diff --git a/system/lib/sbrk.c b/system/lib/sbrk.c index b120123a58124..6451ba7db8b7b 100644 --- a/system/lib/sbrk.c +++ b/system/lib/sbrk.c @@ -29,6 +29,32 @@ #define SET_ERRNO() #endif +// FIXME just use = &sbrk_val here. That is simpler, but currently it has a +// code size cost for tiny programs that don't use malloc. We link in malloc by +// default, and depend on metadce to remove it when not used, which we can do, +// but a static assignment here would mean a nonzero value in a memory segment, +// which metadce cannot remove (it can remove code, but not data in segments). +// The current code allows tiny programs without malloc to have no data segments +// at all, while programs that use malloc may suffer a few more bytes of code +// size, but that's negligible compared to malloc itself. +// TODO: when we stop including malloc by default we can use the simpler way. +static intptr_t sbrk_val = 0; + +intptr_t* emscripten_get_sbrk_ptr() { + extern size_t __heap_base; + intptr_t* sbrk_ptr = &sbrk_val; +#if __EMSCRIPTEN_PTHREADS__ + if (__c11_atomic_load((_Atomic(intptr_t)*)sbrk_ptr, __ATOMIC_SEQ_CST) == 0) { + __c11_atomic_store((_Atomic(intptr_t)*)sbrk_ptr, (intptr_t)&__heap_base, __ATOMIC_SEQ_CST); + } +#else + if (sbrk_val == 0) { + sbrk_val = (intptr_t)&__heap_base; + } +#endif + return &sbrk_val; +} + void *sbrk(intptr_t increment) { uintptr_t old_size; // Enforce preserving a minimal 4-byte alignment for sbrk. @@ -41,7 +67,6 @@ void *sbrk(intptr_t increment) { intptr_t expected; while (1) { #endif // __EMSCRIPTEN_PTHREADS__ - intptr_t* sbrk_ptr = emscripten_get_sbrk_ptr(); #if __EMSCRIPTEN_PTHREADS__ intptr_t old_brk = __c11_atomic_load((_Atomic(intptr_t)*)sbrk_ptr, __ATOMIC_SEQ_CST); diff --git a/tests/code_size/hello_webgl2_wasm.json b/tests/code_size/hello_webgl2_wasm.json index 2460aa820a7ca..a8d3699b8835a 100644 --- a/tests/code_size/hello_webgl2_wasm.json +++ b/tests/code_size/hello_webgl2_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 5060, - "a.js.gz": 2412, - "a.wasm": 10893, - "a.wasm.gz": 6922, - "total": 16516, - "total_gz": 9711 + "a.js": 5040, + "a.js.gz": 2397, + "a.wasm": 10919, + "a.wasm.gz": 6939, + "total": 16522, + "total_gz": 9713 } diff --git a/tests/code_size/hello_webgl2_wasm2js.json b/tests/code_size/hello_webgl2_wasm2js.json index c329071c53be4..c1273c3274c0a 100644 --- a/tests/code_size/hello_webgl2_wasm2js.json +++ b/tests/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 22114, - "a.js.gz": 8453, + "a.js": 22135, + "a.js.gz": 8457, "a.mem": 3168, "a.mem.gz": 2711, - "total": 25870, - "total_gz": 11550 + "total": 25891, + "total_gz": 11554 } diff --git a/tests/code_size/hello_webgl_wasm.json b/tests/code_size/hello_webgl_wasm.json index 605403ec06237..43f5b41f4bd59 100644 --- a/tests/code_size/hello_webgl_wasm.json +++ b/tests/code_size/hello_webgl_wasm.json @@ -1,10 +1,10 @@ { "a.html": 563, "a.html.gz": 377, - "a.js": 4545, - "a.js.gz": 2235, - "a.wasm": 10893, - "a.wasm.gz": 6922, - "total": 16001, - "total_gz": 9534 + "a.js": 4525, + "a.js.gz": 2220, + "a.wasm": 10919, + "a.wasm.gz": 6939, + "total": 16007, + "total_gz": 9536 } diff --git a/tests/code_size/hello_webgl_wasm2js.json b/tests/code_size/hello_webgl_wasm2js.json index 87ad8c5eb137a..6e42776c6eafb 100644 --- a/tests/code_size/hello_webgl_wasm2js.json +++ b/tests/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 588, "a.html.gz": 386, - "a.js": 21603, - "a.js.gz": 8293, + "a.js": 21624, + "a.js.gz": 8298, "a.mem": 3168, "a.mem.gz": 2711, - "total": 25359, - "total_gz": 11390 + "total": 25380, + "total_gz": 11395 } diff --git a/tests/code_size/random_printf_wasm.json b/tests/code_size/random_printf_wasm.json index ddf3fd41a7719..34db71ac95107 100644 --- a/tests/code_size/random_printf_wasm.json +++ b/tests/code_size/random_printf_wasm.json @@ -1,6 +1,6 @@ { - "a.html": 13727, - "a.html.gz": 7361, - "total": 13727, - "total_gz": 7361 + "a.html": 13723, + "a.html.gz": 7354, + "total": 13723, + "total_gz": 7354 } diff --git a/tests/code_size/random_printf_wasm2js.json b/tests/code_size/random_printf_wasm2js.json index ae31b6715fbb2..51665bc3453e7 100644 --- a/tests/code_size/random_printf_wasm2js.json +++ b/tests/code_size/random_printf_wasm2js.json @@ -1,6 +1,6 @@ { - "a.html": 19387, - "a.html.gz": 8070, - "total": 19387, - "total_gz": 8070 + "a.html": 19379, + "a.html.gz": 8065, + "total": 19379, + "total_gz": 8065 } diff --git a/tests/core/legacy_exported_runtime_numbers.cpp b/tests/core/legacy_exported_runtime_numbers.cpp index 24bcced170318..de262b5f3d9e9 100644 --- a/tests/core/legacy_exported_runtime_numbers.cpp +++ b/tests/core/legacy_exported_runtime_numbers.cpp @@ -8,11 +8,11 @@ int main() { #ifdef DIRECT EM_ASM({ - out('|' + ALLOC_DYNAMIC + '|'); + out('|' + ALLOC_STACK + '|'); }); #else EM_ASM({ - out('|' + Module['ALLOC_DYNAMIC'] + '|'); + out('|' + Module['ALLOC_STACK'] + '|'); }); #endif } diff --git a/tests/core/legacy_exported_runtime_numbers.out b/tests/core/legacy_exported_runtime_numbers.out index fd524e7bf08c0..37bc105be17b4 100644 --- a/tests/core/legacy_exported_runtime_numbers.out +++ b/tests/core/legacy_exported_runtime_numbers.out @@ -1 +1 @@ -|2| +|1| diff --git a/tests/core/legacy_exported_runtime_numbers_assert.out b/tests/core/legacy_exported_runtime_numbers_assert.out index ba94bfa3b1c8b..e96de1c45ef5b 100644 --- a/tests/core/legacy_exported_runtime_numbers_assert.out +++ b/tests/core/legacy_exported_runtime_numbers_assert.out @@ -1 +1 @@ -'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ) +'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ) diff --git a/tests/mallinfo.cpp b/tests/mallinfo.cpp index ee268229016cb..c9c5f5120f611 100644 --- a/tests/mallinfo.cpp +++ b/tests/mallinfo.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -36,7 +37,7 @@ unsigned int getFreeMemory() { s_mallinfo i = mallinfo(); unsigned int totalMemory = getTotalMemory(); - unsigned int dynamicTop = EM_ASM_INT(return HEAPU32[DYNAMICTOP_PTR>>2]); + unsigned int dynamicTop = (unsigned int)sbrk(0); return totalMemory - dynamicTop + i.fordblks; } diff --git a/tests/other/metadce/hello_libcxx_O2.sent b/tests/other/metadce/hello_libcxx_O2.sent index 7bd58eb9d1e98..a9cdad1dee327 100644 --- a/tests/other/metadce/hello_libcxx_O2.sent +++ b/tests/other/metadce/hello_libcxx_O2.sent @@ -2,7 +2,6 @@ __cxa_atexit __map_file __sys_munmap abort -emscripten_get_sbrk_ptr emscripten_memcpy_big emscripten_resize_heap environ_get diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions.sent b/tests/other/metadce/hello_libcxx_O2_fexceptions.sent index de5863d96a5b9..041870ba4690f 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions.sent +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions.sent @@ -12,7 +12,6 @@ __map_file __resumeException __sys_munmap abort -emscripten_get_sbrk_ptr emscripten_memcpy_big emscripten_resize_heap environ_get diff --git a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent index de5863d96a5b9..041870ba4690f 100644 --- a/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent +++ b/tests/other/metadce/hello_libcxx_O2_fexceptions_DEMANGLE_SUPPORT.sent @@ -12,7 +12,6 @@ __map_file __resumeException __sys_munmap abort -emscripten_get_sbrk_ptr emscripten_memcpy_big emscripten_resize_heap environ_get diff --git a/tests/other/metadce/hello_world.funcs b/tests/other/metadce/hello_world.funcs index 40885b7eef362..39378bd6badb8 100644 --- a/tests/other/metadce/hello_world.funcs +++ b/tests/other/metadce/hello_world.funcs @@ -24,7 +24,6 @@ $__wasm_call_ctors $dlfree $dlmalloc $dynCall_jiji -$emscripten_get_sbrk_ptr $fflush $fmt_fp $fmt_o diff --git a/tests/other/metadce/hello_world.sent b/tests/other/metadce/hello_world.sent index db324cce439cd..56cd0769a386b 100644 --- a/tests/other/metadce/hello_world.sent +++ b/tests/other/metadce/hello_world.sent @@ -1,4 +1,3 @@ -emscripten_get_sbrk_ptr emscripten_memcpy_big emscripten_resize_heap fd_write diff --git a/tests/other/metadce/hello_world_O1.funcs b/tests/other/metadce/hello_world_O1.funcs index 65dd8d380ad5a..2a013ebe1f2be 100644 --- a/tests/other/metadce/hello_world_O1.funcs +++ b/tests/other/metadce/hello_world_O1.funcs @@ -14,7 +14,6 @@ $__wasm_call_ctors $dlfree $dlmalloc $dynCall_jiji -$emscripten_get_sbrk_ptr $fputs $fwrite $legalstub$dynCall_jiji diff --git a/tests/other/metadce/hello_world_O1.sent b/tests/other/metadce/hello_world_O1.sent index db324cce439cd..56cd0769a386b 100644 --- a/tests/other/metadce/hello_world_O1.sent +++ b/tests/other/metadce/hello_world_O1.sent @@ -1,4 +1,3 @@ -emscripten_get_sbrk_ptr emscripten_memcpy_big emscripten_resize_heap fd_write diff --git a/tests/other/metadce/hello_world_O2.sent b/tests/other/metadce/hello_world_O2.sent index db324cce439cd..56cd0769a386b 100644 --- a/tests/other/metadce/hello_world_O2.sent +++ b/tests/other/metadce/hello_world_O2.sent @@ -1,4 +1,3 @@ -emscripten_get_sbrk_ptr emscripten_memcpy_big emscripten_resize_heap fd_write diff --git a/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.imports b/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.imports index b1c9cb27031ff..927e84b1a94ff 100644 --- a/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.imports +++ b/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.imports @@ -4,6 +4,7 @@ __table_base emscripten_memcpy_big emscripten_resize_heap fd_write +g$__heap_base memory setTempRet0 table diff --git a/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.sent b/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.sent index b1c9cb27031ff..927e84b1a94ff 100644 --- a/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.sent +++ b/tests/other/metadce/hello_world_O3_MAIN_MODULE_2.sent @@ -4,6 +4,7 @@ __table_base emscripten_memcpy_big emscripten_resize_heap fd_write +g$__heap_base memory setTempRet0 table diff --git a/tests/other/metadce/minimal.funcs b/tests/other/metadce/minimal.funcs index f4118decf362f..899eb986a422c 100644 --- a/tests/other/metadce/minimal.funcs +++ b/tests/other/metadce/minimal.funcs @@ -11,7 +11,6 @@ $__wasm_call_ctors $add $dlfree $dlmalloc -$emscripten_get_sbrk_ptr $fflush $sbrk $stackAlloc diff --git a/tests/other/metadce/minimal.sent b/tests/other/metadce/minimal.sent index 460c0d3359cbc..4ef36e19ec337 100644 --- a/tests/other/metadce/minimal.sent +++ b/tests/other/metadce/minimal.sent @@ -1,4 +1,3 @@ -emscripten_get_sbrk_ptr emscripten_resize_heap memory table diff --git a/tests/other/metadce/minimal_O1.funcs b/tests/other/metadce/minimal_O1.funcs index ccf96f86d6149..08eeaa3e673d0 100644 --- a/tests/other/metadce/minimal_O1.funcs +++ b/tests/other/metadce/minimal_O1.funcs @@ -4,7 +4,6 @@ $__wasm_call_ctors $add $dlfree $dlmalloc -$emscripten_get_sbrk_ptr $sbrk $stackAlloc $stackRestore diff --git a/tests/other/metadce/minimal_O1.sent b/tests/other/metadce/minimal_O1.sent index 460c0d3359cbc..4ef36e19ec337 100644 --- a/tests/other/metadce/minimal_O1.sent +++ b/tests/other/metadce/minimal_O1.sent @@ -1,4 +1,3 @@ -emscripten_get_sbrk_ptr emscripten_resize_heap memory table diff --git a/tests/other/metadce/minimal_O2.sent b/tests/other/metadce/minimal_O2.sent index 460c0d3359cbc..4ef36e19ec337 100644 --- a/tests/other/metadce/minimal_O2.sent +++ b/tests/other/metadce/minimal_O2.sent @@ -1,4 +1,3 @@ -emscripten_get_sbrk_ptr emscripten_resize_heap memory table diff --git a/tests/test_core.py b/tests/test_core.py index 26a1b28cf6bdc..510677203ce3f 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6505,7 +6505,7 @@ def test(output_prefix='', args=[], assert_returncode=0): test('_assert', assert_returncode=NON_ZERO) self.set_setting('ASSERTIONS', 0) # see that when we export them, things work on the module - self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['ALLOC_DYNAMIC']) + self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['ALLOC_STACK']) test() def test_response_file(self): @@ -7744,8 +7744,7 @@ def test_memprof_requirements(self): typeof STACK_BASE === 'number' && typeof STACK_MAX === 'number' && typeof STACKTOP === 'number' && - typeof DYNAMIC_BASE === 'number' && - typeof DYNAMICTOP_PTR === 'number') { + typeof DYNAMIC_BASE === 'number') { out('able to run memprof'); } else { out('missing the required variables to run memprof'); diff --git a/tests/test_other.py b/tests/test_other.py index 89cab6ca12f5a..e88c80e6101db 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -5348,10 +5348,10 @@ def test_massive_alloc(self): def test_failing_alloc(self): for pre_fail, post_fail, opts in [ ('', '', []), - ('EM_ASM( Module.temp = HEAP32[DYNAMICTOP_PTR>>2] );', 'EM_ASM( assert(Module.temp === HEAP32[DYNAMICTOP_PTR>>2], "must not adjust DYNAMICTOP when an alloc fails!") );', []), + ('EM_ASM( Module.temp = _sbrk() );', 'EM_ASM( assert(Module.temp === _sbrk(), "must not adjust brk when an alloc fails!") );', []), # also test non-wasm in normal mode ('', '', ['-s', 'WASM=0']), - ('EM_ASM( Module.temp = HEAP32[DYNAMICTOP_PTR>>2] );', 'EM_ASM( assert(Module.temp === HEAP32[DYNAMICTOP_PTR>>2], "must not adjust DYNAMICTOP when an alloc fails!") );', ['-s', 'WASM=0']), + ('EM_ASM( Module.temp = _sbrk() );', 'EM_ASM( assert(Module.temp === _sbrk(), "must not adjust brk when an alloc fails!") );', ['-s', 'WASM=0']), ]: for growth in [0, 1]: for aborting_args in [[], ['-s', 'ABORTING_MALLOC=0'], ['-s', 'ABORTING_MALLOC=1']]: @@ -5395,7 +5395,7 @@ def test_failing_alloc(self): printf("managed another malloc!\n"); } ''' % (pre_fail, post_fail)) - args = [EMCC, 'main.cpp'] + opts + aborting_args + args = [EMCC, 'main.cpp', '-s', 'EXPORTED_FUNCTIONS=[_main,_sbrk]'] + opts + aborting_args args += ['-s', 'TEST_MEMORY_GROWTH_FAILS=1'] # In this test, force memory growing to fail if growth: args += ['-s', 'ALLOW_MEMORY_GROWTH=1'] diff --git a/tools/ctor_evaller.py b/tools/ctor_evaller.py index ceeebddbd7f45..8d48d33e9d3de 100755 --- a/tools/ctor_evaller.py +++ b/tools/ctor_evaller.py @@ -105,7 +105,7 @@ def add_func(asm, func): for bit in bits: name, value = [x.strip() for x in bit.split('=', 1)] if value in ['0', '+0', '0.0'] or name in [ - 'STACKTOP', 'STACK_MAX', 'DYNAMICTOP_PTR', + 'STACKTOP', 'STACK_MAX', 'HEAP8', 'HEAP16', 'HEAP32', 'HEAPU8', 'HEAPU16', 'HEAPU32', 'HEAPF32', 'HEAPF64', @@ -194,7 +194,6 @@ def add_func(asm, func): var libraryArg = { STACKTOP: stackTop, STACK_MAX: stackMax, - DYNAMICTOP_PTR: dynamicTopPtr, ___dso_handle: 0, // used by atexit, value doesn't matter _emscripten_memcpy_big: function(dest, src, num) { heap.set(heap.subarray(src, src+num), dest); diff --git a/tools/shared.py b/tools/shared.py index 2cfd60cef64ae..a0cc530a38c13 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1333,8 +1333,6 @@ def add_emscripten_metadata(js_file, wasm_file): js = open(js_file).read() m = re.search(r"(^|\s)DYNAMIC_BASE\s+=\s+(\d+)", js) dynamic_base = int(m.group(2)) - m = re.search(r"(^|\s)DYNAMICTOP_PTR\s+=\s+(\d+)", js) - dynamictop_ptr = int(m.group(2)) logger.debug('creating wasm emscripten metadata section with mem size %d, table size %d' % (mem_size, table_size,)) name = b'\x13emscripten_metadata' # section name, including prefixed size @@ -1356,7 +1354,8 @@ def add_emscripten_metadata(js_file, wasm_file): WebAssembly.toLEB(table_size) + WebAssembly.toLEB(global_base) + WebAssembly.toLEB(dynamic_base) + - WebAssembly.toLEB(dynamictop_ptr) + + # dynamictopPtr, always 0 now + WebAssembly.toLEB(0) + # tempDoublePtr, always 0 in wasm backend WebAssembly.toLEB(0) +