• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2003 Apple Computer, 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 "jni_utility.h"
28 
29 #if ENABLE(MAC_JAVA_BRIDGE)
30 
31 #include "jni_runtime.h"
32 #include "runtime_array.h"
33 #include "runtime_object.h"
34 #include <runtime/JSArray.h>
35 #include <runtime/JSLock.h>
36 #include <dlfcn.h>
37 
38 namespace JSC {
39 
40 namespace Bindings {
41 
KJS_GetCreatedJavaVMs(JavaVM ** vmBuf,jsize bufLen,jsize * nVMs)42 static jint KJS_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
43 {
44     static void* javaVMFramework = 0;
45     if (!javaVMFramework)
46         javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
47     if (!javaVMFramework)
48         return JNI_ERR;
49 
50     static jint(*functionPointer)(JavaVM**, jsize, jsize *) = 0;
51     if (!functionPointer)
52         functionPointer = (jint(*)(JavaVM**, jsize, jsize *))dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs");
53     if (!functionPointer)
54         return JNI_ERR;
55     return functionPointer(vmBuf, bufLen, nVMs);
56 }
57 
58 static JavaVM *jvm = 0;
59 
60 // Provide the ability for an outside component to specify the JavaVM to use
61 // If the jvm value is set, the getJavaVM function below will just return.
62 // In getJNIEnv(), if AttachCurrentThread is called to a VM that is already
63 // attached, the result is a no-op.
setJavaVM(JavaVM * javaVM)64 void setJavaVM(JavaVM *javaVM)
65 {
66     jvm = javaVM;
67 }
68 
getJavaVM()69 JavaVM *getJavaVM()
70 {
71     if (jvm)
72         return jvm;
73 
74     JavaVM *jvmArray[1];
75     jsize bufLen = 1;
76     jsize nJVMs = 0;
77     jint jniError = 0;
78 
79     // Assumes JVM is already running ..., one per process
80     jniError = KJS_GetCreatedJavaVMs(jvmArray, bufLen, &nJVMs);
81     if ( jniError == JNI_OK && nJVMs > 0 ) {
82         jvm = jvmArray[0];
83     }
84     else
85         fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError);
86 
87     return jvm;
88 }
89 
getJNIEnv()90 JNIEnv* getJNIEnv()
91 {
92     union {
93         JNIEnv* env;
94         void* dummy;
95     } u;
96     jint jniError = 0;
97 
98     jniError = (getJavaVM())->AttachCurrentThread(&u.dummy, NULL);
99     if (jniError == JNI_OK)
100         return u.env;
101     else
102         fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError);
103     return NULL;
104 }
105 
getMethodID(jobject obj,const char * name,const char * sig)106 jmethodID getMethodID (jobject obj, const char *name, const char *sig)
107 {
108     JNIEnv *env = getJNIEnv();
109     jmethodID mid = 0;
110 
111     if ( env != NULL) {
112     jclass cls = env->GetObjectClass(obj);
113     if ( cls != NULL ) {
114             mid = env->GetMethodID(cls, name, sig);
115             if (!mid) {
116                 env->ExceptionClear();
117                 mid = env->GetStaticMethodID(cls, name, sig);
118                 if (!mid) {
119                     env->ExceptionClear();
120                 }
121             }
122         }
123         env->DeleteLocalRef(cls);
124     }
125     return mid;
126 }
127 
getCharactersFromJString(jstring aJString)128 const char *getCharactersFromJString (jstring aJString)
129 {
130     return getCharactersFromJStringInEnv (getJNIEnv(), aJString);
131 }
132 
releaseCharactersForJString(jstring aJString,const char * s)133 void releaseCharactersForJString (jstring aJString, const char *s)
134 {
135     releaseCharactersForJStringInEnv (getJNIEnv(), aJString, s);
136 }
137 
getCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)138 const char *getCharactersFromJStringInEnv (JNIEnv *env, jstring aJString)
139 {
140     jboolean isCopy;
141     const char *s = env->GetStringUTFChars((jstring)aJString, &isCopy);
142     if (!s) {
143         env->ExceptionDescribe();
144         env->ExceptionClear();
145                 fprintf (stderr, "\n");
146     }
147     return s;
148 }
149 
releaseCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const char * s)150 void releaseCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const char *s)
151 {
152     env->ReleaseStringUTFChars (aJString, s);
153 }
154 
getUCharactersFromJStringInEnv(JNIEnv * env,jstring aJString)155 const jchar *getUCharactersFromJStringInEnv (JNIEnv *env, jstring aJString)
156 {
157     jboolean isCopy;
158     const jchar *s = env->GetStringChars((jstring)aJString, &isCopy);
159     if (!s) {
160         env->ExceptionDescribe();
161         env->ExceptionClear();
162                 fprintf (stderr, "\n");
163     }
164     return s;
165 }
166 
releaseUCharactersForJStringInEnv(JNIEnv * env,jstring aJString,const jchar * s)167 void releaseUCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const jchar *s)
168 {
169     env->ReleaseStringChars (aJString, s);
170 }
171 
JNITypeFromClassName(const char * name)172 JNIType JNITypeFromClassName(const char *name)
173 {
174     JNIType type;
175 
176     if (strcmp("byte",name) == 0)
177         type = byte_type;
178     else if (strcmp("short",name) == 0)
179         type = short_type;
180     else if (strcmp("int",name) == 0)
181         type = int_type;
182     else if (strcmp("long",name) == 0)
183         type = long_type;
184     else if (strcmp("float",name) == 0)
185         type = float_type;
186     else if (strcmp("double",name) == 0)
187         type = double_type;
188     else if (strcmp("char",name) == 0)
189         type = char_type;
190     else if (strcmp("boolean",name) == 0)
191         type = boolean_type;
192     else if (strcmp("void",name) == 0)
193         type = void_type;
194     else if ('[' == name[0])
195         type = array_type;
196     else
197         type = object_type;
198 
199     return type;
200 }
201 
signatureFromPrimitiveType(JNIType type)202 const char *signatureFromPrimitiveType(JNIType type)
203 {
204     switch (type){
205         case void_type:
206             return "V";
207 
208         case array_type:
209             return "[";
210 
211         case object_type:
212             return "L";
213 
214         case boolean_type:
215             return "Z";
216 
217         case byte_type:
218             return "B";
219 
220         case char_type:
221             return "C";
222 
223         case short_type:
224             return "S";
225 
226         case int_type:
227             return "I";
228 
229         case long_type:
230             return "J";
231 
232         case float_type:
233             return "F";
234 
235         case double_type:
236             return "D";
237 
238         case invalid_type:
239         default:
240         break;
241     }
242     return "";
243 }
244 
JNITypeFromPrimitiveType(char type)245 JNIType JNITypeFromPrimitiveType(char type)
246 {
247     switch (type){
248         case 'V':
249             return void_type;
250 
251         case 'L':
252             return object_type;
253 
254         case '[':
255             return array_type;
256 
257         case 'Z':
258             return boolean_type;
259 
260         case 'B':
261             return byte_type;
262 
263         case 'C':
264             return char_type;
265 
266         case 'S':
267             return short_type;
268 
269         case 'I':
270             return int_type;
271 
272         case 'J':
273             return long_type;
274 
275         case 'F':
276             return float_type;
277 
278         case 'D':
279             return double_type;
280 
281         default:
282         break;
283     }
284     return invalid_type;
285 }
286 
getJNIField(jobject obj,JNIType type,const char * name,const char * signature)287 jvalue getJNIField( jobject obj, JNIType type, const char *name, const char *signature)
288 {
289     JavaVM *jvm = getJavaVM();
290     JNIEnv *env = getJNIEnv();
291     jvalue result;
292 
293     bzero (&result, sizeof(jvalue));
294     if ( obj != NULL && jvm != NULL && env != NULL) {
295         jclass cls = env->GetObjectClass(obj);
296         if ( cls != NULL ) {
297             jfieldID field = env->GetFieldID(cls, name, signature);
298             if ( field != NULL ) {
299                 switch (type) {
300                 case array_type:
301                 case object_type:
302                     result.l = env->functions->GetObjectField(env, obj, field);
303                     break;
304                 case boolean_type:
305                     result.z = env->functions->GetBooleanField(env, obj, field);
306                     break;
307                 case byte_type:
308                     result.b = env->functions->GetByteField(env, obj, field);
309                     break;
310                 case char_type:
311                     result.c = env->functions->GetCharField(env, obj, field);
312                     break;
313                 case short_type:
314                     result.s = env->functions->GetShortField(env, obj, field);
315                     break;
316                 case int_type:
317                     result.i = env->functions->GetIntField(env, obj, field);
318                     break;
319                 case long_type:
320                     result.j = env->functions->GetLongField(env, obj, field);
321                     break;
322                 case float_type:
323                     result.f = env->functions->GetFloatField(env, obj, field);
324                     break;
325                 case double_type:
326                     result.d = env->functions->GetDoubleField(env, obj, field);
327                     break;
328                 default:
329                     fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, (int)type);
330                 }
331             }
332             else
333             {
334                 fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name);
335                 env->ExceptionDescribe();
336                 env->ExceptionClear();
337                 fprintf (stderr, "\n");
338             }
339 
340             env->DeleteLocalRef(cls);
341         }
342         else {
343             fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__);
344         }
345     }
346 
347     return result;
348 }
349 
convertArrayInstanceToJavaArray(ExecState * exec,JSArray * jsArray,const char * javaClassName)350 static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
351 {
352     JNIEnv *env = getJNIEnv();
353     // As JS Arrays can contain a mixture of objects, assume we can convert to
354     // the requested Java Array type requested, unless the array type is some object array
355     // other than a string.
356     unsigned length = jsArray->length();
357     jobjectArray jarray = 0;
358 
359     // Build the correct array type
360     switch (JNITypeFromPrimitiveType(javaClassName[1])) {
361         case object_type: {
362         // Only support string object types
363         if (0 == strcmp("[Ljava.lang.String;", javaClassName)) {
364             jarray = (jobjectArray)env->NewObjectArray(length,
365                 env->FindClass("java/lang/String"),
366                 env->NewStringUTF(""));
367             for(unsigned i = 0; i < length; i++) {
368                 JSValuePtr item = jsArray->get(exec, i);
369                 UString stringValue = item.toString(exec);
370                 env->SetObjectArrayElement(jarray,i,
371                     env->functions->NewString(env, (const jchar *)stringValue.data(), stringValue.size()));
372                 }
373             }
374             break;
375         }
376 
377         case boolean_type: {
378             jarray = (jobjectArray)env->NewBooleanArray(length);
379             for(unsigned i = 0; i < length; i++) {
380                 JSValuePtr item = jsArray->get(exec, i);
381                 jboolean value = (jboolean)item.toNumber(exec);
382                 env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
383             }
384             break;
385         }
386 
387         case byte_type: {
388             jarray = (jobjectArray)env->NewByteArray(length);
389             for(unsigned i = 0; i < length; i++) {
390                 JSValuePtr item = jsArray->get(exec, i);
391                 jbyte value = (jbyte)item.toNumber(exec);
392                 env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
393             }
394             break;
395         }
396 
397         case char_type: {
398             jarray = (jobjectArray)env->NewCharArray(length);
399             for(unsigned i = 0; i < length; i++) {
400                 JSValuePtr item = jsArray->get(exec, i);
401                 UString stringValue = item.toString(exec);
402                 jchar value = 0;
403                 if (stringValue.size() > 0)
404                     value = ((const jchar*)stringValue.data())[0];
405                 env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
406             }
407             break;
408         }
409 
410         case short_type: {
411             jarray = (jobjectArray)env->NewShortArray(length);
412             for(unsigned i = 0; i < length; i++) {
413                 JSValuePtr item = jsArray->get(exec, i);
414                 jshort value = (jshort)item.toNumber(exec);
415                 env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
416             }
417             break;
418         }
419 
420         case int_type: {
421             jarray = (jobjectArray)env->NewIntArray(length);
422             for(unsigned i = 0; i < length; i++) {
423                 JSValuePtr item = jsArray->get(exec, i);
424                 jint value = (jint)item.toNumber(exec);
425                 env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
426             }
427             break;
428         }
429 
430         case long_type: {
431             jarray = (jobjectArray)env->NewLongArray(length);
432             for(unsigned i = 0; i < length; i++) {
433                 JSValuePtr item = jsArray->get(exec, i);
434                 jlong value = (jlong)item.toNumber(exec);
435                 env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
436             }
437             break;
438         }
439 
440         case float_type: {
441             jarray = (jobjectArray)env->NewFloatArray(length);
442             for(unsigned i = 0; i < length; i++) {
443                 JSValuePtr item = jsArray->get(exec, i);
444                 jfloat value = (jfloat)item.toNumber(exec);
445                 env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
446             }
447             break;
448         }
449 
450         case double_type: {
451             jarray = (jobjectArray)env->NewDoubleArray(length);
452             for(unsigned i = 0; i < length; i++) {
453                 JSValuePtr item = jsArray->get(exec, i);
454                 jdouble value = (jdouble)item.toNumber(exec);
455                 env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
456             }
457             break;
458         }
459 
460         case array_type: // don't handle embedded arrays
461         case void_type: // Don't expect arrays of void objects
462         case invalid_type: // Array of unknown objects
463             break;
464     }
465 
466     // if it was not one of the cases handled, then null is returned
467     return jarray;
468 }
469 
470 
convertValueToJValue(ExecState * exec,JSValuePtr value,JNIType _JNIType,const char * javaClassName)471 jvalue convertValueToJValue(ExecState* exec, JSValuePtr value, JNIType _JNIType, const char* javaClassName)
472 {
473     JSLock lock(false);
474 
475     jvalue result;
476 
477     switch (_JNIType){
478         case array_type:
479         case object_type: {
480             result.l = (jobject)0;
481 
482             // First see if we have a Java instance.
483             if (value.isObject()){
484                 JSObject* objectImp = asObject(value);
485                 if (objectImp->classInfo() == &RuntimeObjectImp::s_info) {
486                     RuntimeObjectImp* imp = static_cast<RuntimeObjectImp*>(objectImp);
487                     JavaInstance *instance = static_cast<JavaInstance*>(imp->getInternalInstance());
488                     if (instance)
489                         result.l = instance->javaInstance();
490                 }
491                 else if (objectImp->classInfo() == &RuntimeArray::s_info) {
492                 // Input is a JavaScript Array that was originally created from a Java Array
493                     RuntimeArray* imp = static_cast<RuntimeArray*>(objectImp);
494                     JavaArray *array = static_cast<JavaArray*>(imp->getConcreteArray());
495                     result.l = array->javaArray();
496                 }
497                 else if (objectImp->classInfo() == &JSArray::info) {
498                     // Input is a Javascript Array. We need to create it to a Java Array.
499                     result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
500                 }
501             }
502 
503             // Now convert value to a string if the target type is a java.lang.string, and we're not
504             // converting from a Null.
505             if (result.l == 0 && strcmp(javaClassName, "java.lang.String") == 0) {
506 #ifdef CONVERT_NULL_TO_EMPTY_STRING
507                 if (value->isNull()) {
508                     JNIEnv *env = getJNIEnv();
509                     jchar buf[2];
510                     jobject javaString = env->functions->NewString (env, buf, 0);
511                     result.l = javaString;
512                 }
513                 else
514 #else
515                 if (!value.isNull())
516 #endif
517                 {
518                     UString stringValue = value.toString(exec);
519                     JNIEnv *env = getJNIEnv();
520                     jobject javaString = env->functions->NewString (env, (const jchar *)stringValue.data(), stringValue.size());
521                     result.l = javaString;
522                 }
523             } else if (result.l == 0)
524                 bzero (&result, sizeof(jvalue)); // Handle it the same as a void case
525         }
526         break;
527 
528         case boolean_type: {
529             result.z = (jboolean)value.toNumber(exec);
530         }
531         break;
532 
533         case byte_type: {
534             result.b = (jbyte)value.toNumber(exec);
535         }
536         break;
537 
538         case char_type: {
539             result.c = (jchar)value.toNumber(exec);
540         }
541         break;
542 
543         case short_type: {
544             result.s = (jshort)value.toNumber(exec);
545         }
546         break;
547 
548         case int_type: {
549             result.i = (jint)value.toNumber(exec);
550         }
551         break;
552 
553         case long_type: {
554             result.j = (jlong)value.toNumber(exec);
555         }
556         break;
557 
558         case float_type: {
559             result.f = (jfloat)value.toNumber(exec);
560         }
561         break;
562 
563         case double_type: {
564             result.d = (jdouble)value.toNumber(exec);
565         }
566         break;
567 
568         break;
569 
570         case invalid_type:
571         default:
572         case void_type: {
573             bzero (&result, sizeof(jvalue));
574         }
575         break;
576     }
577     return result;
578 }
579 
580 }  // end of namespace Bindings
581 
582 } // end of namespace JSC
583 
584 #endif // ENABLE(MAC_JAVA_BRIDGE)
585