aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-01-10 17:54:59 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-01-10 17:54:59 -0800
commit41e3ba8e82863a75d3b81fdad9ebef319a4ac652 (patch)
tree59dade1777786a4f99a8f05ffeeb44520184f714
parent0a71c5438c46d535cc714b927ae328563d76eba6 (diff)
experimental tool to fix closure's over-inlining into FUNCTION_TABLE
-rw-r--r--tests/runner.py8
-rw-r--r--tests/test-fix-closure.js36
-rwxr-xr-xtools/fix_closure.py77
3 files changed, 121 insertions, 0 deletions
diff --git a/tests/runner.py b/tests/runner.py
index 22e8ff1d..6d2ad423 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -5468,6 +5468,14 @@ f.close()
output = Popen([NODE_JS, COFFEESCRIPT, VARIABLE_ELIMINATOR], stdin=PIPE, stdout=PIPE).communicate(input)[0]
self.assertIdentical(expected, output)
+ def test_fix_closure(self):
+ input = path_from_root('tests', 'test-fix-closure.js')
+ expected = path_from_root('tests', 'test-fix-closure.out.js')
+ Popen(['python', path_from_root('tools', 'fix_closure.py'), input, 'out.js']).communicate(input)
+ output = open('out.js').read()
+ assert '0,uninline_Q_269,0' in output
+ assert run_js(input) == run_js('out.js')
+
def test_js_optimizer(self):
for input, expected, passes in [
(open(path_from_root('tools', 'test-js-optimizer.js')).read(), open(path_from_root('tools', 'test-js-optimizer-output.js')).read(),
diff --git a/tests/test-fix-closure.js b/tests/test-fix-closure.js
new file mode 100644
index 00000000..331a06c0
--- /dev/null
+++ b/tests/test-fix-closure.js
@@ -0,0 +1,36 @@
+var k=void 0,l=!0,m=null,n=!1,p=[],aa="object"===typeof process,ba="object"===typeof window,ca="function"===typeof importScripts,da=!ba&&!aa&&!ca;
+if(aa){print=function(a){process.stdout.write(a+"\n")};printErr=function(a){process.stderr.write(a+"\n")};var ea=require("fs");read=function(a){var b=ea.readFileSync(a).toString();!b&&"/"!=a[0]&&(a=__dirname.split("/").slice(0,-1).join("/")+"/src/"+a,b=ea.readFileSync(a).toString());return b};p=process.argv.slice(2)}else if(da)this.read||(read=function(a){snarf(a)}),p=this.arguments?arguments:scriptArgs;else if(ba)print=printErr=function(a){console.log(a)},read=function(a){var b=new XMLHttpRequest;
+b.open("GET",a,n);b.send(m);return b.responseText},this.arguments&&(p=arguments);else if(ca)load=importScripts;else throw"Unknown runtime environment. Where are we?";function fa(a){eval.call(m,a)}"undefined"==typeof load&&"undefined"!=typeof read&&(load=function(a){fa(read(a))});"undefined"===typeof printErr&&(printErr=function(){});"undefined"===typeof print&&(print=printErr);try{this.Module=Module}catch(ga){this.Module=Module={}}Module.arguments||(Module.arguments=p);Module.print&&(print=Module.print);
+var r={T:function(){return q},S:function(a){q=a},Y:function(a,b){b=b||4;return isNumber(a)&&isNumber(b)?Math.ceil(a/b)*b:"Math.ceil(("+a+")/"+b+")*"+b},M:function(a){return a in r.C||a in r.B},N:function(a){return"*"==a[a.length-1]},P:function(a){return isPointerType(a)?n:/^\[\d+\ x\ (.*)\]/.test(a)||/<?{ [^}]* }>?/.test(a)?l:"%"==a[0]},C:{i1:0,i8:0,i16:0,i32:0,i64:0},B:{"float":0,"double":0},aa:function(a,b){return(a|0|b|0)+4294967296*(Math.round(a/4294967296)|Math.round(b/4294967296))},W:function(a,
+b){return((a|0)&(b|0))+4294967296*(Math.round(a/4294967296)&Math.round(b/4294967296))},ea:function(a,b){return((a|0)^(b|0))+4294967296*(Math.round(a/4294967296)^Math.round(b/4294967296))},m:function(a){if(1==r.e)return 1;var b={"%i1":1,"%i8":1,"%i16":2,"%i32":4,"%i64":8,"%float":4,"%double":8}["%"+a];!b&&"*"==a[a.length-1]&&(b=r.e);return b},K:function(a){return Math.max(r.m(a),r.e)},H:function(a,b){var d={};return b?a.filter(function(a){return d[a[b]]?n:d[a[b]]=l}):a.filter(function(a){return d[a]?
+n:d[a]=l})},set:function(){for(var a="object"===typeof arguments[0]?arguments[0]:arguments,b={},d=0;d<a.length;d++)b[a[d]]=0;return b},F:function(a){a.b=0;a.f=0;var b=[],d=-1;a.p=a.l.map(function(c){var e;if(r.M(c)||r.N(c))c=e=r.m(c);else if(r.P(c))e=Types.types[c].b,c=Types.types[c].f;else throw"Unclear type in struct: "+c+", in "+a.Q+" :: "+dump(Types.types[a.Q]);c=a.ba?1:Math.min(c,r.e);a.f=Math.max(a.f,c);c=r.i(a.b,c);a.b=c+e;0<=d&&b.push(c-d);return d=c});a.b=r.i(a.b,a.f);0==b.length?a.o=a.b:
+1==r.H(b).length&&(a.o=b[0]);a.$=1!=a.o;return a.p},J:function(a,b,d){var c,e;if(b){d=d||0;c=("undefined"===typeof Types?r.da:Types.types)[b];if(!c)return m;a||(a=("undefined"===typeof Types?r:Types).ca[b.replace(/.*\./,"")]);if(!a)return m;s(c.l.length===a.length,"Number of named fields must match the type for "+b+". Perhaps due to inheritance, which is not supported yet?");e=c.p}else c={l:a.map(function(a){return a[0]})},e=r.F(c);var i={V:c.b};b?a.forEach(function(a,b){if("string"===typeof a)i[a]=
+e[b]+d;else{var j,v;for(v in a)j=v;i[j]=r.J(a[j],c.l[b],e[b])}}):a.forEach(function(a,b){i[a[1]]=e[b]});return i},R:function(a){var b=q;q+=a;q=4*Math.ceil(q/4);s(q<t+u,"Ran out of stack");return b},z:function(a){var b=w;w+=a;w=4*Math.ceil(w/4);if(w>=x){printErr("Warning: Enlarging memory arrays, this is not fast! "+[w,x]);s(w>=x);for(s(4<x);x<=w;)x=Math.ceil(2*x/A)*A;var a=B,d=new ArrayBuffer(x);B=new Int8Array(d);C=new Int16Array(d);D=new Int32Array(d);H=new Uint8Array(d);ha=new Uint16Array(d);I=
+new Uint32Array(d);J=new Float32Array(d);B.set(a)}return b},i:function(a,b){return Math.ceil(a/(b?b:4))*(b?b:4)},e:4,U:0},ia=[],L,ja=new ArrayBuffer(8),M=new Int32Array(ja),ka=new Float64Array(ja);function la(a){print(a+":\n"+Error().stack);throw"Assertion: "+a;}function s(a,b){a||la("Assertion failed: "+b)}
+function ma(a,b,d){d=d||"i8";"*"===d[d.length-1]&&(d="i32");switch(d){case "i1":B[a]=b;break;case "i8":B[a]=b;break;case "i16":C[a>>1]=b;break;case "i32":D[a>>2]=b;break;case "i64":D[a>>2]=b[0];D[a+4>>2]=b[1];break;case "float":J[a>>2]=b;break;case "double":ka[0]=b;D[a>>2]=M[0];D[a+4>>2]=M[1];break;default:la("invalid type for setValue: "+d)}}Module.setValue=ma;
+Module.getValue=function(a,b){b=b||"i8";"*"===b[b.length-1]&&(b="i32");switch(b){case "i1":return B[a];case "i8":return B[a];case "i16":return C[a>>1];case "i32":return D[a>>2];case "i64":return[I[a>>2],I[a+4>>2]];case "float":return J[a>>2];case "double":return M[0]=D[a>>2],M[1]=D[a+4>>2],ka[0];default:la("invalid type for setValue: "+b)}return m};var na=1,N=2;Module.ALLOC_NORMAL=0;Module.ALLOC_STACK=na;Module.ALLOC_STATIC=N;
+function O(a,b,d){var c,e;"number"===typeof a?(c=l,e=a):(c=n,e=a.length);for(var i="string"===typeof b?b:m,d=[oa,r.R,r.z][d===k?N:d](Math.max(e,i?1:b.length)),h=0,f;h<e;){var j=c?0:a[h];"function"===typeof j&&(j=r.Z(j));f=i||b[h];0===f?h++:(s(f,"Must know what type to store in allocate!"),"i64"==f&&(f="i32"),ma(d+h,j,f),h+=r.m(f))}return d}Module.allocate=O;Module.Pointer_stringify=function(a){for(var b="",d=0,c,e=String.fromCharCode(0);;){c=String.fromCharCode(H[a+d]);if(c==e)break;b+=c;d+=1}return b};
+Module.Array_stringify=function(a){for(var b="",d=0;d<a.length;d++)b+=String.fromCharCode(a[d]);return b};var Q,A=4096,B,H,C,ha,D,I,J,t,q,u,w,pa=Module.TOTAL_STACK||5242880,x=Module.TOTAL_MEMORY||10485760;s(!!Int32Array&&!!Float64Array&&!!(new Int32Array(1)).subarray&&!!(new Int32Array(1)).set,"Cannot fallback to non-typed array case: Code is too specialized");var R=new ArrayBuffer(x);B=new Int8Array(R);C=new Int16Array(R);D=new Int32Array(R);H=new Uint8Array(R);ha=new Uint16Array(R);I=new Uint32Array(R);
+J=new Float32Array(R);D[0]=255;s(255===H[0]&&0===H[3],"Typed arrays 2 must be run on a little-endian system");var qa=S("(null)");w=qa.length;for(var T=0;T<qa.length;T++)B[T]=qa[T];Module.HEAP=k;Module.HEAP8=B;Module.HEAP16=C;Module.HEAP32=D;Module.HEAPU8=H;Module.HEAPU16=ha;Module.HEAPU32=I;Module.HEAPF32=J;t=q=r.i(w);u=t+pa;w=Math.ceil(u/A)*A;function ra(a,b){return Array.prototype.slice.call(B.subarray(a,a+b))}Module.Array_copy=ra;function sa(a){for(var b=0;B[a+b];)b++;return b}
+Module.String_len=sa;function ta(a,b){var d=sa(a);b&&d++;var c=ra(a,d);b&&(c[d-1]=0);return c}Module.String_copy=ta;function S(a,b){for(var d=[],c=0;c<a.length;){var e=a.charCodeAt(c);255<e&&(s(n,"Character code "+e+" ("+a[c]+") at offset "+c+" not in 0x00-0xFF."),e&=255);d.push(e);c+=1}b||d.push(0);return d}Module.intArrayFromString=S;
+Module.intArrayToString=function(a){for(var b=[],d=0;d<a.length;d++){var c=a[d];255<c&&(s(n,"Character code "+c+" ("+String.fromCharCode(c)+") at offset "+d+" not in 0x00-0xFF."),c&=255);b.push(String.fromCharCode(c))}return b.join("")};function U(a,b){return 0<=a?a:32>=b?2*Math.abs(1<<b-1)+a:Math.pow(2,b)+a}function ua(a,b){if(0>=a)return a;var d=32>=b?Math.abs(1<<b-1):Math.pow(2,b-1);if(a>=d&&(32>=b||a>d))a=-2*d+a;return a}
+function va(){var a;a=Q[2]();var b=Q[2](),d=Q[4](),c=Q[4](),e=Q[D[wa>>2]](),i=Q[D[xa>>2]]();ya(za|0,(L=q,q+=24,s(q<t+u,"Ran out of stack"),D[L>>2]=a,D[L+4>>2]=b,D[L+8>>2]=d,D[L+12>>2]=c,D[L+16>>2]=e,D[L+20>>2]=i,L));a=2;b=2==(a|0)&1;a=4==(a|0)&1;ya(Aa|0,(L=q,q+=8,s(q<t+u,"Ran out of stack"),D[L>>2]=b,D[L+4>>2]=a,L));a=4;b=2==(a|0)&1;a=4==(a|0)&1;ya(Ba|0,(L=q,q+=8,s(q<t+u,"Ran out of stack"),D[L>>2]=b,D[L+4>>2]=a,L));Q[6](Ca|0);Q[8](Da|0);return 0}Module._main=va;va.X=1;
+var V=13,Ea=9,Fa=22,Ga=5,Ha=21,Ia=6;function W(a){Ja||(Ja=O([0],"i32",N));D[Ja>>2]=a}var Ja,Ka=0,X=0,La=0,Ma=2,Y=[m],Na=l;function Oa(a,b){if("string"!==typeof a)return m;b===k&&(b="/");a&&"/"==a[0]&&(b="");for(var d=(b+"/"+a).split("/").reverse(),c=[""];d.length;){var e=d.pop();""==e||"."==e||(".."==e?1<c.length&&c.pop():c.push(e))}return 1==c.length?"/":c.join("/")}
+function Pa(a,b,d){var c={O:n,k:n,error:0,name:m,path:m,object:m,s:n,u:m,t:m},a=Oa(a);if("/"==a)c.O=l,c.k=c.s=l,c.name="/",c.path=c.u="/",c.object=c.t=Z;else if(a!==m)for(var d=d||0,a=a.slice(1).split("/"),e=Z,i=[""];a.length;){1==a.length&&e.c&&(c.s=l,c.u=1==i.length?"/":i.join("/"),c.t=e,c.name=a[0]);var h=a.shift();if(e.c)if(e.w){if(!e.a.hasOwnProperty(h)){c.error=2;break}}else{c.error=V;break}else{c.error=20;break}e=e.a[h];if(e.link&&!(b&&0==a.length)){if(40<d){c.error=40;break}c=Oa(e.link,i.join("/"));
+return Pa([c].concat(a).join("/"),b,d+1)}i.push(h);0==a.length&&(c.k=l,c.path=i.join("/"),c.object=e)}return c}
+function Qa(a,b,d,c,e){a||(a="/");"string"===typeof a&&(Ra(),a=Pa(a,k),a.k?a=a.object:(W(a.error),a=m));if(!a)throw W(V),Error("Parent path must exist.");if(!a.c)throw W(20),Error("Parent must be a folder.");if(!a.write&&!Na)throw W(V),Error("Parent folder must be writeable.");if(!b||"."==b||".."==b)throw W(2),Error("Name must not be empty.");if(a.a.hasOwnProperty(b))throw W(17),Error("Can't overwrite object.");a.a[b]={w:c===k?l:c,write:e===k?n:e,timestamp:Date.now(),L:Ma++};for(var i in d)d.hasOwnProperty(i)&&
+(a.a[b][i]=d[i]);return a.a[b]}function Sa(a,b){return Qa("/",a,{c:l,g:n,a:{}},l,b)}function $(a,b,d,c){if(!d&&!c)throw Error("A device must have at least one callback defined.");var e={g:l,input:d,d:c};e.c=n;return Qa(a,b,e,Boolean(d),Boolean(c))}function Ra(){Z||(Z={w:l,write:n,c:l,g:n,timestamp:Date.now(),L:1,a:{}})}var Ta,Z;
+function Ua(a,b,d){var c=Y[a];if(c){if(c.h){if(0>d)return W(Fa),-1;if(c.object.g){if(c.object.d){for(var e=0;e<d;e++)try{c.object.d(B[b+e])}catch(i){return W(Ga),-1}c.object.timestamp=Date.now();return e}W(Ia);return-1}e=c.position;a=Y[a];if(!a||a.object.g)W(Ea),b=-1;else if(a.h)if(a.object.c)W(Ha),b=-1;else if(0>d||0>e)W(Fa),b=-1;else{for(var h=a.object.a;h.length<e;)h.push(0);for(var f=0;f<d;f++)h[e+f]=H[b+f];a.object.timestamp=Date.now();b=f}else W(V),b=-1;-1!=b&&(c.position+=b);return b}W(V);
+return-1}W(Ea);return-1}
+function Va(a,b){function d(a){var c;"double"===a?c=(M[0]=D[b+e>>2],M[1]=D[b+e+4>>2],ka[0]):"i64"==a?(c=[D[b+e>>2],D[b+e+4>>2]],c=U(c[0],32)+U(c[1],32)*Math.pow(2,32)):(a="i32",c=D[b+e>>2]);e+=r.K(a);return Number(c)}for(var c=a,e=0,i=[],h,f;;){var j=c;h=B[c];if(0===h)break;f=B[c+1];if(37==h){var v=n,E=n,F=n,K=n;a:for(;;){switch(f){case 43:v=l;break;case 45:E=l;break;case 35:F=l;break;case 48:if(K)break a;else{K=l;break}default:break a}c++;f=B[c+1]}var G=0;if(42==f)G=d("i32"),c++,f=B[c+1];else for(;48<=
+f&&57>=f;)G=10*G+(f-48),c++,f=B[c+1];var P=n;if(46==f){var y=0,P=l;c++;f=B[c+1];if(42==f)y=d("i32"),c++;else for(;;){f=B[c+1];if(48>f||57<f)break;y=10*y+(f-48);c++}f=B[c+1]}else y=6;var o;switch(String.fromCharCode(f)){case "h":f=B[c+2];104==f?(c++,o=1):o=2;break;case "l":f=B[c+2];108==f?(c++,o=8):o=4;break;case "L":case "q":case "j":o=8;break;case "z":case "t":case "I":o=4;break;default:o=m}o&&c++;f=B[c+1];if(-1!="d,i,u,o,x,X,p".split(",").indexOf(String.fromCharCode(f))){j=100==f||105==f;o=o||4;
+h=d("i"+8*o);4>=o&&(h=(j?ua:U)(h&Math.pow(256,o)-1,8*o));var z=Math.abs(h),g,j="";if(100==f||105==f)g=ua(h,8*o).toString(10);else if(117==f)g=U(h,8*o).toString(10),h=Math.abs(h);else if(111==f)g=(F?"0":"")+z.toString(8);else if(120==f||88==f){j=F?"0x":"";if(0>h){h=-h;g=(z-1).toString(16);F=[];for(z=0;z<g.length;z++)F.push((15-parseInt(g[z],16)).toString(16));for(g=F.join("");g.length<2*o;)g="f"+g}else g=z.toString(16);88==f&&(j=j.toUpperCase(),g=g.toUpperCase())}else 112==f&&(0===z?g="(nil)":(j="0x",
+g=z.toString(16)));if(P)for(;g.length<y;)g="0"+g;for(v&&(j=0>h?"-"+j:"+"+j);j.length+g.length<G;)E?g+=" ":K?g="0"+g:j=" "+j;g=j+g;g.split("").forEach(function(a){i.push(a.charCodeAt(0))})}else if(-1!="f,F,e,E,g,G".split(",").indexOf(String.fromCharCode(f))){h=d("double");if(isNaN(h))g="nan",K=n;else if(isFinite(h)){P=n;o=Math.min(y,20);if(103==f||71==f)P=l,y=y||1,o=parseInt(h.toExponential(o).split("e")[1],10),y>o&&-4<=o?(f=(103==f?"f":"F").charCodeAt(0),y-=o+1):(f=(103==f?"e":"E").charCodeAt(0),
+y--),o=Math.min(y,20);if(101==f||69==f)g=h.toExponential(o),/[eE][-+]\d$/.test(g)&&(g=g.slice(0,-1)+"0"+g.slice(-1));else if(102==f||70==f)g=h.toFixed(o);j=g.split("e");if(P&&!F)for(;1<j[0].length&&-1!=j[0].indexOf(".")&&("0"==j[0].slice(-1)||"."==j[0].slice(-1));)j[0]=j[0].slice(0,-1);else for(F&&-1==g.indexOf(".")&&(j[0]+=".");y>o++;)j[0]+="0";g=j[0]+(1<j.length?"e"+j[1]:"");69==f&&(g=g.toUpperCase());v&&0<=h&&(g="+"+g)}else g=(0>h?"-":"")+"inf",K=n;for(;g.length<G;)g=E?g+" ":K&&("-"==g[0]||"+"==
+g[0])?g[0]+"0"+g.slice(1):(K?"0":" ")+g;97>f&&(g=g.toUpperCase());g.split("").forEach(function(a){i.push(a.charCodeAt(0))})}else if(115==f){(v=d("i8*"))?(v=ta(v),P&&v.length>y&&(v=v.slice(0,y))):v=S("(null)",l);if(!E)for(;v.length<G--;)i.push(32);i=i.concat(v);if(E)for(;v.length<G--;)i.push(32)}else if(99==f){for(E&&i.push(d("i8"));0<--G;)i.push(32);E||i.push(d("i8"))}else if(110==f)E=d("i32*"),D[E>>2]=i.length;else if(37==f)i.push(h);else for(z=j;z<c+2;z++)i.push(B[z]);c+=2}else i.push(h),c+=1}return i}
+function ya(a,b){var d=D[X>>2],c=Va(a,b),e=r.T();var i=O(c,"i8",na),c=1*c.length;0!=c&&-1==Ua(d,i,c)&&Y[d]&&(Y[d].error=l);r.S(e)}function oa(a){ptr=r.z(a+8);return ptr+8&4294967288}
+(function(a,b,d){if(!Ta){Ta=l;Ra();a||(a=function(){if(!a.j||!a.j.length){var b;"undefined"!=typeof window&&"function"==typeof window.prompt?b=window.prompt("Input: "):"function"==typeof readline&&(b=readline());b||(b="");a.j=S(b+"\n",l)}return a.j.shift()});b||(b=function(a){a===m||10===a?(b.v(b.buffer.join("")),b.buffer=[]):b.buffer.push(String.fromCharCode(a))});b.v||(b.v=print);b.buffer||(b.buffer=[]);d||(d=b);Sa("tmp",l);var c=Sa("dev",n),e=$(c,"stdin",a),i=$(c,"stdout",m,b),d=$(c,"stderr",m,
+d);$(c,"tty",a,b);Y[1]={path:"/dev/stdin",object:e,position:0,r:l,h:n,q:n,error:n,n:n,A:[]};Y[2]={path:"/dev/stdout",object:i,position:0,r:n,h:l,q:n,error:n,n:n,A:[]};Y[3]={path:"/dev/stderr",object:d,position:0,r:n,h:l,q:n,error:n,n:n,A:[]};Ka=O([1],"void*",N);X=O([2],"void*",N);La=O([3],"void*",N);Y[Ka]=Y[1];Y[X]=Y[2];Y[La]=Y[3];O([O([0,0,0,0,Ka,0,0,0,X,0,0,0,La,0,0,0],"void*",N)],"void*",N)}})();
+ia.push({I:function(){Ta&&(0<Y[2].object.d.buffer.length&&Y[2].object.d(10),0<Y[3].object.d.buffer.length&&Y[3].object.d(10))}});W(0);var Wa=O([0],"i8",N);Module.G=function(a){function b(){for(var a=0;3>a;a++)c.push(0)}var d=a.length+1,c=[O(S("/bin/this.program"),"i8",N)];b();for(var e=0;e<d-1;e+=1)c.push(O(S(a[e]),"i8",N)),b();c.push(0);c=O(c,"i32",N);return va()};var wa,xa,za,Aa,Ba,Ca,Da;wa=O([2],["i32 ()*",0,0,0,0],N);xa=O([4],["i32 ()*",0,0,0,0],N);
+za=O([42,37,100,44,37,100,44,37,100,44,37,100,44,37,100,44,37,100,42,10,0],"i8",N);Aa=O([42,37,100,44,37,100,0],"i8",N);Ba=O([44,37,100,44,37,100,42,10,0],"i8",N);Ca=O([42,104,101,108,108,111,33,42,0],"i8",N);Da=O([42,103,111,111,100,98,121,101,33,42,0],"i8",N);Q=[0,0,function(){return 26},0,function(){return 90},0,function(){return 0},0,function(a){var b=D[X>>2],a=Ua(b,a,sa(a));if(0>a)b=a;else{var d=U(10);B[Wa]=d;-1==Ua(b,Wa,1)?(b in Y&&(Y[b].error=l),b=-1):b=d;b=0>b?-1:a+1}return b},0];
+Module.FUNCTION_TABLE=Q;function Xa(a){var a=a||Module.arguments,b=m;if(Module._main)for(b=Module.G(a);0<ia.length;){var a=ia.pop(),d=a.I;"number"===typeof d&&(d=Q[d]);d(a.D===k?m:a.D)}return b}Module.run=Xa;try{Na=n}catch(Ya){}Module.noInitialRun||Xa();
diff --git a/tools/fix_closure.py b/tools/fix_closure.py
new file mode 100755
index 00000000..c1d16cb7
--- /dev/null
+++ b/tools/fix_closure.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+'''
+With very very large projects, closure compiler can translate FUNCTION_TABLE into something like
+
+ J = [0, 0, func, 0, f(), 0, function() { ... }, 0, ..]
+
+where f() returns a new empty function, and after it is an inlined function. This inlining can be of very very large functions, in which case it can make the source unparsable by any JS engine due to "too much recursion" or "Maximum call stack size exceeded".
+
+This script uninlines those functions. Note that we can't do this using Uglify, since these scripts can't be parsed by it either!
+'''
+
+import os, sys, re
+
+infile = open(sys.argv[1], 'r')
+outfile = open(sys.argv[2], 'w')
+
+class ObjectParser:
+ def read(self, s, line):
+ '''
+ Read an element of the FUNCTION_TABLE until the end (a comma or the end of FUNCTION_TABLE), returning that location
+ '''
+ assert line[s-1] == ',' # we are a new element, after a comma
+ curly = 0
+ string = 0
+ is_func = 0
+ i = s
+ while True:
+ c = line[i]
+ if not string:
+ if c == '"' or c == "'":
+ string = 1
+ elif c == '{':
+ is_func = 1
+ curly += 1
+ elif c == '}':
+ curly -= 1
+ elif not curly:
+ if c in [',', ']']:
+ return (i, is_func and line[s:i].startswith('function('))
+ else:
+ if c == '"' or c == "'":
+ string = 0
+ i += 1
+
+lines = infile.readlines()
+i = 0
+while i < len(lines):
+ line = lines[i]
+ curr = line.find('=[0,0,')
+ if curr > 0:
+ # a suspect
+ target = line[curr-1]
+ curr += 5
+ parser = ObjectParser()
+ add = []
+ while line[curr] != ']':
+ assert line[curr] == ','
+ curr += 1
+ next, is_func = parser.read(curr, line)
+ if is_func:
+ text = line[curr:next]
+ assert text.startswith('function(')
+ ident = 'uninline_' + target + '_' + str(curr) # these idents should be unique, but might in theory collide with the rest of the JS code! XXX
+ line = line[:curr] + ident + line[next:]
+ add += 'function ' + ident + '(' + text[len('function('):]
+ while line[curr] != ',' and line[curr] != ']':
+ curr += 1
+ lines[i] = line
+ lines = lines[:i] + add + lines[i:]
+ i += len(add)
+ i += 1
+
+for line in lines:
+ outfile.write(line)
+outfile.close()
+