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 46using namespace JSC; 47using namespace JSC::Bindings; 48 49 50JavaField::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 71JSValue 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 79jvalue 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 106JSValue 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 163void 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 189void 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 256JavaArray::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 267JavaArray::~JavaArray() 268{ 269 free(const_cast<char*>(m_type)); 270} 271 272RootObject* JavaArray::rootObject() const 273{ 274 return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0; 275} 276 277void 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 354JSValue 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 446unsigned int JavaArray::getLength() const 447{ 448 return m_length; 449} 450 451#endif // ENABLE(MAC_JAVA_BRIDGE) 452