aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--src/analyzer.js20
-rw-r--r--src/jsifier.js5
-rw-r--r--src/library.js8
-rw-r--r--src/preamble.js4
-rw-r--r--src/runtime.js8
-rw-r--r--tests/runner.py123
7 files changed, 159 insertions, 11 deletions
diff --git a/AUTHORS b/AUTHORS
index 7b60799b..b89b9eb4 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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.')