google / google/closure-compiler

No outlining? / counterproductive inlining?

Open
#3,203 5 comments 0 reactions 0 assignees View on GitHub
internal-issue-created triage-done
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.