• 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_runtime.h>
28 
29 #if ENABLE(MAC_JAVA_BRIDGE)
30 
31 #include <jni_utility.h>
32 
33 #include "runtime_array.h"
34 #include "runtime_object.h"
35 #include "runtime_root.h"
36 #include <runtime/Error.h>
37 #include <runtime/JSLock.h>
38 
39 #ifdef NDEBUG
40 #define JS_LOG(formatAndArgs...) ((void)0)
41 #else
42 #define JS_LOG(formatAndArgs...) { \
43     fprintf (stderr, "%s:%d -- %s:  ", __FILE__, __LINE__, __FUNCTION__); \
44     fprintf(stderr, formatAndArgs); \
45 }
46 #endif
47 
48 using namespace JSC;
49 using namespace JSC::Bindings;
50 
51 
JavaParameter(JNIEnv * env,jstring type)52 JavaParameter::JavaParameter (JNIEnv *env, jstring type)
53 {
54     _type = JavaString (env, type);
55     _JNIType = JNITypeFromClassName (_type.UTF8String());
56 }
57 
JavaField(JNIEnv * env,jobject aField)58 JavaField::JavaField (JNIEnv *env, jobject aField)
59 {
60     // Get field type
61     jobject fieldType = callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;");
62     jstring fieldTypeName = (jstring)callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;");
63     _type = JavaString(env, fieldTypeName);
64     _JNIType = JNITypeFromClassName (_type.UTF8String());
65 
66     // Get field name
67     jstring fieldName = (jstring)callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;");
68     _name = JavaString(env, fieldName);
69 
70     _field = new JObjectWrapper(aField);
71 }
72 
convertJObjectToArray(ExecState * exec,jobject anObject,const char * type,PassRefPtr<RootObject> rootObject)73 JSValue JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject> rootObject)
74 {
75     if (type[0] != '[')
76         return jsUndefined();
77 
78     return new (exec) RuntimeArray(exec, new JavaArray((jobject)anObject, type, rootObject));
79 }
80 
dispatchValueFromInstance(ExecState * exec,const JavaInstance * instance,const char * name,const char * sig,JNIType returnType) const81 jvalue JavaField::dispatchValueFromInstance(ExecState *exec, const JavaInstance *instance, const char *name, const char *sig, JNIType returnType) const
82 {
83     jobject jinstance = instance->javaInstance();
84     jobject fieldJInstance = _field->_instance;
85     JNIEnv *env = getJNIEnv();
86     jvalue result;
87 
88     bzero (&result, sizeof(jvalue));
89     jclass cls = env->GetObjectClass(fieldJInstance);
90     if ( cls != NULL ) {
91         jmethodID mid = env->GetMethodID(cls, name, sig);
92         if ( mid != NULL )
93         {
94             RootObject* rootObject = instance->rootObject();
95             if (rootObject && rootObject->nativeHandle()) {
96                 JSValue exceptionDescription;
97                 jvalue args[1];
98 
99                 args[0].l = jinstance;
100                 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, returnType, mid, args, result, 0, exceptionDescription);
101                 if (exceptionDescription)
102                     throwError(exec, GeneralError, exceptionDescription.toString(exec));
103             }
104         }
105     }
106     return result;
107 }
108 
valueFromInstance(ExecState * exec,const Instance * i) const109 JSValue JavaField::valueFromInstance(ExecState* exec, const Instance* i) const
110 {
111     const JavaInstance *instance = static_cast<const JavaInstance *>(i);
112 
113     JSValue jsresult = jsUndefined();
114 
115     switch (_JNIType) {
116         case array_type:
117         case object_type: {
118             jvalue result = dispatchValueFromInstance (exec, instance, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", object_type);
119             jobject anObject = result.l;
120 
121             const char *arrayType = type();
122             if (arrayType[0] == '[') {
123                 jsresult = JavaArray::convertJObjectToArray(exec, anObject, arrayType, instance->rootObject());
124             }
125             else if (anObject != 0){
126                 jsresult = JavaInstance::create(anObject, instance->rootObject())->createRuntimeObject(exec);
127             }
128         }
129         break;
130 
131         case boolean_type:
132             jsresult = jsBoolean(dispatchValueFromInstance(exec, instance, "getBoolean", "(Ljava/lang/Object;)Z", boolean_type).z);
133             break;
134 
135         case byte_type:
136         case char_type:
137         case short_type:
138 
139         case int_type: {
140             jint value;
141             jvalue result = dispatchValueFromInstance (exec, instance, "getInt", "(Ljava/lang/Object;)I", int_type);
142             value = result.i;
143             jsresult = jsNumber(exec, (int)value);
144         }
145         break;
146 
147         case long_type:
148         case float_type:
149         case double_type: {
150             jdouble value;
151             jvalue result = dispatchValueFromInstance (exec, instance, "getDouble", "(Ljava/lang/Object;)D", double_type);
152             value = result.i;
153             jsresult = jsNumber(exec, (double)value);
154         }
155         break;
156         default:
157         break;
158     }
159 
160     JS_LOG ("getting %s = %s\n", UString(name()).UTF8String().c_str(), jsresult.toString(exec).ascii());
161 
162     return jsresult;
163 }
164 
dispatchSetValueToInstance(ExecState * exec,const JavaInstance * instance,jvalue javaValue,const char * name,const char * sig) const165 void JavaField::dispatchSetValueToInstance(ExecState *exec, const JavaInstance *instance, jvalue javaValue, const char *name, const char *sig) const
166 {
167     jobject jinstance = instance->javaInstance();
168     jobject fieldJInstance = _field->_instance;
169     JNIEnv *env = getJNIEnv();
170 
171     jclass cls = env->GetObjectClass(fieldJInstance);
172     if ( cls != NULL ) {
173         jmethodID mid = env->GetMethodID(cls, name, sig);
174         if ( mid != NULL )
175         {
176             RootObject* rootObject = instance->rootObject();
177             if (rootObject && rootObject->nativeHandle()) {
178                 JSValue exceptionDescription;
179                 jvalue args[2];
180                 jvalue result;
181 
182                 args[0].l = jinstance;
183                 args[1] = javaValue;
184                 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, void_type, mid, args, result, 0, exceptionDescription);
185                 if (exceptionDescription)
186                     throwError(exec, GeneralError, exceptionDescription.toString(exec));
187             }
188         }
189     }
190 }
191 
setValueToInstance(ExecState * exec,const Instance * i,JSValue aValue) const192 void JavaField::setValueToInstance(ExecState* exec, const Instance* i, JSValue aValue) const
193 {
194     const JavaInstance *instance = static_cast<const JavaInstance *>(i);
195     jvalue javaValue = convertValueToJValue (exec, aValue, _JNIType, type());
196 
197     JS_LOG ("setting value %s to %s\n", UString(name()).UTF8String().c_str(), aValue.toString(exec).ascii());
198 
199     switch (_JNIType) {
200         case array_type:
201         case object_type: {
202             dispatchSetValueToInstance (exec, instance, javaValue, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
203         }
204         break;
205 
206         case boolean_type: {
207             dispatchSetValueToInstance (exec, instance, javaValue, "setBoolean", "(Ljava/lang/Object;Z)V");
208         }
209         break;
210 
211         case byte_type: {
212             dispatchSetValueToInstance (exec, instance, javaValue, "setByte", "(Ljava/lang/Object;B)V");
213         }
214         break;
215 
216         case char_type: {
217             dispatchSetValueToInstance (exec, instance, javaValue, "setChar", "(Ljava/lang/Object;C)V");
218         }
219         break;
220 
221         case short_type: {
222             dispatchSetValueToInstance (exec, instance, javaValue, "setShort", "(Ljava/lang/Object;S)V");
223         }
224         break;
225 
226         case int_type: {
227             dispatchSetValueToInstance (exec, instance, javaValue, "setInt", "(Ljava/lang/Object;I)V");
228         }
229         break;
230 
231         case long_type: {
232             dispatchSetValueToInstance (exec, instance, javaValue, "setLong", "(Ljava/lang/Object;J)V");
233         }
234         break;
235 
236         case float_type: {
237             dispatchSetValueToInstance (exec, instance, javaValue, "setFloat", "(Ljava/lang/Object;F)V");
238         }
239         break;
240 
241         case double_type: {
242             dispatchSetValueToInstance (exec, instance, javaValue, "setDouble", "(Ljava/lang/Object;D)V");
243         }
244         break;
245         default:
246         break;
247     }
248 }
249 
JavaMethod(JNIEnv * env,jobject aMethod)250 JavaMethod::JavaMethod (JNIEnv *env, jobject aMethod)
251 {
252     // Get return type
253     jobject returnType = callJNIMethod<jobject>(aMethod, "getReturnType", "()Ljava/lang/Class;");
254     jstring returnTypeName = (jstring)callJNIMethod<jobject>(returnType, "getName", "()Ljava/lang/String;");
255     _returnType =JavaString (env, returnTypeName);
256     _JNIReturnType = JNITypeFromClassName (_returnType.UTF8String());
257     env->DeleteLocalRef (returnType);
258     env->DeleteLocalRef (returnTypeName);
259 
260     // Get method name
261     jstring methodName = (jstring)callJNIMethod<jobject>(aMethod, "getName", "()Ljava/lang/String;");
262     _name = JavaString (env, methodName);
263     env->DeleteLocalRef (methodName);
264 
265     // Get parameters
266     jarray jparameters = (jarray)callJNIMethod<jobject>(aMethod, "getParameterTypes", "()[Ljava/lang/Class;");
267     _numParameters = env->GetArrayLength (jparameters);
268     _parameters = new JavaParameter[_numParameters];
269 
270     int i;
271     for (i = 0; i < _numParameters; i++) {
272         jobject aParameter = env->GetObjectArrayElement ((jobjectArray)jparameters, i);
273         jstring parameterName = (jstring)callJNIMethod<jobject>(aParameter, "getName", "()Ljava/lang/String;");
274         _parameters[i] = JavaParameter(env, parameterName);
275         env->DeleteLocalRef (aParameter);
276         env->DeleteLocalRef (parameterName);
277     }
278     env->DeleteLocalRef (jparameters);
279 
280     // Created lazily.
281     _signature = 0;
282     _methodID = 0;
283 
284     jclass modifierClass = env->FindClass("java/lang/reflect/Modifier");
285     int modifiers = callJNIMethod<jint>(aMethod, "getModifiers", "()I");
286     _isStatic = (bool)callJNIStaticMethod<jboolean>(modifierClass, "isStatic", "(I)Z", modifiers);
287 #ifdef ANDROID_FIX
288     env->DeleteLocalRef(modifierClass);
289 #endif
290 }
291 
~JavaMethod()292 JavaMethod::~JavaMethod()
293 {
294     if (_signature)
295         free(_signature);
296     delete [] _parameters;
297 };
298 
299 // JNI method signatures use '/' between components of a class name, but
300 // we get '.' between components from the reflection API.
appendClassName(UString & aString,const char * className)301 static void appendClassName(UString& aString, const char* className)
302 {
303     ASSERT(JSLock::lockCount() > 0);
304 
305     char *result, *cp = strdup(className);
306 
307     result = cp;
308     while (*cp) {
309         if (*cp == '.')
310             *cp = '/';
311         cp++;
312     }
313 
314     aString.append(result);
315 
316     free (result);
317 }
318 
signature() const319 const char *JavaMethod::signature() const
320 {
321     if (!_signature) {
322         JSLock lock(SilenceAssertionsOnly);
323 
324         UString signatureBuilder("(");
325         for (int i = 0; i < _numParameters; i++) {
326             JavaParameter* aParameter = parameterAt(i);
327             JNIType _JNIType = aParameter->getJNIType();
328             if (_JNIType == array_type)
329                 appendClassName(signatureBuilder, aParameter->type());
330             else {
331                 signatureBuilder.append(signatureFromPrimitiveType(_JNIType));
332                 if (_JNIType == object_type) {
333                     appendClassName(signatureBuilder, aParameter->type());
334                     signatureBuilder.append(";");
335                 }
336             }
337         }
338         signatureBuilder.append(")");
339 
340         const char *returnType = _returnType.UTF8String();
341         if (_JNIReturnType == array_type) {
342             appendClassName(signatureBuilder, returnType);
343         } else {
344             signatureBuilder.append(signatureFromPrimitiveType(_JNIReturnType));
345             if (_JNIReturnType == object_type) {
346                 appendClassName(signatureBuilder, returnType);
347                 signatureBuilder.append(";");
348             }
349         }
350 
351         _signature = strdup(signatureBuilder.ascii());
352     }
353 
354     return _signature;
355 }
356 
JNIReturnType() const357 JNIType JavaMethod::JNIReturnType() const
358 {
359     return _JNIReturnType;
360 }
361 
methodID(jobject obj) const362 jmethodID JavaMethod::methodID (jobject obj) const
363 {
364     if (_methodID == 0) {
365         _methodID = getMethodID (obj, _name.UTF8String(), signature());
366     }
367     return _methodID;
368 }
369 
370 
JavaArray(jobject array,const char * type,PassRefPtr<RootObject> rootObject)371 JavaArray::JavaArray(jobject array, const char* type, PassRefPtr<RootObject> rootObject)
372     : Array(rootObject)
373 {
374     _array = new JObjectWrapper(array);
375     // Java array are fixed length, so we can cache length.
376     JNIEnv *env = getJNIEnv();
377     _length = env->GetArrayLength((jarray)_array->_instance);
378     _type = strdup(type);
379     _rootObject = rootObject;
380 }
381 
~JavaArray()382 JavaArray::~JavaArray ()
383 {
384     free ((void *)_type);
385 }
386 
rootObject() const387 RootObject* JavaArray::rootObject() const
388 {
389     return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
390 }
391 
setValueAt(ExecState * exec,unsigned index,JSValue aValue) const392 void JavaArray::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
393 {
394     JNIEnv *env = getJNIEnv();
395     char *javaClassName = 0;
396 
397     JNIType arrayType = JNITypeFromPrimitiveType(_type[1]);
398     if (_type[1] == 'L'){
399         // The type of the array will be something like:
400         // "[Ljava.lang.string;".  This is guaranteed, so no need
401         // for extra sanity checks.
402         javaClassName = strdup(&_type[2]);
403         javaClassName[strchr(javaClassName, ';')-javaClassName] = 0;
404     }
405     jvalue aJValue = convertValueToJValue (exec, aValue, arrayType, javaClassName);
406 
407     switch (arrayType) {
408         case object_type: {
409             env->SetObjectArrayElement((jobjectArray)javaArray(), index, aJValue.l);
410             break;
411         }
412 
413         case boolean_type: {
414             env->SetBooleanArrayRegion((jbooleanArray)javaArray(), index, 1, &aJValue.z);
415             break;
416         }
417 
418         case byte_type: {
419             env->SetByteArrayRegion((jbyteArray)javaArray(), index, 1, &aJValue.b);
420             break;
421         }
422 
423         case char_type: {
424             env->SetCharArrayRegion((jcharArray)javaArray(), index, 1, &aJValue.c);
425             break;
426         }
427 
428         case short_type: {
429             env->SetShortArrayRegion((jshortArray)javaArray(), index, 1, &aJValue.s);
430             break;
431         }
432 
433         case int_type: {
434             env->SetIntArrayRegion((jintArray)javaArray(), index, 1, &aJValue.i);
435             break;
436         }
437 
438         case long_type: {
439             env->SetLongArrayRegion((jlongArray)javaArray(), index, 1, &aJValue.j);
440         }
441 
442         case float_type: {
443             env->SetFloatArrayRegion((jfloatArray)javaArray(), index, 1, &aJValue.f);
444             break;
445         }
446 
447         case double_type: {
448             env->SetDoubleArrayRegion((jdoubleArray)javaArray(), index, 1, &aJValue.d);
449             break;
450         }
451         default:
452         break;
453     }
454 
455     if (javaClassName)
456         free ((void *)javaClassName);
457 }
458 
459 
valueAt(ExecState * exec,unsigned index) const460 JSValue JavaArray::valueAt(ExecState* exec, unsigned index) const
461 {
462     JNIEnv *env = getJNIEnv();
463     JNIType arrayType = JNITypeFromPrimitiveType(_type[1]);
464     switch (arrayType) {
465         case object_type: {
466             jobjectArray objectArray = (jobjectArray)javaArray();
467             jobject anObject;
468             anObject = env->GetObjectArrayElement(objectArray, index);
469 
470             // No object?
471             if (!anObject) {
472                 return jsNull();
473             }
474 
475             // Nested array?
476             if (_type[1] == '[') {
477                 return JavaArray::convertJObjectToArray(exec, anObject, _type+1, rootObject());
478             }
479             // or array of other object type?
480             return JavaInstance::create(anObject, rootObject())->createRuntimeObject(exec);
481         }
482 
483         case boolean_type: {
484             jbooleanArray booleanArray = (jbooleanArray)javaArray();
485             jboolean aBoolean;
486             env->GetBooleanArrayRegion(booleanArray, index, 1, &aBoolean);
487             return jsBoolean(aBoolean);
488         }
489 
490         case byte_type: {
491             jbyteArray byteArray = (jbyteArray)javaArray();
492             jbyte aByte;
493             env->GetByteArrayRegion(byteArray, index, 1, &aByte);
494             return jsNumber(exec, aByte);
495         }
496 
497         case char_type: {
498             jcharArray charArray = (jcharArray)javaArray();
499             jchar aChar;
500             env->GetCharArrayRegion(charArray, index, 1, &aChar);
501             return jsNumber(exec, aChar);
502             break;
503         }
504 
505         case short_type: {
506             jshortArray shortArray = (jshortArray)javaArray();
507             jshort aShort;
508             env->GetShortArrayRegion(shortArray, index, 1, &aShort);
509             return jsNumber(exec, aShort);
510         }
511 
512         case int_type: {
513             jintArray intArray = (jintArray)javaArray();
514             jint anInt;
515             env->GetIntArrayRegion(intArray, index, 1, &anInt);
516             return jsNumber(exec, anInt);
517         }
518 
519         case long_type: {
520             jlongArray longArray = (jlongArray)javaArray();
521             jlong aLong;
522             env->GetLongArrayRegion(longArray, index, 1, &aLong);
523             return jsNumber(exec, aLong);
524         }
525 
526         case float_type: {
527             jfloatArray floatArray = (jfloatArray)javaArray();
528             jfloat aFloat;
529             env->GetFloatArrayRegion(floatArray, index, 1, &aFloat);
530             return jsNumber(exec, aFloat);
531         }
532 
533         case double_type: {
534             jdoubleArray doubleArray = (jdoubleArray)javaArray();
535             jdouble aDouble;
536             env->GetDoubleArrayRegion(doubleArray, index, 1, &aDouble);
537             return jsNumber(exec, aDouble);
538         }
539         default:
540         break;
541     }
542     return jsUndefined();
543 }
544 
getLength() const545 unsigned int JavaArray::getLength() const
546 {
547     return _length;
548 }
549 
550 #endif // ENABLE(MAC_JAVA_BRIDGE)
551