diff options
-rw-r--r-- | src/intertyper.js | 21 | ||||
-rw-r--r-- | src/jsifier.js | 31 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 60 |
4 files changed, 59 insertions, 55 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 9e3f7f1e..715b6fa4 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -1,6 +1,8 @@ // LLVM assembly => internal intermediate representation, which is ready // to be processed by the later stages. +var tokenizer; // TODO: Clean this up/out + //! @param parseFunctions We parse functions only on later passes, since we do not //! want to parse all of them at once, and have all their //! lines and data in memory at the same time. @@ -92,7 +94,7 @@ function intertyper(data, parseFunctions, baseLineNum) { }; // Line tokenizer - var tokenizer = substrate.addActor('Tokenizer', { + tokenizer = substrate.addActor('Tokenizer', { processItem: function(item, inner) { //assert(item.lineNum != 40000); //if (item.lineNum) print(item.lineNum); @@ -327,7 +329,7 @@ function intertyper(data, parseFunctions, baseLineNum) { // Handle a single segment (after comma separation) function handleSegment(segment) { if (segment[1].text == 'null') { - return { intertype: 'value', value: 0 }; + return { intertype: 'value', value: 0, type: 'i32' }; } else if (segment[1].text == 'zeroinitializer') { return { intertype: 'emptystruct', type: segment[0].text }; } else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) { @@ -339,12 +341,12 @@ function intertyper(data, parseFunctions, baseLineNum) { } else if (segment[1].type && segment[1].type == '[') { return { intertype: 'list', type: segment[0].text, contents: handleSegments(segment[1].item.tokens) }; } else if (segment.length == 2) { - return { intertype: 'value', value: toNiceIdent(segment[1].text) }; + return { intertype: 'value', type: segment[0].text, value: toNiceIdent(segment[1].text) }; } else if (segment[1].text === 'c') { // string var text = segment[2].text; text = text.substr(1, text.length-2); - return { intertype: 'string', text: text }; + return { intertype: 'string', text: text, type: 'i8*' }; } else if (segment[1].text === 'blockaddress') { return parseBlockAddress(segment); } else { @@ -636,15 +638,17 @@ function intertyper(data, parseFunctions, baseLineNum) { processItem: function(item) { item.intertype = 'phi'; item.type = item.tokens[1].text; + var typeToken = [item.tokens[1]]; Types.needAnalysis[item.type] = 0; var last = getTokenIndexByText(item.tokens, ';'); item.params = splitTokenList(item.tokens.slice(2, last)).map(function(segment) { var subSegments = splitTokenList(segment[0].item.tokens); - return { + var ret = { intertype: 'phiparam', label: toNiceIdent(subSegments[1][0].text), - value: parseLLVMSegment(subSegments[0]) + value: parseLLVMSegment(typeToken.concat(subSegments[0])) }; + return ret; }); this.forwardItem(item, 'Reintegrator'); } @@ -675,6 +679,9 @@ function intertyper(data, parseFunctions, baseLineNum) { } else { item.type = item.param1.type; } + for (var i = 1; i <= 4; i++) { + if (item['param'+i]) item['param'+i].type = item.type; // All params have the same type + } Types.needAnalysis[item.type] = 0; this.forwardItem(item, 'Reintegrator'); } @@ -726,7 +733,7 @@ function intertyper(data, parseFunctions, baseLineNum) { return [{ intertype: 'return', type: type, - value: (item.tokens[2] && type !== 'void') ? parseLLVMSegment(item.tokens.slice(2)) : null, + value: (item.tokens[2] && type !== 'void') ? parseLLVMSegment(item.tokens.slice(1)) : null, lineNum: item.lineNum }]; } diff --git a/src/jsifier.js b/src/jsifier.js index 5a92ba52..7784c1ab 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -36,9 +36,6 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { var GLOBAL_VARIABLES = !mainPass ? givenGlobalVariables : data.globalVariables; Functions.currFunctions = !mainPass ? givenFunctions : {}; - if (mainPass) { - Functions.currExternalFunctions = set(data.functionStubs.map(function(item) { return item.ident })); - } // Now that first-pass analysis has completed (so we have basic types, etc.), we can get around to handling unparsedFunctions (!mainPass ? data.functions : data.unparsedFunctions.concat(data.functions)).forEach(function(func) { @@ -127,7 +124,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { if (value.intertype in PARSABLE_LLVM_FUNCTIONS) { return [finalizeLLVMFunctionCall(value)]; } else if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) { - return indexizeFunctions(parseNumerical(value.value)); + return indexizeFunctions(parseNumerical(value.value), type); } else if (value.intertype === 'emptystruct') { return makeEmptyStruct(type); } else if (value.intertype === 'string') { @@ -138,23 +135,26 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { function handleSegments(tokens) { // Handle a single segment (after comma separation) function handleSegment(segment) { + var ret; if (segment.intertype === 'value') { - return segment.value.toString(); + ret = segment.value.toString(); } else if (segment.intertype === 'emptystruct') { - return makeEmptyStruct(segment.type); + ret = makeEmptyStruct(segment.type); } else if (segment.intertype in PARSABLE_LLVM_FUNCTIONS) { - return finalizeLLVMFunctionCall(segment); + ret = finalizeLLVMFunctionCall(segment); } else if (segment.intertype in set('struct', 'list')) { - return alignStruct(handleSegments(segment.contents), segment.type); + ret = alignStruct(handleSegments(segment.contents), segment.type); } else if (segment.intertype === 'string') { - return parseLLVMString(segment.text); // + ' /* ' + text + '*/'; + ret = parseLLVMString(segment.text); // + ' /* ' + text + '*/'; } else if (segment.intertype === 'blockaddress') { - return finalizeBlockAddress(segment); + ret = finalizeBlockAddress(segment); } else { throw 'Invalid segment: ' + dump(segment); } + assert(segment.type, 'Missing type for constant segment: ' + dump(segment)); + return indexizeFunctions(ret, segment.type); }; - return tokens.map(handleSegment).map(indexizeFunctions); + return tokens.map(handleSegment) } return alignStruct(handleSegments(value.contents), type); } @@ -302,7 +302,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { } item.JS = addFromLibrary(shortident); } else { - item.JS = '// stub for ' + item.ident; + item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; } return ret; } @@ -730,6 +730,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { var func = Functions.currFunctions[ident]; var args = []; + var argsTypes = []; var varargs = []; var varargsTypes = []; @@ -737,6 +738,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { var val = finalizeParam(param); if (!func || !func.hasVarArgs || i < func.numParams-1) { // unrecognized functions (like library ones) cannot have varargs args.push(val); + argsTypes.push(param.type); } else { varargs.push(val); varargs = varargs.concat(zeros(getNativeFieldSize(param.type)-1)); @@ -745,8 +747,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { } }); - args = args.map(indexizeFunctions); - varargs = varargs.map(indexizeFunctions); + args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) }); + varargs = varargs.map(function(vararg, i) { return vararg === 0 ? 0 : indexizeFunctions(vararg, varargsTypes[i]) }); + if (func && func.hasVarArgs) { if (varargs.length === 0) { varargs = [0]; diff --git a/src/modules.js b/src/modules.js index f9185725..91758609 100644 --- a/src/modules.js +++ b/src/modules.js @@ -124,8 +124,6 @@ var Types = { var Functions = { // The list of function datas which are being processed in the jsifier, currently currFunctions: [], - // The list of functions that are external'ly defined - currExternalFunctions: [], indexedFunctions: [0, 0], // Start at a non-0 (even, see below) value diff --git a/src/parseTools.js b/src/parseTools.js index fe71ff3b..debfb6da 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -144,11 +144,10 @@ function isFunctionDef(token) { function isFunctionType(type) { var parts = type.split(' '); - if (parts.length != 2) return false; if (pointingLevels(type) !== 1) return false; - var text = removeAllPointing(parts[1]); - var ret = isType(parts[0]) && isFunctionDef({ text: text, item: {tokens: [{text: text.substr(1, text.length-2)}]} }); - return ret; + var text = removeAllPointing(parts.slice(1).join(' ')); + if (!text) return false; + return isType(parts[0]) && isFunctionDef({ text: text, item: tokenizer.processItem({ lineText: text.substr(1, text.length-2) }, true) }); } function isType(type) { // TODO! @@ -346,13 +345,20 @@ function finalizeParam(param) { function parseLLVMSegment(segment) { var type; if (segment.length == 1) { - type = isType(segment[0].text) ? segment[0].text : '?'; - Types.needAnalysis[type] = 0; - return { - intertype: 'value', - ident: toNiceIdent(segment[0].text), - type: type - }; + if (isType(segment[0].text)) { + Types.needAnalysis[segment[0].text] = 0; + return { + intertype: 'type', + ident: toNiceIdent(segment[0].text), + type: segment[0].text + }; + } else { + return { + intertype: 'value', + ident: toNiceIdent(segment[0].text), + type: 'i32' + }; + } } else if (segment[1].type && segment[1].type == '{') { type = segment[0].text; Types.needAnalysis[type] = 0; @@ -694,27 +700,16 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned) { } } -function indexizeFunctions(value) { - if (value in Functions.currFunctions || value in Functions.currExternalFunctions) { +function indexizeFunctions(value, type) { + assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing: ' + [value, type]); + assert(value !== type, 'Type set to value: ' + [value, type]); + if (type && isFunctionType(type) && value[0] === '_') { // checking for _ differentiates from $ (local vars) if (BUILD_AS_SHARED_LIB) { return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')'; } else { return Functions.getIndex(value); } } - if (value && value[0] && value[0] == '_') { - var rootIdent = LibraryManager.getRootIdent(value.slice(1)); - if (!rootIdent) return value; - if (typeof Library[rootIdent] === 'function') { - return Functions.getIndex('_' + rootIdent); - } else if (rootIdent.substr(0, 5) === 'Math.') { - // Library[..] can be a string, in which case we apply that string. There is one - // case where this can be a function: Math.*, since we try to optimize those as much - // as possible. In other words, we don't want to have a wrapper function(x) return Math.sqrt(x). - // If other functions are deemed important as well, we will need to add them here. - return Functions.getIndex(rootIdent); - } - } return value; } @@ -738,7 +733,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore) { return ret.join('; '); } - value = indexizeFunctions(value); + value = indexizeFunctions(value, type); var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; @@ -1046,7 +1041,7 @@ function finalizeLLVMParameter(param) { if (isNumber(param)) { return param; } else if (typeof param === 'string') { - ret = toNiceIdentCarefully(param); + return toNiceIdentCarefully(param); } else if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { ret = finalizeLLVMFunctionCall(param); } else if (param.intertype == 'value') { @@ -1055,10 +1050,13 @@ function finalizeLLVMParameter(param) { ret = param.values.map(finalizeLLVMParameter); } else if (param.intertype === 'blockaddress') { return finalizeBlockAddress(param); + } else if (param.intertype === 'type') { + return param.ident; // we don't really want the type here } else { throw 'invalid llvm parameter: ' + param.intertype; } - return indexizeFunctions(ret); + assert(param.type || (typeof param === 'string' && param.substr(0, 6) === 'CHECK_'), 'Missing type for param: ' + dump(param)); + return indexizeFunctions(ret, param.type); } function makeSignOp(value, type, op) { @@ -1264,8 +1262,6 @@ function processMathop(item) { with(item) { // TODO: Use this in analyzer, possibly also in jsifier function walkInterdata(item, pre, post, obj) { if (!item || !item.intertype) return false; -//print(' walk: ' + [item.lineNum, item.intertype]); -//if (item.intertype === 'value') print(dump(item)); if (pre(item, obj)) return true; var originalObj = obj; if (obj.replaceWith) obj = obj.replaceWith; // allow pre to replace the object we pass to all its children @@ -1283,7 +1279,7 @@ function walkInterdata(item, pre, post, obj) { } function parseBlockAddress(segment) { - return { intertype: 'blockaddress', func: toNiceIdent(segment[2].item.tokens[0].text), label: toNiceIdent(segment[2].item.tokens[2].text) }; + return { intertype: 'blockaddress', func: toNiceIdent(segment[2].item.tokens[0].text), label: toNiceIdent(segment[2].item.tokens[2].text), type: 'i32' }; } function finalizeBlockAddress(param) { |