The following code:
function f(a) { a.a = 5; return a; }
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
f(function() {});
is optimized by Closure compiler to this:
function a(){return function(){}}function b(c){c.a=5}b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());b(a());
(It leaves the dead code.)
However, if I remove the last line (repeat the calling only 24x), it removes the dead code. The result is empty.
How can I force the Closure compiler to remove all the dead code also in larger projects?
The difference is whether the compiler decides to inline "f" or not. Once it is inlined "(function(){}).a = 5" is a dead expression. Before that "f" is a function that has side-effects (it modifies its parameters) and is not removable on its own.
The decision to inline is based on an estimate as to whether inlining will result in smaller code size. The change from 24 to 25 in this case is the tipping point for when the cost of inlining is estimated to be more than what is saved by removing the function definition.