Skip to content

Commit

Permalink
Move enlargeMemory() and getTotalMemory() to library JS file
Browse files Browse the repository at this point in the history
  • Loading branch information
juj committed Jan 21, 2019
1 parent 7013ed9 commit 1655d72
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 145 deletions.
4 changes: 2 additions & 2 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ def setup_function_pointers(function_table_sigs):


def create_basic_funcs(function_table_sigs, invoke_function_names):
basic_funcs = ['abort', 'assert', 'enlargeMemory', 'getTotalMemory', 'setTempRet0', 'getTempRet0']
basic_funcs = ['abort', 'assert', 'setTempRet0', 'getTempRet0']
if shared.Settings.ABORTING_MALLOC:
basic_funcs += ['abortOnCannotGrowMemory']
if shared.Settings.STACK_OVERFLOW_CHECK:
Expand Down Expand Up @@ -2136,7 +2136,7 @@ def create_em_js(forwarded_json, metadata):


def create_sending_wasm(invoke_funcs, jscall_sigs, forwarded_json, metadata):
basic_funcs = ['assert', 'enlargeMemory', 'getTotalMemory']
basic_funcs = ['assert']
if shared.Settings.ABORTING_MALLOC:
basic_funcs += ['abortOnCannotGrowMemory']
if shared.Settings.SAFE_HEAP:
Expand Down
1 change: 0 additions & 1 deletion site/source/docs/api_reference/preamble.js.rst
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,6 @@ The :ref:`emscripten-memory-model` uses a typed array buffer (``ArrayBuffer``) t
Module['HEAP'] = HEAP;
Module['IHEAP'] = IHEAP;
function alignUp(x, multiple)
function enlargeMemory()
function demangle(func)
function demangleAll(text)
function parseJSFunc(jsfunc)
Expand Down
2 changes: 1 addition & 1 deletion src/embind/embind.js
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ var LibraryEmbind = {
'free', 'malloc', '$readLatin1String', '$registerType',
'$simpleReadValueFromPointer'],
_embind_register_std_wstring: function(rawType, charSize, name) {
// nb. do not cache HEAPU16 and HEAPU32, they may be destroyed by enlargeMemory().
// nb. do not cache HEAPU16 and HEAPU32, they may be destroyed by emscripten_resize_heap().
name = readLatin1String(name);
var getHeap, shift;
if (charSize === 2) {
Expand Down
3 changes: 0 additions & 3 deletions src/fetch-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ var ENVIRONMENT_IS_PTHREAD = true;
var __pthread_is_main_runtime_thread=0;
var DYNAMICTOP_PTR = 0;
var TOTAL_MEMORY = 0;
function enlargeMemory() {
abort('Cannot enlarge memory arrays, since compiling with pthreads support enabled (-s USE_PTHREADS=1).');
}
var nan = NaN;
var inf = Infinity;

Expand Down
137 changes: 122 additions & 15 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,21 +467,129 @@ LibraryManager.library = {
return -1;
},

emscripten_get_heap_size: function() {
return TOTAL_MEMORY;
},

emscripten_resize_heap__deps: ['emscripten_get_heap_size'],
emscripten_resize_heap: function(requestedSize) {
#if USE_PTHREADS
abort('Cannot enlarge memory arrays, since compiling with pthreads support enabled (-s USE_PTHREADS=1).');
#else
#if ALLOW_MEMORY_GROWTH == 0
#if ABORTING_MALLOC
abortOnCannotGrowMemory();
#else
return false; // malloc will report failure
#endif
#else
var oldSize = _emscripten_get_heap_size();
// TOTAL_MEMORY is the current size of the actual array, and DYNAMICTOP is the new top.
#if ASSERTIONS
assert(requestedSize > oldSize); // This function should only ever be called after the ceiling of the dynamic heap has already been bumped to exceed the current total size of the asm.js heap.
#endif

#if EMSCRIPTEN_TRACING
// Report old layout one last time
_emscripten_trace_report_memory_layout();
#endif

var PAGE_MULTIPLE = {{{ getPageSize() }}};
var LIMIT = 2147483648 - PAGE_MULTIPLE; // We can do one page short of 2GB as theoretical maximum.

if (requestedSize > LIMIT) {
#if ASSERTIONS
err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + LIMIT + ' bytes!');
#endif
return false;
}

var MIN_TOTAL_MEMORY = 16777216;
var newSize = Math.max(oldSize, MIN_TOTAL_MEMORY); // So the loop below will not be infinite, and minimum asm.js memory size is 16MB.

while (newSize < requestedSize) { // Keep incrementing the heap size as long as it's less than what is requested.
if (newSize <= 536870912) {
newSize = alignUp(2 * newSize, PAGE_MULTIPLE); // Simple heuristic: double until 1GB...
} else {
// ..., but after that, add smaller increments towards 2GB, which we cannot reach
newSize = Math.min(alignUp((3 * newSize + 2147483648) / 4, PAGE_MULTIPLE), LIMIT);
#if ASSERTIONS
if (newSize === oldSize) {
warnOnce('Cannot ask for more memory since we reached the practical limit in browsers (which is just below 2GB), so the request would have failed. Requesting only ' + TOTAL_MEMORY);
}
#endif
}
}

#if WASM_MEM_MAX != -1
// A limit was set for how much we can grow. We should not exceed that
// (the wasm binary specifies it, so if we tried, we'd fail anyhow). That is,
// if we are at say 64MB, and the max is 100MB, then we should *not* try to
// grow 64->128MB which is the default behavior (doubling), as 128MB will
// fail because of the max limit. Instead, we should only try to grow
// 64->100MB in this example, which has a chance of succeeding (but may
// still fail for another reason, of actually running out of memory).
newSize = Math.min(newSize, {{{ WASM_MEM_MAX }}});
if (newSize == oldSize) {
#if ASSERTIONS
err('Failed to grow the heap from ' + oldSize + ', as we reached the WASM_MEM_MAX limit (' + {{{ WASM_MEM_MAX }}} + ') set during compilation');
#endif
return false;
}
#endif

#if ASSERTIONS
var start = Date.now();
#endif

var replacement = Module['reallocBuffer'](newSize);
if (!replacement || replacement.byteLength != newSize) {
#if ASSERTIONS
err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
if (replacement) {
err('Expected to get back a buffer of size ' + newSize + ' bytes, but instead got back a buffer of size ' + replacement.byteLength);
}
#endif
return false;
}

// everything worked
updateGlobalBuffer(replacement);
updateGlobalBufferViews();

TOTAL_MEMORY = newSize;
HEAPU32[DYNAMICTOP_PTR>>2] = requestedSize;

#if ASSERTIONS && !WASM
err('Warning: Enlarging memory arrays, this is not fast! ' + [oldSize, newSize]);
#endif

#if EMSCRIPTEN_TRACING
_emscripten_trace_js_log_message("Emscripten", "Enlarging memory arrays from " + oldSize + " to " + newSize);
// And now report the new layout
_emscripten_trace_report_memory_layout();
#endif

return true;
#endif // ALLOW_MEMORY_GROWTH
#endif // USE_PTHREADS
},

// Implement a Linux-like 'memory area' for our 'process'.
// Changes the size of the memory area by |bytes|; returns the
// address of the previous top ('break') of the memory area
// We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
sbrk__asm: true,
sbrk__sig: ['ii'],
sbrk__deps: ['__setErrNo'],
sbrk__deps: ['__setErrNo', 'emscripten_get_heap_size', 'emscripten_resize_heap'],
sbrk: function(increment) {
increment = increment|0;
var oldDynamicTop = 0;
var oldDynamicTopOnChange = 0;
var newDynamicTop = 0;
var totalMemory = 0;
#if USE_PTHREADS
totalMemory = getTotalMemory()|0;
totalMemory = _emscripten_get_heap_size()|0;

// Perform a compare-and-swap loop to update the new dynamic top value. This is because
// this function can becalled simultaneously in multiple threads.
Expand Down Expand Up @@ -517,11 +625,11 @@ LibraryManager.library = {
return -1;
}

HEAP32[DYNAMICTOP_PTR>>2] = newDynamicTop;
totalMemory = getTotalMemory()|0;
if ((newDynamicTop|0) > (totalMemory|0)) {
if ((enlargeMemory()|0) == 0) {
HEAP32[DYNAMICTOP_PTR>>2] = oldDynamicTop;
totalMemory = _emscripten_get_heap_size()|0;
if ((newDynamicTop|0) <= (totalMemory|0)) {
HEAP32[DYNAMICTOP_PTR>>2] = newDynamicTop|0;
} else {
if ((_emscripten_resize_heap(newDynamicTop|0)|0) == 0) {
___setErrNo({{{ cDefine('ENOMEM') }}});
return -1;
}
Expand All @@ -532,12 +640,12 @@ LibraryManager.library = {

brk__asm: true,
brk__sig: ['ii'],
brk__deps: ['__setErrNo', 'emscripten_get_heap_size', 'emscripten_resize_heap'],
brk: function(newDynamicTop) {
newDynamicTop = newDynamicTop|0;
var oldDynamicTop = 0;
var totalMemory = 0;
#if USE_PTHREADS
totalMemory = getTotalMemory()|0;
totalMemory = _emscripten_get_heap_size()|0;
// Asking to increase dynamic top to a too high value? In pthreads builds we cannot
// enlarge memory, so this needs to fail.
if ((newDynamicTop|0) < 0 | (newDynamicTop|0) > (totalMemory|0)) {
Expand All @@ -558,13 +666,12 @@ LibraryManager.library = {
return -1;
}

oldDynamicTop = HEAP32[DYNAMICTOP_PTR>>2]|0;
HEAP32[DYNAMICTOP_PTR>>2] = newDynamicTop;
totalMemory = getTotalMemory()|0;
if ((newDynamicTop|0) > (totalMemory|0)) {
if ((enlargeMemory()|0) == 0) {
totalMemory = _emscripten_get_heap_size()|0;
if ((newDynamicTop|0) <= (totalMemory|0)) {
HEAP32[DYNAMICTOP_PTR>>2] = newDynamicTop|0;
} else {
if ((_emscripten_resize_heap(newDynamicTop|0)|0) == 0) {
___setErrNo({{{ cDefine('ENOMEM') }}});
HEAP32[DYNAMICTOP_PTR>>2] = oldDynamicTop;
return -1;
}
}
Expand Down
109 changes: 0 additions & 109 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,6 @@ function stackTrace() {
var PAGE_SIZE = 16384;
var WASM_PAGE_SIZE = {{{ WASM_PAGE_SIZE }}};
var ASMJS_PAGE_SIZE = {{{ ASMJS_PAGE_SIZE }}};
var MIN_TOTAL_MEMORY = 16777216;

function alignUp(x, multiple) {
if (x % multiple > 0) {
Expand Down Expand Up @@ -959,110 +958,6 @@ if (!Module['reallocBuffer']) Module['reallocBuffer'] = function(size) {
#endif // ALLOW_MEMORY_GROWTH
#endif // WASM == 0

function enlargeMemory() {
#if USE_PTHREADS
abort('Cannot enlarge memory arrays, since compiling with pthreads support enabled (-s USE_PTHREADS=1).');
#else
#if ALLOW_MEMORY_GROWTH == 0
#if ABORTING_MALLOC
abortOnCannotGrowMemory();
#else
return false; // malloc will report failure
#endif
#else
// TOTAL_MEMORY is the current size of the actual array, and DYNAMICTOP is the new top.
#if ASSERTIONS
assert(HEAP32[DYNAMICTOP_PTR>>2] > TOTAL_MEMORY); // This function should only ever be called after the ceiling of the dynamic heap has already been bumped to exceed the current total size of the asm.js heap.
#endif

#if EMSCRIPTEN_TRACING
// Report old layout one last time
_emscripten_trace_report_memory_layout();
#endif

var PAGE_MULTIPLE = {{{ getPageSize() }}};
var LIMIT = 2147483648 - PAGE_MULTIPLE; // We can do one page short of 2GB as theoretical maximum.

if (HEAP32[DYNAMICTOP_PTR>>2] > LIMIT) {
#if ASSERTIONS
err('Cannot enlarge memory, asked to go up to ' + HEAP32[DYNAMICTOP_PTR>>2] + ' bytes, but the limit is ' + LIMIT + ' bytes!');
#endif
return false;
}

var OLD_TOTAL_MEMORY = TOTAL_MEMORY;
TOTAL_MEMORY = Math.max(TOTAL_MEMORY, MIN_TOTAL_MEMORY); // So the loop below will not be infinite, and minimum asm.js memory size is 16MB.

while (TOTAL_MEMORY < HEAP32[DYNAMICTOP_PTR>>2]) { // Keep incrementing the heap size as long as it's less than what is requested.
if (TOTAL_MEMORY <= 536870912) {
TOTAL_MEMORY = alignUp(2 * TOTAL_MEMORY, PAGE_MULTIPLE); // Simple heuristic: double until 1GB...
} else {
// ..., but after that, add smaller increments towards 2GB, which we cannot reach
TOTAL_MEMORY = Math.min(alignUp((3 * TOTAL_MEMORY + 2147483648) / 4, PAGE_MULTIPLE), LIMIT);
#if ASSERTIONS
if (TOTAL_MEMORY === OLD_TOTAL_MEMORY) {
warnOnce('Cannot ask for more memory since we reached the practical limit in browsers (which is just below 2GB), so the request would have failed. Requesting only ' + TOTAL_MEMORY);
}
#endif
}
}

#if WASM_MEM_MAX != -1
// A limit was set for how much we can grow. We should not exceed that
// (the wasm binary specifies it, so if we tried, we'd fail anyhow). That is,
// if we are at say 64MB, and the max is 100MB, then we should *not* try to
// grow 64->128MB which is the default behavior (doubling), as 128MB will
// fail because of the max limit. Instead, we should only try to grow
// 64->100MB in this example, which has a chance of succeeding (but may
// still fail for another reason, of actually running out of memory).
TOTAL_MEMORY = Math.min(TOTAL_MEMORY, {{{ WASM_MEM_MAX }}});
if (TOTAL_MEMORY == OLD_TOTAL_MEMORY) {
#if ASSERTIONS
err('Failed to grow the heap from ' + OLD_TOTAL_MEMORY + ', as we reached the WASM_MEM_MAX limit (' + {{{ WASM_MEM_MAX }}} + ') set during compilation');
#endif
// restore the state to before this call, we failed
TOTAL_MEMORY = OLD_TOTAL_MEMORY;
return false;
}
#endif

#if ASSERTIONS
var start = Date.now();
#endif

var replacement = Module['reallocBuffer'](TOTAL_MEMORY);
if (!replacement || replacement.byteLength != TOTAL_MEMORY) {
#if ASSERTIONS
err('Failed to grow the heap from ' + OLD_TOTAL_MEMORY + ' bytes to ' + TOTAL_MEMORY + ' bytes, not enough memory!');
if (replacement) {
err('Expected to get back a buffer of size ' + TOTAL_MEMORY + ' bytes, but instead got back a buffer of size ' + replacement.byteLength);
}
#endif
// restore the state to before this call, we failed
TOTAL_MEMORY = OLD_TOTAL_MEMORY;
return false;
}

// everything worked

updateGlobalBuffer(replacement);
updateGlobalBufferViews();

#if ASSERTIONS && !WASM
err('Warning: Enlarging memory arrays, this is not fast! ' + [OLD_TOTAL_MEMORY, TOTAL_MEMORY]);
#endif

#if EMSCRIPTEN_TRACING
_emscripten_trace_js_log_message("Emscripten", "Enlarging memory arrays from " + OLD_TOTAL_MEMORY + " to " + TOTAL_MEMORY);
// And now report the new layout
_emscripten_trace_report_memory_layout();
#endif

return true;
#endif // ALLOW_MEMORY_GROWTH
#endif // USE_PTHREADS
}

#if ALLOW_MEMORY_GROWTH
var byteLength;
try {
Expand Down Expand Up @@ -1226,10 +1121,6 @@ HEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE;
}
#endif

function getTotalMemory() {
return TOTAL_MEMORY;
}

// Endianness check (note: assumes compiler arch was little-endian)
#if STACK_OVERFLOW_CHECK
#if USE_PTHREADS
Expand Down
9 changes: 8 additions & 1 deletion src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,14 @@ var PROFILING_FUNCS = 0;
// may be slightly misleading, as this is for any JS library element, and not
// just functions. For example, you can include the Browser object by adding
// "$Browser" to this list.
var DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = ['memcpy', 'memset', 'malloc', 'free'];
var DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = [
'memcpy',
'memset',
'malloc',
'free',
'emscripten_get_heap_size', // Used by dynamicAlloc() and -s FETCH=1
'emscripten_resize_heap' // Used by dynamicAlloc() and -s FETCH=1
];

// This list is also used to determine auto-exporting of library dependencies
// (i.e., functions that might be dependencies of JS library functions, that if
Expand Down
Loading

0 comments on commit 1655d72

Please sign in to comment.