aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js33
-rw-r--r--src/compiler.js2
-rw-r--r--src/dlmalloc.c2
-rw-r--r--src/experimental/noncallgraphprofiling.diff197
-rw-r--r--src/include/emscripten.h16
-rw-r--r--src/intertyper.js118
-rw-r--r--src/jsifier.js90
-rw-r--r--src/library.js611
-rw-r--r--src/modules.js52
-rw-r--r--src/parseTools.js90
-rw-r--r--src/preamble.js108
-rw-r--r--src/runtime.js11
-rw-r--r--src/settings.js38
13 files changed, 946 insertions, 422 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 824e7903..37285733 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -46,8 +46,10 @@ function analyzer(data) {
// 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.
+ item.items.sort(function(a, b) { return a.lineNum - b.lineNum });
for (var i = 0; i < item.items.length; i++) {
var subItem = item.items[i];
+ assert(subItem.lineNum);
if (subItem.intertype == 'function') {
item.functions.push(subItem);
subItem.endLineNum = null;
@@ -58,7 +60,7 @@ function analyzer(data) {
if (LLVM_STYLE == 'new' && item.items[i+1].intertype !== 'label') {
item.items.splice(i+1, 0, {
intertype: 'label',
- ident: '_entry',
+ ident: toNiceIdent('%0'),
lineNum: subItem.lineNum + '.5'
});
}
@@ -77,10 +79,10 @@ function analyzer(data) {
currLabelFinished = true;
}
} else {
- print('// WARNING: content after a branch in a label, line: ' + subItem.lineNum);
+ print('// WARNING: content after a branch in a label, line: ' + subItem.lineNum + '::' + dump(subItem));
}
} else {
- print("ERROR: what is this? " + JSON.stringify(subItem));
+ throw "ERROR: what is this? " + JSON.stringify(subItem);
}
}
delete item.items;
@@ -93,6 +95,7 @@ function analyzer(data) {
if (Types.types[type]) return;
if (['internal', 'hidden', 'inbounds', 'void'].indexOf(type) != -1) return;
if (Runtime.isNumberType(type)) return;
+ dprint('types', 'Adding type: ' + type);
// 'blocks': [14 x %struct.X] etc. If this is a pointer, we need
// to look at the underlying type - it was not defined explicitly
@@ -107,6 +110,8 @@ function analyzer(data) {
// check that we never allocate with this (either as a child structure
// in the analyzer, or in calcSize in alloca).
var subType = check[2];
+ addTypeInternal(subType, data); // needed for anonymous structure definitions (see below)
+
Types.types[nonPointing] = {
name_: nonPointing,
fields: range(num).map(function() { return subType }),
@@ -124,6 +129,21 @@ function analyzer(data) {
return;
}
+ // anonymous structure definition, for example |{ i32, i8*, void ()*, i32 }|
+ if (type[0] == '{' || type[0] == '<') {
+ type = nonPointing;
+ var packed = type[0] == '<';
+ Types.types[type] = {
+ name_: type,
+ fields: splitTokenList(tokenize(type.substr(2 + packed, type.length - 4 - 2*packed)).tokens).map(function(segment) {
+ return segment[0].text;
+ }),
+ packed: packed,
+ lineNum: '?'
+ };
+ return;
+ }
+
if (isPointerType(type)) return;
if (['['].indexOf(type) != -1) return;
Types.types[type] = {
@@ -333,7 +353,7 @@ function analyzer(data) {
// Decision time
- var pointedType = removePointing(variable.type);
+ var pointedType = pointingLevels(variable.type) > 0 ? removePointing(variable.type) : null;
if (variable.origin == 'getelementptr') {
// Use our implementation that emulates pointers etc.
// TODO Can we perhaps nativize some of these? However to do so, we need to discover their
@@ -563,7 +583,7 @@ function analyzer(data) {
func.labelsDict[label.ident] = label;
func.labelIds[label.ident] = func.labelIdCounter++;
});
- func.labelIds[toNiceIdent('%entry')] = -1; // entry is always -1
+ func.labelIds[toNiceIdent('%0')] = -1; // entry is always -1
func.hasPhi = false;
func.hasIndirectBr = false;
@@ -575,8 +595,9 @@ function analyzer(data) {
var remarkableLabelId = line.value.params[i].label;
func.remarkableLabels.push(remarkableLabelId);
var remarkableLabel = func.labelsDict[remarkableLabelId];
+ assert(remarkableLabel);
var lastLine = remarkableLabel.lines.slice(-1)[0];
- if (lastLine.value) {
+ if (lastLine.intertype === 'assign') {
lastLine.value.currLabelId = remarkableLabelId;
} else {
lastLine.currLabelId = remarkableLabelId;
diff --git a/src/compiler.js b/src/compiler.js
index 9bf81ba4..1639d4e7 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -79,5 +79,7 @@ raw = null;
// Do it
+//dprint(JSON.stringify(C_DEFINES));
+
JSify(analyzer(intertyper(lines)));
diff --git a/src/dlmalloc.c b/src/dlmalloc.c
index 672ca48d..aa37dc0d 100644
--- a/src/dlmalloc.c
+++ b/src/dlmalloc.c
@@ -2,7 +2,7 @@
#define __THROW
#define __attribute_malloc__
#define __wur
-#include "emscripten.h"
+
/*
This is a version (aka dlmalloc) of malloc/free/realloc written by
diff --git a/src/experimental/noncallgraphprofiling.diff b/src/experimental/noncallgraphprofiling.diff
new file mode 100644
index 00000000..9bceeee9
--- /dev/null
+++ b/src/experimental/noncallgraphprofiling.diff
@@ -0,0 +1,197 @@
+diff --git a/src/jsifier.js b/src/jsifier.js
+index da8c4db..2d606be 100644
+--- a/src/jsifier.js
++++ b/src/jsifier.js
+@@ -432,12 +432,16 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
+ func.JS = '\nfunction ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n';
+
+ if (PROFILE) {
+- func.JS += ' if (PROFILING) { '
+- + 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
+- + 'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };'
+- + 'PROFILING_NODE.calls++; '
+- + 'var __profilingStartTime__ = Date.now() '
+- + '}\n';
++ if (PROFILE_CALLGRAPH) {
++ func.JS += ' if (PROFILING) { '
++ + 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
++ + 'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };'
++ + 'PROFILING_NODE.calls++; '
++ + 'var __profilingStartTime__ = Date.now() '
++ + '}\n';
++ } else {
++ func.JS += ' PROFILING_DATA[' + Profiling.getIndex(func.ident) + '] -= Date.now();';
++ }
+ }
+
+ func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack) + ';\n';
+@@ -733,10 +737,14 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
+ makeFuncLineActor('return', function(item) {
+ var ret = RuntimeGenerator.stackExit(item.funcData.initialStack) + ';\n';
+ if (PROFILE) {
+- ret += 'if (PROFILING) { '
+- + 'PROFILING_NODE.time += Date.now() - __profilingStartTime__; '
+- + 'PROFILING_NODE = __parentProfilingNode__ '
+- + '}\n';
++ if (PROFILE_CALLGRAPH) {
++ ret += 'if (PROFILING) { '
++ + 'PROFILING_NODE.time += Date.now() - __profilingStartTime__; '
++ + 'PROFILING_NODE = __parentProfilingNode__ '
++ + '}\n';
++ } else {
++ ret += 'PROFILING_DATA[' + Profiling.getIndex(item.funcData.ident) + '] += Date.now();'
++ }
+ }
+ if (LABEL_DEBUG) {
+ ret += "print(INDENT + 'Exiting: " + item.funcData.ident + "');\n"
+@@ -945,6 +953,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
+ print(shellParts[0]);
+ var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
+ var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()), CONSTANTS));
++ if (PROFILE && !PROFILE_CALLGRAPH) {
++ pre = pre.replace('{{PROFILING_DATA}}', Profiling.generateIndexing());
++ }
+ print(pre);
+ print('Runtime.QUANTUM_SIZE = ' + QUANTUM_SIZE);
+ if (RUNTIME_TYPE_INFO) {
+diff --git a/src/modules.js b/src/modules.js
+index 20f42f9..624c5ae 100644
+--- a/src/modules.js
++++ b/src/modules.js
+@@ -226,13 +226,15 @@ var Functions = {
+
+ indexedFunctions: [0, 0], // Start at a non-0 (even, see below) value
+
++ skip: true,
++
+ // Mark a function as needing indexing, and returns the index
+ getIndex: function(ident) {
+ var key = this.indexedFunctions.indexOf(ident);
+ if (key < 0) {
+ key = this.indexedFunctions.length;
+ this.indexedFunctions[key] = ident;
+- this.indexedFunctions[key+1] = 0; // Need to have keys be even numbers, see |polymorph| test
++ if (this.skip) this.indexedFunctions[key+1] = 0; // Need to have keys be even numbers, see |polymorph| test
+ }
+ return key.toString();
+ },
+@@ -281,3 +283,19 @@ var LibraryManager = {
+ }
+ };
+
++var Profiling = { // We use the same principle of function hashing as in Functions
++ currFunctions: [],
++ implementedFunctions: null,
++ indexedFunctions: [],
++ getIndex: Functions.getIndex,
++
++ generateIndexing: function() {
++ var ret = 'var PROFILING_DATA = new Array(' + this.indexedFunctions.length + ');\n'
++ + 'for (var i = 0; i < ' + this.indexedFunctions.length + '; i++) {\n'
++ + ' PROFILING_DATA[i] = 0;\n'
++ + '}\n'
++ + 'var PROFILING_NAMES = ' + JSON.stringify(this.indexedFunctions) + ';\n';
++ return ret;
++ }
++};
++
+diff --git a/src/preamble.js b/src/preamble.js
+index 1c1ec91..1bda448 100644
+--- a/src/preamble.js
++++ b/src/preamble.js
+@@ -276,22 +276,26 @@ var START_TIME = Date.now();
+
+ #if PROFILE
+ var PROFILING = 0;
++
++#if PROFILE_CALLGRAPH
+ var PROFILING_ROOT = { time: 0, children: {}, calls: 0 };
+ var PROFILING_NODE;
+-
+ function startProfiling() {
+ PROFILING_NODE = PROFILING_ROOT;
+ PROFILING = 1;
+ }
+ Module['startProfiling'] = startProfiling;
+-
+ function stopProfiling() {
+ PROFILING = 0;
+ assert(PROFILING_NODE === PROFILING_ROOT, 'Must have popped all the profiling call stack');
+ }
+ Module['stopProfiling'] = stopProfiling;
++#else
++{{PROFILING_DATA}}
++#endif
+
+ function printProfiling() {
++#if PROFILE_CALLGRAPH
+ function dumpData(name_, node, indent) {
+ print(indent + ('________' + node.time).substr(-8) + ': ' + name_ + ' (' + node.calls + ')');
+ var children = [];
+@@ -303,9 +307,20 @@ function printProfiling() {
+ children.forEach(function(child) { dumpData(child.name_, child, indent + ' ') });
+ }
+ dumpData('root', PROFILING_ROOT, ' ');
++#else
++ var items = [];
++ for (var i = 0; i < PROFILING_NAMES.length; i++) {
++ items.push({ name_: PROFILING_NAMES[i], time: PROFILING_DATA[i] });
++ }
++ items.sort(function(x, y) { return y.time - x.time });
++ items.forEach(function(item) {
++ print(('________' + item.time).substr(-8) + ': ' + item.name_);
++ });
++#endif
+ }
+ Module['printProfiling'] = printProfiling;
+
++#if PROFILE_CALLGRAPH
+ function printXULProfiling() {
+ function dumpData(name_, node, indent) {
+ var children = [];
+@@ -357,6 +372,7 @@ function printXULProfiling() {
+ }
+ Module['printXULProfiling'] = printXULProfiling;
+ #endif
++#endif
+
+ //========================================
+ // Runtime essentials
+diff --git a/src/settings.js b/src/settings.js
+index ef8b399..749468b 100644
+--- a/src/settings.js
++++ b/src/settings.js
+@@ -114,7 +114,8 @@ AUTO_OPTIMIZE = 0; // When run with the CHECK_* options, will not fail on errors
+ // checking enabled and which do not, that is, this is a way to automate the
+ // generation of line data for CORRECT_*_LINES options
+
+-PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example.
++PROFILE = 1; // Enables runtime profiling. As lightweight as possible.
++PROFILE_CALLGRAPH = 0; // Much heavier profiling, of entire callgraphs.
+
+ EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported, so they are guaranteed to
+ // be accessible outside of the generated code.
+diff --git a/tests/runner.py b/tests/runner.py
+index f7ae9b0..3caedad 100644
+--- a/tests/runner.py
++++ b/tests/runner.py
+@@ -3525,16 +3525,16 @@ if 'benchmark' not in str(sys.argv):
+ def post(filename):
+ src = open(filename, 'a')
+ src.write('''
+- startProfiling();
++ //startProfiling();
+ run();
+- stopProfiling();
++ //stopProfiling();
+ printProfiling();
+ print('*ok*');
+ ''')
+ src.close()
+
+ # Using build_ll_hook forces a recompile, which leads to DFE being done even without opts
+- self.do_test(src, ': __Z6inner1i (5000)\n*ok*', post_build=post)
++ self.do_test(src, ': __Z6inner2i\n*ok*', post_build=post)
+
+ ### Integration tests
+
diff --git a/src/include/emscripten.h b/src/include/emscripten.h
deleted file mode 100644
index b06f3781..00000000
--- a/src/include/emscripten.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * This file contains a few useful things for compiling C/C++ code
- * with Emscripten, an LLVM-to-JavaScript compiler.
- *
- * The code can be used permissively under the MIT license.
- *
- * http://emscripten.org
- */
-
-#undef __i386__
-#undef __x86_64__
-
-// Interface to the underlying JS engine. This function will
-// eval() the given script.
-extern void emscripten_run_script(const char *script);
-
diff --git a/src/intertyper.js b/src/intertyper.js
index 83a49645..74f38e3a 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -2,6 +2,9 @@
// to be processed by the later stages.
var tokenizer; // TODO: Clean this up/out
+function tokenize(text) {
+ return tokenizer.processItem({ lineText: text }, true);
+}
//! @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
@@ -48,8 +51,11 @@ function intertyper(data, parseFunctions, baseLineNum) {
currFunctionLineNum = i + 1;
}
if (!inFunction || parseFunctions) {
- if (inContinual || new RegExp(/^\ +to.*/g).test(line)) {
- // to after invoke
+ if (inContinual || new RegExp(/^\ +to.*/g).test(line)
+ || new RegExp(/^\ +catch .*/g).test(line)
+ || new RegExp(/^\ +filter .*/g).test(line)
+ || new RegExp(/^\ +cleanup.*/g).test(line)) {
+ // to after invoke or landingpad second line
ret.slice(-1)[0].lineText += line;
if (new RegExp(/^\ +\]/g).test(line)) { // end of llvm switch
inContinual = false;
@@ -137,13 +143,15 @@ function intertyper(data, parseFunctions, baseLineNum) {
// merge certain tokens
if (lastToken && isType(lastToken.text) && isFunctionDef(token)) {
lastToken.text += ' ' + text;
- } else if (lastToken && text[text.length-1] == '}') {
+ } else if (lastToken && /^}\**$/.exec(text)) { // }, }*, etc.
var openBrace = tokens.length-1;
- while (tokens[openBrace].text != '{') openBrace --;
+ while (tokens[openBrace].text.substr(-1) != '{') openBrace --;
token = combineTokens(tokens.slice(openBrace+1));
tokens.splice(openBrace, tokens.length-openBrace+1);
tokens.push(token);
token.type = '{';
+ token.text = '{ ' + token.text + ' }';
+ while (pointingLevels(text) > pointingLevels(token.text)) token.text += '*'; // TODO: optimize
lastToken = token;
} else {
tokens.push(token);
@@ -265,6 +273,8 @@ function intertyper(data, parseFunctions, baseLineNum) {
return 'Unreachable';
if (tokensLength >= 3 && token0Text == 'indirectbr')
return 'IndirectBr';
+ if (tokensLength >= 2 && token0Text == 'resume')
+ return 'Resume';
} else if (item.indent === -1) {
if (tokensLength >= 3 &&
(token0Text == 'load' || token1Text == 'load'))
@@ -280,8 +290,12 @@ function intertyper(data, parseFunctions, baseLineNum) {
return 'Alloca';
if (tokensLength >= 3 && token0Text == 'extractvalue')
return 'ExtractValue';
+ if (tokensLength >= 3 && token0Text == 'insertvalue')
+ return 'InsertValue';
if (tokensLength >= 3 && token0Text == 'phi')
return 'Phi';
+ if (tokensLength >= 3 && token0Text == 'landingpad')
+ return 'Landingpad';
} else if (item.indent === 0) {
if ((tokensLength >= 1 && token0Text.substr(-1) == ':') || // LLVM 2.7 format, or llvm-gcc in 2.8
(tokensLength >= 3 && token1Text == '<label>'))
@@ -320,6 +334,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
processItem: function(item) {
function scanConst(value, type) {
//dprint('inter-const: ' + item.lineNum + ' : ' + JSON.stringify(value) + ',' + type + '\n');
+ Types.needAnalysis[type] = 0;
if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) {
return { value: toNiceIdent(value.text), type: type };
} else if (value.text in set('zeroinitializer', 'undef')) { // undef doesn't really need initting, but why not
@@ -334,16 +349,21 @@ function intertyper(data, parseFunctions, baseLineNum) {
if (segment[1].text == 'null') {
return { intertype: 'value', value: 0, type: 'i32' };
} else if (segment[1].text == 'zeroinitializer') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'emptystruct', type: segment[0].text };
} else if (segment[1].text in PARSABLE_LLVM_FUNCTIONS) {
return parseLLVMFunctionCall(segment);
} else if (segment[1].type && segment[1].type == '{') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'struct', type: segment[0].text, contents: handleSegments(segment[1].tokens) };
} else if (segment[1].type && segment[1].type == '<') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'struct', type: segment[0].text, contents: handleSegments(segment[1].item.tokens[0].tokens) };
} else if (segment[1].type && segment[1].type == '[') {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'list', type: segment[0].text, contents: handleSegments(segment[1].item.tokens) };
} else if (segment.length == 2) {
+ Types.needAnalysis[segment[0].text] = 0;
return { intertype: 'value', type: segment[0].text, value: toNiceIdent(segment[1].text) };
} else if (segment[1].text === 'c') {
// string
@@ -377,16 +397,20 @@ function intertyper(data, parseFunctions, baseLineNum) {
}
}
+ cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 2);
if (item.tokens[2].text == 'alias') {
- cleanOutTokensSet(LLVM.LINKAGES, item.tokens, 3);
- cleanOutTokensSet(LLVM.VISIBILITIES, item.tokens, 3);
- return [{
+ cleanOutTokens(LLVM.LINKAGES, item.tokens, 3);
+ cleanOutTokens(LLVM.VISIBILITIES, item.tokens, 3);
+ var last = getTokenIndexByText(item.tokens, ';');
+ var ret = {
intertype: 'alias',
ident: toNiceIdent(item.tokens[0].text),
- aliasee: toNiceIdent(item.tokens[4].text),
- type: item.tokens[3].text,
+ value: parseLLVMSegment(item.tokens.slice(3, last)),
lineNum: item.lineNum
- }];
+ };
+ ret.type = ret.value.type;
+ Types.needAnalysis[ret.type] = 0;
+ return [ret];
}
if (item.tokens[2].text == 'type') {
var fields = [];
@@ -397,7 +421,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
} else if (item.tokens[3].text != 'opaque') {
if (item.tokens[3].type == '<') {
packed = true;
- item.tokens[3] = tokenizer.processItem({ lineText: '{ ' + item.tokens[3].item.tokens[0].text + ' }' }, true).tokens[0];
+ item.tokens[3] = item.tokens[3].item.tokens[0];
}
var subTokens = item.tokens[3].tokens;
subTokens.push({text:','});
@@ -418,13 +442,13 @@ function intertyper(data, parseFunctions, baseLineNum) {
} else {
// variable
var ident = item.tokens[0].text;
- cleanOutTokensSet(LLVM.GLOBAL_MODIFIERS, item.tokens, 3);
- cleanOutTokensSet(LLVM.GLOBAL_MODIFIERS, item.tokens, 2);
+ cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]);
var external = false;
if (item.tokens[2].text === 'external') {
external = true;
item.tokens.splice(2, 1);
}
+ Types.needAnalysis[item.tokens[2].text] = 0;
var ret = {
intertype: 'globalVariable',
ident: toNiceIdent(ident),
@@ -515,7 +539,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
substrate.addActor('Load', {
processItem: function(item) {
item.intertype = 'load';
- if (item.tokens[0].text == 'volatile') item.tokens.shift(0);
+ cleanOutTokens(LLVM.ACCESS_OPTIONS, item.tokens, [0, 1]);
item.pointerType = item.tokens[1].text;
item.valueType = item.type = removePointing(item.pointerType);
Types.needAnalysis[item.type] = 0;
@@ -537,6 +561,20 @@ function intertyper(data, parseFunctions, baseLineNum) {
this.forwardItem(item, 'Reintegrator');
}
});
+ // 'insertvalue'
+ substrate.addActor('InsertValue', {
+ processItem: function(item) {
+ var last = getTokenIndexByText(item.tokens, ';');
+ item.intertype = 'insertvalue';
+ item.type = item.tokens[1].text; // Of the origin aggregate, as well as the result
+ Types.needAnalysis[item.type] = 0;
+ item.ident = toNiceIdent(item.tokens[2].text);
+ var segments = splitTokenList(item.tokens.slice(4, last));
+ item.value = parseLLVMSegment(segments[0]);
+ item.indexes = segments.slice(1);
+ this.forwardItem(item, 'Reintegrator');
+ }
+ });
// 'bitcast'
substrate.addActor('Bitcast', {
processItem: function(item) {
@@ -556,6 +594,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
processItem: function(item) {
var first = 0;
while (!isType(item.tokens[first].text)) first++;
+ Types.needAnalysis[item.tokens[first].text] = 0;
var last = getTokenIndexByText(item.tokens, ';');
var segment = [ item.tokens[first], { text: 'getelementptr' }, null, { item: {
tokens: item.tokens.slice(first, last)
@@ -574,7 +613,6 @@ function intertyper(data, parseFunctions, baseLineNum) {
if (['tail'].indexOf(item.tokens[0].text) != -1) {
item.tokens.splice(0, 1);
}
- assertEq(item.tokens[0].text, type);
while (item.tokens[1].text in LLVM.PARAM_ATTR || item.tokens[1].text in LLVM.CALLING_CONVENTIONS) {
item.tokens.splice(1, 1);
}
@@ -607,26 +645,47 @@ function intertyper(data, parseFunctions, baseLineNum) {
}
item.ident = toNiceIdent(item.ident);
if (type === 'invoke') {
- cleanOutTokens(['alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq'], item.tokens, 4);
- item.toLabel = toNiceIdent(item.tokens[6].text);
- item.unwindLabel = toNiceIdent(item.tokens[9].text);
+ var toIndex = findTokenText(item, 'to');
+ item.toLabel = toNiceIdent(item.tokens[toIndex+2].text);
+ item.unwindLabel = toNiceIdent(item.tokens[toIndex+5].text);
+ assert(item.toLabel && item.unwindLabel);
}
if (item.indent == 2) {
// standalone call - not in assign
item.standalone = true;
- return [item];
+ return { forward: null, ret: [item], item: item };
}
- this.forwardItem(item, 'Reintegrator');
- return null;
+ return { forward: item, ret: [], item: item };
}
substrate.addActor('Call', {
processItem: function(item) {
- return makeCall.call(this, item, 'call');
+ var result = makeCall.call(this, item, 'call');
+ if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
+ return result.ret;
}
});
substrate.addActor('Invoke', {
processItem: function(item) {
- return makeCall.call(this, item, 'invoke');
+ var result = makeCall.call(this, item, 'invoke');
+ if (DISABLE_EXCEPTION_CATCHING) {
+ result.item.intertype = 'call';
+ result.ret.push({
+ intertype: 'branch',
+ label: result.item.toLabel,
+ lineNum: (result.forward ? item.parentLineNum : item.lineNum) + 0.5
+ });
+ }
+ if (result.forward) this.forwardItem(result.forward, 'Reintegrator');
+ return result.ret;
+ }
+ });
+ // 'landingpad' - just a stub implementation
+ substrate.addActor('Landingpad', {
+ processItem: function(item) {
+ item.intertype = 'landingpad';
+ item.type = item.tokens[1].text;
+ Types.needAnalysis[item.type] = 0;
+ this.forwardItem(item, 'Reintegrator');
}
});
// 'alloca'
@@ -704,7 +763,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
// 'store'
substrate.addActor('Store', {
processItem: function(item) {
- if (item.tokens[0].text == 'volatile') item.tokens.shift(0);
+ cleanOutTokens(LLVM.ACCESS_OPTIONS, item.tokens, [0, 1]);
var segments = splitTokenList(item.tokens.slice(1));
var ret = {
intertype: 'store',
@@ -733,7 +792,7 @@ function intertyper(data, parseFunctions, baseLineNum) {
var commaIndex = findTokenText(item, ',');
return [{
intertype: 'branch',
- condition: parseLLVMSegment(item.tokens.slice(1, commaIndex)),
+ value: parseLLVMSegment(item.tokens.slice(1, commaIndex)),
labelTrue: toNiceIdent(item.tokens[commaIndex+2].text),
labelFalse: toNiceIdent(item.tokens[commaIndex+5].text),
lineNum: item.lineNum
@@ -754,6 +813,15 @@ function intertyper(data, parseFunctions, baseLineNum) {
}];
}
});
+ // 'resume' - partial implementation
+ substrate.addActor('Resume', {
+ processItem: function(item) {
+ return [{
+ intertype: 'resume',
+ lineNum: item.lineNum
+ }];
+ }
+ });
// 'switch'
substrate.addActor('Switch', {
processItem: function(item) {
diff --git a/src/jsifier.js b/src/jsifier.js
index 9a2a82c4..cd59d43c 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -26,6 +26,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
ident: '_' + ident
});
});
+
+ Functions.implementedFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident }));
}
// Does simple 'macro' substitution, using Django-like syntax,
@@ -279,17 +281,18 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
item.intertype = 'GlobalVariableStub';
var ret = [item];
item.JS = 'var ' + item.ident + ';';
- // Set the actual value in a postset, since it may be a global variable. TODO: handle alias of alias (needs ordering)
+ // Set the actual value in a postset, since it may be a global variable. We also order by dependencies there
+ var value = finalizeLLVMParameter(item.value, true); // do *not* indexize functions here
ret.push({
intertype: 'GlobalVariablePostSet',
- JS: item.ident + ' = ' + item.aliasee + ';'
+ ident: item.ident,
+ dependencies: set([value]),
+ JS: item.ident + ' = ' + value + ';'
});
return ret;
}
});
- var moduleFunctions = set(data.unparsedFunctions.map(function(func) { return func.ident }));
-
var addedLibraryItems = {};
// functionStub
@@ -305,7 +308,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
if (ident in addedLibraryItems) return '';
// Don't replace implemented functions with library ones (which can happen when we add dependencies).
// Note: We don't return the dependencies here. Be careful not to end up where this matters
- if (('_' + ident) in moduleFunctions) return '';
+ if (('_' + ident) in Functions.implementedFunctions) return '';
addedLibraryItems[ident] = true;
var snippet = LibraryManager.library[ident];
@@ -338,8 +341,14 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
} else if (typeof snippet === 'function') {
isFunction = true;
snippet = snippet.toString();
+ assert(snippet.indexOf('XXX missing C define') == -1,
+ 'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet);
+
// name the function; overwrite if it's already named
snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '(');
+ if (LIBRARY_DEBUG) {
+ snippet = snippet.replace('{', '{ print("[library call:' + ident + ']"); ');
+ }
}
var postsetId = ident + '__postset';
@@ -425,6 +434,15 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
func.JS = '\nfunction ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n';
+ if (PROFILE) {
+ func.JS += ' if (PROFILING) { '
+ + 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
+ + 'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };'
+ + 'PROFILING_NODE.calls++; '
+ + 'var __profilingStartTime__ = Date.now() '
+ + '}\n';
+ }
+
func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack) + ';\n';
if (LABEL_DEBUG) func.JS += " print(INDENT + ' Entering: " + func.ident + "'); INDENT += ' ';\n";
@@ -540,7 +558,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
function getVarImpl(funcData, ident) {
- if (ident === 'null') return VAR_NATIVIZED; // like nativized, in that we have the actual value right here
+ if (ident === 'null' || isNumber(ident)) return VAR_NATIVIZED; // like nativized, in that we have the actual value right here
var data = getVarData(funcData, ident);
assert(data, 'What variable is this? |' + ident + '|');
return data.impl;
@@ -674,10 +692,10 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
makeFuncLineActor('branch', function(item) {
if (item.stolen) return ';'; // We will appear where we were stolen to
- if (!item.condition) {
+ if (!item.value) {
return makeBranch(item.label, item.currLabelId);
} else {
- var condition = finalizeLLVMParameter(item.condition);
+ var condition = finalizeLLVMParameter(item.value);
var labelTrue = makeBranch(item.labelTrue, item.currLabelId);
var labelFalse = makeBranch(item.labelFalse, item.currLabelId);
if (labelTrue == ';' && labelFalse == ';') return ';';
@@ -707,9 +725,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
ret += ' ' + makeBranch(switchLabel.label, item.currLabelId || null) + '\n';
ret += '}\n';
});
- ret += 'else {\n';
+ if (item.switchLabels.length > 0) ret += 'else {\n';
ret += makeBranch(item.defaultLabel, item.currLabelId) + '\n';
- ret += '}\n';
+ if (item.switchLabels.length > 0) ret += '}\n';
if (item.value) {
ret += ' ' + toNiceIdent(item.value);
}
@@ -717,6 +735,12 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
});
makeFuncLineActor('return', function(item) {
var ret = RuntimeGenerator.stackExit(item.funcData.initialStack) + ';\n';
+ if (PROFILE) {
+ ret += 'if (PROFILING) { '
+ + 'PROFILING_NODE.time += Date.now() - __profilingStartTime__; '
+ + 'PROFILING_NODE = __parentProfilingNode__ '
+ + '}\n';
+ }
if (LABEL_DEBUG) {
ret += "print(INDENT + 'Exiting: " + item.funcData.ident + "');\n"
+ "INDENT = INDENT.substr(0, INDENT.length-2);\n";
@@ -727,12 +751,14 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
return ret + ';';
});
+ makeFuncLineActor('resume', function(item) {
+ return (EXCEPTION_DEBUG ? 'print("Resuming exception");' : '') + 'throw [0,0];';
+ });
makeFuncLineActor('invoke', function(item) {
// Wrapping in a function lets us easily return values if we are
// in an assignment
var call_ = makeFunctionCall(item.ident, item.params, item.funcData);
var branch = makeBranch(item.toLabel, item.currLabelId);
- if (DISABLE_EXCEPTIONS) return call_ + '; ' + branch;
var ret = '(function() { try { __THREW__ = false; return '
+ call_ + ' '
+ '} catch(e) { '
@@ -743,6 +769,10 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
+ ' } else { ' + makeBranch(item.unwindLabel, item.currLabelId) + ' }';
return ret;
});
+ makeFuncLineActor('landingpad', function(item) {
+ // Just a stub
+ return '{ f0: 0, f1: 0 }';
+ });
makeFuncLineActor('load', function(item) {
var value = finalizeLLVMParameter(item.pointer);
var impl = item.ident ? getVarImpl(item.funcData, item.ident) : VAR_EMULATED;
@@ -759,6 +789,15 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
// and we emulate them using simple JS objects { f1: , f2: , } etc., for speed
return item.ident + '.f' + item.indexes[0][0].text;
});
+ makeFuncLineActor('insertvalue', function(item) {
+ assert(item.indexes.length == 1); // TODO: see extractvalue
+ var ret = '(', ident;
+ if (item.ident === 'undef') {
+ item.ident = 'tempValue';
+ ret += item.ident + ' = [' + makeEmptyStruct(item.type) + '], ';
+ }
+ return ret + item.ident + '.f' + item.indexes[0][0].text + ' = ' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')';
+ });
makeFuncLineActor('indirectbr', function(item) {
return makeBranch(finalizeLLVMParameter(item.pointer), item.currLabelId, true);
});
@@ -841,6 +880,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
}
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
makeFuncLineActor('call', function(item) {
+ if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';';
return makeFunctionCall(item.ident, item.params, item.funcData) + (item.standalone ? ';' : '');
});
@@ -853,11 +893,34 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
var itemsDict = { type: [], GlobalVariableStub: [], functionStub: [], function: [], GlobalVariable: [], GlobalVariablePostSet: [] };
items.forEach(function(item) {
item.lines = null;
- var small = { intertype: item.intertype, JS: item.JS }; // Release memory
+