Home | History | Annotate | Download | only in jsc
      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 
     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 
     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 
     79 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 
    106 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 
    163 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 
    189 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 
    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 
    267 JavaArray::~JavaArray()
    268 {
    269     free(const_cast<char*>(m_type));
    270 }
    271 
    272 RootObject* JavaArray::rootObject() const
    273 {
    274     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
    275 }
    276 
    277 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 
    354 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 
    446 unsigned int JavaArray::getLength() const
    447 {
    448     return m_length;
    449 }
    450 
    451 #endif // ENABLE(MAC_JAVA_BRIDGE)
    452