diff options
author | alon@honor <none@none> | 2010-09-15 21:00:26 -0700 |
---|---|---|
committer | alon@honor <none@none> | 2010-09-15 21:00:26 -0700 |
commit | 9b369c6e57ad1f7a5f47c0198573c89aa9255d22 (patch) | |
tree | 3151804fecc13fd1e6c9edc9e61353af027b7284 /src/parser.js | |
parent | 92fac9b713e3b13e5a77af2e1c89bd75040af550 (diff) |
rewrite enzymatic, compilation is x2.5 faster
Diffstat (limited to 'src/parser.js')
-rw-r--r-- | src/parser.js | 574 |
1 files changed, 283 insertions, 291 deletions
diff --git a/src/parser.js b/src/parser.js index f3ce9a68..0db8460a 100644 --- a/src/parser.js +++ b/src/parser.js @@ -156,6 +156,13 @@ function getTokenIndexByText(tokens, text) { return i; } +function findTokenText(item, text) { + for (var i = 0; i < item.tokens.length; i++) { + if (item.tokens[i].text == text) return i; + } + return -1; +} + // Splits a list of tokens separated by commas. For example, a list of arguments in a function call function splitTokenList(tokens) { if (tokens.length == 0) return []; @@ -173,50 +180,51 @@ function splitTokenList(tokens) { return ret; } -function makeSplitter(parentSlot, parentSlotValue, parentUnrequiredSlot, childSlot, copySlots) { +// Splits an item, with the intent of later reintegration +function splitItem(parent, childSlot, copySlots) { + if (!copySlots) copySlots = []; + if (!parent[childSlot]) parent[childSlot] = {}; + var child = parent[childSlot]; + parent[childSlot] = null; + child.parentUid = parent.__uid__; + child.parentSlot = childSlot; + child.parentLineNum = child.lineNum = parent.lineNum; + copySlots.forEach(function(slot) { child[slot] = parent[slot] }); return { - selectItem: function(item) { return item[parentSlot] == parentSlotValue && !item[parentUnrequiredSlot] && item[childSlot] !== null }, - process: function(parents) { - if (!copySlots) copySlots = []; - var ret = parents.slice(0); - for (var i = 0; i < parents.length; i++) { - var parent = parents[i]; - var child = parent[childSlot]; - parent[childSlot] = null; - child.parentUid = parent.__uid__; - child.parentSlot = childSlot; - child.lineNum = parent.lineNum; // Debugging - copySlots.forEach(function(slot) { child[slot] = parent[slot] }); - ret.push(child); - } - return ret; - }, + parent: parent, + child: child, }; } -function makeCombiner(parentSlot, parentSlotValue, parentUnrequiredSlot, childRequiredSlot, finalizeFunc) { +function makeReintegrator(afterFunc) { + // reintegration - find intermediate representation-parsed items and + // place back in parents TODO: Optimize this code to optimal O(..) return { - select: function(items) { + process: function(items) { var ret = []; - var parents = items.filter(function(item) { return item[parentSlot] == parentSlotValue && !item[parentUnrequiredSlot] }); - for (var i = 0; i < parents.length; i++) { - var parent = parents[i]; - var child = items.filter(function(item) { return item[childRequiredSlot] && item.parentUid === parent.__uid__ })[0]; - if (child) { - ret = ret.concat([parent, child]); + for (var i = 0; i < items.length; i++) { + var found = false; + if (items[i] && items[i].parentSlot) { + var child = items[i]; + for (var j = 0; j < items.length; j++) { + if (items[j] && items[j].lineNum == items[i].parentLineNum) { + var parent = items[j]; + // process the pair + parent[child.parentSlot] = child; + delete child.parentLineNum; + afterFunc.call(this, parent, child); + + items[i] = null; + items[j] = null; + found = true; + break; + } + } } } + this.forwardItems(items.filter(function(item) { return !!item }), this.name_); // next time hopefully return ret; - }, - process: function(items) { - return Zyme.prototype.processPairs(items, function(parent, child) { - parent[child.parentSlot] = child; - delete child.parentUid; - delete child.parentSlot; - finalizeFunc(parent); - return [parent]; - }); - }, + } }; } @@ -273,6 +281,7 @@ function cleanSegment(segment) { // Expects one of the several LVM getelementptr formats: // a qualifier, a type, a null, then an () item with tokens function parseGetElementPtr(segment) { +//print("Parse GTP: " + dump(segment)); segment = segment.slice(0); segment = cleanSegment(segment); assertTrue(['inreg', 'byval'].indexOf(segment[1].text) == -1); @@ -371,24 +380,8 @@ function intertyper(data) { substrate = new Substrate('Intertyper'); - // Input - - substrate.addItem({ - llvmText: data, - }); - - // Tools - - function findTokenText(item, text) { - for (var i = 0; i < item.tokens.length; i++) { - if (item.tokens[i].text == text) return i; - } - return -1; - } - // Line splitter. substrate.addZyme('LineSplitter', { - selectItem: function(item) { return !!item.llvmText; }, processItem: function(item) { var lines = item.llvmText.split('\n'); var ret = []; @@ -412,15 +405,13 @@ function intertyper(data) { } } } - return ret.filter(function(item) { return item.lineText; }); + this.forwardItems(ret.filter(function(item) { return item.lineText; }), 'Tokenizer'); }, }); // Line tokenizer substrate.addZyme('Tokenizer', { - selectItem: function(item) { return item.lineText; }, - processItem: function(item) { - //print("line: " + item.lineText); + processItem: function(item, inner) { var lineText = item.lineText + " "; var tokens = []; var tokenStart = -1; @@ -458,7 +449,7 @@ function intertyper(data) { if (token.text[0] in enclosers) { token.item = that.processItem({ lineText: token.text.substr(1, token.text.length-2) - }); + }, true); token.type = token.text[0]; } if (indent == -1) { @@ -520,29 +511,86 @@ function intertyper(data) { } } } - return [{ + var item = { tokens: tokens, indent: indent, lineNum: item.lineNum, - }]; + }; + if (inner) { + return [item]; + } else { + this.forwardItem(item, 'Triager'); + } + }, + }); + + substrate.addZyme('Triager', { + processItem: function(item) { + function triage() { + if (!item.intertype) { + if (item.tokens[0].text in searchable(';', 'target')) + return '/dev/null'; + if (item.tokens.length >= 3 && item.indent === 0 && item.tokens[1].text == '=') + return 'Global'; + if (item.tokens.length >= 4 && item.indent === 0 && item.tokens[0].text == 'define' && + item.tokens.slice(-1)[0].text == '{') + return 'FuncHeader'; + if (item.tokens.length >= 1 && item.indent === 0 && item.tokens[0].text.substr(-1) == ':') + return 'Label'; + if (item.indent === 2 && item.tokens && item.tokens.length >= 3 && findTokenText(item, '=') >= 0 && + !item.intertype) + return 'Assign'; + if (!item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'load') + return 'Load'; + if (!item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'bitcast') + return 'Bitcast'; + if (!item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'getelementptr') + return 'GEP'; + if (item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'call' && !item.intertype) + return 'Call'; + if (item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'invoke' && !item.intertype) + return 'Invoke'; + if (!item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'alloca') + return 'Alloca'; + if (item.indent === -1 && item.tokens && item.tokens.length >= 3 && + ['add', 'sub', 'sdiv', 'mul', 'icmp', 'zext', 'urem', 'srem', 'fadd', 'fsub', 'fmul', 'fdiv', 'fcmp', 'uitofp', 'sitofp', 'fpext', 'fptrunc', 'fptoui', 'fptosi', 'trunc', 'sext', 'select', 'shl', 'shr', 'ashl', 'ashr', 'lshr', 'lshl', 'xor', 'or', 'and', 'ptrtoint', 'inttoptr'].indexOf(item.tokens[0].text) != -1 && !item.intertype) + return 'Mathops'; + if (item.indent === 2 && item.tokens && item.tokens.length >= 5 && item.tokens[0].text == 'store' && + !item.intertype) + return 'Store'; + if (item.indent === 2 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'br' && + !item.intertype) + return 'Branch'; + if (item.indent === 2 && item.tokens && item.tokens.length >= 2 && item.tokens[0].text == 'ret' && + !item.intertype) + return 'Return'; + if (item.indent === 2 && item.tokens && item.tokens.length >= 2 && item.tokens[0].text == 'switch' && + !item.intertype) + return 'Switch'; + if (item.indent === 0 && item.tokens && item.tokens.length >= 1 && item.tokens[0].text == '}' && !item.intertype) + return 'FuncEnd'; + if (item.indent === 0 && item.tokens && item.tokens.length >= 4 && item.tokens[0].text == 'declare' && + !item.intertype) + return 'External'; + if (item.indent === 2 && item.tokens && item.tokens[0].text == 'unreachable' && + !item.intertype) + return 'Unreachable'; + } else { + // Already intertyped + if (item.parentSlot) + return 'Reintegrator'; + } + print("Item: " + JSON.stringify(item)); + assert(false); + } + this.forwardItem(item, triage(item)); }, }); // Line parsers to intermediate form - // Comment - substrate.addZyme('Comment', { - selectItem: function(item) { return item.tokens && item.tokens[0].text == ';' }, - processItem: function(item) { return [] }, - }); - // target - substrate.addZyme('Target', { - selectItem: function(item) { return item.tokens && item.tokens[0].text == 'target' }, - processItem: function(item) { return [] }, - }); // globals: type or variable substrate.addZyme('Global', { - selectItem: function(item) { return item.tokens && item.tokens.length >= 3 && item.indent === 0 && item.tokens[1].text == '=' }, processItem: function(item) { if (item.tokens[2].text == 'type') { //dprint('type/const linenum: ' + item.lineNum + ':' + dump(item)); @@ -560,7 +608,7 @@ function intertyper(data) { } } return [{ - __result__: true, + __result__: true, // XXX can remove these intertype: 'type', name_: item.tokens[0].text, fields: fields, @@ -595,8 +643,6 @@ function intertyper(data) { }); // function header substrate.addZyme('FuncHeader', { - selectItem: function(item) { return item.tokens && item.tokens.length >= 4 && item.indent === 0 && item.tokens[0].text == 'define' && - item.tokens.slice(-1)[0].text == '{' }, processItem: function(item) { item.tokens = item.tokens.filter(function(token) { return ['internal', 'signext', 'zeroext', 'nounwind', 'define', 'linkonce_odr', 'inlinehint', '{'].indexOf(token.text) == -1; @@ -613,7 +659,6 @@ function intertyper(data) { }); // label substrate.addZyme('Label', { - selectItem: function(item) { return item.tokens && item.tokens.length >= 1 && item.indent === 0 && item.tokens[0].text.substr(-1) == ':' }, processItem: function(item) { return [{ __result__: true, @@ -623,59 +668,35 @@ function intertyper(data) { }]; }, }); + // assignment substrate.addZyme('Assign', { - selectItem: function(item) { return item.indent === 2 && item.tokens && item.tokens.length >= 3 && findTokenText(item, '=') >= 0 && - !item.intertype }, processItem: function(item) { var opIndex = findTokenText(item, '='); - return [{ + var pair = splitItem({ intertype: 'assign', ident: combineTokens(item.tokens.slice(0, opIndex)).text, - value: null, lineNum: item.lineNum, - }, { // Additional token, to be parsed, and later re-integrated + }, 'value'); + this.forwardItem(pair.parent, 'Reintegrator'); + this.forwardItem(mergeInto(pair.child, { // Additional token, to be triaged and later re-integrated indent: -1, tokens: item.tokens.slice(opIndex+1), - parentLineNum: item.lineNum, - parentSlot: 'value', - }]; + }), 'Triager'); }, }); // reintegration - find intermediate representation-parsed items and - // place back in parents - substrate.addZyme('Reintegrator', { - select: function(items) { - var ret = []; - for (var i = 0; i < items.length; i++) { - if (items[i].parentSlot && items[i].intertype) { - for (var j = 0; j < items.length; j++) { - if (items[j].lineNum == items[i].parentLineNum) { - ret = ret.concat([items[j], items[i]]); - } - } - } - } - return ret; - }, - process: function(items) { - return Zyme.prototype.processPairs(items, function(parent, child) { - parent[child.parentSlot] = child; - parent.__result__ = true; - delete child.parentLineNum; - - // Special re-integration behaviors - if (child.intertype == 'fastgetelementptrload') { - parent.intertype = 'fastgetelementptrload'; - } - - return [parent]; - }); + // place back in parents TODO: Optimize this code to optimal O(..) + substrate.addZyme('Reintegrator', makeReintegrator(function(parent, child) { + // Special re-integration behaviors + if (child.intertype == 'fastgetelementptrload') { + parent.intertype = 'fastgetelementptrload'; } - }); + this.forwardItem(parent, '/dev/stdout'); + })); + // 'load' substrate.addZyme('Load', { - selectItem: function(item) { return !item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'load' }, processItem: function(item) { item.pointerType = item.tokens[1]; item.type = { text: removePointing(item.pointerType.text) }; @@ -692,30 +713,28 @@ function intertyper(data) { } else { item.intertype = 'load'; if (item.tokens[2].text == 'bitcast') { - item.pointer = item.tokens[3].item[0].tokens[1]; // XXX item without [0], also below + item.pointer = item.tokens[3].item[0].tokens[1]; item.originalType = item.tokens[3].item[0].tokens[0]; } else { item.pointer = item.tokens[2]; } } item.ident = item.pointer.text; - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // 'bitcast' substrate.addZyme('Bitcast', { - selectItem: function(item) { return !item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'bitcast' }, processItem: function(item) { item.intertype = 'bitcast'; item.type = item.tokens[1]; item.ident = item.tokens[2].text; item.type2 = item.tokens[4]; - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // 'getelementptr' substrate.addZyme('GEP', { - selectItem: function(item) { return !item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'getelementptr' }, processItem: function(item) { var last = getTokenIndexByText(item.tokens, ';'); var segment = [ item.tokens[1], { text: null }, null, { item: [ { @@ -726,12 +745,11 @@ function intertyper(data) { item.type = data.type; item.params = data.params; item.ident = data.ident; - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // 'call' substrate.addZyme('Call', { - selectItem: function(item) { return item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'call' && !item.intertype }, processItem: function(item) { item.intertype = 'call'; if (['signext', 'zeroext'].indexOf(item.tokens[1].text) != -1) { @@ -749,13 +767,13 @@ function intertyper(data) { // standalone call - not in assign item.standalone = true; item.__result__ = true; + return [item]; } - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // 'invoke' substrate.addZyme('Invoke', { - selectItem: function(item) { return item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'invoke' && !item.intertype }, processItem: function(item) { item.intertype = 'invoke'; item.type = item.tokens[1]; @@ -773,26 +791,23 @@ function intertyper(data) { // standalone call - not in assign item.standalone = true; item.__result__ = true; + return [item]; } - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // 'alloca' substrate.addZyme('Alloca', { - selectItem: function(item) { return !item.intertype && item.indent === -1 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'alloca' }, processItem: function(item) { item.intertype = 'alloca'; item.allocatedType = item.tokens[1]; item.type = { text: addPointing(item.tokens[1].text) }; // type of pointer we will get item.type2 = { text: item.tokens[1].text }; // value we will create, and get a pointer to - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // mathops substrate.addZyme('Mathops', { - selectItem: function(item) { return item.indent === -1 && item.tokens && item.tokens.length >= 3 && - ['add', 'sub', 'sdiv', 'mul', 'icmp', 'zext', 'urem', 'srem', 'fadd', 'fsub', 'fmul', 'fdiv', 'fcmp', 'uitofp', 'sitofp', 'fpext', 'fptrunc', 'fptoui', 'fptosi', 'trunc', 'sext', 'select', 'shl', 'shr', 'ashl', 'ashr', 'lshr', 'lshl', 'xor', 'or', 'and', 'ptrtoint', 'inttoptr'] - .indexOf(item.tokens[0].text) != -1 && !item.intertype }, processItem: function(item) { item.intertype = 'mathop'; item.op = item.tokens[0].text; @@ -808,13 +823,11 @@ function intertyper(data) { item.ident3 = item.tokens[5] ? item.tokens[5].text : null; item.ident4 = item.tokens[8] ? item.tokens[8].text : null; //print('// zz got maptop ' + item.op + ',' + item.variant + ',' + item.ident + ',' + item.value); - return [item]; + this.forwardItem(item, 'Reintegrator'); }, }); // 'store' substrate.addZyme('Store', { - selectItem: function(item) { return item.indent === 2 && item.tokens && item.tokens.length >= 5 && item.tokens[0].text == 'store' && - !item.intertype }, processItem: function(item) { if (item.tokens[3].text != ',') { assertEq(item.tokens[2].text, 'getelementptr'); @@ -846,8 +859,6 @@ function intertyper(data) { }); // 'br' substrate.addZyme('Branch', { - selectItem: function(item) { return item.indent === 2 && item.tokens && item.tokens.length >= 3 && item.tokens[0].text == 'br' && - !item.intertype }, processItem: function(item) { if (item.tokens[1].text == 'label') { return [{ @@ -870,8 +881,6 @@ function intertyper(data) { }); // 'ret' substrate.addZyme('Return', { - selectItem: function(item) { return item.indent === 2 && item.tokens && item.tokens.length >= 2 && item.tokens[0].text == 'ret' && - !item.intertype }, processItem: function(item) { return [{ __result__: true, @@ -884,8 +893,6 @@ function intertyper(data) { }); // 'switch' substrate.addZyme('Switch', { - selectItem: function(item) { return item.indent === 2 && item.tokens && item.tokens.length >= 2 && item.tokens[0].text == 'switch' && - !item.intertype }, processItem: function(item) { function parseSwitchLabels(item) { var ret = []; @@ -912,7 +919,6 @@ function intertyper(data) { }); // function end substrate.addZyme('FuncEnd', { - selectItem: function(item) { return item.indent === 0 && item.tokens && item.tokens.length >= 1 && item.tokens[0].text == '}' && !item.intertype }, processItem: function(item) { return [{ __result__: true, @@ -923,8 +929,6 @@ function intertyper(data) { }); // external function stub substrate.addZyme('External', { - selectItem: function(item) { return item.indent === 0 && item.tokens && item.tokens.length >= 4 && item.tokens[0].text == 'declare' && - !item.intertype }, processItem: function(item) { return [{ __result__: true, @@ -938,8 +942,6 @@ function intertyper(data) { }); // 'unreachable' substrate.addZyme('Unreachable', { - selectItem: function(item) { return item.indent === 2 && item.tokens && item.tokens[0].text == 'unreachable' && - !item.intertype }, processItem: function(item) { return [{ __result__: true, @@ -949,6 +951,12 @@ function intertyper(data) { }, }); + // Input + + substrate.addItem({ + llvmText: data, + }, 'LineSplitter'); + return substrate.solve(); } @@ -969,23 +977,16 @@ function analyzer(data) { //print('zz analaz') substrate = new Substrate('Analyzer'); - substrate.addItem({ - items: data, - }); - // Sorter substrate.addZyme('Sorter', { - selectItem: function(item) { return !item.sorted; }, processItem: function(item) { item.items.sort(function (a, b) { return a.lineNum - b.lineNum }); - item.sorted = true; - return [item]; + this.forwardItem(item, 'Gatherer'); }, }); // Gatherer substrate.addZyme('Gatherer', { - selectItem: function(item) { return item.sorted && !item.gathered; }, processItem: function(item) { // Single-liners ['globalVariable', 'functionStub', 'type'].forEach(function(intertype) { @@ -1016,14 +1017,12 @@ function analyzer(data) { } } delete item.items; - item.gathered = true; - return [item]; + this.forwardItem(item, 'Identinicer'); }, }); // IdentiNicer substrate.addZyme('Identinicer', { - selectItem: function(item) { return item.gathered && !item.identiniced; }, processItem: function(output) { walkJSON(output, function(item) { ['', '2', '3', '4', '5'].forEach(function(ext) { @@ -1031,8 +1030,7 @@ function analyzer(data) { item['ident' + ext] = toNiceIdent(item['ident' + ext]); }); }); - output.identiniced = true; - return [output]; + this.forwardItem(output, 'Typevestigator'); } }); @@ -1065,7 +1063,6 @@ function analyzer(data) { // Typevestigator substrate.addZyme('Typevestigator', { - selectItem: function(item) { return item.gathered && !item.typevestigated; }, processItem: function(data) { // Convert types list to dict var old = data.types; @@ -1082,14 +1079,12 @@ function analyzer(data) { addType(!item.type2.text ? item.type2 : item.type2.text, data); } }); - data.typevestigated = true; - return [data]; + this.forwardItem(data, 'Typeanalyzer'); } }); // Type analyzer - substrate.addZyme('Type Analyzer', { - selectItem: function(item) { return item.typevestigated && !item.typed; }, + substrate.addZyme('Typeanalyzer', { processItem: function(item) { //print('zz analaz types') // 'fields' is the raw list of LLVM fields. However, we embed @@ -1152,14 +1147,12 @@ function analyzer(data) { }); } - item.typed = true; - return [item]; + this.forwardItem(item, 'VariableAnalyzer'); }, }); // Variable analyzer - substrate.addZyme('Variable Analyzer', { - selectItem: function(item) { return item.typevestigated && !item.variablized; }, + substrate.addZyme('VariableAnalyzer', { processItem: function(item) { item.functions.forEach(function(func) { func.variables = {}; @@ -1233,18 +1226,16 @@ function analyzer(data) { //print('// var ' + vname + ': ' + JSON.stringify(variable)); } }); - item.variablized = true; - return [item]; + this.forwardItem(item, 'Relooper'); }, }); // ReLooper - reconstruct nice loops, as much as possible substrate.addZyme('Relooper', { - selectItem: function(item) { return item.variablized && !item.relooped }, processItem: function(item) { + var that = this; function finish() { - item.relooped = true; - return [item]; + that.forwardItem(item, 'Optimizer'); } // Tools @@ -1651,10 +1642,9 @@ print('// zz Merged away! ' + label2.ident + ' into ' + label1.ident); // Optimizer substrate.addZyme('Optimizer', { - selectItem: function(item) { return item.relooped && !item.optimized; }, processItem: function(item) { + var that = this; function finish() { - item.optimized = true; item.__finalResult__ = true; return [item]; } @@ -1845,6 +1835,10 @@ print('// zz Merged away! ' + label2.ident + ' into ' + label1.ident); }, }); + substrate.addItem({ + items: data, + }, 'Sorter'); + return substrate.solve(); } @@ -1852,20 +1846,10 @@ print('// zz Merged away! ' + label2.ident + ' into ' + label1.ident); function JSify(data) { substrate = new Substrate('JSifyer'); - [].concat(values(data.types).filter(function(type) { return type.lineNum != '?' })) - .concat(data.globalVariables) - .concat(data.functions) - .concat(data.functionStubs) - .forEach(function(item) { - item.passes = {}; - substrate.addItem(item); - }); - var TYPES = data.types; // type substrate.addZyme('Type', { - selectItem: function(item) { return item.intertype == 'type' && !item.JS }, processItem: function(item) { var type = TYPES[item.name_]; if (type.needsFlattening) { @@ -1980,7 +1964,6 @@ function JSify(data) { // globalVariablw substrate.addZyme('GlobalVariable', { - selectItem: function(item) { return item.intertype == 'globalVariable' && !item.JS }, processItem: function(item) { dprint('gconst', '// zz global Cons: ' + dump(item) + ' :: ' + dump(item.value)); if (item.ident == '_llvm_global_ctors') { @@ -2000,7 +1983,6 @@ function JSify(data) { // functionStub substrate.addZyme('FunctionStub', { - selectItem: function(item) { return item.intertype == 'functionStub' && !item.JS }, processItem: function(item) { var shortident = item.ident.substr(1); if (shortident in Snippets) { @@ -2015,7 +1997,6 @@ function JSify(data) { // function splitter substrate.addZyme('FunctionSplitter', { - selectItem: function(item) { return item.intertype == 'function' && !item.passes.splitted }, processItem: function(item) { var ret = [item]; item.splitItems = 0; @@ -2029,114 +2010,102 @@ function JSify(data) { }); }); - item.passes.splitted = true; - return ret; + this.forwardItems(ret, 'FuncLineTriager'); }, }); // function reconstructor & post-JS optimizer substrate.addZyme('FunctionReconstructor', { - select: function(items) { - var funcs = items.filter(function(item) { return item.intertype == 'function' && item.passes.splitted }); - return funcs.map(function(func) { - var lines = items.filter(function(item) { return item.JS && item.func === func.ident }); - if (lines.length === 0) return []; - return [func].concat(lines); - }).reduce(concatenator, []); - }, - process: function(allItems) { - var ret = []; - for (var i = 0; i < allItems.length;) { - var func = allItems[i]; - var j = i+1; - while (j < allItems.length && allItems[j].intertype != 'function') j++; - var lines = allItems.slice(i+1, j); - i = j; - - lines.forEach(function(line) { - delete line.funcData; // clean up - - var label = func.labels.filter(function(label) { return label.ident == line.parentLabel })[0]; - label.lines = label.lines.map(function(line2) { - return (line2.lineNum !== line.lineNum) ? line2 : line; - }); - }); + funcs: {}, + seen: {}, + processItem: function(item) { + if (this.seen[item.__uid__]) return; + if (item.intertype == 'function') { + this.funcs[item.ident] = item; + item.relines = {}; + this.seen[item.__uid__] = true; + return; + } + var line = item; + var func = this.funcs[line.func]; + if (!func) return; + + // Re-insert our line + this.seen[item.__uid__] = true; + var label = func.labels.filter(function(label) { return label.ident == line.parentLabel })[0]; + label.lines = label.lines.map(function(line2) { + return (line2.lineNum !== line.lineNum) ? line2 : line; + }); + func.splitItems --; + // OLD delete line.funcData; // clean up + if (func.splitItems > 0) return; + + // We have this function all reconstructed, go and finalize it's JS! + var hasVarArgs = false; + var params = parseParamTokens(func.params.item[0].tokens).map(function(param) { + if (param.intertype == 'varargs') { + hasVarArgs = true; + return null; + } + return toNiceIdent(param.ident); + }).filter(function(param) { return param != null });; - func.splitItems -= lines.length; - if (func.splitItems === 0) { - // Final recombination - //print('zz params::::: ' + JSON.stringify(func.params)); - //print('zz params::::: ' + JSON.stringify(parseParamTokens(func.params.item[0].tokens))); - - var hasVarArgs = false; - var params = parseParamTokens(func.params.item[0].tokens).map(function(param) { - if (param.intertype == 'varargs') { - hasVarArgs = true; - return null; - } - return toNiceIdent(param.ident); - }).filter(function(param) { return param != null });; + func.JS = '\nfunction ' + func.ident + '(' + params.join(', ') + ') {\n'; + if (LABEL_DEBUG) func.JS += " print(INDENT + ' Entering: " + func.ident + "'); INDENT += ' ';\n"; - func.JS = '\nfunction ' + func.ident + '(' + params.join(', ') + ') {\n'; - if (LABEL_DEBUG) func.JS += " print(INDENT + ' Entering: " + func.ident + "'); INDENT += ' ';\n"; + if (hasVarArgs) { + func.JS += ' __numArgs__ = ' + params.length + ';\n'; + } - if (hasVarArgs) { - func.JS += ' __numArgs__ = ' + params.length + ';\n'; + // Walk function blocks and generate JS + function walkBlock(block, indent) { + if (!block) return ''; + function getLabelLines(label, indent) { + var ret = ''; + if (LABEL_DEBUG) { + ret += indent + " print(INDENT + '" + func.ident + ":" + label.ident + "');\n"; } - - // Walk function blocks and generate JS - function walkBlock(block, indent) { - if (!block) return ''; - function getLabelLines(label, indent) { - var ret = ''; - if (LABEL_DEBUG) { - ret += indent + " print(INDENT + '" + func.ident + ":" + label.ident + "');\n"; - } - return ret + label.lines.map(function(line) { return indent + line.JS + (line.comment ? ' // ' + line.comment : '') }).join('\n'); - } - var ret = ''; - if (block.type == 'emulated' || block.type == 'simple') { - if (block.labels.length > 1) { - ret += indent + 'var __label__ = ' + getLabelId(block.entry) + '; /* ' + block.entry + ' */\n'; - ret += indent + 'while(1) switch(__label__) {\n'; - ret += block.labels.map(function(label) { - return indent + ' case ' + getLabelId(label.ident) + ': // ' + label.ident + '\n' + getLabelLines(label, indent + ' '); - }).join('\n'); - ret += '\n' + indent + '}'; - } else { - ret += getLabelLines(block.labels[0], indent); - } - ret += '\n'; - } else if (block.type == 'loop') { - // if (mustGetTo(first.outLabels[0], [first.ident, first.outLabels[1]])) { /* left branch must return here, or go to right branch */ - ret += indent + block.entry + ': while(1) {\n'; - ret += walkBlock(block.inc, indent + ' '); - ret += walkBlock(block.rest, indent + ' '); - ret += indent + '}\n'; - } else if (block.type == 'breakingif') { - ret += walkBlock(block.check, indent); - ret += indent + block.entry + ': do { if (' + block.ifVar + ') {\n'; - ret += walkBlock(block.ifTrue, indent + ' '); - ret += indent + '} } while(0);\n'; - } else if (block.type == 'if') { - ret += walkBlock(block.check, indent); - ret += indent + 'if (' + block.ifVar + ') {\n'; - ret += walkBlock(block.ifTrue, indent + ' '); - ret += indent + '}\n'; - } else { - ret = 'XXXXXXXXX!'; - } - return ret + walkBlock(block.next, indent); + return ret + label.lines.map(function(line) { return indent + line.JS + (line.comment ? ' // ' + line.comment : '') }).join('\n'); + } + var ret = ''; + if (block.type == 'emulated' || block.type == 'simple') { + if (block.labels.length > 1) { + ret += indent + 'var __label__ = ' + getLabelId(block.entry) + '; /* ' + block.entry + ' */\n'; + ret += indent + 'while(1) switch(__label__) {\n'; + ret += block.labels.map(function(label) { + return indent + ' case ' + getLabelId(label.ident) + ': // ' + label.ident + '\n' + getLabelLines(label, indent + ' '); + }).join('\n'); + ret += '\n' + indent + '}'; + } else { + ret += getLabelLines(block.labels[0], indent); } - func.JS += walkBlock(func.block, ' '); - // Finalize function - if (LABEL_DEBUG) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n"; - func.JS += '}\n'; - func.__result__ = true; + ret += '\n'; + } else if (block.type == 'loop') { +// if (mustGetTo(first.outLabels[0], [first.ident, first.outLabels[1]])) { /* left branch must return here, or go to right branch */ + ret += indent + block.entry + ': while(1) {\n'; + ret += walkBlock(block.inc, indent + ' '); + ret += walkBlock(block.rest, indent + ' '); + ret += indent + '}\n'; + } else if (block.type == 'breakingif') { + ret += walkBlock(block.check, indent); + ret += indent + block.entry + ': do { if (' + block.ifVar + ') {\n'; + ret += walkBlock(block.ifTrue, indent + ' '); + ret += indent + '} } while(0);\n'; + } else if (block.type == 'if') { + ret += walkBlock(block.check, indent); + ret += indent + 'if (' + block.ifVar + ') {\n'; + ret += walkBlock(block.ifTrue, indent + ' '); + ret += indent + '}\n'; + } else { + ret = 'XXXXXXXXX!'; } - - ret.push(func); + return ret + walkBlock(block.next, indent); } - return ret; + func.JS += walkBlock(func.block, ' '); + // Finalize function + if (LABEL_DEBUG) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n"; + func.JS += '}\n'; + func.__result__ = true; + return func; }, }); @@ -2148,10 +2117,31 @@ function JSify(data) { } } - // 'assign' - // SLOW?! XXX FIXME These two account for most of the runtime in sauer!? 34&25 seconds respectively - substrate.addZyme('AssignSplitter', makeSplitter('intertype', 'assign', 'JS', 'value', ['funcData'])); - substrate.addZyme('AssignCombiner', makeCombiner('intertype', 'assign', 'JS', 'JS', function (item) { |