• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2007, 2009 Apple Inc. All rights reserved.
3  * Copyright 2010, The Android Open Source Project
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "JNIBridgeJSC.h"
29 
30 #if ENABLE(MAC_JAVA_BRIDGE)
31 
32 #include "JNIUtilityPrivate.h"
33 #include "runtime_array.h"
34 #include "runtime_object.h"
35 #include <runtime/Error.h>
36 
37 #ifdef NDEBUG
38 #define JS_LOG(formatAndArgs...) ((void)0)
39 #else
40 #define JS_LOG(formatAndArgs...) { \
41     fprintf(stderr, "%s:%d -- %s:  ", __FILE__, __LINE__, __FUNCTION__); \
42     fprintf(stderr, formatAndArgs); \
43 }
44 #endif
45 
46 using namespace JSC;
47 using namespace JSC::Bindings;
48 
49 
JavaField(JNIEnv * env,jobject aField)50 JavaField::JavaField(JNIEnv* env, jobject aField)
51 {
52     // Get field type name
53     jstring fieldTypeName = 0;
54     if (jobject fieldType = callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;"))
55         fieldTypeName = static_cast<jstring>(callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;"));
56     if (!fieldTypeName)
57         fieldTypeName = env->NewStringUTF("<Unknown>");
58     m_type = JavaString(env, fieldTypeName);
59 
60     m_JNIType = JNITypeFromClassName(m_type.UTF8String());
61 
62     // Get field name
63     jstring fieldName = static_cast<jstring>(callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;"));
64     if (!fieldName)
65         fieldName = env->NewStringUTF("<Unknown>");
66     m_name = JavaString(env, fieldName);
67 
68     m_field = new JObjectWrapper(aField);
69 }
70 
convertJObjectToArray(ExecState * exec,jobject anObject,const char * type,PassRefPtr<RootObject> rootObject)71 JSValue JavaArray::convertJObjectToArray(ExecState* exec, jobject anObject, const char* type, PassRefPtr<RootObject> rootObject)
72 {
73     if (type[0] != '[')
74         return jsUndefined();
75 
76     return new (exec) RuntimeArray(exec, new JavaArray(anObject, type, rootObject));
77 }
78 
dispatchValueFromInstance(ExecState * exec,const JavaInstance * instance,const char * name,const char * sig,JNIType returnType) const79 jvalue JavaField::dispatchValueFromInstance(ExecState* exec, const JavaInstance* instance, const char* name, const char* sig, JNIType returnType) const
80 {
81     jobject jinstance = instance->javaInstance();
82     jobject fieldJInstance = m_field->m_instance;
83     JNIEnv* env = getJNIEnv();
84     jvalue result;
85 
86     memset(&result, 0, sizeof(jvalue));
87     jclass cls = env->GetObjectClass(fieldJInstance);
88     if (cls) {
89         jmethodID mid = env->GetMethodID(cls, name, sig);
90         if (mid) {
91             RootObject* rootObject = instance->rootObject();
92             if (rootObject && rootObject->nativeHandle()) {
93                 JSValue exceptionDescription;
94                 jvalue args[1];
95 
96                 args[0].l = jinstance;
97                 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, returnType, mid, args, result, 0, exceptionDescription);
98                 if (exceptionDescription)
99                     throwError(exec, GeneralError, exceptionDescription.toString(exec));
100             }
101         }
102     }
103     return result;
104 }
105 
valueFromInstance(ExecState * exec,const Instance * i) const106 JSValue JavaField::valueFromInstance(ExecState* exec, const Instance* i) const
107 {
108     const JavaInstance* instance = static_cast<const JavaInstance*>(i);
109 
110     JSValue jsresult = jsUndefined();
111 
112     switch (m_JNIType) {
113     case array_type:
114     case object_type:
115         {
116             jvalue result = dispatchValueFromInstance(exec, instance, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", object_type);
117             jobject anObject = result.l;
118 
119             const char* arrayType = type();
120             if (arrayType[0] == '[')
121                 jsresult = JavaArray::convertJObjectToArray(exec, anObject, arrayType, instance->rootObject());
122             else if (anObject)
123                 jsresult = JavaInstance::create(anObject, instance->rootObject())->createRuntimeObject(exec);
124         }
125         break;
126 
127     case boolean_type:
128         jsresult = jsBoolean(dispatchValueFromInstance(exec, instance, "getBoolean", "(Ljava/lang/Object;)Z", boolean_type).z);
129         break;
130 
131     case byte_type:
132     case char_type:
133     case short_type:
134 
135     case int_type:
136         {
137             jint value;
138             jvalue result = dispatchValueFromInstance(exec, instance, "getInt", "(Ljava/lang/Object;)I", int_type);
139             value = result.i;
140             jsresult = jsNumber(exec, static_cast<int>(value));
141         }
142         break;
143 
144     case long_type:
145     case float_type:
146     case double_type:
147         {
148             jdouble value;
149             jvalue result = dispatchValueFromInstance(exec, instance, "getDouble", "(Ljava/lang/Object;)D", double_type);
150             value = result.i;
151             jsresult = jsNumber(exec, static_cast<double>(value));
152         }
153         break;
154     default:
155         break;
156     }
157 
158     JS_LOG("getting %s = %s\n", UString(name()).UTF8String().c_str(), jsresult.toString(exec).ascii());
159 
160     return jsresult;
161 }
162 
dispatchSetValueToInstance(ExecState * exec,const JavaInstance * instance,jvalue javaValue,const char * name,const char * sig) const163 void JavaField::dispatchSetValueToInstance(ExecState* exec, const JavaInstance* instance, jvalue javaValue, const char* name, const char* sig) const
164 {
165     jobject jinstance = instance->javaInstance();
166     jobject fieldJInstance = m_field->m_instance;
167     JNIEnv* env = getJNIEnv();
168 
169     jclass cls = env->GetObjectClass(fieldJInstance);
170     if (cls) {
171         jmethodID mid = env->GetMethodID(cls, name, sig);
172         if (mid) {
173             RootObject* rootObject = instance->rootObject();
174             if (rootObject && rootObject->nativeHandle()) {
175                 JSValue exceptionDescription;
176                 jvalue args[2];
177                 jvalue result;
178 
179                 args[0].l = jinstance;
180                 args[1] = javaValue;
181                 dispatchJNICall(exec, rootObject->nativeHandle(), fieldJInstance, false, void_type, mid, args, result, 0, exceptionDescription);
182                 if (exceptionDescription)
183                     throwError(exec, GeneralError, exceptionDescription.toString(exec));
184             }
185         }
186     }
187 }
188 
setValueToInstance(ExecState * exec,const Instance * i,JSValue aValue) const189 void JavaField::setValueToInstance(ExecState* exec, const Instance* i, JSValue aValue) const
190 {
191     const JavaInstance* instance = static_cast<const JavaInstance*>(i);
192     jvalue javaValue = convertValueToJValue(exec, aValue, m_JNIType, type());
193 
194     JS_LOG("setting value %s to %s\n", UString(name()).UTF8String().c_str(), aValue.toString(exec).ascii());
195 
196     switch (m_JNIType) {
197     case array_type:
198     case object_type:
199         {
200             dispatchSetValueToInstance(exec, instance, javaValue, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V");
201         }
202         break;
203 
204     case boolean_type:
205         {
206             dispatchSetValueToInstance(exec, instance, javaValue, "setBoolean", "(Ljava/lang/Object;Z)V");
207         }
208         break;
209 
210     case byte_type:
211         {
212             dispatchSetValueToInstance(exec, instance, javaValue, "setByte", "(Ljava/lang/Object;B)V");
213         }
214         break;
215 
216     case char_type:
217         {
218             dispatchSetValueToInstance(exec, instance, javaValue, "setChar", "(Ljava/lang/Object;C)V");
219         }
220         break;
221 
222     case short_type:
223         {
224             dispatchSetValueToInstance(exec, instance, javaValue, "setShort", "(Ljava/lang/Object;S)V");
225         }
226         break;
227 
228     case int_type:
229         {
230             dispatchSetValueToInstance(exec, instance, javaValue, "setInt", "(Ljava/lang/Object;I)V");
231         }
232         break;
233 
234     case long_type:
235         {
236             dispatchSetValueToInstance(exec, instance, javaValue, "setLong", "(Ljava/lang/Object;J)V");
237         }
238         break;
239 
240     case float_type:
241         {
242             dispatchSetValueToInstance(exec, instance, javaValue, "setFloat", "(Ljava/lang/Object;F)V");
243         }
244         break;
245 
246     case double_type:
247         {
248             dispatchSetValueToInstance(exec, instance, javaValue, "setDouble", "(Ljava/lang/Object;D)V");
249         }
250         break;
251     default:
252         break;
253     }
254 }
255 
JavaArray(jobject array,const char * type,PassRefPtr<RootObject> rootObject)256 JavaArray::JavaArray(jobject array, const char* type, PassRefPtr<RootObject> rootObject)
257     : Array(rootObject)
258 {
259     m_array = new JObjectWrapper(array);
260     // Java array are fixed length, so we can cache length.
261     JNIEnv* env = getJNIEnv();
262     m_length = env->GetArrayLength(static_cast<jarray>(m_array->m_instance));
263     m_type = strdup(type);
264     m_rootObject = rootObject;
265 }
266 
~JavaArray()267 JavaArray::~JavaArray()
268 {
269     free(const_cast<char*>(m_type));
270 }
271 
rootObject() const272 RootObject* JavaArray::rootObject() const
273 {
274     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
275 }
276 
setValueAt(ExecState * exec,unsigned index,JSValue aValue) const277 void JavaArray::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
278 {
279     JNIEnv* env = getJNIEnv();
280     char* javaClassName = 0;
281 
282     JNIType arrayType = JNITypeFromPrimitiveType(m_type[1]);
283     if (m_type[1] == 'L') {
284         // The type of the array will be something like:
285         // "[Ljava.lang.string;".  This is guaranteed, so no need
286         // for extra sanity checks.
287         javaClassName = strdup(&m_type[2]);
288         javaClassName[strchr(javaClassName, ';')-javaClassName] = 0;
289     }
290     jvalue aJValue = convertValueToJValue(exec, aValue, arrayType, javaClassName);
291 
292     switch (arrayType) {
293     case object_type:
294         {
295             env->SetObjectArrayElement(static_cast<jobjectArray>(javaArray()), index, aJValue.l);
296             break;
297         }
298 
299     case boolean_type:
300         {
301             env->SetBooleanArrayRegion(static_cast<jbooleanArray>(javaArray()), index, 1, &aJValue.z);
302             break;
303         }
304 
305     case byte_type:
306         {
307             env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray()), index, 1, &aJValue.b);
308             break;
309         }
310 
311     case char_type:
312         {
313             env->SetCharArrayRegion(static_cast<jcharArray>(javaArray()), index, 1, &aJValue.c);
314             break;
315         }
316 
317     case short_type:
318         {
319             env->SetShortArrayRegion(static_cast<jshortArray>(javaArray()), index, 1, &aJValue.s);
320             break;
321         }
322 
323     case int_type:
324         {
325             env->SetIntArrayRegion(static_cast<jintArray>(javaArray()), index, 1, &aJValue.i);
326             break;
327         }
328 
329     case long_type:
330         {
331             env->SetLongArrayRegion(static_cast<jlongArray>(javaArray()), index, 1, &aJValue.j);
332         }
333 
334     case float_type:
335         {
336             env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray()), index, 1, &aJValue.f);
337             break;
338         }
339 
340     case double_type:
341         {
342             env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray()), index, 1, &aJValue.d);
343             break;
344         }
345     default:
346         break;
347     }
348 
349     if (javaClassName)
350         free(const_cast<char*>(javaClassName));
351 }
352 
353 
valueAt(ExecState * exec,unsigned index) const354 JSValue JavaArray::valueAt(ExecState* exec, unsigned index) const
355 {
356     JNIEnv* env = getJNIEnv();
357     JNIType arrayType = JNITypeFromPrimitiveType(m_type[1]);
358     switch (arrayType) {
359     case object_type:
360         {
361             jobjectArray objectArray = static_cast<jobjectArray>(javaArray());
362             jobject anObject;
363             anObject = env->GetObjectArrayElement(objectArray, index);
364 
365             // No object?
366             if (!anObject)
367                 return jsNull();
368 
369             // Nested array?
370             if (m_type[1] == '[')
371                 return JavaArray::convertJObjectToArray(exec, anObject, m_type + 1, rootObject());
372             // or array of other object type?
373             return JavaInstance::create(anObject, rootObject())->createRuntimeObject(exec);
374         }
375 
376     case boolean_type:
377         {
378             jbooleanArray booleanArray = static_cast<jbooleanArray>(javaArray());
379             jboolean aBoolean;
380             env->GetBooleanArrayRegion(booleanArray, index, 1, &aBoolean);
381             return jsBoolean(aBoolean);
382         }
383 
384     case byte_type:
385         {
386             jbyteArray byteArray = static_cast<jbyteArray>(javaArray());
387             jbyte aByte;
388             env->GetByteArrayRegion(byteArray, index, 1, &aByte);
389             return jsNumber(exec, aByte);
390         }
391 
392     case char_type:
393         {
394             jcharArray charArray = static_cast<jcharArray>(javaArray());
395             jchar aChar;
396             env->GetCharArrayRegion(charArray, index, 1, &aChar);
397             return jsNumber(exec, aChar);
398             break;
399         }
400 
401     case short_type:
402         {
403             jshortArray shortArray = static_cast<jshortArray>(javaArray());
404             jshort aShort;
405             env->GetShortArrayRegion(shortArray, index, 1, &aShort);
406             return jsNumber(exec, aShort);
407         }
408 
409     case int_type:
410         {
411             jintArray intArray = static_cast<jintArray>(javaArray());
412             jint anInt;
413             env->GetIntArrayRegion(intArray, index, 1, &anInt);
414             return jsNumber(exec, anInt);
415         }
416 
417     case long_type:
418         {
419             jlongArray longArray = static_cast<jlongArray>(javaArray());
420             jlong aLong;
421             env->GetLongArrayRegion(longArray, index, 1, &aLong);
422             return jsNumber(exec, aLong);
423         }
424 
425     case float_type:
426         {
427             jfloatArray floatArray = static_cast<jfloatArray>(javaArray());
428             jfloat aFloat;
429             env->GetFloatArrayRegion(floatArray, index, 1, &aFloat);
430             return jsNumber(exec, aFloat);
431         }
432 
433     case double_type:
434         {
435             jdoubleArray doubleArray = static_cast<jdoubleArray>(javaArray());
436             jdouble aDouble;
437             env->GetDoubleArrayRegion(doubleArray, index, 1, &aDouble);
438             return jsNumber(exec, aDouble);
439         }
440     default:
441         break;
442     }
443     return jsUndefined();
444 }
445 
getLength() const446 unsigned int JavaArray::getLength() const
447 {
448     return m_length;
449 }
450 
451 #endif // ENABLE(MAC_JAVA_BRIDGE)
452