An annotation to either prevent or force inlining of a function #2751
Description
We've been using GCC in the simple mode for compiling React for a few months, and are really happy with its heuristics. However, recently I've been noticing a minor pain point.
Problem
In some cases, as library authors we want to have more control over whether a function should be inlined or not. In particular, there are two scenarios:
-
Some functions are in a very hot path, and we have determined that not inlining them would hurt the runtime performance. Usually at this point we just inline them manually in the code. However, that often produces duplicate code that is hard to work with. Ideally, we'd love to have a way to tell GCC that it has to either inline a function or fail the build (if it’s impossible). This way we know that we won’t regress on this particular function.
-
There is an opposite problem as well. Sometimes we split a function into several to have tighter control over the argument types. For example, if some path is very hot, and we need to ensure a function is called with monomorphic arguments. However, GCC can break these optimizations by inlining the separated function (and thus preventing engines from optimizing that code due to deopts). For this use case, we'd like to have a way to tell GCC to not inline a function, even if the resulting code size will be larger.
Prior Art
The other GCC 🙂
Proposal
New @inline
annotation forces inlining
/** @inline */
function someHelper() {
// ...
}
// We want to fail the build if these couldn't be inlined.
someHelper();
someHelper();
This forces the function to be inlined even if the code size becomes bigger.
If it can’t be inlined, the build fails.
Alternative possible naming: @always-inline
, @force-inline
.
New @noinline
annotation prevents inlining
/** @noinline */
function doSomethingWithString(stringValue) {
// ...
}
/** @noinline */
function doSomethingWithNumber(numberValue) {
// ...
}
function doSomething(mixedValue) {
// It is important that these calls never get inlined
if (typeof mixedValue === 'string') {
doSomethingWithString(mixedValue);
} else if (typeof mixedValue === 'number') {
doSomethingWithNumber(mixedValue);
}
}
This forces a function to never be considered for inlining, even if there is a size win.
Alternative possible naming: @never-inline
, @prevent-inline
.
Other hint formats?
I don't have a strong opinion about how to supply these hints. A comment, a JSDoc annotation, special function name, etc, would all work for me. Please let me know if this is something you would consider!
Current Workarounds
In case anyone’s curious, I’ve thought a bit about how to achieve this today.
Forcing inlining
There's no way to force inlining, but we could plausibly adopt a special naming convention (e.g. *Inline
). We already have a special build where we disable the renaming pass (#2707) so we could analyze the bundle, and fail the build if any *Inline
function still exists. This wouldn’t force GCC to inline it, but at least we’d know if it was inlined but then started bailing.
Preventing inlining
This file might contain some hints. For example attaching function to an object would prevent inlining that function.
Of course it would be nice to have an official solution for this, as both options are hacky and incomplete.
Activity