Skip to content

Commit 119be9d

Browse files
committed
Merge pull request msgpack#198 from xerial/v07-no-unsafe
Google App Engine Support
2 parents 3c15d21 + 5fd6964 commit 119be9d

2 files changed

Lines changed: 231 additions & 204 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package org.msgpack.core.buffer;
2+
3+
import java.lang.reflect.Constructor;
4+
import java.lang.reflect.InvocationTargetException;
5+
import java.lang.reflect.Method;
6+
import java.nio.ByteBuffer;
7+
8+
/**
9+
* Wraps the difference of access methods to DirectBuffers between Android and others.
10+
*/
11+
class DirectBufferAccess {
12+
13+
enum DirectBufferConstructorType {
14+
ARGS_LONG_INT_REF,
15+
ARGS_LONG_INT,
16+
ARGS_INT_INT,
17+
ARGS_MB_INT_INT
18+
}
19+
20+
21+
static Method mGetAddress;
22+
static Method mCleaner;
23+
static Method mClean;
24+
25+
// TODO We should use MethodHandle for efficiency, but it is not available in JDK6
26+
static Constructor byteBufferConstructor;
27+
static Class<?> directByteBufferClass;
28+
static DirectBufferConstructorType directBufferConstructorType;
29+
static Method memoryBlockWrapFromJni;
30+
31+
static {
32+
try {
33+
// Find the hidden constructor for DirectByteBuffer
34+
directByteBufferClass = ClassLoader.getSystemClassLoader().loadClass("java.nio.DirectByteBuffer");
35+
Constructor directByteBufferConstructor = null;
36+
DirectBufferConstructorType constructorType = null;
37+
Method mbWrap = null;
38+
try {
39+
// TODO We should use MethodHandle for Java7, which can avoid the cost of boxing with JIT optimization
40+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class, Object.class);
41+
constructorType = DirectBufferConstructorType.ARGS_LONG_INT_REF;
42+
}
43+
catch(NoSuchMethodException e0) {
44+
try {
45+
// https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/nio/DirectByteBuffer.java
46+
// DirectByteBuffer(long address, int capacity)
47+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(long.class, int.class);
48+
constructorType = DirectBufferConstructorType.ARGS_LONG_INT;
49+
}
50+
catch(NoSuchMethodException e1) {
51+
try {
52+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(int.class, int.class);
53+
constructorType = DirectBufferConstructorType.ARGS_INT_INT;
54+
}
55+
catch(NoSuchMethodException e2) {
56+
Class<?> aClass = Class.forName("java.nio.MemoryBlock");
57+
mbWrap = aClass.getDeclaredMethod("wrapFromJni", int.class, long.class);
58+
mbWrap.setAccessible(true);
59+
directByteBufferConstructor = directByteBufferClass.getDeclaredConstructor(aClass, int.class, int.class);
60+
constructorType = DirectBufferConstructorType.ARGS_MB_INT_INT;
61+
}
62+
}
63+
}
64+
65+
byteBufferConstructor = directByteBufferConstructor;
66+
directBufferConstructorType = constructorType;
67+
memoryBlockWrapFromJni = mbWrap;
68+
69+
if(byteBufferConstructor == null)
70+
throw new RuntimeException("Constructor of DirectByteBuffer is not found");
71+
byteBufferConstructor.setAccessible(true);
72+
73+
mGetAddress = directByteBufferClass.getDeclaredMethod("address");
74+
mGetAddress.setAccessible(true);
75+
76+
mCleaner = directByteBufferClass.getDeclaredMethod("cleaner");
77+
mCleaner.setAccessible(true);
78+
79+
mClean = mCleaner.getReturnType().getDeclaredMethod("clean");
80+
mClean.setAccessible(true);
81+
}
82+
catch(Exception e) {
83+
throw new RuntimeException(e);
84+
}
85+
}
86+
87+
static long getAddress(Object base) {
88+
try {
89+
return (Long) mGetAddress.invoke(base);
90+
}
91+
catch(IllegalAccessException e) {
92+
throw new RuntimeException(e);
93+
}
94+
catch(InvocationTargetException e) {
95+
throw new RuntimeException(e);
96+
}
97+
}
98+
99+
static void clean(Object base) {
100+
try {
101+
Object cleaner = mCleaner.invoke(base);
102+
mClean.invoke(cleaner);
103+
}
104+
catch(Throwable e) {
105+
throw new RuntimeException(e);
106+
}
107+
}
108+
109+
static boolean isDirectByteBufferInstance(Object s) {
110+
return directByteBufferClass.isInstance(s);
111+
}
112+
113+
static ByteBuffer newByteBuffer(long address, int index, int length, ByteBuffer reference) {
114+
try {
115+
switch(directBufferConstructorType) {
116+
case ARGS_LONG_INT_REF:
117+
return (ByteBuffer) byteBufferConstructor.newInstance(address + index, length, reference);
118+
case ARGS_LONG_INT:
119+
return (ByteBuffer) byteBufferConstructor.newInstance(address + index, length);
120+
case ARGS_INT_INT:
121+
return (ByteBuffer) byteBufferConstructor.newInstance((int) address + index, length);
122+
case ARGS_MB_INT_INT:
123+
return (ByteBuffer) byteBufferConstructor.newInstance(
124+
memoryBlockWrapFromJni.invoke(null, address + index, length),
125+
length, 0);
126+
default:
127+
throw new IllegalStateException("Unexpected value");
128+
}
129+
}
130+
catch(Throwable e) {
131+
// Convert checked exception to unchecked exception
132+
throw new RuntimeException(e);
133+
}
134+
}
135+
}

0 commit comments

Comments
 (0)