line-specific CORRECT_OVERFLOWS and CORRECT_SIGNS

This commit is contained in:
Alon Zakai 2011-02-19 15:45:17 -08:00
Родитель f4a934a2ad
Коммит f81feaff96
8 изменённых файлов: 126 добавлений и 22 удалений

Просмотреть файл

@ -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');

Просмотреть файл

@ -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;
}
};

Просмотреть файл

@ -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];
}
};

Просмотреть файл

@ -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 + ')';
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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;