diff options
-rw-r--r-- | src/library.js | 4 | ||||
-rw-r--r-- | src/preamble.js | 35 | ||||
-rw-r--r-- | src/runtime.js | 6 | ||||
-rw-r--r-- | src/settings.js | 7 | ||||
-rw-r--r-- | system/include/emscripten.h | 1 | ||||
-rw-r--r-- | tests/runner.py | 45 | ||||
-rw-r--r-- | tools/js-optimizer.js | 5 |
7 files changed, 94 insertions, 9 deletions
diff --git a/src/library.js b/src/library.js index 1d296981..a4278b9f 100644 --- a/src/library.js +++ b/src/library.js @@ -5493,8 +5493,8 @@ LibraryManager.library = { eval(Pointer_stringify(ptr)); }, - _Z21emscripten_run_scriptPKc: function(ptr) { - eval(Pointer_stringify(ptr)); + emscripten_run_script_int: function(ptr) { + return eval(Pointer_stringify(ptr)); }, $Profiling: { diff --git a/src/preamble.js b/src/preamble.js index 3fcdf1f8..7fd51733 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -532,6 +532,41 @@ var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32; var STACK_ROOT, STACKTOP, STACK_MAX; var STATICTOP; +#if USE_TYPED_ARRAYS +var LAST_STATICTOP; +function enlargeMemory() { + // LAST_STATICTOP is the previous top, TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top. +#if ASSERTIONS + assert(STATICTOP >= TOTAL_MEMORY && LAST_STATICTOP < TOTAL_MEMORY); + assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite +#endif + while (TOTAL_MEMORY <= STATICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it + TOTAL_MEMORY = alignMemoryPage(TOTAL_MEMORY*1.25); + } +#if USE_TYPED_ARRAYS == 1 + var oldIHEAP = IHEAP; + HEAP = IHEAP = new Int32Array(TOTAL_MEMORY); + IHEAP.set(oldIHEAP); +#if USE_FHEAP + var oldFHEAP = FHEAP; + FHEAP = new Float64Array(TOTAL_MEMORY); + FHEAP.set(oldFHEAP); +#endif +#endif +#if USE_TYPED_ARRAYS == 2 + var oldHEAP8 = HEAP8; + var buffer = new ArrayBuffer(TOTAL_MEMORY); + HEAP8 = new Int8Array(buffer); + HEAP16 = new Int16Array(buffer); + HEAP32 = new Int32Array(buffer); + HEAPU8 = new Uint8Array(buffer); + HEAPU16 = new Uint16Array(buffer); + HEAPU32 = new Uint32Array(buffer); + HEAPF32 = new Float32Array(buffer); + HEAP8.set(oldHEAP8); +#endif +} +#endif var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}}; diff --git a/src/runtime.js b/src/runtime.js index a6261c74..e0eb7404 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -56,7 +56,11 @@ var RuntimeGenerator = { // An allocation that cannot be free'd staticAlloc: function(size) { - return RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP); + var ret = ''; + if (USE_TYPED_ARRAYS) ret += 'LAST_STATICTOP = STATICTOP;' + ret += RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP); + if (USE_TYPED_ARRAYS) ret += 'if (STATICTOP >= TOTAL_MEMORY) enlargeMemory();' + return ret; }, alignMemory: function(target, quantum) { diff --git a/src/settings.js b/src/settings.js index 0964d4bb..4dc94f4a 100644 --- a/src/settings.js +++ b/src/settings.js @@ -33,10 +33,9 @@ var INIT_STACK = 1; // Whether to initialize memory on the stack to 0. var INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to 0. var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This ensures it will be // in a flat array. This only matters in non-typed array builds. -var TOTAL_MEMORY = 50*1024*1024; // The total amount of memory to use. This mainly matters in - // typed array builds - accessing memory about this value will - // return undefined values and lead to serious problems, and there - // is currently no warning about that! +var TOTAL_MEMORY = 50*1024*1024; // The total amount of memory to use. Using more memory than this will + // cause us to expand the heap, which can be costly with typed arrays: + // we need to copy the old heap into a new one in that case. // Code embetterments var MICRO_OPTS = 0; // Various micro-optimizations, like nativizing variables diff --git a/system/include/emscripten.h b/system/include/emscripten.h index 482f7ef3..7b135c5a 100644 --- a/system/include/emscripten.h +++ b/system/include/emscripten.h @@ -16,6 +16,7 @@ extern "C" { * eval() the given script. */ extern void emscripten_run_script(const char *script); +extern int emscripten_run_script_int(const char *script); /* * This macro-looking function will cause Emscripten to diff --git a/tests/runner.py b/tests/runner.py index 04913a11..aa1d5922 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -1579,13 +1579,14 @@ if 'benchmark' not in str(sys.argv): def test_emscripten_api(self): #if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME') - src = ''' + src = r''' #include <stdio.h> #include "emscripten.h" int main() { // EMSCRIPTEN_COMMENT("hello from the source"); emscripten_run_script("print('hello world' + '!')"); + printf("*%d*\n", emscripten_run_script_int("5*20")); return 0; } ''' @@ -1594,7 +1595,47 @@ if 'benchmark' not in str(sys.argv): src = open(filename, 'r').read() # TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src - self.do_run(src, 'hello world!', post_build=check) + self.do_run(src, 'hello world!\n*100*', post_build=check) + + def test_memorygrowth(self): + # With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY, + # since we then need to enlarge the heap(s). + src = r''' + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <assert.h> + #include "emscripten.h" + + int main() + { + char *buf1 = (char*)malloc(100); + char *data1 = "hello"; + memcpy(buf1, data1, strlen(data1)+1); + + float *buf2 = (float*)malloc(100); + float pie = 4.955; + memcpy(buf2, &pie, sizeof(float)); + + printf("*pre: %s,%.3f*\n", buf1, buf2[0]); + + int totalMemory = emscripten_run_script_int("TOTAL_MEMORY"); + char *buf3 = (char*)malloc(totalMemory*2); + char *buf4 = (char*)malloc(100); + float *buf5 = (float*)malloc(100); + //printf("totalMemory: %d bufs: %d,%d,%d,%d,%d\n", totalMemory, buf1, buf2, buf3, buf4, buf5); + assert((int)buf4 > (int)totalMemory && (int)buf5 > (int)totalMemory); + + printf("*%s,%.3f*\n", buf1, buf2[0]); // the old heap data should still be there + + memcpy(buf4, buf1, strlen(data1)+1); + memcpy(buf5, buf2, sizeof(float)); + printf("*%s,%.3f*\n", buf4, buf5[0]); // and the new heap space should work too + + return 0; + } + ''' + self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*') def test_ssr(self): # struct self-ref src = ''' diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index e889c7a3..d22de39c 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -193,6 +193,11 @@ function unGlobalize(ast) { // - and in library/shell code too! - we should never rely on // undefined being assigned. So we can simply remove those assignments. // +// Note: An inlined function that kept a large value referenced, may +// keep that references when inlined, if we remove the setting to +// undefined. This is not dangerous in compiled code, but might be +// in supporting code (for example, holding on to the HEAP when copying). +// // This pass assumes that unGlobalize has been run, so undefined // is now explicit. function removeAssignsToUndefined(ast) { |