55
66import java .lang .reflect .Constructor ;
77import java .lang .reflect .Field ;
8- import java .lang .reflect .InvocationTargetException ;
9- import java .lang .reflect .Method ;
108import java .nio .BufferOverflowException ;
119import java .nio .ByteBuffer ;
1210import java .nio .ByteOrder ;
13- import java .security .AccessControlException ;
1411
1512import static org .msgpack .core .Preconditions .*;
1613
@@ -26,18 +23,10 @@ public class MessageBuffer {
2623
2724 static final boolean isUniversalBuffer ;
2825 static final Unsafe unsafe ;
29- // TODO We should use MethodHandle for efficiency, but it is not available in JDK6
26+
3027 static final int ARRAY_BYTE_BASE_OFFSET ;
3128 static final int ARRAY_BYTE_INDEX_SCALE ;
3229
33- enum DirectBufferConstructorType {
34- ARGS_LONG_INT_REF ,
35- ARGS_LONG_INT ,
36- ARGS_INT_INT ,
37- ARGS_MB_INT_INT ,
38- NONE
39- }
40-
4130 static {
4231 try {
4332 // Check java version
@@ -134,133 +123,6 @@ enum DirectBufferConstructorType {
134123 }
135124 }
136125
137- /**
138- * Wraps the difference of access methods to DirectBuffers between Android and others.
139- */
140- private static class DirectBufferAccess {
141- static Method mGetAddress ;
142- static Method mCleaner ;
143- static Method mClean ;
144-
145- static Constructor byteBufferConstructor ;
146-
147- static Class <?> directByteBufferClass ;
148- static DirectBufferConstructorType directBufferConstructorType ;
149- static Method memoryBlockWrapFromJni ;
150-
151- static {
152- 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-
200- mGetAddress = directByteBufferClass .getDeclaredMethod ("address" );
201- mGetAddress .setAccessible (true );
202-
203- mCleaner = directByteBufferClass .getDeclaredMethod ("cleaner" );
204- mCleaner .setAccessible (true );
205-
206- mClean = mCleaner .getReturnType ().getDeclaredMethod ("clean" );
207- mClean .setAccessible (true );
208- }
209- catch (NoSuchMethodException e ) {
210- throw new RuntimeException (e );
211- }
212- }
213-
214- static long getAddress (Object base ) {
215- try {
216- return (Long ) mGetAddress .invoke (base );
217- }
218- catch (IllegalAccessException e ) {
219- throw new RuntimeException (e );
220- }
221- catch (InvocationTargetException e ) {
222- throw new RuntimeException (e );
223- }
224- }
225-
226- static void clean (Object base ) {
227- try {
228- Object cleaner = mCleaner .invoke (base );
229- mClean .invoke (cleaner );
230- }
231- catch (Throwable e ) {
232- throw new RuntimeException (e );
233- }
234- }
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- }
262- }
263-
264126 /**
265127 * MessageBuffer class to use. If this machine is big-endian, it uses MessageBufferBE, which overrides some methods in this class that translate endians. If not, uses MessageBuffer.
266128 */
@@ -295,10 +157,6 @@ static ByteBuffer newByteBuffer(long address, int index, int length, ByteBuffer
295157 */
296158 protected final ByteBuffer reference ;
297159
298- // TODO life-time management of this buffer
299- //private AtomicInteger referenceCounter;
300-
301-
302160 static MessageBuffer newOffHeapBuffer (int length ) {
303161 // This method is not available in Android OS
304162 if (!isUniversalBuffer ) {
@@ -362,7 +220,7 @@ private static MessageBuffer newMessageBuffer(byte[] arr) {
362220 }
363221
364222 public static void releaseBuffer (MessageBuffer buffer ) {
365- if (buffer .base instanceof byte []) {
223+ if (isUniversalBuffer || buffer .base instanceof byte []) {
366224 // We have nothing to do. Wait until the garbage-collector collects this array object
367225 }
368226 else if (DirectBufferAccess .isDirectByteBufferInstance (buffer .base )) {
@@ -394,6 +252,9 @@ else if(DirectBufferAccess.isDirectByteBufferInstance(buffer.base)) {
394252 */
395253 MessageBuffer (ByteBuffer bb ) {
396254 if (bb .isDirect ()) {
255+ if (isUniversalBuffer ) {
256+ throw new IllegalStateException ("Cannot create MessageBuffer from DirectBuffer" );
257+ }
397258 // Direct buffer or off-heap memory
398259 this .base = null ;
399260 this .address = DirectBufferAccess .getAddress (bb );
0 commit comments