diff options
-rw-r--r-- | src/library_gl.js | 31 | ||||
-rw-r--r-- | src/preamble.js | 3 | ||||
-rw-r--r-- | src/relooper/Relooper.h | 10 | ||||
-rw-r--r-- | tools/js-optimizer.js | 44 | ||||
-rw-r--r-- | tools/js_optimizer.py | 32 |
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 |