1 /*
2 * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "JNIUtility.h"
28
29 #if ENABLE(JAVA_BRIDGE)
30
31 #include <dlfcn.h>
32
33 namespace JSC {
34
35 namespace Bindings {
36
KJSGetCreatedJavaVMs(JavaVM ** vmBuf,jsize bufLen,jsize * nVMs)37 static jint KJSGetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
38 {
39 static void* javaVMFramework = 0;
40 if (!javaVMFramework)
41 javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
42 if (!javaVMFramework)
43 return JNI_ERR;
44
45 typedef jint(*FunctionPointerType)(JavaVM**, jsize, jsize*);
46 static FunctionPointerType functionPointer = 0;
47 if (!functionPointer)
48 functionPointer = reinterpret_cast<FunctionPointerType>(dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs"));
49 if (!functionPointer)
50 return JNI_ERR;
51 return functionPointer(vmBuf, bufLen, nVMs);
52 }
53
54 static JavaVM* jvm = 0;
55
56 // Provide the ability for an outside component to specify the JavaVM to use
57 // If the jvm value is set, the getJavaVM function below will just return.
58 // In getJNIEnv(), if AttachCurrentThread is called to a VM that is already
59 // attached, the result is a no-op.
setJavaVM(JavaVM * javaVM)60 void setJavaVM(JavaVM* javaVM)
61 {
62 jvm = javaVM;
63 }
64
getJavaVM()65 JavaVM* getJavaVM()
66 {
67 if (jvm)
68 return jvm;
69
70 JavaVM* jvmArray[1];
71 jsize bufLen = 1;
72 jsize nJVMs = 0;
73 jint jniError = 0;
74
75 // Assumes JVM is already running ..., one per process
76 jniError = KJSGetCreatedJavaVMs(jvmArray, bufLen, &nJVMs);
77 if (jniError == JNI_OK && nJVMs > 0)
78 jvm = jvmArray[0];
79 else
80 LOG_ERROR("JNI_GetCreatedJavaVMs failed, returned %ld", static_cast<long>(jniError));
81
82 return jvm;
83 }
84
getJNIEnv()85 JNIEnv* getJNIEnv()
86 {
87 union {
88 JNIEnv* env;
89 void* dummy;
90 } u;
91 jint jniError = 0;
92
93 #if OS(ANDROID)
94 jniError = getJavaVM()->AttachCurrentThread(&u.env, 0);
95 #else
96 jniError = getJavaVM()->AttachCurrentThread(&u.dummy, 0);
97 #endif
98 if (jniError == JNI_OK)
99 return u.env;
100 LOG_ERROR("AttachCurrentThread failed, returned %ld", static_cast<long>(jniError));
101 return 0;
102 }
103
getMethodID(jobject obj,const char * name,const char * sig)104 jmethodID getMethodID(jobject obj, const char* name, const char* sig)
105 {
106 JNIEnv* env = getJNIEnv();
107 jmethodID mid = 0;
108
109 if (env) {
110 jclass cls = env->GetObjectClass(obj);
111 if (cls) {
112 mid = env->GetMethodID(cls, name, sig);
113 if (!mid) {
114 env->ExceptionClear();
115 mid = env->GetStaticMethodID(cls, name, sig);
116 if (!mid)
117 env->ExceptionClear();
118 }
119 }
120 env->DeleteLocalRef(cls);
121 }
122 return mid;
123 }
124
getCharactersFromJString(jstring aJString)125 const char* getCharactersFromJString(jstring aJString)
126 {
127 return getCharactersFromJStringInEnv(getJNIEnv(), aJString);
128 }
129
releaseCharactersForJString(jstring aJString,const char * s)130 void releaseCharactersForJString(jstring aJString, const char* s)
131 {
132 releaseCharactersForJStringInEnv(getJNIEnv(), aJString, s);
133 }
134
getCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)135 const char* getCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
136 {
137 jboolean isCopy;
138 const char* s = env->GetStringUTFChars(aJString, &isCopy);
139 if (!s) {
140 env->ExceptionDescribe();
141 env->ExceptionClear();
142 fprintf(stderr, "\n");
143 }
144 return s;
145 }
146
releaseCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const char * s)147 void releaseCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const char* s)
148 {
149 env->ReleaseStringUTFChars(aJString, s);
150 }
151
getUCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)152 const jchar* getUCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
153 {
154 jboolean isCopy;
155 const jchar* s = env->GetStringChars(aJString, &isCopy);
156 if (!s) {
157 env->ExceptionDescribe();
158 env->ExceptionClear();
159 fprintf(stderr, "\n");
160 }
161 return s;
162 }
163
releaseUCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const jchar * s)164 void releaseUCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const jchar* s)
165 {
166 env->ReleaseStringChars(aJString, s);
167 }
168
javaTypeFromClassName(const char * name)169 JavaType javaTypeFromClassName(const char* name)
170 {
171 JavaType type;
172
173 if (!strcmp("byte", name))
174 type = JavaTypeByte;
175 else if (!strcmp("short", name))
176 type = JavaTypeShort;
177 else if (!strcmp("int", name))
178 type = JavaTypeInt;
179 else if (!strcmp("long", name))
180 type = JavaTypeLong;
181 else if (!strcmp("float", name))
182 type = JavaTypeFloat;
183 else if (!strcmp("double", name))
184 type = JavaTypeDouble;
185 else if (!strcmp("char", name))
186 type = JavaTypeChar;
187 else if (!strcmp("boolean", name))
188 type = JavaTypeBoolean;
189 else if (!strcmp("void", name))
190 type = JavaTypeVoid;
191 else if ('[' == name[0])
192 type = JavaTypeArray;
193 #if USE(V8)
194 else if (!strcmp("java.lang.String", name))
195 type = JavaTypeString;
196 #endif
197 else
198 type = JavaTypeObject;
199
200 return type;
201 }
202
signatureFromJavaType(JavaType type)203 const char* signatureFromJavaType(JavaType type)
204 {
205 switch (type) {
206 case JavaTypeVoid:
207 return "V";
208
209 case JavaTypeArray:
210 return "[";
211
212 case JavaTypeObject:
213 #if USE(V8)
214 case JavaTypeString:
215 #endif
216 return "L";
217
218 case JavaTypeBoolean:
219 return "Z";
220
221 case JavaTypeByte:
222 return "B";
223
224 case JavaTypeChar:
225 return "C";
226
227 case JavaTypeShort:
228 return "S";
229
230 case JavaTypeInt:
231 return "I";
232
233 case JavaTypeLong:
234 return "J";
235
236 case JavaTypeFloat:
237 return "F";
238
239 case JavaTypeDouble:
240 return "D";
241
242 case JavaTypeInvalid:
243 default:
244 break;
245 }
246 return "";
247 }
248
javaTypeFromPrimitiveType(char type)249 JavaType javaTypeFromPrimitiveType(char type)
250 {
251 switch (type) {
252 case 'V':
253 return JavaTypeVoid;
254
255 case 'L':
256 return JavaTypeObject;
257
258 case '[':
259 return JavaTypeArray;
260
261 case 'Z':
262 return JavaTypeBoolean;
263
264 case 'B':
265 return JavaTypeByte;
266
267 case 'C':
268 return JavaTypeChar;
269
270 case 'S':
271 return JavaTypeShort;
272
273 case 'I':
274 return JavaTypeInt;
275
276 case 'J':
277 return JavaTypeLong;
278
279 case 'F':
280 return JavaTypeFloat;
281
282 case 'D':
283 return JavaTypeDouble;
284
285 default:
286 break;
287 }
288 return JavaTypeInvalid;
289 }
290
getJNIField(jobject obj,JavaType type,const char * name,const char * signature)291 jvalue getJNIField(jobject obj, JavaType type, const char* name, const char* signature)
292 {
293 JavaVM* jvm = getJavaVM();
294 JNIEnv* env = getJNIEnv();
295 jvalue result;
296
297 memset(&result, 0, sizeof(jvalue));
298 if (obj && jvm && env) {
299 jclass cls = env->GetObjectClass(obj);
300 if (cls) {
301 jfieldID field = env->GetFieldID(cls, name, signature);
302 if (field) {
303 switch (type) {
304 case JavaTypeArray:
305 case JavaTypeObject:
306 #if USE(V8)
307 case JavaTypeString:
308 #endif
309 result.l = env->functions->GetObjectField(env, obj, field);
310 break;
311 case JavaTypeBoolean:
312 result.z = env->functions->GetBooleanField(env, obj, field);
313 break;
314 case JavaTypeByte:
315 result.b = env->functions->GetByteField(env, obj, field);
316 break;
317 case JavaTypeChar:
318 result.c = env->functions->GetCharField(env, obj, field);
319 break;
320 case JavaTypeShort:
321 result.s = env->functions->GetShortField(env, obj, field);
322 break;
323 case JavaTypeInt:
324 result.i = env->functions->GetIntField(env, obj, field);
325 break;
326 case JavaTypeLong:
327 result.j = env->functions->GetLongField(env, obj, field);
328 break;
329 case JavaTypeFloat:
330 result.f = env->functions->GetFloatField(env, obj, field);
331 break;
332 case JavaTypeDouble:
333 result.d = env->functions->GetDoubleField(env, obj, field);
334 break;
335 default:
336 LOG_ERROR("Invalid field type (%d)", static_cast<int>(type));
337 }
338 } else {
339 LOG_ERROR("Could not find field: %s", name);
340 env->ExceptionDescribe();
341 env->ExceptionClear();
342 fprintf(stderr, "\n");
343 }
344
345 env->DeleteLocalRef(cls);
346 } else
347 LOG_ERROR("Could not find class for object");
348 }
349
350 return result;
351 }
352
callJNIMethod(jobject object,JavaType returnType,const char * name,const char * signature,jvalue * args)353 jvalue callJNIMethod(jobject object, JavaType returnType, const char* name, const char* signature, jvalue* args)
354 {
355 jmethodID methodId = getMethodID(object, name, signature);
356 jvalue result;
357 switch (returnType) {
358 case JavaTypeVoid:
359 callJNIMethodIDA<void>(object, methodId, args);
360 break;
361 case JavaTypeObject:
362 #if USE(V8)
363 case JavaTypeString:
364 #endif
365 result.l = callJNIMethodIDA<jobject>(object, methodId, args);
366 break;
367 case JavaTypeBoolean:
368 result.z = callJNIMethodIDA<jboolean>(object, methodId, args);
369 break;
370 case JavaTypeByte:
371 result.b = callJNIMethodIDA<jbyte>(object, methodId, args);
372 break;
373 case JavaTypeChar:
374 result.c = callJNIMethodIDA<jchar>(object, methodId, args);
375 break;
376 case JavaTypeShort:
377 result.s = callJNIMethodIDA<jshort>(object, methodId, args);
378 break;
379 case JavaTypeInt:
380 result.i = callJNIMethodIDA<jint>(object, methodId, args);
381 break;
382 case JavaTypeLong:
383 result.j = callJNIMethodIDA<jlong>(object, methodId, args);
384 break;
385 case JavaTypeFloat:
386 result.f = callJNIMethodIDA<jfloat>(object, methodId, args);
387 break;
388 case JavaTypeDouble:
389 result.d = callJNIMethodIDA<jdouble>(object, methodId, args);
390 break;
391 default:
392 break;
393 }
394 return result;
395 }
396
397 } // namespace Bindings
398
399 } // namespace JSC
400
401 #endif // ENABLE(JAVA_BRIDGE)
402