Skip to content

Commit 693d38c

Browse files
committed
Refactoring MessageBuffer initializer
1 parent c73366f commit 693d38c

File tree

1 file changed

+62
-69
lines changed

1 file changed

+62
-69
lines changed

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

Lines changed: 62 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.lang.reflect.Method;
1010
import java.nio.BufferOverflowException;
1111
import java.nio.ByteBuffer;
12+
import java.nio.ByteOrder;
1213

1314
import 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

Comments
 (0)