| Index: third_party/protobuf/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
|
| diff --git a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
|
| index 3e32c2c536a87298eb8da64f3d149d944ab96df7..ad174d0ff6049c73dfad44cc55ed02e29284fb06 100644
|
| --- a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
|
| +++ b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
|
| @@ -30,17 +30,18 @@
|
|
|
| package com.google.protobuf;
|
|
|
| -import static com.google.protobuf.WireFormat.FIXED_32_SIZE;
|
| -import static com.google.protobuf.WireFormat.FIXED_64_SIZE;
|
| -import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE;
|
| import static java.lang.Math.max;
|
|
|
| import com.google.protobuf.Utf8.UnpairedSurrogateException;
|
| +
|
| import java.io.IOException;
|
| import java.io.OutputStream;
|
| +import java.lang.reflect.Field;
|
| import java.nio.BufferOverflowException;
|
| import java.nio.ByteBuffer;
|
| import java.nio.ByteOrder;
|
| +import java.security.AccessController;
|
| +import java.security.PrivilegedExceptionAction;
|
| import java.util.logging.Level;
|
| import java.util.logging.Logger;
|
|
|
| @@ -58,8 +59,13 @@ import java.util.logging.Logger;
|
| */
|
| public abstract class CodedOutputStream extends ByteOutput {
|
| private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
|
| - private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
|
| - private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset();
|
| + private static final sun.misc.Unsafe UNSAFE = getUnsafe();
|
| + private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
|
| + private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
|
| +
|
| + private static final int FIXED_32_SIZE = 4;
|
| + private static final int FIXED_64_SIZE = 8;
|
| + private static final int MAX_VARINT_SIZE = 10;
|
|
|
| /**
|
| * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead.
|
| @@ -132,66 +138,15 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| return new ArrayEncoder(flatArray, offset, length);
|
| }
|
|
|
| - /** Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. */
|
| - public static CodedOutputStream newInstance(ByteBuffer buffer) {
|
| - if (buffer.hasArray()) {
|
| - return new HeapNioEncoder(buffer);
|
| - }
|
| - if (buffer.isDirect() && !buffer.isReadOnly()) {
|
| - return UnsafeDirectNioEncoder.isSupported()
|
| - ? newUnsafeInstance(buffer)
|
| - : newSafeInstance(buffer);
|
| - }
|
| - throw new IllegalArgumentException("ByteBuffer is read-only");
|
| - }
|
| -
|
| - /** For testing purposes only. */
|
| - static CodedOutputStream newUnsafeInstance(ByteBuffer buffer) {
|
| - return new UnsafeDirectNioEncoder(buffer);
|
| - }
|
| -
|
| - /** For testing purposes only. */
|
| - static CodedOutputStream newSafeInstance(ByteBuffer buffer) {
|
| - return new SafeDirectNioEncoder(buffer);
|
| - }
|
| -
|
| /**
|
| - * Configures serialization to be deterministic.
|
| - *
|
| - * <p>The deterministic serialization guarantees that for a given binary, equal (defined by the
|
| - * {@code equals()} methods in protos) messages will always be serialized to the same bytes. This
|
| - * implies:
|
| - *
|
| - * <ul>
|
| - * <li>repeated serialization of a message will return the same bytes
|
| - * <li>different processes of the same binary (which may be executing on different machines) will
|
| - * serialize equal messages to the same bytes.
|
| - * </ul>
|
| - *
|
| - * <p>Note the deterministic serialization is NOT canonical across languages; it is also unstable
|
| - * across different builds with schema changes due to unknown fields. Users who need canonical
|
| - * serialization, e.g. persistent storage in a canonical form, fingerprinting, etc, should define
|
| - * their own canonicalization specification and implement the serializer using reflection APIs
|
| - * rather than relying on this API.
|
| - *
|
| - * <p> Once set, the serializer will: (Note this is an implementation detail and may subject to
|
| - * change in the future)
|
| - *
|
| - * <ul>
|
| - * <li> sort map entries by keys in lexicographical order or numerical order. Note: For string
|
| - * keys, the order is based on comparing the Unicode value of each character in the strings.
|
| - * The order may be different from the deterministic serialization in other languages where
|
| - * maps are sorted on the lexicographical order of the UTF8 encoded keys.
|
| - * </ul>
|
| + * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
|
| */
|
| - void useDeterministicSerialization() {
|
| - serializationDeterministic = true;
|
| - }
|
| -
|
| - boolean isSerializationDeterministic() {
|
| - return serializationDeterministic;
|
| + public static CodedOutputStream newInstance(ByteBuffer byteBuffer) {
|
| + if (byteBuffer.hasArray()) {
|
| + return new NioHeapEncoder(byteBuffer);
|
| + }
|
| + return new NioEncoder(byteBuffer);
|
| }
|
| - private boolean serializationDeterministic;
|
|
|
| /**
|
| * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}.
|
| @@ -914,7 +869,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| return computeLengthDelimitedFieldSize(value.getSerializedSize());
|
| }
|
|
|
| - static int computeLengthDelimitedFieldSize(int fieldLength) {
|
| + private static int computeLengthDelimitedFieldSize(int fieldLength) {
|
| return computeUInt32SizeNoTag(fieldLength) + fieldLength;
|
| }
|
|
|
| @@ -990,17 +945,9 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| super(MESSAGE);
|
| }
|
|
|
| - OutOfSpaceException(String explanationMessage) {
|
| - super(MESSAGE + ": " + explanationMessage);
|
| - }
|
| -
|
| OutOfSpaceException(Throwable cause) {
|
| super(MESSAGE, cause);
|
| }
|
| -
|
| - OutOfSpaceException(String explanationMessage, Throwable cause) {
|
| - super(MESSAGE + ": " + explanationMessage, cause);
|
| - }
|
| }
|
|
|
| /**
|
| @@ -1303,8 +1250,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| try {
|
| buffer[position++] = value;
|
| } catch (IndexOutOfBoundsException e) {
|
| - throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
|
| + throw new OutOfSpaceException(new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
|
| }
|
| }
|
|
|
| @@ -1324,11 +1271,11 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| long pos = ARRAY_BASE_OFFSET + position;
|
| while (true) {
|
| if ((value & ~0x7F) == 0) {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) value);
|
| + UNSAFE.putByte(buffer, pos++, (byte) value);
|
| position++;
|
| return;
|
| } else {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
|
| + UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
|
| position++;
|
| value >>>= 7;
|
| }
|
| @@ -1346,7 +1293,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| }
|
| } catch (IndexOutOfBoundsException e) {
|
| throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
|
| + new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
|
| }
|
| }
|
| }
|
| @@ -1360,7 +1308,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| buffer[position++] = (byte) ((value >> 24) & 0xFF);
|
| } catch (IndexOutOfBoundsException e) {
|
| throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
|
| + new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
|
| }
|
| }
|
|
|
| @@ -1370,11 +1319,11 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| long pos = ARRAY_BASE_OFFSET + position;
|
| while (true) {
|
| if ((value & ~0x7FL) == 0) {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) value);
|
| + UNSAFE.putByte(buffer, pos++, (byte) value);
|
| position++;
|
| return;
|
| } else {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
|
| + UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
|
| position++;
|
| value >>>= 7;
|
| }
|
| @@ -1392,7 +1341,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| }
|
| } catch (IndexOutOfBoundsException e) {
|
| throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
|
| + new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
|
| }
|
| }
|
| }
|
| @@ -1410,7 +1360,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
|
| } catch (IndexOutOfBoundsException e) {
|
| throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
|
| + new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
|
| }
|
| }
|
|
|
| @@ -1421,7 +1372,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| position += length;
|
| } catch (IndexOutOfBoundsException e) {
|
| throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
|
| + new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
|
| }
|
| }
|
|
|
| @@ -1438,7 +1390,8 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| position += length;
|
| } catch (IndexOutOfBoundsException e) {
|
| throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
|
| + new IndexOutOfBoundsException(
|
| + String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
|
| }
|
| }
|
|
|
| @@ -1501,11 +1454,11 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are
|
| * done directly to the underlying array. The buffer position is only updated after a flush.
|
| */
|
| - private static final class HeapNioEncoder extends ArrayEncoder {
|
| + private static final class NioHeapEncoder extends ArrayEncoder {
|
| private final ByteBuffer byteBuffer;
|
| private int initialPosition;
|
|
|
| - HeapNioEncoder(ByteBuffer byteBuffer) {
|
| + NioHeapEncoder(ByteBuffer byteBuffer) {
|
| super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
|
| byteBuffer.remaining());
|
| this.byteBuffer = byteBuffer;
|
| @@ -1520,15 +1473,14 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| }
|
|
|
| /**
|
| - * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer}, using only
|
| - * safe operations..
|
| + * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}.
|
| */
|
| - private static final class SafeDirectNioEncoder extends CodedOutputStream {
|
| + private static final class NioEncoder extends CodedOutputStream {
|
| private final ByteBuffer originalBuffer;
|
| private final ByteBuffer buffer;
|
| private final int initialPosition;
|
|
|
| - SafeDirectNioEncoder(ByteBuffer buffer) {
|
| + NioEncoder(ByteBuffer buffer) {
|
| this.originalBuffer = buffer;
|
| this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
|
| initialPosition = buffer.position();
|
| @@ -1831,356 +1783,6 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| }
|
|
|
| /**
|
| - * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuffer} using {@code
|
| - * sun.misc.Unsafe}.
|
| - */
|
| - private static final class UnsafeDirectNioEncoder extends CodedOutputStream {
|
| - private final ByteBuffer originalBuffer;
|
| - private final ByteBuffer buffer;
|
| - private final long address;
|
| - private final long initialPosition;
|
| - private final long limit;
|
| - private final long oneVarintLimit;
|
| - private long position;
|
| -
|
| - UnsafeDirectNioEncoder(ByteBuffer buffer) {
|
| - this.originalBuffer = buffer;
|
| - this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
|
| - address = UnsafeUtil.addressOffset(buffer);
|
| - initialPosition = address + buffer.position();
|
| - limit = address + buffer.limit();
|
| - oneVarintLimit = limit - MAX_VARINT_SIZE;
|
| - position = initialPosition;
|
| - }
|
| -
|
| - static boolean isSupported() {
|
| - return UnsafeUtil.hasUnsafeByteBufferOperations();
|
| - }
|
| -
|
| - @Override
|
| - public void writeTag(int fieldNumber, int wireType) throws IOException {
|
| - writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType));
|
| - }
|
| -
|
| - @Override
|
| - public void writeInt32(int fieldNumber, int value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
|
| - writeInt32NoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeUInt32(int fieldNumber, int value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
|
| - writeUInt32NoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeFixed32(int fieldNumber, int value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32);
|
| - writeFixed32NoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeUInt64(int fieldNumber, long value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
|
| - writeUInt64NoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeFixed64(int fieldNumber, long value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64);
|
| - writeFixed64NoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeBool(int fieldNumber, boolean value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT);
|
| - write((byte) (value ? 1 : 0));
|
| - }
|
| -
|
| - @Override
|
| - public void writeString(int fieldNumber, String value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
| - writeStringNoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeBytes(int fieldNumber, ByteString value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
| - writeBytesNoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeByteArray(int fieldNumber, byte[] value) throws IOException {
|
| - writeByteArray(fieldNumber, value, 0, value.length);
|
| - }
|
| -
|
| - @Override
|
| - public void writeByteArray(int fieldNumber, byte[] value, int offset, int length)
|
| - throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
| - writeByteArrayNoTag(value, offset, length);
|
| - }
|
| -
|
| - @Override
|
| - public void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
| - writeUInt32NoTag(value.capacity());
|
| - writeRawBytes(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeMessage(int fieldNumber, MessageLite value) throws IOException {
|
| - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
|
| - writeMessageNoTag(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeMessageSetExtension(int fieldNumber, MessageLite value) throws IOException {
|
| - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
|
| - writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
|
| - writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
|
| - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
|
| - }
|
| -
|
| - @Override
|
| - public void writeRawMessageSetExtension(int fieldNumber, ByteString value) throws IOException {
|
| - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
|
| - writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
|
| - writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
|
| - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
|
| - }
|
| -
|
| - @Override
|
| - public void writeMessageNoTag(MessageLite value) throws IOException {
|
| - writeUInt32NoTag(value.getSerializedSize());
|
| - value.writeTo(this);
|
| - }
|
| -
|
| - @Override
|
| - public void write(byte value) throws IOException {
|
| - if (position >= limit) {
|
| - throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
|
| - }
|
| - UnsafeUtil.putByte(position++, value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeBytesNoTag(ByteString value) throws IOException {
|
| - writeUInt32NoTag(value.size());
|
| - value.writeTo(this);
|
| - }
|
| -
|
| - @Override
|
| - public void writeByteArrayNoTag(byte[] value, int offset, int length) throws IOException {
|
| - writeUInt32NoTag(length);
|
| - write(value, offset, length);
|
| - }
|
| -
|
| - @Override
|
| - public void writeRawBytes(ByteBuffer value) throws IOException {
|
| - if (value.hasArray()) {
|
| - write(value.array(), value.arrayOffset(), value.capacity());
|
| - } else {
|
| - ByteBuffer duplicated = value.duplicate();
|
| - duplicated.clear();
|
| - write(duplicated);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void writeInt32NoTag(int value) throws IOException {
|
| - if (value >= 0) {
|
| - writeUInt32NoTag(value);
|
| - } else {
|
| - // Must sign-extend.
|
| - writeUInt64NoTag(value);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void writeUInt32NoTag(int value) throws IOException {
|
| - if (position <= oneVarintLimit) {
|
| - // Optimization to avoid bounds checks on each iteration.
|
| - while (true) {
|
| - if ((value & ~0x7F) == 0) {
|
| - UnsafeUtil.putByte(position++, (byte) value);
|
| - return;
|
| - } else {
|
| - UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
|
| - value >>>= 7;
|
| - }
|
| - }
|
| - } else {
|
| - while (position < limit) {
|
| - if ((value & ~0x7F) == 0) {
|
| - UnsafeUtil.putByte(position++, (byte) value);
|
| - return;
|
| - } else {
|
| - UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80));
|
| - value >>>= 7;
|
| - }
|
| - }
|
| - throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void writeFixed32NoTag(int value) throws IOException {
|
| - buffer.putInt(bufferPos(position), value);
|
| - position += FIXED_32_SIZE;
|
| - }
|
| -
|
| - @Override
|
| - public void writeUInt64NoTag(long value) throws IOException {
|
| - if (position <= oneVarintLimit) {
|
| - // Optimization to avoid bounds checks on each iteration.
|
| - while (true) {
|
| - if ((value & ~0x7FL) == 0) {
|
| - UnsafeUtil.putByte(position++, (byte) value);
|
| - return;
|
| - } else {
|
| - UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
|
| - value >>>= 7;
|
| - }
|
| - }
|
| - } else {
|
| - while (position < limit) {
|
| - if ((value & ~0x7FL) == 0) {
|
| - UnsafeUtil.putByte(position++, (byte) value);
|
| - return;
|
| - } else {
|
| - UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80));
|
| - value >>>= 7;
|
| - }
|
| - }
|
| - throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, 1));
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void writeFixed64NoTag(long value) throws IOException {
|
| - buffer.putLong(bufferPos(position), value);
|
| - position += FIXED_64_SIZE;
|
| - }
|
| -
|
| - @Override
|
| - public void write(byte[] value, int offset, int length) throws IOException {
|
| - if (value == null
|
| - || offset < 0
|
| - || length < 0
|
| - || (value.length - length) < offset
|
| - || (limit - length) < position) {
|
| - if (value == null) {
|
| - throw new NullPointerException("value");
|
| - }
|
| - throw new OutOfSpaceException(
|
| - String.format("Pos: %d, limit: %d, len: %d", position, limit, length));
|
| - }
|
| -
|
| - UnsafeUtil.copyMemory(
|
| - value, UnsafeUtil.getArrayBaseOffset() + offset, null, position, length);
|
| - position += length;
|
| - }
|
| -
|
| - @Override
|
| - public void writeLazy(byte[] value, int offset, int length) throws IOException {
|
| - write(value, offset, length);
|
| - }
|
| -
|
| - @Override
|
| - public void write(ByteBuffer value) throws IOException {
|
| - try {
|
| - int length = value.remaining();
|
| - repositionBuffer(position);
|
| - buffer.put(value);
|
| - position += length;
|
| - } catch (BufferOverflowException e) {
|
| - throw new OutOfSpaceException(e);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void writeLazy(ByteBuffer value) throws IOException {
|
| - write(value);
|
| - }
|
| -
|
| - @Override
|
| - public void writeStringNoTag(String value) throws IOException {
|
| - long prevPos = position;
|
| - try {
|
| - // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()),
|
| - // and at most 3 times of it. We take advantage of this in both branches below.
|
| - int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR;
|
| - int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize);
|
| - int minLengthVarIntSize = computeUInt32SizeNoTag(value.length());
|
| - if (minLengthVarIntSize == maxLengthVarIntSize) {
|
| - // Save the current position and increment past the length field. We'll come back
|
| - // and write the length field after the encoding is complete.
|
| - int stringStart = bufferPos(position) + minLengthVarIntSize;
|
| - buffer.position(stringStart);
|
| -
|
| - // Encode the string.
|
| - Utf8.encodeUtf8(value, buffer);
|
| -
|
| - // Write the length and advance the position.
|
| - int length = buffer.position() - stringStart;
|
| - writeUInt32NoTag(length);
|
| - position += length;
|
| - } else {
|
| - // Calculate and write the encoded length.
|
| - int length = Utf8.encodedLength(value);
|
| - writeUInt32NoTag(length);
|
| -
|
| - // Write the string and advance the position.
|
| - repositionBuffer(position);
|
| - Utf8.encodeUtf8(value, buffer);
|
| - position += length;
|
| - }
|
| - } catch (UnpairedSurrogateException e) {
|
| - // Roll back the change and convert to an IOException.
|
| - position = prevPos;
|
| - repositionBuffer(position);
|
| -
|
| - // TODO(nathanmittler): We should throw an IOException here instead.
|
| - inefficientWriteStringNoTag(value, e);
|
| - } catch (IllegalArgumentException e) {
|
| - // Thrown by buffer.position() if out of range.
|
| - throw new OutOfSpaceException(e);
|
| - } catch (IndexOutOfBoundsException e) {
|
| - throw new OutOfSpaceException(e);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void flush() {
|
| - // Update the position of the original buffer.
|
| - originalBuffer.position(bufferPos(position));
|
| - }
|
| -
|
| - @Override
|
| - public int spaceLeft() {
|
| - return (int) (limit - position);
|
| - }
|
| -
|
| - @Override
|
| - public int getTotalBytesWritten() {
|
| - return (int) (position - initialPosition);
|
| - }
|
| -
|
| - private void repositionBuffer(long pos) {
|
| - buffer.position(bufferPos(pos));
|
| - }
|
| -
|
| - private int bufferPos(long pos) {
|
| - return (int) (pos - address);
|
| - }
|
| - }
|
| -
|
| - /**
|
| * Abstract base class for buffered encoders.
|
| */
|
| private abstract static class AbstractBufferedEncoder extends CodedOutputStream {
|
| @@ -2253,10 +1855,10 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| long pos = originalPos;
|
| while (true) {
|
| if ((value & ~0x7F) == 0) {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) value);
|
| + UNSAFE.putByte(buffer, pos++, (byte) value);
|
| break;
|
| } else {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
|
| + UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
|
| value >>>= 7;
|
| }
|
| }
|
| @@ -2288,10 +1890,10 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| long pos = originalPos;
|
| while (true) {
|
| if ((value & ~0x7FL) == 0) {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) value);
|
| + UNSAFE.putByte(buffer, pos++, (byte) value);
|
| break;
|
| } else {
|
| - UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
|
| + UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
|
| value >>>= 7;
|
| }
|
| }
|
| @@ -2998,4 +2600,65 @@ public abstract class CodedOutputStream extends ByteOutput {
|
| position = 0;
|
| }
|
| }
|
| +
|
| + /**
|
| + * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
|
| + * platform.
|
| + */
|
| + private static sun.misc.Unsafe getUnsafe() {
|
| + sun.misc.Unsafe unsafe = null;
|
| + try {
|
| + unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
|
| + @Override
|
| + public sun.misc.Unsafe run() throws Exception {
|
| + Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
|
| +
|
| + for (Field f : k.getDeclaredFields()) {
|
| + f.setAccessible(true);
|
| + Object x = f.get(null);
|
| + if (k.isInstance(x)) {
|
| + return k.cast(x);
|
| + }
|
| + }
|
| + // The sun.misc.Unsafe field does not exist.
|
| + return null;
|
| + }
|
| + });
|
| + } catch (Throwable e) {
|
| + // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
|
| + // for Unsafe.
|
| + }
|
| +
|
| + logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
|
| + unsafe != null ? "available" : "unavailable");
|
| + return unsafe;
|
| + }
|
| +
|
| + /**
|
| + * Indicates whether or not unsafe array operations are supported on this platform.
|
| + */
|
| + // TODO(nathanmittler): Add support for Android's MemoryBlock.
|
| + private static boolean supportsUnsafeArrayOperations() {
|
| + boolean supported = false;
|
| + if (UNSAFE != null) {
|
| + try {
|
| + UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class);
|
| + UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class);
|
| + supported = true;
|
| + } catch (Throwable e) {
|
| + // Do nothing.
|
| + }
|
| + }
|
| + logger.log(Level.FINEST, "Unsafe array operations: {}",
|
| + supported ? "available" : "unavailable");
|
| + return supported;
|
| + }
|
| +
|
| + /**
|
| + * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
|
| + * available.
|
| + */
|
| + private static <T> int byteArrayBaseOffset() {
|
| + return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
|
| + }
|
| }
|
|
|