Skip to content

Commit

Permalink
Speed up SingleFieldBuilder.getBuilder() by avoiding reloading this.b…
Browse files Browse the repository at this point in the history
…uilder at return.

See godbolt for Android ART compiler: https://godbolt.org/z/M9dWhdqbf

This optimisation brings the implementation  down from 284 bytes to 272 bytes.

- `GeneratedMessage$Builder SingleFieldBuilder.getBuilder() [284 bytes]`
- `GeneratedMessage$Builder SingleFieldBuilder.getBuilder__withLocalVariable() [272 bytes]`

It's not big. It's just a few instructions dropped. These were dropped just before the `ret`:

```
-mov x23, x1
-ldr w0, [x23, #8]
```

And this load dropped before calling `markClean`.
```
-ldr w1, [x23, #8]
```

PiperOrigin-RevId: 677669563
  • Loading branch information
mhansen authored and copybara-github committed Oct 8, 2024
1 parent 9dad0b9 commit 4f00042
Showing 1 changed file with 7 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,18 @@ public MType build() {
*/
@SuppressWarnings("unchecked")
public BType getBuilder() {
// This code is very hot.
// Optimisation: store this.builder in a local variable so that the compiler doesn't reload
// it at 'return'. Android's compiler thinks the methods called between assignment & return
// might reassign this.builder so the compiler can't make this optimisation without our help.
BType builder = this.builder;

if (builder == null) {
// builder.mergeFrom() on a fresh builder
// does not create any sub-objects with independent clean/dirty states,
// therefore setting the builder itself to clean without actually calling
// build() cannot break any invariants.
builder = (BType) message.newBuilderForType(this);
this.builder = builder = (BType) message.newBuilderForType(this);
builder.mergeFrom(message); // no-op if message is the default message
builder.markClean();
}
Expand Down

0 comments on commit 4f00042

Please sign in to comment.