diff options
Diffstat (limited to 'src/parseTools.js')
| -rw-r--r-- | src/parseTools.js | 211 | 
1 files changed, 122 insertions, 89 deletions
| diff --git a/src/parseTools.js b/src/parseTools.js index 2ccf0179..7ebc0de2 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -111,12 +111,22 @@ function isNiceIdent(ident, loose) {  }  function isJSVar(ident) { -  return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident); - +  if (ident[0] === '(') { +    if (ident[ident.length-1] !== ')') return false; +    ident = ident.substr(1, ident.length-2); +  } +  return /^[$_]?[\w$_\d]* *$/.test(ident);  }  function isLocalVar(ident) { -  return ident[0] == '$'; +  return ident[0] === '$'; +} + +// Simple variables or numbers, or things already quoted, do not need to be quoted +function needsQuoting(ident) { +  if (/^[-+]?[$_]?[\w$_\d]*$/.test(ident)) return false; // number or variable +  if (ident[0] === '(' && ident[ident.length-1] === ')' && ident.indexOf('(', 1) < 0) return false; // already fully quoted +  return true;  }  function isStructPointerType(type) { @@ -933,12 +943,12 @@ function parseLLVMString(str) {    var ret = [];    var i = 0;    while (i < str.length) { -    var chr = str[i]; -    if (chr != '\\') { -      ret.push(chr.charCodeAt(0)); +    var chr = str.charCodeAt(i); +    if (chr !== 92) { // 92 === '//'.charCodeAt(0) +      ret.push(chr);        i++;      } else { -      ret.push(eval('0x' + str[i+1]+str[i+2])); +      ret.push(parseInt(str[i+1]+str[i+2], '16'));        i += 3;      }    } @@ -1197,7 +1207,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa      var typeData = Types.types[type];      var ret = [];      for (var i = 0; i < typeData.fields.length; i++) { -      ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned)); +      ret.push('f' + i + ': ' + makeGetValue(ptr, pos + typeData.flatIndexes[i], typeData.fields[i], noNeedFirst, unsigned, 0, 0, noSafe));      }      return '{ ' + ret.join(', ') + ' }';    } @@ -1205,8 +1215,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa    // In double mode 1, in x86 we always assume unaligned because we can't trust that; otherwise in le32    // we need this code path if we are not fully aligned.    if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double' && (TARGET_X86 || align < 8)) { -    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)) + ',' + +    return '(' + makeSetTempDouble(0, 'i32', makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' + +                 makeSetTempDouble(1, 'i32', makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align, noSafe)) + ',' +              makeGetTempDouble(0, 'double') + ')';    } @@ -1219,12 +1229,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa        if (isIntImplemented(type)) {          if (bytes == 4 && align == 2) {            // Special case that we can optimize -          ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore) + '|' + -                 '(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore) + '<<16)'; +          ret += makeGetValue(ptr, pos, 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '|' + +                 '(' + makeGetValue(ptr, getFastValue(pos, '+', 2), 'i16', noNeedFirst, 2, ignore, 2, noSafe) + '<<16)';          } else { // XXX we cannot truly handle > 4... (in x86)            ret = '';            for (var i = 0; i < bytes; i++) { -            ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore) + (i > 0 ? '<<' + (8*i) : '') + ')'; +            ret += '(' + makeGetValue(ptr, getFastValue(pos, '+', i), 'i8', noNeedFirst, 1, ignore, 1, noSafe) + (i > 0 ? '<<' + (8*i) : '') + ')';              if (i < bytes-1) ret += '|';            }            ret = '(' + makeSignOp(ret, type, unsigned ? 'un' : 're', true); @@ -1303,7 +1313,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,        value = range(typeData.fields.length).map(function(i) { return value + '.f' + i });      }      for (var i = 0; i < typeData.fields.length; i++) { -      ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst)); +      ret.push(makeSetValue(ptr, getFastValue(pos, '+', typeData.flatIndexes[i]), value[i], typeData.fields[i], noNeedFirst, 0, 0, noSafe));      }      return ret.join('; ');    } @@ -1330,17 +1340,17 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,          if (bytes == 4 && align == 2) {            // Special case that we can optimize            ret += 'tempBigInt=' + value + sep; -          ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2) + sep; -          ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2); +          ret += makeSetValue(ptr, pos, 'tempBigInt&0xffff', 'i16', noNeedFirst, ignore, 2, noSafe) + sep; +          ret += makeSetValue(ptr, getFastValue(pos, '+', 2), 'tempBigInt>>16', 'i16', noNeedFirst, ignore, 2, noSafe);          } else {            ret += 'tempBigInt=' + value + sep;            for (var i = 0; i < bytes; i++) { -            ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1); +            ret += makeSetValue(ptr, getFastValue(pos, '+', i), 'tempBigInt&0xff', 'i8', noNeedFirst, ignore, 1, noSafe);              if (i < bytes-1) ret += sep + 'tempBigInt = tempBigInt>>8' + sep;            }          }        } else { -        ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, null, null, true) + sep; +        ret += makeSetValue('tempDoublePtr', 0, value, type, noNeedFirst, ignore, 8, noSafe, null, true) + sep;          ret += makeCopyValues(getFastValue(ptr, '+', pos), 'tempDoublePtr', Runtime.getNativeTypeSize(type), type, null, align, sep);        }        return ret; @@ -1349,6 +1359,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,    value = indexizeFunctions(value, type);    var offset = calcFastOffset(ptr, pos, noNeedFirst); +  if (phase === 'pre' && isNumber(offset)) offset += ' '; // avoid pure numeric strings, seem to be perf issues with overly-aggressive interning or slt in pre processing of heap inits    if (SAFE_HEAP && !noSafe) {      var printType = type;      if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; @@ -1465,77 +1476,97 @@ function makeHEAPView(which, start, end) {    return 'HEAP' + which + '.subarray((' + start + ')' + mod + ',(' + end + ')' + mod + ')';  } -var PLUS_MUL = set('+', '*'); -var MUL_DIV = set('*', '/'); -var PLUS_MINUS = set('+', '-');  var TWO_TWENTY = Math.pow(2, 20);  // Given two values and an operation, returns the result of that operation.  // Tries to do as much as possible at compile time.  // Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul  function getFastValue(a, op, b, type) { -  a = a.toString(); -  b = b.toString(); -  a = a == 'true' ? '1' : (a == 'false' ? '0' : a); -  b = b == 'true' ? '1' : (b == 'false' ? '0' : b); -  if (isNumber(a) && isNumber(b)) { -    if (op == 'pow') { -      return Math.pow(a, b).toString(); -    } else { -      var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12" -      if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats -      return value.toString(); +  a = a === 'true' ? '1' : (a === 'false' ? '0' : a); +  b = b === 'true' ? '1' : (b === 'false' ? '0' : b); + +  var aNumber = null, bNumber = null; +  if (typeof a === 'number') { +    aNumber = a; +    a = a.toString(); +  } else if (isNumber(a)) aNumber = parseFloat(a); +  if (typeof b === 'number') { +    bNumber = b; +    b = b.toString(); +  } else if (isNumber(b)) bNumber = parseFloat(b); + +  if (aNumber !== null && bNumber !== null) { +    switch (op) { +      case '+': return (aNumber + bNumber).toString(); +      case '-': return (aNumber - bNumber).toString(); +      case '*': return (aNumber * bNumber).toString(); +      case '/': { +        if (type[0] === 'i') { +          return ((aNumber / bNumber)|0).toString(); +        } else { +          return (aNumber / bNumber).toString(); +        } +      } +      case '%': return (aNumber % bNumber).toString(); +      case '|': return (aNumber | bNumber).toString(); +      case '>>>': return (aNumber >>> bNumber).toString(); +      case '&': return (aNumber & bNumber).toString(); +      case 'pow': return Math.pow(aNumber, bNumber).toString(); +      default: throw 'need to implement getFastValue pn ' + op;      }    } -  if (op == 'pow') { -    if (a == '2' && isIntImplemented(type)) { +  if (op === 'pow') { +    if (a === '2' && isIntImplemented(type)) {        return '(1 << (' + b + '))';      }      return 'Math.pow(' + a + ', ' + b + ')';    } -  if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last +  if ((op === '+' || op === '*') && aNumber !== null) { // if one of them is a number, keep it last      var c = b;      b = a;      a = c; -  } -  if (op in MUL_DIV) { -    if (op == '*') { -      if (a == 0 || b == 0) { -        return '0'; -      } else if (a == 1) { -        return b; -      } else if (b == 1) { -        return a; -      } else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) { -        var shifts = Math.log(parseFloat(b))/Math.LN2; -        if (shifts % 1 == 0) { -          return '(' + a + '<<' + shifts + ')'; -        } +    var cNumber = bNumber; +    bNumber = aNumber; +    aNumber = cNumber; +  } +  if (op === '*') { +    // We can't eliminate where a or b are 0 as that would break things for creating +    // a negative 0. +    if ((aNumber === 0 || bNumber === 0) && !(type in Runtime.FLOAT_TYPES)) { +      return '0'; +    } else if (aNumber === 1) { +      return b; +    } else if (bNumber === 1) { +      return a; +    } else if (bNumber !== null && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) { +      var shifts = Math.log(bNumber)/Math.LN2; +      if (shifts % 1 === 0) { +        return '(' + a + '<<' + shifts + ')';        } -      if (!(type in Runtime.FLOAT_TYPES)) { -        // if guaranteed small enough to not overflow into a double, do a normal multiply -        var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes -        // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there -        if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { -          return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this -        } -        return '(Math.imul(' + a + ',' + b + ')|0)'; +    } +    if (!(type in Runtime.FLOAT_TYPES)) { +      // if guaranteed small enough to not overflow into a double, do a normal multiply +      var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes +      // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there +      if ((aNumber !== null && Math.abs(a) < TWO_TWENTY) || (bNumber !== null && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) { +        return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this        } -    } else { -      if (a == '0') { -        return '0'; -      } else if (b == 1) { -        return a; -      } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky -    } -  } else if (op in PLUS_MINUS) { -    if (b[0] == '-') { -      op = op == '+' ? '-' : '+'; +      return '(Math.imul(' + a + ',' + b + ')|0)'; +    } +  } else if (op === '/') { +    if (a === '0' && !(type in Runtime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0 +      return '0'; +    } else if (b === 1) { +      return a; +    } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky +  } else if (op === '+' || op === '-') { +    if (b[0] === '-') { +      op = op === '+' ? '-' : '+';        b = b.substr(1);      } -    if (a == 0) { -      return op == '+' ? b : '(-' + b + ')'; -    } else if (b == 0) { +    if (aNumber === 0) { +      return op === '+' ? b : '(-' + b + ')'; +    } else if (bNumber === 0) {        return a;      }    } @@ -1564,12 +1595,8 @@ function getFastValues(list, op, type) {  }  function calcFastOffset(ptr, pos, noNeedFirst) { -  var offset = noNeedFirst ? '0' : makeGetPos(ptr); -  return getFastValue(offset, '+', pos, 'i32'); -} - -function makeGetPos(ptr) { -  return ptr; +  assert(!noNeedFirst); +  return getFastValue(ptr, '+', pos, 'i32');  }  var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); @@ -1759,7 +1786,7 @@ function checkBitcast(item) {        } else {          warnOnce('Casting a function pointer type to a potentially incompatible one (use -s VERBOSE=1 to see more)');        } -      warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidlinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts'); +      warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidelinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts');        if (ASM_JS) warnOnce('Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these');      }      if (oldCount != newCount && oldCount && newCount) showWarning(); @@ -1806,7 +1833,7 @@ function getGetElementPtrIndexes(item) {    // struct, and possibly further substructures, all embedded    // can also be to 'blocks': [8 x i32]*, not just structs    type = removePointing(type); -  var indexes = [makeGetPos(ident)]; +  var indexes = [ident];    var offset = item.params[1];    if (offset != 0) {      if (isStructType(type)) { @@ -1961,13 +1988,12 @@ function makeSignOp(value, type, op, force, ignore) {    if (USE_TYPED_ARRAYS == 2 && type == 'i64') {      return value; // these are always assumed to be two 32-bit unsigneds.    } -    if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints    if (!value) return value;    var bits, full;    if (type in Runtime.INT_TYPES) {      bits = parseInt(type.substr(1)); -    full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')'; +    full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || correctSpecificSign()) + ')';      // Always sign/unsign constants at compile time, regardless of CHECK/CORRECT      if (isNumber(value)) {        return eval(full).toString(); @@ -1975,23 +2001,25 @@ function makeSignOp(value, type, op, force, ignore) {    }    if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value;    if (type in Runtime.INT_TYPES) { +    // this is an integer, but not a number (or we would have already handled it)      // shortcuts      if (!CHECK_SIGNS || ignore) { +      if (value === 'true') { +        value = '1'; +      } else if (value === 'false') { +        value = '0'; +      } else if (needsQuoting(value)) value = '(' + value + ')';        if (bits === 32) {          if (op === 're') { -          return '(' + getFastValue(value, '|', '0') + ')'; +          return '(' + value + '|0)';          } else { - -          return '(' + getFastValue(value, '>>>', '0') + ')'; -          // Alternatively, we can consider the lengthier -          //    return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt'); -          // which does not always turn us into a 32-bit *un*signed value +          return '(' + value +  '>>>0)';          }        } else if (bits < 32) {          if (op === 're') { -          return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt'); +          return '((' + value + '<<' + (32-bits) + ')>>' + (32-bits) + ')';          } else { -          return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')'; +          return '(' + value + '&' + (Math.pow(2, bits)-1) + ')';          }        } else { // bits > 32          if (op === 're') { @@ -2081,7 +2109,7 @@ function processMathop(item) {      if (item.params[i]) {        paramTypes[i] = item.params[i].type || type;        idents[i] = finalizeLLVMParameter(item.params[i]); -      if (!isNumber(idents[i]) && !isNiceIdent(idents[i])) { +      if (needsQuoting(idents[i])) {          idents[i] = '(' + idents[i] + ')'; // we may have nested expressions. So enforce the order of operations we want        }      } else { @@ -2520,3 +2548,8 @@ function makePrintChars(s, sep) {    return ret;  } +function parseAlign(text) { // parse ", align \d+" +  if (!text) return QUANTUM_SIZE; +  return parseInt(text.substr(8)); +} + | 
