diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/library.js | 4 | ||||
-rw-r--r-- | src/parseTools.js | 70 | ||||
-rw-r--r-- | src/preamble.js | 217 | ||||
-rw-r--r-- | src/runtime.js | 8 | ||||
-rw-r--r-- | src/settings.js | 23 |
5 files changed, 194 insertions, 128 deletions
diff --git a/src/library.js b/src/library.js index 1d296981..a4278b9f 100644 --- a/src/library.js +++ b/src/library.js @@ -5493,8 +5493,8 @@ LibraryManager.library = { eval(Pointer_stringify(ptr)); }, - _Z21emscripten_run_scriptPKc: function(ptr) { - eval(Pointer_stringify(ptr)); + emscripten_run_script_int: function(ptr) { + return eval(Pointer_stringify(ptr)); }, $Profiling: { diff --git a/src/parseTools.js b/src/parseTools.js index 3eaf3577..9a599db8 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -559,17 +559,23 @@ function makeInlineCalculation(expression, value, tempVar) { return '(' + expression.replace(/VALUE/g, value) + ')'; } -// Makes a proper runtime value for a 64-bit value from low and high i32s. +// Given two 32-bit unsigned parts of an emulated 64-bit number, combine them into a JS number (double). +// Rounding is inevitable if the number is large. This is a particular problem for small negative numbers +// (-1 will be rounded!), so handle negatives separately and carefully +function makeBigInt(low, high) { + // here VALUE will be the big part + return '(' + high + ' <= 2147483648 ? (' + makeSignOp(low, 'i32', 'un', 1) + '+(' + makeSignOp(high, 'i32', 'un', 1) + '*4294967296))' + + ' : (' + makeSignOp(low, 'i32', 're', 1) + '+(1+' + makeSignOp(high, 'i32', 're', 1) + ')*4294967296))'; +} + +// Makes a proper runtime value for a 64-bit value from low and high i32s. low and high are assumed to be unsigned. function makeI64(low, high) { + high = high || '0'; if (I64_MODE == 1) { - return '[' + low + ',' + (high || '0') + ']'; - // FIXME with this? return '[unSign(' + low + ',32),' + (high ? ('unSign(' + high + ',32)') : '0') + ']'; + return '[' + makeSignOp(low, 'i32', 'un', 1) + ',' + makeSignOp(high, 'i32', 'un', 1) + ']'; } else { - var ret = low; - if (high) { - ret = '(' + low + '+(4294967296*' + high + '))'; - } - return ret; + if (high) return makeBigInt(low, high); + return low; } } @@ -577,24 +583,25 @@ function makeI64(low, high) { // Will suffer from rounding. margeI64 does the opposite. // TODO: optimize I64 calcs. For example, saving their parts as signed 32 as opposed to unsigned would help function splitI64(value) { - assert(I64_MODE == 1); - return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.floor(VALUE/4294967296)'), value, 'tempBigInt'); + // We need to min here, since our input might be a double, and large values are rounded, so they can + // be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a + // HEAP32 or |0'd, etc. + return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP'); } function mergeI64(value) { assert(I64_MODE == 1); - return '(tempI64=' + value + ',tempI64[0]+tempI64[1]*4294967296)'; + return makeInlineCalculation(makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64'); } // Takes an i64 value and changes it into the [low, high] form used in i64 mode 1. In that // mode, this is a no-op function ensureI64_1(value) { if (I64_MODE == 1) return value; - return makeInlineCalculation('[VALUE>>>0, Math.floor(VALUE/4294967296)]', value, 'tempBigInt'); + return splitI64(value, 1); } function makeCopyI64(value) { assert(I64_MODE == 1); - return value + '.slice(0)'; } @@ -889,7 +896,7 @@ function getHeapOffset(offset, type) { } // See makeSetValue -function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { +function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) { if (isStructType(type)) { var typeData = Types.types[type]; var ret = []; @@ -899,6 +906,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { return '{ ' + ret.join(', ') + ' }'; } + if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { + return '(tempDoubleF32[0]=' + makeGetValue(ptr, pos, 'float', noNeedFirst, unsigned, ignore) + ',' + + 'tempDoubleF32[1]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('float')), 'float', noNeedFirst, unsigned, ignore) + ',' + + 'tempDoubleF64[0])'; + } + if (EMULATE_UNALIGNED_ACCESSES && USE_TYPED_ARRAYS == 2 && align && isIntImplemented(type)) { // TODO: support unaligned doubles and floats // Alignment is important here. May need to split this up var bytes = Runtime.getNativeTypeSize(type); @@ -923,12 +936,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { } if (type == 'i64' && I64_MODE == 1) { - return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore) + ',' - + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore) + ']'; + return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, 1, ignore) + ',' + + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, 1, ignore) + ']'; } var offset = calcFastOffset(ptr, pos, noNeedFirst); - if (SAFE_HEAP) { + if (SAFE_HEAP && !noSafe) { if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; if (type[0] === '#') type = type.substr(1); return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; @@ -960,7 +973,7 @@ function indexizeFunctions(value, type) { //! '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, ignore, align) { +function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe) { if (isStructType(type)) { var typeData = Types.types[type]; var ret = []; @@ -975,6 +988,12 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) { return ret.join('; '); } + if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { + return '(tempDoubleF64[0]=' + value + ',' + + makeSetValue(ptr, pos, 'tempDoubleF32[0]', 'float', noNeedFirst, ignore, align/2) + ',' + + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleF32[1]', 'float', noNeedFirst, ignore, align/2) + ')'; + } + if (EMULATE_UNALIGNED_ACCESSES && USE_TYPED_ARRAYS == 2 && align && isIntImplemented(type)) { // TODO: support unaligned doubles and floats // Alignment is important here. May need to split this up var bytes = Runtime.getNativeTypeSize(type); @@ -1003,7 +1022,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) { value = indexizeFunctions(value, type); var offset = calcFastOffset(ptr, pos, noNeedFirst); - if (SAFE_HEAP) { + if (SAFE_HEAP && !noSafe) { 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) + ')'; @@ -1458,9 +1477,8 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) { } function makeSignOp(value, type, op, force) { - // XXX this is not quite right. both parts should always be unsigned (or, perhaps always signed, we should move to that - separate issue though) if (I64_MODE == 1 && type == 'i64') { - return '(tempPair=' + value + ',[' + makeSignOp('tempPair[0]', 'i32', op, force) + ',' + makeSignOp('tempPair[1]', 'i32', op, force) + '])'; + return value; // these are always assumed to be two 32-bit unsigneds. } if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints @@ -1497,9 +1515,9 @@ function makeSignOp(value, type, op, force) { } } else { // bits > 32 if (op === 're') { - return makeInlineCalculation('VALUE >= ' + Math.pow(2, bits-1) + ' ? VALUE-' + Math.pow(2, bits) + ' : VALUE', value, 'tempBigInt'); + return makeInlineCalculation('VALUE >= ' + Math.pow(2, bits-1) + ' ? VALUE-' + Math.pow(2, bits) + ' : VALUE', value, 'tempBigIntS'); } else { - return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + '+VALUE', value, 'tempBigInt'); + return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + '+VALUE', value, 'tempBigIntS'); } } } @@ -1524,7 +1542,7 @@ function makeRounding(value, bits, signed, floatConversion) { // Note that if converting a float, we may have the wrong sign at this point! But, we have // been rounded properly regardless, and we will be sign-corrected later when actually used, if // necessary. - return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigInt'); + return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR'); } // fptoui and fptosi are not in these, because we need to be careful about what we do there. We can't @@ -1574,7 +1592,7 @@ function processMathop(item) { var bitsLeft = ident2 ? ident2.substr(2, ident2.length-3) : null; // remove (i and ), to leave number. This value is important in float ops function integerizeBignum(value) { - return makeInlineCalculation('VALUE-VALUE%1', value, 'tempBigInt'); + return makeInlineCalculation('VALUE-VALUE%1', value, 'tempBigIntI'); } if ((type == 'i64' || paramTypes[0] == 'i64' || paramTypes[1] == 'i64' || ident2 == '(i64)') && I64_MODE == 1) { @@ -1632,7 +1650,7 @@ function processMathop(item) { } } case 'zext': return makeI64(ident1, 0); - case 'sext': return makeInlineCalculation(makeI64('VALUE', 'VALUE<0 ? 4294967295 : 0'), ident1, 'tempBigInt'); + case 'sext': return makeInlineCalculation(makeI64('VALUE', 'VALUE<0 ? 4294967295 : 0'), ident1, 'tempBigIntD'); case 'trunc': { return '((' + ident1 + '[0]) & ' + (Math.pow(2, bitsLeft)-1) + ')'; } diff --git a/src/preamble.js b/src/preamble.js index 3fcdf1f8..1c614e21 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -86,93 +86,50 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) { print((new Error()).stack); throw "Bad store!" + dest; } -#if USE_TYPED_ARRAYS == 1 - if (type === null) { - IHEAP[dest] = value; -#if USE_FHEAP - FHEAP[dest] = value; -#endif - } else if (type in Runtime.FLOAT_TYPES) { - FHEAP[dest] = value; - } else { - IHEAP[dest] = value; - } -#else + #if USE_TYPED_ARRAYS == 2 - assert(type != 'null', 'typed arrays 2 with null type!'); - if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit + // Check alignment switch(type) { - case 'i1': case 'i8': HEAP8[dest] = value; break; - case 'i16': assert(dest % 2 === 0, type + ' stores must be aligned: ' + dest); HEAP16[dest>>1] = value; break; - case 'i32': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAP32[dest>>2] = value; break; - case 'i64': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAP32[dest>>2] = value; break; // XXX store int64 as int32 - case 'float': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAPF32[dest>>2] = value; break; - case 'double': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAPF32[dest>>2] = value; break; // XXX store doubles as floats - default: throw 'weird type for typed array II: ' + type + new Error().stack; - } + case 'i16': assert(dest % 2 == 0); break; + case 'i32': assert(dest % 4 == 0); break; + case 'i64': assert(dest % 8 == 0); break; + case 'float': assert(dest % 4 == 0); break; +#if DOUBLE_MODE == 1 + case 'double': assert(dest % 4 == 0); break; #else - HEAP[dest] = value; + case 'double': assert(dest % 4 == 0); warn64(); break; #endif + } #endif + + setValue(dest, value, type, 1); } function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) { SAFE_HEAP_ACCESS(dest, type, ignore); -#if USE_TYPED_ARRAYS == 1 - if (type in Runtime.FLOAT_TYPES) { #if SAFE_HEAP_LOG - print('SAFE_HEAP load: ' + [dest, type, FHEAP[dest], ignore]); + print('SAFE_HEAP load: ' + [dest, type, getValue(dest, type, 1), ignore]); #endif - return FHEAP[dest]; - } else { -#if SAFE_HEAP_LOG - print('SAFE_HEAP load: ' + [dest, type, IHEAP[dest], ignore]); -#endif - return IHEAP[dest]; - } -#else + #if USE_TYPED_ARRAYS == 2 -#if SAFE_HEAP_LOG - var originalType = type; -#endif - var ret; - if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit + // Check alignment switch(type) { - case 'i1': case 'i8': { - ret = (unsigned ? HEAPU8 : HEAP8)[dest]; - break; - } - case 'i16': { - assert(dest % 2 === 0, type + ' loads must be aligned: ' + dest); - ret = (unsigned ? HEAPU16 : HEAP16)[dest>>1]; - break; - } - case 'i32': case 'i64': { // XXX store int64 as int32 - assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest); - if (type === 'i64') warn64(); - ret = (unsigned ? HEAPU32 : HEAP32)[dest>>2]; - break; - } - case 'float': case 'double': { // XXX store doubles as floats - assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest); - if (type === 'double') warn64(); - ret = HEAPF32[dest>>2]; - break; - } - default: throw 'weird type for typed array II: ' + type; - } -#if SAFE_HEAP_LOG - print('SAFE_HEAP load: ' + [dest, originalType, ret, unsigned, ignore]); -#endif - return ret; + case 'i16': assert(dest % 2 == 0); break; + case 'i32': assert(dest % 4 == 0); break; + case 'i64': assert(dest % 8 == 0); break; + case 'float': assert(dest % 4 == 0); break; +#if DOUBLE_MODE == 1 + case 'double': assert(dest % 4 == 0); break; #else -#if SAFE_HEAP_LOG - print('SAFE_HEAP load: ' + [dest, type, HEAP[dest], ignore]); -#endif - return HEAP[dest]; + case 'double': assert(dest % 4 == 0); warn64(); break; #endif + } #endif + + var ret = getValue(dest, type, 1); + if (unsigned) ret = unSign(ret, parseInt(type.substr(1))); + return ret; } function SAFE_HEAP_COPY_HISTORY(dest, src) { @@ -377,10 +334,17 @@ var ABORT = false; var undef = 0; // tempInt is used for 32-bit signed values or smaller. tempBigInt is used // for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt -var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair; +var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD; #if I64_MODE == 1 var tempI64, tempI64b; #endif +#if DOUBLE_MODE == 1 +#if USE_TYPED_ARRAYS == 2 +var tempDoubleBuffer = new ArrayBuffer(8); +var tempDoubleF32 = new Float32Array(tempDoubleBuffer); +var tempDoubleF64 = new Float64Array(tempDoubleBuffer); +#endif +#endif function abort(text) { print(text + ':\n' + (new Error).stack); @@ -400,35 +364,71 @@ function assert(condition, text) { // code then, whereas this function picks the right code at // run-time. -function setValue(ptr, value, type) { +function setValue(ptr, value, type, noSafe) { + type = type || 'i8'; if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit - switch(type) { - case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1') }}}; break; - case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8') }}}; break; - case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16') }}}; break; - case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32') }}}; break; - case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64') }}}; break; - case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float') }}}; break; - case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double') }}}; break; - default: abort('invalid type for setValue: ' + type); +#if SAFE_HEAP + if (noSafe) { + switch(type) { + case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1', undefined, undefined, undefined, '1') }}}; break; + case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8', undefined, undefined, undefined, '1') }}}; break; + case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16', undefined, undefined, undefined, '1') }}}; break; + case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32', undefined, undefined, undefined, '1') }}}; break; + case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64', undefined, undefined, undefined, '1') }}}; break; + case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float', undefined, undefined, undefined, '1') }}}; break; + case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double', undefined, undefined, undefined, '1') }}}; break; + default: abort('invalid type for setValue: ' + type); + } + } else { +#endif + switch(type) { + case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1') }}}; break; + case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8') }}}; break; + case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16') }}}; break; + case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32') }}}; break; + case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64') }}}; break; + case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float') }}}; break; + case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double') }}}; break; + default: abort('invalid type for setValue: ' + type); + } +#if SAFE_HEAP } +#endif } Module['setValue'] = setValue; // Parallel to setValue. -function getValue(ptr, type) { +function getValue(ptr, type, noSafe) { + type = type || 'i8'; if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit - switch(type) { - case 'i1': return {{{ makeGetValue('ptr', '0', 'i1') }}}; - case 'i8': return {{{ makeGetValue('ptr', '0', 'i8') }}}; - case 'i16': return {{{ makeGetValue('ptr', '0', 'i16') }}}; - case 'i32': return {{{ makeGetValue('ptr', '0', 'i32') }}}; - case 'i64': return {{{ makeGetValue('ptr', '0', 'i64') }}}; - case 'float': return {{{ makeGetValue('ptr', '0', 'float') }}}; - case 'double': return {{{ makeGetValue('ptr', '0', 'double') }}}; - default: abort('invalid type for setValue: ' + type); +#if SAFE_HEAP + if (noSafe) { + switch(type) { + case 'i1': return {{{ makeGetValue('ptr', '0', 'i1', undefined, undefined, undefined, undefined, '1') }}}; + case 'i8': return {{{ makeGetValue('ptr', '0', 'i8', undefined, undefined, undefined, undefined, '1') }}}; + case 'i16': return {{{ makeGetValue('ptr', '0', 'i16', undefined, undefined, undefined, undefined, '1') }}}; + case 'i32': return {{{ makeGetValue('ptr', '0', 'i32', undefined, undefined, undefined, undefined, '1') }}}; + case 'i64': return {{{ makeGetValue('ptr', '0', 'i64', undefined, undefined, undefined, undefined, '1') }}}; + case 'float': return {{{ makeGetValue('ptr', '0', 'float', undefined, undefined, undefined, undefined, '1') }}}; + case 'double': return {{{ makeGetValue('ptr', '0', 'double', undefined, undefined, undefined, undefined, '1') }}}; + default: abort('invalid type for setValue: ' + type); + } + } else { +#endif + switch(type) { + case 'i1': return {{{ makeGetValue('ptr', '0', 'i1') }}}; + case 'i8': return {{{ makeGetValue('ptr', '0', 'i8') }}}; + case 'i16': return {{{ makeGetValue('ptr', '0', 'i16') }}}; + case 'i32': return {{{ makeGetValue('ptr', '0', 'i32') }}}; + case 'i64': return {{{ makeGetValue('ptr', '0', 'i64') }}}; + case 'float': return {{{ makeGetValue('ptr', '0', 'float') }}}; + case 'double': return {{{ makeGetValue('ptr', '0', 'double') }}}; + default: abort('invalid type for setValue: ' + type); + } +#if SAFE_HEAP } +#endif return null; } Module['getValue'] = getValue; @@ -532,6 +532,41 @@ var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32; var STACK_ROOT, STACKTOP, STACK_MAX; var STATICTOP; +#if USE_TYPED_ARRAYS +var LAST_STATICTOP; +function enlargeMemory() { + // LAST_STATICTOP is the previous top, TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top. +#if ASSERTIONS + assert(STATICTOP >= TOTAL_MEMORY && LAST_STATICTOP < TOTAL_MEMORY); + assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite +#endif + while (TOTAL_MEMORY <= STATICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it + TOTAL_MEMORY = alignMemoryPage(TOTAL_MEMORY*1.25); + } +#if USE_TYPED_ARRAYS == 1 + var oldIHEAP = IHEAP; + HEAP = IHEAP = new Int32Array(TOTAL_MEMORY); + IHEAP.set(oldIHEAP); +#if USE_FHEAP + var oldFHEAP = FHEAP; + FHEAP = new Float64Array(TOTAL_MEMORY); + FHEAP.set(oldFHEAP); +#endif +#endif +#if USE_TYPED_ARRAYS == 2 + var oldHEAP8 = HEAP8; + var buffer = new ArrayBuffer(TOTAL_MEMORY); + HEAP8 = new Int8Array(buffer); + HEAP16 = new Int16Array(buffer); + HEAP32 = new Int32Array(buffer); + HEAPU8 = new Uint8Array(buffer); + HEAPU16 = new Uint16Array(buffer); + HEAPU32 = new Uint32Array(buffer); + HEAPF32 = new Float32Array(buffer); + HEAP8.set(oldHEAP8); +#endif +} +#endif var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}}; diff --git a/src/runtime.js b/src/runtime.js index a6261c74..0b36f967 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -56,7 +56,11 @@ var RuntimeGenerator = { // An allocation that cannot be free'd staticAlloc: function(size) { - return RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP); + var ret = ''; + if (USE_TYPED_ARRAYS) ret += 'LAST_STATICTOP = STATICTOP;' + ret += RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP); + if (USE_TYPED_ARRAYS) ret += '; if (STATICTOP >= TOTAL_MEMORY) enlargeMemory();' + return ret; }, alignMemory: function(target, quantum) { @@ -301,6 +305,8 @@ function reSign(value, bits, ignore, sig) { var noted = false; #endif if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that + // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors + // TODO: In i64 mode 1, resign the two parts separately and safely #if CHECK_SIGNS if (!ignore) { CorrectionsMonitor.note('ReSign', 0, sig); diff --git a/src/settings.js b/src/settings.js index 0964d4bb..2d645a12 100644 --- a/src/settings.js +++ b/src/settings.js @@ -29,19 +29,18 @@ var ASSERTIONS = 1; // Whether we should add runtime assertions, for example to var INVOKE_RUN = 1; // Whether we will call run(). Disable if you embed the generated // code in your own, and will call run() yourself at the right time -var INIT_STACK = 1; // Whether to initialize memory on the stack to 0. +var INIT_STACK = 0; // Whether to initialize memory on the stack to 0. var INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to 0. var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This ensures it will be // in a flat array. This only matters in non-typed array builds. -var TOTAL_MEMORY = 50*1024*1024; // The total amount of memory to use. This mainly matters in - // typed array builds - accessing memory about this value will - // return undefined values and lead to serious problems, and there - // is currently no warning about that! +var TOTAL_MEMORY = 10*1024*1024; // The total amount of memory to use. Using more memory than this will + // cause us to expand the heap, which can be costly with typed arrays: + // we need to copy the old heap into a new one in that case. // Code embetterments -var MICRO_OPTS = 0; // Various micro-optimizations, like nativizing variables +var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables var RELOOP = 0; // Recreate js native loops from llvm data -var USE_TYPED_ARRAYS = 0; // Try to use typed arrays for the heap +var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap // 1 has two heaps, IHEAP (int32) and FHEAP (double), // and addresses there are a match for normal addresses. This wastes memory but can be fast. // 2 is a single heap, accessible through views as int8, int32, etc. This saves memory but @@ -52,12 +51,20 @@ var USE_TYPED_ARRAYS = 0; // Try to use typed arrays for the heap // TODO: require compiling with -malign-double, which does align doubles var USE_FHEAP = 1; // Relevant in USE_TYPED_ARRAYS == 1. If this is disabled, only IHEAP will be used, and FHEAP // not generated at all. This is useful if your code is 100% ints without floats or doubles -var I64_MODE = 0; // How to implement 64-bit integers: +var I64_MODE = 1; // How to implement 64-bit integers: // 0: As doubles. This will work up to about 53 bits. // 1: As [low, high]. This will support all 64 bits for bit ops, etc. properly, but will still // use doubles for addition etc., like mode 0. This mode is slower than // mode 0, so its only benefit is proper support for 64 bit bitops. // TODO: Full bignum support +var DOUBLE_MODE = 1; // How to load and store 64-bit doubles. Without typed arrays or in typed array mode 1, + // this doesn't matter - these values are just values like any other. In typed array mode 2, + // a potentialy risk is that doubles may be only 32-bit aligned. Forcing 64-bit alignment + // in Clang itself should be able to solve that, or as a workaround in DOUBLE_MODE 1 we + // will carefully load in parts, in a way that requires only 32-bit alignment. In DOUBLE_MODE + // 0 we will simply store and load doubles as 32-bit floats, so when they are stored/loaded + // they will truncate from 64 to 32 bits, and lose precision. This is faster, and might + // work for some code (but probably that code should just use floats and not doubles anyhow). var EMULATE_UNALIGNED_ACCESSES = 1; // If set, the compiler will 'emulate' loads and stores that are not known to // be sufficiently aligned, by working on individual bytes. This can be // important in USE_TYPED_ARRAYS == 2, where unaligned accesses do not work, |