diff options
author | Alon Zakai <azakai@mozilla.com> | 2011-02-19 15:45:17 -0800 |
---|---|---|
committer | Alon Zakai <azakai@mozilla.com> | 2011-02-19 15:45:17 -0800 |
commit | f81feaff967ffdd8212ffe2da8579c4734fc7cbb (patch) | |
tree | a92d47ad3cad7146c704745426ed661714682a89 | |
parent | f4a934a2adec69bc82c42342c7924fdf259f64cc (diff) |
line-specific CORRECT_OVERFLOWS and CORRECT_SIGNS
-rw-r--r-- | src/compiler.js | 13 | ||||
-rw-r--r-- | src/framework.js | 20 | ||||
-rw-r--r-- | src/intertyper.js | 6 | ||||
-rw-r--r-- | src/jsifier.js | 4 | ||||
-rw-r--r-- | src/parseTools.js | 10 | ||||
-rw-r--r-- | src/settings.js | 5 | ||||
-rw-r--r-- | tests/runner.py | 86 | ||||
-rw-r--r-- | tests/zlib/trees.c | 4 |
8 files changed, 126 insertions, 22 deletions
diff --git a/src/compiler.js b/src/compiler.js index b4e9530a..72ef554c 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -8,6 +8,10 @@ if (!this['read']) { read = function(f) { snarf(f) }; } +// Basic utilities + +load('utility.js'); + // Load settings, can be overridden by commandline load('settings.js'); @@ -18,9 +22,16 @@ for (setting in settings) { } var CONSTANTS = { 'QUANTUM_SIZE': QUANTUM_SIZE }; +if (CORRECT_SIGNS === 2) { + CORRECT_SIGNS_LINES = set(CORRECT_SIGNS_LINES); // for fast checking +} + +if (CORRECT_OVERFLOWS === 2) { + CORRECT_OVERFLOWS_LINES = set(CORRECT_OVERFLOWS_LINES); // for fast checking +} + // Load compiler code -load('utility.js'); load('framework.js'); load('parseTools.js'); load('intertyper.js'); diff --git a/src/framework.js b/src/framework.js index e9ff592e..959d73fd 100644 --- a/src/framework.js +++ b/src/framework.js @@ -140,6 +140,12 @@ Substrate.prototype = { } }; +// Global access to the currently-being processed item. +// Note that if you overload process in Actor, this will need to be set if you rely on it. +var Framework = { + currItem: null +}; + Actor = function() { }; Actor.prototype = { process: function(items) { @@ -147,7 +153,9 @@ Actor.prototype = { for (var i = 0; i < items.length; i++) { var item = items[i]; try { + Framework.currItem = item; var outputs = this.processItem(item); + Framework.currItem = null; // Do not keep an unneeded reference. Note that we don't care about this if an exception is thrown if (outputs) { ret = ret.concat(outputs); } @@ -157,18 +165,6 @@ Actor.prototype = { } } return ret; - }, - processPairs: function(items, func) { - var ret = []; - for (var i = 0; i < items.length; i += 2) { - try { - ret = ret.concat(func(items[i], items[i+1])); - } catch (e) { - print("Exception in processPairs(), current items are: " + dump(items[i]) + ' :::: ' + dump(items[i+1])); - throw e; - } - } - return ret; } }; diff --git a/src/intertyper.js b/src/intertyper.js index e4a3cf4b..a8254b30 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -86,6 +86,12 @@ var Debugging = { getComment: function(lineNum) { return lineNum in this.llvmLineToSourceLine ? ' //@line ' + this.llvmLineToSourceLine[lineNum] + ' "' + this.llvmLineToSourceFile[lineNum] + '"' : ''; + }, + + getIdentifier: function(lineNum) { + var sourceFile = this.llvmLineToSourceFile[lineNum]; + if (!sourceFile) return null; + return sourceFile.split('/').slice(-1)[0] + ':' + this.llvmLineToSourceLine[lineNum]; } }; diff --git a/src/jsifier.js b/src/jsifier.js index a6ce4c6a..f3e55a39 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -758,7 +758,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria function makeSignOp(value, type, op) { // TODO: If value isNumber, do this at compile time if (!value) return value; - if (!CORRECT_SIGNS && !CHECK_SIGNS) return value; + if (!correctSigns() && !CHECK_SIGNS) return value; if (type in Runtime.INT_TYPES) { var bits = parseInt(type.substr(1)); // shortcuts for 32-bit case @@ -777,7 +777,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria function handleOverflow(text, bits) { if (!bits) return text; - if (CORRECT_OVERFLOWS && bits <= 32) text = '(' + text + ')&' + (Math.pow(2, bits) - 1); + if (bits <= 32 && correctOverflows()) text = '(' + text + ')&' + (Math.pow(2, bits) - 1); if (!CHECK_OVERFLOWS) return text; return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')'; } diff --git a/src/parseTools.js b/src/parseTools.js index fed1ee7c..81831d75 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -537,3 +537,13 @@ function indentify(text, indent) { return text.split('\n').map(function(line) { return indent + line }).join('\n'); } +// Correction tools + +function correctSigns() { + return CORRECT_SIGNS === 1 || (CORRECT_SIGNS === 2 && Debugging.getIdentifier(Framework.currItem.lineNum) in CORRECT_SIGNS_LINES); +} + +function correctOverflows() { + return CORRECT_OVERFLOWS === 1 || (CORRECT_OVERFLOWS === 2 && Debugging.getIdentifier(Framework.currItem.lineNum) in CORRECT_OVERFLOWS_LINES); +} + diff --git a/src/settings.js b/src/settings.js index 4eb6b6a4..38e75baa 100644 --- a/src/settings.js +++ b/src/settings.js @@ -16,6 +16,8 @@ QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. 1 w CORRECT_SIGNS = 1; // Whether we make sure to convert unsigned values to signed values. // Decreases performance with additional runtime checks. Might not be // needed in some kinds of code. + // If equal to 2, done on a line-by-line basis according to + // CORRECT_SIGNS_LINES CHECK_SIGNS = 0; // Runtime errors for signing issues that need correcting. // It is recommended to use this in // order to find if your code needs CORRECT_SIGNS. If you can get your @@ -56,6 +58,9 @@ CORRECT_OVERFLOWS = 1; // Experimental code that tries to prevent unexpected JS // not rely on overflows in your C/C++ code, as even if this option works, // it slows things down. // + // If equal to 2, done on a line-by-line basis according to + // CORRECT_OVERFLOWS_LINES + // // NOTE: You can introduce signing issues by using this option. If you // take a large enough 32-bit value, and correct it for overflows, // you may get a negative number, as JS & operations are signed. diff --git a/tests/runner.py b/tests/runner.py index cfe0dd55..882a7403 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -163,8 +163,12 @@ 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', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS']: - exported_settings[setting] = eval(setting) + for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'GUARD_MEMORY', 'USE_TYPED_ARRAYS', 'SAFE_HEAP', 'CHECK_OVERFLOWS', 'CORRECT_OVERFLOWS', 'CORRECT_SIGNS', 'CHECK_SIGNS', 'CORRECT_OVERFLOWS_LINES', 'CORRECT_SIGNS_LINES']: + value = eval(setting) + if type(value) == str: + if value == '': continue + value = eval(value) + exported_settings[setting] = value 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') output = open(filename + '.o.js').read() @@ -1748,13 +1752,87 @@ if 'benchmark' not in sys.argv: # This test *should* fail assert 'Assertion failed' in str(e), str(e) + def test_linebyline_corrections(self): + global COMPILER_TEST_OPTS + COMPILER_TEST_OPTS = ['-g'] + + global CHECK_SIGNS; CHECK_SIGNS = 0 + global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0 + global CORRECT_SIGNS, CORRECT_OVERFLOWS, CORRECT_SIGNS_LINES, CORRECT_OVERFLOWS_LINES + + src = ''' + #include <stdio.h> + #include <assert.h> + + int main() + { + int varey = 100; + unsigned int MAXEY = -1; + printf("*%d*\\n", varey >= MAXEY); // 100 >= -1? not in unsigned! + } + ''' + + CORRECT_SIGNS = 0 + self.do_test(src, '*1*') # This is a fail - we expect 0 + + CORRECT_SIGNS = 1 + self.do_test(src, '*0*') # Now it will work properly + + # And now let's fix just that one line + CORRECT_SIGNS = 2 + CORRECT_SIGNS_LINES = '["src.cpp:9"]' + self.do_test(src, '*0*') + + # Fixing the wrong line should not work + CORRECT_SIGNS = 2 + CORRECT_SIGNS_LINES = '["src.cpp:3"]' + self.do_test(src, '*1*') + + src = ''' + #include<stdio.h> + int main() { + int t = 77; + for (int i = 0; i < 30; i++) { + t = t*5 + 1; + } + printf("*%d,%d*\\n", t, t & 127); + return 0; + } + ''' + + correct = '*186854335,63*' + CORRECT_OVERFLOWS = 0 + try: + self.do_test(src, correct) + raise Exception('UNEXPECTED-PASS') + except Exception, e: + assert 'UNEXPECTED' not in str(e), str(e) + assert 'Expected to find' in str(e), str(e) + + CORRECT_OVERFLOWS = 1 + self.do_test(src, correct) # Now it will work properly + + # And now let's fix just that one line + CORRECT_OVERFLOWS = 2 + CORRECT_OVERFLOWS_LINES = '["src.cpp:6"]' + self.do_test(src, correct) + + # Fixing the wrong line should not work + CORRECT_OVERFLOWS = 2 + CORRECT_OVERFLOWS_LINES = '["src.cpp:3"]' + try: + self.do_test(src, correct) + raise Exception('UNEXPECTED-PASS') + except Exception, e: + assert 'UNEXPECTED' not in str(e), str(e) + assert 'Expected to find' in str(e), str(e) # Generate tests for all our compilers def make_test(name, compiler, llvm_opts, embetter): exec(''' class %s(T): def setUp(self): - global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS, CORRECT_OVERFLOWS, CORRECT_SIGNS, CHECK_SIGNS, COMPILER_TEST_OPTS + global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS, LLVM_OPTS, SAFE_HEAP, CHECK_OVERFLOWS, CORRECT_OVERFLOWS, CORRECT_OVERFLOWS_LINES, CORRECT_SIGNS, CORRECT_SIGNS_LINES, CHECK_SIGNS, COMPILER_TEST_OPTS COMPILER = '%s' QUANTUM_SIZE = %d @@ -1767,6 +1845,7 @@ class %s(T): CHECK_OVERFLOWS = 1-(embetter or llvm_opts) CORRECT_OVERFLOWS = 1-(embetter and llvm_opts) CORRECT_SIGNS = 0 + CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = '' CHECK_SIGNS = 0 #1-(embetter or llvm_opts) if LLVM_OPTS: self.pick_llvm_opts(3, True) @@ -1802,6 +1881,7 @@ else: USE_TYPED_ARRAYS = 0 GUARD_MEMORY = SAFE_HEAP = CHECK_OVERFLOWS = CORRECT_OVERFLOWS = 0 CORRECT_SIGNS = 0 + CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = '' LLVM_OPTS = 1 USE_CLOSURE_COMPILER = 1 diff --git a/tests/zlib/trees.c b/tests/zlib/trees.c index 18be5013..56e9bb1c 100644 --- a/tests/zlib/trees.c +++ b/tests/zlib/trees.c @@ -722,11 +722,7 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; -#ifndef EMSCRIPTEN_OPTS tree[max_code+1].Len = (ush)0xffff; /* guard */ -#else - tree[max_code+1].Len = (ush)0x7fff; /* guard. Emscripten: Prevents llvm_gcc from creating '-1' which needs unsigning later */ -#endif for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; |