summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library_gl.js31
-rw-r--r--src/preamble.js3
-rw-r--r--src/relooper/Relooper.h10
-rw-r--r--tools/js-optimizer.js44
-rw-r--r--tools/js_optimizer.py32
5 files changed, 71 insertions, 49 deletions
diff --git a/src/library_gl.js b/src/library_gl.js
index 075d7cb5..19e64c32 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -1777,7 +1777,10 @@ var LibraryGL = {
// skipping renderer setup is aimed at the case of multiple glDraw* right after each other
if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
if (cap == 0x0B60 /* GL_FOG */) {
- GLEmulation.fogEnabled = true;
+ if (GLEmulation.fogEnabled != true) {
+ GL.immediate.currentRenderer = null; // Fog parameter is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogEnabled = true;
+ }
return;
} else if (cap == 0x0de1 /* GL_TEXTURE_2D */) {
// XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
@@ -1797,7 +1800,10 @@ var LibraryGL = {
_glDisable = function _glDisable(cap) {
if (GL.immediate.lastRenderer) GL.immediate.lastRenderer.cleanup();
if (cap == 0x0B60 /* GL_FOG */) {
- GLEmulation.fogEnabled = false;
+ if (GLEmulation.fogEnabled != false) {
+ GL.immediate.currentRenderer = null; // Fog parameter is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogEnabled = false;
+ }
return;
} else if (cap == 0x0de1 /* GL_TEXTURE_2D */) {
// XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support
@@ -2104,7 +2110,7 @@ var LibraryGL = {
}
#endif
if (GL.currProgram != program) {
- GL.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
+ GL.immediate.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
GL.currProgram = program;
}
glUseProgram(program);
@@ -2113,7 +2119,10 @@ var LibraryGL = {
var glDeleteProgram = _glDeleteProgram;
_glDeleteProgram = function _glDeleteProgram(program) {
glDeleteProgram(program);
- if (program == GL.currProgram) GL.currProgram = 0;
+ if (program == GL.currProgram) {
+ GL.immediate.currentRenderer = null; // This changes the FFP emulation shader program, need to recompute that.
+ GL.currProgram = 0;
+ }
};
// If attribute 0 was not bound, bind it to 0 for WebGL performance reasons. Track if 0 is free for that.
@@ -4270,7 +4279,7 @@ var LibraryGL = {
// Pop the old state:
GL.immediate.enabledClientAttributes = GL.immediate.enabledClientAttributes_preBegin;
GL.immediate.clientAttributes = GL.immediate.clientAttributes_preBegin;
-
+ GL.immediate.currentRenderer = null; // The set of active client attributes changed, we must re-lookup the renderer to use.
GL.immediate.modifiedClientAttributes = true;
},
@@ -4409,9 +4418,17 @@ var LibraryGL = {
switch (param) {
case 0x0801: // GL_EXP2
case 0x2601: // GL_LINEAR
- GLEmulation.fogMode = param; break;
+ if (GLEmulation.fogMode != param) {
+ GL.immediate.currentRenderer = null; // Fog mode is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogMode = param;
+ }
+ break;
default: // default to GL_EXP
- GLEmulation.fogMode = 0x0800 /* GL_EXP */; break;
+ if (GLEmulation.fogMode != 0x0800 /* GL_EXP */) {
+ GL.immediate.currentRenderer = null; // Fog mode is part of the FFP shader state, we must re-lookup the renderer to use.
+ GLEmulation.fogMode = 0x0800 /* GL_EXP */;
+ }
+ break;
}
break;
}
diff --git a/src/preamble.js b/src/preamble.js
index f9fccdf6..ac6ee7b3 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -1090,7 +1090,8 @@ Module['writeAsciiToMemory'] = writeAsciiToMemory;
{{{ reSign }}}
#if PRECISE_I32_MUL
-if (!Math['imul']) Math['imul'] = function imul(a, b) {
+// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
+if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
var ah = a >>> 16;
var al = a & 0xffff;
var bh = b >>> 16;
diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h
index 04f2ffc3..dfabcabb 100644
--- a/src/relooper/Relooper.h
+++ b/src/relooper/Relooper.h
@@ -89,11 +89,11 @@ struct Block {
// setjmp returns, etc.)
//
-class SimpleShape;
-class LabeledShape;
-class MultipleShape;
-class LoopShape;
-class EmulatedShape;
+struct SimpleShape;
+struct LabeledShape;
+struct MultipleShape;
+struct LoopShape;
+struct EmulatedShape;
struct Shape {
int Id; // A unique identifier. Used to identify loops, labels are Lx where x is the Id. Defined when added to relooper
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index b507a45a..5324e15c 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1743,6 +1743,36 @@ function getStackBumpSize(ast) {
return node ? node[3][2][3][1] : 0;
}
+// Name minification
+
+var RESERVED = set('do', 'if', 'in', 'for', 'new', 'try', 'var', 'env', 'let');
+var VALID_MIN_INITS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
+var VALID_MIN_LATERS = VALID_MIN_INITS + '0123456789';
+
+var minifiedNames = [];
+var minifiedState = [0];
+
+function ensureMinifiedNames(n) { // make sure the nth index in minifiedNames exists. done 100% deterministically
+ while (minifiedNames.length < n+1) {
+ // generate the current name
+ var name = VALID_MIN_INITS[minifiedState[0]];
+ for (var i = 1; i < minifiedState.length; i++) {
+ name += VALID_MIN_LATERS[minifiedState[i]];
+ }
+ if (!(name in RESERVED)) minifiedNames.push(name);
+ // increment the state
+ var i = 0;
+ while (1) {
+ minifiedState[i]++;
+ if (minifiedState[i] < (i === 0 ? VALID_MIN_INITS : VALID_MIN_LATERS).length) break;
+ // overflow
+ minifiedState[i] = 0;
+ i++;
+ if (i === minifiedState.length) minifiedState.push(-1); // will become 0 after increment in next loop head
+ }
+ }
+}
+
// Very simple 'registerization', coalescing of variables into a smaller number,
// as part of minification. Globals-level minification began in a previous pass,
// we receive extraInfo which tells us how to rename globals. (Only in asm.js.)
@@ -1853,14 +1883,14 @@ function registerize(ast) {
return ret;
}
// find the next free minified name that is not used by a global that shows up in this function
- while (nextRegName < extraInfo.names.length) {
- var ret = extraInfo.names[nextRegName++];
+ while (1) {
+ ensureMinifiedNames(nextRegName);
+ var ret = minifiedNames[nextRegName++];
if (!usedGlobals[ret]) {
regTypes[ret] = type;
return ret;
}
}
- assert('ran out of names');
}
// Find the # of uses of each variable.
// While doing so, check if all a variable's uses are dominated in a simple
@@ -2847,16 +2877,16 @@ function minifyGlobals(ast) {
var vars = node[1];
for (var i = 0; i < vars.length; i++) {
var name = vars[i][0];
- assert(next < extraInfo.names.length);
- vars[i][0] = minified[name] = extraInfo.names[next++];
+ ensureMinifiedNames(next);
+ vars[i][0] = minified[name] = minifiedNames[next++];
}
}
});
// add all globals in function chunks, i.e. not here but passed to us
for (var i = 0; i < extraInfo.globals.length; i++) {
name = extraInfo.globals[i];
- assert(next < extraInfo.names.length);
- minified[name] = extraInfo.names[next++];
+ ensureMinifiedNames(next);
+ minified[name] = minifiedNames[next++];
}
// apply minification
traverse(ast, function(node, type) {
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index dcc9cd5f..d5b1df27 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -24,41 +24,16 @@ import_sig = re.compile('var ([_\w$]+) *=[^;]+;')
class Minifier:
'''
- asm.js minification support. We calculate possible names and minification of
+ asm.js minification support. We calculate minification of
globals here, then pass that into the parallel js-optimizer.js runners which
during registerize perform minification of locals.
'''
- def __init__(self, js, js_engine, MAX_NAMES):
+ def __init__(self, js, js_engine):
self.js = js
self.js_engine = js_engine
- MAX_NAMES = min(MAX_NAMES, 120000)
-
- # Create list of valid short names
-
- INVALID_2 = set(['do', 'if', 'in'])
- INVALID_3 = set(['for', 'new', 'try', 'var', 'env', 'let'])
-
- self.names = []
- init_possibles = string.ascii_letters + '_$'
- later_possibles = init_possibles + string.digits
- for a in init_possibles:
- if len(self.names) >= MAX_NAMES: break
- self.names.append(a)
- for a in init_possibles:
- for b in later_possibles:
- if len(self.names) >= MAX_NAMES: break
- curr = a + b
- if curr not in INVALID_2: self.names.append(curr)
- for a in init_possibles:
- for b in later_possibles:
- for c in later_possibles:
- if len(self.names) >= MAX_NAMES: break
- curr = a + b + c
- if curr not in INVALID_3: self.names.append(curr)
def minify_shell(self, shell, minify_whitespace, source_map=False):
- #print >> sys.stderr, "MINIFY SHELL 1111111111", shell, "\n222222222222222"
# Run through js-optimizer.js to find and minify the global symbols
# We send it the globals, which it parses at the proper time. JS decides how
# to minify all global names, we receive a dictionary back, which is then
@@ -91,7 +66,6 @@ class Minifier:
def serialize(self):
return {
- 'names': self.names,
'globals': self.globs
}
@@ -187,7 +161,7 @@ EMSCRIPTEN_FUNCS();
js = js[start_funcs + len(start_funcs_marker):end_funcs]
# we assume there is a maximum of one new name per line
- minifier = Minifier(js, js_engine, js.count('\n') + asm_shell.count('\n'))
+ minifier = Minifier(js, js_engine)
asm_shell_pre, asm_shell_post = minifier.minify_shell(asm_shell, 'minifyWhitespace' in passes, source_map).split('EMSCRIPTEN_FUNCS();');
asm_shell_post = asm_shell_post.replace('});', '})');
pre += asm_shell_pre + '\n' + start_funcs_marker