google / google/closure-compiler
No outlining? / counterproductive inlining?
- Dominant language
- JavaScript
- Stars
- 7.7k
- Forks
- 1.2k
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 6
Description
Consider
A:
```js
function foo(timeStamp) {
console.log(timeStamp);
}
function emscripten_request_animation_frame_loop(cb) {
function tick(timeStamp) {
cb(timeStamp);
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
emscripten_request_animation_frame_loop(foo);
```
this minifies down to
1:
```js
(function(a){function b(c){a(c);requestAnimationFrame(b)}requestAnimationFrame(b)})(function(a){console.log(a)});
```
which is 113 bytes. Beautified to be more readable:
```js
(function(a) {
function b(c) {
a(c);
requestAnimationFrame(b)
}
requestAnimationFrame(b)
})(function(a) {
console.log(a)
});
```
the extern browser API function `requestAnimationFrame` is sufficiently long, that it would be beneficial to outline access to that function. That is, one can hand-write the following equivalent minified code:
2:
```js
function d(a){requestAnimationFrame(a)}(function(a){function b(c){a(c);d(b)}d(b)})(function(a){console.log(a)});
```
which is 112 bytes, winning by one character. Beautified for better readability:
```js
function d(a) {
requestAnimationFrame(a)
}(function(a) {
function b(c) {
a(c);
d(b)
}
d(b)
})(function(a) {
console.log(a)
});
```
I.e. if access to `requestAnimationFrame()` is outlined to a function of its own that is minified, then it can be accessed via a minified name to net a size saving. Here the saving is only one byte, but if across the whole program there were more accesses to `requestAnimationFrame()`, the saving would be more considerable.
Of course there is an extra function call indirection, which might mean lower performance, so not sure if this is something that would always be better, but perhaps a tradeoff call. However, if I manually outline, i.e. had hand-written the following JS code to start with:
B:
```js
function raf(f) {
return requestAnimationFrame(f);
}
function foo(timeStamp) {
console.log(timeStamp);
}
function emscripten_request_animation_frame_loop(cb) {
function tick(timeStamp) {
cb(timeStamp);
raf(tick);
}
raf(tick);
}
emscripten_request_animation_frame_loop(foo);
```
then it seems like an incorrect call for Closure to inline function `raf`, because the resulting program will be bigger by one character than the version where `raf` was not inlined. So in this case, one might expect to get version 2 instead of 1 to retain the small size? However the above code does generate 1, instead of 2.
The above raises two questions to mind:
- Does Closure ever outline functions if that would produce a net win in code size? If not, I'd like to manually identify places where I should outline, like the requestAnimationFrame() case above.
- I wonder if the fact that it inlined version B was just a fluke of this example because of the really close call in sizes between the two versions (112 vs 113 bytes)? Now Closure is undoing my own manual outlining for a counterproductive effect. Is there a way I could tell Closure to not inline my function?
Contributor guide
Assessment
This issue has not been assessed yet.