1010import java .nio .BufferOverflowException ;
1111import java .nio .ByteBuffer ;
1212import java .nio .ByteOrder ;
13+ import java .security .AccessControlException ;
1314
1415import static org .msgpack .core .Preconditions .*;
1516
2324 */
2425public 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