line-specific CORRECT_OVERFLOWS and CORRECT_SIGNS
This commit is contained in:
Родитель
f4a934a2ad
Коммит
f81feaff96
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче