diff options
Diffstat (limited to 'src/parseTools.js')
-rw-r--r-- | src/parseTools.js | 173 |
1 files changed, 138 insertions, 35 deletions
diff --git a/src/parseTools.js b/src/parseTools.js index 4a76a9a2..13839d17 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -128,16 +128,48 @@ function isStructType(type) { return type[0] == '%'; } +function isStructuralType(type) { + return /^{ ?[^}]* ?}$/.test(type); // { i32, i8 } etc. - anonymous struct types +} + +function getStructuralTypeParts(type) { // split { i32, i8 } etc. into parts + return type.replace(/[ {}]/g, '').split(','); +} + +function getStructureTypeParts(type) { + if (isStructuralType(type)) { + return type.replace(/[ {}]/g, '').split(','); + } else { + var typeData = Types.types[type]; + assert(typeData, type); + return typeData.fields; + } +} + +function getStructuralTypePartBits(part) { + return Math.ceil((getBits(part) || 32)/32)*32; // simple 32-bit alignment. || 32 is for pointers +} + function isIntImplemented(type) { return type[0] == 'i' || isPointerType(type); } -// Note: works for iX types, not pointers (even though they are implemented as ints) +// Note: works for iX types and structure types, not pointers (even though they are implemented as ints) function getBits(type) { - if (!type || type[0] != 'i') return 0; - var left = type.substr(1); - if (!isNumber(left)) return 0; - return parseInt(left); + if (!type) return 0; + if (type[0] == 'i') { + var left = type.substr(1); + if (!isNumber(left)) return 0; + return parseInt(left); + } + if (isStructuralType(type)) { + return sum(getStructuralTypeParts(type).map(getStructuralTypePartBits)); + } + if (isStructType(type)) { + var typeData = Types.types[type]; + return typeData.flatSize*8; + } + return 0; } function isIllegalType(type) { @@ -163,11 +195,13 @@ function isFunctionDef(token, out) { var subtext = segment[0].text; fail = fail || segment.length > 1 || !(isType(subtext) || subtext == '...'); }); - if (out) out.numArgs = segments.length; + if (out) { + out.segments = segments; + out.numArgs = segments.length; + } return !fail; } - function isPossiblyFunctionType(type) { // A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite. var len = type.length; @@ -189,6 +223,7 @@ function isFunctionType(type, out) { if (pointingLevels(type) !== 1) return false; var text = removeAllPointing(parts.slice(1).join(' ')); if (!text) return false; + if (out) out.returnType = parts[0]; return isType(parts[0]) && isFunctionDef({ text: text, item: tokenize(text.substr(1, text.length-2), true) }, out); } @@ -373,12 +408,12 @@ function isIndexableGlobal(ident) { function makeGlobalDef(ident) { if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return ''; - return 'var ' + ident + ';'; // TODO: add option for namespacing or offsetting to allow reducing the number of globals + return 'var ' + ident + ';'; } function makeGlobalUse(ident) { if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '(' + getFastValue('GLOBAL_BASE', '+', Variables.indexedGlobals[ident]) + ')'; - return ident; // TODO: add option for namespacing or offsetting to allow reducing the number of globals + return ident; } function sortGlobals(globals) { @@ -922,6 +957,12 @@ function checkSafeHeap() { return SAFE_HEAP === 1 || checkSpecificSafeHeap(); } +if (ASM_JS) { + var hexMemoryMask = '0x' + (TOTAL_MEMORY-1).toString(16); + var decMemoryMask = (TOTAL_MEMORY-1).toString(); + var memoryMask = hexMemoryMask.length <= decMemoryMask.length ? hexMemoryMask : decMemoryMask; +} + function getHeapOffset(offset, type) { if (USE_TYPED_ARRAYS !== 2) { return offset; @@ -930,14 +971,42 @@ function getHeapOffset(offset, type) { type = 'i32'; // XXX we emulate 64-bit values as 32 } var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2; + offset = '(' + offset + ')'; + if (ASM_JS && phase == 'funcs') offset = '(' + offset + '&' + memoryMask + ')'; if (shifts != 0) { - return '((' + offset + ')>>' + (shifts) + ')'; + return '(' + offset + '>>' + shifts + ')'; } else { - return '(' + offset + ')'; + return offset; } } } +function makeVarDef(js) { + if (!ASM_JS) js = 'var ' + js; + return js; +} + +function asmInitializer(type, impl) { + if (isIntImplemented(type)) {// || (impl && impl == 'VAR_EMULATED')) { + return '0'; + } else { + return '+0'; + } +} + +function asmCoercion(value, type) { + if (!ASM_JS) return value; + if (isIntImplemented(type)) { + return '((' + value + ')|0)'; + } else { + return '(+(' + value + '))'; + } +} + +function makeGetTempDouble(i) { + return makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32')*i, 'i32'); +} + // See makeSetValue function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) { noticePtr(ptr); @@ -952,9 +1021,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(tempDoubleI32[0]=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' + - 'tempDoubleI32[1]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' + - 'tempDoubleF64[0])'; + return '(HEAP32[tempDoublePtr>>2]=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' + + 'HEAP32[tempDoublePtr+4>>2]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' + + 'HEAPF64[tempDoublePtr>>3])'; } if (USE_TYPED_ARRAYS == 2 && align) { @@ -977,9 +1046,9 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa } } else { if (type == 'float') { - ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),tempDoubleF32[0]'; + ret += 'copyTempFloat(' + getFastValue(ptr, '+', pos) + '),HEAPF32[tempDoublePtr>>2]'; } else { - ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),tempDoubleF64[0]'; + ret += 'copyTempDouble(' + getFastValue(ptr, '+', pos) + '),HEAP64[tempDoublePtr>>3]'; } } ret += ')'; @@ -993,14 +1062,24 @@ 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 { - return makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']'; + var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']'; + if (ASM_JS && phase == 'funcs') { + ret = asmCoercion(ret, type); + } + return ret; } } 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'); - if (type && isFunctionType(type) && value[0] === '_') { // checking for _ differentiates from $ (local vars) + var out = {}; + if (type && isFunctionType(type, out) && value[0] === '_') { // checking for _ differentiates from $ (local vars) + // add signature to library functions that we now know need indexing + if (!(value in Functions.implementedFunctions) && !(value in Functions.unimplementedFunctions)) { + Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : []); + } + if (BUILD_AS_SHARED_LIB) { return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')'; } else { @@ -1039,9 +1118,9 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, } if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') { - return '(tempDoubleF64[0]=' + value + ',' + - makeSetValue(ptr, pos, 'tempDoubleI32[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + - makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleI32[1]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; + return '(HEAPF64[tempDoublePtr>>3]=' + value + ',' + + makeSetValue(ptr, pos, 'HEAP32[tempDoublePtr>>2]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + + makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'HEAP32[tempDoublePtr+4>>2]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ')'; } else if (USE_TYPED_ARRAYS == 2 && type == 'i64') { return '(tempI64 = [' + splitI64(value) + '],' + makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, noSafe, ',') + ',' + @@ -1125,7 +1204,7 @@ function makeSetValues(ptr, pos, value, type, num, align) { [4, 2, 1].forEach(function(possibleAlign) { if (num == 0) return; if (align >= possibleAlign) { - if (num <= UNROLL_LOOP_MAX*possibleAlign) { + if (num <= UNROLL_LOOP_MAX*possibleAlign || ASM_JS) { // XXX test asm performance ret.push(unroll('i' + (possibleAlign*8), Math.floor(num/possibleAlign), possibleAlign, values[possibleAlign])); } else { ret.push('for (var $$dest = ' + getFastValue(ptr, '+', pos) + (possibleAlign > 1 ? '>>' + log2(possibleAlign) : '') + ', ' + @@ -1179,7 +1258,7 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep) { if (num == 0) return; if (align >= possibleAlign) { // If we can unroll the loop, do so. Also do so if we must unroll it (we do not create real loops when inlined) - if (num <= UNROLL_LOOP_MAX*possibleAlign || sep == ',') { + if (num <= UNROLL_LOOP_MAX*possibleAlign || sep == ',' || ASM_JS) { // XXX test asm performance ret.push(unroll('i' + (possibleAlign*8), Math.floor(num/possibleAlign), possibleAlign)); } else { assert(sep == ';'); @@ -1489,8 +1568,27 @@ function handleOverflow(text, bits) { } } -function makeLLVMStruct(values) { // TODO: Use this everywhere - return '{ ' + values.map(function(value, i) { return 'f' + i + ': ' + value }).join(', ') + ' }' +function makeLLVMStruct(values) { + if (USE_TYPED_ARRAYS == 2) { + return 'DEPRECATED' + (new Error().stack) + 'XXX'; + } else { + return '{ ' + values.map(function(value, i) { return 'f' + i + ': ' + value }).join(', ') + ' }' + } +} + +function makeStructuralReturn(values) { + if (USE_TYPED_ARRAYS == 2) { + var i = 0; + return 'return (' + values.slice(1).map(function(value) { + return ASM_JS ? 'asm.setTempRet' + (i++) + '(' + value + ')' + : 'tempRet' + (i++) + ' = ' + value; + }).concat([values[0]]).join(',') + ')'; + } else { + var i = 0; + return 'return { ' + values.map(function(value) { + return 'f' + (i++) + ': ' + value; + }).join(', ') + ' }'; + } } // From parseLLVMSegment @@ -1599,6 +1697,10 @@ function makeSignOp(value, type, op, force, ignore) { function makeRounding(value, bits, signed, floatConversion) { // TODO: handle roundings of i64s assert(bits); + if (ASM_JS && floatConversion && bits <= 32) { + return '(~~(' + value + '))'; // explicit float-to-int conversion + } + // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that. if (bits <= 32 && signed) return '((' + value + ')&-1)'; // This is fast and even correct, for all cases. Note that it is the same // as |0, but &-1 hints to the js optimizer that this is a rounding correction @@ -1696,8 +1798,8 @@ function processMathop(item) { } function i64PreciseOp(type, lastArg) { Types.preciseI64MathUsed = true; - return finish(['(i64Math.' + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + - (lastArg ? ',' + lastArg : '') + '),i64Math.result[0])', 'i64Math.result[1]']); + return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + + (lastArg ? ',' + lastArg : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); } switch (op) { // basic integer ops @@ -1714,7 +1816,8 @@ function processMathop(item) { case 'ashr': case 'lshr': { if (!isNumber(idents[1])) { - return 'Runtime.bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0)'; + return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],"' + op + '",' + stripCorrections(idents[1]) + '[0]|0),' + + '[' + makeGetTempDouble(0) + ',' + makeGetTempDouble(1) + '])'; } bits = parseInt(idents[1]); var ander = Math.pow(2, bits)-1; @@ -1831,15 +1934,15 @@ function processMathop(item) { var outType = item.type; if (inType in Runtime.INT_TYPES && outType in Runtime.FLOAT_TYPES) { if (legalizedI64s) { - return '(tempDoubleI32[0]=' + idents[0] + '$0, tempDoubleI32[1]=' + idents[0] + '$1, tempDoubleF64[0])'; + return '(HEAP32[tempDoublePtr>>2]=' + idents[0] + '$0, HEAP32[tempDoublePtr+4>>2]=' + idents[0] + '$1, HEAPF64[tempDoublePtr>>3])'; } else { - return makeInlineCalculation('tempDoubleI32[0]=VALUE[0],tempDoubleI32[1]=VALUE[1],tempDoubleF64[0]', idents[0], 'tempI64'); + return makeInlineCalculation('HEAP32[tempDoublePtr>>2]=VALUE[0],HEAP32[tempDoublePtr+4>>2]=VALUE[1],HEAPF64[tempDoublePtr>>>3]', idents[0], 'tempI64'); } } else if (inType in Runtime.FLOAT_TYPES && outType in Runtime.INT_TYPES) { if (legalizedI64s) { - return 'tempDoubleF64[0]=' + idents[0] + '; ' + finish(['tempDoubleI32[0]','tempDoubleI32[1]']); + return 'HEAPF64[tempDoublePtr>>3]=' + idents[0] + '; ' + finish(['HEAP32[tempDoublePtr>>2]','HEAP32[tempDoublePtr+4>>2]']); } else { - return '(tempDoubleF64[0]=' + idents[0] + ',[tempDoubleI32[0],tempDoubleI32[1]])'; + return '(HEAPF64[tempDoublePtr>>3]=' + idents[0] + ',[HEAP32[tempDoublePtr>>2],HEAP32[tempDoublePtr+4>>2]])'; } } else { throw 'Invalid USE_TYPED_ARRAYS == 2 bitcast: ' + dump(item) + ' : ' + item.params[0].type; @@ -1857,7 +1960,7 @@ function processMathop(item) { case 'mul': { if (bits == 32 && PRECISE_I32_MUL) { Types.preciseI64MathUsed = true; - return '(i64Math.multiply(' + idents[0] + ',0,' + idents[1] + ',0),i64Math.result[0])'; + return '(i64Math' + (ASM_JS ? '_' : '.') + 'multiply(' + idents[0] + ',0,' + idents[1] + ',0),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')'; } else { return handleOverflow(getFastValue(idents[0], '*', idents[1], item.type), bits); } @@ -1978,9 +2081,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 '(tempDoubleI32[0] = ' + idents[0] + ',tempDoubleF32[0])'; + return '(HEAP32[tempDoublePtr>>2] = ' + idents[0] + ',HEAPF32[tempDoublePtr>>2])'; } else { - return '(tempDoubleF32[0] = ' + idents[0] + ',tempDoubleI32[0])'; + return '(HEAPF32[tempDoublePtr>>2] = ' + idents[0] + ',HEAP32[tempDoublePtr>>2])'; } } return idents[0]; |