• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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