diff options
author | Alon Zakai <azakai@mozilla.com> | 2010-11-21 17:43:22 -0800 |
---|---|---|
committer | Alon Zakai <azakai@mozilla.com> | 2010-11-21 17:43:22 -0800 |
commit | 52d04311943f4ccd5ec86bb6982c6f755d7db888 (patch) | |
tree | 61d957c9bbac42f2f2a049138dcb238e5e79b5fc /src | |
parent | fa5bac952a9eb74d4964b8497454aac1b32299a5 (diff) |
SAFE_HEAP now validates the load-store consistency assumption, plus minor related fixes
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler.js | 6 | ||||
-rw-r--r-- | src/intertyper.js | 9 | ||||
-rw-r--r-- | src/jsifier.js | 26 | ||||
-rw-r--r-- | src/library.js | 8 | ||||
-rw-r--r-- | src/parseTools.js | 4 | ||||
-rw-r--r-- | src/preamble.js | 40 | ||||
-rw-r--r-- | src/runtime.js | 20 | ||||
-rw-r--r-- | src/utility.js | 5 |
8 files changed, 98 insertions, 20 deletions
diff --git a/src/compiler.js b/src/compiler.js index 7626bde5..395c7acd 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -12,12 +12,10 @@ load('settings.js'); load('utility.js'); load('enzymatic.js'); -load('library.js'); load('parseTools.js'); load('intertyper.js'); load('analyzer.js'); load('jsifier.js'); -load('runtime.js'); //=============================== // Main @@ -28,6 +26,9 @@ var settings = JSON.parse(readline()); for (setting in settings) { this[setting] = settings[setting]; } +var CONSTANTS = { 'QUANTUM_SIZE': QUANTUM_SIZE }; + +load('runtime.js'); // Sanity of settings @@ -43,5 +44,6 @@ do { } while(true); // Do it +eval(preprocess(read('library.js'), CONSTANTS)); print(JSify(analyzer(intertyper(lines)))); diff --git a/src/intertyper.js b/src/intertyper.js index e98012f9..db1a58f5 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -335,11 +335,17 @@ function intertyper(data, parseFunctions, baseLineNum) { var ident = item.tokens[0].text; while (item.tokens[2].text in set('private', 'constant', 'appending', 'global', 'weak_odr', 'internal', 'linkonce', 'linkonce_odr', 'weak', 'hidden')) item.tokens.splice(2, 1); + var external = false; + if (item.tokens[2].text === 'external') { + external = true; + item.tokens.splice(2, 1); + } var ret = { __result__: true, intertype: 'globalVariable', ident: ident, type: item.tokens[2].text, + external: external, lineNum: item.lineNum, }; if (ident == '@llvm.global_ctors') { @@ -699,6 +705,9 @@ function intertyper(data, parseFunctions, baseLineNum) { // external function stub substrate.addZyme('External', { processItem: function(item) { + if (item.tokens[1].text == 'noalias') { + item.tokens.splice(1, 1); + } return [{ __result__: true, intertype: 'functionStub', diff --git a/src/jsifier.js b/src/jsifier.js index fb813e30..4720798c 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -76,7 +76,12 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { return '{ ' + ret.join(', ') + ' }'; } - return makeGetSlab(ptr, type) + '[' + calcFastOffset(ptr, pos, noNeedFirst) + ']'; + var offset = calcFastOffset(ptr, pos, noNeedFirst); + if (SAFE_HEAP) { + return 'SAFE_HEAP_LOAD(' + offset + ', "' + safeQuote(type) + '")'; + } else { + return makeGetSlab(ptr, type) + '[' + offset + ']'; + } } function indexizeFunctions(value) { // TODO: Also check for other functions (externals, library, etc.) @@ -99,15 +104,13 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { value = indexizeFunctions(value); var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { - return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ')'; + return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', "' + safeQuote(type) + '")'; } else { return makeGetSlab(ptr, type) + '[' + offset + '] = ' + value; } } function makeEmptyStruct(type) { - dprint('types', '??makeemptystruct?? ' + dump(type)); - // XXX hardcoded ptr impl var ret = []; var typeData = TYPES[type]; assertTrue(typeData); @@ -218,13 +221,16 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { item.JS = '\n__globalConstructor__ = function() {\n' + item.ctors.map(function(ctor) { return ' ' + toNiceIdent(ctor) + '();' }).join('\n') + '\n}\n'; - } else if (item.type == 'external') { - item.JS = 'var ' + item.ident + ' = ' + '0; /* external value? */'; } else { item.JS = 'var ' + item.ident + ';'; return [item, { intertype: 'GlobalVariable', - JS: 'globalFuncs.push(function() { return ' + item.ident + ' = ' + parseConst(item.value, item.type) + ' });', + JS: 'globalFuncs.push(function() { return ' + item.ident + ' = ' + ( + item.external ? + makePointer(JSON.stringify(makeEmptyStruct(item.type)), null, 'ALLOC_STATIC', item.type) + ' /* external value? */' + : + parseConst(item.value, item.type) + ) + ' });', __result__: true, }]; } @@ -868,10 +874,11 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { function makeFunctionCall(ident, params, funcData) { // Special cases if (ident == '_llvm_va_start') { + // varargs var args = 'Array.prototype.slice.call(arguments, __numArgs__)'; var data = 'Pointer_make([' + args + '.length].concat(' + args + '), 0)'; if (SAFE_HEAP) { - return 'SAFE_HEAP_STORE(' + params[0].ident + ', ' + data + ', 0)'; + return 'SAFE_HEAP_STORE(' + params[0].ident + ', ' + data + ', null)'; } else { return 'IHEAP[' + params[0].ident + '] = ' + data; } @@ -927,8 +934,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { if (functionsOnly) return ret; - var params = { 'QUANTUM_SIZE': QUANTUM_SIZE }; - var body = preprocess(read('preamble.js').replace('{{RUNTIME}}', getRuntime()) + ret + read('postamble.js'), params); + var body = preprocess(read('preamble.js').replace('{{RUNTIME}}', getRuntime()) + ret + read('postamble.js'), CONSTANTS); function reverse_(x) { if (LLVM_STYLE === 'old') { return x.reverse(); diff --git a/src/library.js b/src/library.js index a052c44b..c1312e1f 100644 --- a/src/library.js +++ b/src/library.js @@ -117,7 +117,11 @@ var Library = { strcpy: function(pdest, psrc) { var i = 0; do { +#if SAFE_HEAP + SAFE_HEAP_STORE(pdest+i, IHEAP[psrc+i], null); +#else IHEAP[pdest+i] = IHEAP[psrc+i]; +#endif i ++; } while (IHEAP[psrc+i-1] != 0); }, @@ -125,7 +129,11 @@ var Library = { strncpy: function(pdest, psrc, num) { var padding = false; for (var i = 0; i < num; i++) { +#if SAFE_HEAP + SAFE_HEAP_STORE(pdest+i, padding ? 0 : IHEAP[psrc+i], null); +#else IHEAP[pdest+i] = padding ? 0 : IHEAP[psrc+i]; +#endif padding = padding || IHEAP[psrc+i] == 0; } }, diff --git a/src/parseTools.js b/src/parseTools.js index d2e3655f..37e0a881 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -387,6 +387,10 @@ function parseNumerical(value, type) { } else if (value == 'null') { // NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.) value = '0'; + } else if (value === 'true') { + return '1'; + } else if (value === 'false') { + return '0'; } if (isNumber(value)) { return eval(value).toString(); // will change e.g. 5.000000e+01 to 50 diff --git a/src/preamble.js b/src/preamble.js index 1623d387..f02ada7a 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -16,13 +16,47 @@ var __ATEXIT__ = []; #if SAFE_HEAP // Semi-manual memory corruption debugging var HEAP_WATCHED = {}; -function SAFE_HEAP_STORE(dest, value) { +var HEAP_HISTORY = {}; +function SAFE_HEAP_CLEAR(dest) { + HEAP_HISTORY[dest] = []; +} +function SAFE_HEAP_ACCESS(dest, type, store) { + if (type && type[type.length-1] == '*') type = 'i32'; // pointers are ints, for our purposes here + // Note that this will pass even with unions: You can store X, load X, then store Y and load Y. + // You cannot, however, do the nonportable act of store X and load Y! + if (store) { + HEAP_HISTORY[dest] = [{ type: type, /*stack: new Error().stack */ }]; // |stack| is useful for debugging + } else { + if (!HEAP[dest] && HEAP[dest] !== 0) { + print('Warning: Reading an invalid value at ' + dest + ' :: ' + new Error().stack + '\n'); + } + var history = HEAP_HISTORY[dest]; + assert((history && history[0]) /* || HEAP[dest] === 0 */, "Loading from where there was no store! " + dest + ',' + HEAP[dest] + ',' + type + ', \n\n' + new Error().stack + '\n'); + if (history[0].type && history[0].type !== type) { + print('Load-store consistency assumption failure! ' + dest); + print('\n'); + print(history.map(function(item) { + return item.type + ' :: ' + JSON.stringify(item.stack); + }).join('\n\n')); + print('\n'); + print('LOAD: ' + type + ', ' + new Error().stack); + print('\n'); + assert(0, 'Load-store consistency assumption failure!'); + } + } +} +function SAFE_HEAP_STORE(dest, value, type) { + SAFE_HEAP_ACCESS(dest, type, true); if (dest in HEAP_WATCHED) { print((new Error()).stack); throw "Bad store!" + dest; } HEAP[dest] = value; } +function SAFE_HEAP_LOAD(dest, type) { + SAFE_HEAP_ACCESS(dest, type); + return HEAP[dest]; +} function __Z16PROTECT_HEAPADDRPv(dest) { HEAP_WATCHED[dest] = true; } @@ -120,7 +154,7 @@ function Pointer_make(slab, pos, allocator) { curr = Runtime.getFunctionIndex(curr); } #if SAFE_HEAP - SAFE_HEAP_STORE(ret + i, curr); + SAFE_HEAP_STORE(ret + i, curr, null); #else #if USE_TYPED_ARRAYS // TODO: Check - also in non-typedarray case - for functions, and if so add |.__index__| @@ -303,7 +337,7 @@ function _atoi(s) { function _llvm_memcpy_i32(dest, src, num, idunno) { for (var i = 0; i < num; i++) { #if SAFE_HEAP - SAFE_HEAP_STORE(dest + i, HEAP[src + i]); + SAFE_HEAP_STORE(dest + i, HEAP[src + i], null); #else HEAP[dest + i] = HEAP[src + i]; #if USE_TYPED_ARRAYS diff --git a/src/runtime.js b/src/runtime.js index daa9086d..2ad54295 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -6,6 +6,9 @@ RuntimeGenerator = { alloc: function(size, type) { var ret = type + 'TOP'; // ret += '; for (var i = 0; i < ' + size + '; i++) HEAP[' + type + 'TOP+i] = 0'; // No need for typed arrays - per the spec, initialized to 0 anyhow + if (SAFE_HEAP) { + ret += '; for (var j = 0; j < ' + size + '; j++) SAFE_HEAP_CLEAR(' + type + 'TOP+j);'; + } if (GUARD_MEMORY) { ret += '; assert(' + size + ' > 0)'; } @@ -26,11 +29,14 @@ RuntimeGenerator = { }, stackEnter: function(initial) { - if (initial === 0) return ''; // XXX Note that we don't even push the stack! This is faster, but - // means that we don't clear stack allocations done in this function - // until the parent unwinds its stack. So potentially if we are in - // a loop, we can use a lot of memory. + if (!GUARD_MEMORY && initial === 0) return ''; // XXX Note that we don't even push the stack! This is faster, but + // means that we don't clear stack allocations done in this function + // until the parent unwinds its stack. So potentially if we are in + // a loop, we can use a lot of memory. var ret = 'var __stackBase__ = STACKTOP; STACKTOP += ' + initial; + if (SAFE_HEAP) { + ret += '; for (var i = __stackBase__; i < STACKTOP; i++) SAFE_HEAP_STORE(i, 0, null);'; + } if (GUARD_MEMORY) { ret += '; assert(STACKTOP < STACK_MAX)'; } @@ -39,7 +45,11 @@ RuntimeGenerator = { stackExit: function(initial) { if (initial === 0) return ''; // XXX See comment in stackEnter - return 'STACKTOP = __stackBase__'; + var ret = ''; + if (SAFE_HEAP) { + ret += 'for (var i = __stackBase__; i < STACKTOP; i++) SAFE_HEAP_CLEAR(i);'; + } + return ret += 'STACKTOP = __stackBase__'; }, // An allocation that cannot be free'd diff --git a/src/utility.js b/src/utility.js index 3085fc61..fd8a1bce 100644 --- a/src/utility.js +++ b/src/utility.js @@ -1,5 +1,10 @@ // General JS utilities +function safeQuote(x) { + return x.replace(/"/g, '\\"') + .replace(/'/g, "\\'"); +} + function dump(item) { var CHUNK = 500; function lineify(text) { |