File protobuf-4f02f056b5cea99052bfdfb6698afe47a3cf2964.patch of Package protobuf.26315
From 4f02f056b5cea99052bfdfb6698afe47a3cf2964 Mon Sep 17 00:00:00 2001
From: Rafi Kamal <rafikamal@google.com>
Date: Thu, 22 Aug 2019 16:14:22 -0700
Subject: [PATCH] Down integrate to GitHub
---
java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java | 9
java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java | 10
java/core/src/main/java/com/google/protobuf/UnsafeUtil.java | 318 ++++++++++
java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java | 4
java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java | 12
src/google/protobuf/compiler/java/java_file.cc | 3
src/google/protobuf/compiler/java/java_helpers.cc | 3
src/google/protobuf/compiler/java/java_helpers.h | 2
src/google/protobuf/compiler/java/java_message.cc | 10
src/google/protobuf/compiler/java/java_message_lite.cc | 7
src/google/protobuf/compiler/java/java_string_field.cc | 3
11 files changed, 366 insertions(+), 15 deletions(-)
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -146,6 +146,15 @@ public abstract class AbstractMessageLit
Builder.addAll(values, list);
}
+ /** Interface for an enum which signifies which field in a {@code oneof} was specified. */
+ protected interface InternalOneOfEnum {
+ /**
+ * Retrieves the field number of the field which was set in this {@code oneof}, or {@code 0} if
+ * none were.
+ */
+ int getNumber();
+ }
+
/**
* A partial implementation of the {@link Message.Builder} interface which implements as many
* methods of that interface as possible in terms of other methods.
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -2365,6 +2365,11 @@ public abstract class GeneratedMessageV3
}
try {
return new MethodHandleInvoker(accessor);
+ } catch (NoClassDefFoundError e) {
+ // Fall back to reflection if MethodHandleInvoker isn't available,
+ // allowing clients that don't want to use method handles to opt out
+ // by deleting the class.
+ return accessor;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
@@ -2703,6 +2708,11 @@ public abstract class GeneratedMessageV3
}
try {
return new MethodHandleInvoker(accessor);
+ } catch (NoClassDefFoundError e) {
+ // Fall back to reflection if MethodHandleInvoker isn't available,
+ // allowing clients that don't want to use method handles to opt out
+ // by deleting the class.
+ return accessor;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
--- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -43,6 +43,9 @@ import java.util.logging.Logger;
final class UnsafeUtil {
private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+ private static final Class<?> MEMORY_CLASS = Android.getMemoryClass();
+ private static final boolean IS_ANDROID_64 = determineAndroidSupportByAddressSize(long.class);
+ private static final boolean IS_ANDROID_32 = determineAndroidSupportByAddressSize(int.class);
private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
supportsUnsafeByteBufferOperations();
@@ -89,6 +92,9 @@ final class UnsafeUtil {
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
}
+ static boolean isAndroid64() {
+ return IS_ANDROID_64;
+ }
@SuppressWarnings("unchecked") // safe by method contract
static <T> T allocateInstance(Class<T> clazz) {
@@ -314,6 +320,16 @@ final class UnsafeUtil {
if (UNSAFE == null) {
return null;
}
+ if (Android.isOnAndroidDevice()) {
+ if (IS_ANDROID_64) {
+ return new Android64MemoryAccessor(UNSAFE);
+ } else if (IS_ANDROID_32) {
+ return new Android32MemoryAccessor(UNSAFE);
+ } else {
+ return null;
+ }
+ }
+
return new JvmMemoryAccessor(UNSAFE);
}
@@ -333,6 +349,9 @@ final class UnsafeUtil {
clazz.getMethod("putLong", Object.class, long.class, long.class);
clazz.getMethod("getObject", Object.class, long.class);
clazz.getMethod("putObject", Object.class, long.class, Object.class);
+ if (Android.isOnAndroidDevice()) {
+ return true;
+ }
clazz.getMethod("getByte", Object.class, long.class);
clazz.getMethod("putByte", Object.class, long.class, byte.class);
clazz.getMethod("getBoolean", Object.class, long.class);
@@ -365,6 +384,9 @@ final class UnsafeUtil {
return false;
}
+ if (Android.isOnAndroidDevice()) {
+ return true;
+ }
clazz.getMethod("getByte", long.class);
clazz.getMethod("putByte", long.class, byte.class);
clazz.getMethod("getInt", long.class);
@@ -382,9 +404,36 @@ final class UnsafeUtil {
return false;
}
+ private static boolean determineAndroidSupportByAddressSize(Class<?> addressClass) {
+ if (!Android.isOnAndroidDevice()) {
+ return false;
+ }
+ try {
+ Class<?> clazz = MEMORY_CLASS;
+ clazz.getMethod("peekLong", addressClass, boolean.class);
+ clazz.getMethod("pokeLong", addressClass, long.class, boolean.class);
+ clazz.getMethod("pokeInt", addressClass, int.class, boolean.class);
+ clazz.getMethod("peekInt", addressClass, boolean.class);
+ clazz.getMethod("pokeByte", addressClass, byte.class);
+ clazz.getMethod("peekByte", addressClass);
+ clazz.getMethod("pokeByteArray", addressClass, byte[].class, int.class, int.class);
+ clazz.getMethod("peekByteArray", addressClass, byte[].class, int.class, int.class);
+ return true;
+ } catch (Throwable t) {
+ return false;
+ }
+ }
/** Finds the address field within a direct {@link Buffer}. */
private static Field bufferAddressField() {
+ if (Android.isOnAndroidDevice()) {
+ // Old versions of Android had renamed the address field to 'effectiveDirectAddress', but
+ // recent versions of Android (>M?) use the OpenJDK implementation. Fall through in that case.
+ Field field = field(Buffer.class, "effectiveDirectAddress");
+ if (field != null) {
+ return field;
+ }
+ }
Field field = field(Buffer.class, "address");
return field != null && field.getType() == long.class ? field : null;
}
@@ -656,4 +705,273 @@ final class UnsafeUtil {
}
}
+ private static final class Android64MemoryAccessor extends MemoryAccessor {
+
+ Android64MemoryAccessor(sun.misc.Unsafe unsafe) {
+ super(unsafe);
+ }
+
+ @Override
+ public byte getByte(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putByte(long address, byte value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getInt(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putInt(long address, int value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLong(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putLong(long address, long value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte getByte(Object target, long offset) {
+ if (IS_BIG_ENDIAN) {
+ return getByteBigEndian(target, offset);
+ } else {
+ return getByteLittleEndian(target, offset);
+ }
+ }
+
+ @Override
+ public void putByte(Object target, long offset, byte value) {
+ if (IS_BIG_ENDIAN) {
+ putByteBigEndian(target, offset, value);
+ } else {
+ putByteLittleEndian(target, offset, value);
+ }
+ }
+
+ @Override
+ public boolean getBoolean(Object target, long offset) {
+ if (IS_BIG_ENDIAN) {
+ return getBooleanBigEndian(target, offset);
+ } else {
+ return getBooleanLittleEndian(target, offset);
+ }
+ }
+
+ @Override
+ public void putBoolean(Object target, long offset, boolean value) {
+ if (IS_BIG_ENDIAN) {
+ putBooleanBigEndian(target, offset, value);
+ } else {
+ putBooleanLittleEndian(target, offset, value);
+ }
+ }
+
+ @Override
+ public float getFloat(Object target, long offset) {
+ return Float.intBitsToFloat(getInt(target, offset));
+ }
+
+ @Override
+ public void putFloat(Object target, long offset, float value) {
+ putInt(target, offset, Float.floatToIntBits(value));
+ }
+
+ @Override
+ public double getDouble(Object target, long offset) {
+ return Double.longBitsToDouble(getLong(target, offset));
+ }
+
+ @Override
+ public void putDouble(Object target, long offset, double value) {
+ putLong(target, offset, Double.doubleToLongBits(value));
+ }
+
+ @Override
+ public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getStaticObject(Field field) {
+ try {
+ return field.get(null);
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ }
+ }
+
+ private static final class Android32MemoryAccessor extends MemoryAccessor {
+
+ /** Mask used to convert a 64 bit memory address to a 32 bit address. */
+ private static final long SMALL_ADDRESS_MASK = 0x00000000FFFFFFFF;
+
+ /** Truncate a {@code long} address into a short {@code int} address. */
+ private static int smallAddress(long address) {
+ return (int) (SMALL_ADDRESS_MASK & address);
+ }
+
+ Android32MemoryAccessor(sun.misc.Unsafe unsafe) {
+ super(unsafe);
+ }
+
+ @Override
+ public byte getByte(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putByte(long address, byte value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getInt(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putInt(long address, int value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLong(long address) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putLong(long address, long value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte getByte(Object target, long offset) {
+ if (IS_BIG_ENDIAN) {
+ return getByteBigEndian(target, offset);
+ } else {
+ return getByteLittleEndian(target, offset);
+ }
+ }
+
+ @Override
+ public void putByte(Object target, long offset, byte value) {
+ if (IS_BIG_ENDIAN) {
+ putByteBigEndian(target, offset, value);
+ } else {
+ putByteLittleEndian(target, offset, value);
+ }
+ }
+
+ @Override
+ public boolean getBoolean(Object target, long offset) {
+ if (IS_BIG_ENDIAN) {
+ return getBooleanBigEndian(target, offset);
+ } else {
+ return getBooleanLittleEndian(target, offset);
+ }
+ }
+
+ @Override
+ public void putBoolean(Object target, long offset, boolean value) {
+ if (IS_BIG_ENDIAN) {
+ putBooleanBigEndian(target, offset, value);
+ } else {
+ putBooleanLittleEndian(target, offset, value);
+ }
+ }
+
+ @Override
+ public float getFloat(Object target, long offset) {
+ return Float.intBitsToFloat(getInt(target, offset));
+ }
+
+ @Override
+ public void putFloat(Object target, long offset, float value) {
+ putInt(target, offset, Float.floatToIntBits(value));
+ }
+
+ @Override
+ public double getDouble(Object target, long offset) {
+ return Double.longBitsToDouble(getLong(target, offset));
+ }
+
+ @Override
+ public void putDouble(Object target, long offset, double value) {
+ putLong(target, offset, Double.doubleToLongBits(value));
+ }
+
+ @Override
+ public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getStaticObject(Field field) {
+ try {
+ return field.get(null);
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ }
+ }
+
+ private static byte getByteBigEndian(Object target, long offset) {
+ return (byte) ((getInt(target, offset & ~3) >>> ((~offset & 3) << 3)) & 0xFF);
+ }
+
+ private static byte getByteLittleEndian(Object target, long offset) {
+ return (byte) ((getInt(target, offset & ~3) >>> ((offset & 3) << 3)) & 0xFF);
+ }
+
+ private static void putByteBigEndian(Object target, long offset, byte value) {
+ int intValue = getInt(target, offset & ~3);
+ int shift = ((~(int) offset) & 3) << 3;
+ int output = (intValue & ~(0xFF << shift)) | ((0xFF & value) << shift);
+ putInt(target, offset & ~3, output);
+ }
+
+ private static void putByteLittleEndian(Object target, long offset, byte value) {
+ int intValue = getInt(target, offset & ~3);
+ int shift = (((int) offset) & 3) << 3;
+ int output = (intValue & ~(0xFF << shift)) | ((0xFF & value) << shift);
+ putInt(target, offset & ~3, output);
+ }
+
+ private static boolean getBooleanBigEndian(Object target, long offset) {
+ return getByteBigEndian(target, offset) != 0;
+ }
+
+ private static boolean getBooleanLittleEndian(Object target, long offset) {
+ return getByteLittleEndian(target, offset) != 0;
+ }
+
+ private static void putBooleanBigEndian(Object target, long offset, boolean value) {
+ putByteBigEndian(target, offset, (byte) (value ? 1 : 0));
+ }
+
+ private static void putBooleanLittleEndian(Object target, long offset, boolean value) {
+ putByteLittleEndian(target, offset, (byte) (value ? 1 : 0));
+ }
}
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -345,8 +345,8 @@ public class FieldMaskUtil {
}
/**
- * Merges fields specified by a FieldMask from one message to another with the
- * specified merge options.
+ * Merges fields specified by a FieldMask from one message to another with the specified merge
+ * options. The destination will remain unchanged if an empty FieldMask is provided.
*/
public static void merge(
FieldMask mask, Message source, Message.Builder destination, MergeOptions options) {
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java
@@ -182,11 +182,19 @@ public class FieldMaskTreeTest extends T
FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions();
- // Test merging each individual field.
+ // Test merging with an empty FieldMask.
NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
+ builder.getPayloadBuilder().addRepeatedInt32(1000);
+ merge(new FieldMaskTree(), source, builder, options, useDynamicMessage);
+ NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
+ expected.getPayloadBuilder().addRepeatedInt32(1000);
+ assertEquals(expected.build(), builder.build());
+
+ // Test merging each individual field.
+ builder = NestedTestAllTypes.newBuilder();
merge(new FieldMaskTree().addFieldPath("payload.optional_int32"),
source, builder, options, useDynamicMessage);
- NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder();
+ expected = NestedTestAllTypes.newBuilder();
expected.getPayloadBuilder().setOptionalInt32(1234);
assertEquals(expected.build(), builder.build());
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -238,7 +238,8 @@ bool FileGenerator::Validate(std::string
}
// Print a warning if optimize_for = LITE_RUNTIME is used.
- if (file_->options().optimize_for() == FileOptions::LITE_RUNTIME) {
+ if (file_->options().optimize_for() == FileOptions::LITE_RUNTIME &&
+ !options_.enforce_lite) {
GOOGLE_LOG(WARNING)
<< "The optimize_for = LITE_RUNTIME option is no longer supported by "
<< "protobuf Java code generator and is ignored--protoc will always "
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -32,13 +32,14 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <google/protobuf/compiler/java/java_helpers.h>
+
#include <algorithm>
#include <limits>
#include <unordered_set>
#include <vector>
#include <google/protobuf/stubs/stringprintf.h>
-#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/compiler/java/java_name_resolver.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/wire_format.h>
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -369,7 +369,7 @@ inline bool SupportUnknownEnumValue(cons
return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
-// Check whether a mesasge has repeated fields.
+// Check whether a message has repeated fields.
bool HasRepeatedFields(const Descriptor* descriptor);
inline bool IsMapEntry(const Descriptor* descriptor) {
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -417,9 +417,13 @@ void ImmutableMessageGenerator::Generate
"private int $oneof_name$Case_ = 0;\n"
"private java.lang.Object $oneof_name$_;\n");
// OneofCase enum
- printer->Print(vars,
- "public enum $oneof_capitalized_name$Case\n"
- " implements com.google.protobuf.Internal.EnumLite {\n");
+ printer->Print(
+ vars,
+ "public enum $oneof_capitalized_name$Case\n"
+ // TODO(dweis): Remove EnumLite when we want to break compatibility with
+ // 3.x users
+ " implements com.google.protobuf.Internal.EnumLite,\n"
+ " com.google.protobuf.AbstractMessage.InternalOneOfEnum {\n");
printer->Indent();
for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -237,9 +237,7 @@ void ImmutableMessageLiteGenerator::Gene
"private int $oneof_name$Case_ = 0;\n"
"private java.lang.Object $oneof_name$_;\n");
// OneofCase enum
- printer->Print(vars,
- "public enum $oneof_capitalized_name$Case\n"
- " implements com.google.protobuf.Internal.EnumLite {\n");
+ printer->Print(vars, "public enum $oneof_capitalized_name$Case {\n");
printer->Indent();
for (int j = 0; j < oneof->field_count(); j++) {
const FieldDescriptor* field = oneof->field(j);
@@ -277,7 +275,8 @@ void ImmutableMessageLiteGenerator::Gene
" default: return null;\n"
" }\n"
"}\n"
- "@java.lang.Override\n"
+ // TODO(b/135620659): Rename this to "getFieldNumber" or something to
+ // disambiguate it from actual proto enums.
"public int getNumber() {\n"
" return this.value;\n"
"}\n",
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -833,7 +833,8 @@ void RepeatedImmutableStringFieldGenerat
" return $name$_.get(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- WriteFieldStringBytesAccessorDocComment(printer, descriptor_, LIST_ADDER);
+ WriteFieldStringBytesAccessorDocComment(printer, descriptor_,
+ LIST_INDEXED_GETTER);
printer->Print(variables_,
"$deprecation$public com.google.protobuf.ByteString\n"
" ${$get$capitalized_name$Bytes$}$(int index) {\n"