diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/library.js | 19 | ||||
-rw-r--r-- | src/parseTools.js | 12 | ||||
-rw-r--r-- | src/preamble.js | 69 | ||||
-rw-r--r-- | src/settings.js | 13 |
4 files changed, 96 insertions, 17 deletions
diff --git a/src/library.js b/src/library.js index 471bbc96..bd9491af 100644 --- a/src/library.js +++ b/src/library.js @@ -1297,9 +1297,15 @@ function reSign(value, bits, ignore) { if (value <= 0) return value; var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32 : Math.pow(2, bits-1); +#if CHECK_SIGNS + var noted = false; +#endif if (value >= half) { #if CHECK_SIGNS - if (!ignore) CorrectionsMonitor.note('ReSign'); + if (!ignore) { + CorrectionsMonitor.note('ReSign'); + noted = true; + } #endif value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts } @@ -1308,9 +1314,18 @@ function reSign(value, bits, ignore) { // without CHECK_SIGNS, we would just do the |0 shortcut, so check that that // would indeed give the exact same result. if (bits === 32 && (value|0) !== value && typeof value !== 'boolean') { - if (!ignore) CorrectionsMonitor.note('ReSign'); + if (!ignore) { + CorrectionsMonitor.note('ReSign'); + noted = true; + } } + if (!noted) CorrectionsMonitor.note('ReSign', true); #endif return value; } +// Just a stub. We don't care about noting compile-time corrections. But they are called. +var CorrectionsMonitor = { + note: function(){} +}; + diff --git a/src/parseTools.js b/src/parseTools.js index 9e0fc24c..5dec458e 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -848,9 +848,15 @@ function getGetElementPtrIndexes(item) { function handleOverflow(text, bits) { if (!bits) return text; - if (bits <= 32 && correctOverflows()) text = '(' + text + ')&' + (Math.pow(2, bits) - 1); - if (!CHECK_OVERFLOWS || correctSpecificOverflow()) return text; // If we are correcting a specific overflow here, do not check for it - return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')'; + var correct = correctOverflows(); + warn(!correct || bits <= 32, 'Cannot correct overflows of this many bits: ' + bits); + if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')'; + if (!correct) return text; + if (bits <= 32) { + return '(' + text + ')&' + (Math.pow(2, bits) - 1); + } else { + return text; // We warned about this earlier + } } // From parseLLVMSegment diff --git a/src/preamble.js b/src/preamble.js index e05e1e95..cb4e8571 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -103,19 +103,47 @@ function __Z18UNPROTECT_HEAPADDRPv(dest) { #endif var CorrectionsMonitor = { - MAX_ALLOWED: 0, // Infinity, +#if AUTO_OPTIMIZE + MAX_ALLOWED: Infinity, +#else + MAX_ALLOWED: 0, // XXX +#endif corrections: 0, sigs: {}, - note: function(type) { - var sig = type + '|' + new Error().stack; + note: function(type, succeed, sig) { + if (!succeed) { + this.corrections++; + if (this.corrections >= this.MAX_ALLOWED) abort('\n\nToo many corrections!'); + } +#if AUTO_OPTIMIZE + if (succeed) return; // XXX - enable this later on, as a profiling tool + if (!sig) + sig = (new Error().stack).toString().split('\n')[2].split(':').slice(-1)[0]; // Spidermonkey-specific FIXME + sig = type + '|' + sig; if (!this.sigs[sig]) { - print('Correction: ' + sig); - this.sigs[sig] = 0; + //print('Correction: ' + sig); + this.sigs[sig] = [0, 0]; // fail, succeed + } + this.sigs[sig][succeed ? 1 : 0]++; +#endif + }, + + print: function() { + var items = []; + for (var sig in this.sigs) { + items.push({ + sig: sig, + fails: this.sigs[sig][0], + succeeds: this.sigs[sig][1], + total: this.sigs[sig][0] + this.sigs[sig][1] + }); + } + items.sort(function(x, y) { return y.total - x.total; }); + for (var i = 0; i < items.length; i++) { + var item = items[i]; + print(item.sig + ' : ' + item.total + ' hits, %' + (Math.floor(100*item.fails/item.total)) + ' failures'); } - this.sigs[sig]++; - this.corrections++; - if (this.corrections >= this.MAX_ALLOWED) abort('\n\nToo many corrections!'); } }; @@ -131,8 +159,28 @@ function cRound(x) { //======================================== function CHECK_OVERFLOW(value, bits, ignore) { if (ignore) return value; - if (value === Infinity || value === -Infinity || Math.abs(value) >= Math.pow(2, bits)) { + var twopbits = Math.pow(2, bits); + var twopbits1 = Math.pow(2, bits-1); + // For signedness issue here, see settings.js, CHECK_SIGNED_OVERFLOWS +#if CHECK_SIGNED_OVERFLOWS + if (value === Infinity || value === -Infinity || value >= twopbits1 || value < -twopbits1) { + CorrectionsMonitor.note('SignedOverflow'); + if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) CorrectionsMonitor.note('Overflow'); +#else + if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) { CorrectionsMonitor.note('Overflow'); +#endif +#if CORRECT_OVERFLOWS + // Fail on >32 bits - we warned at compile time + if (bits <= 32) { + value = value & (twopbits - 1); + } +#endif + } else { +#if CHECK_SIGNED_OVERFLOWS + CorrectionsMonitor.note('SignedOverflow', 1); +#endif + CorrectionsMonitor.note('Overflow', 1); } return value; } @@ -296,6 +344,9 @@ function __shutdownRuntime__() { func(atexit.arg); } //HEAP = IHEAP = FHEAP = null; // allow browser to GC? + + // Print summary of correction activity + CorrectionsMonitor.print(); } diff --git a/src/settings.js b/src/settings.js index b50ac04d..45934c8d 100644 --- a/src/settings.js +++ b/src/settings.js @@ -63,9 +63,10 @@ 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. - // Note: CHECK_OVERFLOWS checks for overflows *after* CORRECT_OVERFLOWS - // has operated (if it has). So you must run *without* CORRECT_OVERFLOWS - // for this option to work. (Sorry for the discrepancy with CHECK_SIGNS - FIXME.) +CHECK_SIGNED_OVERFLOWS = 0; // Whether to allow *signed* overflows - our correction for overflows generates signed + // values (since we use &). This means that we correct some things are not strictly overflows, + // and we cause them to be signed (which may lead to unnecessary unSign()ing later). + // With this enabled, we check signed overflows for CHECK_OVERFLOWS 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 @@ -83,6 +84,12 @@ CORRECT_ROUNDINGS = 1; // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no // Math.floor is to negative, ceil to positive. With CORRECT_ROUNDINGS, // we will do slow but correct C rounding operations. +AUTO_OPTIMIZE = 0; // When run with the CHECK_* options, will not fail on errors. Instead, will + // keep a record of which checks succeeded and which failed. On shutdown, will + // print out that information. This is useful for knowing which lines need + // checking enabled and which do not, that is, this is a way to automate the + // generation of line data for CORRECT_*_LINES options + EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported, so they are guaranteed to // be accessible outside of the generated code. |