aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js5
-rw-r--r--src/compiler.js1
-rw-r--r--src/intertyper.js23
-rw-r--r--src/jsifier.js18
-rw-r--r--src/library_gl.js12
-rw-r--r--src/modules.js4
-rw-r--r--src/preamble.js17
-rw-r--r--src/runtime.js2
-rw-r--r--src/settings.js8
9 files changed, 65 insertions, 25 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 209e3140..926ac9d3 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -231,9 +231,10 @@ function analyzer(data, sidePass) {
}
if (isIllegalType(item.valueType) || isIllegalType(item.type)) {
isIllegal = true;
- }
- if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) {
+ } else if ((item.intertype == 'load' || item.intertype == 'store') && isStructType(item.valueType)) {
isIllegal = true; // storing an entire structure is illegal
+ } else if (item.intertype == 'mathop' && item.op == 'trunc' && isIllegalType(item.params[1].ident)) { // trunc stores target value in second ident
+ isIllegal = true;
}
});
if (!isIllegal) {
diff --git a/src/compiler.js b/src/compiler.js
index 3047daf1..447d34b7 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -163,6 +163,7 @@ if (SAFE_HEAP >= 2) {
EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS);
EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);
EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST);
+DEAD_FUNCTIONS = set(DEAD_FUNCTIONS);
RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;
diff --git a/src/intertyper.js b/src/intertyper.js
index 2103ecfa..57e3011d 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -122,16 +122,19 @@ function intertyper(data, sidePass, baseLineNums) {
SKIP_STACK_IN_SMALL = 0;
}
- unparsedBundles.push({
- intertype: 'unparsedFunction',
- // We need this early, to know basic function info - ident, params, varargs
- ident: toNiceIdent(func.ident),
- params: func.params,
- returnType: func.returnType,
- hasVarArgs: func.hasVarArgs,
- lineNum: currFunctionLineNum,
- lines: currFunctionLines
- });
+ var ident = toNiceIdent(func.ident);
+ if (!(ident in DEAD_FUNCTIONS)) {
+ unparsedBundles.push({
+ intertype: 'unparsedFunction',
+ // We need this early, to know basic function info - ident, params, varargs
+ ident: ident,
+ params: func.params,
+ returnType: func.returnType,
+ hasVarArgs: func.hasVarArgs,
+ lineNum: currFunctionLineNum,
+ lines: currFunctionLines
+ });
+ }
currFunctionLines = [];
}
}
diff --git a/src/jsifier.js b/src/jsifier.js
index ff58ece2..1662d249 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -600,6 +600,10 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
+ if (PGO) {
+ func.JS += ' PGOMonitor.called["' + func.ident + '"] = 1;\n';
+ }
+
if (ASM_JS) {
// spell out argument types
func.params.forEach(function(param) {
@@ -1587,11 +1591,17 @@ function JSify(data, functionsOnly, givenFunctions) {
var shellParts = read(shellFile).split('{{BODY}}');
print(shellParts[1]);
- // Print out some useful metadata (for additional optimizations later, like the eliminator)
- if (EMIT_GENERATED_FUNCTIONS) {
- print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) {
+ // Print out some useful metadata
+ if (EMIT_GENERATED_FUNCTIONS || PGO) {
+ var generatedFunctions = JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) {
return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
- })) + '\n');
+ }));
+ if (PGO) {
+ print('PGOMonitor.allGenerated = ' + generatedFunctions + ';\nremoveRunDependency("pgo");\n');
+ }
+ if (EMIT_GENERATED_FUNCTIONS) {
+ print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + generatedFunctions + '\n');
+ }
}
PassManager.serialize();
diff --git a/src/library_gl.js b/src/library_gl.js
index c6007809..b978e931 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -291,9 +291,9 @@ var LibraryGL = {
} while (used.indexOf(buf) >= 0);
used.push(buf);
Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf);
- Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER,
- HEAPU8.subarray(cb.ptr, cb.ptr + size),
- Module.ctx.DYNAMIC_DRAW);
+ Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER,
+ 0,
+ HEAPU8.subarray(cb.ptr, cb.ptr + size));
Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0);
}
},
@@ -2939,9 +2939,9 @@ var LibraryGL = {
var size = GL.calcBufLength(1, type, 0, count);
buf = GL.tempIndexBuffers[GL.tempBufferIndexLookup[size]];
Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, buf);
- Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER,
- HEAPU8.subarray(indices, indices + size),
- Module.ctx.DYNAMIC_DRAW);
+ Module.ctx.bufferSubData(Module.ctx.ELEMENT_ARRAY_BUFFER,
+ 0,
+ HEAPU8.subarray(indices, indices + size));
// the index is now 0
indices = 0;
}
diff --git a/src/modules.js b/src/modules.js
index 797d4d83..65b8d437 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -291,7 +291,7 @@ var Functions = {
var sig = ASM_JS ? Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig'] : 'x';
assert(sig, ident);
if (!tables[sig]) tables[sig] = emptyTable(sig); // TODO: make them compact
- tables[sig][this.indexedFunctions[ident]] = ident;
+ tables[sig][this.indexedFunctions[ident]] = ident in DEAD_FUNCTIONS ? '0' : ident;
}
var generated = false;
var wrapped = {};
@@ -315,7 +315,7 @@ var Functions = {
}
if (ASM_JS) {
var curr = table[i];
- if (curr && !Functions.implementedFunctions[curr]) {
+ if (curr && curr != '0' && !Functions.implementedFunctions[curr]) {
// This is a library function, we can't just put it in the function table, need a wrapper
if (!wrapped[curr]) {
var args = '', arg_coercions = '', call = curr + '(', retPre = '', retPost = '';
diff --git a/src/preamble.js b/src/preamble.js
index 9bc68d8f..7538b19c 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -848,5 +848,22 @@ Module['removeRunDependency'] = removeRunDependency;
Module["preloadedImages"] = {}; // maps url to image data
Module["preloadedAudios"] = {}; // maps url to audio data
+#if PGO
+var PGOMonitor = {
+ called: {},
+ dump: function() {
+ var dead = [];
+ for (var i = 0; i < this.allGenerated.length; i++) {
+ var func = this.allGenerated[i];
+ if (!this.called[func]) dead.push(func);
+ }
+ Module.print('-s DEAD_FUNCTIONS=\'' + JSON.stringify(dead) + '\'\n');
+ }
+};
+__ATEXIT__.push({ func: function() { PGOMonitor.dump() } });
+if (!Module.preRun) Module.preRun = [];
+Module.preRun.push(function() { addRunDependency('pgo') });
+#endif
+
// === Body ===
diff --git a/src/runtime.js b/src/runtime.js
index dc604a8d..8352ade1 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -87,7 +87,7 @@ var RuntimeGenerator = {
};
function unInline(name_, params) {
- var src = '(function ' + name_ + '(' + params + ') { var ret = ' + RuntimeGenerator[name_].apply(null, params) + '; return ret; })';
+ var src = '(function(' + params + ') { var ret = ' + RuntimeGenerator[name_].apply(null, params) + '; return ret; })';
var ret = eval(src);
return ret;
}
diff --git a/src/settings.js b/src/settings.js
index 440d5094..101c403c 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -332,6 +332,14 @@ var ASM_JS = 0; // If 1, generate code in asm.js format. XXX This is highly expe
// and will not work on most codebases yet. It is NOT recommended that you
// try this yet.
+var PGO = 0; // Enables profile-guided optimization in the form of runtime checks for
+ // which functions are actually called. Emits a list during shutdown that you
+ // can pass to DEAD_FUNCTIONS (you can also emit the list manually by
+ // calling PGOMonitor.dump());
+var DEAD_FUNCTIONS = []; // A list of functions that no code will be emitted for, and
+ // a runtime abort will happen if they are called
+ // TODO: options to lazily load such functions
+
var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?:
var NECESSARY_BLOCKADDRS = []; // List of (function, block) for all block addresses that are taken.