2377 lines
71 KiB
Java
2377 lines
71 KiB
Java
|
/*
|
||
|
* Copyright 2008 The Closure Compiler Authors.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package com.google.javascript.jscomp;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Inline function tests.
|
||
|
* @author johnlenz@google.com (john lenz)
|
||
|
*/
|
||
|
public class InlineFunctionsTest extends CompilerTestCase {
|
||
|
boolean allowGlobalFunctionInlining = true;
|
||
|
boolean allowBlockInlining = true;
|
||
|
final boolean allowExpressionDecomposition = true;
|
||
|
final boolean allowFunctionExpressionInlining = true;
|
||
|
final boolean allowLocalFunctionInlining = true;
|
||
|
boolean assumeStrictThis = false;
|
||
|
boolean assumeMinimumCapture = false;
|
||
|
|
||
|
public InlineFunctionsTest() {
|
||
|
this.enableNormalize();
|
||
|
this.enableMarkNoSideEffects();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void setUp() throws Exception {
|
||
|
super.setUp();
|
||
|
super.enableLineNumberCheck(true);
|
||
|
allowGlobalFunctionInlining = true;
|
||
|
allowBlockInlining = true;
|
||
|
assumeStrictThis = false;
|
||
|
assumeMinimumCapture = false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected CompilerPass getProcessor(Compiler compiler) {
|
||
|
compiler.resetUniqueNameId();
|
||
|
return new InlineFunctions(
|
||
|
compiler,
|
||
|
compiler.getUniqueNameIdSupplier(),
|
||
|
allowGlobalFunctionInlining,
|
||
|
allowLocalFunctionInlining,
|
||
|
allowBlockInlining,
|
||
|
assumeStrictThis,
|
||
|
assumeMinimumCapture);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the number of times the pass should be run before results are
|
||
|
* verified.
|
||
|
*/
|
||
|
@Override
|
||
|
protected int getNumRepetitions() {
|
||
|
// Some inlining can only be done in multiple passes.
|
||
|
return 3;
|
||
|
}
|
||
|
|
||
|
public void testInlineEmptyFunction1() {
|
||
|
// Empty function, no params.
|
||
|
test("function foo(){}" +
|
||
|
"foo();",
|
||
|
"void 0;");
|
||
|
}
|
||
|
|
||
|
public void testInlineEmptyFunction2() {
|
||
|
// Empty function, params with no side-effects.
|
||
|
test("function foo(){}" +
|
||
|
"foo(1, new Date, function(){});",
|
||
|
"void 0;");
|
||
|
}
|
||
|
|
||
|
public void testInlineEmptyFunction3() {
|
||
|
// Empty function, multiple references.
|
||
|
test("function foo(){}" +
|
||
|
"foo();foo();foo();",
|
||
|
"void 0;void 0;void 0");
|
||
|
}
|
||
|
|
||
|
public void testInlineEmptyFunction4() {
|
||
|
// Empty function, params with side-effects forces block inlining.
|
||
|
test("function foo(){}" +
|
||
|
"foo(x());",
|
||
|
"{var JSCompiler_inline_anon_param_0=x();}");
|
||
|
}
|
||
|
|
||
|
public void testInlineEmptyFunction5() {
|
||
|
// Empty function, call params with side-effects in expression can not
|
||
|
// be inlined.
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function foo(){}" +
|
||
|
"foo(x());");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions1() {
|
||
|
// As simple a test as we can get.
|
||
|
test("function foo(){ return 4 }" +
|
||
|
"foo();",
|
||
|
"4");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions2() {
|
||
|
// inline simple constants
|
||
|
// NOTE: CD is not inlined.
|
||
|
test("var t;var AB=function(){return 4};" +
|
||
|
"function BC(){return 6;}" +
|
||
|
"CD=function(x){return x + 5};x=CD(3);y=AB();z=BC();",
|
||
|
"var t;CD=function(x){return x+5};x=CD(3);y=4;z=6"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions3() {
|
||
|
// inline simple constants
|
||
|
test("var t;var AB=function(){return 4};" +
|
||
|
"function BC(){return 6;}" +
|
||
|
"var CD=function(x){return x + 5};x=CD(3);y=AB();z=BC();",
|
||
|
"var t;x=3+5;y=4;z=6");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions4() {
|
||
|
// don't inline if there are multiple definitions (need DFA for that).
|
||
|
test("var t; var AB = function() { return 4 }; " +
|
||
|
"function BC() { return 6; }" +
|
||
|
"CD = 0;" +
|
||
|
"CD = function(x) { return x + 5 }; x = CD(3); y = AB(); z = BC();",
|
||
|
|
||
|
"var t;CD=0;CD=function(x){return x+5};x=CD(3);y=4;z=6");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions5() {
|
||
|
// inline additions
|
||
|
test("var FOO_FN=function(x,y) { return \"de\" + x + \"nu\" + y };" +
|
||
|
"var a = FOO_FN(\"ez\", \"ts\")",
|
||
|
|
||
|
"var a=\"de\"+\"ez\"+\"nu\"+\"ts\"");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions6() {
|
||
|
// more complex inlines
|
||
|
test("function BAR_FN(x, y, z) { return z(foo(x + y)) }" +
|
||
|
"alert(BAR_FN(1, 2, baz))",
|
||
|
|
||
|
"alert(baz(foo(1+2)))");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions7() {
|
||
|
// inlines appearing multiple times
|
||
|
test("function FN(x,y,z){return x+x+y}" +
|
||
|
"var b=FN(1,2,3)",
|
||
|
|
||
|
"var b=1+1+2");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions8() {
|
||
|
// check correct parenthesization
|
||
|
test("function MUL(x,y){return x*y}function ADD(x,y){return x+y}" +
|
||
|
"var a=1+MUL(2,3);var b=2*ADD(3,4)",
|
||
|
|
||
|
"var a=1+2*3;var b=2*(3+4)");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions9() {
|
||
|
// don't inline if the input parameter is modified.
|
||
|
test("function INC(x){return x++}" +
|
||
|
"var y=INC(i)",
|
||
|
"var y;{var x$$inline_0=i;" +
|
||
|
"y=x$$inline_0++}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions10() {
|
||
|
test("function INC(x){return x++}" +
|
||
|
"var y=INC(i);y=INC(i)",
|
||
|
"var y;" +
|
||
|
"{var x$$inline_0=i;" +
|
||
|
"y=x$$inline_0++}" +
|
||
|
"{var x$$inline_2=i;" +
|
||
|
"y=x$$inline_2++}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions11() {
|
||
|
test("function f(x){return x}" +
|
||
|
"var y=f(i)",
|
||
|
"var y=i");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions12() {
|
||
|
// don't inline if the input parameter has side-effects.
|
||
|
allowBlockInlining = false;
|
||
|
test("function f(x){return x}" +
|
||
|
"var y=f(i)",
|
||
|
"var y=i");
|
||
|
testSame("function f(x){return x}" +
|
||
|
"var y=f(i++)");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions13() {
|
||
|
// inline as block if the input parameter has side-effects.
|
||
|
test("function f(x){return x}" +
|
||
|
"var y=f(i++)",
|
||
|
"var y;{var x$$inline_0=i++;y=x$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions14() {
|
||
|
// don't remove functions that are referenced on other ways
|
||
|
test("function FOO(x){return x}var BAR=function(y){return y}" +
|
||
|
";b=FOO;a(BAR);x=FOO(1);y=BAR(2)",
|
||
|
|
||
|
"function FOO(x){return x}var BAR=function(y){return y}" +
|
||
|
";b=FOO;a(BAR);x=1;y=2");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions15a() {
|
||
|
// closure factories: do inline into global scope.
|
||
|
test("function foo(){return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"var d=b()+foo()",
|
||
|
|
||
|
"var d=c+function(a){return a+1}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions15b() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
// closure factories: don't inline closure with locals into global scope.
|
||
|
test("function foo(){var x;return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"var d=b()+foo()",
|
||
|
|
||
|
"function foo(){var x;return function(a){return a+1}}" +
|
||
|
"var d=c+foo()");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
test("function foo(){var x;return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"var d=b()+foo()",
|
||
|
|
||
|
"var JSCompiler_temp_const$$0 = c;\n" +
|
||
|
"var JSCompiler_inline_result$$1;\n" +
|
||
|
"{\n" +
|
||
|
"var x$$inline_2;\n" +
|
||
|
"JSCompiler_inline_result$$1 = " +
|
||
|
" function(a$$inline_3){ return a$$inline_3+1 };\n" +
|
||
|
"}" +
|
||
|
"var d=JSCompiler_temp_const$$0 + JSCompiler_inline_result$$1");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions15c() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
// closure factories: don't inline into non-global scope.
|
||
|
test("function foo(){return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"function _x(){ var d=b()+foo() }",
|
||
|
|
||
|
"function foo(){return function(a){return a+1}}" +
|
||
|
"function _x(){ var d=c+foo() }");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
// closure factories: don't inline into non-global scope.
|
||
|
test("function foo(){return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"function _x(){ var d=b()+foo() }",
|
||
|
|
||
|
"function _x(){var d=c+function(a){return a+1}}");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions15d() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
// closure factories: don't inline functions with vars.
|
||
|
test("function foo(){var x; return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"function _x(){ var d=b()+foo() }",
|
||
|
|
||
|
"function foo(){var x; return function(a){return a+1}}" +
|
||
|
"function _x(){ var d=c+foo() }");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
// closure factories: don't inline functions with vars.
|
||
|
test("function foo(){var x; return function(a){return a+1}}" +
|
||
|
"var b=function(){return c};" +
|
||
|
"function _x(){ var d=b()+foo() }",
|
||
|
|
||
|
"function _x() { \n" +
|
||
|
" var JSCompiler_temp_const$$0 = c;\n" +
|
||
|
" var JSCompiler_inline_result$$1;\n" +
|
||
|
" {\n" +
|
||
|
" var x$$inline_2;\n" +
|
||
|
" JSCompiler_inline_result$$1 = " +
|
||
|
" function(a$$inline_3) {return a$$inline_3+1};\n" +
|
||
|
" }\n" +
|
||
|
" var d = JSCompiler_temp_const$$0+JSCompiler_inline_result$$1\n" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions16a() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
testSame("function foo(b){return window.bar(function(){c(b)})}" +
|
||
|
"var d=foo(e)");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
test(
|
||
|
"function foo(b){return window.bar(function(){c(b)})}" +
|
||
|
"var d=foo(e)",
|
||
|
"var d;{var b$$inline_0=e;" +
|
||
|
"d=window.bar(function(){c(b$$inline_0)})}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions16b() {
|
||
|
test("function foo(){return window.bar(function(){c()})}" +
|
||
|
"var d=foo(e)",
|
||
|
"var d=window.bar(function(){c()})");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions17() {
|
||
|
// don't inline recursive functions
|
||
|
testSame("function foo(x){return x*x+foo(3)}var bar=foo(4)");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions18() {
|
||
|
// TRICKY ... test nested inlines
|
||
|
allowBlockInlining = false;
|
||
|
test("function foo(a, b){return a+b}" +
|
||
|
"function bar(d){return c}" +
|
||
|
"var d=foo(bar(1),e)",
|
||
|
"var d=c+e");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions19() {
|
||
|
// TRICKY ... test nested inlines
|
||
|
// with block inlining possible
|
||
|
test("function foo(a, b){return a+b}" +
|
||
|
"function bar(d){return c}" +
|
||
|
"var d=foo(bar(1),e)",
|
||
|
"var d;{d=c+e}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions20() {
|
||
|
// Make sure both orderings work
|
||
|
allowBlockInlining = false;
|
||
|
test("function foo(a, b){return a+b}" +
|
||
|
"function bar(d){return c}" +
|
||
|
"var d=bar(foo(1,e));",
|
||
|
"var d=c");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions21() {
|
||
|
// with block inlining possible
|
||
|
test("function foo(a, b){return a+b}" +
|
||
|
"function bar(d){return c}" +
|
||
|
"var d=bar(foo(1,e))",
|
||
|
"var d;{d=c}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions22() {
|
||
|
// Another tricky case ... test nested compiler inlines
|
||
|
test("function plex(a){if(a) return 0;else return 1;}" +
|
||
|
"function foo(a, b){return bar(a+b)}" +
|
||
|
"function bar(d){return plex(d)}" +
|
||
|
"var d=foo(1,2)",
|
||
|
|
||
|
"var d;{JSCompiler_inline_label_plex_1:{" +
|
||
|
"if(1+2){" +
|
||
|
"d=0;break JSCompiler_inline_label_plex_1}" +
|
||
|
"else{" +
|
||
|
"d=1;break JSCompiler_inline_label_plex_1}d=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions23() {
|
||
|
// Test both orderings again
|
||
|
test("function complex(a){if(a) return 0;else return 1;}" +
|
||
|
"function bar(d){return complex(d)}" +
|
||
|
"function foo(a, b){return bar(a+b)}" +
|
||
|
"var d=foo(1,2)",
|
||
|
|
||
|
"var d;{JSCompiler_inline_label_complex_1:{" +
|
||
|
"if(1+2){" +
|
||
|
"d=0;break JSCompiler_inline_label_complex_1" +
|
||
|
"}else{" +
|
||
|
"d=1;break JSCompiler_inline_label_complex_1" +
|
||
|
"}d=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions24() {
|
||
|
// Don't inline functions with 'arguments' or 'this'
|
||
|
testSame("function foo(x){return this}foo(1)");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions25() {
|
||
|
testSame("function foo(){return arguments[0]}foo()");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions26() {
|
||
|
// Don't inline external functions
|
||
|
testSame("function _foo(x){return x}_foo(1)");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions27() {
|
||
|
test("var window = {}; function foo(){window.bar++; return 3;}" +
|
||
|
"var x = {y: 1, z: foo(2)};",
|
||
|
"var window={};" +
|
||
|
"var JSCompiler_inline_result$$0;" +
|
||
|
"{" +
|
||
|
" window.bar++;" +
|
||
|
" JSCompiler_inline_result$$0 = 3;" +
|
||
|
"}" +
|
||
|
"var x = {y: 1, z: JSCompiler_inline_result$$0};");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions28() {
|
||
|
test("var window = {}; function foo(){window.bar++; return 3;}" +
|
||
|
"var x = {y: alert(), z: foo(2)};",
|
||
|
"var window = {};" +
|
||
|
"var JSCompiler_temp_const$$0 = alert();" +
|
||
|
"var JSCompiler_inline_result$$1;" +
|
||
|
"{" +
|
||
|
" window.bar++;" +
|
||
|
" JSCompiler_inline_result$$1 = 3;}" +
|
||
|
"var x = {" +
|
||
|
" y: JSCompiler_temp_const$$0," +
|
||
|
" z: JSCompiler_inline_result$$1" +
|
||
|
"};");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions29() {
|
||
|
test("var window = {}; function foo(){window.bar++; return 3;}" +
|
||
|
"var x = {a: alert(), b: alert2(), c: foo(2)};",
|
||
|
"var window = {};" +
|
||
|
"var JSCompiler_temp_const$$1 = alert();" +
|
||
|
"var JSCompiler_temp_const$$0 = alert2();" +
|
||
|
"var JSCompiler_inline_result$$2;" +
|
||
|
"{" +
|
||
|
" window.bar++;" +
|
||
|
" JSCompiler_inline_result$$2 = 3;}" +
|
||
|
"var x = {" +
|
||
|
" a: JSCompiler_temp_const$$1," +
|
||
|
" b: JSCompiler_temp_const$$0," +
|
||
|
" c: JSCompiler_inline_result$$2" +
|
||
|
"};");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions30() {
|
||
|
// As simple a test as we can get.
|
||
|
testSame("function foo(){ return eval() }" +
|
||
|
"foo();");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctions31() {
|
||
|
// Don't introduce a duplicate label in the same scope
|
||
|
test("function foo(){ lab:{4;} }" +
|
||
|
"lab:{foo();}",
|
||
|
"lab:{{JSCompiler_inline_label_0:{4}}}");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInlining1() {
|
||
|
// Base line tests, direct inlining
|
||
|
test("function foo(){return 1}" +
|
||
|
"foo();",
|
||
|
"1;");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInlining2() {
|
||
|
// Base line tests, block inlining. Block inlining is needed by
|
||
|
// possible-side-effect parameter.
|
||
|
test("function foo(){return 1}" +
|
||
|
"foo(x());",
|
||
|
"{var JSCompiler_inline_anon_param_0=x();1}");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInlining3() {
|
||
|
// Inline using both modes.
|
||
|
test("function foo(){return 1}" +
|
||
|
"foo();foo(x());",
|
||
|
"1;{var JSCompiler_inline_anon_param_0=x();1}");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInlining4() {
|
||
|
// Inline using both modes. Alternating. Second call of each type has
|
||
|
// side-effect-less parameter, this is thrown away.
|
||
|
test("function foo(){return 1}" +
|
||
|
"foo();foo(x());" +
|
||
|
"foo(1);foo(1,x());",
|
||
|
"1;{var JSCompiler_inline_anon_param_0=x();1}" +
|
||
|
"1;{var JSCompiler_inline_anon_param_4=x();1}");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInliningCosting1() {
|
||
|
// Inline using both modes. Costing estimates.
|
||
|
|
||
|
// Base line.
|
||
|
test(
|
||
|
"function foo(a,b){return a+b+a+b+4+5+6+7+8+9+1+2+3+4+5}" +
|
||
|
"foo(1,2);" +
|
||
|
"foo(2,3)",
|
||
|
|
||
|
"1+2+1+2+4+5+6+7+8+9+1+2+3+4+5;" +
|
||
|
"2+3+2+3+4+5+6+7+8+9+1+2+3+4+5");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInliningCosting2() {
|
||
|
// Don't inline here because the function definition can not be eliminated.
|
||
|
// TODO(johnlenz): Should we add constant removing to the unit test?
|
||
|
testSame(
|
||
|
"function foo(a,b){return a+b+a+b+4+5+6+7+8+9+1+2+3+4+5}" +
|
||
|
"foo(1,2);" +
|
||
|
"foo(2,3,x())");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInliningCosting3() {
|
||
|
// Do inline here because the function definition can be eliminated.
|
||
|
test(
|
||
|
"function foo(a,b){return a+b+a+b+4+5+6+7+8+9+1+2+3+10}" +
|
||
|
"foo(1,2);" +
|
||
|
"foo(2,3,x())",
|
||
|
|
||
|
"1+2+1+2+4+5+6+7+8+9+1+2+3+10;" +
|
||
|
"{var JSCompiler_inline_anon_param_2=x();" +
|
||
|
"2+3+2+3+4+5+6+7+8+9+1+2+3+10}");
|
||
|
}
|
||
|
|
||
|
public void testMixedModeInliningCosting4() {
|
||
|
// Threshold test.
|
||
|
testSame(
|
||
|
"function foo(a,b){return a+b+a+b+4+5+6+7+8+9+1+2+3+4+101}" +
|
||
|
"foo(1,2);" +
|
||
|
"foo(2,3,x())");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified1() {
|
||
|
// Assignment
|
||
|
test("function f(x){return x=1}f(undefined)",
|
||
|
"{var x$$inline_0=undefined;" +
|
||
|
"x$$inline_0=1}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified2() {
|
||
|
test("function f(x){return (x)=1;}f(2)",
|
||
|
"{var x$$inline_0=2;" +
|
||
|
"x$$inline_0=1}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified3() {
|
||
|
// Assignment variant.
|
||
|
test("function f(x){return x*=2}f(2)",
|
||
|
"{var x$$inline_0=2;" +
|
||
|
"x$$inline_0*=2}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified4() {
|
||
|
// Assignment in if.
|
||
|
test("function f(x){return x?(x=2):0}f(2)",
|
||
|
"{var x$$inline_0=2;" +
|
||
|
"x$$inline_0?(" +
|
||
|
"x$$inline_0=2):0}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified5() {
|
||
|
// Assignment in if, multiple params
|
||
|
test("function f(x,y){return x?(y=2):0}f(2,undefined)",
|
||
|
"{var y$$inline_1=undefined;2?(" +
|
||
|
"y$$inline_1=2):0}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified6() {
|
||
|
test("function f(x,y){return x?(y=2):0}f(2)",
|
||
|
"{var y$$inline_1=void 0;2?(" +
|
||
|
"y$$inline_1=2):0}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified7() {
|
||
|
// Increment
|
||
|
test("function f(a){return++a<++a}f(1)",
|
||
|
"{var a$$inline_0=1;" +
|
||
|
"++a$$inline_0<" +
|
||
|
"++a$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified8() {
|
||
|
// OK, object parameter modified.
|
||
|
test("function f(a){return a.x=2}f(o)", "o.x=2");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineIfParametersModified9() {
|
||
|
// OK, array parameter modified.
|
||
|
test("function f(a){return a[2]=2}f(o)", "o[2]=2");
|
||
|
}
|
||
|
|
||
|
public void testInlineNeverPartialSubtitution1() {
|
||
|
test("function f(z){return x.y.z;}f(1)",
|
||
|
"x.y.z");
|
||
|
}
|
||
|
|
||
|
public void testInlineNeverPartialSubtitution2() {
|
||
|
test("function f(z){return x.y[z];}f(a)",
|
||
|
"x.y[a]");
|
||
|
}
|
||
|
|
||
|
public void testInlineNeverMutateConstants() {
|
||
|
test("function f(x){return x=1}f(undefined)",
|
||
|
"{var x$$inline_0=undefined;" +
|
||
|
"x$$inline_0=1}");
|
||
|
}
|
||
|
|
||
|
public void testInlineNeverOverrideNewValues() {
|
||
|
test("function f(a){return++a<++a}f(1)",
|
||
|
"{var a$$inline_0=1;" +
|
||
|
"++a$$inline_0<++a$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineMutableArgsReferencedOnce() {
|
||
|
test("function foo(x){return x;}foo([])", "[]");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineMutableArgs1() {
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function foo(x){return x+x} foo([])");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineMutableArgs2() {
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function foo(x){return x+x} foo(new Date)");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineMutableArgs3() {
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function foo(x){return x+x} foo(true&&new Date)");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineMutableArgs4() {
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function foo(x){return x+x} foo({})");
|
||
|
}
|
||
|
|
||
|
public void testInlineBlockMutableArgs1() {
|
||
|
test("function foo(x){x+x}foo([])",
|
||
|
"{var x$$inline_0=[];" +
|
||
|
"x$$inline_0+x$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineBlockMutableArgs2() {
|
||
|
test("function foo(x){x+x}foo(new Date)",
|
||
|
"{var x$$inline_0=new Date;" +
|
||
|
"x$$inline_0+x$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineBlockMutableArgs3() {
|
||
|
test("function foo(x){x+x}foo(true&&new Date)",
|
||
|
"{var x$$inline_0=true&&new Date;" +
|
||
|
"x$$inline_0+x$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineBlockMutableArgs4() {
|
||
|
test("function foo(x){x+x}foo({})",
|
||
|
"{var x$$inline_0={};" +
|
||
|
"x$$inline_0+x$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables1() {
|
||
|
// The Normalize pass now guarantees that that globals are never shadowed
|
||
|
// by locals.
|
||
|
|
||
|
// "foo" is inlined here as its parameter "a" doesn't conflict.
|
||
|
// "bar" is assigned a new name.
|
||
|
test("var a=0;" +
|
||
|
"function foo(a){return 3+a}" +
|
||
|
"function bar(){var a=foo(4)}" +
|
||
|
"bar();",
|
||
|
|
||
|
"var a=0;" +
|
||
|
"{var a$$inline_0=3+4}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables2() {
|
||
|
// "foo" is inlined here as its parameter "a" doesn't conflict.
|
||
|
// "bar" is inlined as its uses global "a", and does introduce any new
|
||
|
// globals.
|
||
|
test("var a=0;" +
|
||
|
"function foo(a){return 3+a}" +
|
||
|
"function bar(){a=foo(4)}" +
|
||
|
"bar()",
|
||
|
|
||
|
"var a=0;" +
|
||
|
"{a=3+4}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables3() {
|
||
|
// "foo" is inlined into exported "_bar", aliasing foo's "a".
|
||
|
test("var a=0;" +
|
||
|
"function foo(){var a=2;return 3+a}" +
|
||
|
"function _bar(){a=foo()}",
|
||
|
|
||
|
"var a=0;" +
|
||
|
"function _bar(){{var a$$inline_0=2;" +
|
||
|
"a=3+a$$inline_0}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables4() {
|
||
|
// "foo" is inlined.
|
||
|
// block access to global "a".
|
||
|
test("var a=0;" +
|
||
|
"function foo(){return 3+a}" +
|
||
|
"function _bar(a){a=foo(4)+a}",
|
||
|
|
||
|
"var a=0;function _bar(a$$1){" +
|
||
|
"a$$1=" +
|
||
|
"3+a+a$$1}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables5() {
|
||
|
// Can't yet inline multiple statements functions into expressions
|
||
|
// (though some are possible using the COMMA operator).
|
||
|
allowBlockInlining = false;
|
||
|
testSame("var a=0;" +
|
||
|
"function foo(){var a=4;return 3+a}" +
|
||
|
"function _bar(a){a=foo(4)+a}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables6() {
|
||
|
test("var a=0;" +
|
||
|
"function foo(){var a=4;return 3+a}" +
|
||
|
"function _bar(a){a=foo(4)}",
|
||
|
|
||
|
"var a=0;function _bar(a$$2){{" +
|
||
|
"var a$$inline_0=4;" +
|
||
|
"a$$2=3+a$$inline_0}}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables7() {
|
||
|
assumeMinimumCapture = false;
|
||
|
test("var a=3;" +
|
||
|
"function foo(){return a}" +
|
||
|
"(function(){var a=5;(function(){foo()})()})()",
|
||
|
"var a=3;" +
|
||
|
"{var a$$inline_0=5;{a}}"
|
||
|
);
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test("var a=3;" +
|
||
|
"function foo(){return a}" +
|
||
|
"(function(){var a=5;(function(){foo()})()})()",
|
||
|
"var a=3;" +
|
||
|
"{var a$$inline_1=5;{a}}"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables8() {
|
||
|
// this should be inlined
|
||
|
test("var a=0;" +
|
||
|
"function foo(){return 3}" +
|
||
|
"function _bar(){var a=foo()}",
|
||
|
|
||
|
"var a=0;" +
|
||
|
"function _bar(){var a=3}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables9() {
|
||
|
// this should be inlined too [even if the global is not declared]
|
||
|
test("function foo(){return 3}" +
|
||
|
"function _bar(){var a=foo()}",
|
||
|
|
||
|
"function _bar(){var a=3}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables10() {
|
||
|
// callee var must be renamed.
|
||
|
test("var a;function foo(){return a}" +
|
||
|
"function _bar(){var a=foo()}",
|
||
|
"var a;function _bar(){var a$$1=a}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables11() {
|
||
|
// The call has a local variable
|
||
|
// which collides with the function being inlined
|
||
|
test("var a=0;var b=1;" +
|
||
|
"function foo(){return a+a}" +
|
||
|
"function _bar(){var a=foo();alert(a)}",
|
||
|
"var a=0;var b=1;" +
|
||
|
"function _bar(){var a$$1=a+a;" +
|
||
|
"alert(a$$1)}"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables12() {
|
||
|
// 2 globals colliding
|
||
|
test("var a=0;var b=1;" +
|
||
|
"function foo(){return a+b}" +
|
||
|
"function _bar(){var a=foo(),b;alert(a)}",
|
||
|
"var a=0;var b=1;" +
|
||
|
"function _bar(){var a$$1=a+b," +
|
||
|
"b$$1;" +
|
||
|
"alert(a$$1)}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables13() {
|
||
|
// The only change is to remove the collision
|
||
|
test("var a=0;var b=1;" +
|
||
|
"function foo(){return a+a}" +
|
||
|
"function _bar(){var c=foo();alert(c)}",
|
||
|
|
||
|
"var a=0;var b=1;" +
|
||
|
"function _bar(){var c=a+a;alert(c)}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables14() {
|
||
|
// There is a collision even though it is not read.
|
||
|
test("var a=0;var b=1;" +
|
||
|
"function foo(){return a+b}" +
|
||
|
"function _bar(){var c=foo(),b;alert(c)}",
|
||
|
"var a=0;var b=1;" +
|
||
|
"function _bar(){var c=a+b," +
|
||
|
"b$$1;alert(c)}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables15() {
|
||
|
// Both parent and child reference a global
|
||
|
test("var a=0;var b=1;" +
|
||
|
"function foo(){return a+a}" +
|
||
|
"function _bar(){var c=foo();alert(c+a)}",
|
||
|
|
||
|
"var a=0;var b=1;" +
|
||
|
"function _bar(){var c=a+a;alert(c+a)}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables16() {
|
||
|
assumeMinimumCapture = false;
|
||
|
// Inline functions defined as a child of the CALL node.
|
||
|
test("var a=3;" +
|
||
|
"function foo(){return a}" +
|
||
|
"(function(){var a=5;(function(){foo()})()})()",
|
||
|
"var a=3;" +
|
||
|
"{var a$$inline_0=5;{a}}"
|
||
|
);
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
// Inline functions defined as a child of the CALL node.
|
||
|
test("var a=3;" +
|
||
|
"function foo(){return a}" +
|
||
|
"(function(){var a=5;(function(){foo()})()})()",
|
||
|
"var a=3;" +
|
||
|
"{var a$$inline_1=5;{a}}"
|
||
|
);
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables17() {
|
||
|
test("var a=0;" +
|
||
|
"function bar(){return a+a}" +
|
||
|
"function foo(){return bar()}" +
|
||
|
"function _goo(){var a=2;var x=foo();}",
|
||
|
|
||
|
"var a=0;" +
|
||
|
"function _goo(){var a$$1=2;var x=a+a}");
|
||
|
}
|
||
|
|
||
|
public void testShadowVariables18() {
|
||
|
test("var a=0;" +
|
||
|
"function bar(){return a+a}" +
|
||
|
"function foo(){var a=3;return bar()}" +
|
||
|
"function _goo(){var a=2;var x=foo();}",
|
||
|
|
||
|
"var a=0;" +
|
||
|
"function _goo(){var a$$2=2;var x;" +
|
||
|
"{var a$$inline_0=3;x=a+a}}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining1() {
|
||
|
testSame(
|
||
|
"function foo(a){return a}" +
|
||
|
"foo=new Function(\"return 1\");" +
|
||
|
"foo(1)");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining2() {
|
||
|
// Baseline complexity tests.
|
||
|
// Single call, function not removed.
|
||
|
test(
|
||
|
"function foo(a){return a}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){return foo(1)}",
|
||
|
|
||
|
"function foo(a){return a}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){return 1}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining3() {
|
||
|
// Two calls, function not removed.
|
||
|
test(
|
||
|
"function foo(a,b){return a+b}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){return foo(1,2)}" +
|
||
|
"function _t2(){return foo(2,3)}",
|
||
|
|
||
|
"function foo(a,b){return a+b}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){return 1+2}" +
|
||
|
"function _t2(){return 2+3}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining4() {
|
||
|
// Two calls, function not removed.
|
||
|
// Here there isn't enough savings to justify inlining.
|
||
|
testSame(
|
||
|
"function foo(a,b){return a+b+a+b}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){return foo(1,2)}" +
|
||
|
"function _t2(){return foo(2,3)}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining5() {
|
||
|
// Here there is enough savings to justify inlining.
|
||
|
test(
|
||
|
"function foo(a,b){return a+b+a+b}" +
|
||
|
"function _t1(){return foo(1,2)}" +
|
||
|
"function _t2(){return foo(2,3)}",
|
||
|
|
||
|
"function _t1(){return 1+2+1+2}" +
|
||
|
"function _t2(){return 2+3+2+3}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining6() {
|
||
|
// Here we have a threshold test.
|
||
|
// Do inline here:
|
||
|
test(
|
||
|
"function foo(a,b){return a+b+a+b+a+b+a+b+4+5+6+7+8+9+1+2+3+4+5}" +
|
||
|
"function _t1(){return foo(1,2)}" +
|
||
|
"function _t2(){return foo(2,3)}",
|
||
|
|
||
|
"function _t1(){return 1+2+1+2+1+2+1+2+4+5+6+7+8+9+1+2+3+4+5}" +
|
||
|
"function _t2(){return 2+3+2+3+2+3+2+3+4+5+6+7+8+9+1+2+3+4+5}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining7() {
|
||
|
// Don't inline here (not enough savings):
|
||
|
testSame(
|
||
|
"function foo(a,b){" +
|
||
|
" return a+b+a+b+a+b+a+b+4+5+6+7+8+9+1+2+3+4+5+6}" +
|
||
|
"function _t1(){return foo(1,2)}" +
|
||
|
"function _t2(){return foo(2,3)}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining8() {
|
||
|
// Verify multiple references in the same statement:
|
||
|
// Here "f" is not known to be removable, as it is a used as parameter
|
||
|
// and is not known to be side-effect free. The first call to f() can
|
||
|
// not be inlined on the first pass (as the call to f() as a parameter
|
||
|
// prevents this). However, the call to f() would be inlinable, if it
|
||
|
// is small enough to be inlined without removing the function declaration.
|
||
|
// but it is not in this first test.
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function f(a){return 1 + a + a;}" +
|
||
|
"var a = f(f(1));");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining9() {
|
||
|
// Here both direct and block inlining is used. The call to f as a
|
||
|
// parameter is inlined directly, which the call to f with f as a parameter
|
||
|
// is inlined using block inlining.
|
||
|
test("function f(a){return 1 + a + a;}" +
|
||
|
"var a = f(f(1));",
|
||
|
"var a;" +
|
||
|
"{var a$$inline_0=1+1+1;" +
|
||
|
"a=1+a$$inline_0+a$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining10() {
|
||
|
// But it is small enough here, and on the second iteration, the remaining
|
||
|
// call to f() is inlined, as there is no longer a possible side-effect-ing
|
||
|
// parameter.
|
||
|
allowBlockInlining = false;
|
||
|
test("function f(a){return a + a;}" +
|
||
|
"var a = f(f(1));",
|
||
|
"var a= 1+1+(1+1);");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining11() {
|
||
|
// With block inlining
|
||
|
test("function f(a){return a + a;}" +
|
||
|
"var a = f(f(1))",
|
||
|
"var a;" +
|
||
|
"{var a$$inline_0=1+1;" +
|
||
|
"a=a$$inline_0+a$$inline_0}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInlining12() {
|
||
|
test("function f(a){return 1 + a + a;}" +
|
||
|
"var a = f(1) + f(2);",
|
||
|
|
||
|
"var a=1+1+1+(1+2+2)");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex1() {
|
||
|
testSame(
|
||
|
"function foo(a){a()}" +
|
||
|
"foo=new Function(\"return 1\");" +
|
||
|
"foo(1)");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex2() {
|
||
|
// Baseline complexity tests.
|
||
|
// Single call, function not removed.
|
||
|
test(
|
||
|
"function foo(a){a()}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){foo(x)}",
|
||
|
|
||
|
"function foo(a){a()}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){{x()}}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex3() {
|
||
|
// Two calls, function not removed.
|
||
|
test(
|
||
|
"function foo(a,b){a+b}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){foo(1,2)}" +
|
||
|
"function _t2(){foo(2,3)}",
|
||
|
|
||
|
"function foo(a,b){a+b}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){{1+2}}" +
|
||
|
"function _t2(){{2+3}}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex4() {
|
||
|
// Two calls, function not removed.
|
||
|
// Here there isn't enough savings to justify inlining.
|
||
|
testSame(
|
||
|
"function foo(a,b){a+b+a+b}" +
|
||
|
"var b=foo;" +
|
||
|
"function _t1(){foo(1,2)}" +
|
||
|
"function _t2(){foo(2,3)}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex5() {
|
||
|
// Here there is enough savings to justify inlining.
|
||
|
test(
|
||
|
"function foo(a,b){a+b+a+b}" +
|
||
|
"function _t1(){foo(1,2)}" +
|
||
|
"function _t2(){foo(2,3)}",
|
||
|
|
||
|
"function _t1(){{1+2+1+2}}" +
|
||
|
"function _t2(){{2+3+2+3}}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex6() {
|
||
|
// Here we have a threshold test.
|
||
|
// Do inline here:
|
||
|
test(
|
||
|
"function foo(a,b){a+b+a+b+a+b+a+b+4+5+6+7+8+9+1}" +
|
||
|
"function _t1(){foo(1,2)}" +
|
||
|
"function _t2(){foo(2,3)}",
|
||
|
|
||
|
"function _t1(){{1+2+1+2+1+2+1+2+4+5+6+7+8+9+1}}" +
|
||
|
"function _t2(){{2+3+2+3+2+3+2+3+4+5+6+7+8+9+1}}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex7() {
|
||
|
// Don't inline here (not enough savings):
|
||
|
testSame(
|
||
|
"function foo(a,b){a+b+a+b+a+b+a+b+4+5+6+7+8+9+1+2}" +
|
||
|
"function _t1(){foo(1,2)}" +
|
||
|
"function _t2(){foo(2,3)}");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex8() {
|
||
|
// Verify multiple references in the same statement.
|
||
|
testSame("function _f(a){1+a+a}" +
|
||
|
"a=_f(1)+_f(1)");
|
||
|
}
|
||
|
|
||
|
public void testCostBasedInliningComplex9() {
|
||
|
test("function f(a){1 + a + a;}" +
|
||
|
"f(1);f(2);",
|
||
|
"{1+1+1}{1+2+2}");
|
||
|
}
|
||
|
|
||
|
public void testDoubleInlining1() {
|
||
|
allowBlockInlining = false;
|
||
|
test("var foo = function(a) { return getWindow(a); };" +
|
||
|
"var bar = function(b) { return b; };" +
|
||
|
"foo(bar(x));",
|
||
|
"getWindow(x)");
|
||
|
}
|
||
|
|
||
|
public void testDoubleInlining2() {
|
||
|
test("var foo = function(a) { return getWindow(a); };" +
|
||
|
"var bar = function(b) { return b; };" +
|
||
|
"foo(bar(x));",
|
||
|
"{getWindow(x)}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfNonGlobalFunction1() {
|
||
|
test("var g;function _f(){function g(){return 0}}" +
|
||
|
"function _h(){return g()}",
|
||
|
"var g;function _f(){}" +
|
||
|
"function _h(){return g()}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfNonGlobalFunction2() {
|
||
|
test("var g;function _f(){var g=function(){return 0}}" +
|
||
|
"function _h(){return g()}",
|
||
|
"var g;function _f(){}" +
|
||
|
"function _h(){return g()}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfNonGlobalFunction3() {
|
||
|
test("var g;function _f(){var g=function(){return 0}}" +
|
||
|
"function _h(){return g()}",
|
||
|
"var g;function _f(){}" +
|
||
|
"function _h(){return g()}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineOfNonGlobalFunction4() {
|
||
|
test("var g;function _f(){function g(){return 0}}" +
|
||
|
"function _h(){return g()}",
|
||
|
"var g;function _f(){}" +
|
||
|
"function _h(){return g()}");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testNoInlineMaskedFunction() {
|
||
|
// Normalization makes this test of marginal value.
|
||
|
// The unreferenced function is removed.
|
||
|
test("var g=function(){return 0};" +
|
||
|
"function _f(g){return g()}",
|
||
|
"function _f(g$$1){return g$$1()}");
|
||
|
}
|
||
|
|
||
|
public void testNoInlineNonFunction() {
|
||
|
testSame("var g=3;function _f(){return g()}");
|
||
|
}
|
||
|
|
||
|
public void testInlineCall() {
|
||
|
test("function f(g) { return g.h(); } f('x');",
|
||
|
"\"x\".h()");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctionWithArgsMismatch1() {
|
||
|
test("function f(g) { return g; } f();",
|
||
|
"void 0");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctionWithArgsMismatch2() {
|
||
|
test("function f() { return 0; } f(1);",
|
||
|
"0");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctionWithArgsMismatch3() {
|
||
|
test("function f(one, two, three) { return one + two + three; } f(1);",
|
||
|
"1+void 0+void 0");
|
||
|
}
|
||
|
|
||
|
public void testInlineFunctionWithArgsMismatch4() {
|
||
|
test("function f(one, two, three) { return one + two + three; }" +
|
||
|
"f(1,2,3,4,5);",
|
||
|
"1+2+3");
|
||
|
}
|
||
|
|
||
|
public void testArgumentsWithSideEffectsNeverInlined1() {
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function f(){return 0} f(new goo());");
|
||
|
}
|
||
|
|
||
|
public void testArgumentsWithSideEffectsNeverInlined2() {
|
||
|
allowBlockInlining = false;
|
||
|
testSame("function f(g,h){return h+g}f(g(),h());");
|
||
|
}
|
||
|
|
||
|
public void testOneSideEffectCallDoesNotRuinOthers() {
|
||
|
allowBlockInlining = false;
|
||
|
test("function f(){return 0}f(new goo());f()",
|
||
|
"function f(){return 0}f(new goo());0");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineNoResultNoParamCall1() {
|
||
|
test("function f(){a()}f()",
|
||
|
"{a()}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineNoResultNoParamCall2() {
|
||
|
test("function f(){if (true){return;}else;} f();",
|
||
|
"{JSCompiler_inline_label_f_0:{" +
|
||
|
"if(true)break JSCompiler_inline_label_f_0;else;}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineNoResultNoParamCall3() {
|
||
|
// We now allow vars in the global space.
|
||
|
// Don't inline into vars into global scope.
|
||
|
// testSame("function f(){a();b();var z=1+1}f()");
|
||
|
|
||
|
// But do inline into functions
|
||
|
test("function f(){a();b();var z=1+1}function _foo(){f()}",
|
||
|
"function _foo(){{a();b();var z$$inline_0=1+1}}");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineNoResultWithParamCall1() {
|
||
|
test("function f(x){a(x)}f(1)",
|
||
|
"{a(1)}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineNoResultWithParamCall2() {
|
||
|
test("function f(x,y){a(x)}var b=1;f(1,b)",
|
||
|
"var b=1;{a(1)}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineNoResultWithParamCall3() {
|
||
|
test("function f(x,y){if (x) y(); return true;}var b=1;f(1,b)",
|
||
|
"var b=1;{if(1)b();true}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline1() {
|
||
|
test("function f(){if (true){return;}else;} z=f();",
|
||
|
"{JSCompiler_inline_label_f_0:" +
|
||
|
"{if(true){z=void 0;" +
|
||
|
"break JSCompiler_inline_label_f_0}else;z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline2() {
|
||
|
test("function f(){if (true){return;}else return;} z=f();",
|
||
|
"{JSCompiler_inline_label_f_0:{if(true){z=void 0;" +
|
||
|
"break JSCompiler_inline_label_f_0}else{z=void 0;" +
|
||
|
"break JSCompiler_inline_label_f_0}z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline3() {
|
||
|
test("function f(){if (true){return 1;}else return 0;} z=f();",
|
||
|
"{JSCompiler_inline_label_f_0:{if(true){z=1;" +
|
||
|
"break JSCompiler_inline_label_f_0}else{z=0;" +
|
||
|
"break JSCompiler_inline_label_f_0}z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline4() {
|
||
|
test("function f(x){a(x)} z = f(1)",
|
||
|
"{a(1);z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline5() {
|
||
|
test("function f(x,y){a(x)}var b=1;z=f(1,b)",
|
||
|
"var b=1;{a(1);z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline6() {
|
||
|
test("function f(x,y){if (x) y(); return true;}var b=1;z=f(1,b)",
|
||
|
"var b=1;{if(1)b();z=true}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline7() {
|
||
|
test("function f(x,y){if (x) return y(); else return true;}" +
|
||
|
"var b=1;z=f(1,b)",
|
||
|
"var b=1;{JSCompiler_inline_label_f_2:{if(1){z=b();" +
|
||
|
"break JSCompiler_inline_label_f_2}else{z=true;" +
|
||
|
"break JSCompiler_inline_label_f_2}z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInline8() {
|
||
|
test("function f(x){a(x)}var z=f(1)",
|
||
|
"var z;{a(1);z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars1() {
|
||
|
test("function f(){if (true){return;}else;}var z=f();",
|
||
|
"var z;{JSCompiler_inline_label_f_0:{" +
|
||
|
"if(true){z=void 0;break JSCompiler_inline_label_f_0}else;z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars2() {
|
||
|
test("function f(){if (true){return;}else return;}var z=f();",
|
||
|
"var z;{JSCompiler_inline_label_f_0:{" +
|
||
|
"if(true){z=void 0;break JSCompiler_inline_label_f_0" +
|
||
|
"}else{" +
|
||
|
"z=void 0;break JSCompiler_inline_label_f_0}z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars3() {
|
||
|
test("function f(){if (true){return 1;}else return 0;}var z=f();",
|
||
|
"var z;{JSCompiler_inline_label_f_0:{if(true){" +
|
||
|
"z=1;break JSCompiler_inline_label_f_0" +
|
||
|
"}else{" +
|
||
|
"z=0;break JSCompiler_inline_label_f_0}z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars4() {
|
||
|
test("function f(x){a(x)}var z = f(1)",
|
||
|
"var z;{a(1);z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars5() {
|
||
|
test("function f(x,y){a(x)}var b=1;var z=f(1,b)",
|
||
|
"var b=1;var z;{a(1);z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars6() {
|
||
|
test("function f(x,y){if (x) y(); return true;}var b=1;var z=f(1,b)",
|
||
|
"var b=1;var z;{if(1)b();z=true}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars7() {
|
||
|
test("function f(x,y){if (x) return y(); else return true;}" +
|
||
|
"var b=1;var z=f(1,b)",
|
||
|
"var b=1;var z;" +
|
||
|
"{JSCompiler_inline_label_f_2:{if(1){z=b();" +
|
||
|
"break JSCompiler_inline_label_f_2" +
|
||
|
"}else{" +
|
||
|
"z=true;break JSCompiler_inline_label_f_2}z=void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars8() {
|
||
|
test("function f(x){a(x)}var x;var z=f(1)",
|
||
|
"var x;var z;{a(1);z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars9() {
|
||
|
test("function f(x){a(x)}var x;var z=f(1);var y",
|
||
|
"var x;var z;{a(1);z=void 0}var y");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars10() {
|
||
|
test("function f(x){a(x)}var x=blah();var z=f(1);var y=blah();",
|
||
|
"var x=blah();var z;{a(1);z=void 0}var y=blah()");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars11() {
|
||
|
test("function f(x){a(x)}var x=blah();var z=f(1);var y;",
|
||
|
"var x=blah();var z;{a(1);z=void 0}var y");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineVars12() {
|
||
|
test("function f(x){a(x)}var x;var z=f(1);var y=blah();",
|
||
|
"var x;var z;{a(1);z=void 0}var y=blah()");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineInExpresssions1() {
|
||
|
test("function f(){a()}var z=f()",
|
||
|
"var z;{a();z=void 0}");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineInExpresssions2() {
|
||
|
test("function f(){a()}c=z=f()",
|
||
|
"var JSCompiler_inline_result$$0;" +
|
||
|
"{a();JSCompiler_inline_result$$0=void 0;}" +
|
||
|
"c=z=JSCompiler_inline_result$$0");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineInExpresssions3() {
|
||
|
test("function f(){a()}c=z=f()",
|
||
|
"var JSCompiler_inline_result$$0;" +
|
||
|
"{a();JSCompiler_inline_result$$0=void 0;}" +
|
||
|
"c=z=JSCompiler_inline_result$$0");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineInExpresssions4() {
|
||
|
test("function f(){a()}if(z=f());",
|
||
|
"var JSCompiler_inline_result$$0;" +
|
||
|
"{a();JSCompiler_inline_result$$0=void 0;}" +
|
||
|
"if(z=JSCompiler_inline_result$$0);");
|
||
|
}
|
||
|
|
||
|
public void testComplexInlineInExpresssions5() {
|
||
|
test("function f(){a()}if(z.y=f());",
|
||
|
"var JSCompiler_temp_const$$0=z;" +
|
||
|
"var JSCompiler_inline_result$$1;" +
|
||
|
"{a();JSCompiler_inline_result$$1=void 0;}" +
|
||
|
"if(JSCompiler_temp_const$$0.y=JSCompiler_inline_result$$1);");
|
||
|
}
|
||
|
|
||
|
public void testComplexNoInline1() {
|
||
|
testSame("function f(){a()}while(z=f())continue");
|
||
|
}
|
||
|
|
||
|
public void testComplexNoInline2() {
|
||
|
testSame("function f(){a()}do;while(z=f())");
|
||
|
}
|
||
|
|
||
|
public void testComplexSample() {
|
||
|
String result = "" +
|
||
|
"{{" +
|
||
|
"var styleSheet$$inline_2=null;" +
|
||
|
"if(goog$userAgent$IE)" +
|
||
|
"styleSheet$$inline_2=0;" +
|
||
|
"else " +
|
||
|
"var head$$inline_3=0;" +
|
||
|
"{" +
|
||
|
"var element$$inline_4=" +
|
||
|
"styleSheet$$inline_2;" +
|
||
|
"var stylesString$$inline_5=a;" +
|
||
|
"if(goog$userAgent$IE)" +
|
||
|
"element$$inline_4.cssText=" +
|
||
|
"stylesString$$inline_5;" +
|
||
|
"else " +
|
||
|
"{" +
|
||
|
"var propToSet$$inline_6=" +
|
||
|
"\"innerText\";" +
|
||
|
"element$$inline_4[" +
|
||
|
"propToSet$$inline_6]=" +
|
||
|
"stylesString$$inline_5" +
|
||
|
"}" +
|
||
|
"}" +
|
||
|
"styleSheet$$inline_2" +
|
||
|
"}}";
|
||
|
|
||
|
test("var foo = function(stylesString, opt_element) { " +
|
||
|
"var styleSheet = null;" +
|
||
|
"if (goog$userAgent$IE)" +
|
||
|
"styleSheet = 0;" +
|
||
|
"else " +
|
||
|
"var head = 0;" +
|
||
|
"" +
|
||
|
"goo$zoo(styleSheet, stylesString);" +
|
||
|
"return styleSheet;" +
|
||
|
" };\n " +
|
||
|
|
||
|
"var goo$zoo = function(element, stylesString) {" +
|
||
|
"if (goog$userAgent$IE)" +
|
||
|
"element.cssText = stylesString;" +
|
||
|
"else {" +
|
||
|
"var propToSet = 'innerText';" +
|
||
|
"element[propToSet] = stylesString;" +
|
||
|
"}" +
|
||
|
"};" +
|
||
|
"(function(){foo(a,b);})();",
|
||
|
result);
|
||
|
}
|
||
|
|
||
|
public void testComplexSampleNoInline() {
|
||
|
// This is the result we would expect if we could handle "foo = function"
|
||
|
String result =
|
||
|
"foo=function(stylesString,opt_element){" +
|
||
|
"var styleSheet=null;" +
|
||
|
"if(goog$userAgent$IE){" +
|
||
|
"styleSheet=0" +
|
||
|
"}else{" +
|
||
|
"var head=0" +
|
||
|
"}" +
|
||
|
"{var JSCompiler_inline_element_0=styleSheet;" +
|
||
|
"var JSCompiler_inline_stylesString_1=stylesString;" +
|
||
|
"if(goog$userAgent$IE){" +
|
||
|
"JSCompiler_inline_element_0.cssText=" +
|
||
|
"JSCompiler_inline_stylesString_1" +
|
||
|
"}else{" +
|
||
|
"var propToSet=goog$userAgent$WEBKIT?\"innerText\":\"innerHTML\";" +
|
||
|
"JSCompiler_inline_element_0[propToSet]=" +
|
||
|
"JSCompiler_inline_stylesString_1" +
|
||
|
"}}" +
|
||
|
"return styleSheet" +
|
||
|
"}";
|
||
|
|
||
|
testSame(
|
||
|
"foo=function(stylesString,opt_element){" +
|
||
|
"var styleSheet=null;" +
|
||
|
"if(goog$userAgent$IE)" +
|
||
|
"styleSheet=0;" +
|
||
|
"else " +
|
||
|
"var head=0;" +
|
||
|
"" +
|
||
|
"goo$zoo(styleSheet,stylesString);" +
|
||
|
"return styleSheet" +
|
||
|
"};" +
|
||
|
"goo$zoo=function(element,stylesString){" +
|
||
|
"if(goog$userAgent$IE)" +
|
||
|
"element.cssText=stylesString;" +
|
||
|
"else{" +
|
||
|
"var propToSet=goog$userAgent$WEBKIT?\"innerText\":\"innerHTML\";" +
|
||
|
"element[propToSet]=stylesString" +
|
||
|
"}" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
// Test redefinition of parameter name.
|
||
|
public void testComplexNoVarSub() {
|
||
|
test(
|
||
|
"function foo(x){" +
|
||
|
"var x;" +
|
||
|
"y=x" +
|
||
|
"}" +
|
||
|
"foo(1)",
|
||
|
|
||
|
"{y=1}"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public void testComplexFunctionWithFunctionDefinition1() {
|
||
|
test("function f(){call(function(){return})}f()",
|
||
|
"{call(function(){return})}");
|
||
|
}
|
||
|
|
||
|
public void testComplexFunctionWithFunctionDefinition2() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
// Don't inline if local names might be captured.
|
||
|
testSame("function f(a){call(function(){return})}f()");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
test("(function(){" +
|
||
|
"var f = function(a){call(function(){return a})};f()})()",
|
||
|
"{{var a$$inline_0=void 0;call(function(){return a$$inline_0})}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexFunctionWithFunctionDefinition2a() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
// Don't inline if local names might be captured.
|
||
|
testSame("(function(){" +
|
||
|
"var f = function(a){call(function(){return a})};f()})()");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
test("(function(){" +
|
||
|
"var f = function(a){call(function(){return a})};f()})()",
|
||
|
"{{var a$$inline_0=void 0;call(function(){return a$$inline_0})}}");
|
||
|
}
|
||
|
|
||
|
public void testComplexFunctionWithFunctionDefinition3() {
|
||
|
assumeMinimumCapture = false;
|
||
|
|
||
|
// Don't inline if local names might need to be captured.
|
||
|
testSame("function f(){var a; call(function(){return a})}f()");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
|
||
|
test("function f(){var a; call(function(){return a})}f()",
|
||
|
"{var a$$inline_0;call(function(){return a$$inline_0})}");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testDecomposePlusEquals() {
|
||
|
test("function f(){a=1;return 1} var x = 1; x += f()",
|
||
|
"var x = 1;" +
|
||
|
"var JSCompiler_temp_const$$0 = x;" +
|
||
|
"var JSCompiler_inline_result$$1;" +
|
||
|
"{a=1;" +
|
||
|
" JSCompiler_inline_result$$1=1}" +
|
||
|
"x = JSCompiler_temp_const$$0 + JSCompiler_inline_result$$1;");
|
||
|
}
|
||
|
|
||
|
public void testDecomposeFunctionExpressionInCall() {
|
||
|
test(
|
||
|
"(function(map){descriptions_=map})(\n" +
|
||
|
"function(){\n" +
|
||
|
"var ret={};\n" +
|
||
|
"ret[ONE]='a';\n" +
|
||
|
"ret[TWO]='b';\n" +
|
||
|
"return ret\n" +
|
||
|
"}()\n" +
|
||
|
");",
|
||
|
"var JSCompiler_inline_result$$0;" +
|
||
|
"{" +
|
||
|
"var ret$$inline_1={};\n" +
|
||
|
"ret$$inline_1[ONE]='a';\n" +
|
||
|
"ret$$inline_1[TWO]='b';\n" +
|
||
|
"JSCompiler_inline_result$$0 = ret$$inline_1;\n" +
|
||
|
"}" +
|
||
|
"{" +
|
||
|
"descriptions_=JSCompiler_inline_result$$0;" +
|
||
|
"}"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public void testInlineConstructor1() {
|
||
|
test("function f() {} function _g() {f.call(this)}",
|
||
|
"function _g() {void 0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineConstructor2() {
|
||
|
test("function f() {} f.prototype.a = 0; function _g() {f.call(this)}",
|
||
|
"function f() {} f.prototype.a = 0; function _g() {void 0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineConstructor3() {
|
||
|
test("function f() {x.call(this)} f.prototype.a = 0;" +
|
||
|
"function _g() {f.call(this)}",
|
||
|
"function f() {x.call(this)} f.prototype.a = 0;" +
|
||
|
"function _g() {{x.call(this)}}");
|
||
|
}
|
||
|
|
||
|
public void testInlineConstructor4() {
|
||
|
test("function f() {x.call(this)} f.prototype.a = 0;" +
|
||
|
"function _g() {var t = f.call(this)}",
|
||
|
"function f() {x.call(this)} f.prototype.a = 0;" +
|
||
|
"function _g() {var t; {x.call(this); t = void 0}}");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionInlining1() {
|
||
|
test("(function(){})()",
|
||
|
"void 0");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionInlining2() {
|
||
|
test("(function(){foo()})()",
|
||
|
"{foo()}");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionInlining3() {
|
||
|
test("var a = (function(){return foo()})()",
|
||
|
"var a = foo()");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionInlining4() {
|
||
|
test("var a; a = 1 + (function(){return foo()})()",
|
||
|
"var a; a = 1 + foo()");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining1() {
|
||
|
test("(function(){}).call(this)",
|
||
|
"void 0");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining2() {
|
||
|
test("(function(){foo(this)}).call(this)",
|
||
|
"{foo(this)}");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining3() {
|
||
|
test("var a = (function(){return foo(this)}).call(this)",
|
||
|
"var a = foo(this)");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining4() {
|
||
|
test("var a; a = 1 + (function(){return foo(this)}).call(this)",
|
||
|
"var a; a = 1 + foo(this)");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining5() {
|
||
|
test("a:(function(){return foo()})()",
|
||
|
"a:foo()");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining6() {
|
||
|
test("a:(function(){return foo()}).call(this)",
|
||
|
"a:foo()");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining7() {
|
||
|
test("a:(function(){})()",
|
||
|
"a:void 0");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining8() {
|
||
|
test("a:(function(){}).call(this)",
|
||
|
"a:void 0");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining9() {
|
||
|
// ... with unused recursive name.
|
||
|
test("(function foo(){})()",
|
||
|
"void 0");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining10() {
|
||
|
// ... with unused recursive name.
|
||
|
test("(function foo(){}).call(this)",
|
||
|
"void 0");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining11a() {
|
||
|
// Inline functions that return inner functions.
|
||
|
test("((function(){return function(){foo()}})())();", "{foo()}");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining11b() {
|
||
|
assumeMinimumCapture = false;
|
||
|
// Can't inline functions that return inner functions and have local names.
|
||
|
testSame("((function(){var a; return function(){foo()}})())();");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test(
|
||
|
"((function(){var a; return function(){foo()}})())();",
|
||
|
|
||
|
"var JSCompiler_inline_result$$0;" +
|
||
|
"{var a$$inline_1;" +
|
||
|
"JSCompiler_inline_result$$0=function(){foo()};}" +
|
||
|
"JSCompiler_inline_result$$0()");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining11c() {
|
||
|
// TODO(johnlenz): Can inline, not temps needed.
|
||
|
assumeMinimumCapture = false;
|
||
|
testSame("function _x() {" +
|
||
|
" ((function(){return function(){foo()}})())();" +
|
||
|
"}");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test(
|
||
|
"function _x() {" +
|
||
|
" ((function(){return function(){foo()}})())();" +
|
||
|
"}",
|
||
|
"function _x() {" +
|
||
|
" {foo()}" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining11d() {
|
||
|
// TODO(johnlenz): Can inline into a function containing eval, if
|
||
|
// no names are introduced.
|
||
|
assumeMinimumCapture = false;
|
||
|
testSame("function _x() {" +
|
||
|
" eval();" +
|
||
|
" ((function(){return function(){foo()}})())();" +
|
||
|
"}");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test(
|
||
|
"function _x() {" +
|
||
|
" eval();" +
|
||
|
" ((function(){return function(){foo()}})())();" +
|
||
|
"}",
|
||
|
"function _x() {" +
|
||
|
" eval();" +
|
||
|
" {foo()}" +
|
||
|
"}");
|
||
|
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining11e() {
|
||
|
// No, don't inline into a function containing eval,
|
||
|
// if temps are introduced.
|
||
|
assumeMinimumCapture = false;
|
||
|
testSame("function _x() {" +
|
||
|
" eval();" +
|
||
|
" ((function(a){return function(){foo()}})())();" +
|
||
|
"}");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test("function _x() {" +
|
||
|
" eval();" +
|
||
|
" ((function(a){return function(){foo()}})())();" +
|
||
|
"}",
|
||
|
"function _x() {" +
|
||
|
" eval();" +
|
||
|
" {foo();}" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionCallInlining12() {
|
||
|
// Can't inline functions that recurse.
|
||
|
testSame("(function foo(){foo()})()");
|
||
|
}
|
||
|
|
||
|
public void testFunctionExpressionOmega() {
|
||
|
// ... with unused recursive name.
|
||
|
test("(function (f){f(f)})(function(f){f(f)})",
|
||
|
"{var f$$inline_0=function(f$$1){f$$1(f$$1)};" +
|
||
|
"{{f$$inline_0(f$$inline_0)}}}");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInlining1() {
|
||
|
test("function _f(){ function g() {} g() }",
|
||
|
"function _f(){ void 0 }");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInlining2() {
|
||
|
test("function _f(){ function g() {foo(); bar();} g() }",
|
||
|
"function _f(){ {foo(); bar();} }");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInlining3() {
|
||
|
test("function _f(){ function g() {foo(); bar();} g() }",
|
||
|
"function _f(){ {foo(); bar();} }");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInlining4() {
|
||
|
test("function _f(){ function g() {return 1} return g() }",
|
||
|
"function _f(){ return 1 }");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInlining5() {
|
||
|
testSame("function _f(){ function g() {this;} g() }");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInlining6() {
|
||
|
testSame("function _f(){ function g() {this;} return g; }");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInliningOnly1() {
|
||
|
this.allowGlobalFunctionInlining = true;
|
||
|
test("function f(){} f()", "void 0;");
|
||
|
this.allowGlobalFunctionInlining = false;
|
||
|
testSame("function f(){} f()");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInliningOnly2() {
|
||
|
this.allowGlobalFunctionInlining = false;
|
||
|
testSame("function f(){} f()");
|
||
|
|
||
|
test("function f(){ function g() {return 1} return g() }; f();",
|
||
|
"function f(){ return 1 }; f();");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInliningOnly3() {
|
||
|
this.allowGlobalFunctionInlining = false;
|
||
|
testSame("function f(){} f()");
|
||
|
|
||
|
test("(function(){ function g() {return 1} return g() })();",
|
||
|
"(function(){ return 1 })();");
|
||
|
}
|
||
|
|
||
|
public void testLocalFunctionInliningOnly4() {
|
||
|
this.allowGlobalFunctionInlining = false;
|
||
|
testSame("function f(){} f()");
|
||
|
|
||
|
test("(function(){ return (function() {return 1})() })();",
|
||
|
"(function(){ return 1 })();");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis1() {
|
||
|
assumeStrictThis = false;
|
||
|
// If no "this" is provided it might need to be coerced to the global
|
||
|
// "this".
|
||
|
testSame("function f(){} f.call();");
|
||
|
testSame("function f(){this} f.call();");
|
||
|
|
||
|
assumeStrictThis = true;
|
||
|
// In strict mode, "this" is never coerced so we can use the provided value.
|
||
|
test("function f(){} f.call();", "{}");
|
||
|
test("function f(){this} f.call();",
|
||
|
"{void 0;}");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis2() {
|
||
|
// "this" can always be replaced with "this"
|
||
|
assumeStrictThis = false;
|
||
|
test("function f(){} f.call(this);", "void 0");
|
||
|
|
||
|
assumeStrictThis = true;
|
||
|
test("function f(){} f.call(this);", "void 0");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis3() {
|
||
|
assumeStrictThis = false;
|
||
|
// If no "this" is provided it might need to be coerced to the global
|
||
|
// "this".
|
||
|
testSame("function f(){} f.call([]);");
|
||
|
|
||
|
assumeStrictThis = true;
|
||
|
// In strict mode, "this" is never coerced so we can use the provided value.
|
||
|
test("function f(){} f.call([]);", "{}");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis4() {
|
||
|
assumeStrictThis = false;
|
||
|
// If no "this" is provided it might need to be coerced to the global
|
||
|
// "this".
|
||
|
testSame("function f(){} f.call(new g);");
|
||
|
|
||
|
assumeStrictThis = true;
|
||
|
// In strict mode, "this" is never coerced so we can use the provided value.
|
||
|
test("function f(){} f.call(new g);",
|
||
|
"{var JSCompiler_inline_this_0=new g}");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis5() {
|
||
|
assumeStrictThis = false;
|
||
|
// If no "this" is provided it might need to be coerced to the global
|
||
|
// "this".
|
||
|
testSame("function f(){} f.call(g());");
|
||
|
|
||
|
assumeStrictThis = true;
|
||
|
// In strict mode, "this" is never coerced so we can use the provided value.
|
||
|
test("function f(){} f.call(g());",
|
||
|
"{var JSCompiler_inline_this_0=g()}");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis6() {
|
||
|
assumeStrictThis = false;
|
||
|
// If no "this" is provided it might need to be coerced to the global
|
||
|
// "this".
|
||
|
testSame("function f(){this} f.call(new g);");
|
||
|
|
||
|
assumeStrictThis = true;
|
||
|
// In strict mode, "this" is never coerced so we can use the provided value.
|
||
|
test("function f(){this} f.call(new g);",
|
||
|
"{var JSCompiler_inline_this_0=new g;JSCompiler_inline_this_0}");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithThis7() {
|
||
|
assumeStrictThis = true;
|
||
|
// In strict mode, "this" is never coerced so we can use the provided value.
|
||
|
test("function f(a){a=1;this} f.call();",
|
||
|
"{var a$$inline_0=void 0; a$$inline_0=1; void 0;}");
|
||
|
test("function f(a){a=1;this} f.call(x, x);",
|
||
|
"{var a$$inline_0=x; a$$inline_0=1; x;}");
|
||
|
}
|
||
|
|
||
|
// http://en.wikipedia.org/wiki/Fixed_point_combinator#Y_combinator
|
||
|
public void testFunctionExpressionYCombinator() {
|
||
|
assumeMinimumCapture = false;
|
||
|
testSame(
|
||
|
"var factorial = ((function(M) {\n" +
|
||
|
" return ((function(f) {\n" +
|
||
|
" return M(function(arg) {\n" +
|
||
|
" return (f(f))(arg);\n" +
|
||
|
" })\n" +
|
||
|
" })\n" +
|
||
|
" (function(f) {\n" +
|
||
|
" return M(function(arg) {\n" +
|
||
|
" return (f(f))(arg);\n" +
|
||
|
" })\n" +
|
||
|
" }));\n" +
|
||
|
" })\n" +
|
||
|
" (function(f) {\n" +
|
||
|
" return function(n) {\n" +
|
||
|
" if (n === 0)\n" +
|
||
|
" return 1;\n" +
|
||
|
" else\n" +
|
||
|
" return n * f(n - 1);\n" +
|
||
|
" };\n" +
|
||
|
" }));\n" +
|
||
|
"\n" +
|
||
|
"factorial(5)\n");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test(
|
||
|
"var factorial = ((function(M) {\n" +
|
||
|
" return ((function(f) {\n" +
|
||
|
" return M(function(arg) {\n" +
|
||
|
" return (f(f))(arg);\n" +
|
||
|
" })\n" +
|
||
|
" })\n" +
|
||
|
" (function(f) {\n" +
|
||
|
" return M(function(arg) {\n" +
|
||
|
" return (f(f))(arg);\n" +
|
||
|
" })\n" +
|
||
|
" }));\n" +
|
||
|
" })\n" +
|
||
|
" (function(f) {\n" +
|
||
|
" return function(n) {\n" +
|
||
|
" if (n === 0)\n" +
|
||
|
" return 1;\n" +
|
||
|
" else\n" +
|
||
|
" return n * f(n - 1);\n" +
|
||
|
" };\n" +
|
||
|
" }));\n" +
|
||
|
"\n" +
|
||
|
"factorial(5)\n",
|
||
|
"var factorial;\n" +
|
||
|
"{\n" +
|
||
|
"var M$$inline_4 = function(f$$2) {\n" +
|
||
|
" return function(n){if(n===0)return 1;else return n*f$$2(n-1)}\n" +
|
||
|
"};\n" +
|
||
|
"{\n" +
|
||
|
"var f$$inline_0=function(f$$inline_7){\n" +
|
||
|
" return M$$inline_4(\n" +
|
||
|
" function(arg$$inline_8){\n" +
|
||
|
" return f$$inline_7(f$$inline_7)(arg$$inline_8)\n" +
|
||
|
" })\n" +
|
||
|
"};\n" +
|
||
|
"factorial=M$$inline_4(\n" +
|
||
|
" function(arg$$inline_1){\n" +
|
||
|
" return f$$inline_0(f$$inline_0)(arg$$inline_1)\n" +
|
||
|
"});\n" +
|
||
|
"}\n" +
|
||
|
"}" +
|
||
|
"factorial(5)");
|
||
|
}
|
||
|
|
||
|
public void testRenamePropertyFunction() {
|
||
|
testSame("function JSCompiler_renameProperty(x) {return x} " +
|
||
|
"JSCompiler_renameProperty('foo')");
|
||
|
}
|
||
|
|
||
|
public void testReplacePropertyFunction() {
|
||
|
// baseline: an alias doesn't prevents declaration removal, but not
|
||
|
// inlining.
|
||
|
test("function f(x) {return x} " +
|
||
|
"foo(window, f); f(1)",
|
||
|
"function f(x) {return x} " +
|
||
|
"foo(window, f); 1");
|
||
|
// a reference passed to JSCompiler_ObjectPropertyString prevents inlining
|
||
|
// as well.
|
||
|
testSame("function f(x) {return x} " +
|
||
|
"new JSCompiler_ObjectPropertyString(window, f); f(1)");
|
||
|
}
|
||
|
|
||
|
public void testInlineWithClosureContainingThis() {
|
||
|
test("(function (){return f(function(){return this})})();",
|
||
|
"f(function(){return this})");
|
||
|
}
|
||
|
|
||
|
public void testIssue5159924a() {
|
||
|
test("function f() { if (x()) return y() }\n" +
|
||
|
"while(1){ var m = f() || z() }",
|
||
|
"for(;1;) {" +
|
||
|
" var JSCompiler_inline_result$$0;" +
|
||
|
" {" +
|
||
|
" JSCompiler_inline_label_f_1: {" +
|
||
|
" if(x()) {" +
|
||
|
" JSCompiler_inline_result$$0 = y();" +
|
||
|
" break JSCompiler_inline_label_f_1" +
|
||
|
" }" +
|
||
|
" JSCompiler_inline_result$$0 = void 0;" +
|
||
|
" }" +
|
||
|
" }" +
|
||
|
" var m=JSCompiler_inline_result$$0 || z()" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testIssue5159924b() {
|
||
|
test("function f() { if (x()) return y() }\n" +
|
||
|
"while(1){ var m = f() }",
|
||
|
"for(;1;){" +
|
||
|
" var m;" +
|
||
|
" {" +
|
||
|
" JSCompiler_inline_label_f_0: { " +
|
||
|
" if(x()) {" +
|
||
|
" m = y();" +
|
||
|
" break JSCompiler_inline_label_f_0" +
|
||
|
" }" +
|
||
|
" m = void 0" +
|
||
|
" }" +
|
||
|
" }" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testInlineObject() {
|
||
|
new StringCompare().testInlineObject();
|
||
|
}
|
||
|
|
||
|
private static class StringCompare extends CompilerTestCase {
|
||
|
private boolean allowGlobalFunctionInlining = true;
|
||
|
|
||
|
StringCompare() {
|
||
|
super("", false);
|
||
|
this.enableNormalize();
|
||
|
this.enableMarkNoSideEffects();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setUp() throws Exception {
|
||
|
super.setUp();
|
||
|
super.enableLineNumberCheck(true);
|
||
|
allowGlobalFunctionInlining = true;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected CompilerPass getProcessor(Compiler compiler) {
|
||
|
compiler.resetUniqueNameId();
|
||
|
return new InlineFunctions(
|
||
|
compiler,
|
||
|
compiler.getUniqueNameIdSupplier(),
|
||
|
allowGlobalFunctionInlining,
|
||
|
true, // allowLocalFunctionInlining
|
||
|
true, // allowBlockInlining
|
||
|
true, // assumeStrictThis
|
||
|
true); // assumeMinimumCapture
|
||
|
}
|
||
|
|
||
|
public void testInlineObject() {
|
||
|
allowGlobalFunctionInlining = false;
|
||
|
// TODO(johnlenz): normalize the AST so an AST comparison can be done.
|
||
|
// As is, the expected AST does not match the actual correct result:
|
||
|
// The AST matches "g.a()" with a FREE_CALL annotation, but this as
|
||
|
// expected string would fail as it won't be mark as a free call.
|
||
|
// "(0,g.a)()" matches the output, but not the resulting AST.
|
||
|
test("function inner(){function f(){return g.a}(f())()}",
|
||
|
"function inner(){(0,g.a)()}");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void testBug4944818() {
|
||
|
test(
|
||
|
"var getDomServices_ = function(self) {\n" +
|
||
|
" if (!self.domServices_) {\n" +
|
||
|
" self.domServices_ = goog$component$DomServices.get(" +
|
||
|
" self.appContext_);\n" +
|
||
|
" }\n" +
|
||
|
"\n" +
|
||
|
" return self.domServices_;\n" +
|
||
|
"};\n" +
|
||
|
"\n" +
|
||
|
"var getOwnerWin_ = function(self) {\n" +
|
||
|
" return getDomServices_(self).getDomHelper().getWindow();\n" +
|
||
|
"};\n" +
|
||
|
"\n" +
|
||
|
"HangoutStarter.prototype.launchHangout = function() {\n" +
|
||
|
" var self = a.b;\n" +
|
||
|
" var myUrl = new goog.Uri(getOwnerWin_(self).location.href);\n" +
|
||
|
"};",
|
||
|
"HangoutStarter.prototype.launchHangout = function() { " +
|
||
|
" var self$$2 = a.b;" +
|
||
|
" var JSCompiler_temp_const$$0 = goog.Uri;" +
|
||
|
" var JSCompiler_inline_result$$1;" +
|
||
|
" {" +
|
||
|
" var self$$inline_2 = self$$2;" +
|
||
|
" if (!self$$inline_2.domServices_) {" +
|
||
|
" self$$inline_2.domServices_ = goog$component$DomServices.get(" +
|
||
|
" self$$inline_2.appContext_);" +
|
||
|
" }" +
|
||
|
" JSCompiler_inline_result$$1=self$$inline_2.domServices_;" +
|
||
|
" }" +
|
||
|
" var myUrl = new JSCompiler_temp_const$$0(" +
|
||
|
" JSCompiler_inline_result$$1.getDomHelper()." +
|
||
|
" getWindow().location.href)" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testIssue423() {
|
||
|
assumeMinimumCapture = false;
|
||
|
test(
|
||
|
"(function($) {\n" +
|
||
|
" $.fn.multicheck = function(options) {\n" +
|
||
|
" initialize.call(this, options);\n" +
|
||
|
" };\n" +
|
||
|
"\n" +
|
||
|
" function initialize(options) {\n" +
|
||
|
" options.checkboxes = $(this).siblings(':checkbox');\n" +
|
||
|
" preload_check_all.call(this);\n" +
|
||
|
" }\n" +
|
||
|
"\n" +
|
||
|
" function preload_check_all() {\n" +
|
||
|
" $(this).data('checkboxes');\n" +
|
||
|
" }\n" +
|
||
|
"})(jQuery)",
|
||
|
"(function($){" +
|
||
|
" $.fn.multicheck=function(options$$1){" +
|
||
|
" {" +
|
||
|
" options$$1.checkboxes=$(this).siblings(\":checkbox\");" +
|
||
|
" {" +
|
||
|
" $(this).data(\"checkboxes\")" +
|
||
|
" }" +
|
||
|
" }" +
|
||
|
" }" +
|
||
|
"})(jQuery)");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test(
|
||
|
"(function($) {\n" +
|
||
|
" $.fn.multicheck = function(options) {\n" +
|
||
|
" initialize.call(this, options);\n" +
|
||
|
" };\n" +
|
||
|
"\n" +
|
||
|
" function initialize(options) {\n" +
|
||
|
" options.checkboxes = $(this).siblings(':checkbox');\n" +
|
||
|
" preload_check_all.call(this);\n" +
|
||
|
" }\n" +
|
||
|
"\n" +
|
||
|
" function preload_check_all() {\n" +
|
||
|
" $(this).data('checkboxes');\n" +
|
||
|
" }\n" +
|
||
|
"})(jQuery)",
|
||
|
"{var $$$inline_0=jQuery;\n" +
|
||
|
"$$$inline_0.fn.multicheck=function(options$$inline_4){\n" +
|
||
|
" {options$$inline_4.checkboxes=" +
|
||
|
"$$$inline_0(this).siblings(\":checkbox\");\n" +
|
||
|
" {$$$inline_0(this).data(\"checkboxes\")}" +
|
||
|
" }\n" +
|
||
|
"}\n" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testIssue728() {
|
||
|
String f = "var f = function() { return false; };";
|
||
|
StringBuilder calls = new StringBuilder();
|
||
|
StringBuilder folded = new StringBuilder();
|
||
|
for (int i = 0; i < 30; i++) {
|
||
|
calls.append("if (!f()) alert('x');");
|
||
|
folded.append("if (!false) alert('x');");
|
||
|
}
|
||
|
|
||
|
test(f + calls, folded.toString());
|
||
|
}
|
||
|
|
||
|
public void testAnonymous1() {
|
||
|
assumeMinimumCapture = false;
|
||
|
test("(function(){var a=10;(function(){var b=a;a++;alert(b)})()})();",
|
||
|
"{var a$$inline_0=10;" +
|
||
|
"{var b$$inline_1=a$$inline_0;" +
|
||
|
"a$$inline_0++;alert(b$$inline_1)}}");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test("(function(){var a=10;(function(){var b=a;a++;alert(b)})()})();",
|
||
|
"{var a$$inline_2=10;" +
|
||
|
"{var b$$inline_0=a$$inline_2;" +
|
||
|
"a$$inline_2++;alert(b$$inline_0)}}");
|
||
|
}
|
||
|
|
||
|
public void testAnonymous2() {
|
||
|
testSame("(function(){eval();(function(){var b=a;a++;alert(b)})()})();");
|
||
|
}
|
||
|
|
||
|
public void testAnonymous3() {
|
||
|
// Introducing a new value into is tricky
|
||
|
assumeMinimumCapture = false;
|
||
|
testSame("(function(){var a=10;(function(){arguments;})()})();");
|
||
|
|
||
|
assumeMinimumCapture = true;
|
||
|
test("(function(){var a=10;(function(){arguments;})()})();",
|
||
|
"{var a$$inline_0=10;(function(){arguments;})();}");
|
||
|
|
||
|
test("(function(){(function(){arguments;})()})();",
|
||
|
"{(function(){arguments;})()}");
|
||
|
}
|
||
|
|
||
|
|
||
|
public void testLoopWithFunctionWithFunction() {
|
||
|
assumeMinimumCapture = true;
|
||
|
test("function _testLocalVariableInLoop_() {\n" +
|
||
|
" var result = 0;\n" +
|
||
|
" function foo() {\n" +
|
||
|
" var arr = [1, 2, 3, 4, 5];\n" +
|
||
|
" for (var i = 0, l = arr.length; i < l; i++) {\n" +
|
||
|
" var j = arr[i];\n" +
|
||
|
// don't inline this function, because the correct behavior depends
|
||
|
// captured values.
|
||
|
" (function() {\n" +
|
||
|
" var k = j;\n" +
|
||
|
" setTimeout(function() { result += k; }, 5 * i);\n" +
|
||
|
" })();\n" +
|
||
|
" }\n" +
|
||
|
" }\n" +
|
||
|
" foo();\n" +
|
||
|
"}",
|
||
|
"function _testLocalVariableInLoop_(){\n" +
|
||
|
" var result=0;\n" +
|
||
|
" {" +
|
||
|
" var arr$$inline_0=[1,2,3,4,5];\n" +
|
||
|
" var i$$inline_1=0;\n" +
|
||
|
" var l$$inline_2=arr$$inline_0.length;\n" +
|
||
|
" for(;i$$inline_1<l$$inline_2;i$$inline_1++){\n" +
|
||
|
" var j$$inline_3=arr$$inline_0[i$$inline_1];\n" +
|
||
|
" (function(){\n" +
|
||
|
" var k$$inline_4=j$$inline_3;\n" +
|
||
|
" setTimeout(function(){result+=k$$inline_4},5*i$$inline_1)\n" +
|
||
|
" })()\n" +
|
||
|
" }\n" +
|
||
|
" }\n" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
public void testMethodWithFunctionWithFunction() {
|
||
|
assumeMinimumCapture = true;
|
||
|
test("function _testLocalVariable_() {\n" +
|
||
|
" var result = 0;\n" +
|
||
|
" function foo() {\n" +
|
||
|
" var j = [i];\n" +
|
||
|
" (function(j) {\n" +
|
||
|
" setTimeout(function() { result += j; }, 5 * i);\n" +
|
||
|
" })(j);\n" +
|
||
|
" j = null;" +
|
||
|
" }\n" +
|
||
|
" foo();\n" +
|
||
|
"}",
|
||
|
"function _testLocalVariable_(){\n" +
|
||
|
" var result=0;\n" +
|
||
|
" {\n" +
|
||
|
" var j$$inline_2=[i];\n" +
|
||
|
" {\n" +
|
||
|
" var j$$inline_0=j$$inline_2;\n" + // this temp is needed.
|
||
|
" setTimeout(function(){result+=j$$inline_0},5*i);\n" +
|
||
|
" }\n" +
|
||
|
" j$$inline_2=null\n" + // because this value can be modified later.
|
||
|
" }\n" +
|
||
|
"}");
|
||
|
}
|
||
|
|
||
|
// Inline a single reference function into deeper modules
|
||
|
public void testCrossModuleInlining1() {
|
||
|
test(createModuleChain(
|
||
|
// m1
|
||
|
"function foo(){return f(1)+g(2)+h(3);}",
|
||
|
// m2
|
||
|
"foo()"
|
||
|
),
|
||
|
new String[] {
|
||
|
// m1
|
||
|
"",
|
||
|
// m2
|
||
|
"f(1)+g(2)+h(3);"
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Inline a single reference function into shallow modules, only if it
|
||
|
// is cheaper than the call itself.
|
||
|
public void testCrossModuleInlining2() {
|
||
|
testSame(createModuleChain(
|
||
|
// m1
|
||
|
"foo()",
|
||
|
// m2
|
||
|
"function foo(){return f(1)+g(2)+h(3);}"
|
||
|
)
|
||
|
);
|
||
|
|
||
|
test(createModuleChain(
|
||
|
// m1
|
||
|
"foo()",
|
||
|
// m2
|
||
|
"function foo(){return f();}"
|
||
|
),
|
||
|
new String[] {
|
||
|
// m1
|
||
|
"f();",
|
||
|
// m2
|
||
|
""
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Inline a multi-reference functions into shallow modules, only if it
|
||
|
// is cheaper than the call itself.
|
||
|
public void testCrossModuleInlining3() {
|
||
|
testSame(createModuleChain(
|
||
|
// m1
|
||
|
"foo()",
|
||
|
// m2
|
||
|
"function foo(){return f(1)+g(2)+h(3);}",
|
||
|
// m3
|
||
|
"foo()"
|
||
|
)
|
||
|
);
|
||
|
|
||
|
test(createModuleChain(
|
||
|
// m1
|
||
|
"foo()",
|
||
|
// m2
|
||
|
"function foo(){return f();}",
|
||
|
// m3
|
||
|
"foo()"
|
||
|
),
|
||
|
new String[] {
|
||
|
// m1
|
||
|
"f();",
|
||
|
// m2
|
||
|
"",
|
||
|
// m3
|
||
|
"f();"
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public void test6671158() {
|
||
|
test(
|
||
|
"function f() {return g()}" +
|
||
|
"function Y(a){a.loader_()}" +
|
||
|
"function _Z(){}" +
|
||
|
"function _X() { new _Z(a,b, Y(singleton), f()) }",
|
||
|
|
||
|
"function _Z(){}" +
|
||
|
"function _X(){" +
|
||
|
" var JSCompiler_temp_const$$2=_Z;" +
|
||
|
" var JSCompiler_temp_const$$1=a;" +
|
||
|
" var JSCompiler_temp_const$$0=b;" +
|
||
|
" var JSCompiler_inline_result$$3;" +
|
||
|
" {" +
|
||
|
" singleton.loader_();" +
|
||
|
" JSCompiler_inline_result$$3=void 0;" +
|
||
|
" }" +
|
||
|
" new JSCompiler_temp_const$$2(" +
|
||
|
" JSCompiler_temp_const$$1," +
|
||
|
" JSCompiler_temp_const$$0," +
|
||
|
" JSCompiler_inline_result$$3," +
|
||
|
" g())}");
|
||
|
}
|
||
|
|
||
|
}
|