Skip to content

Commit

Permalink
Avoid allocating new ExtensionWriters when serializing messages with …
Browse files Browse the repository at this point in the history
…no extensions

This should speed up serializing Extendable Messages (messages with extension ranges declared in their schema) if those message instances have no extensions set inside them at runtime.

PiperOrigin-RevId: 638087120
  • Loading branch information
mhansen authored and copybara-github committed May 29, 2024
1 parent 81041ed commit 05e5107
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
33 changes: 29 additions & 4 deletions java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -1028,21 +1028,38 @@ public boolean isInitialized() {
* numbers, but we must write them in canonical (sorted by field number) order. ExtensionWriter
* helps us write individual ranges of extensions at once.
*/
protected class ExtensionWriter {
protected interface ExtensionWriter {
public void writeUntil(final int end, final CodedOutputStream output) throws IOException;
}

// Singleton instance so we can avoid allocating a new one for each message serialization.
private static final NoOpExtensionWriter NO_OP_EXTENSION_WRITER = new NoOpExtensionWriter();

/** No-op implementation that writes nothing, for messages with no extensions. */
private static final class NoOpExtensionWriter implements ExtensionWriter {
@Override
public void writeUntil(final int end, final CodedOutputStream output) {
// no-op
}
}

/** Implementation that writes extensions from the FieldSet, for messages with extensions. */
private final class FieldSetExtensionWriter implements ExtensionWriter {
// Imagine how much simpler this code would be if Java iterators had
// a way to get the next element without advancing the iterator.

private final Iterator<Map.Entry<FieldDescriptor, Object>> iter = extensions.iterator();
private Map.Entry<FieldDescriptor, Object> next;
private final boolean messageSetWireFormat;

private ExtensionWriter(final boolean messageSetWireFormat) {
private FieldSetExtensionWriter(final boolean messageSetWireFormat) {
if (iter.hasNext()) {
next = iter.next();
}
this.messageSetWireFormat = messageSetWireFormat;
}

@Override
public void writeUntil(final int end, final CodedOutputStream output) throws IOException {
while (next != null && next.getKey().getNumber() < end) {
FieldDescriptor descriptor = next.getKey();
Expand Down Expand Up @@ -1076,11 +1093,19 @@ public void writeUntil(final int end, final CodedOutputStream output) throws IOE
}

protected ExtensionWriter newExtensionWriter() {
return new ExtensionWriter(false);
// Avoid allocation in the common case of no extensions.
if (extensions.isEmpty()) {
return NO_OP_EXTENSION_WRITER;
}
return new FieldSetExtensionWriter(false);
}

protected ExtensionWriter newMessageSetExtensionWriter() {
return new ExtensionWriter(true);
// Avoid allocation in the common case of no extensions.
if (extensions.isEmpty()) {
return NO_OP_EXTENSION_WRITER;
}
return new FieldSetExtensionWriter(true);
}

/** Called by subclasses to compute the size of extensions. */
Expand Down
10 changes: 4 additions & 6 deletions src/google/protobuf/compiler/java/full/message.cc
Original file line number Diff line number Diff line change
Expand Up @@ -587,15 +587,13 @@ void ImmutableMessageGenerator::GenerateMessageSerializationMethods(
if (descriptor_->options().message_set_wire_format()) {
printer->Print(
"com.google.protobuf.GeneratedMessage\n"
" .ExtendableMessage<$classname$>.ExtensionWriter\n"
" extensionWriter = newMessageSetExtensionWriter();\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
" .ExtendableMessage.ExtensionWriter\n"
" extensionWriter = newMessageSetExtensionWriter();\n");
} else {
printer->Print(
"com.google.protobuf.GeneratedMessage\n"
" .ExtendableMessage<$classname$>.ExtensionWriter\n"
" extensionWriter = newExtensionWriter();\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
" .ExtendableMessage.ExtensionWriter\n"
" extensionWriter = newExtensionWriter();\n");
}
}

Expand Down

0 comments on commit 05e5107

Please sign in to comment.