@@ -1773,9 +1773,7 @@ function ensureMinifiedNames(n) { // make sure the nth index in minifiedNames ex
1773
1773
}
1774
1774
}
1775
1775
1776
- // Very simple 'registerization', coalescing of variables into a smaller number,
1777
- // as part of minification. Globals-level minification began in a previous pass,
1778
- // we receive extraInfo which tells us how to rename globals. (Only in asm.js.)
1776
+ // Very simple 'registerization', coalescing of variables into a smaller number.
1779
1777
//
1780
1778
// We do not optimize when there are switches, so this pass only makes sense with
1781
1779
// relooping.
@@ -1811,6 +1809,7 @@ function registerize(ast) {
1811
1809
// Replace all var definitions with assignments; we will add var definitions at the top after we registerize
1812
1810
// We also mark local variables - i.e., having a var definition
1813
1811
var localVars = { } ;
1812
+ var allVars = { } ;
1814
1813
var hasSwitch = false ; // we cannot optimize variables if there is a switch, unless in asm mode
1815
1814
traverse ( fun , function ( node , type ) {
1816
1815
if ( type === 'var' ) {
@@ -1823,74 +1822,25 @@ function registerize(ast) {
1823
1822
}
1824
1823
} else if ( type === 'switch' ) {
1825
1824
hasSwitch = true ;
1825
+ } else if ( type === 'name' ) {
1826
+ allVars [ node [ 1 ] ] = 1 ;
1826
1827
}
1827
1828
} ) ;
1828
1829
vacuum ( fun ) ;
1829
- if ( extraInfo && extraInfo . globals ) {
1830
- assert ( asm ) ;
1831
- var usedGlobals = { } ;
1832
- var nextLocal = 0 ;
1833
- // Minify globals using the mapping we were given
1834
- traverse ( fun , function ( node , type ) {
1835
- if ( type === 'name' ) {
1836
- var name = node [ 1 ] ;
1837
- var minified = extraInfo . globals [ name ] ;
1838
- if ( minified ) {
1839
- assert ( ! localVars [ name ] , name ) ; // locals must not shadow globals, or else we don't know which is which
1840
- if ( localVars [ minified ] ) {
1841
- // trying to minify a global into a name used locally. rename all the locals
1842
- var newName = '$_newLocal_' + ( nextLocal ++ ) ;
1843
- assert ( ! localVars [ newName ] ) ;
1844
- if ( params [ minified ] ) {
1845
- params [ newName ] = 1 ;
1846
- delete params [ minified ] ;
1847
- }
1848
- localVars [ newName ] = 1 ;
1849
- delete localVars [ minified ] ;
1850
- asmData . vars [ newName ] = asmData . vars [ minified ] ;
1851
- delete asmData . vars [ minified ] ;
1852
- asmData . params [ newName ] = asmData . params [ minified ] ;
1853
- delete asmData . params [ minified ] ;
1854
- traverse ( fun , function ( node , type ) {
1855
- if ( type === 'name' && node [ 1 ] === minified ) {
1856
- node [ 1 ] = newName ;
1857
- }
1858
- } ) ;
1859
- if ( fun [ 2 ] ) {
1860
- for ( var i = 0 ; i < fun [ 2 ] . length ; i ++ ) {
1861
- if ( fun [ 2 ] [ i ] === minified ) fun [ 2 ] [ i ] = newName ;
1862
- }
1863
- }
1864
- }
1865
- node [ 1 ] = minified ;
1866
- usedGlobals [ minified ] = 1 ;
1867
- }
1868
- }
1869
- } ) ;
1870
- if ( fun [ 1 ] in extraInfo . globals ) { // if fun was created by a previous optimization pass, it will not be here
1871
- fun [ 1 ] = extraInfo . globals [ fun [ 1 ] ] ;
1872
- assert ( fun [ 1 ] ) ;
1873
- }
1874
- var nextRegName = 0 ;
1875
- }
1876
1830
var regTypes = { } ;
1877
1831
function getNewRegName ( num , name ) {
1878
- if ( ! asm ) return 'r' + num ;
1879
- var type = asmData . vars [ name ] ;
1880
- if ( ! extraInfo || ! extraInfo . globals ) {
1881
- var ret = ( type ? 'd' : 'i' ) + num ;
1832
+ var ret ;
1833
+ if ( ! asm ) {
1834
+ ret = 'r' + num ;
1835
+ } else {
1836
+ var type = asmData . vars [ name ] ;
1837
+ ret = ( type ? 'd' : 'i' ) + num ;
1882
1838
regTypes [ ret ] = type ;
1883
- return ret ;
1884
1839
}
1885
- // find the next free minified name that is not used by a global that shows up in this function
1886
- while ( 1 ) {
1887
- ensureMinifiedNames ( nextRegName ) ;
1888
- var ret = minifiedNames [ nextRegName ++ ] ;
1889
- if ( ! usedGlobals [ ret ] ) {
1890
- regTypes [ ret ] = type ;
1891
- return ret ;
1892
- }
1840
+ if ( ret in allVars ) {
1841
+ assert ( ret in localVars , 'register shadows non-local name' ) ;
1893
1842
}
1843
+ return ret ;
1894
1844
}
1895
1845
// Find the # of uses of each variable.
1896
1846
// While doing so, check if all a variable's uses are dominated in a simple
@@ -2111,33 +2061,6 @@ function registerize(ast) {
2111
2061
}
2112
2062
}
2113
2063
denormalizeAsm ( fun , finalAsmData ) ;
2114
- if ( extraInfo && extraInfo . globals ) {
2115
- // minify in asm var definitions, that denormalizeAsm just generated
2116
- function minify ( value ) {
2117
- if ( value && value [ 0 ] === 'call' && value [ 1 ] [ 0 ] === 'name' ) {
2118
- var name = value [ 1 ] [ 1 ] ;
2119
- var minified = extraInfo . globals [ name ] ;
2120
- if ( minified ) {
2121
- value [ 1 ] [ 1 ] = minified ;
2122
- }
2123
- }
2124
- }
2125
- var stats = fun [ 3 ] ;
2126
- for ( var i = 0 ; i < stats . length ; i ++ ) {
2127
- var line = stats [ i ] ;
2128
- if ( i >= fun [ 2 ] . length && line [ 0 ] !== 'var' ) break ; // when we pass the arg and var coercions, break
2129
- if ( line [ 0 ] === 'stat' ) {
2130
- assert ( line [ 1 ] [ 0 ] === 'assign' ) ;
2131
- minify ( line [ 1 ] [ 3 ] ) ;
2132
- } else {
2133
- assert ( line [ 0 ] === 'var' ) ;
2134
- var pairs = line [ 1 ] ;
2135
- for ( var j = 0 ; j < pairs . length ; j ++ ) {
2136
- minify ( pairs [ j ] [ 1 ] ) ;
2137
- }
2138
- }
2139
- }
2140
- }
2141
2064
}
2142
2065
} ) ;
2143
2066
}
@@ -2913,6 +2836,92 @@ function minifyGlobals(ast) {
2913
2836
suffix = '// EXTRA_INFO:' + JSON . stringify ( minified ) ;
2914
2837
}
2915
2838
2839
+
2840
+ function minifyLocals ( ast ) {
2841
+ assert ( asm )
2842
+ assert ( extraInfo && extraInfo . globals )
2843
+
2844
+ traverseGeneratedFunctions ( ast , function ( fun , type ) {
2845
+
2846
+ // Analyse the asmjs to figure out local variable names,
2847
+ // but operate on the original source tree so that we don't
2848
+ // miss any global names in e.g. variable initializers.
2849
+ var asmData = normalizeAsm ( fun ) ; denormalizeAsm ( fun , asmData ) ;
2850
+ var newNames = { } ;
2851
+ var usedNames = { } ;
2852
+
2853
+ // Find all the globals that we need to minify using
2854
+ // pre-assigned names. Don't actually minify them yet
2855
+ // as that might interfere with local variable names.
2856
+ function isLocalName ( name ) {
2857
+ return name in asmData . vars || name in asmData . params ;
2858
+ }
2859
+ traverse ( fun , function ( node , type ) {
2860
+ if ( type === 'name' ) {
2861
+ var name = node [ 1 ] ;
2862
+ if ( ! isLocalName ( name ) ) {
2863
+ var minified = extraInfo . globals [ name ] ;
2864
+ if ( minified ) {
2865
+ newNames [ name ] = minified ;
2866
+ usedNames [ minified ] = 1 ;
2867
+ }
2868
+ }
2869
+ }
2870
+ } ) ;
2871
+
2872
+ // Traverse and minify all names.
2873
+ // The first time we encounter a local name, we assign it a
2874
+ // minified name that's not currently in use. Allocating on
2875
+ // demand means they're processed in a predicatable order,
2876
+ // which is very handy for testing/debugging purposes.
2877
+ var nextMinifiedName = 0 ;
2878
+ function getNextMinifiedName ( ) {
2879
+ var minified ;
2880
+ while ( 1 ) {
2881
+ ensureMinifiedNames ( nextMinifiedName ) ;
2882
+ minified = minifiedNames [ nextMinifiedName ++ ] ;
2883
+ // TODO: we can probably remove !isLocalName here
2884
+ if ( ! usedNames [ minified ] && ! isLocalName ( minified ) ) {
2885
+ return minified ;
2886
+ }
2887
+ }
2888
+ }
2889
+ if ( fun [ 1 ] in extraInfo . globals ) {
2890
+ fun [ 1 ] = extraInfo . globals [ fun [ 1 ] ] ;
2891
+ assert ( fun [ 1 ] ) ;
2892
+ }
2893
+ if ( fun [ 2 ] ) {
2894
+ for ( var i = 0 ; i < fun [ 2 ] . length ; i ++ ) {
2895
+ var minified = getNextMinifiedName ( ) ;
2896
+ newNames [ fun [ 2 ] [ i ] ] = minified ;
2897
+ fun [ 2 ] [ i ] = minified ;
2898
+ }
2899
+ }
2900
+ traverse ( fun [ 3 ] , function ( node , type ) {
2901
+ if ( type === 'name' ) {
2902
+ var name = node [ 1 ] ;
2903
+ var minified = newNames [ name ] ;
2904
+ if ( minified ) {
2905
+ node [ 1 ] = minified ;
2906
+ } else if ( isLocalName ( name ) ) {
2907
+ minified = getNextMinifiedName ( ) ;
2908
+ newNames [ name ] = minified ;
2909
+ node [ 1 ] = minified ;
2910
+ }
2911
+ } else if ( type === 'var' ) {
2912
+ node [ 1 ] . forEach ( function ( defn ) {
2913
+ var name = defn [ 0 ] ;
2914
+ if ( ! ( name in newNames ) ) {
2915
+ newNames [ name ] = getNextMinifiedName ( ) ;
2916
+ }
2917
+ defn [ 0 ] = newNames [ name ] ;
2918
+ } ) ;
2919
+ }
2920
+ } ) ;
2921
+
2922
+ } ) ;
2923
+ }
2924
+
2916
2925
// Relocation pass for a shared module (for the functions part of the module)
2917
2926
//
2918
2927
// 1. Replace function names with alternate names as defined (to avoid colliding with
@@ -3984,6 +3993,7 @@ var passes = {
3984
3993
eliminateMemSafe : eliminateMemSafe ,
3985
3994
aggressiveVariableElimination : aggressiveVariableElimination ,
3986
3995
minifyGlobals : minifyGlobals ,
3996
+ minifyLocals : minifyLocals ,
3987
3997
relocate : relocate ,
3988
3998
outline : outline ,
3989
3999
minifyWhitespace : function ( ) { minifyWhitespace = true } ,
0 commit comments