diff options
-rw-r--r-- | src/jsifier.js | 17 | ||||
-rw-r--r-- | src/library.js | 54 | ||||
-rw-r--r-- | src/parseTools.js | 77 | ||||
-rw-r--r-- | src/postamble.js | 6 | ||||
-rw-r--r-- | src/preamble.js | 130 | ||||
-rw-r--r-- | src/runtime.js | 1 | ||||
-rw-r--r-- | src/settings.js | 4 | ||||
-rw-r--r-- | src/utility.js | 8 | ||||
-rw-r--r-- | tests/cases/loadbitcastgep.ll | 2 | ||||
-rw-r--r-- | tests/runner.py | 39 |
10 files changed, 229 insertions, 109 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index d1e608a1..13b8377f 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -169,7 +169,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { if (needsPostSet(value)) { // ident, or expression containing an ident ret.push({ intertype: 'GlobalVariablePostSet', - JS: 'IHEAP[' + getFastValue(item.ident, '+', i) + '] = ' + value + ';' + JS: makeSetValue(item.ident, i, value, 'i32', false, true) // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors }); constant[i] = '0'; } @@ -682,11 +682,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { if (ident == '_llvm_va_start') { // varargs - we received a pointer to the varargs as a final 'extra' parameter var data = 'arguments[' + Framework.currItem.funcData.ident + '.length]'; - if (SAFE_HEAP) { - return 'SAFE_HEAP_STORE(' + params[0].ident + ', ' + data + ', null, ' + !checkSafeHeap() + ')'; - } else { - return 'IHEAP[' + params[0].ident + '] = ' + data; - } + return makeSetValue(params[0].ident, 0, data, 'void*'); } else if (ident == '_llvm_va_end') { return ';'; } @@ -694,6 +690,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { var func = Functions.currFunctions[ident]; var args = []; var varargs = []; + var varargsTypes = []; params.forEach(function(param, i) { var val = finalizeParam(param); @@ -702,13 +699,19 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { } else { varargs.push(val); varargs = varargs.concat(zeros(getNativeFieldSize(param.type)-1)); + varargsTypes.push(param.type); + varargsTypes = varargsTypes.concat(zeros(getNativeFieldSize(param.type)-1)); } }); args = args.map(indexizeFunctions); varargs = varargs.map(indexizeFunctions); if (func && func.hasVarArgs) { - varargs = makePointer('[' + varargs + ']', 0, 'ALLOC_STACK'); + if (varargs.length === 0) { + varargs = [0]; + varargsTypes = ['i32']; + } + varargs = makePointer('[' + varargs + ']', 0, 'ALLOC_STACK', varargsTypes); } if (getVarData(funcData, ident)) { diff --git a/src/library.js b/src/library.js index aedd04c9..794b270c 100644 --- a/src/library.js +++ b/src/library.js @@ -167,7 +167,7 @@ var Library = { textIndex += 1; } } - return Pointer_make(ret.concat(0), 0, ALLOC_STACK); // NB: Stored on the stack + return Pointer_make(ret.concat(0), 0, ALLOC_STACK, 'i8'); // NB: Stored on the stack //var len = ret.length+1; //var ret = Pointer_make(ret.concat(0), 0, ALLOC_STACK); // NB: Stored on the stack //STACKTOP -= len; // XXX horrible hack. we rewind the stack, to 'undo' the alloc we just did. @@ -263,16 +263,16 @@ var Library = { SEEK_END: 2, /* End of file. */ init: function() { try { - _stdin = Pointer_make([0], null, ALLOC_STATIC); - IHEAP[_stdin] = STDIO.prepare('<<stdin>>'); + _stdin = Pointer_make([0], null, ALLOC_STATIC, 'void*'); + {{{ makeSetValue('_stdin', '0', "STDIO.prepare('<<stdin>>')", 'i32') }}}; } catch(e){} // stdin/out/err may not exist if not needed try { - _stdout = Pointer_make([0], null, ALLOC_STATIC); - IHEAP[_stdout] = STDIO.prepare('<<stdout>>', null, true); + _stdout = Pointer_make([0], null, ALLOC_STATIC, 'void*'); + {{{ makeSetValue('_stdout', '0', "STDIO.prepare('<<stdin>>', null, true)", 'i32') }}}; } catch(e){} try { - _stderr = Pointer_make([0], null, ALLOC_STATIC); - IHEAP[_stderr] = STDIO.prepare('<<stderr>>', null, true); + _stderr = Pointer_make([0], null, ALLOC_STATIC, 'void*'); + {{{ makeSetValue('_stderr', '0', "STDIO.prepare('<<stdin>>', null, true)", 'i32') }}}; } catch(e){} }, cleanFilename: function(filename) { @@ -487,7 +487,7 @@ var Library = { // Leaky and non-shared... FIXME var info = STDIO.streams[stream]; if (!info) return -1; - return Pointer_make(info.data.slice(offset, offset+num), null, ALLOC_NORMAL); + return Pointer_make(info.data.slice(offset, offset+num), null, ALLOC_NORMAL, 'i8'); }, munmap: function(start, num) { @@ -623,11 +623,27 @@ var Library = { assert(num % 1 === 0, 'memcpy given ' + num + ' bytes to copy. Problem with QUANTUM_SIZE=1 corrections perhaps?'); #endif var curr; +#if USE_TYPED_ARRAYS == 2 + var stop = src + num; + var fast = dest%4 === src%4; + while (src%4 !== 0 && src < stop) { + HEAP8[dest++] = HEAP8[src++]; + } + while (src+4 <= stop && fast) { + HEAP32[dest] = HEAP32[src]; + src += 4; + dest += 4; + } + while (src < stop) { + HEAP8[dest++] = HEAP8[src++]; + } +#else for (var i = 0; i < num; i++) { // TODO: optimize for the typed arrays case // || 0, since memcpy sometimes copies uninitialized areas XXX: Investigate why initializing alloc'ed memory does not fix that too {{{ makeCopyValue('dest', 'i', 'src', 'i', 'null', ' || 0') }}}; } +#endif }, llvm_memcpy_i32: 'memcpy', llvm_memcpy_i64: 'memcpy', @@ -816,7 +832,7 @@ var Library = { }, strdup: function(ptr) { - return Pointer_make(String_copy(ptr, true), 0, ALLOC_NORMAL); + return Pointer_make(String_copy(ptr, true), 0, ALLOC_NORMAL, 'i8'); }, strpbrk: function(ptr1, ptr2) { @@ -828,8 +844,8 @@ var Library = { return 0; }, - // Compiled from newlib; for the original source and licensing, see library_strtok_r.c - strtok_r: function(b,j,f){var a;a=null;var c,e;b=b;var i=b!=0;a:do if(i)a=0;else{b=IHEAP[f];if(b!=0){a=0;break a}c=0;a=3;break a}while(0);if(a==0){a:for(;;){e=IHEAP[b];b+=1;a=j;var g=e;i=a;a=2;b:for(;;){d=a==5?d:0;a=IHEAP[i+d];if(a!=0==0){a=9;break a}var d=d+1;if(g==a)break b;else a=5}a=2}if(a==9)if(g==0)c=IHEAP[f]=0;else{c=b+-1;a:for(;;){e=IHEAP[b];b+=1;a=j;g=e;d=a;a=10;b:for(;;){h=a==13?h:0;a=IHEAP[d+h];if(a==g!=0)break a;var h=h+1;if(a!=0)a=13;else break b}}if(e==0)b=0;else IHEAP[b+-1]=0; IHEAP[f]=b;c=c}else if(a==7){IHEAP[f]=b;IHEAP[b+-1]=0;c=b+-1}}return c}, + // Compiled from newlib; for the original source and licensing, see library_strtok_r.c XXX will not work with typed arrays + strtok_r: function(b,j,f){var a;a=null;var c,e;b=b;var i=b!=0;a:do if(i)a=0;else{b=HEAP[f];if(b!=0){a=0;break a}c=0;a=3;break a}while(0);if(a==0){a:for(;;){e=HEAP[b];b+=1;a=j;var g=e;i=a;a=2;b:for(;;){d=a==5?d:0;a=HEAP[i+d];if(a!=0==0){a=9;break a}var d=d+1;if(g==a)break b;else a=5}a=2}if(a==9)if(g==0)c=HEAP[f]=0;else{c=b+-1;a:for(;;){e=HEAP[b];b+=1;a=j;g=e;d=a;a=10;b:for(;;){h=a==13?h:0;a=HEAP[d+h];if(a==g!=0)break a;var h=h+1;if(a!=0)a=13;else break b}}if(e==0)b=0;else HEAP[b+-1]=0; HEAP[f]=b;c=c}else if(a==7){HEAP[f]=b;HEAP[b+-1]=0;c=b+-1}}return c}, // ctype.h @@ -905,10 +921,12 @@ var Library = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0 ]; - me.ret = Pointer_make([Pointer_make(values, 0, ALLOC_STATIC)+256], 0, ALLOC_STATIC); - assert(IHEAP[IHEAP[me.ret]] == 2); - assert(IHEAP[IHEAP[me.ret]-2] == 0); - assert(IHEAP[IHEAP[me.ret]+18] == 8195); + me.ret = Pointer_make([Pointer_make(values, 0, ALLOC_STATIC, 'void*')+256], 0, ALLOC_STATIC, 'i16'); +#if USE_TYPED_ARRAYS == 0 + assert(HEAP[HEAP[me.ret]] == 2); + assert(HEAP[HEAP[me.ret]-2] == 0); + assert(HEAP[HEAP[me.ret]+18] == 8195); +#endif } return me.ret; }, @@ -1220,7 +1238,7 @@ var Library = { // var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] }); var me = _localeconv; if (!me.ret) { - me.ret = Pointer_make([Pointer_make(intArrayFromString('.'), null)], null); // just decimal point, for now + me.ret = Pointer_make([Pointer_make(intArrayFromString('.'), null, ALLOC_NORMAL, 'i8')], null, ALLOC_NORMAL, 'i8'); // just decimal point, for now } return me.ret; }, @@ -1230,7 +1248,7 @@ var Library = { nl_langinfo: function(item) { var me = _nl_langinfo; if (!me.ret) { - me.ret = Pointer_make(intArrayFromString("eh?"), null); + me.ret = Pointer_make(intArrayFromString("eh?"), null, ALLOC_NORMAL, 'i8'); } return me.ret; }, @@ -1240,7 +1258,7 @@ var Library = { __errno_location: function() { var me = ___errno_location; if (!me.ret) { - me.ret = Pointer_make([0], 0, ALLOC_STATIC); + me.ret = Pointer_make([0], 0, ALLOC_STATIC, 'i32'); } return me.ret; }, diff --git a/src/parseTools.js b/src/parseTools.js index 2d94f73b..aa18a010 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -27,8 +27,16 @@ function preprocess(text, constants) { } } else { if (line[1] && line[1] == 'i') { // if - var ident = line.substr(4); - showStack.push(!!this[ident] && this[ident] > 0); + var parts = line.split(' '); + var ident = parts[1]; + var op = parts[2]; + var value = parts[3]; + if (op) { + assert(op === '==') + showStack.push(ident in this && this[ident] == value); + } else { + showStack.push(ident in this && this[ident] > 0); + } } else if (line[2] && line[2] == 'l') { // else showStack.push(!showStack.pop()); } else if (line[2] && line[2] == 'n') { // endif @@ -560,6 +568,26 @@ function calcAllocatedSize(type) { } } +// Generates the type signature for a structure, for each byte, the type that is there. +// i32, 0, 0, 0 - for example, an int32 is here, then nothing to do for the 3 next bytes, naturally +function generateStructTypes(type) { + if (isArray(type)) return type; // already in the form of [type, type,...] + if (Runtime.isNumberType(type) || isPointerType(type)) { + return [type];//.concat(zeros(getNativeFieldSize(type))); + } + var typeData = Types.types[type]; + assert(typeData, 'invalid type in generateStructTypes: ' + type); + var fields = typeData.fields; + var ret = []; + for (var i = 0; i < fields.length; i++) { + ret = ret.concat(generateStructTypes(fields[i])); + if (i < fields.length-1) { + ret = ret.concat(zeros(typeData.flatIndexes[i+1] - ret.length)); + } + } + return ret; +} + // Flow blocks function recurseBlock(block, func) { @@ -645,7 +673,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst) { var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { - if (type !== 'null') type = '"' + safeQuote(type) + '"'; + if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; + if (type[0] === '#') type = type.substr(1); return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + !checkSafeHeap() + ')'; } else { return makeGetSlabs(ptr, type)[0] + '[' + offset + ']'; @@ -675,7 +704,7 @@ function indexizeFunctions(value) { // TODO: Also check for externals //! 'null' means, in the context of SAFE_HEAP, that we should accept all types; //! which means we should write to all slabs, ignore type differences if any on reads, etc. //! @param noNeedFirst Whether to ignore the offset in the pointer itself. -function makeSetValue(ptr, pos, value, type, noNeedFirst) { +function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore) { if (isStructType(type)) { var typeData = Types.types[type]; var ret = []; @@ -688,8 +717,9 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst) { value = indexizeFunctions(value); var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { - if (type !== 'null') type = '"' + safeQuote(type) + '"'; - return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + type + ', ' + !checkSafeHeap() + ');'; + if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; + if (type[0] === '#') type = type.substr(1); + return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + type + ', ' + ((!checkSafeHeap() || ignore)|0) + ');'; } else { return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + offset + ']=' + value }).join('; ') + ';'; } @@ -700,9 +730,9 @@ function makeCopyValue(dest, destPos, src, srcPos, type, modifier) { return makeSetValue(dest, destPos, makeGetValue(src, srcPos, type) + (modifier || ''), type); } // Null is special-cased: We copy over all heaps - return 'IHEAP[' + dest + '+' + destPos + '] = IHEAP[' + src + '+' + srcPos + ']; ' + - (USE_TYPED_ARRAY_FHEAP ? 'FHEAP[' + dest + '+' + destPos + '] = FHEAP[' + src + '+' + srcPos + ']; ' : '') + - (SAFE_HEAP ? 'SAFE_HEAP_COPY_HISTORY(' + dest + ' + ' + destPos + ', ' + src + ' + ' + srcPos + ')' : ''); + return makeGetSlabs(dest, 'null', true).map(function(slab) { + return slab + '[' + dest + ' + ' + destPos + ']=' + slab + '[' + src + ' + ' + srcPos + ']' + }).join('; ') + ';' + (SAFE_HEAP ? 'SAFE_HEAP_COPY_HISTORY(' + dest + ' + ' + destPos + ', ' + src + ' + ' + srcPos + ')' : ''); } // Given two values and an operation, returns the result of that operation. @@ -742,26 +772,45 @@ function makeGetPos(ptr) { return ptr; } -function makePointer(slab, pos, allocator, type) { // type is FFU +function makePointer(slab, pos, allocator, type) { + assert(type, 'makePointer requires type info'); if (slab in set('HEAP', 'IHEAP', 'FHEAP')) return pos; - return 'Pointer_make(' + slab + ', ' + (pos ? pos : 0) + (allocator ? ', ' + allocator : '') + ')'; + var types = generateStructTypes(type); + if (dedup(types).length === 1) types = types[0]; + return 'Pointer_make(' + slab + ', ' + (pos ? pos : 0) + (allocator ? ', ' + allocator : '') + ', ' + + JSON.stringify(types) + + ')'; } function makeGetSlabs(ptr, type, allowMultiple) { assert(type); if (!USE_TYPED_ARRAYS) { return ['HEAP']; - } else { + } else if (USE_TYPED_ARRAYS == 1) { if (type in Runtime.FLOAT_TYPES || type === 'int64') { - assert(USE_TYPED_ARRAY_FHEAP, 'Attempt to use FHEAP without USE_TYPED_ARRAY_FHEAP'); return ['FHEAP']; - } else if (type in Runtime.INT_TYPES || isPointerType(type) || !USE_TYPED_ARRAY_FHEAP) { + } else if (type in Runtime.INT_TYPES || isPointerType(type)) { return ['IHEAP']; } else { assert(allowMultiple, 'Unknown slab type and !allowMultiple: ' + type); return ['IHEAP', 'FHEAP']; // unknown, so assign to both typed arrays } + } else { // USE_TYPED_ARRAYS == 2) + switch(type) { + case 'i8': return ['HEAP8']; break; + case 'i16': return ['HEAP16']; break; + case 'i32': return ['HEAP32']; break; + case 'i64': return ['HEAP64']; break; + case 'float': return ['HEAPF32']; break; + case 'double': return ['HEAPF64']; break; + default: { + assert(allowMultiple, 'Unknown slab type and !allowMultiple: ' + type); + throw 'what, exactly, can we do for unknown types in TA2?! ' + new Error().stack; + return ['IHEAP', 'FHEAP']; + } + } } + return []; } function finalizeLLVMFunctionCall(item) { diff --git a/src/postamble.js b/src/postamble.js index 12d4ebca..eb8437e6 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -8,14 +8,14 @@ Module.callMain = function callMain(args) { argv.push(0); } } - var argv = [Pointer_make(intArrayFromString("/bin/this.program"), null) ]; + var argv = [Pointer_make(intArrayFromString("/bin/this.program"), null, ALLOC_STATIC, 'i8') ]; pad(); for (var i = 0; i < argc-1; i = i + 1) { - argv.push(Pointer_make(intArrayFromString(args[i]), null)); + argv.push(Pointer_make(intArrayFromString(args[i]), null, ALLOC_STATIC, 'i8')); pad(); } argv.push(0); - argv = Pointer_make(argv, null); + argv = Pointer_make(argv, null, ALLOC_STATIC, 'i32'); _main(argc, argv, 0); } diff --git a/src/preamble.js b/src/preamble.js index f6b0b633..20a645e3 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -19,18 +19,18 @@ var SAFE_HEAP_ERRORS = 0; var ACCEPTABLE_SAFE_HEAP_ERRORS = 0; function SAFE_HEAP_ACCESS(dest, type, store, ignore) { -#if SAFE_HEAP_LOG //if (dest === A_NUMBER) print ([dest, type, store] + ' ' + new Error().stack); // Something like this may be useful, in debugging -#endif 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: type, stack: new Error().stack }]; // |stack| is useful for debugging. Also uncomment the lines later down + HEAP_HISTORY[dest] = ignore ? null : type; } else { +#if USE_TYPED_ARRAYS == 0 if (!HEAP[dest] && HEAP[dest] !== 0 && HEAP[dest] !== false) { // false can be the result of a mathop comparator throw('Warning: Reading an invalid value at ' + dest + ' :: ' + new Error().stack + '\n'); } +#endif if (type === null) return; var history = HEAP_HISTORY[dest]; if (history === null) return; @@ -52,10 +52,7 @@ function SAFE_HEAP_ACCESS(dest, type, store, ignore) { } } function SAFE_HEAP_STORE(dest, value, type, ignore) { -#if SAFE_HEAP_LOG - print('store: ' + dest + ' [' + type + '] |' + value + '|'); -#endif - if (!value && value !== 0 && value !== false) { // false can be the result of a mathop comparator + if (!ignore && !value && value !== 0 && value !== false) { // false can be the result of a mathop comparator throw('Warning: Writing an invalid value of ' + JSON.stringify(value) + ' at ' + dest + ' :: ' + new Error().stack + '\n'); } SAFE_HEAP_ACCESS(dest, type, true, ignore); @@ -63,41 +60,61 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) { print((new Error()).stack); throw "Bad store!" + dest; } -#if USE_TYPED_ARRAY_FHEAP +#if USE_TYPED_ARRAYS == 1 if (type === null) { IHEAP[dest] = value; FHEAP[dest] = value; } else if (type in Runtime.FLOAT_TYPES) { FHEAP[dest] = value; - } else -#endif - { + } else { IHEAP[dest] = value; } +#else +#if USE_TYPED_ARRAYS == 2 + assert(type != 'null', 'typed arrays 2 with null type!'); + switch(type) { + case 'i8': HEAP8[dest] = value; break; + case 'i16': HEAP16[dest] = value; break; + case 'i32': HEAP32[dest] = value; break; + case 'i64': HEAP64[dest] = value; break; + case 'float': HEAPF32[dest] = value; break; + case 'double': HEAPF64[dest] = value; break; + default: throw 'weird type for typed array II: ' + type + new Error().stack; + } +#else + HEAP[dest] = value; +#endif +#endif } function SAFE_HEAP_LOAD(dest, type, ignore) { SAFE_HEAP_ACCESS(dest, type, ignore); -#if USE_TYPED_ARRAY_FHEAP + +#if USE_TYPED_ARRAYS == 1 if (type in Runtime.FLOAT_TYPES) { -#if SAFE_HEAP_LOG - print('load : ' + dest + ' [' + type + '] |' + FHEAP[dest] + '|'); -#endif return FHEAP[dest]; - } else -#endif - { -#if SAFE_HEAP_LOG - print('load : ' + dest + ' [' + type + '] |' + IHEAP[dest] + '|'); -#endif + } else { return IHEAP[dest]; } +#else +#if USE_TYPED_ARRAYS == 2 + switch(type) { + case 'i8': return HEAP8[dest]; break; + case 'i16': return HEAP16[dest]; break; + case 'i32': return HEAP32[dest]; break; + case 'i64': return HEAP64[dest]; break; + case 'float': return HEAPF32[dest]; break; + case 'double': return HEAPF64[dest]; break; + default: throw 'weird type for typed array II: ' + type; + } + return null; +#else + return HEAP[dest]; +#endif +#endif } function SAFE_HEAP_COPY_HISTORY(dest, src) { HEAP_HISTORY[dest] = HEAP_HISTORY[src]; SAFE_HEAP_ACCESS(dest, HEAP_HISTORY[dest] || null, true, false); -#if SAFE_HEAP_LOG - print('copy history: ' + dest + ' [' + HEAP_HISTORY[dest] + '] from ' + src); -#endif } function __Z16PROTECT_HEAPADDRPv(dest) { HEAP_WATCHED[dest] = true; @@ -241,7 +258,7 @@ var ALLOC_NORMAL = 0; // Tries to use _malloc() var ALLOC_STACK = 1; // Lives for the duration of the current function call var ALLOC_STATIC = 2; // Cannot be freed -function Pointer_make(slab, pos, allocator) { +function Pointer_make(slab, pos, allocator, types) { pos = pos ? pos : 0; assert(pos === 0); // TODO: remove 'pos' if (slab === HEAP) return pos; @@ -259,6 +276,8 @@ function Pointer_make(slab, pos, allocator) { // Finalize var ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator ? allocator : ALLOC_STATIC](Math.max(size, 1)); + var type = typeof types === 'string' ? types : null; + for (i = 0; i < size; i++) { var curr = slab[i]; @@ -266,7 +285,9 @@ function Pointer_make(slab, pos, allocator) { curr = Runtime.getFunctionIndex(curr); } - {{{ makeSetValue(0, 'ret+i', 'curr', 'null') }}} + if (type || types[i]) { + {{{ makeSetValue(0, 'ret+i', 'curr', '#type || types[i]') }}} + } } return ret; @@ -293,7 +314,14 @@ function alignMemoryPage(x) { return Math.ceil(x/PAGE_SIZE)*PAGE_SIZE; } -var HEAP, IHEAP, FHEAP; +var HEAP; +#if USE_TYPED_ARRAYS == 1 +var IHEAP, FHEAP; +#endif +#if USE_TYPED_ARRAYS == 2 +var HEAP8, HEAP16, HEAP32, HEAPF32, HEAPF64; +#endif + var STACK_ROOT, STACKTOP, STACK_MAX; var STATICTOP; @@ -302,30 +330,39 @@ var TOTAL_MEMORY = 50*1024*1024; function __initializeRuntime__() { #if USE_TYPED_ARRAYS - // TODO: Remove one of the 3 heaps! HAS_TYPED_ARRAYS = false; try { -#if USE_TYPED_ARRAY_FHEAP HAS_TYPED_ARRAYS = !!Int32Array && !!Float64Array && !!(new Int32Array()['subarray']); // check for full engine support (use string 'subarray' to avoid closure compiler confusion) -#else - HAS_TYPED_ARRAYS = !!Int32Array && !!(new Int32Array()['subarray']); // check for full engine support (use string #endif -#endif } catch(e) {} if (HAS_TYPED_ARRAYS) { +#if USE_TYPED_ARRAYS == 1 HEAP = IHEAP = new Int32Array(TOTAL_MEMORY); -#if USE_TYPED_ARRAY_FHEAP FHEAP = new Float64Array(TOTAL_MEMORY); #endif +#if USE_TYPED_ARRAYS == 2 + var buffer = new ArrayBuffer(TOTAL_MEMORY); + HEAP8 = new Int8Array(buffer); + HEAP16 = new Int16Array(buffer); + HEAP32 = new Int32Array(buffer); + HEAPF32 = new Float32Array(buffer); + HEAPF64 = new Float64Array(buffer); +#endif } else #endif { // Without this optimization, Chrome is slow. Sadly, the constant here needs to be tweaked depending on the code being run... var FAST_MEMORY = TOTAL_MEMORY/32; - IHEAP = FHEAP = HEAP = new Array(FAST_MEMORY); + HEAP = new Array(FAST_MEMORY); for (var i = 0; i < FAST_MEMORY; i++) { - IHEAP[i] = 0; // We do *not* use {{{ makeSetValue(0, 'i', 0, 'null') }}} here, since this is done just to optimize runtime speed + HEAP[i] = 0; // XXX We do *not* use {{{ makeSetValue(0, 'i', 0, 'null') }}} here, since this is done just to optimize runtime speed } +#if USE_TYPED_ARRAYS == 1 + IHEAP = FHEAP = HEAP; +#endif +#if USE_TYPED_ARRAYS == 2 + HEAP8 = HEAP16 = HEAP32 = HEAPF32 = HEAPF64 = HEAP; +#endif } var base = intArrayFromString('(null)'); // So printing %s of NULL gives '(null)' @@ -335,10 +372,6 @@ function __initializeRuntime__() { } Module['HEAP'] = HEAP; - Module['IHEAP'] = IHEAP; -#if USE_TYPED_ARRAY_FHEAP - Module['FHEAP'] = FHEAP; -#endif STACK_ROOT = STACKTOP = alignMemoryPage(10); var TOTAL_STACK = 1024*1024; // XXX: Changing this value can lead to bad perf on v8! @@ -356,7 +389,8 @@ function __shutdownRuntime__() { } func(atexit.arg); } - //HEAP = IHEAP = FHEAP = null; // allow browser to GC? + + // allow browser to GC, set heaps to null? // Print summary of correction activity CorrectionsMonitor.print(); @@ -367,15 +401,23 @@ function __shutdownRuntime__() { // a normal JavaScript array of numbers function Array_copy(ptr, num) { // TODO: In the SAFE_HEAP case, do some reading here, for debugging purposes - currently this is an 'unnoticed read'. -#if USE_TYPED_ARRAYS +#if USE_TYPED_ARRAYS == 1 if (HAS_TYPED_ARRAYS) { return Array.prototype.slice.call(IHEAP.subarray(ptr, ptr+num)); // Make a normal array out of the typed 'view' // Consider making a typed array here, for speed? - } else -#endif - { + } else { return IHEAP.slice(ptr, ptr+num); } +#endif +#if USE_TYPED_ARRAYS == 2 + if (HAS_TYPED_ARRAYS) { + return Array.prototype.slice.call(HEAP8.subarray(ptr, ptr+num)); // Make a normal array out of the typed 'view' + // Consider making a typed array here, for speed? + } else { + return HEAP8.slice(ptr, ptr+num); + } +#endif + return HEAP.slice(ptr, ptr+num); } function String_len(ptr) { diff --git a/src/runtime.js b/src/runtime.js index 1aefc135..adf62521 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -74,7 +74,6 @@ Runtime = { staticAlloc: unInline('staticAlloc', ['size']), alignMemory: unInline('alignMemory', ['size', 'quantum']), - // TODO: cleanup isNumberType: function(type) { return type in Runtime.INT_TYPES || type in Runtime.FLOAT_TYPES; }, diff --git a/src/settings.js b/src/settings.js index d03d3aa9..cbdb6ac1 100644 --- a/src/settings.js +++ b/src/settings.js @@ -39,9 +39,6 @@ INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to OPTIMIZE = 0; // Optimize llvm operations into js commands RELOOP = 0; // Recreate js native loops from llvm data USE_TYPED_ARRAYS = 0; // Try to use typed arrays for the heap -USE_TYPED_ARRAY_FHEAP = 1; // When USE_TYPED_ARRAYS is enabled, enables a separate FHEAP of Float64. - // When disabled, assumes FHEAP is not needed, i.e., no float/int64/etc. operations - // are stored or loaded SKIP_STACK_IN_SMALL = 1; // When enabled, does not push/pop the stack at all in // functions that have no basic stack usage. But, they // may allocate stack later, and in a loop, this can be @@ -54,7 +51,6 @@ SAFE_HEAP = 0; // Check each write to the heap against a list of blocked address // SAFE_HEAP_LINES, checking only the specified lines. // If equal to 3, checking all *but* the specified lines. Note // that 3 is the option you usually want here. -SAFE_HEAP_LOG = 0; // Print out every single heap read and write (LOTS of output) LABEL_DEBUG = 0; // Print out labels and functions as we enter them EXCEPTION_DEBUG = 1; // Print out exceptions in emscriptened code EXECUTION_TIMEOUT = -1; // Throw an exception after X seconds - useful to debug infinite loops diff --git a/src/utility.js b/src/utility.js index 2fb18e0d..7ab9e1ed 100644 --- a/src/utility.js +++ b/src/utility.js @@ -188,6 +188,14 @@ function isNumber(x) { return x == parseFloat(x); } +function isArray(x) { + try { + return typeof x === 'object' && 'length' in x && 'slice' in x; + } catch(e) { + return false; + } +} + function flatten(x) { if (typeof x !== 'object') return x; var ret = []; diff --git a/tests/cases/loadbitcastgep.ll b/tests/cases/loadbitcastgep.ll index a402f647..2a90dbb7 100644 --- a/tests/cases/loadbitcastgep.ll +++ b/tests/cases/loadbitcastgep.ll @@ -14,7 +14,7 @@ entry: %retval = alloca i32 ; [#uses=2] %0 = alloca i32 ; [#uses=2] %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] - %1 = load i16* bitcast (i32* getelementptr inbounds (%struct.CPU_Regs* @cpu_regs, i32 0, i32 0, i32 1, i32 0, i32 0) to i16*), align 2 ; [#uses=1] + %1 = load i32* bitcast (i32* getelementptr inbounds (%struct.CPU_Regs* @cpu_regs, i32 0, i32 0, i32 1, i32 0, i32 0) to i32*), align 2 ; [#uses=1] store i16 %1, i16* bitcast (%struct.CPU_Regs* @cpu_regs to i16*), align 2 %2 = call i32 @puts(i8* getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0)) ; [#uses=0] store i32 0, i32* %0, align 4 diff --git a/tests/runner.py b/tests/runner.py index 42b300f1..65a5ecfa 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -1522,6 +1522,13 @@ if 'benchmark' not in sys.argv: self.do_test(src, '*1,2,3,5,5,6*\n*stdin==0:0*\n*%*\n*5*\n*66.0*\n*cleaned*') def test_statics(self): + # static initializers save i16 but load i8 for some reason + global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g'] + global SAFE_HEAP, SAFE_HEAP_LINES + if SAFE_HEAP: + SAFE_HEAP = 3 + SAFE_HEAP_LINES = ['src.cpp:19', 'src.cpp:26'] + src = ''' #include <stdio.h> #include <string.h> @@ -2061,7 +2068,7 @@ if 'benchmark' not in sys.argv: self.do_test(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(), 'Successfully generated', # The real test for valid output is in image_compare - ['-i', 'image.j2k', '-o', 'image.raw'], + '-i image.j2k -o image.raw'.split(' '), libraries=[lib], includes=[path_from_root('tests', 'openjpeg', 'libopenjpeg'), path_from_root('tests', 'openjpeg', 'codec'), @@ -2243,14 +2250,6 @@ if 'benchmark' not in sys.argv: self.do_test(src, '*ok*') - SAFE_HEAP_LINES = ["src.cpp:7"] - - try: - self.do_test(src, '*nothingatall*') - except Exception, e: - # This test *should* fail, by throwing this exception - assert 'Assertion failed: Load-store consistency assumption failure!' in str(e), str(e) - def test_check_overflow(self): global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 1 global CORRECT_OVERFLOWS; CORRECT_OVERFLOWS = 0 @@ -2478,7 +2477,7 @@ if 'benchmark' not in sys.argv: # Generate tests for all our compilers - def make_test(name, compiler, llvm_opts, embetter, quantum_size): + def make_test(name, compiler, llvm_opts, embetter, quantum_size, typed_arrays): exec(''' class %s(T): def setUp(self): @@ -2488,8 +2487,9 @@ class %s(T): llvm_opts = %d embetter = %d quantum_size = %d + USE_TYPED_ARRAYS = %d INVOKE_RUN = 1 - RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = embetter + RELOOP = OPTIMIZE = embetter QUANTUM_SIZE = quantum_size ASSERTIONS = 1-embetter SAFE_HEAP = 1-(embetter and llvm_opts) @@ -2508,14 +2508,19 @@ class %s(T): shutil.rmtree(self.get_dir()) # Useful in debugging sometimes to comment this out self.get_dir() # make sure it exists TT = %s -''' % (fullname, compiler, llvm_opts, embetter, quantum_size, fullname)) +''' % (fullname, compiler, llvm_opts, embetter, quantum_size, typed_arrays, fullname)) return TT - for embetter in [0,1]: - for llvm_opts in [0,1]: - for name, compiler, quantum in [('clang', CLANG, 1), ('clang', CLANG, 4), ('llvm_gcc', LLVM_GCC, 4)]: - fullname = '%s_%d_%d%s' % (name, llvm_opts, embetter, '' if quantum == 4 else '_q' + str(quantum)) - exec('%s = make_test("%s","%s",%d,%d,%d)' % (fullname, fullname, compiler, llvm_opts, embetter, quantum)) + for llvm_opts in [0,1]: + for name, compiler, quantum, embetter, typed_arrays in [ + ('clang', CLANG, 1, 0, 0), ('clang', CLANG, 4, 0, 0), ('llvm_gcc', LLVM_GCC, 4, 0, 0), + ('clang', CLANG, 1, 1, 1), ('clang', CLANG, 4, 1, 1), ('llvm_gcc', LLVM_GCC, 4, 1, 1)#, +# ('clang', CLANG, 4, 1, 2), ('llvm_gcc', LLVM_GCC, 4, 1, 2) + ]: + fullname = '%s_%d_%d%s%s' % ( + name, llvm_opts, embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays) + ) + exec('%s = make_test("%s","%s",%d,%d,%d,%d)' % (fullname, fullname, compiler, llvm_opts, embetter, quantum, typed_arrays)) del T # T is just a shape for the specific subclasses, we don't test it itself |