aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jsifier.js17
-rw-r--r--src/library.js54
-rw-r--r--src/parseTools.js77
-rw-r--r--src/postamble.js6
-rw-r--r--src/preamble.js130
-rw-r--r--src/runtime.js1
-rw-r--r--src/settings.js4
-rw-r--r--src/utility.js8
-rw-r--r--tests/cases/loadbitcastgep.ll2
-rw-r--r--tests/runner.py39
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