diff options
-rw-r--r-- | src/analyzer.js | 45 | ||||
-rw-r--r-- | src/compiler.js | 1 | ||||
-rw-r--r-- | src/intertyper.js | 94 | ||||
-rw-r--r-- | src/jsifier.js | 32 | ||||
-rw-r--r-- | src/modules.js | 100 | ||||
-rw-r--r-- | src/parseTools.js | 4 | ||||
-rw-r--r-- | src/runtime.js | 6 |
7 files changed, 141 insertions, 141 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 42654502..b5ab29d9 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -13,7 +13,7 @@ function cleanFunc(func) { }); } -function analyzer(data, givenTypes) { +function analyzer(data) { // Substrate substrate = new Substrate('Analyzer'); @@ -29,15 +29,17 @@ function analyzer(data, givenTypes) { substrate.addActor('Gatherer', { processItem: function(item) { // Single-liners - ['globalVariable', 'functionStub', 'type', 'unparsedFunction'].forEach(function(intertype) { - if (intertype === 'type' && givenTypes) { - item.types = givenTypes; - return; - } + ['globalVariable', 'functionStub', 'unparsedFunction'].forEach(function(intertype) { var temp = splitter(item.items, function(item) { return item.intertype == intertype }); - item[intertype + 's'] = temp.splitOut; item.items = temp.leftIn; + item[intertype + 's'] = temp.splitOut; + }); + var temp = splitter(item.items, function(item) { return item.intertype == 'type' }); + item.items = temp.leftIn; + temp.splitOut.forEach(function(type) { + Types.types[type.name_] = type; }); + // Functions & labels item.functions = []; var currLabelFinished; // Sometimes LLVM puts a branch in the middle of a label. We need to ignore all lines after that. @@ -85,7 +87,7 @@ function analyzer(data, givenTypes) { function addType(type, data) { if (type.length == 1) return; - if (data.types[type]) return; + if (Types.types[type]) return; if (['internal', 'hidden', 'inbounds', 'void'].indexOf(type) != -1) return; if (Runtime.isNumberType(type)) return; @@ -94,7 +96,7 @@ function analyzer(data, givenTypes) { // anywhere else. var nonPointing = removeAllPointing(type); var check = new RegExp(/^\[(\d+)\ x\ (.*)\]$/g).exec(nonPointing); - if (check && !data.types[nonPointing]) { + if (check && !Types.types[nonPointing]) { var num = parseInt(check[1]); num = Math.max(num, 1); // [0 x something] is used not for allocations and such of course, but // for indexing - for an |array of unknown length|, basically. So we @@ -102,15 +104,15 @@ function analyzer(data, givenTypes) { // check that we never allocate with this (either as a child structure // in the analyzer, or in calcSize in alloca). var subType = check[2]; - data.types[nonPointing] = { + Types.types[nonPointing] = { name_: nonPointing, fields: range(num).map(function() { return subType }), lineNum: '?' }; // Also add a |[0 x type]| type var zerod = '[0 x ' + subType + ']'; - if (!data.types[zerod]) { - data.types[zerod] = { + if (!Types.types[zerod]) { + Types.types[zerod] = { name_: zerod, fields: [subType, subType], // Two, so we get the flatFactor right. We care about the flatFactor, not the size here lineNum: '?' @@ -121,7 +123,7 @@ function analyzer(data, givenTypes) { if (isPointerType(type)) return; if (['['].indexOf(type) != -1) return; - data.types[type] = { + Types.types[type] = { name_: type, fields: [ 'i' + (QUANTUM_SIZE*8) ], // a single quantum size flatSize: 1, @@ -132,13 +134,6 @@ function analyzer(data, givenTypes) { // Typevestigator substrate.addActor('Typevestigator', { processItem: function(data) { - // Convert types list to dict - if (data.types.length !== undefined) { - var old = data.types; - data.types = {}; - old.forEach(function(type) { data.types[type.name_] = type }); - } - // Find additional types walkJSON(data, function(item) { if (!item) return; @@ -181,17 +176,17 @@ function analyzer(data, givenTypes) { var more = true; while (more) { more = false; - values(item.types).forEach(function(type) { + values(Types.types).forEach(function(type) { if (type.flatIndexes) return; var ready = true; type.fields.forEach(function(field) { //print('// zz getT: ' + type.name_ + ' : ' + field); if (isStructType(field)) { - if (!item.types[field]) { + if (!Types.types[field]) { addType(field, item); ready = false; } else { - if (!item.types[field].flatIndexes) { + if (!Types.types[field].flatIndexes) { ready = false; } } @@ -202,7 +197,7 @@ function analyzer(data, givenTypes) { return; } - Runtime.calculateStructAlignment(type, item.types); + Runtime.calculateStructAlignment(type); dprint('types', 'type: ' + type.name_ + ' : ' + JSON.stringify(type.fields)); dprint('types', ' has final size of ' + type.flatSize + ', flatting: ' + type.needsFlattening + ' ? ' + (type.flatFactor ? type.flatFactor : JSON.stringify(type.flatIndexes))); @@ -371,7 +366,7 @@ function analyzer(data, givenTypes) { if (!item || item.intertype != 'alloca') break; assert(isNumber(item.allocatedNum)); item.allocatedSize = func.variables[line.ident].impl === VAR_EMULATED ? - calcAllocatedSize(item.allocatedType, data.types)*item.allocatedNum: 0; + calcAllocatedSize(item.allocatedType)*item.allocatedNum: 0; total += item.allocatedSize; } func.initialStack = total; diff --git a/src/compiler.js b/src/compiler.js index 72ef554c..e18492d5 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -33,6 +33,7 @@ if (CORRECT_OVERFLOWS === 2) { // Load compiler code load('framework.js'); +load('modules.js'); load('parseTools.js'); load('intertyper.js'); load('analyzer.js'); diff --git a/src/intertyper.js b/src/intertyper.js index 33168e7d..57e24eeb 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -1,100 +1,6 @@ // LLVM assembly => internal intermediate representation, which is ready // to be processed by the later stages. -var LLVM_STYLE = null; - -var LLVM = { - LINKAGES: set('private', 'linker_private', 'linker_private_weak', 'linker_private_weak_def_auto', 'internal', - 'available_externally', 'linkonce', 'common', 'weak', 'appending', 'extern_weak', 'linkonce_odr', - 'weak_odr', 'externally_visible', 'dllimport', 'dllexport'), - CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10') -}; - -var Debugging = { - processMetadata: function(lines) { - var llvmLineToMetadata = {}; - var metadataToSourceLine = {}; - var metadataToParentMetadata = {}; - var metadataToFilename = {}; - var form1 = new RegExp(/^ .*, !dbg !(\d+)$/); - var form2 = new RegExp(/^ .*, !dbg !(\d+) +; \[#uses=\d+\]$/); - var form3 = new RegExp(/^!(\d+) = metadata !{i32 (\d+), i32 \d+, metadata !(\d+), .*}$/); - var form3a = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !\d+, i32 \d+, i32 \d+, metadata !(\d+), i32 \d+} ; \[ DW_TAG_lexical_block \]$/); - var form3ab = new RegExp(/^!(\d+) = metadata !{i32 \d+, i32 \d+, metadata !(\d+), .*$/); - var form3ac = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !\d+, metadata !"[^"]+", metadata !(\d+)[^\[]* ; \[ DW_TAG_structure_type \]$/); - var form3b = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !"([^"]+)", metadata !"([^"]+)", metadata !\d+} ; \[ DW_TAG_file_type \]$/); - var form3c = new RegExp(/^!(\d+) = metadata !{\w+\d* !?(\d+)[^\d].*$/); - var form4 = new RegExp(/^!llvm.dbg.\w+ = .*$/); - var form5 = new RegExp(/^!(\d+) = metadata !{null.*$/); - var form6 = new RegExp(/^ call void \@llvm.dbg.declare\(metadata .*$/); - - var ret = lines.map(function(line, i) { - if (form6.exec(line)) return null; - - var calc = form1.exec(line) || form2.exec(line); - if (calc) { - llvmLineToMetadata[i+1] = calc[1]; - return line.replace(', !dbg !' + calc[1], ''); - } - calc = form3.exec(line); - if (calc) { - metadataToSourceLine[calc[1]] = calc[2]; - metadataToParentMetadata[calc[1]] = calc[3]; - return ';'; // return an empty line, to keep line numbers of subsequent lines the same - } - calc = form3a.exec(line) || form3ab.exec(line) || form3ac.exec(line); - if (calc) { - metadataToParentMetadata[calc[1]] = calc[2]; - return ';'; - } - calc = form3b.exec(line); - if (calc) { - metadataToFilename[calc[1]] = calc[3] + '/' + calc[2]; - return ';'; - } - calc = form3c.exec(line) || form4.exec(line) || form5.exec(line); - if (calc) return ';'; - return line; - }, this); - - /* - dprint("ll ==> meta: " + JSON.stringify(llvmLineToMetadata)); - dprint("meta ==> sline: " + JSON.stringify(metadataToSourceLine)); - dprint("meta ==> pmeta: " + JSON.stringify(metadataToParentMetadata)); - dprint("meta ==> fname: " + JSON.stringify(metadataToFilename)); - */ - - this.llvmLineToSourceLine = {}; - this.llvmLineToSourceFile = {}; - for (var l in llvmLineToMetadata) { - var m = llvmLineToMetadata[l]; - this.llvmLineToSourceLine[l] = metadataToSourceLine[m]; - //dprint('starting to recurse metadata for: ' + m); - while (!metadataToFilename[m]) { - //dprint('recursing metadata, at: ' + m); - m = metadataToParentMetadata[m]; - assert(m, 'Confused as to parent metadata for llvm #' + l + ', metadata !' + m); - } - this.llvmLineToSourceFile[l] = metadataToFilename[m]; - } - - this.on = true; - - return ret; - }, - - getComment: function(lineNum) { - return lineNum in this.llvmLineToSourceLine ? ' //@line ' + this.llvmLineToSourceLine[lineNum] + ' "' + - this.llvmLineToSourceFile[lineNum] + '"' : ''; - }, - - getIdentifier: function(lineNum) { - var sourceFile = this.llvmLineToSourceFile[lineNum]; - if (!sourceFile) return null; - return sourceFile.split('/').slice(-1)[0] + ':' + this.llvmLineToSourceLine[lineNum]; - } -}; - //! @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. diff --git a/src/jsifier.js b/src/jsifier.js index 3b054119..5f0f11c6 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -2,7 +2,7 @@ // before this stage, which just does the final conversion to JavaScript. // Main function -function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVariables) { +function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { // Does simple 'macro' substitution, using Django-like syntax, // {{{ code }}} will be replaced with |eval(code)|. function processMacros(text) { @@ -14,8 +14,6 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria substrate = new Substrate('JSifyer'); - var TYPES = functionsOnly ? givenTypes : data.types; - var GLOBAL_VARIABLES = functionsOnly ? givenGlobalVariables : data.globalVariables; var FUNCTIONS = functionsOnly ? givenFunctions : {}; @@ -32,7 +30,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria var func = data.unparsedFunctions[i]; dprint('unparsedFunctions', '====================\n// Processing |' + func.ident + '|, ' + i + '/' + data.unparsedFunctions.length); //var t = Date.now(); - func.JS = JSify(analyzer(intertyper(func.lines, true, func.lineNum-1), TYPES), true, TYPES, FUNCTIONS, GLOBAL_VARIABLES); + func.JS = JSify(analyzer(intertyper(func.lines, true, func.lineNum-1)), true, FUNCTIONS, GLOBAL_VARIABLES); //t = (Date.now()-t)/1000; //dprint('unparsedFunctions', 'unparsedFunction took ' + t + ' seconds.'); delete func.lines; // clean up memory as much as possible @@ -50,12 +48,12 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria // type substrate.addActor('Type', { processItem: function(item) { - var type = TYPES[item.name_]; + var type = Types.types[item.name_]; var niceName = toNiceIdent(item.name_); - // We might export all of TYPES, cleaner that way, but do not want slowdowns in accessing flatteners - item.JS = 'var ' + niceName + '___SIZE = ' + TYPES[item.name_].flatSize + '; // ' + item.name_ + '\n'; + // We might export all of Types.types, cleaner that way, but do not want slowdowns in accessing flatteners + item.JS = 'var ' + niceName + '___SIZE = ' + Types.types[item.name_].flatSize + '; // ' + item.name_ + '\n'; if (type.needsFlattening && !type.flatFactor) { - item.JS += 'var ' + niceName + '___FLATTENER = ' + JSON.stringify(TYPES[item.name_].flatIndexes) + ';'; + item.JS += 'var ' + niceName + '___FLATTENER = ' + JSON.stringify(Types.types[item.name_].flatIndexes) + ';'; } return [item]; } @@ -94,7 +92,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria // See makeSetValue function makeGetValue(ptr, pos, type, noNeedFirst) { if (isStructType(type)) { - var typeData = TYPES[type]; + 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)); @@ -130,7 +128,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria //! @param noNeedFirst Whether to ignore the offset in the pointer itself. function makeSetValue(ptr, pos, value, type, noNeedFirst) { if (isStructType(type)) { - var typeData = TYPES[type]; + var typeData = Types.types[type]; var ret = []; for (var i = 0; i < typeData.fields.length; i++) { ret.push(makeSetValue(ptr, pos + typeData.flatIndexes[i], value[i], typeData.fields[i], noNeedFirst)); @@ -160,7 +158,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria function makeEmptyStruct(type) { var ret = []; - var typeData = TYPES[type]; + var typeData = Types.types[type]; assertTrue(typeData); for (var i = 0; i < typeData.flatSize; i++) { ret.push(0); @@ -169,7 +167,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria } function alignStruct(values, type) { - var typeData = TYPES[type]; + var typeData = Types.types[type]; assertTrue(typeData); var ret = []; var i = 0, soFar = 0; @@ -758,7 +756,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria if (item.allocatedSize === 0) return ''; // This will not actually be shown - it's nativized return getFastValue('__stackBase__', '+', item.allocatedIndex.toString()); } else { - return RuntimeGenerator.stackAlloc(getFastValue(calcAllocatedSize(item.allocatedType, TYPES), '*', item.allocatedNum)); + return RuntimeGenerator.stackAlloc(getFastValue(calcAllocatedSize(item.allocatedType), '*', item.allocatedNum)); } }); makeFuncLineActor('phi', function(item) { @@ -944,7 +942,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria var offset = toNiceIdent(item.params[1].ident); if (offset != 0) { if (isStructType(type)) { - indexes.push(getFastValue(TYPES[type].flatSize, '*', offset)); + indexes.push(getFastValue(Types.types[type].flatSize, '*', offset)); } else { indexes.push(getFastValue(getNativeFieldSize(type, true), '*', offset)); } @@ -953,7 +951,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria dprint('types', 'GEP type: ' + type); var curr = toNiceIdent(arg.ident); // TODO: If index is constant, optimize - var typeData = TYPES[type]; + var typeData = Types.types[type]; if (isStructType(type) && typeData.needsFlattening) { if (typeData.flatFactor) { indexes.push(getFastValue(curr, '*', typeData.flatFactor)); @@ -1091,7 +1089,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria return makeFunctionCall(item.ident, item.params, item.funcData) + (item.standalone ? ';' : ''); }); - // Optimzed intertypes + // Optimized intertypes makeFuncLineActor('fastgetelementptrload', function(item) { return 'var ' + item.ident + ' = ' + makeGetValue(parseNumerical(item.value.ident), getGetElementPtrIndexes(item.value), item.value.valueType, true) + ';'; @@ -1131,7 +1129,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions, givenGlobalVaria // Data - substrate.addItems(values(data.types).filter(function(type) { return type.lineNum != '?' }), 'Type'); + substrate.addItems(values(Types.types).filter(function(type) { return type.lineNum != '?' }), 'Type'); substrate.addItems(values(data.globalVariables), 'GlobalVariable'); substrate.addItems(data.functions, 'FunctionSplitter'); substrate.addItems(data.functionStubs, 'FunctionStub'); diff --git a/src/modules.js b/src/modules.js new file mode 100644 index 00000000..f2c458f5 --- /dev/null +++ b/src/modules.js @@ -0,0 +1,100 @@ +// Various namespace-like modules + +var LLVM_STYLE = null; + +var LLVM = { + LINKAGES: set('private', 'linker_private', 'linker_private_weak', 'linker_private_weak_def_auto', 'internal', + 'available_externally', 'linkonce', 'common', 'weak', 'appending', 'extern_weak', 'linkonce_odr', + 'weak_odr', 'externally_visible', 'dllimport', 'dllexport'), + CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10') +}; + +var Debugging = { + processMetadata: function(lines) { + var llvmLineToMetadata = {}; + var metadataToSourceLine = {}; + var metadataToParentMetadata = {}; + var metadataToFilename = {}; + var form1 = new RegExp(/^ .*, !dbg !(\d+)$/); + var form2 = new RegExp(/^ .*, !dbg !(\d+) +; \[#uses=\d+\]$/); + var form3 = new RegExp(/^!(\d+) = metadata !{i32 (\d+), i32 \d+, metadata !(\d+), .*}$/); + var form3a = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !\d+, i32 \d+, i32 \d+, metadata !(\d+), i32 \d+} ; \[ DW_TAG_lexical_block \]$/); + var form3ab = new RegExp(/^!(\d+) = metadata !{i32 \d+, i32 \d+, metadata !(\d+), .*$/); + var form3ac = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !\d+, metadata !"[^"]+", metadata !(\d+)[^\[]* ; \[ DW_TAG_structure_type \]$/); + var form3b = new RegExp(/^!(\d+) = metadata !{i32 \d+, metadata !"([^"]+)", metadata !"([^"]+)", metadata !\d+} ; \[ DW_TAG_file_type \]$/); + var form3c = new RegExp(/^!(\d+) = metadata !{\w+\d* !?(\d+)[^\d].*$/); + var form4 = new RegExp(/^!llvm.dbg.\w+ = .*$/); + var form5 = new RegExp(/^!(\d+) = metadata !{null.*$/); + var form6 = new RegExp(/^ call void \@llvm.dbg.declare\(metadata .*$/); + + var ret = lines.map(function(line, i) { + if (form6.exec(line)) return null; + + var calc = form1.exec(line) || form2.exec(line); + if (calc) { + llvmLineToMetadata[i+1] = calc[1]; + return line.replace(', !dbg !' + calc[1], ''); + } + calc = form3.exec(line); + if (calc) { + metadataToSourceLine[calc[1]] = calc[2]; + metadataToParentMetadata[calc[1]] = calc[3]; + return ';'; // return an empty line, to keep line numbers of subsequent lines the same + } + calc = form3a.exec(line) || form3ab.exec(line) || form3ac.exec(line); + if (calc) { + metadataToParentMetadata[calc[1]] = calc[2]; + return ';'; + } + calc = form3b.exec(line); + if (calc) { + metadataToFilename[calc[1]] = calc[3] + '/' + calc[2]; + return ';'; + } + calc = form3c.exec(line) || form4.exec(line) || form5.exec(line); + if (calc) return ';'; + return line; + }, this); + + /* + dprint("ll ==> meta: " + JSON.stringify(llvmLineToMetadata)); + dprint("meta ==> sline: " + JSON.stringify(metadataToSourceLine)); + dprint("meta ==> pmeta: " + JSON.stringify(metadataToParentMetadata)); + dprint("meta ==> fname: " + JSON.stringify(metadataToFilename)); + */ + + this.llvmLineToSourceLine = {}; + this.llvmLineToSourceFile = {}; + for (var l in llvmLineToMetadata) { + var m = llvmLineToMetadata[l]; + this.llvmLineToSourceLine[l] = metadataToSourceLine[m]; + //dprint('starting to recurse metadata for: ' + m); + while (!metadataToFilename[m]) { + //dprint('recursing metadata, at: ' + m); + m = metadataToParentMetadata[m]; + assert(m, 'Confused as to parent metadata for llvm #' + l + ', metadata !' + m); + } + this.llvmLineToSourceFile[l] = metadataToFilename[m]; + } + + this.on = true; + + return ret; + }, + + getComment: function(lineNum) { + return lineNum in this.llvmLineToSourceLine ? ' //@line ' + this.llvmLineToSourceLine[lineNum] + ' "' + + this.llvmLineToSourceFile[lineNum] + '"' : ''; + }, + + getIdentifier: function(lineNum) { + var sourceFile = this.llvmLineToSourceFile[lineNum]; + if (!sourceFile) return null; + return sourceFile.split('/').slice(-1)[0] + ':' + this.llvmLineToSourceLine[lineNum]; + } +}; + +var Types = { + types: {}, +}; + diff --git a/src/parseTools.js b/src/parseTools.js index 6cf186d0..4c70867a 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -501,9 +501,9 @@ function cleanLabel(label) { } } -function calcAllocatedSize(type, TYPES) { +function calcAllocatedSize(type) { if (pointingLevels(type) == 0 && isStructType(type)) { - return TYPES[type].flatSize; // makeEmptyStruct(item.allocatedType).length; + return Types.types[type].flatSize; // makeEmptyStruct(item.allocatedType).length; } else { return getNativeFieldSize(type, true); // We can really get away with '1', though, at least on the stack... } diff --git a/src/runtime.js b/src/runtime.js index 9cdba894..6ab78611 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -104,7 +104,7 @@ Runtime = { // Calculate aligned size, just like C structs should be. TODO: Consider // requesting that compilation be done with #pragma pack(push) /n #pragma pack(1), // which would remove much of the complexity here. - calculateStructAlignment: function calculateStructAlignment(type, otherTypes) { + calculateStructAlignment: function calculateStructAlignment(type) { type.flatSize = 0; type.alignSize = 0; var diffs = []; @@ -115,8 +115,8 @@ Runtime = { size = Runtime.getNativeFieldSize(field, true); // pack char; char; in structs, also char[X]s. alignSize = size; } else if (Runtime.isStructType(field)) { - size = otherTypes[field].flatSize; - alignSize = otherTypes[field].alignSize; + size = Types.types[field].flatSize; + alignSize = Types.types[field].alignSize; } else { dprint('Unclear type in struct: ' + field + ', in ' + type.name_); assert(0); |