aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-10-27 20:07:07 -0700
committerAlon Zakai <alonzakai@gmail.com>2012-10-27 20:07:07 -0700
commited88bc7051a61e05c6e85e792d56513826722d2e (patch)
treed40113a39ebe21626cb193e1a5652f621052e942
parentb1989519a9e66a8c2f5b2174a2eadb53bb8f9f56 (diff)
memory growth must be manually enabled with ALLOW_MEMORY_GROWTH, in which case the eliminator runs in safe mode
-rwxr-xr-xemcc7
-rw-r--r--src/preamble.js6
-rw-r--r--src/settings.js7
-rwxr-xr-xtests/runner.py17
4 files changed, 34 insertions, 3 deletions
diff --git a/emcc b/emcc
index c26fb200..36497e55 100755
--- a/emcc
+++ b/emcc
@@ -1045,11 +1045,14 @@ try:
if shared.Settings.RELOOP:
js_optimizer_queue += ['hoistMultiples', 'loopOptimizer']
- js_optimizer_queue += ['eliminate']
+ def get_eliminate():
+ return 'eliminate' if not shared.Settings.ALLOW_MEMORY_GROWTH else 'eliminateMemSafe'
+
+ js_optimizer_queue += [get_eliminate()]
js_optimizer_queue += ['simplifyExpressionsPre']
if shared.Settings.RELOOP:
- js_optimizer_queue += ['optimizeShiftsAggressive', 'eliminate'] # aggressive shifts optimization requires loops, it breaks on switches
+ js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches
if closure:
flush_js_optimizer_queue()
diff --git a/src/preamble.js b/src/preamble.js
index b197ef02..24277014 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -576,9 +576,12 @@ var STACK_ROOT, STACKTOP, STACK_MAX;
var STATICTOP;
#if USE_TYPED_ARRAYS
function enlargeMemory() {
+#if ALLOW_MEMORY_GROWTH == 0
+ abort('Cannot enlarge memory arrays. Adjust TOTAL_MEMORY or compile with ALLOW_MEMORY_GROWTH');
+#else
// TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top.
#if ASSERTIONS
- Module.printErr('Warning: Enlarging memory arrays, this is not fast, and can also break in high optimization levels where we assume globals are not modified! ' + [STATICTOP, TOTAL_MEMORY]); // XXX perhaps never do elimination optimizations of calls that can lead to resizing, to avoid HEAP[malloc()] = X; where JS semantic will write to the old HEAP if malloc replaces it
+ Module.printErr('Warning: Enlarging memory arrays, this is not fast, and ALLOW_MEMORY_GROWTH is not fully tested with all optimizations on! ' + [STATICTOP, TOTAL_MEMORY]); // We perform safe elimination instead of elimination in this mode, but if you see this error, try to disable it and other optimizations entirely
assert(STATICTOP >= TOTAL_MEMORY);
assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite
#endif
@@ -609,6 +612,7 @@ function enlargeMemory() {
HEAPF64 = new Float64Array(buffer);
HEAP8.set(oldHEAP8);
#endif
+#endif
}
#endif
diff --git a/src/settings.js b/src/settings.js
index a1c41de7..7e7caa6f 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -48,6 +48,13 @@ var TOTAL_MEMORY = 10*1024*1024; // The total amount of memory to use. Using mor
// we need to copy the old heap into a new one in that case.
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 ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to allocate more memory than
+ // we can (TOTAL_MEMORY). If true, we will grow the memory arrays at
+ // runtime, seamlessly and dynamically. This has a performance cost though,
+ // both during the actual growth and in general (the latter is because in
+ // that case we must be careful about optimizations, in particular the
+ // eliminator). Note that memory growth is only supported with typed
+ // arrays.
// Code embetterments
var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables
diff --git a/tests/runner.py b/tests/runner.py
index 1f60e7fb..5780b910 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -2742,6 +2742,8 @@ def process(filename):
self.do_run(src, 'Inline JS is very cool')
def test_memorygrowth(self):
+ if Settings.USE_TYPED_ARRAYS == 0: return self.skip('memory growth is only supported with typed arrays')
+
# 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'''
@@ -2779,7 +2781,22 @@ def process(filename):
return 0;
}
'''
+
+ # Fail without memory growth
+ self.do_run(src, 'Cannot enlarge memory arrays. Adjust TOTAL_MEMORY or compile with ALLOW_MEMORY_GROWTH')
+ fail = open('src.cpp.o.js').read()
+
+ # Win with it
+ Settings.ALLOW_MEMORY_GROWTH = 1
self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*')
+ win = open('src.cpp.o.js').read()
+
+ if self.emcc_args and '-O2' in self.emcc_args:
+ # Make sure ALLOW_MEMORY_GROWTH generates different code (should be less optimized)
+ code_start = 'var TOTAL_MEMORY = '
+ fail = fail[fail.find(code_start):]
+ win = win[win.find(code_start):]
+ assert len(fail) < len(win), 'failing code - without memory growth on - is more optimized, and smaller'
def test_ssr(self): # struct self-ref
src = '''