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(MAC_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 fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, 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 jniError = getJavaVM()->AttachCurrentThread(&u.dummy, 0);
94 if (jniError == JNI_OK)
95 return u.env;
96 fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, static_cast<long>(jniError));
97 return 0;
98 }
99
getMethodID(jobject obj,const char * name,const char * sig)100 jmethodID getMethodID(jobject obj, const char* name, const char* sig)
101 {
102 JNIEnv* env = getJNIEnv();
103 jmethodID mid = 0;
104
105 if (env) {
106 jclass cls = env->GetObjectClass(obj);
107 if (cls) {
108 mid = env->GetMethodID(cls, name, sig);
109 if (!mid) {
110 env->ExceptionClear();
111 mid = env->GetStaticMethodID(cls, name, sig);
112 if (!mid)
113 env->ExceptionClear();
114 }
115 }
116 env->DeleteLocalRef(cls);
117 }
118 return mid;
119 }
120
getCharactersFromJString(jstring aJString)121 const char* getCharactersFromJString(jstring aJString)
122 {
123 return getCharactersFromJStringInEnv(getJNIEnv(), aJString);
124 }
125
releaseCharactersForJString(jstring aJString,const char * s)126 void releaseCharactersForJString(jstring aJString, const char* s)
127 {
128 releaseCharactersForJStringInEnv(getJNIEnv(), aJString, s);
129 }
130
getCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)131 const char* getCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
132 {
133 jboolean isCopy;
134 const char* s = env->GetStringUTFChars(aJString, &isCopy);
135 if (!s) {
136 env->ExceptionDescribe();
137 env->ExceptionClear();
138 fprintf(stderr, "\n");
139 }
140 return s;
141 }
142
releaseCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const char * s)143 void releaseCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const char* s)
144 {
145 env->ReleaseStringUTFChars(aJString, s);
146 }
147
getUCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)148 const jchar* getUCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
149 {
150 jboolean isCopy;
151 const jchar* s = env->GetStringChars(aJString, &isCopy);
152 if (!s) {
153 env->ExceptionDescribe();
154 env->ExceptionClear();
155 fprintf(stderr, "\n");
156 }
157 return s;
158 }
159
releaseUCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const jchar * s)160 void releaseUCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const jchar* s)
161 {
162 env->ReleaseStringChars(aJString, s);
163 }
164
JNITypeFromClassName(const char * name)165 JNIType JNITypeFromClassName(const char* name)
166 {
167 JNIType type;
168
169 if (!strcmp("byte", name))
170 type = byte_type;
171 else if (!strcmp("short", name))
172 type = short_type;
173 else if (!strcmp("int", name))
174 type = int_type;
175 else if (!strcmp("long", name))
176 type = long_type;
177 else if (!strcmp("float", name))
178 type = float_type;
179 else if (!strcmp("double", name))
180 type = double_type;
181 else if (!strcmp("char", name))
182 type = char_type;
183 else if (!strcmp("boolean", name))
184 type = boolean_type;
185 else if (!strcmp("void", name))
186 type = void_type;
187 else if ('[' == name[0])
188 type = array_type;
189 else
190 type = object_type;
191
192 return type;
193 }
194
signatureFromPrimitiveType(JNIType type)195 const char* signatureFromPrimitiveType(JNIType type)
196 {
197 switch (type) {
198 case void_type:
199 return "V";
200
201 case array_type:
202 return "[";
203
204 case object_type:
205 return "L";
206
207 case boolean_type:
208 return "Z";
209
210 case byte_type:
211 return "B";
212
213 case char_type:
214 return "C";
215
216 case short_type:
217 return "S";
218
219 case int_type:
220 return "I";
221
222 case long_type:
223 return "J";
224
225 case float_type:
226 return "F";
227
228 case double_type:
229 return "D";
230
231 case invalid_type:
232 default:
233 break;
234 }
235 return "";
236 }
237
JNITypeFromPrimitiveType(char type)238 JNIType JNITypeFromPrimitiveType(char type)
239 {
240 switch (type) {
241 case 'V':
242 return void_type;
243
244 case 'L':
245 return object_type;
246
247 case '[':
248 return array_type;
249
250 case 'Z':
251 return boolean_type;
252
253 case 'B':
254 return byte_type;
255
256 case 'C':
257 return char_type;
258
259 case 'S':
260 return short_type;
261
262 case 'I':
263 return int_type;
264
265 case 'J':
266 return long_type;
267
268 case 'F':
269 return float_type;
270
271 case 'D':
272 return double_type;
273
274 default:
275 break;
276 }
277 return invalid_type;
278 }
279
getJNIField(jobject obj,JNIType type,const char * name,const char * signature)280 jvalue getJNIField(jobject obj, JNIType type, const char* name, const char* signature)
281 {
282 JavaVM* jvm = getJavaVM();
283 JNIEnv* env = getJNIEnv();
284 jvalue result;
285
286 memset(&result, 0, sizeof(jvalue));
287 if (obj && jvm && env) {
288 jclass cls = env->GetObjectClass(obj);
289 if (cls) {
290 jfieldID field = env->GetFieldID(cls, name, signature);
291 if (field) {
292 switch (type) {
293 case array_type:
294 case object_type:
295 result.l = env->functions->GetObjectField(env, obj, field);
296 break;
297 case boolean_type:
298 result.z = env->functions->GetBooleanField(env, obj, field);
299 break;
300 case byte_type:
301 result.b = env->functions->GetByteField(env, obj, field);
302 break;
303 case char_type:
304 result.c = env->functions->GetCharField(env, obj, field);
305 break;
306 case short_type:
307 result.s = env->functions->GetShortField(env, obj, field);
308 break;
309 case int_type:
310 result.i = env->functions->GetIntField(env, obj, field);
311 break;
312 case long_type:
313 result.j = env->functions->GetLongField(env, obj, field);
314 break;
315 case float_type:
316 result.f = env->functions->GetFloatField(env, obj, field);
317 break;
318 case double_type:
319 result.d = env->functions->GetDoubleField(env, obj, field);
320 break;
321 default:
322 fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, static_cast<int>(type));
323 }
324 } else {
325 fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name);
326 env->ExceptionDescribe();
327 env->ExceptionClear();
328 fprintf(stderr, "\n");
329 }
330
331 env->DeleteLocalRef(cls);
332 } else
333 fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__);
334 }
335
336 return result;
337 }
338
339 } // namespace Bindings
340
341 } // namespace JSC
342
343 #endif // ENABLE(MAC_JAVA_BRIDGE)
344