aboutsummaryrefslogtreecommitdiffhomepage
path: root/java/core/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'java/core/src/main/java')
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractMessage.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java21
-rw-r--r--java/core/src/main/java/com/google/protobuf/AbstractParser.java26
-rw-r--r--java/core/src/main/java/com/google/protobuf/BooleanArrayList.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedInputStream.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedOutputStream.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/Descriptors.java7
-rw-r--r--java/core/src/main/java/com/google/protobuf/DoubleArrayList.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/DynamicMessage.java7
-rw-r--r--java/core/src/main/java/com/google/protobuf/FieldSet.java7
-rw-r--r--java/core/src/main/java/com/google/protobuf/FloatArrayList.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java22
-rw-r--r--java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java2
-rw-r--r--java/core/src/main/java/com/google/protobuf/IntArrayList.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/Internal.java15
-rw-r--r--java/core/src/main/java/com/google/protobuf/LazyFieldLite.java1
-rw-r--r--java/core/src/main/java/com/google/protobuf/LongArrayList.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntry.java24
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapEntryLite.java5
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapField.java8
-rw-r--r--java/core/src/main/java/com/google/protobuf/MapFieldLite.java14
-rw-r--r--java/core/src/main/java/com/google/protobuf/Parser.java13
-rw-r--r--java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java34
-rw-r--r--java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java18
-rw-r--r--java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java12
-rw-r--r--java/core/src/main/java/com/google/protobuf/TextFormat.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java4
-rw-r--r--java/core/src/main/java/com/google/protobuf/UnsafeUtil.java401
-rw-r--r--java/core/src/main/java/com/google/protobuf/Utf8.java2
29 files changed, 528 insertions, 191 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 37180da8..b5043eb5 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -34,7 +34,6 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Internal.EnumLite;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@@ -328,7 +327,8 @@ public abstract class AbstractMessage
extends AbstractMessageLite.Builder
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
- // Method isn't abstract to bypass Java 1.6 compiler issue http://bugs.java.com/view_bug.do?bug_id=6908259
+ // Method isn't abstract to bypass Java 1.6 compiler issue:
+ // http://bugs.java.com/view_bug.do?bug_id=6908259
@Override
public BuilderType clone() {
throw new UnsupportedOperationException("clone() should be implemented in subclasses.");
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
index 4f691dfd..99787fcc 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -351,22 +353,23 @@ public abstract class AbstractMessageLite<
*/
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
- if (values == null) {
- throw new NullPointerException();
- }
+ checkNotNull(values);
if (values instanceof LazyStringList) {
// For StringOrByteStringLists, check the underlying elements to avoid
// forcing conversions of ByteStrings to Strings.
+ // TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
+ // if even possible to hit this condition as all protobuf methods check for null first,
+ // right?
checkForNullValues(((LazyStringList) values).getUnderlyingElements());
list.addAll((Collection<T>) values);
} else if (values instanceof Collection) {
- checkForNullValues(values);
+ if (!(values instanceof PrimitiveNonBoxingCollection)) {
+ checkForNullValues(values);
+ }
list.addAll((Collection<T>) values);
} else {
for (final T value : values) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
list.add(value);
}
}
@@ -374,9 +377,7 @@ public abstract class AbstractMessageLite<
private static void checkForNullValues(final Iterable<?> values) {
for (final Object value : values) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
}
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
index 7ff73ba4..ba570e3d 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractParser.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractParser.java
@@ -31,9 +31,9 @@
package com.google.protobuf;
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
-
import java.io.IOException;
import java.io.InputStream;
+import java.nio.ByteBuffer;
/**
* A partial implementation of the {@link Parser} interface which implements
@@ -131,6 +131,30 @@ public abstract class AbstractParser<MessageType extends MessageLite>
}
@Override
+ public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ MessageType message;
+ try {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ message = parsePartialFrom(input, extensionRegistry);
+ try {
+ input.checkLastTagWas(0);
+ } catch (InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(message);
+ }
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ }
+
+ return checkMessageInitialized(message);
+ }
+
+ @Override
+ public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException {
+ return parseFrom(data, EMPTY_REGISTRY);
+ }
+
+ @Override
public MessageType parsePartialFrom(
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 0d9f87ba..fd4c142b 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.BooleanList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.BooleanList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class BooleanArrayList
- extends AbstractProtobufList<Boolean>
- implements BooleanList, RandomAccess {
+final class BooleanArrayList extends AbstractProtobufList<Boolean>
+ implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
static {
@@ -198,9 +198,7 @@ final class BooleanArrayList
public boolean addAll(Collection<? extends Boolean> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another BooleanArrayList to avoid boxing elements.
if (!(collection instanceof BooleanArrayList)) {
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index 239798e4..3dfbcb0a 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -355,8 +355,8 @@ public abstract class CodedInputStream {
* <p>Set the maximum message size. In order to prevent malicious messages from exhausting memory
* or causing integer overflows, {@code CodedInputStream} limits how large a message may be. The
* default limit is {@code Integer.MAX_INT}. You should set this limit as small as you can without
- * harming your app's functionality. Note that size limits only apply when reading from an
- * {@code InputStream}, not when constructed around a raw byte array.
+ * harming your app's functionality. Note that size limits only apply when reading from an {@code
+ * InputStream}, not when constructed around a raw byte array.
*
* <p>If you want to read several messages from a single CodedInputStream, you could call {@link
* #resetSizeCounter()} after each one to avoid hitting the size limit.
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index 3e32c2c5..da0e9b12 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -184,7 +184,7 @@ public abstract class CodedOutputStream extends ByteOutput {
* maps are sorted on the lexicographical order of the UTF8 encoded keys.
* </ul>
*/
- void useDeterministicSerialization() {
+ public void useDeterministicSerialization() {
serializationDeterministic = true;
}
@@ -1854,7 +1854,7 @@ public abstract class CodedOutputStream extends ByteOutput {
}
static boolean isSupported() {
- return UnsafeUtil.hasUnsafeByteBufferOperations();
+ return UnsafeUtil.hasUnsafeByteBufferOperations() && UnsafeUtil.hasUnsafeCopyMemory();
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index 38346f15..75b16fe3 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -30,9 +30,10 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import com.google.protobuf.DescriptorProtos.*;
import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
-
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -682,9 +683,7 @@ public final class Descriptors {
/** Determines if the given field name is reserved. */
public boolean isReservedName(final String name) {
- if (name == null) {
- throw new NullPointerException();
- }
+ checkNotNull(name);
for (final String reservedName : proto.getReservedNameList()) {
if (reservedName.equals(name)) {
return true;
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index 6177f3ca..867b85ce 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.DoubleList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.DoubleList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class DoubleArrayList
- extends AbstractProtobufList<Double>
- implements DoubleList, RandomAccess {
+final class DoubleArrayList extends AbstractProtobufList<Double>
+ implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
static {
@@ -199,9 +199,7 @@ final class DoubleArrayList
public boolean addAll(Collection<? extends Double> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another DoubleArrayList to avoid boxing elements.
if (!(collection instanceof DoubleArrayList)) {
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
index e6358c3b..2631db74 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -30,11 +30,12 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.OneofDescriptor;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
@@ -631,9 +632,7 @@ public final class DynamicMessage extends AbstractMessage {
/** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
private void ensureSingularEnumValueDescriptor(
FieldDescriptor field, Object value) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
if (!(value instanceof EnumValueDescriptor)) {
throw new IllegalArgumentException(
"DynamicMessage should use EnumValueDescriptor to set Enum Value.");
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 a828f30e..8a9239ed 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.LazyField.LazyIterator;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.LazyField.LazyIterator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -385,9 +386,7 @@ final class FieldSet<FieldDescriptorType extends
*/
private static void verifyType(final WireFormat.FieldType type,
final Object value) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
boolean isValid = false;
switch (type.getJavaType()) {
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 90d6154b..76645583 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.FloatList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.FloatList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class FloatArrayList
- extends AbstractProtobufList<Float>
- implements FloatList, RandomAccess {
+final class FloatArrayList extends AbstractProtobufList<Float>
+ implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
static {
@@ -198,9 +198,7 @@ final class FloatArrayList
public boolean addAll(Collection<? extends Float> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another FloatArrayList to avoid boxing elements.
if (!(collection instanceof FloatArrayList)) {
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 2d7fd334..cf3486e1 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -34,6 +34,7 @@ import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
import com.google.protobuf.GeneratedMessageLite.EqualsVisitor.NotEqualsException;
import com.google.protobuf.Internal.BooleanList;
import com.google.protobuf.Internal.DoubleList;
+import com.google.protobuf.Internal.EnumLiteMap;
import com.google.protobuf.Internal.FloatList;
import com.google.protobuf.Internal.IntList;
import com.google.protobuf.Internal.LongList;
@@ -45,6 +46,7 @@ import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -136,6 +138,7 @@ public abstract class GeneratedMessageLite<
return false;
}
+
try {
visit(EqualsVisitor.INSTANCE, (MessageType) other);
} catch (NotEqualsException e) {
@@ -1154,6 +1157,7 @@ public abstract class GeneratedMessageLite<
}
}
+
/**
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
*
@@ -1529,6 +1533,20 @@ public abstract class GeneratedMessageLite<
// Validates last tag.
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return checkMessageInitialized(
+ parseFrom(defaultInstance, CodedInputStream.newInstance(data), extensionRegistry));
+ }
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
+ T defaultInstance, ByteBuffer data) throws InvalidProtocolBufferException {
+ return parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry());
+ }
+
+ // Validates last tag.
+ protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
T defaultInstance, ByteString data)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
@@ -1979,13 +1997,13 @@ public abstract class GeneratedMessageLite<
/**
* Implements hashCode by accumulating state.
*/
- private static class HashCodeVisitor implements Visitor {
+ static class HashCodeVisitor implements Visitor {
// The caller must ensure that the visitor is invoked parameterized with this and this such that
// other is this. This is required due to how oneof cases are handled. See the class comment
// on Visitor for more information.
- private int hashCode = 0;
+ int hashCode = 0;
@Override
public boolean visitBoolean(
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index fd051e75..b949cd17 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -41,7 +41,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
// class without breaking binary compatibility with old generated code that still subclasses
// the old GeneratedMessageV3 class. To allow these different GeneratedMessageV3V? classes to
// interoperate (e.g., a GeneratedMessageV3V3 object has a message extension field whose class
-// type is GeneratedMessageV3V4), these classes still share a common parent class AbstarctMessage
+// type is GeneratedMessageV3V4), these classes still share a common parent class AbstractMessage
// and are using the same GeneratedMessage.GeneratedExtension class for extension definitions.
// Since this class becomes GeneratedMessageV3V? in opensource, we have to add an import here
// to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index 2f526e3f..aff5c21b 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.IntList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.IntList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class IntArrayList
- extends AbstractProtobufList<Integer>
- implements IntList, RandomAccess {
+final class IntArrayList extends AbstractProtobufList<Integer>
+ implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
private static final IntArrayList EMPTY_LIST = new IntArrayList();
static {
@@ -198,9 +198,7 @@ final class IntArrayList
public boolean addAll(Collection<? extends Integer> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another IntArrayList to avoid boxing elements.
if (!(collection instanceof IntArrayList)) {
diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java
index c234559c..36bdece3 100644
--- a/java/core/src/main/java/com/google/protobuf/Internal.java
+++ b/java/core/src/main/java/com/google/protobuf/Internal.java
@@ -62,6 +62,16 @@ public final class Internal {
/**
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
*/
+ static <T> T checkNotNull(T obj) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ return obj;
+ }
+
+ /**
+ * Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
+ */
static <T> T checkNotNull(T obj, String message) {
if (obj == null) {
throw new NullPointerException(message);
@@ -420,6 +430,11 @@ public final class Internal {
CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
+ /** Helper method to merge two MessageLite instances. */
+ static Object mergeMessage(Object destination, Object source) {
+ return ((MessageLite) destination).toBuilder().mergeFrom((MessageLite) source).buildPartial();
+ }
+
/**
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
*
diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
index 4b0ba0fd..49ecfc0b 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java
@@ -394,6 +394,7 @@ public class LazyFieldLite {
}
}
+
/**
* Might lazily parse the bytes that were previously passed in. Is thread-safe.
*/
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index 5a772e3a..fc146e23 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.LongList;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.LongList;
import java.util.Arrays;
import java.util.Collection;
import java.util.RandomAccess;
@@ -41,9 +42,8 @@ import java.util.RandomAccess;
*
* @author dweis@google.com (Daniel Weis)
*/
-final class LongArrayList
- extends AbstractProtobufList<Long>
- implements LongList, RandomAccess {
+final class LongArrayList extends AbstractProtobufList<Long>
+ implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
private static final LongArrayList EMPTY_LIST = new LongArrayList();
static {
@@ -198,9 +198,7 @@ final class LongArrayList
public boolean addAll(Collection<? extends Long> collection) {
ensureIsMutable();
- if (collection == null) {
- throw new NullPointerException();
- }
+ checkNotNull(collection);
// We specialize when adding another LongArrayList to avoid boxing elements.
if (!(collection instanceof LongArrayList)) {
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
index 7e8e9aad..0849b821 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntry.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -33,7 +33,6 @@ package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
-
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
@@ -171,7 +170,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
@Override
public Builder<K, V> toBuilder() {
- return new Builder<K, V>(metadata, key, value);
+ return new Builder<K, V>(metadata, key, value, true, true);
}
@Override
@@ -247,15 +246,19 @@ public final class MapEntry<K, V> extends AbstractMessage {
private final Metadata<K, V> metadata;
private K key;
private V value;
+ private boolean hasKey;
+ private boolean hasValue;
private Builder(Metadata<K, V> metadata) {
- this(metadata, metadata.defaultKey, metadata.defaultValue);
+ this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
}
- private Builder(Metadata<K, V> metadata, K key, V value) {
+ private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
this.metadata = metadata;
this.key = key;
this.value = value;
+ this.hasKey = hasKey;
+ this.hasValue = hasValue;
}
public K getKey() {
@@ -268,21 +271,25 @@ public final class MapEntry<K, V> extends AbstractMessage {
public Builder<K, V> setKey(K key) {
this.key = key;
+ this.hasKey = true;
return this;
}
public Builder<K, V> clearKey() {
this.key = metadata.defaultKey;
+ this.hasKey = false;
return this;
}
public Builder<K, V> setValue(V value) {
this.value = value;
+ this.hasValue = true;
return this;
}
public Builder<K, V> clearValue() {
this.value = metadata.defaultValue;
+ this.hasValue = false;
return this;
}
@@ -404,7 +411,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
@Override
public boolean hasField(FieldDescriptor field) {
checkFieldDescriptor(field);
- return true;
+ return field.getNumber() == 1 ? hasKey : hasValue;
}
@Override
@@ -438,7 +445,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
@Override
@SuppressWarnings("unchecked")
public Builder<K, V> clone() {
- return new Builder(metadata, key, value);
+ return new Builder(metadata, key, value, hasKey, hasValue);
}
}
@@ -448,4 +455,9 @@ public final class MapEntry<K, V> extends AbstractMessage {
}
return true;
}
+
+ /** Returns the metadata only for experimental runtime. */
+ final Metadata<K, V> getMetadata() {
+ return metadata;
+ }
}
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
index 22aef8f9..dcb5dfad 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -223,4 +223,9 @@ public class MapEntryLite<K, V> {
input.popLimit(oldLimit);
map.put(key, value);
}
+
+ /** For experimental runtime internal use only. */
+ Metadata<K, V> getMetadata() {
+ return metadata;
+ }
}
diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
index 805defe2..ad8ceb02 100644
--- a/java/core/src/main/java/com/google/protobuf/MapField.java
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -329,6 +331,8 @@ public class MapField<K, V> implements MutabilityOracle {
@Override
public V put(K key, V value) {
mutabilityOracle.ensureMutable();
+ checkNotNull(key);
+ checkNotNull(value);
return delegate.put(key, value);
}
@@ -341,6 +345,10 @@ public class MapField<K, V> implements MutabilityOracle {
@Override
public void putAll(Map<? extends K, ? extends V> m) {
mutabilityOracle.ensureMutable();
+ for (K key : m.keySet()) {
+ checkNotNull(key);
+ checkNotNull(m.get(key));
+ }
delegate.putAll(m);
}
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index 42640279..a8b3dd88 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -30,8 +30,9 @@
package com.google.protobuf;
-import com.google.protobuf.Internal.EnumLite;
+import static com.google.protobuf.Internal.checkNotNull;
+import com.google.protobuf.Internal.EnumLite;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -88,6 +89,9 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
@Override public V put(K key, V value) {
ensureMutable();
+ checkNotNull(key);
+
+ checkNotNull(value);
return super.put(key, value);
}
@@ -97,6 +101,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
@Override public void putAll(Map<? extends K, ? extends V> m) {
ensureMutable();
+ checkForNullKeysAndValues(m);
super.putAll(m);
}
@@ -105,6 +110,13 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
return super.remove(key);
}
+ private static void checkForNullKeysAndValues(Map<?, ?> m) {
+ for (Object key : m.keySet()) {
+ checkNotNull(key);
+ checkNotNull(m.get(key));
+ }
+ }
+
private static boolean equals(Object a, Object b) {
if (a instanceof byte[] && b instanceof byte[]) {
return Arrays.equals((byte[]) a, (byte[]) b);
diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java
index cfbcb442..e07c6895 100644
--- a/java/core/src/main/java/com/google/protobuf/Parser.java
+++ b/java/core/src/main/java/com/google/protobuf/Parser.java
@@ -31,6 +31,7 @@
package com.google.protobuf;
import java.io.InputStream;
+import java.nio.ByteBuffer;
/**
* Abstract interface for parsing Protocol Messages.
@@ -93,6 +94,18 @@ public interface Parser<MessageType> {
// Convenience methods.
/**
+ * Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream)}.
+ */
+ public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException;
+
+ /**
+ * Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
+ * {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
+ */
+ public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+ /**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
*/
diff --git a/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java b/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java
new file mode 100644
index 00000000..79b5769d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java
@@ -0,0 +1,34 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+/** A marker interface indicating that the collection supports primitives and is non-boxing. */
+interface PrimitiveNonBoxingCollection {}
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
index 77b61b5f..30c991d4 100644
--- a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
@@ -290,9 +292,7 @@ public class RepeatedFieldBuilderV3
*/
public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
int index, MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
+ checkNotNull(message);
ensureMutableMessageList();
messages.set(index, message);
if (builders != null) {
@@ -315,9 +315,7 @@ public class RepeatedFieldBuilderV3
*/
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
+ checkNotNull(message);
ensureMutableMessageList();
messages.add(message);
if (builders != null) {
@@ -339,9 +337,7 @@ public class RepeatedFieldBuilderV3
*/
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
int index, MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
+ checkNotNull(message);
ensureMutableMessageList();
messages.add(index, message);
if (builders != null) {
@@ -363,9 +359,7 @@ public class RepeatedFieldBuilderV3
public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
Iterable<? extends MType> values) {
for (final MType value : values) {
- if (value == null) {
- throw new NullPointerException();
- }
+ checkNotNull(value);
}
// If we can inspect the size, we can more efficiently add messages.
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
index fb1f76a7..8ab0f26d 100644
--- a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import static com.google.protobuf.Internal.checkNotNull;
+
/**
* {@code SingleFieldBuilderV3} implements a structure that a protocol
* message uses to hold a single field of another protocol message. It supports
@@ -84,10 +86,7 @@ public class SingleFieldBuilderV3
MType message,
AbstractMessage.BuilderParent parent,
boolean isClean) {
- if (message == null) {
- throw new NullPointerException();
- }
- this.message = message;
+ this.message = checkNotNull(message);
this.parent = parent;
this.isClean = isClean;
}
@@ -169,10 +168,7 @@ public class SingleFieldBuilderV3
*/
public SingleFieldBuilderV3<MType, BType, IType> setMessage(
MType message) {
- if (message == null) {
- throw new NullPointerException();
- }
- this.message = message;
+ this.message = checkNotNull(message);
if (builder != null) {
builder.dispose();
builder = null;
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index 49708242..53dead80 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -1442,7 +1442,7 @@ public final class TextFormat {
/**
* Parse a single field from {@code tokenizer} and merge it into
- * {@code builder}.
+ * {@code target}.
*/
private void mergeField(final Tokenizer tokenizer,
final ExtensionRegistry extensionRegistry,
@@ -1712,6 +1712,8 @@ public final class TextFormat {
}
if (field.isRepeated()) {
+ // TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
+ // check for duplicate map keys here.
target.addRepeatedField(field, value);
} else if ((singularOverwritePolicy
== SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
index 2bef27e9..d9381135 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -91,7 +91,7 @@ public final class UnknownFieldSet implements MessageLite {
* Construct an {@code UnknownFieldSet} around the given map. The map is
* expected to be immutable.
*/
- private UnknownFieldSet(final Map<Integer, Field> fields,
+ UnknownFieldSet(final Map<Integer, Field> fields,
final Map<Integer, Field> fieldsDescending) {
this.fields = fields;
}
@@ -715,7 +715,7 @@ public final class UnknownFieldSet implements MessageLite {
* @see UnknownFieldSet
*/
public static final class Field {
- private Field() {}
+ Field() {}
/** Construct a new {@link Builder}. */
public static Builder newBuilder() {
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
index 5f7bafd6..ca80d946 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -33,19 +33,23 @@ package com.google.protobuf;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
-import sun.misc.Unsafe;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/** Utility class for working with unsafe operations. */
-// TODO(nathanmittler): Add support for Android Memory/MemoryBlock
final class UnsafeUtil {
+ private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+ private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
supportsUnsafeByteBufferOperations();
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
+ private static final boolean HAS_UNSAFE_COPY_MEMORY = supportsUnsafeCopyMemory();
private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
- private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
+ private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
private UnsafeUtil() {}
@@ -53,20 +57,16 @@ final class UnsafeUtil {
return HAS_UNSAFE_ARRAY_OPERATIONS;
}
- static boolean hasUnsafeByteBufferOperations() {
- return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
+ static boolean hasUnsafeCopyMemory() {
+ return HAS_UNSAFE_COPY_MEMORY;
}
- static Object allocateInstance(Class<?> clazz) {
- try {
- return UNSAFE.allocateInstance(clazz);
- } catch (InstantiationException e) {
- throw new RuntimeException(e);
- }
+ static boolean hasUnsafeByteBufferOperations() {
+ return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
}
static long objectFieldOffset(Field field) {
- return UNSAFE.objectFieldOffset(field);
+ return MEMORY_ACCESSOR.objectFieldOffset(field);
}
static long getArrayBaseOffset() {
@@ -74,103 +74,103 @@ final class UnsafeUtil {
}
static byte getByte(Object target, long offset) {
- return UNSAFE.getByte(target, offset);
+ return MEMORY_ACCESSOR.getByte(target, offset);
}
static void putByte(Object target, long offset, byte value) {
- UNSAFE.putByte(target, offset, value);
+ MEMORY_ACCESSOR.putByte(target, offset, value);
}
static int getInt(Object target, long offset) {
- return UNSAFE.getInt(target, offset);
+ return MEMORY_ACCESSOR.getInt(target, offset);
}
static void putInt(Object target, long offset, int value) {
- UNSAFE.putInt(target, offset, value);
+ MEMORY_ACCESSOR.putInt(target, offset, value);
}
static long getLong(Object target, long offset) {
- return UNSAFE.getLong(target, offset);
+ return MEMORY_ACCESSOR.getLong(target, offset);
}
static void putLong(Object target, long offset, long value) {
- UNSAFE.putLong(target, offset, value);
+ MEMORY_ACCESSOR.putLong(target, offset, value);
}
static boolean getBoolean(Object target, long offset) {
- return UNSAFE.getBoolean(target, offset);
+ return MEMORY_ACCESSOR.getBoolean(target, offset);
}
static void putBoolean(Object target, long offset, boolean value) {
- UNSAFE.putBoolean(target, offset, value);
+ MEMORY_ACCESSOR.putBoolean(target, offset, value);
}
static float getFloat(Object target, long offset) {
- return UNSAFE.getFloat(target, offset);
+ return MEMORY_ACCESSOR.getFloat(target, offset);
}
static void putFloat(Object target, long offset, float value) {
- UNSAFE.putFloat(target, offset, value);
+ MEMORY_ACCESSOR.putFloat(target, offset, value);
}
static double getDouble(Object target, long offset) {
- return UNSAFE.getDouble(target, offset);
+ return MEMORY_ACCESSOR.getDouble(target, offset);
}
static void putDouble(Object target, long offset, double value) {
- UNSAFE.putDouble(target, offset, value);
+ MEMORY_ACCESSOR.putDouble(target, offset, value);
}
static Object getObject(Object target, long offset) {
- return UNSAFE.getObject(target, offset);
+ return MEMORY_ACCESSOR.getObject(target, offset);
}
static void putObject(Object target, long offset, Object value) {
- UNSAFE.putObject(target, offset, value);
+ MEMORY_ACCESSOR.putObject(target, offset, value);
}
static void copyMemory(
Object src, long srcOffset, Object target, long targetOffset, long length) {
- UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
+ MEMORY_ACCESSOR.copyMemory(src, srcOffset, target, targetOffset, length);
}
static byte getByte(long address) {
- return UNSAFE.getByte(address);
+ return MEMORY_ACCESSOR.getByte(address);
}
static void putByte(long address, byte value) {
- UNSAFE.putByte(address, value);
+ MEMORY_ACCESSOR.putByte(address, value);
}
static int getInt(long address) {
- return UNSAFE.getInt(address);
+ return MEMORY_ACCESSOR.getInt(address);
}
static void putInt(long address, int value) {
- UNSAFE.putInt(address, value);
+ MEMORY_ACCESSOR.putInt(address, value);
}
static long getLong(long address) {
- return UNSAFE.getLong(address);
+ return MEMORY_ACCESSOR.getLong(address);
}
static void putLong(long address, long value) {
- UNSAFE.putLong(address, value);
+ MEMORY_ACCESSOR.putLong(address, value);
}
static void copyMemory(long srcAddress, long targetAddress, long length) {
- UNSAFE.copyMemory(srcAddress, targetAddress, length);
- }
-
- static void setMemory(long address, long numBytes, byte value) {
- UNSAFE.setMemory(address, numBytes, value);
+ MEMORY_ACCESSOR.copyMemory(srcAddress, targetAddress, length);
}
/**
* Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
*/
static long addressOffset(ByteBuffer buffer) {
- return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+ return MEMORY_ACCESSOR.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+ }
+
+ static Object getStaticObject(Field field) {
+ return MEMORY_ACCESSOR.getStaticObject(field);
}
/**
@@ -181,7 +181,7 @@ final class UnsafeUtil {
try {
unsafe =
AccessController.doPrivileged(
- new PrivilegedExceptionAction<Unsafe>() {
+ new PrivilegedExceptionAction<sun.misc.Unsafe>() {
@Override
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
@@ -204,69 +204,114 @@ final class UnsafeUtil {
return unsafe;
}
+ /** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */
+ private static MemoryAccessor getMemoryAccessor() {
+ if (UNSAFE == null) {
+ return null;
+ }
+ return new JvmMemoryAccessor(UNSAFE);
+ }
+
/** Indicates whether or not unsafe array operations are supported on this platform. */
private static boolean supportsUnsafeArrayOperations() {
- boolean supported = false;
- if (UNSAFE != null) {
- try {
- Class<?> clazz = UNSAFE.getClass();
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("allocateInstance", Class.class);
- clazz.getMethod("arrayBaseOffset", Class.class);
- clazz.getMethod("getByte", Object.class, long.class);
- clazz.getMethod("putByte", Object.class, long.class, byte.class);
- clazz.getMethod("getBoolean", Object.class, long.class);
- clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
- clazz.getMethod("getInt", Object.class, long.class);
- clazz.getMethod("putInt", Object.class, long.class, int.class);
- clazz.getMethod("getLong", Object.class, long.class);
- clazz.getMethod("putLong", Object.class, long.class, long.class);
- clazz.getMethod("getFloat", Object.class, long.class);
- clazz.getMethod("putFloat", Object.class, long.class, float.class);
- clazz.getMethod("getDouble", Object.class, long.class);
- clazz.getMethod("putDouble", Object.class, long.class, double.class);
- clazz.getMethod("getObject", Object.class, long.class);
- clazz.getMethod("putObject", Object.class, long.class, Object.class);
- clazz.getMethod(
- "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
- supported = true;
- } catch (Throwable e) {
- // Do nothing.
- }
- }
- return supported;
+ if (UNSAFE == null) {
+ return false;
+ }
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("arrayBaseOffset", Class.class);
+ clazz.getMethod("getInt", Object.class, long.class);
+ clazz.getMethod("putInt", Object.class, long.class, int.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+ 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);
+ clazz.getMethod("getByte", Object.class, long.class);
+ clazz.getMethod("putByte", Object.class, long.class, byte.class);
+ clazz.getMethod("getBoolean", Object.class, long.class);
+ clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
+ clazz.getMethod("getFloat", Object.class, long.class);
+ clazz.getMethod("putFloat", Object.class, long.class, float.class);
+ clazz.getMethod("getDouble", Object.class, long.class);
+ clazz.getMethod("putDouble", Object.class, long.class, double.class);
+
+ return true;
+ } catch (Throwable e) {
+ logger.log(
+ Level.WARNING,
+ "platform method missing - proto runtime falling back to safer methods: " + e);
+ }
+ return false;
+ }
+
+ /**
+ * Indicates whether or not unsafe copyMemory(object, long, object, long, long) operations are
+ * supported on this platform.
+ */
+ private static boolean supportsUnsafeCopyMemory() {
+ if (UNSAFE == null) {
+ return false;
+ }
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+
+ return true;
+ } catch (Throwable e) {
+ logger.log(
+ Level.WARNING,
+ "copyMemory is missing from platform - proto runtime falling back to safer methods.");
+ }
+ return false;
}
private static boolean supportsUnsafeByteBufferOperations() {
- boolean supported = false;
- if (UNSAFE != null) {
- try {
- Class<?> clazz = UNSAFE.getClass();
- // Methods for getting direct buffer address.
- clazz.getMethod("objectFieldOffset", Field.class);
- clazz.getMethod("getLong", Object.class, long.class);
-
- clazz.getMethod("getByte", long.class);
- clazz.getMethod("putByte", long.class, byte.class);
- clazz.getMethod("getInt", long.class);
- clazz.getMethod("putInt", long.class, int.class);
- clazz.getMethod("getLong", long.class);
- clazz.getMethod("putLong", long.class, long.class);
- clazz.getMethod("setMemory", long.class, long.class, byte.class);
- clazz.getMethod("copyMemory", long.class, long.class, long.class);
- supported = true;
- } catch (Throwable e) {
- // Do nothing.
- }
- }
- return supported;
+ if (UNSAFE == null) {
+ return false;
+ }
+ try {
+ Class<?> clazz = UNSAFE.getClass();
+ // Methods for getting direct buffer address.
+ clazz.getMethod("objectFieldOffset", Field.class);
+ clazz.getMethod("getLong", Object.class, long.class);
+
+ clazz.getMethod("getByte", long.class);
+ clazz.getMethod("putByte", long.class, byte.class);
+ clazz.getMethod("getInt", long.class);
+ clazz.getMethod("putInt", long.class, int.class);
+ clazz.getMethod("getLong", long.class);
+ clazz.getMethod("putLong", long.class, long.class);
+ clazz.getMethod("copyMemory", long.class, long.class, long.class);
+ return true;
+ } catch (Throwable e) {
+ logger.log(
+ Level.WARNING,
+ "platform method missing - proto runtime falling back to safer methods: " + e);
+ }
+ return false;
+ }
+
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> getClassForName(String name) {
+ try {
+ return (Class<T>) Class.forName(name);
+ } catch (Throwable e) {
+ return null;
+ }
+ }
+
+ /** Finds the address field within a direct {@link Buffer}. */
+ private static Field bufferAddressField() {
+ return field(Buffer.class, "address");
}
/**
* Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
*/
private static int byteArrayBaseOffset() {
- return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
+ return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(byte[].class) : -1;
}
/**
@@ -274,7 +319,7 @@ final class UnsafeUtil {
* available.
*/
private static long fieldOffset(Field field) {
- return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
+ return field == null || MEMORY_ACCESSOR == null ? -1 : MEMORY_ACCESSOR.objectFieldOffset(field);
}
/**
@@ -292,4 +337,174 @@ final class UnsafeUtil {
}
return field;
}
+
+ private abstract static class MemoryAccessor {
+
+ sun.misc.Unsafe unsafe;
+
+ MemoryAccessor(sun.misc.Unsafe unsafe) {
+ this.unsafe = unsafe;
+ }
+
+ public final long objectFieldOffset(Field field) {
+ return unsafe.objectFieldOffset(field);
+ }
+
+ public abstract byte getByte(Object target, long offset);
+
+ public abstract void putByte(Object target, long offset, byte value);
+
+ public final int getInt(Object target, long offset) {
+ return unsafe.getInt(target, offset);
+ }
+
+ public final void putInt(Object target, long offset, int value) {
+ unsafe.putInt(target, offset, value);
+ }
+
+ public final long getLong(Object target, long offset) {
+ return unsafe.getLong(target, offset);
+ }
+
+ public final void putLong(Object target, long offset, long value) {
+ unsafe.putLong(target, offset, value);
+ }
+
+ public abstract boolean getBoolean(Object target, long offset);
+
+ public abstract void putBoolean(Object target, long offset, boolean value);
+
+ public abstract float getFloat(Object target, long offset);
+
+ public abstract void putFloat(Object target, long offset, float value);
+
+ public abstract double getDouble(Object target, long offset);
+
+ public abstract void putDouble(Object target, long offset, double value);
+
+ public final Object getObject(Object target, long offset) {
+ return unsafe.getObject(target, offset);
+ }
+
+ public final void putObject(Object target, long offset, Object value) {
+ unsafe.putObject(target, offset, value);
+ }
+
+ public final int arrayBaseOffset(Class<?> clazz) {
+ return unsafe.arrayBaseOffset(clazz);
+ }
+
+ public abstract byte getByte(long address);
+
+ public abstract void putByte(long address, byte value);
+
+ public abstract int getInt(long address);
+
+ public abstract void putInt(long address, int value);
+
+ public abstract long getLong(long address);
+
+ public abstract void putLong(long address, long value);
+
+ public abstract void copyMemory(long srcAddress, long targetAddress, long length);
+
+ public abstract void copyMemory(
+ Object src, long srcOffset, Object target, long targetOffset, long length);
+
+ public abstract Object getStaticObject(Field field);
+ }
+
+ private static final class JvmMemoryAccessor extends MemoryAccessor {
+
+ JvmMemoryAccessor(sun.misc.Unsafe unsafe) {
+ super(unsafe);
+ }
+
+ @Override
+ public byte getByte(long address) {
+ return unsafe.getByte(address);
+ }
+
+ @Override
+ public void putByte(long address, byte value) {
+ unsafe.putByte(address, value);
+ }
+
+ @Override
+ public int getInt(long address) {
+ return unsafe.getInt(address);
+ }
+
+ @Override
+ public void putInt(long address, int value) {
+ unsafe.putInt(address, value);
+ }
+
+ @Override
+ public long getLong(long address) {
+ return unsafe.getLong(address);
+ }
+
+ @Override
+ public void putLong(long address, long value) {
+ unsafe.putLong(address, value);
+ }
+
+ @Override
+ public byte getByte(Object target, long offset) {
+ return unsafe.getByte(target, offset);
+ }
+
+ @Override
+ public void putByte(Object target, long offset, byte value) {
+ unsafe.putByte(target, offset, value);
+ }
+
+ @Override
+ public boolean getBoolean(Object target, long offset) {
+ return unsafe.getBoolean(target, offset);
+ }
+
+ @Override
+ public void putBoolean(Object target, long offset, boolean value) {
+ unsafe.putBoolean(target, offset, value);
+ }
+
+ @Override
+ public float getFloat(Object target, long offset) {
+ return unsafe.getFloat(target, offset);
+ }
+
+ @Override
+ public void putFloat(Object target, long offset, float value) {
+ unsafe.putFloat(target, offset, value);
+ }
+
+ @Override
+ public double getDouble(Object target, long offset) {
+ return unsafe.getDouble(target, offset);
+ }
+
+ @Override
+ public void putDouble(Object target, long offset, double value) {
+ unsafe.putDouble(target, offset, value);
+ }
+
+ @Override
+ public void copyMemory(
+ Object src, long srcOffset, Object target, long targetOffset, long length) {
+ unsafe.copyMemory(src, srcOffset, target, targetOffset, length);
+ }
+
+ @Override
+ public void copyMemory(long srcAddress, long targetAddress, long length) {
+ unsafe.copyMemory(srcAddress, targetAddress, length);
+ }
+
+ @Override
+ public Object getStaticObject(Field field) {
+ return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
+ }
+ }
+
}
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
index 5b80d405..be7b746e 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -1332,7 +1332,7 @@ final class Utf8 {
// the index (relative to the start of the array) is also 8-byte aligned. We do this by
// ANDing the index with 7 to determine the number of bytes that need to be read before
// we're 8-byte aligned.
- final int unaligned = (int) offset & 7;
+ final int unaligned = 8 - ((int) offset & 7);
for (int j = unaligned; j > 0; j--) {
if (UnsafeUtil.getByte(bytes, offset++) < 0) {
return unaligned - j;