aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@mozilla.com>2011-02-19 15:45:17 -0800
committerAlon Zakai <azakai@mozilla.com>2011-02-19 15:45:17 -0800
commitf81feaff967ffdd8212ffe2da8579c4734fc7cbb (patch)
treea92d47ad3cad7146c704745426ed661714682a89
parentf4a934a2adec69bc82c42342c7924fdf259f64cc (diff)
line-specific CORRECT_OVERFLOWS and CORRECT_SIGNS
-rw-r--r--src/compiler.js13
-rw-r--r--src/framework.js20
-rw-r--r--src/intertyper.js6
-rw-r--r--src/jsifier.js4
-rw-r--r--src/parseTools.js10
-rw-r--r--src/settings.js5
-rw-r--r--tests/runner.py86
-rw-r--r--tests/zlib/trees.c4
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;