99import java .lang .reflect .Method ;
1010import java .nio .BufferOverflowException ;
1111import java .nio .ByteBuffer ;
12+ import java .nio .ByteOrder ;
1213
1314import static org .msgpack .core .Preconditions .*;
1415
@@ -45,10 +46,7 @@ enum DirectBufferConstructorType {
4546 String javaVersion = System .getProperty ("java.specification.version" , "" );
4647 int dotPos = javaVersion .indexOf ('.' );
4748 boolean isJavaAtLeast7 = false ;
48- if (dotPos == -1 ) {
49- isJavaAtLeast7 = false ;
50- }
51- else {
49+ if (dotPos != -1 ) {
5250 try {
5351 int major = Integer .parseInt (javaVersion .substring (0 , dotPos ));
5452 int minor = Integer .parseInt (javaVersion .substring (dotPos + 1 ));
@@ -59,33 +57,74 @@ enum DirectBufferConstructorType {
5957 }
6058 }
6159
60+ boolean hasUnsafe = false ;
61+ try {
62+ Class .forName ("sun.misc.Unsafe" );
63+ hasUnsafe = true ;
64+ }
65+ catch (ClassNotFoundException e ) {
66+ }
67+
6268 // Detect android VM
6369 boolean isAndroid = System .getProperty ("java.runtime.name" , "" ).toLowerCase ().contains ("android" );
64- // Fetch theUnsafe object for Orackle JDK and OpenJDK
65- Unsafe u ;
66- if (!isAndroid ) {
67- // Fetch theUnsafe object for Oracle JDK and OpenJDK
70+
71+ // For Java6, android and JVM that has no Unsafe class, use Universal MessageBuffer
72+ boolean useUniversalBuffer =
73+ Boolean .parseBoolean (System .getProperty ("msgpack.universal-buffer" , "false" ))
74+ || isAndroid
75+ || !isJavaAtLeast7
76+ || !hasUnsafe ;
77+
78+ // We need to use reflection to find MessageBuffer implementation classes because
79+ // importing these classes creates TypeProfile and adds some overhead to method calls.
80+ String bufferClsName ;
81+ if (useUniversalBuffer ) {
82+ bufferClsName = "org.msgpack.core.buffer.MessageBufferU" ;
83+ unsafe = null ;
84+ ARRAY_BYTE_BASE_OFFSET = 16 ; // dummy value
85+ ARRAY_BYTE_INDEX_SCALE = 1 ;
86+ }
87+ else {
88+ // Check the endian of this CPU
89+ boolean isLittleEndian = ByteOrder .nativeOrder () == ByteOrder .LITTLE_ENDIAN ;
90+ if (isLittleEndian ) {
91+ bufferClsName = "org.msgpack.core.buffer.MessageBuffer" ;
92+ }
93+ else {
94+ bufferClsName = "org.msgpack.core.buffer.MessageBufferBE" ;
95+ }
96+
97+ // Fetch theUnsafe object for Oracle and OpenJDK
98+ Unsafe u ;
6899 Field field = Unsafe .class .getDeclaredField ("theUnsafe" );
69100 field .setAccessible (true );
70101 unsafe = (Unsafe ) field .get (null );
102+ if (unsafe == null ) {
103+ throw new RuntimeException ("Unsafe is unavailable" );
104+ }
105+ ARRAY_BYTE_BASE_OFFSET = unsafe .arrayBaseOffset (byte [].class );
106+ ARRAY_BYTE_INDEX_SCALE = unsafe .arrayIndexScale (byte [].class );
107+
108+ // Make sure the VM thinks bytes are only one byte wide
109+ if (ARRAY_BYTE_INDEX_SCALE != 1 ) {
110+ throw new IllegalStateException ("Byte array index scale must be 1, but is " + ARRAY_BYTE_INDEX_SCALE );
111+ }
71112 }
72- else {
73- // Workaround for creating an Unsafe instance for Android OS
74- Constructor <Unsafe > unsafeConstructor = Unsafe .class .getDeclaredConstructor ();
75- unsafeConstructor .setAccessible (true );
76- unsafe = unsafeConstructor .newInstance ();
77- }
78- if (unsafe == null ) {
79- throw new RuntimeException ("Unsafe is unavailable" );
80- }
113+ Class <?> bufferCls = Class .forName (bufferClsName );
114+ msgBufferClass = bufferCls ;
81115
82- ARRAY_BYTE_BASE_OFFSET = unsafe .arrayBaseOffset (byte [].class );
83- ARRAY_BYTE_INDEX_SCALE = unsafe .arrayIndexScale (byte [].class );
116+ Constructor <?> mbArrCstr = bufferCls .getDeclaredConstructor (byte [].class );
117+ mbArrCstr .setAccessible (true );
118+ mbArrConstructor = mbArrCstr ;
84119
85- // Make sure the VM thinks bytes are only one byte wide
86- if (ARRAY_BYTE_INDEX_SCALE != 1 ) {
87- throw new IllegalStateException ("Byte array index scale must be 1, but is " + ARRAY_BYTE_INDEX_SCALE );
88- }
120+ Constructor <?> mbBBCstr = bufferCls .getDeclaredConstructor (ByteBuffer .class );
121+ mbBBCstr .setAccessible (true );
122+ mbBBConstructor = mbBBCstr ;
123+
124+ // Requires Java7
125+ //newMsgBuffer = MethodHandles.lookup().unreflectConstructor(mbArrCstr).asType(
126+ // MethodType.methodType(bufferCls, byte[].class)
127+ //);
89128
90129 // Find the hidden constructor for DirectByteBuffer
91130 directByteBufferClass = ClassLoader .getSystemClassLoader ().loadClass ("java.nio.DirectByteBuffer" );
@@ -123,52 +162,6 @@ enum DirectBufferConstructorType {
123162 throw new RuntimeException ("Constructor of DirectByteBuffer is not found" );
124163
125164 byteBufferConstructor .setAccessible (true );
126-
127- // Check the endian of this CPU
128- boolean isLittleEndian = true ;
129- byte [] a = new byte [8 ];
130- // use Unsafe.putLong to an array since Unsafe.getByte is not available in Android
131- unsafe .putLong (a , (long ) ARRAY_BYTE_BASE_OFFSET , 0x0102030405060708L );
132- switch (a [0 ]) {
133- case 0x01 :
134- isLittleEndian = false ;
135- break ;
136- case 0x08 :
137- isLittleEndian = true ;
138- break ;
139- default :
140- assert false ;
141- }
142-
143- // We need to use reflection to find MessageBuffer implementation classes because
144- // importing these classes creates TypeProfile and adds some overhead to method calls.
145- String bufferClsName ;
146- boolean useUniversalBuffer = Boolean .parseBoolean (System .getProperty ("msgpack.universal-buffer" , "false" ));
147- if (!useUniversalBuffer && !isAndroid && isJavaAtLeast7 ) {
148- if (isLittleEndian )
149- bufferClsName = "org.msgpack.core.buffer.MessageBuffer" ;
150- else
151- bufferClsName = "org.msgpack.core.buffer.MessageBufferBE" ;
152- }
153- else {
154- bufferClsName = "org.msgpack.core.buffer.MessageBufferU" ;
155- }
156-
157- Class <?> bufferCls = Class .forName (bufferClsName );
158- msgBufferClass = bufferCls ;
159-
160- Constructor <?> mbArrCstr = bufferCls .getDeclaredConstructor (byte [].class );
161- mbArrCstr .setAccessible (true );
162- mbArrConstructor = mbArrCstr ;
163-
164- Constructor <?> mbBBCstr = bufferCls .getDeclaredConstructor (ByteBuffer .class );
165- mbBBCstr .setAccessible (true );
166- mbBBConstructor = mbBBCstr ;
167-
168- // Requires Java7
169- //newMsgBuffer = MethodHandles.lookup().unreflectConstructor(mbArrCstr).asType(
170- // MethodType.methodType(bufferCls, byte[].class)
171- //);
172165 }
173166 catch (Exception e ) {
174167 e .printStackTrace (System .err );
0 commit comments