aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/library.js19
-rw-r--r--src/parseTools.js12
-rw-r--r--src/preamble.js69
-rw-r--r--src/settings.js13
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.