diff options
Diffstat (limited to 'src/parseTools.js')
-rw-r--r-- | src/parseTools.js | 185 |
1 files changed, 128 insertions, 57 deletions
diff --git a/src/parseTools.js b/src/parseTools.js index 32bf70e9..5f8797b0 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -974,7 +974,7 @@ if (ASM_JS) { var memoryMask = hexMemoryMask.length <= decMemoryMask.length ? hexMemoryMask : decMemoryMask; } -function getHeapOffset(offset, type) { +function getHeapOffset(offset, type, forceAsm) { if (USE_TYPED_ARRAYS !== 2) { return offset; } else { @@ -983,7 +983,7 @@ function getHeapOffset(offset, type) { } var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2; offset = '(' + offset + ')'; - if (ASM_JS && phase == 'funcs') offset = '(' + offset + '&' + memoryMask + ')'; + if (ASM_JS && (phase == 'funcs' || forceAsm)) offset = '(' + offset + '&' + memoryMask + ')'; if (shifts != 0) { return '(' + offset + '>>' + shifts + ')'; } else { @@ -1019,14 +1019,18 @@ function asmCoercion(value, type, signedness) { if (type == 'void') { return value; } else if (type in Runtime.FLOAT_TYPES) { - if (signedness) { - if (signedness == 'u') { - value = '(' + value + ')>>>0'; - } else { - value = '(' + value + ')|0'; + if (isNumber(value)) { + return asmEnsureFloat(value, type); + } else { + if (signedness) { + if (signedness == 'u') { + value = '(' + value + ')>>>0'; + } else { + value = '(' + value + ')|0'; + } } + return '(+(' + value + '))'; } - return '(+(' + value + '))'; } else { return '((' + value + ')|0)'; } @@ -1041,7 +1045,7 @@ function asmMultiplyI32(a, b) { return '(~~(+((' + a + ')|0) * +((' + b + ')|0)))'; } -function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble temporary storage +function makeGetTempDouble(i, type, forSet) { // get an aliased part of the tempDouble temporary storage // Cannot use makeGetValue because it uses us // this is a unique case where we *can* use HEAPF64 var slab = type == 'double' ? 'HEAPF64' : makeGetSlabs(null, type)[0]; @@ -1053,11 +1057,17 @@ function makeGetTempDouble(i, type) { // get an aliased part of the tempDouble t } else { offset = getHeapOffset(ptr, type); } - return slab + '[' + offset + ']'; + var ret = slab + '[' + offset + ']'; + if (!forSet) ret = asmCoercion(ret, type); + return ret; +} + +function makeSetTempDouble(i, type, value) { + return makeGetTempDouble(i, type, true) + '=' + asmEnsureFloat(value, type); } // See makeSetValue -function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) { +function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe, forceAsm) { if (UNALIGNED_MEMORY) align = 1; if (isStructType(type)) { var typeData = Types.types[type]; @@ -1069,8 +1079,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(' + makeGetTempDouble(0, 'i32') + '=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' + - makeGetTempDouble(1, 'i32') + '=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' + + return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + + makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align)) + ',' + makeGetTempDouble(0, 'double') + ')'; } @@ -1110,7 +1120,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa if (type[0] === '#') type = type.substr(1); return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; } else { - var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']'; + var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; if (ASM_JS && phase == 'funcs') { ret = asmCoercion(ret, type); } @@ -1118,6 +1128,10 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } } +function makeGetValueAsm(ptr, pos, type) { + return makeGetValue(ptr, pos, type, null, null, null, null, null, true); +} + function indexizeFunctions(value, type) { assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing'); assert(value !== type, 'Type set to value'); @@ -1165,7 +1179,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(' + makeGetTempDouble(0, 'double') + '=' + value + ',' + + return '(' + makeSetTempDouble(0, 'double', value) + ',' + makeSetValue(ptr, pos, makeGetTempDouble(0, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), makeGetTempDouble(1, 'i32'), 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; } else if (USE_TYPED_ARRAYS == 2 && type == 'i64') { @@ -1191,7 +1205,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, ret += 'tempBigInt=' + value + sep; for (var i = 0; i < bytes; i++) { ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1); - if (i < bytes-1) ret += sep + 'tempBigInt>>=8' + sep; + if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep; } } } else { @@ -1236,7 +1250,7 @@ function makeSetValues(ptr, pos, value, type, num, align) { // If we don't know how to handle this at compile-time, or handling it is best done in a large amount of code, call memset // TODO: optimize the case of numeric num but non-numeric value if (!isNumber(num) || !isNumber(value) || (align < 4 && parseInt(num) >= SEEK_OPTIMAL_ALIGN_MIN)) { - return '_memset(' + getFastValue(ptr, '+', pos) + ', ' + value + ', ' + num + ', ' + align + ')'; + return '_memset(' + asmCoercion(getFastValue(ptr, '+', pos), 'i32') + ', ' + asmCoercion(value, 'i32') + ', ' + asmCoercion(num, 'i32') + ', ' + align + ')'; } num = parseInt(num); value = parseInt(value); @@ -1426,8 +1440,18 @@ var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); function makePointer(slab, pos, allocator, type, ptr) { assert(type, 'makePointer requires type info'); - if (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP)) return pos; + if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos; var types = generateStructTypes(type); + if (typeof slab == 'object') { + for (var i = 0; i < slab.length; i++) { + var curr = slab[i]; + if (isNumber(curr)) { + slab[i] = parseFloat(curr); // fix "5" to 5 etc. + } else if (curr == 'undef') { + slab[i] = 0; + } + } + } // compress type info and data if possible var de; try { @@ -1435,25 +1459,68 @@ function makePointer(slab, pos, allocator, type, ptr) { // note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str var evaled = typeof slab === 'string' ? eval(slab) : slab; de = dedup(evaled); - if (de.length === 1 && de[0] === 0) { + if (de.length === 1 && de[0] == 0) { slab = types.length; - if (USE_TYPED_ARRAYS == 2) { - types = ['i8']; // if data is zeros, we don't need type info - } } // TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also // be careful of structure padding } catch(e){} - de = dedup(types); - if (de.length === 1) { - types = de[0]; - } else if (de.length === 2 && typeof slab === 'number') { - // If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros - de = de.filter(function(x) { return x !== 0 }); + if (USE_TYPED_ARRAYS != 2) { + de = dedup(types); if (de.length === 1) { types = de[0]; + } else if (de.length === 2 && typeof slab === 'number') { + // If slab is all zeros, we can compress types even if we have i32,0,0,0,i32,0,0,0 etc. - we do not need the zeros + de = de.filter(function(x) { return x !== 0 }); + if (de.length === 1) { + types = de[0]; + } + } + } else { // USE_TYPED_ARRAYS == 2 + var fail = false; + if (typeof slab === 'object') { + // flatten out into i8 values, so we can just to typed array .set() + for (var i = 0; i < slab.length; i++) { + if (!isNumber(slab[i])) { fail = true; break } + } + if (!fail) { + // XXX This heavily assumes the target endianness is the same as our current endianness! XXX + var i = 0; + var temp64f = new Float64Array(1); + var temp32f = new Float32Array(temp64f.buffer); + var temp32 = new Uint32Array(temp64f.buffer); + var temp16 = new Uint16Array(temp64f.buffer); + var temp8 = new Uint8Array(temp64f.buffer); + while (i < slab.length) { + var currType = types[i]; + if (!currType) { i++; continue } + var currSize = 0, currValue = slab[i]; + switch (currType) { + case 'i8': i++; continue; + case 'i16': temp16[0] = currValue; currSize = 2; break; + case 'i64': // fall through, i64 is two i32 chunks + case 'i32': temp32[0] = currValue; currSize = 4; break; + case 'float': temp32f[0] = currValue; currSize = 4; break; + case 'double': temp64f[0] = currValue; currSize = 8; break; + default: { + if (currType[currType.length-1] == '*') { + temp32[0] = currValue; + currSize = 4; + } else { + throw 'what? ' + types[i]; + } + } + } + for (var j = 0; j < currSize; j++) { + slab[i+j] = temp8[j]; + } + i += currSize; + } + } } + if (!fail) types = 'i8'; } + if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime var chunkSize = 10240; function chunkify(array) { @@ -1466,7 +1533,7 @@ function makePointer(slab, pos, allocator, type, ptr) { } return ret; } - if (typeof slab == 'string' && evaled && evaled.length > chunkSize) { + if (typeof slab == 'string' && evaled && evaled.length > chunkSize && slab.length > chunkSize) { slab = chunkify(evaled); } if (typeof types != 'string' && types.length > chunkSize) { @@ -1666,6 +1733,10 @@ function makeStructuralAccess(ident, i) { } } +function makeThrow(what) { + return 'throw ' + what + (DISABLE_EXCEPTION_CATCHING == 1 ? ' + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch."' : '') + ';'; +} + // From parseLLVMSegment function finalizeLLVMParameter(param, noIndexizeFunctions) { var ret; @@ -1876,8 +1947,8 @@ function processMathop(item) { } function i64PreciseOp(type, lastArg) { Types.preciseI64MathUsed = true; - return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + - (lastArg ? ',' + lastArg : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); + return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') + + (lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); } switch (op) { // basic integer ops @@ -1894,7 +1965,7 @@ function processMathop(item) { case 'ashr': case 'lshr': { if (!isNumber(idents[1])) { - return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0),' + + return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],' + Runtime['BITSHIFT64_' + op.toUpperCase()] + ',' + stripCorrections(idents[1]) + '[0]|0),' + '[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])'; } bits = parseInt(idents[1]); @@ -1935,24 +2006,24 @@ function processMathop(item) { case 'fptoui': case 'fptosi': return finish(splitI64(idents[0])); case 'icmp': { switch (variant) { - case 'uge': return '(' + high1 + '>>>0) >= (' + high2 + '>>>0) && ((' + high1 + '>>>0) > (' + high2 + '>>>0) || ' + - '(' + low1 + '>>>0) >= (' + low2 + '>>>0))'; - case 'sge': return '(' + high1 + '|0) >= (' + high2 + '|0) && ((' + high1 + '|0) > (' + high2 + '|0) || ' + - '(' + low1 + '>>>0) >= (' + low2 + '>>>0))'; - case 'ule': return '(' + high1 + '>>>0) <= (' + high2 + '>>>0) && ((' + high1 + '>>>0) < (' + high2 + '>>>0) || ' + - '(' + low1 + '>>>0) <= (' + low2 + '>>>0))'; - case 'sle': return '(' + high1 + '|0) <= (' + high2 + '|0) && ((' + high1 + '|0) < (' + high2 + '|0) || ' + - '(' + low1 + '>>>0) <= (' + low2 + '>>>0))'; - case 'ugt': return '(' + high1 + '>>>0) > (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' + - '(' + low1 + '>>>0) > (' + low2 + '>>>0))'; - case 'sgt': return '(' + high1 + '|0) > (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' + - '(' + low1 + '>>>0) > (' + low2 + '>>>0))'; - case 'ult': return '(' + high1 + '>>>0) < (' + high2 + '>>>0) || ((' + high1 + '>>>0) == (' + high2 + '>>>0) && ' + - '(' + low1 + '>>>0) < (' + low2 + '>>>0))'; - case 'slt': return '(' + high1 + '|0) < (' + high2 + '|0) || ((' + high1 + '|0) == (' + high2 + '|0) && ' + - '(' + low1 + '>>>0) < (' + low2 + '>>>0))'; - case 'ne': return low1 + ' != ' + low2 + ' || ' + high1 + ' != ' + high2 + ''; - case 'eq': return low1 + ' == ' + low2 + ' && ' + high1 + ' == ' + high2 + ''; + case 'uge': return '((' + high1 + '>>>0) >= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ' + + '(' + low1 + '>>>0) >= (' + low2 + '>>>0)))'; + case 'sge': return '((' + high1 + '|0) >= (' + high2 + '|0)) & ((((' + high1 + '|0) > (' + high2 + '|0)) | ' + + '(' + low1 + '>>>0) >= (' + low2 + '>>>0)))'; + case 'ule': return '((' + high1 + '>>>0) <= (' + high2 + '>>>0)) & ((((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ' + + '(' + low1 + '>>>0) <= (' + low2 + '>>>0)))'; + case 'sle': return '((' + high1 + '|0) <= (' + high2 + '|0)) & ((((' + high1 + '|0) < (' + high2 + '|0)) | ' + + '(' + low1 + '>>>0) <= (' + low2 + '>>>0)))'; + case 'ugt': return '((' + high1 + '>>>0) > (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' + + '(' + low1 + '>>>0) > (' + low2 + '>>>0))))'; + case 'sgt': return '((' + high1 + '|0) > (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' + + '(' + low1 + '>>>0) > (' + low2 + '>>>0))))'; + case 'ult': return '((' + high1 + '>>>0) < (' + high2 + '>>>0)) | ((((' + high1 + '>>>0) == (' + high2 + '>>>0) & ' + + '(' + low1 + '>>>0) < (' + low2 + '>>>0))))'; + case 'slt': return '((' + high1 + '|0) < (' + high2 + '|0)) | ((((' + high1 + '|0) == (' + high2 + '|0) & ' + + '(' + low1 + '>>>0) < (' + low2 + '>>>0))))'; + case 'ne': return '((' + low1 + '|0) != (' + low2 + '|0)) | ((' + high1 + '|0) != (' + high2 + '|0))'; + case 'eq': return '((' + low1 + '|0) == (' + low2 + '|0)) & ((' + high1 + '|0) == (' + high2 + '|0))'; default: throw 'Unknown icmp variant: ' + variant; } } @@ -2012,15 +2083,15 @@ function processMathop(item) { var outType = item.type; if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) { if (legalizedI64s) { - return '(' + makeGetTempDouble(0, 'i32') + '=' + idents[0] + '$0, ' + makeGetTempDouble(1, 'i32') + '=' + idents[0] + '$1, ' + makeGetTempDouble(0, 'double') + ')'; + return '(' + makeSetTempDouble(0, 'i32', idents[0] + '$0') + ', ' + makeSetTempDouble(1, 'i32', idents[0] + '$1') + ', ' + makeGetTempDouble(0, 'double') + ')'; } else { - return makeInlineCalculation(makeGetTempDouble(0, 'i32') + '=VALUE[0],' + makeGetTempDouble(1, 'i32') + '=VALUE[1],' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64'); + return makeInlineCalculation(makeSetTempDouble(0, 'i32', 'VALUE[0]') + ',' + makeSetTempDouble(1, 'i32', 'VALUE[1]') + ',' + makeGetTempDouble(0, 'double'), idents[0], 'tempI64'); } } else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) { if (legalizedI64s) { - return makeGetTempDouble(0, 'double') + '=' + idents[0] + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]); + return makeSetTempDouble(0, 'double', idents[0]) + '; ' + finish([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32')]); } else { - return '(' + makeGetTempDouble(0, 'double') + '=' + idents[0] + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])'; + return '(' + makeSetTempDouble(0, 'double', idents[0]) + ',[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])'; } } else { throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type; @@ -2038,7 +2109,7 @@ function processMathop(item) { case 'mul': { if (bits == 32 && PRECISE_I32_MUL) { Types.preciseI64MathUsed = true; - return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + idents[0] + ',0,' + idents[1] + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')'; + return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + asmCoercion(idents[0], 'i32') + ',0,' + asmCoercion(idents[1], 'i32') + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')'; } else { return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits); } @@ -2159,9 +2230,9 @@ function processMathop(item) { (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES)) { assert(USE_TYPED_ARRAYS == 2, 'Can only bitcast ints <-> floats with typed arrays mode 2'); if (inType in Runtime.INT_TYPES) { - return '(' + makeGetTempDouble(0, 'i32') + '=' + idents[0] + ',' + makeGetTempDouble(0, 'float') + ')'; + return '(' + makeSetTempDouble(0, 'i32', idents[0]) + ',' + makeGetTempDouble(0, 'float') + ')'; } else { - return '(' + makeGetTempDouble(0, 'float') + '=' + idents[0] + ',' + makeGetTempDouble(0, 'i32') + ')'; + return '(' + makeSetTempDouble(0, 'float', idents[0]) + ',' + makeGetTempDouble(0, 'i32') + ')'; } } return idents[0]; |