aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@mozilla.com>2011-01-01 16:56:22 -0800
committerAlon Zakai <azakai@mozilla.com>2011-01-01 16:56:22 -0800
commit785e01b0d00125bbf9b1d32ecfd98af311f4e985 (patch)
tree13d8f13d47189d41778d65a593a96d8be42e2b1a
parent0a2735ebc744bb877b20ff4b9669ab55b8e5100b (diff)
CORRECT_OVERFLOWS option; strengthening of various tests, and fixes a bug in python with typed arrays
-rw-r--r--src/jsifier.js26
-rw-r--r--src/preamble.js13
-rw-r--r--src/settings.js5
-rw-r--r--tests/runner.py31
4 files changed, 51 insertions, 24 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index af8d19ab..a753fd05 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -742,36 +742,46 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria
ident2 = makeUnSign(ident2, type);
}
}
- function checkOverflow(text) {
+ var bits = null;
+ if (item.type[0] === 'i') {
+ bits = parseInt(item.type.substr(1));
+ }
+ function handleOverflow(text) {
+ if (!bits) return text;
+ if (CORRECT_OVERFLOWS && bits <= 32) text = '(' + text + ')&' + (Math.pow(2, bits) - 1);
if (!CHECK_OVERFLOWS) return text;
- if (item.type[0] !== 'i') return text;
- var bits = item.type.substr(1);
return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')';
}
switch (op) {
- case 'add': return checkOverflow(ident1 + ' + ' + ident2);
- case 'sub': return checkOverflow(ident1 + ' - ' + ident2);
- case 'sdiv': case 'udiv': return checkOverflow('Math.floor(' + ident1 + ' / ' + ident2 + ')');
- case 'mul': return checkOverflow(ident1 + ' * ' + ident2);
+ // basic integer ops
+ case 'add': return handleOverflow(ident1 + ' + ' + ident2);
+ case 'sub': return handleOverflow(ident1 + ' - ' + ident2);
+ case 'sdiv': case 'udiv': return 'Math.floor(' + ident1 + ' / ' + ident2 + ')';
+ case 'mul': return handleOverflow(ident1 + ' * ' + ident2);
case 'urem': case 'srem': return 'Math.floor(' + ident1 + ' % ' + ident2 + ')';
case 'or': return ident1 + ' | ' + ident2; // TODO this forces into a 32-bit int - add overflow-style checks? also other bitops below us
case 'and': return ident1 + ' & ' + ident2;
case 'xor': return ident1 + ' ^ ' + ident2;
- case 'shl': return ident1 + ' << ' + ident2;
+ case 'shl': return handleOverflow(ident1 + ' << ' + ident2);
case 'ashr': return ident1 + ' >> ' + ident2;
case 'lshr': return ident1 + ' >>> ' + ident2;
+ // basic float ops
case 'fadd': return ident1 + ' + ' + ident2;
case 'fsub': return ident1 + ' - ' + ident2;
case 'fdiv': return ident1 + ' / ' + ident2;
case 'fmul': return ident1 + ' * ' + ident2;
case 'uitofp': case 'sitofp': return ident1;
case 'fptoui': case 'fptosi': return 'Math.floor(' + ident1 + ')';
+
+ // TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking
+ // Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs.
case 'icmp': {
switch (variant) {
case 'uge': case 'sge': return ident1 + ' >= ' + ident2;
case 'ule': case 'sle': return ident1 + ' <= ' + ident2;
case 'ugt': case 'sgt': return ident1 + ' > ' + ident2;
case 'ult': case 'slt': return ident1 + ' < ' + ident2;
+ // We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp
case 'ne': case 'une': return ident1 + ' != ' + ident2;
case 'eq': return ident1 + ' == ' + ident2;
default: throw 'Unknown icmp variant: ' + variant;
diff --git a/src/preamble.js b/src/preamble.js
index 181a3340..2bf7c17e 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -25,7 +25,7 @@ var SAFE_HEAP_ERRORS = 0;
var ACCEPTABLE_SAFE_HEAP_ERRORS = 0;
function SAFE_HEAP_ACCESS(dest, type, store) {
#if SAFE_HEAP_LOG
- //if (dest === A_NUMBER) print (new Error().stack); // Something like this may be useful, in debugging
+ //if (dest === A_NUMBER) print ([dest, type, store] + ' ' + new Error().stack); // Something like this may be useful, in debugging
#endif
if (type && type[type.length-1] == '*') type = 'i32'; // pointers are ints, for our purposes here
// Note that this will pass even with unions: You can store X, load X, then store Y and load Y.
@@ -77,13 +77,16 @@ function SAFE_HEAP_STORE(dest, value, type) {
}
}
function SAFE_HEAP_LOAD(dest, type) {
-#if SAFE_HEAP_LOG
- print('load : ' + dest + ' [' + type + '] |' + JSON.stringify([IHEAP[dest],FHEAP[dest]]) + '|');
-#endif
SAFE_HEAP_ACCESS(dest, type);
if (type in Runtime.FLOAT_TYPES) {
+#if SAFE_HEAP_LOG
+ print('load : ' + dest + ' [' + type + '] |' + FHEAP[dest] + '|');
+#endif
return FHEAP[dest];
} else {
+#if SAFE_HEAP_LOG
+ print('load : ' + dest + ' [' + type + '] |' + IHEAP[dest] + '|');
+#endif
return IHEAP[dest];
}
}
@@ -99,7 +102,7 @@ function __Z18UNPROTECT_HEAPADDRPv(dest) {
#if CHECK_OVERFLOWS
function CHECK_OVERFLOW(value, bits) {
assert(value !== Infinity && value !== -Infinity, 'Infinity!');
- assert(Math.abs(value) < Math.pow(2, bits-1), 'Overflow!');
+ assert(Math.abs(value) < Math.pow(2, bits), 'Overflow!');
return value;
}
#endif
diff --git a/src/settings.js b/src/settings.js
index 79b4e6fa..0bc6c88d 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -43,6 +43,11 @@ CHECK_OVERFLOWS = 0; // Add code that checks for overflows in integer math opera
// some factor, in order to get 'random' hash values - by taking
// that |value & hash_table_size| - then multiplying enough times will overflow.
// But instead, you can do |value = value & 30_BITS| in each iteration.
+CORRECT_OVERFLOWS = 1; // Experimental code that tries to prevent unexpected JS overflows in integer
+ // mathops, by doing controlled overflows (sort of parallel to a CPU).
+ // Note that as mentioned above in CHECK_OVERFLOWS, the best thing is to
+ // not rely on overflows in your C/C++ code, as even if this option works,
+ // it slows things down.
// Compiler debugging options
DEBUG_TAGS_SHOWING = [];
diff --git a/tests/runner.py b/tests/runner.py
index d6291ff9..157f5b38 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -127,7 +127,7 @@ class RunnerCore(unittest.TestCase):
def do_emscripten(self, filename, output_processor=None):
# Run Emscripten
exported_settings = {}
- for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'GUARD_MEMORY', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS']:
+ for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'GUARD_MEMORY', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS']:
exported_settings[setting] = eval(setting)
out = open(filename + '.o.js', 'w') if not OUTPUT_TO_SCREEN else None
timeout_run(Popen([EMSCRIPTEN, filename + '.o.ll', COMPILER_ENGINE[0], str(exported_settings).replace("'", '"')], stdout=out, stderr=STDOUT), TIMEOUT, 'Compiling')
@@ -1313,7 +1313,9 @@ if 'benchmark' not in sys.argv:
# XXX Warning: Running this in SpiderMonkey can lead to an extreme amount of memory being
# used, see Mozilla bug 593659.
global SAFE_HEAP; SAFE_HEAP = 0 # Has some actual loads of unwritten-to places, in the C++ code...
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0 # Overflows in hash loop... seems to work though, doesn't overflow too much
+
+ # Overflows happen in hash loop
+ global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
self.do_test(path_from_root(['tests', 'cubescript']), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
@@ -1335,19 +1337,23 @@ if 'benchmark' not in sys.argv:
self.do_ll_test(path_from_root(['tests', 'bullet', 'bulletTest.ll']), open(path_from_root(['tests', 'bullet', 'output.txt']), 'r').read())
def test_lua(self):
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0 # Overflows in luaS_newlstr hash loop... seems to work though, doesn't overflow too much
+ # Overflows in luaS_newlstr hash loop
+ global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
+
self.do_ll_test(path_from_root(['tests', 'lua', 'lua.ll']),
'hello lua world!\n\n\n17.00000000000\n\n\n1.00000000000\n\n\n2.00000000000\n\n\n3.00000000000\n\n\n4.00000000000\n\n\n7.00000000000',
args=['-e', '''print("hello lua world!");print(17);for x = 1,4 do print(x) end;print(10-3)'''],
f_opt_ll_file=path_from_root(['tests', 'lua', 'lua.Os.ll']))
def test_python(self):
- global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0 # Overflows in string_hash... seems to work though, doesn't overflow too much
+ # Overflows in string_hash
+ global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 1
+
global RELOOP; RELOOP = 0 # Too slow; we do care about typed arrays and OPTIMIZE though
- global SAFE_HEAP; SAFE_HEAP = 0 # Has bitfields etc.
+ global SAFE_HEAP; SAFE_HEAP = 0 # Has bitfields which are false positives. Also the PyFloat_Init tries to detect endianness.
self.do_ll_test(path_from_root(['tests', 'python', 'python.ll']),
- 'hello python world!\n\n[0, 2, 4, 6]\n\n5\n\n5.470',
- args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print '%f' % 5.47'''],
+ 'hello python world!\n\n[0, 2, 4, 6]\n\n5\n\n22\n\n5.470',
+ args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''],
js_engines=[V8_ENGINE]) # script stack space exceeded in SpiderMonkey, TODO
### Test cases in separate files
@@ -1420,7 +1426,9 @@ if 'benchmark' not in sys.argv:
assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e)
def test_check_overflow(self):
- if LLVM_OPTS: return # We check for overflows when !LLVM_OPTS
+ global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 1
+ global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 0
+
src = '''
#include<stdio.h>
int main() {
@@ -1445,16 +1453,17 @@ if 'benchmark' not in sys.argv:
exec('''
class %s(T):
def setUp(self):
- global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS
+ global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS, CORRECT_OVERFLOWS
COMPILER = '%s'
QUANTUM_SIZE = %d
llvm_opts = %d
embetter = %d
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = embetter
GUARD_MEMORY = 1-embetter
- SAFE_HEAP = 1 - (embetter and llvm_opts)
+ SAFE_HEAP = 1-(embetter and llvm_opts)
LLVM_OPTS = llvm_opts
- CHECK_OVERFLOWS = 1-llvm_opts
+ CHECK_OVERFLOWS = 1-(embetter or llvm_opts)
+ CORRECT_OVERFLOWS = 1-(embetter and llvm_opts)
if LLVM_OPTS:
self.pick_llvm_opts(3, True)
TT = %s