Skip to content

Commit 3ba731f

Browse files
committed
Encupslate DirectByteBuffer accessors
1 parent e2b4a71 commit 3ba731f

File tree

1 file changed

+97
-73
lines changed

1 file changed

+97
-73
lines changed

msgpack-core/src/main/java/org/msgpack/core/buffer/MessageBuffer.java

Lines changed: 97 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.nio.BufferOverflowException;
1111
import java.nio.ByteBuffer;
1212
import java.nio.ByteOrder;
13+
import java.security.AccessControlException;
1314

1415
import static org.msgpack.core.Preconditions.*;
1516

@@ -23,21 +24,18 @@
2324
*/
2425
public class MessageBuffer {
2526

27+
static final boolean isUniversalBuffer;
2628
static final Unsafe unsafe;
2729
// TODO We should use MethodHandle for efficiency, but it is not available in JDK6
28-
static final Constructor byteBufferConstructor;
29-
30-
static final Class<?> directByteBufferClass;
31-
static final DirectBufferConstructorType directBufferConstructorType;
32-
static final Method memoryBlockWrapFromJni;
3330
static final int ARRAY_BYTE_BASE_OFFSET;
3431
static final int ARRAY_BYTE_INDEX_SCALE;
3532

3633
enum DirectBufferConstructorType {
3734
ARGS_LONG_INT_REF,
3835
ARGS_LONG_INT,
3936
ARGS_INT_INT,
40-
ARGS_MB_INT_INT
37+
ARGS_MB_INT_INT,
38+
NONE
4139
}
4240

4341
static {
@@ -71,17 +69,17 @@ enum DirectBufferConstructorType {
7169
boolean isGAE = System.getProperty("com.google.appengine.runtime.version") != null;
7270

7371
// For Java6, android and JVM that has no Unsafe class, use Universal MessageBuffer
74-
boolean useUniversalBuffer =
72+
isUniversalBuffer =
7573
Boolean.parseBoolean(System.getProperty("msgpack.universal-buffer", "false"))
7674
|| isAndroid
7775
|| isGAE
7876
|| !isJavaAtLeast7
7977
|| !hasUnsafe;
8078

81-
// We need to use reflection to find MessageBuffer implementation classes abecause
79+
// We need to use reflection to find MessageBuffer implementation classes because
8280
// importing these classes creates TypeProfile and adds some overhead to method calls.
8381
String bufferClsName;
84-
if(useUniversalBuffer) {
82+
if(isUniversalBuffer) {
8583
bufferClsName = "org.msgpack.core.buffer.MessageBufferU";
8684
unsafe = null;
8785
ARRAY_BYTE_BASE_OFFSET = 16; // dummy value
@@ -129,42 +127,6 @@ enum DirectBufferConstructorType {
129127
// MethodType.methodType(bufferCls, byte[].class)
130128
//);
131129

132-
// Find the hidden constructor for DirectByteBuffer
133-
directByteBufferClass = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer");
134-
Constructor directByteBufferConstructor = null;
135-
DirectBufferConstructorType constructorType = null;
136-
Method mbWrap = null;
137-
try {
138-
// TODO We should use MethodHandle for Java7, which can avoid the cost of boxing with JIT optimization
139-
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class, Object.class);
140-
constructorType = DirectBufferConstructorType.ARGS_LONG_INT_REF;
141-
}
142-
catch(NoSuchMethodException e0) {
143-
try {
144-
// https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/DirectByteBuffer.java
145-
// DirectByteBuffer(long address, int capacity)
146-
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class);
147-
constructorType = DirectBufferConstructorType.ARGS_LONG_INT;
148-
} catch (NoSuchMethodException e1) {
149-
try {
150-
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(int.class, int.class);
151-
constructorType = DirectBufferConstructorType.ARGS_INT_INT;
152-
} catch (NoSuchMethodException e2) {
153-
Class<?> aClass = Class.forName("java.nio.MemoryBlock");
154-
mbWrap = aClass.getDeclaredMethod("wrapFromJni", int.class, long.class);
155-
mbWrap.setAccessible(true);
156-
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(aClass, int.class, int.class);
157-
constructorType = DirectBufferConstructorType.ARGS_MB_INT_INT;
158-
}
159-
}
160-
}
161-
byteBufferConstructor = directByteBufferConstructor;
162-
directBufferConstructorType = constructorType;
163-
memoryBlockWrapFromJni = mbWrap;
164-
if(byteBufferConstructor == null)
165-
throw new RuntimeException("Constructor of DirectByteBuffer is not found");
166-
167-
byteBufferConstructor.setAccessible(true);
168130
}
169131
catch(Exception e) {
170132
e.printStackTrace(System.err);
@@ -180,8 +142,61 @@ private static class DirectBufferAccess {
180142
static Method mCleaner;
181143
static Method mClean;
182144

145+
static Constructor byteBufferConstructor;
146+
147+
static Class<?> directByteBufferClass;
148+
static DirectBufferConstructorType directBufferConstructorType;
149+
static Method memoryBlockWrapFromJni;
150+
183151
static {
184152
try {
153+
if(!isUniversalBuffer) {
154+
try {
155+
// Find the hidden constructor for DirectByteBuffer
156+
directByteBufferClass = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer");
157+
Constructor directByteBufferConstructor = null;
158+
DirectBufferConstructorType constructorType = null;
159+
Method mbWrap = null;
160+
try {
161+
// TODO We should use MethodHandle for Java7, which can avoid the cost of boxing with JIT optimization
162+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class, Object.class);
163+
constructorType = DirectBufferConstructorType.ARGS_LONG_INT_REF;
164+
}
165+
catch(NoSuchMethodException e0) {
166+
try {
167+
// https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/DirectByteBuffer.java
168+
// DirectByteBuffer(long address, int capacity)
169+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class);
170+
constructorType = DirectBufferConstructorType.ARGS_LONG_INT;
171+
}
172+
catch(NoSuchMethodException e1) {
173+
try {
174+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(int.class, int.class);
175+
constructorType = DirectBufferConstructorType.ARGS_INT_INT;
176+
}
177+
catch(NoSuchMethodException e2) {
178+
Class<?> aClass = Class.forName("java.nio.MemoryBlock");
179+
mbWrap = aClass.getDeclaredMethod("wrapFromJni", int.class, long.class);
180+
mbWrap.setAccessible(true);
181+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(aClass, int.class, int.class);
182+
constructorType = DirectBufferConstructorType.ARGS_MB_INT_INT;
183+
}
184+
}
185+
}
186+
187+
byteBufferConstructor = directByteBufferConstructor;
188+
directBufferConstructorType = constructorType;
189+
memoryBlockWrapFromJni = mbWrap;
190+
191+
if(byteBufferConstructor == null)
192+
throw new RuntimeException("Constructor of DirectByteBuffer is not found");
193+
byteBufferConstructor.setAccessible(true);
194+
}
195+
catch(Exception e) {
196+
directBufferConstructorType = DirectBufferConstructorType.NONE;
197+
}
198+
}
199+
185200
mGetAddress = directByteBufferClass.getDeclaredMethod("address");
186201
mGetAddress.setAccessible(true);
187202

@@ -217,6 +232,33 @@ static void clean(Object base) {
217232
throw new RuntimeException(e);
218233
}
219234
}
235+
236+
static boolean isDirectByteBufferInstance(Object s) {
237+
return directByteBufferClass.isInstance(s);
238+
}
239+
240+
static ByteBuffer newByteBuffer(long address, int index, int length, ByteBuffer reference) {
241+
try {
242+
switch(directBufferConstructorType) {
243+
case ARGS_LONG_INT_REF:
244+
return (ByteBuffer) byteBufferConstructor.newInstance(address + index, length, reference);
245+
case ARGS_LONG_INT:
246+
return (ByteBuffer) byteBufferConstructor.newInstance(address + index, length);
247+
case ARGS_INT_INT:
248+
return (ByteBuffer) byteBufferConstructor.newInstance((int) address + index, length);
249+
case ARGS_MB_INT_INT:
250+
return (ByteBuffer) byteBufferConstructor.newInstance(
251+
memoryBlockWrapFromJni.invoke(null, address + index, length),
252+
length, 0);
253+
default:
254+
throw new IllegalStateException("Unexpected value");
255+
}
256+
}
257+
catch(Throwable e) {
258+
// Convert checked exception to unchecked exception
259+
throw new RuntimeException(e);
260+
}
261+
}
220262
}
221263

222264
/**
@@ -259,8 +301,13 @@ static void clean(Object base) {
259301

260302
static MessageBuffer newOffHeapBuffer(int length) {
261303
// This method is not available in Android OS
262-
long address = unsafe.allocateMemory(length);
263-
return new MessageBuffer(address, length);
304+
if(!isUniversalBuffer) {
305+
long address = unsafe.allocateMemory(length);
306+
return new MessageBuffer(address, length);
307+
}
308+
else {
309+
return newDirectBuffer(length);
310+
}
264311
}
265312

266313
public static MessageBuffer newDirectBuffer(int length) {
@@ -318,7 +365,7 @@ public static void releaseBuffer(MessageBuffer buffer) {
318365
if(buffer.base instanceof byte[]) {
319366
// We have nothing to do. Wait until the garbage-collector collects this array object
320367
}
321-
else if(directByteBufferClass.isInstance(buffer.base)) {
368+
else if(DirectBufferAccess.isDirectByteBufferInstance(buffer.base)) {
322369
DirectBufferAccess.clean(buffer.base);
323370
}
324371
else {
@@ -530,31 +577,8 @@ public ByteBuffer toByteBuffer(int index, int length) {
530577
if(hasArray()) {
531578
return ByteBuffer.wrap((byte[]) base, (int) ((address - ARRAY_BYTE_BASE_OFFSET) + index), length);
532579
}
533-
try {
534-
ByteBuffer bb = null;
535-
switch (directBufferConstructorType) {
536-
case ARGS_LONG_INT_REF:
537-
bb = (ByteBuffer) byteBufferConstructor.newInstance(address + index, length, reference);
538-
break;
539-
case ARGS_LONG_INT:
540-
bb = (ByteBuffer) byteBufferConstructor.newInstance(address + index, length);
541-
break;
542-
case ARGS_INT_INT:
543-
bb = (ByteBuffer) byteBufferConstructor.newInstance((int)address + index, length);
544-
break;
545-
case ARGS_MB_INT_INT:
546-
bb = (ByteBuffer) byteBufferConstructor.newInstance(
547-
memoryBlockWrapFromJni.invoke(null, address + index, length),
548-
length, 0);
549-
break;
550-
default:
551-
throw new IllegalStateException("Unexpected value");
552-
}
553-
return bb;
554-
}
555-
catch(Throwable e) {
556-
// Convert checked exception to unchecked exception
557-
throw new RuntimeException(e);
580+
else {
581+
return DirectBufferAccess.newByteBuffer(address, index, length, reference);
558582
}
559583
}
560584

0 commit comments

Comments
 (0)