Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions java/core/src/main/java/com/google/protobuf/CodedInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -1504,7 +1504,10 @@ public String readString() throws IOException {
// TODO(anuraaga): It might be possible to share the optimized loop with
// readStringRequireUtf8 by implementing Java replacement logic there.
// The same as readBytes' logic
byte[] bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
UnsafeUtil.copyMemory(pos, bytes, 0, size);
String result = new String(bytes, UTF_8);
pos += size;
Expand Down Expand Up @@ -1621,7 +1624,10 @@ public ByteString readBytes() throws IOException {
return ByteString.wrap(result);
} else {
// Use UnsafeUtil to copy the memory to bytes instead of using ByteBuffer ways.
byte[] bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
UnsafeUtil.copyMemory(pos, bytes, 0, size);
pos += size;
return ByteString.wrap(bytes);
Expand Down Expand Up @@ -1655,7 +1661,10 @@ public ByteBuffer readByteBuffer() throws IOException {
return result;
} else {
// The same as readBytes' logic
byte[] bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
UnsafeUtil.copyMemory(pos, bytes, 0, size);
pos += size;
return ByteBuffer.wrap(bytes);
Expand Down Expand Up @@ -1954,7 +1963,10 @@ public byte readRawByte() throws IOException {
@Override
public byte[] readRawBytes(final int length) throws IOException {
if (length >= 0 && length <= remaining()) {
byte[] bytes = new byte[length];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(length)
: new byte[length];
slice(pos, pos + length).get(bytes);
pos += length;
return bytes;
Expand Down Expand Up @@ -3348,14 +3360,20 @@ public boolean readBool() throws IOException {
public String readString() throws IOException {
final int size = readRawVarint32();
if (size > 0 && size <= currentByteBufferLimit - currentByteBufferPos) {
byte[] bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
String result = new String(bytes, UTF_8);
currentByteBufferPos += size;
return result;
} else if (size > 0 && size <= remaining()) {
// TODO(yilunchong): To use an underlying bytes[] instead of allocating a new bytes[]
byte[] bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
readRawBytesTo(bytes, 0, size);
String result = new String(bytes, UTF_8);
return result;
Expand Down Expand Up @@ -3476,14 +3494,19 @@ public ByteString readBytes() throws IOException {
currentByteBufferPos += size;
return result;
} else {
byte[] bytes;
bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
currentByteBufferPos += size;
return ByteString.wrap(bytes);
}
} else if (size > 0 && size <= remaining()) {
byte[] temp = new byte[size];
byte[] temp =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
readRawBytesTo(temp, 0, size);
return ByteString.wrap(temp);
}
Expand Down Expand Up @@ -3512,13 +3535,19 @@ public ByteBuffer readByteBuffer() throws IOException {
(int) (currentByteBufferPos - currentAddress - size),
(int) (currentByteBufferPos - currentAddress));
} else {
byte[] bytes = new byte[size];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, size);
currentByteBufferPos += size;
return ByteBuffer.wrap(bytes);
}
} else if (size > 0 && size <= remaining()) {
byte[] temp = new byte[size];
byte[] temp =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(size)
: new byte[size];
readRawBytesTo(temp, 0, size);
return ByteBuffer.wrap(temp);
}
Expand Down Expand Up @@ -3793,13 +3822,19 @@ public byte readRawByte() throws IOException {
@Override
public byte[] readRawBytes(final int length) throws IOException {
if (length >= 0 && length <= currentRemaining()) {
byte[] bytes = new byte[length];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(length)
: new byte[length];
UnsafeUtil.copyMemory(currentByteBufferPos, bytes, 0, length);
currentByteBufferPos += length;
return bytes;
}
if (length >= 0 && length <= remaining()) {
byte[] bytes = new byte[length];
byte[] bytes =
UnsafeUtil.hasUnsafeAllocateArrayOperation()
? UnsafeUtil.allocateUninitializedArray(length)
: new byte[length];
readRawBytesTo(bytes, 0, length);
return bytes;
}
Expand Down
99 changes: 97 additions & 2 deletions java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@
package com.google.protobuf;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -43,6 +46,8 @@
final class UnsafeUtil {
private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
private static final Object INTERNAL_UNSAFE = getInternalUnsafe();
private static final Method ALLOCATE_ARRAY_METHOD = getAllocateArrayMethod();
private static final Class<?> MEMORY_CLASS = Android.getMemoryClass();
private static final boolean IS_ANDROID_64 = determineAndroidSupportByAddressSize(long.class);
private static final boolean IS_ANDROID_32 = determineAndroidSupportByAddressSize(int.class);
Expand Down Expand Up @@ -92,6 +97,10 @@ static boolean hasUnsafeByteBufferOperations() {
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
}

static boolean hasUnsafeAllocateArrayOperation() {
return ALLOCATE_ARRAY_METHOD != null;
}

static boolean isAndroid64() {
return IS_ANDROID_64;
}
Expand Down Expand Up @@ -251,6 +260,10 @@ static void copyMemory(byte[] src, long srcIndex, byte[] target, long targetInde
System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length);
}

static byte[] allocateUninitializedArray(int size) {
return MEMORY_ACCESSOR.allocateUninitializedArray(size);
}

static byte getByte(long address) {
return MEMORY_ACCESSOR.getByte(address);
}
Expand Down Expand Up @@ -315,6 +328,60 @@ public sun.misc.Unsafe run() throws Exception {
return unsafe;
}

static Object getInternalUnsafe() {
Object internalUnsafe = null;
try {
internalUnsafe =
AccessController.doPrivileged(
new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
Class<?> k =
getClassLoader(UnsafeUtil.class).loadClass("jdk.internal.misc.Unsafe");
Method m = k.getDeclaredMethod("getUnsafe");
return m.invoke(null);
}
});
} catch (Throwable e) {
// Catching Throwable for Java 8.
}
return internalUnsafe;
}

static Method getAllocateArrayMethod() {
if (INTERNAL_UNSAFE == null) {
return null;
}
Method allocateArrayMethod = null;
try {
allocateArrayMethod =
AccessController.doPrivileged(
new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws Exception {
return INTERNAL_UNSAFE.getClass().getDeclaredMethod(
"allocateUninitializedArray", Class.class, int.class);
}
});
} catch (Throwable e) {
// Catching Throwable for Java 8.
}
return allocateArrayMethod;
}

private static ClassLoader getClassLoader(final Class<?> clazz) {
if (System.getSecurityManager() == null) {
return clazz.getClassLoader();
} else {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
}
});
}
}

/** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */
private static MemoryAccessor getMemoryAccessor() {
if (UNSAFE == null) {
Expand All @@ -330,7 +397,7 @@ private static MemoryAccessor getMemoryAccessor() {
}
}

return new JvmMemoryAccessor(UNSAFE);
return new JvmMemoryAccessor(UNSAFE, INTERNAL_UNSAFE, ALLOCATE_ARRAY_METHOD);
}

/** Indicates whether or not unsafe array operations are supported on this platform. */
Expand Down Expand Up @@ -611,12 +678,19 @@ public final int arrayIndexScale(Class<?> clazz) {
public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);

public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);

