Home | History | Annotate | Download | only in jsc
      1 /*
      2  * Copyright (C) 2003, 2010 Apple, Inc.  All rights reserved.
      3  * Copyright 2009, 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  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 "JNIUtilityPrivate.h"
     29 
     30 #if ENABLE(JAVA_BRIDGE)
     31 
     32 #include "JavaArrayJSC.h"
     33 #include "JavaInstanceJSC.h"
     34 #include "JavaRuntimeObject.h"
     35 #include "jni_jsobject.h"
     36 #include "runtime_array.h"
     37 #include "runtime_object.h"
     38 #include "runtime_root.h"
     39 #include <runtime/JSArray.h>
     40 #include <runtime/JSLock.h>
     41 
     42 namespace JSC {
     43 
     44 namespace Bindings {
     45 
     46 static jobject convertArrayInstanceToJavaArray(ExecState* exec, JSArray* jsArray, const char* javaClassName)
     47 {
     48     JNIEnv* env = getJNIEnv();
     49     // As JS Arrays can contain a mixture of objects, assume we can convert to
     50     // the requested Java Array type requested, unless the array type is some object array
     51     // other than a string.
     52     unsigned length = jsArray->length();
     53     jobjectArray jarray = 0;
     54 
     55     // Build the correct array type
     56     switch (javaTypeFromPrimitiveType(javaClassName[1])) {
     57     case JavaTypeObject:
     58             {
     59             // Only support string object types
     60             if (!strcmp("[Ljava.lang.String;", javaClassName)) {
     61                 jarray = (jobjectArray)env->NewObjectArray(length,
     62                     env->FindClass("java/lang/String"),
     63                     env->NewStringUTF(""));
     64                 for (unsigned i = 0; i < length; i++) {
     65                     JSValue item = jsArray->get(exec, i);
     66                     UString stringValue = item.toString(exec);
     67                     env->SetObjectArrayElement(jarray, i,
     68                         env->functions->NewString(env, (const jchar *)stringValue.characters(), stringValue.length()));
     69                 }
     70             }
     71             break;
     72         }
     73 
     74     case JavaTypeBoolean:
     75         {
     76             jarray = (jobjectArray)env->NewBooleanArray(length);
     77             for (unsigned i = 0; i < length; i++) {
     78                 JSValue item = jsArray->get(exec, i);
     79                 jboolean value = (jboolean)item.toNumber(exec);
     80                 env->SetBooleanArrayRegion((jbooleanArray)jarray, (jsize)i, (jsize)1, &value);
     81             }
     82             break;
     83         }
     84 
     85     case JavaTypeByte:
     86         {
     87             jarray = (jobjectArray)env->NewByteArray(length);
     88             for (unsigned i = 0; i < length; i++) {
     89                 JSValue item = jsArray->get(exec, i);
     90                 jbyte value = (jbyte)item.toNumber(exec);
     91                 env->SetByteArrayRegion((jbyteArray)jarray, (jsize)i, (jsize)1, &value);
     92             }
     93             break;
     94         }
     95 
     96     case JavaTypeChar:
     97         {
     98             jarray = (jobjectArray)env->NewCharArray(length);
     99             for (unsigned i = 0; i < length; i++) {
    100                 JSValue item = jsArray->get(exec, i);
    101                 UString stringValue = item.toString(exec);
    102                 jchar value = 0;
    103                 if (stringValue.length() > 0)
    104                     value = ((const jchar*)stringValue.characters())[0];
    105                 env->SetCharArrayRegion((jcharArray)jarray, (jsize)i, (jsize)1, &value);
    106             }
    107             break;
    108         }
    109 
    110     case JavaTypeShort:
    111         {
    112             jarray = (jobjectArray)env->NewShortArray(length);
    113             for (unsigned i = 0; i < length; i++) {
    114                 JSValue item = jsArray->get(exec, i);
    115                 jshort value = (jshort)item.toNumber(exec);
    116                 env->SetShortArrayRegion((jshortArray)jarray, (jsize)i, (jsize)1, &value);
    117             }
    118             break;
    119         }
    120 
    121     case JavaTypeInt:
    122         {
    123             jarray = (jobjectArray)env->NewIntArray(length);
    124             for (unsigned i = 0; i < length; i++) {
    125                 JSValue item = jsArray->get(exec, i);
    126                 jint value = (jint)item.toNumber(exec);
    127                 env->SetIntArrayRegion((jintArray)jarray, (jsize)i, (jsize)1, &value);
    128             }
    129             break;
    130         }
    131 
    132     case JavaTypeLong:
    133         {
    134             jarray = (jobjectArray)env->NewLongArray(length);
    135             for (unsigned i = 0; i < length; i++) {
    136                 JSValue item = jsArray->get(exec, i);
    137                 jlong value = (jlong)item.toNumber(exec);
    138                 env->SetLongArrayRegion((jlongArray)jarray, (jsize)i, (jsize)1, &value);
    139             }
    140             break;
    141         }
    142 
    143     case JavaTypeFloat:
    144         {
    145             jarray = (jobjectArray)env->NewFloatArray(length);
    146             for (unsigned i = 0; i < length; i++) {
    147                 JSValue item = jsArray->get(exec, i);
    148                 jfloat value = (jfloat)item.toNumber(exec);
    149                 env->SetFloatArrayRegion((jfloatArray)jarray, (jsize)i, (jsize)1, &value);
    150             }
    151             break;
    152         }
    153 
    154     case JavaTypeDouble:
    155         {
    156             jarray = (jobjectArray)env->NewDoubleArray(length);
    157             for (unsigned i = 0; i < length; i++) {
    158                 JSValue item = jsArray->get(exec, i);
    159                 jdouble value = (jdouble)item.toNumber(exec);
    160                 env->SetDoubleArrayRegion((jdoubleArray)jarray, (jsize)i, (jsize)1, &value);
    161             }
    162             break;
    163         }
    164 
    165     case JavaTypeArray: // don't handle embedded arrays
    166     case JavaTypeVoid: // Don't expect arrays of void objects
    167     case JavaTypeInvalid: // Array of unknown objects
    168         break;
    169     }
    170 
    171     // if it was not one of the cases handled, then null is returned
    172     return jarray;
    173 }
    174 
    175 jvalue convertValueToJValue(ExecState* exec, RootObject* rootObject, JSValue value, JavaType javaType, const char* javaClassName)
    176 {
    177     JSLock lock(SilenceAssertionsOnly);
    178 
    179     jvalue result;
    180     memset(&result, 0, sizeof(jvalue));
    181 
    182     switch (javaType) {
    183     case JavaTypeArray:
    184     case JavaTypeObject:
    185         {
    186             // FIXME: JavaJSObject::convertValueToJObject functionality is almost exactly the same,
    187             // these functions should use common code.
    188 
    189             if (value.isObject()) {
    190                 JSObject* object = asObject(value);
    191                 if (object->inherits(&JavaRuntimeObject::s_info)) {
    192                     // Unwrap a Java instance.
    193                     JavaRuntimeObject* runtimeObject = static_cast<JavaRuntimeObject*>(object);
    194                     JavaInstance* instance = runtimeObject->getInternalJavaInstance();
    195                     if (instance)
    196                         result.l = instance->javaInstance();
    197                 } else if (object->classInfo() == &RuntimeArray::s_info) {
    198                     // Input is a JavaScript Array that was originally created from a Java Array
    199                     RuntimeArray* imp = static_cast<RuntimeArray*>(object);
    200                     JavaArray* array = static_cast<JavaArray*>(imp->getConcreteArray());
    201                     result.l = array->javaArray();
    202                 } else if (object->classInfo() == &JSArray::s_info) {
    203                     // Input is a Javascript Array. We need to create it to a Java Array.
    204                     result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName);
    205                 } else if ((!result.l && (!strcmp(javaClassName, "java.lang.Object")))
    206                            || (!strcmp(javaClassName, "netscape.javascript.JSObject"))) {
    207                     // Wrap objects in JSObject instances.
    208                     JNIEnv* env = getJNIEnv();
    209                     jclass jsObjectClass = env->FindClass("sun/plugin/javascript/webkit/JSObject");
    210                     jmethodID constructorID = env->GetMethodID(jsObjectClass, "<init>", "(J)V");
    211                     if (constructorID) {
    212                         jlong nativeHandle = ptr_to_jlong(object);
    213                         rootObject->gcProtect(object);
    214                         result.l = env->NewObject(jsObjectClass, constructorID, nativeHandle);
    215                     }
    216                 }
    217             }
    218 
    219             // Create an appropriate Java object if target type is java.lang.Object.
    220             if (!result.l && !strcmp(javaClassName, "java.lang.Object")) {
    221                 if (value.isString()) {
    222                     UString stringValue = asString(value)->value(exec);
    223                     JNIEnv* env = getJNIEnv();
    224                     jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length());
    225                     result.l = javaString;
    226                 } else if (value.isNumber()) {
    227                     double doubleValue = value.uncheckedGetNumber();
    228                     JNIEnv* env = getJNIEnv();
    229                     jclass clazz = env->FindClass("java/lang/Double");
    230                     jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V");
    231                     jobject javaDouble = env->functions->NewObject(env, clazz, constructor, doubleValue);
    232                     result.l = javaDouble;
    233                 } else if (value.isBoolean()) {
    234                     bool boolValue = value.getBoolean();
    235                     JNIEnv* env = getJNIEnv();
    236                     jclass clazz = env->FindClass("java/lang/Boolean");
    237                     jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V");
    238                     jobject javaBoolean = env->functions->NewObject(env, clazz, constructor, boolValue);
    239                     result.l = javaBoolean;
    240                 } else if (value.isUndefined()) {
    241                     UString stringValue = "undefined";
    242                     JNIEnv* env = getJNIEnv();
    243                     jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length());
    244                     result.l = javaString;
    245                 }
    246             }
    247 
    248             // Convert value to a string if the target type is a java.lang.String, and we're not
    249             // converting from a null.
    250             if (!result.l && !strcmp(javaClassName, "java.lang.String")) {
    251                 if (!value.isNull()) {
    252                     UString stringValue = value.toString(exec);
    253                     JNIEnv* env = getJNIEnv();
    254                     jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length());
    255                     result.l = javaString;
    256                 }
    257             }
    258         }
    259         break;
    260 
    261     case JavaTypeBoolean:
    262         {
    263             result.z = (jboolean)value.toNumber(exec);
    264         }
    265         break;
    266 
    267     case JavaTypeByte:
    268         {
    269             result.b = (jbyte)value.toNumber(exec);
    270         }
    271         break;
    272 
    273     case JavaTypeChar:
    274         {
    275             result.c = (jchar)value.toNumber(exec);
    276         }
    277         break;
    278 
    279     case JavaTypeShort:
    280         {
    281             result.s = (jshort)value.toNumber(exec);
    282         }
    283         break;
    284 
    285     case JavaTypeInt:
    286         {
    287             result.i = (jint)value.toNumber(exec);
    288         }
    289         break;
    290 
    291     case JavaTypeLong:
    292         {
    293             result.j = (jlong)value.toNumber(exec);
    294         }
    295         break;
    296 
    297     case JavaTypeFloat:
    298         {
    299             result.f = (jfloat)value.toNumber(exec);
    300         }
    301         break;
    302 
    303     case JavaTypeDouble:
    304         {
    305             result.d = (jdouble)value.toNumber(exec);
    306         }
    307         break;
    308 
    309     case JavaTypeInvalid:
    310     case JavaTypeVoid:
    311         break;
    312     }
    313     return result;
    314 }
    315 
    316 } // end of namespace Bindings
    317 
    318 } // end of namespace JSC
    319 
    320 #endif // ENABLE(JAVA_BRIDGE)
    321