Skip to content

An annotation to either prevent or force inlining of a function #2751

Closed

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:

  1. 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.

  2. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions