diff options
author | Alon Zakai <alonzakai@gmail.com> | 2011-04-18 17:43:43 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2011-04-18 17:43:43 -0700 |
commit | 46e3b2a78717b112254be5f6e8cbd1fad6ab1703 (patch) | |
tree | 6c2d8966086d72e632eb37ed313d1f3c0a939e7d /src | |
parent | f89d9e2be63cbc3d4984dc748dac433dc3491fed (diff) |
refactor assertions and parsing code
Diffstat (limited to 'src')
-rw-r--r-- | src/jsifier.js | 255 | ||||
-rw-r--r-- | src/parseTools.js | 262 | ||||
-rw-r--r-- | src/runtime.js | 6 | ||||
-rw-r--r-- | src/settings.js | 11 | ||||
-rw-r--r-- | src/utility.js | 10 |
5 files changed, 283 insertions, 261 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index f185cbd2..09a29656 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -385,7 +385,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { first = false; }); } - if (GUARD_LABELS) { + if (ASSERTIONS) { ret += indent + multipleIdent + 'else { throw "Bad multiple branching: " + __label__ + " : " + (new Error().stack); }\n'; } if (!block.loopless) { @@ -654,258 +654,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { return makeOne(0); }); - function makeSignOp(value, type, op) { // TODO: If value isNumber, do this at compile time - if (!value) return value; - if (!correctSigns() && !CHECK_SIGNS) return value; - if (type in Runtime.INT_TYPES) { - var bits = parseInt(type.substr(1)); - if (isNumber(value)) { - // Sign/unsign constants at compile time - return eval(op + 'Sign(' + value + ', ' + bits + ', 1)').toString(); - } - // shortcuts for 32-bit case - if (bits === 32 && !CHECK_SIGNS) { - if (op === 're') { - return '((' + value + ')|0)'; - } else { - // TODO: figure out something here along the lines of return '(' + Math.pow(2, 32) + '+((' + value + ')|0))'; - } - } - return op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(correctSpecificSign()) + ')'; // If we are correcting a specific sign here, do not check for it - } else { - return value; - } - } - - function handleOverflow(text, bits) { - if (!bits) return text; - if (bits <= 32 && correctOverflows()) text = '(' + text + ')&' + (Math.pow(2, bits) - 1); - if (!CHECK_OVERFLOWS || correctSpecificOverflow()) return text; // If we are correcting a specific overflow here, do not check for it - return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')'; - } - - function makeRounding(value, bits, signed) { - // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that. - // With 32 bits and less, and a signed value, |0 will round it like C does. - if (bits && bits <= 32 && signed) return '('+value+'|0)'; - // If the value may be negative, and we care about proper rounding, then use a slow but correct function - if (signed && correctRoundings()) return 'cRound(' + value + ')'; - // Either this must be positive, so Math.Floor is correct, or we don't care - return 'Math.floor(' + value + ')'; - } - - var mathop = makeFuncLineActor('mathop', function(item) { with(item) { - for (var i = 1; i <= 4; i++) { - if (item['param'+i]) { - item['ident'+i] = indexizeFunctions(finalizeLLVMParameter(item['param'+i])); - if (!isNumber(item['ident'+i])) { - item['ident'+i] = '(' + item['ident'+i] + ')'; // we may have nested expressions. So enforce the order of operations we want - } - } else { - item['ident'+i] = null; // just so it exists for purposes of reading ident2 etc. later on, and no exception is thrown - } - } - if (op in set('udiv', 'urem', 'uitofp', 'zext', 'lshr') || (variant && variant[0] == 'u')) { - ident1 = makeSignOp(ident1, type, 'un'); - ident2 = makeSignOp(ident2, type, 'un'); - } else if (op in set('sdiv', 'srem', 'sitofp', 'sext', 'ashr') || (variant && variant[0] == 's')) { - ident1 = makeSignOp(ident1, type, 're'); - ident2 = makeSignOp(ident2, type, 're'); - } - var bits = null; - if (item.type[0] === 'i') { - bits = parseInt(item.type.substr(1)); - } - var bitsLeft = ident2 ? ident2.substr(2, ident2.length-3) : null; // remove (i and ), to leave number. This value is important in float ops - - switch (op) { - // basic integer ops - case 'add': return handleOverflow(ident1 + ' + ' + ident2, bits); - case 'sub': return handleOverflow(ident1 + ' - ' + ident2, bits); - case 'sdiv': case 'udiv': return makeRounding(ident1 + '/' + ident2, bits, op[0] === 's'); - case 'mul': return handleOverflow(ident1 + ' * ' + ident2, bits); - case 'urem': case 'srem': return ident1 + ' % ' + ident2; - case 'or': return ident1 + ' | ' + ident2; // TODO this forces into a 32-bit int - add overflow-style checks? also other bitops below us - case 'and': return ident1 + ' & ' + ident2; - case 'xor': return ident1 + ' ^ ' + ident2; - case 'shl': { - // Note: Increases in size may reach the 32-bit limit... where our sign can flip. But this may be expected by the code... - /* - if (bits >= 32) { - if (CHECK_SIGNS && !CORRECT_SIGNS) return 'shlSignCheck(' + ident1 + ', ' + ident2 + ')'; - if (CORRECT_SIGNS) { - var mul = 'Math.pow(2, ' + ident2 + ')'; - if (isNumber(ident2)) mul = eval(mul); - return ident1 + ' * ' + mul; - } - } - */ - return ident1 + ' << ' + ident2; - } - case 'ashr': return ident1 + ' >> ' + ident2; - case 'lshr': return ident1 + ' >>> ' + ident2; - // basic float ops - case 'fadd': return ident1 + ' + ' + ident2; - case 'fsub': return ident1 + ' - ' + ident2; - case 'fdiv': return ident1 + ' / ' + ident2; - case 'fmul': return ident1 + ' * ' + ident2; - case 'uitofp': case 'sitofp': return ident1; - case 'fptoui': case 'fptosi': return makeRounding(ident1, bitsLeft, op === 'fptosi'); - - // TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking - // Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs. - case 'icmp': { - switch (variant) { - case 'uge': case 'sge': return ident1 + ' >= ' + ident2; - case 'ule': case 'sle': return ident1 + ' <= ' + ident2; - case 'ugt': case 'sgt': return ident1 + ' > ' + ident2; - case 'ult': case 'slt': return ident1 + ' < ' + ident2; - // We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp - case 'ne': case 'eq': { - // We must sign them, so we do not compare -1 to 255 (could have unsigned them both too) - // since LLVM tells us if <=, >= etc. comparisons are signed, but not == and !=. - ident1 = makeSignOp(ident1, type, 're'); - ident2 = makeSignOp(ident2, type, 're'); - return ident1 + (variant === 'eq' ? '==' : '!=') + ident2; - } - default: throw 'Unknown icmp variant: ' + variant; - } - } - case 'fcmp': { - switch (variant) { - // TODO 'o' ones should be 'ordered (no NaN) and', - // 'u' ones should be 'unordered or'. - case 'uge': case 'oge': return ident1 + ' >= ' + ident2; - case 'ule': case 'ole': return ident1 + ' <= ' + ident2; - case 'ugt': case 'ogt': return ident1 + ' > ' + ident2; - case 'ult': case 'olt': return ident1 + ' < ' + ident2; - case 'une': case 'one': return ident1 + ' != ' + ident2; - case 'ueq': case 'oeq': return ident1 + ' == ' + ident2; - case 'ord': return '!isNaN(' + ident1 + ') && !isNaN(' + ident2 + ')'; - case 'uno': return 'isNaN(' + ident1 + ') || isNaN(' + ident2 + ')'; - case 'true': return '1'; - default: throw 'Unknown fcmp variant: ' + variant; - } - } - // Note that zext has sign checking, see above. We must guard against -33 in i8 turning into -33 in i32 - // then unsigning that i32... which would give something huge. - case 'zext': case 'fpext': case 'sext': return ident1; - case 'fptrunc': return ident1; - case 'trunc': { - // Unlike extending, which we just 'do' (by doing nothing), - // truncating can change the number, e.g. by truncating to an i1 - // in order to get the first bit - assert(ident2[1] == 'i'); - assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op'); - return '((' + ident1 + ') & ' + (Math.pow(2, bitsLeft)-1) + ')'; - } - case 'select': return ident1 + ' ? ' + ident2 + ' : ' + ident3; - case 'ptrtoint': return ident1; - case 'inttoptr': return ident1; - default: throw 'Unknown mathcmp op: ' + item.op; - } - } }); - - function getGetElementPtrIndexes(item) { - var type = item.params[0].type; - item.params = item.params.map(finalizeLLVMParameter); - var ident = item.params[0]; - - // struct pointer, struct*, and getting a ptr to an element in that struct. Param 1 is which struct, then we have items in that - // 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 offset = item.params[1]; - if (offset != 0) { - if (isStructType(type)) { - indexes.push(getFastValue(Types.types[type].flatSize, '*', offset)); - } else { - indexes.push(getFastValue(getNativeFieldSize(type, true), '*', offset)); - } - } - item.params.slice(2, item.params.length).forEach(function(arg) { - var curr = arg; - // TODO: If index is constant, optimize - var typeData = Types.types[type]; - if (isStructType(type) && typeData.needsFlattening) { - if (typeData.flatFactor) { - indexes.push(getFastValue(curr, '*', typeData.flatFactor)); - } else { - if (isNumber(curr)) { - indexes.push(typeData.flatIndexes[curr]); - } else { - indexes.push(toNiceIdent(type) + '___FLATTENER[' + curr + ']'); // TODO: If curr is constant, optimize out the flattener struct - } - } - } else { - if (curr != 0) { - indexes.push(curr); - } - } - if (!isNumber(curr) || parseInt(curr) < 0) { - // We have a *variable* to index with, or a negative number. In both - // cases, in theory we might need to do something dynamic here. FIXME? - // But, most likely all the possible types are the same, so do that case here now... - for (var i = 1; i < typeData.fields.length; i++) { - assert(typeData.fields[0] === typeData.fields[i]); - } - curr = 0; - } - type = typeData ? typeData.fields[curr] : ''; - }); - var ret = indexes[0]; - for (var i = 1; i < indexes.length; i++) { - ret = getFastValue(ret, '+', indexes[i]); - } - - ret = handleOverflow(ret, 32); // XXX - we assume a 32-bit arch here. If you fail on this, change to 64 - - return ret; - } - - function finalizeLLVMFunctionCall(item) { - switch(item.intertype) { - case 'getelementptr': - return makePointer(makeGetSlabs(item.ident, item.type)[0], getGetElementPtrIndexes(item), null, item.type); - case 'bitcast': - case 'inttoptr': - case 'ptrtoint': - return finalizeLLVMParameter(item.params[0]); - case 'icmp': case 'mul': case 'zext': case 'add': case 'sub': case 'div': - var temp = { - op: item.intertype, - variant: item.variant, - type: item.type - }; - for (var i = 1; i <= 4; i++) { - if (item.params[i-1]) { - temp['param' + i] = finalizeLLVMParameter(item.params[i-1]); - } - } - mathop.processItem(temp); - return temp.JS; - default: - throw 'Invalid function to finalize: ' + dump(item.intertype); - } - } - - // From parseLLVMSegment - function finalizeLLVMParameter(param) { - if (isNumber(param)) { - return param; - } else if (typeof param === 'string') { - return toNiceIdentCarefully(param); - } else if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { - return finalizeLLVMFunctionCall(param); - } else if (param.intertype == 'value') { - return parseNumerical(param.ident); - } else if (param.intertype == 'structvalue') { - return param.values.map(finalizeLLVMParameter); - } else { - throw 'invalid llvm parameter: ' + param.intertype; - } - } + makeFuncLineActor('mathop', processMathop); makeFuncLineActor('bitcast', function(item) { var ident = toNiceIdent(item.ident); diff --git a/src/parseTools.js b/src/parseTools.js index 5954749a..fde8e703 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -307,6 +307,16 @@ function parseParamTokens(params) { return ret; } +function finalizeParam(param) { + if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { + return finalizeLLVMFunctionCall(param); + } else if (param.intertype === 'jsvalue') { + return param.ident; + } else { + return toNiceIdent(param.ident); + } +} + // Segment ==> Parameter function parseLLVMSegment(segment) { var type; @@ -715,3 +725,255 @@ function makeGetSlabs(ptr, type, allowMultiple) { } } +function finalizeLLVMFunctionCall(item) { + switch(item.intertype) { + case 'getelementptr': // TODO finalizeLLVMParameter on the ident and the indexes? + return makePointer(makeGetSlabs(item.ident, item.type)[0], getGetElementPtrIndexes(item), null, item.type); + case 'bitcast': + case 'inttoptr': + case 'ptrtoint': + return finalizeLLVMParameter(item.params[0]); + case 'icmp': case 'mul': case 'zext': case 'add': case 'sub': case 'div': + var temp = { + op: item.intertype, + variant: item.variant, + type: item.type + }; + for (var i = 1; i <= 4; i++) { + if (item.params[i-1]) { + temp['param' + i] = finalizeLLVMParameter(item.params[i-1]); + } + } + return processMathop(temp); + default: + throw 'Invalid function to finalize: ' + dump(item.intertype); + } +} + +function getGetElementPtrIndexes(item) { + var type = item.params[0].type; + item.params = item.params.map(finalizeLLVMParameter); + var ident = item.params[0]; + + // struct pointer, struct*, and getting a ptr to an element in that struct. Param 1 is which struct, then we have items in that + // 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 offset = item.params[1]; + if (offset != 0) { + if (isStructType(type)) { + indexes.push(getFastValue(Types.types[type].flatSize, '*', offset)); + } else { + indexes.push(getFastValue(getNativeFieldSize(type, true), '*', offset)); + } + } + item.params.slice(2, item.params.length).forEach(function(arg) { + var curr = arg; + // TODO: If index is constant, optimize + var typeData = Types.types[type]; + if (isStructType(type) && typeData.needsFlattening) { + if (typeData.flatFactor) { + indexes.push(getFastValue(curr, '*', typeData.flatFactor)); + } else { + if (isNumber(curr)) { + indexes.push(typeData.flatIndexes[curr]); + } else { + indexes.push(toNiceIdent(type) + '___FLATTENER[' + curr + ']'); // TODO: If curr is constant, optimize out the flattener struct + } + } + } else { + if (curr != 0) { + indexes.push(curr); + } + } + if (!isNumber(curr) || parseInt(curr) < 0) { + // We have a *variable* to index with, or a negative number. In both + // cases, in theory we might need to do something dynamic here. FIXME? + // But, most likely all the possible types are the same, so do that case here now... + for (var i = 1; i < typeData.fields.length; i++) { + assert(typeData.fields[0] === typeData.fields[i]); + } + curr = 0; + } + type = typeData ? typeData.fields[curr] : ''; + }); + var ret = indexes[0]; + for (var i = 1; i < indexes.length; i++) { + ret = getFastValue(ret, '+', indexes[i]); + } + + ret = handleOverflow(ret, 32); // XXX - we assume a 32-bit arch here. If you fail on this, change to 64 + + return ret; +} + +function handleOverflow(text, bits) { + if (!bits) return text; + if (bits <= 32 && correctOverflows()) text = '(' + text + ')&' + (Math.pow(2, bits) - 1); + if (!CHECK_OVERFLOWS || correctSpecificOverflow()) return text; // If we are correcting a specific overflow here, do not check for it + return 'CHECK_OVERFLOW(' + text + ', ' + bits + ')'; +} + +// From parseLLVMSegment +function finalizeLLVMParameter(param) { + if (isNumber(param)) { + return param; + } else if (typeof param === 'string') { + return toNiceIdentCarefully(param); + } else if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { + return finalizeLLVMFunctionCall(param); + } else if (param.intertype == 'value') { + return parseNumerical(param.ident); + } else if (param.intertype == 'structvalue') { + return param.values.map(finalizeLLVMParameter); + } else { + throw 'invalid llvm parameter: ' + param.intertype; + } +} + +function makeSignOp(value, type, op) { // TODO: If value isNumber, do this at compile time + if (!value) return value; + if (!correctSigns() && !CHECK_SIGNS) return value; + if (type in Runtime.INT_TYPES) { + var bits = parseInt(type.substr(1)); + if (isNumber(value)) { + // Sign/unsign constants at compile time + return eval(op + 'Sign(' + value + ', ' + bits + ', 1)').toString(); + } + // shortcuts for 32-bit case + if (bits === 32 && !CHECK_SIGNS) { + if (op === 're') { + return '((' + value + ')|0)'; + } else { + // TODO: figure out something here along the lines of return '(' + Math.pow(2, 32) + '+((' + value + ')|0))'; + } + } + return op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(correctSpecificSign()) + ')'; // If we are correcting a specific sign here, do not check for it + } else { + return value; + } +} + +function makeRounding(value, bits, signed) { + // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that. + // With 32 bits and less, and a signed value, |0 will round it like C does. + if (bits && bits <= 32 && signed) return '('+value+'|0)'; + // If the value may be negative, and we care about proper rounding, then use a slow but correct function + if (signed && correctRoundings()) return 'cRound(' + value + ')'; + // Either this must be positive, so Math.Floor is correct, or we don't care + return 'Math.floor(' + value + ')'; +} + +function processMathop(item) { with(item) { + for (var i = 1; i <= 4; i++) { + if (item['param'+i]) { + item['ident'+i] = indexizeFunctions(finalizeLLVMParameter(item['param'+i])); + if (!isNumber(item['ident'+i])) { + item['ident'+i] = '(' + item['ident'+i] + ')'; // we may have nested expressions. So enforce the order of operations we want + } + } else { + item['ident'+i] = null; // just so it exists for purposes of reading ident2 etc. later on, and no exception is thrown + } + } + if (op in set('udiv', 'urem', 'uitofp', 'zext', 'lshr') || (variant && variant[0] == 'u')) { + ident1 = makeSignOp(ident1, type, 'un'); + ident2 = makeSignOp(ident2, type, 'un'); + } else if (op in set('sdiv', 'srem', 'sitofp', 'sext', 'ashr') || (variant && variant[0] == 's')) { + ident1 = makeSignOp(ident1, type, 're'); + ident2 = makeSignOp(ident2, type, 're'); + } + var bits = null; + if (item.type[0] === 'i') { + bits = parseInt(item.type.substr(1)); + } + var bitsLeft = ident2 ? ident2.substr(2, ident2.length-3) : null; // remove (i and ), to leave number. This value is important in float ops + + switch (op) { + // basic integer ops + case 'add': return handleOverflow(ident1 + ' + ' + ident2, bits); + case 'sub': return handleOverflow(ident1 + ' - ' + ident2, bits); + case 'sdiv': case 'udiv': return makeRounding(ident1 + '/' + ident2, bits, op[0] === 's'); + case 'mul': return handleOverflow(ident1 + ' * ' + ident2, bits); + case 'urem': case 'srem': return ident1 + ' % ' + ident2; + case 'or': return ident1 + ' | ' + ident2; // TODO this forces into a 32-bit int - add overflow-style checks? also other bitops below us + case 'and': return ident1 + ' & ' + ident2; + case 'xor': return ident1 + ' ^ ' + ident2; + case 'shl': { + // Note: Increases in size may reach the 32-bit limit... where our sign can flip. But this may be expected by the code... + /* + if (bits >= 32) { + if (CHECK_SIGNS && !CORRECT_SIGNS) return 'shlSignCheck(' + ident1 + ', ' + ident2 + ')'; + if (CORRECT_SIGNS) { + var mul = 'Math.pow(2, ' + ident2 + ')'; + if (isNumber(ident2)) mul = eval(mul); + return ident1 + ' * ' + mul; + } + } + */ + return ident1 + ' << ' + ident2; + } + case 'ashr': return ident1 + ' >> ' + ident2; + case 'lshr': return ident1 + ' >>> ' + ident2; + // basic float ops + case 'fadd': return ident1 + ' + ' + ident2; + case 'fsub': return ident1 + ' - ' + ident2; + case 'fdiv': return ident1 + ' / ' + ident2; + case 'fmul': return ident1 + ' * ' + ident2; + case 'uitofp': case 'sitofp': return ident1; + case 'fptoui': case 'fptosi': return makeRounding(ident1, bitsLeft, op === 'fptosi'); + + // TODO: We sometimes generate false instead of 0, etc., in the *cmps. It seemed slightly faster before, but worth rechecking + // Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs. + case 'icmp': { + switch (variant) { + case 'uge': case 'sge': return ident1 + ' >= ' + ident2; + case 'ule': case 'sle': return ident1 + ' <= ' + ident2; + case 'ugt': case 'sgt': return ident1 + ' > ' + ident2; + case 'ult': case 'slt': return ident1 + ' < ' + ident2; + // We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp + case 'ne': case 'eq': { + // We must sign them, so we do not compare -1 to 255 (could have unsigned them both too) + // since LLVM tells us if <=, >= etc. comparisons are signed, but not == and !=. + ident1 = makeSignOp(ident1, type, 're'); + ident2 = makeSignOp(ident2, type, 're'); + return ident1 + (variant === 'eq' ? '==' : '!=') + ident2; + } + default: throw 'Unknown icmp variant: ' + variant; + } + } + case 'fcmp': { + switch (variant) { + // TODO 'o' ones should be 'ordered (no NaN) and', + // 'u' ones should be 'unordered or'. + case 'uge': case 'oge': return ident1 + ' >= ' + ident2; + case 'ule': case 'ole': return ident1 + ' <= ' + ident2; + case 'ugt': case 'ogt': return ident1 + ' > ' + ident2; + case 'ult': case 'olt': return ident1 + ' < ' + ident2; + case 'une': case 'one': return ident1 + ' != ' + ident2; + case 'ueq': case 'oeq': return ident1 + ' == ' + ident2; + case 'ord': return '!isNaN(' + ident1 + ') && !isNaN(' + ident2 + ')'; + case 'uno': return 'isNaN(' + ident1 + ') || isNaN(' + ident2 + ')'; + case 'true': return '1'; + default: throw 'Unknown fcmp variant: ' + variant; + } + } + // Note that zext has sign checking, see above. We must guard against -33 in i8 turning into -33 in i32 + // then unsigning that i32... which would give something huge. + case 'zext': case 'fpext': case 'sext': return ident1; + case 'fptrunc': return ident1; + case 'trunc': { + // Unlike extending, which we just 'do' (by doing nothing), + // truncating can change the number, e.g. by truncating to an i1 + // in order to get the first bit + assert(ident2[1] == 'i'); + assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op'); + return '((' + ident1 + ') & ' + (Math.pow(2, bitsLeft)-1) + ')'; + } + case 'select': return ident1 + ' ? ' + ident2 + ' : ' + ident3; + case 'ptrtoint': return ident1; + case 'inttoptr': return ident1; + default: throw 'Unknown mathcmp op: ' + item.op; + } +} } + diff --git a/src/runtime.js b/src/runtime.js index 6c3d630c..10aab3c9 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -7,7 +7,7 @@ RuntimeGenerator = { alloc: function(size, type, init) { var ret = type + 'TOP'; - if (GUARD_MEMORY) { + if (ASSERTIONS) { ret += '; assert(' + size + ' > 0, "Trying to allocate 0")'; } if (init) { @@ -23,7 +23,7 @@ RuntimeGenerator = { // An allocation that lives as long as the current function call stackAlloc: function(size) { var ret = RuntimeGenerator.alloc(size, 'STACK', INIT_STACK); - if (GUARD_MEMORY) { + if (ASSERTIONS) { ret += '; assert(STACKTOP < STACK_ROOT + STACK_MAX, "Ran out of stack")'; } return ret; @@ -35,7 +35,7 @@ RuntimeGenerator = { // until the parent unwinds its stack. So potentially if we are in // a loop, we can use a lot of memory. var ret = 'var __stackBase__ = STACKTOP; STACKTOP += ' + initial; - if (GUARD_MEMORY) { + if (ASSERTIONS) { ret += '; assert(STACKTOP < STACK_MAX)'; } if (INIT_STACK) { diff --git a/src/settings.js b/src/settings.js index a93d9183..fc86edcf 100644 --- a/src/settings.js +++ b/src/settings.js @@ -23,11 +23,12 @@ CHECK_SIGNS = 0; // Runtime errors for signing issues that need correcting. // order to find if your code needs CORRECT_SIGNS. If you can get your // code to run without CORRECT_SIGNS, it will run much faster -GUARD_LABELS = 0; // Whether we should throw if we encounter a bad __label__, i.e., - // if code flow runs into a fault -GUARD_MEMORY = 1; // Whether we should check that each allocation to the stack does not - // exceed it's size, whether all allocations (stack and static) are - // of positive size, etc. +ASSERTIONS = 1; // Whether we should add runtime assertions, for example to + // check that each allocation to the stack does not + // exceed it's size, whether all allocations (stack and static) are + // of positive size, etc., whether we should throw if we encounter a bad __label__, i.e., + // if code flow runs into a fault + 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 INIT_STACK = 1; // Whether to initialize memory on the stack to 0. diff --git a/src/utility.js b/src/utility.js index f0d8e37e..64d9011a 100644 --- a/src/utility.js +++ b/src/utility.js @@ -62,6 +62,12 @@ function assertTrue(a, msg) { } assert = assertTrue; +function warn(a, msg) { + if (!a) { + dprint('Warning: ' + msg); + } +} + function dedup(items, ident) { var seen = {}; if (ident) { @@ -226,3 +232,7 @@ function setIntersect(x, y) { return ret; } +function copy(x) { + return JSON.parse(JSON.stringify(x)); +} + |