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; |
+ } |
} |