public abstract byte[] allocateUninitializedArray(int size);
}

private static final class JvmMemoryAccessor extends MemoryAccessor {

JvmMemoryAccessor(sun.misc.Unsafe unsafe) {
Object internalUnsafe;
Method allocateArrayMethod;

JvmMemoryAccessor(sun.misc.Unsafe unsafe, Object internalUnsafe, Method allocateArrayMethod) {
super(unsafe);
this.internalUnsafe = internalUnsafe;
this.allocateArrayMethod = allocateArrayMethod;
}

@Override
Expand Down Expand Up @@ -699,6 +773,17 @@ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length
unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
}

@Override
public byte[] allocateUninitializedArray(int size) {
try {
return (byte[]) allocateArrayMethod.invoke(internalUnsafe, byte.class, size);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}

@Override
public Object getStaticObject(Field field) {
return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
Expand Down Expand Up @@ -807,6 +892,11 @@ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length
throw new UnsupportedOperationException();
}

@Override
public byte[] allocateUninitializedArray(int size) {
throw new UnsupportedOperationException();
}

@Override
public Object getStaticObject(Field field) {
try {
Expand Down Expand Up @@ -927,6 +1017,11 @@ public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length
throw new UnsupportedOperationException();
}

@Override
public byte[] allocateUninitializedArray(int size) {
throw new UnsupportedOperationException();
}

@Override
public Object getStaticObject(Field field) {
try {
Expand Down