From 229c958a5c9417129942959c9819f7f4ffa4c8a3 Mon Sep 17 00:00:00 2001 From: Mark Hansen Date: Sun, 7 Jul 2024 18:29:02 -0700 Subject: [PATCH] Hoist SmallSortedMap.getNumArrayEntries() outside loops over array entries This should slightly speed things up. Should be safe: these operations don't change the number of entries inside the loop. PiperOrigin-RevId: 650087172 --- .../java/com/google/protobuf/FieldSet.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java index 85b1ad0c64fa..ea67b5b3d573 100644 --- a/java/core/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java @@ -99,7 +99,8 @@ public void makeImmutable() { if (isImmutable) { return; } - for (int i = 0; i < fields.getNumArrayEntries(); ++i) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; ++i) { Entry entry = fields.getArrayEntryAt(i); if (entry.getValue() instanceof GeneratedMessageLite) { ((GeneratedMessageLite) entry.getValue()).makeImmutable(); @@ -149,7 +150,8 @@ public FieldSet clone() { // We can't just call fields.clone because List objects in the map // should not be shared. FieldSet clone = FieldSet.newFieldSet(); - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { Map.Entry entry = fields.getArrayEntryAt(i); clone.setField(entry.getKey(), entry.getValue()); } @@ -184,7 +186,8 @@ public Map getAllFields() { private static > SmallSortedMap cloneAllFieldsMap( SmallSortedMap fields, boolean copyList, boolean resolveLazyFields) { SmallSortedMap result = SmallSortedMap.newFieldMap(); - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { cloneFieldEntry(result, fields.getArrayEntryAt(i), copyList, resolveLazyFields); } for (Map.Entry entry : fields.getOverflowEntries()) { @@ -426,7 +429,8 @@ private static boolean isValidType(final WireFormat.FieldType type, final Object * caller to check that all required fields are present. */ public boolean isInitialized() { - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { if (!isInitialized(fields.getArrayEntryAt(i))) { return false; } @@ -484,7 +488,8 @@ static int getWireFormatForFieldType(final WireFormat.FieldType type, boolean is /** Like {@link Message.Builder#mergeFrom(Message)}, but merges from another {@link FieldSet}. */ public void mergeFrom(final FieldSet other) { - for (int i = 0; i < other.fields.getNumArrayEntries(); i++) { + int n = other.fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { mergeFromField(other.fields.getArrayEntryAt(i)); } for (final Map.Entry entry : other.fields.getOverflowEntries()) { @@ -571,7 +576,8 @@ public static Object readPrimitiveField( /** See {@link Message#writeTo(CodedOutputStream)}. */ public void writeTo(final CodedOutputStream output) throws IOException { - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { final Map.Entry entry = fields.getArrayEntryAt(i); writeField(entry.getKey(), entry.getValue(), output); } @@ -582,7 +588,8 @@ public void writeTo(final CodedOutputStream output) throws IOException { /** Like {@link #writeTo} but uses MessageSet wire format. */ public void writeMessageSetTo(final CodedOutputStream output) throws IOException { - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { writeMessageSetTo(fields.getArrayEntryAt(i), output); } for (final Map.Entry entry : fields.getOverflowEntries()) { @@ -759,7 +766,8 @@ public static void writeField( */ public int getSerializedSize() { int size = 0; - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { final Map.Entry entry = fields.getArrayEntryAt(i); size += computeFieldSize(entry.getKey(), entry.getValue()); } @@ -772,7 +780,8 @@ public int getSerializedSize() { /** Like {@link #getSerializedSize} but uses MessageSet wire format. */ public int getMessageSetSerializedSize() { int size = 0; - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { size += getMessageSetSerializedSize(fields.getArrayEntryAt(i)); } for (final Map.Entry entry : fields.getOverflowEntries()) { @@ -976,7 +985,8 @@ private FieldSet buildImpl(boolean partial) { private static > void replaceBuilders( SmallSortedMap fieldMap, boolean partial) { - for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) { + int n = fieldMap.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { replaceBuilders(fieldMap.getArrayEntryAt(i), partial); } for (Map.Entry entry : fieldMap.getOverflowEntries()) { @@ -1268,7 +1278,8 @@ private void verifyType(final T descriptor, final Object value) { * caller to check that all required fields are present. */ public boolean isInitialized() { - for (int i = 0; i < fields.getNumArrayEntries(); i++) { + int n = fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { if (!FieldSet.isInitialized(fields.getArrayEntryAt(i))) { return false; } @@ -1286,7 +1297,8 @@ public boolean isInitialized() { */ public void mergeFrom(final FieldSet other) { ensureIsMutable(); - for (int i = 0; i < other.fields.getNumArrayEntries(); i++) { + int n = other.fields.getNumArrayEntries(); // Optimisation: hoist out of hot loop. + for (int i = 0; i < n; i++) { mergeFromField(other.fields.getArrayEntryAt(i)); } for (final Map.Entry entry : other.fields.getOverflowEntries()) {