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