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