Speed up SingleFieldBuilder.getBuilder() by avoiding reloading this.builder 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: 683619150
pull/18668/head
Mark Hansen 2 months ago committed by Copybara-Service
parent 9bce530117
commit f7b0faf558
  1. 8
      java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java

@ -100,12 +100,18 @@ public class SingleFieldBuilder<
*/
@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();
}

Loading…
Cancel
Save