diff options
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | src/analyzer.js | 20 | ||||
-rw-r--r-- | src/jsifier.js | 5 | ||||
-rw-r--r-- | src/library.js | 8 | ||||
-rw-r--r-- | src/preamble.js | 4 | ||||
-rw-r--r-- | src/runtime.js | 8 | ||||
-rw-r--r-- | tests/runner.py | 123 |
7 files changed, 159 insertions, 11 deletions
@@ -12,3 +12,5 @@ under the licensing terms detailed in LICENSE. * David Claughton <dave@eclecticdave.com> * David Yip <yipdw@member.fsf.org> * Julien Hamaide <julien.hamaide@gmail.com> + + diff --git a/src/analyzer.js b/src/analyzer.js index 4ff5d2d9..7d99ab69 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -785,6 +785,26 @@ function analyzer(data, sidePass) { delete item.allocatedSize; } func.initialStack = index; + // We need to note if stack allocations other than initial allocs can happen here + // (for example, via alloca). If so, we need to rewind the stack when we leave. + func.otherStackAllocations = false; + var finishedInitial = false; + for (var i = 0; i < lines.length; i++) { + var item = lines[i].value; + if (!item || item.intertype != 'alloca') { + finishedInitial = true; + continue; + } + if (item.intertype == 'alloca' && finishedInitial) { + func.otherStackAllocations = true; + } + } + // by-value params are also causes of additional allocas (although we could in theory make them normal allocas too) + func.params.forEach(function(param) { + if (param.byVal) { + func.otherStackAllocations = true; + } + }); }); this.forwardItem(data, 'Relooper'); } diff --git a/src/jsifier.js b/src/jsifier.js index a750f805..8a75e49f 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -505,7 +505,8 @@ function JSify(data, functionsOnly, givenFunctions) { + '}\n'; } - func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack) + ';\n'; + // Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up. + func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n'; // Make copies of by-value params // XXX It is not clear we actually need this. While without this we fail, it does look like @@ -907,7 +908,7 @@ function JSify(data, functionsOnly, givenFunctions) { return ret; }); makeFuncLineActor('return', function(item) { - var ret = RuntimeGenerator.stackExit(item.funcData.initialStack) + ';\n'; + var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations) + ';\n'; if (PROFILE) { ret += 'if (PROFILING) { ' + 'PROFILING_NODE.time += Date.now() - __profilingStartTime__; ' diff --git a/src/library.js b/src/library.js index 58a48d94..6329a67d 100644 --- a/src/library.js +++ b/src/library.js @@ -4199,11 +4199,11 @@ LibraryManager.library = { throw 'Assertion failed: ' + Pointer_stringify(condition) + ', at: ' + [Pointer_stringify(filename), line, Pointer_stringify(func)]; }, - __cxa_guard_acquire: function() { - return 1; + __cxa_guard_acquire: function(variable) { + return !{{{ makeGetValue(0, 'variable', 'i8') }}} }, - __cxa_guard_release: function() { - return 1; + __cxa_guard_release: function(variable) { + {{{ makeSetValue(0, 'variable', '1', 'i8') }}} }, _ZTVN10__cxxabiv117__class_type_infoE: [1], // no inherited classes diff --git a/src/preamble.js b/src/preamble.js index c8e3570a..25e3e754 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -178,6 +178,7 @@ var CorrectionsMonitor = { #endif }, +#if PGO print: function() { var items = []; for (var sig in this.sigs) { @@ -194,6 +195,7 @@ var CorrectionsMonitor = { print(item.sig + ' : ' + item.total + ' hits, %' + (Math.ceil(100*item.fails/item.total)) + ' failures'); } } +#end }; #if CHECK_OVERFLOWS @@ -659,7 +661,9 @@ function __shutdownRuntime__() { // allow browser to GC, set heaps to null? // Print summary of correction activity +#if PGO CorrectionsMonitor.print(); +#endif } diff --git a/src/runtime.js b/src/runtime.js index 76b01089..605de749 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -29,8 +29,8 @@ var RuntimeGenerator = { return ret; }, - stackEnter: function(initial) { - if (initial === 0 && SKIP_STACK_IN_SMALL) return ''; + stackEnter: function(initial, force) { + if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; if (USE_TYPED_ARRAYS === 2) initial = Runtime.forceAlign(initial); var ret = 'var __stackBase__ = STACKTOP; STACKTOP += ' + initial; if (ASSERTIONS) { @@ -42,8 +42,8 @@ var RuntimeGenerator = { return ret; }, - stackExit: function(initial) { - if (initial === 0 && SKIP_STACK_IN_SMALL) return ''; + stackExit: function(initial, force) { + if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return ''; var ret = ''; if (SAFE_HEAP) { ret += 'for (var i = __stackBase__; i < STACKTOP; i++) SAFE_HEAP_CLEAR(i);'; diff --git a/tests/runner.py b/tests/runner.py index 07d55650..5c2f5e13 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -1409,6 +1409,56 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): ''' self.do_run(src, 'z:1*', force_c=True) + if self.emcc_args is not None: # too slow in other modes + # We should not blow up the stack with numerous allocas + + src = ''' + #include <stdio.h> + #include <stdlib.h> + + func(int i) { + char *pc = (char *)alloca(100); + *pc = i; + (*pc)++; + return (*pc) % 10; + } + int main() { + int total = 0; + for (int i = 0; i < 1024*1024; i++) + total += func(i); + printf("ok:%d*\\n", total); + return 0; + } + ''' + self.do_run(src, 'ok:-32768*', force_c=True) + + # We should also not blow up the stack with byval arguments + src = r''' + #include<stdio.h> + struct vec { + int x, y, z; + vec(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {} + static vec add(vec a, vec b) { + return vec(a.x+b.x, a.y+b.y, a.z+b.z); + } + }; + int main() { + int total = 0; + for (int i = 0; i < 1000; i++) { + for (int j = 0; j < 1000; j++) { + vec c(i+i%10, j*2, i%255); + vec d(j*2, j%255, i%120); + vec f = vec::add(c, d); + total += (f.x + f.y + f.z) % 100; + total %= 10240; + } + } + printf("sum:%d*\n", total); + return 1; + } + ''' + self.do_run(src, 'sum:9780*') + def test_array2(self): src = ''' #include <stdio.h> @@ -3804,6 +3854,35 @@ def process(filename): return 1; } ''', 'hello world', includes=[path_from_root('tests', 'libcxx', 'include')]); + + def test_static_variable(self): + src = ''' + #include <stdio.h> + + struct DATA + { + int value; + + DATA() + { + value = 0; + } + }; + + DATA & GetData() + { + static DATA data; + + return data; + } + + int main() + { + GetData().value = 10; + printf( "value:%i", GetData().value ); + } + ''' + self.do_run(src, 'value:10') def test_cubescript(self): if self.emcc_args is not None and '-O2' in self.emcc_args: @@ -5529,7 +5608,6 @@ elif 'benchmark' in str(sys.argv): self.do_benchmark(src, [], 'lastprime: 1297001.') def test_memops(self): - # memcpy would also be interesting, however native code uses SSE/NEON/etc. and is much, much faster than JS can be src = ''' #include<stdio.h> #include<string.h> @@ -5552,6 +5630,49 @@ elif 'benchmark' in str(sys.argv): ''' self.do_benchmark(src, [], 'final: 720.') + def zzztest_copy(self): + src = r''' + #include<stdio.h> + struct vec { + int x, y, z; + int r, g, b; + vec(int x_, int y_, int z_, int r_, int g_, int b_) : x(x_), y(y_), z(z_), r(r_), g(g_), b(b_) {} + static vec add(vec a, vec b) { + return vec(a.x+b.x, a.y+b.y, a.z+b.z, a.r+b.r, a.g+b.g, a.b+b.b); + } + void norm() { + x %= 1024; + y %= 1024; + z %= 1024; + r %= 1024; + b %= 1024; + g %= 1024; + } + int sum() { return x + y + z + r + g + b; } + }; + int main() { + int total = 0; + for (int i = 0; i < 2500; i++) { + for (int j = 0; j < 1000; j++) { + vec c(i, i+i%10, j*2, i%255, j%120, i%15); + vec d(j+i%10, j*2, j%255, i%120, j%15, j); + vec e = c; + c.norm(); + d.norm(); + vec f = vec::add(c, d); + f = vec::add(e, f); + f.norm(); + f = vec::add(d, f); + total += f.sum() % 100; + total %= 10240; + } + } + printf("sum:%d\n", total); + return 1; + } + ''' + self.do_benchmark(src, [], 'sum:3588\n', emcc_args=['-s', 'QUANTUM_SIZE=4', '-s', 'USE_TYPED_ARRAYS=2']) + def test_fannkuch(self): src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read() self.do_benchmark(src, ['10'], 'Pfannkuchen(10) = 38.') |