Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "jni_jsobject.h"
     28 
     29 #if ENABLE(JAVA_BRIDGE)
     30 
     31 #include "Frame.h"
     32 #include "JNIUtility.h"
     33 #include "JNIUtilityPrivate.h"
     34 #include "JSDOMBinding.h"
     35 #include "JavaRuntimeObject.h"
     36 #include "JavaString.h"
     37 #include "Logging.h"
     38 #include "ScriptController.h"
     39 #include "StringSourceProvider.h"
     40 #include "WebCoreFrameView.h"
     41 #include "runtime_object.h"
     42 #include "runtime_root.h"
     43 #include <interpreter/CallFrame.h>
     44 #include <runtime/Completion.h>
     45 #include <runtime/JSGlobalObject.h>
     46 #include <runtime/JSLock.h>
     47 
     48 using WebCore::Frame;
     49 
     50 using namespace JSC::Bindings;
     51 using namespace JSC;
     52 using namespace WebCore;
     53 
     54 #define UndefinedHandle 1
     55 
     56 static CFRunLoopSourceRef _performJavaScriptSource;
     57 static CFRunLoopRef _performJavaScriptRunLoop;
     58 
     59 // May only be set by dispatchToJavaScriptThread().
     60 static CFRunLoopSourceRef completionSource;
     61 
     62 static void completedJavaScriptAccess (void *i)
     63 {
     64     ASSERT(CFRunLoopGetCurrent() != _performJavaScriptRunLoop);
     65 
     66     JSObjectCallContext *callContext = (JSObjectCallContext *)i;
     67     CFRunLoopRef runLoop = (CFRunLoopRef)callContext->originatingLoop;
     68 
     69     ASSERT(CFRunLoopGetCurrent() == runLoop);
     70 
     71     CFRunLoopStop(runLoop);
     72 }
     73 
     74 static pthread_once_t javaScriptAccessLockOnce = PTHREAD_ONCE_INIT;
     75 static pthread_mutex_t javaScriptAccessLock;
     76 static int javaScriptAccessLockCount = 0;
     77 
     78 static void initializeJavaScriptAccessLock()
     79 {
     80     pthread_mutexattr_t attr;
     81 
     82     pthread_mutexattr_init(&attr);
     83     pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
     84 
     85     pthread_mutex_init(&javaScriptAccessLock, &attr);
     86 }
     87 
     88 static inline void lockJavaScriptAccess()
     89 {
     90     // Perhaps add deadlock detection?
     91     pthread_once(&javaScriptAccessLockOnce, initializeJavaScriptAccessLock);
     92     pthread_mutex_lock(&javaScriptAccessLock);
     93     javaScriptAccessLockCount++;
     94 }
     95 
     96 static inline void unlockJavaScriptAccess()
     97 {
     98     javaScriptAccessLockCount--;
     99     pthread_mutex_unlock(&javaScriptAccessLock);
    100 }
    101 
    102 static void dispatchToJavaScriptThread(JSObjectCallContext *context)
    103 {
    104     // This lock guarantees that only one thread can invoke
    105     // at a time, and also guarantees that completionSource;
    106     // won't get clobbered.
    107     lockJavaScriptAccess();
    108 
    109     CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
    110 
    111     ASSERT(currentRunLoop != _performJavaScriptRunLoop);
    112 
    113     // Setup a source to signal once the invocation of the JavaScript
    114     // call completes.
    115     //
    116     // FIXME:  This could be a potential performance issue.  Creating and
    117     // adding run loop sources is expensive.  We could create one source
    118     // per thread, as needed, instead.
    119     context->originatingLoop = currentRunLoop;
    120     CFRunLoopSourceContext sourceContext = {0, context, NULL, NULL, NULL, NULL, NULL, NULL, NULL, completedJavaScriptAccess};
    121     completionSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
    122     CFRunLoopAddSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode);
    123 
    124     // Wakeup JavaScript access thread and make it do its work.
    125     CFRunLoopSourceSignal(_performJavaScriptSource);
    126     if (CFRunLoopIsWaiting(_performJavaScriptRunLoop))
    127         CFRunLoopWakeUp(_performJavaScriptRunLoop);
    128 
    129     // Wait until the JavaScript access thread is done.
    130     CFRunLoopRun ();
    131 
    132     CFRunLoopRemoveSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode);
    133     CFRelease (completionSource);
    134 
    135     unlockJavaScriptAccess();
    136 }
    137 
    138 static void performJavaScriptAccess(void*)
    139 {
    140     ASSERT(CFRunLoopGetCurrent() == _performJavaScriptRunLoop);
    141 
    142     // Dispatch JavaScript calls here.
    143     CFRunLoopSourceContext sourceContext;
    144     CFRunLoopSourceGetContext (completionSource, &sourceContext);
    145     JSObjectCallContext *callContext = (JSObjectCallContext *)sourceContext.info;
    146     CFRunLoopRef originatingLoop = callContext->originatingLoop;
    147 
    148     JavaJSObject::invoke (callContext);
    149 
    150     // Signal the originating thread that we're done.
    151     CFRunLoopSourceSignal (completionSource);
    152     if (CFRunLoopIsWaiting(originatingLoop))
    153         CFRunLoopWakeUp(originatingLoop);
    154 }
    155 
    156 // Must be called from the thread that will be used to access JavaScript.
    157 void JavaJSObject::initializeJNIThreading() {
    158     // Should only be called once.
    159     ASSERT(!_performJavaScriptRunLoop);
    160 
    161     // Assume that we can retain this run loop forever.  It'll most
    162     // likely (always?) be the main loop.
    163     _performJavaScriptRunLoop = (CFRunLoopRef)CFRetain(CFRunLoopGetCurrent());
    164 
    165     // Setup a source the other threads can use to signal the _runLoop
    166     // thread that a JavaScript call needs to be invoked.
    167     CFRunLoopSourceContext sourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, performJavaScriptAccess};
    168     _performJavaScriptSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
    169     CFRunLoopAddSource(_performJavaScriptRunLoop, _performJavaScriptSource, kCFRunLoopDefaultMode);
    170 }
    171 
    172 static bool isJavaScriptThread()
    173 {
    174     return (_performJavaScriptRunLoop == CFRunLoopGetCurrent());
    175 }
    176 
    177 jvalue JavaJSObject::invoke(JSObjectCallContext *context)
    178 {
    179     jvalue result;
    180 
    181     bzero ((void *)&result, sizeof(jvalue));
    182 
    183     if (!isJavaScriptThread()) {
    184         // Send the call context to the thread that is allowed to
    185         // call JavaScript.
    186         dispatchToJavaScriptThread(context);
    187         result = context->result;
    188     }
    189     else {
    190         jlong nativeHandle = context->nativeHandle;
    191         if (nativeHandle == UndefinedHandle || nativeHandle == 0) {
    192             return result;
    193         }
    194 
    195         if (context->type == CreateNative) {
    196             result.j = JavaJSObject::createNative(nativeHandle);
    197         }
    198         else {
    199             JSObject *imp = jlong_to_impptr(nativeHandle);
    200             if (!findProtectingRootObject(imp)) {
    201                 LOG_ERROR("Attempt to access JavaScript from destroyed applet, type %d.", context->type);
    202                 return result;
    203             }
    204 
    205             switch (context->type){
    206                 case Call: {
    207                     result.l = JavaJSObject(nativeHandle).call(context->string, context->args);
    208                     break;
    209                 }
    210 
    211                 case Eval: {
    212                     result.l = JavaJSObject(nativeHandle).eval(context->string);
    213                     break;
    214                 }
    215 
    216                 case GetMember: {
    217                     result.l = JavaJSObject(nativeHandle).getMember(context->string);
    218                     break;
    219                 }
    220 
    221                 case SetMember: {
    222                     JavaJSObject(nativeHandle).setMember(context->string, context->value);
    223                     break;
    224                 }
    225 
    226                 case RemoveMember: {
    227                     JavaJSObject(nativeHandle).removeMember(context->string);
    228                     break;
    229                 }
    230 
    231                 case GetSlot: {
    232                     result.l = JavaJSObject(nativeHandle).getSlot(context->index);
    233                     break;
    234                 }
    235 
    236                 case SetSlot: {
    237                     JavaJSObject(nativeHandle).setSlot(context->index, context->value);
    238                     break;
    239                 }
    240 
    241                 case ToString: {
    242                     result.l = (jobject) JavaJSObject(nativeHandle).toString();
    243                     break;
    244                 }
    245 
    246                 case Finalize: {
    247                     JavaJSObject(nativeHandle).finalize();
    248                     break;
    249                 }
    250 
    251                 default: {
    252                     LOG_ERROR("invalid JavaScript call");
    253                 }
    254             }
    255         }
    256         context->result = result;
    257     }
    258 
    259     return result;
    260 }
    261 
    262 
    263 JavaJSObject::JavaJSObject(jlong nativeJSObject)
    264 {
    265     _imp = jlong_to_impptr(nativeJSObject);
    266 
    267     ASSERT(_imp);
    268     _rootObject = findProtectingRootObject(_imp);
    269     ASSERT(_rootObject);
    270 }
    271 
    272 RootObject* JavaJSObject::rootObject() const
    273 {
    274     return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
    275 }
    276 
    277 jobject JavaJSObject::call(jstring methodName, jobjectArray args) const
    278 {
    279     LOG(LiveConnect, "JavaJSObject::call methodName = %s", JavaString(methodName).utf8());
    280 
    281     RootObject* rootObject = this->rootObject();
    282     if (!rootObject)
    283         return 0;
    284 
    285     // Lookup the function object.
    286     ExecState* exec = rootObject->globalObject()->globalExec();
    287     JSLock lock(SilenceAssertionsOnly);
    288 
    289     Identifier identifier(exec, JavaString(methodName).impl());
    290     JSValue function = _imp->get(exec, identifier);
    291     CallData callData;
    292     CallType callType = getCallData(function, callData);
    293     if (callType == CallTypeNone)
    294         return 0;
    295 
    296     // Call the function object.
    297     MarkedArgumentBuffer argList;
    298     getListFromJArray(exec, args, argList);
    299     rootObject->globalObject()->globalData().timeoutChecker.start();
    300     JSValue result = JSC::call(exec, function, callType, callData, _imp, argList);
    301     rootObject->globalObject()->globalData().timeoutChecker.stop();
    302 
    303     return convertValueToJObject(result);
    304 }
    305 
    306 jobject JavaJSObject::eval(jstring script) const
    307 {
    308     LOG(LiveConnect, "JavaJSObject::eval script = %s", JavaString(script).utf8());
    309 
    310     JSValue result;
    311 
    312     JSLock lock(SilenceAssertionsOnly);
    313 
    314     RootObject* rootObject = this->rootObject();
    315     if (!rootObject)
    316         return 0;
    317 
    318     rootObject->globalObject()->globalData().timeoutChecker.start();
    319     Completion completion = JSC::evaluate(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), makeSource(JavaString(script).impl()), JSC::JSValue());
    320     rootObject->globalObject()->globalData().timeoutChecker.stop();
    321     ComplType type = completion.complType();
    322 
    323     if (type == Normal) {
    324         result = completion.value();
    325         if (!result)
    326             result = jsUndefined();
    327     } else
    328         result = jsUndefined();
    329 
    330     return convertValueToJObject (result);
    331 }
    332 
    333 jobject JavaJSObject::getMember(jstring memberName) const
    334 {
    335     LOG(LiveConnect, "JavaJSObject::getMember (%p) memberName = %s", _imp, JavaString(memberName).utf8());
    336 
    337     RootObject* rootObject = this->rootObject();
    338     if (!rootObject)
    339         return 0;
    340 
    341     ExecState* exec = rootObject->globalObject()->globalExec();
    342 
    343     JSLock lock(SilenceAssertionsOnly);
    344     JSValue result = _imp->get(exec, Identifier(exec, JavaString(memberName).impl()));
    345 
    346     return convertValueToJObject(result);
    347 }
    348 
    349 void JavaJSObject::setMember(jstring memberName, jobject value) const
    350 {
    351     LOG(LiveConnect, "JavaJSObject::setMember memberName = %s, value = %p", JavaString(memberName).utf8(), value);
    352 
    353     RootObject* rootObject = this->rootObject();
    354     if (!rootObject)
    355         return;
    356 
    357     ExecState* exec = rootObject->globalObject()->globalExec();
    358 
    359     JSLock lock(SilenceAssertionsOnly);
    360     PutPropertySlot slot;
    361     _imp->put(exec, Identifier(exec, JavaString(memberName).impl()), convertJObjectToValue(exec, value), slot);
    362 }
    363 
    364 
    365 void JavaJSObject::removeMember(jstring memberName) const
    366 {
    367     LOG(LiveConnect, "JavaJSObject::removeMember memberName = %s", JavaString(memberName).utf8());
    368 
    369     RootObject* rootObject = this->rootObject();
    370     if (!rootObject)
    371         return;
    372 
    373     ExecState* exec = rootObject->globalObject()->globalExec();
    374     JSLock lock(SilenceAssertionsOnly);
    375     _imp->deleteProperty(exec, Identifier(exec, JavaString(memberName).impl()));
    376 }
    377 
    378 
    379 jobject JavaJSObject::getSlot(jint index) const
    380 {
    381     LOG(LiveConnect, "JavaJSObject::getSlot index = %ld", static_cast<long>(index));
    382 
    383     RootObject* rootObject = this->rootObject();
    384     if (!rootObject)
    385         return 0;
    386 
    387     ExecState* exec = rootObject->globalObject()->globalExec();
    388 
    389     JSLock lock(SilenceAssertionsOnly);
    390     JSValue result = _imp->get(exec, index);
    391 
    392     return convertValueToJObject(result);
    393 }
    394 
    395 
    396 void JavaJSObject::setSlot(jint index, jobject value) const
    397 {
    398     LOG(LiveConnect, "JavaJSObject::setSlot index = %ld, value = %p", static_cast<long>(index), value);
    399 
    400     RootObject* rootObject = this->rootObject();
    401     if (!rootObject)
    402         return;
    403 
    404     ExecState* exec = rootObject->globalObject()->globalExec();
    405     JSLock lock(SilenceAssertionsOnly);
    406     _imp->put(exec, (unsigned)index, convertJObjectToValue(exec, value));
    407 }
    408 
    409 
    410 jstring JavaJSObject::toString() const
    411 {
    412     LOG(LiveConnect, "JavaJSObject::toString");
    413 
    414     RootObject* rootObject = this->rootObject();
    415     if (!rootObject)
    416         return 0;
    417 
    418     JSLock lock(SilenceAssertionsOnly);
    419     JSObject *thisObj = const_cast<JSObject*>(_imp);
    420     ExecState* exec = rootObject->globalObject()->globalExec();
    421 
    422     return static_cast<jstring>(convertValueToJValue(exec, rootObject, thisObj, JavaTypeObject, "java.lang.String").l);
    423 }
    424 
    425 void JavaJSObject::finalize() const
    426 {
    427     if (RootObject* rootObject = this->rootObject())
    428         rootObject->gcUnprotect(_imp);
    429 }
    430 
    431 static PassRefPtr<RootObject> createRootObject(void* nativeHandle)
    432 {
    433     Frame* frame = 0;
    434     for (NSView *view = (NSView *)nativeHandle; view; view = [view superview]) {
    435         if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
    436             NSView<WebCoreFrameView> *webCoreFrameView = static_cast<NSView<WebCoreFrameView>*>(view);
    437             frame = [webCoreFrameView _web_frame];
    438             break;
    439         }
    440     }
    441     if (!frame)
    442         return 0;
    443     return frame->script()->createRootObject(nativeHandle);
    444 }
    445 
    446 // We're either creating a 'Root' object (via a call to JavaJSObject.getWindow()), or
    447 // another JavaJSObject.
    448 jlong JavaJSObject::createNative(jlong nativeHandle)
    449 {
    450     LOG(LiveConnect, "JavaJSObject::createNative nativeHandle = %d", static_cast<int>(nativeHandle));
    451 
    452     if (nativeHandle == UndefinedHandle)
    453         return nativeHandle;
    454 
    455     if (findProtectingRootObject(jlong_to_impptr(nativeHandle)))
    456         return nativeHandle;
    457 
    458     RefPtr<RootObject> rootObject = createRootObject(jlong_to_ptr(nativeHandle));
    459 
    460     // If rootObject is !NULL We must have been called via netscape.javascript.JavaJSObject.getWindow(),
    461     // otherwise we are being called after creating a JavaJSObject in
    462     // JavaJSObject::convertValueToJObject().
    463     if (rootObject) {
    464         JSObject* globalObject = rootObject->globalObject();
    465         // We call gcProtect here to get the object into the root object's "protect set" which
    466         // is used to test if a native handle is valid as well as getting the root object given the handle.
    467         rootObject->gcProtect(globalObject);
    468         return ptr_to_jlong(globalObject);
    469     }
    470 
    471     return nativeHandle;
    472 }
    473 
    474 jobject JavaJSObject::convertValueToJObject(JSValue value) const
    475 {
    476     JSLock lock(SilenceAssertionsOnly);
    477 
    478     RootObject* rootObject = this->rootObject();
    479     if (!rootObject)
    480         return 0;
    481 
    482     ExecState* exec = rootObject->globalObject()->globalExec();
    483     JNIEnv *env = getJNIEnv();
    484     jobject result = 0;
    485 
    486     // See section 22.7 of 'JavaScript:  The Definitive Guide, 4th Edition',
    487     // figure 22-5.
    488     // number -> java.lang.Double
    489     // string -> java.lang.String
    490     // boolean -> java.lang.Boolean
    491     // Java instance -> Java instance
    492     // Everything else -> JavaJSObject
    493 
    494     if (value.isNumber()) {
    495         jclass JSObjectClass = env->FindClass ("java/lang/Double");
    496         jmethodID constructorID = env->GetMethodID (JSObjectClass, "<init>", "(D)V");
    497         if (constructorID != NULL) {
    498             result = env->NewObject (JSObjectClass, constructorID, (jdouble)value.toNumber(exec));
    499         }
    500     } else if (value.isString()) {
    501         UString stringValue = value.toString(exec);
    502         JNIEnv *env = getJNIEnv();
    503         result = env->NewString ((const jchar *)stringValue.characters(), stringValue.length());
    504     } else if (value.isBoolean()) {
    505         jclass JSObjectClass = env->FindClass ("java/lang/Boolean");
    506         jmethodID constructorID = env->GetMethodID (JSObjectClass, "<init>", "(Z)V");
    507         if (constructorID != NULL) {
    508             result = env->NewObject (JSObjectClass, constructorID, (jboolean)value.toBoolean(exec));
    509         }
    510     }
    511     else {
    512         // Create a JavaJSObject.
    513         jlong nativeHandle;
    514 
    515         if (value.isObject()) {
    516             JSObject* object = asObject(value);
    517 
    518             // We either have a wrapper around a Java instance or a JavaScript
    519             // object.  If we have a wrapper around a Java instance, return that
    520             // instance, otherwise create a new Java JavaJSObject with the JSObject*
    521             // as its nativeHandle.
    522             if (object->inherits(&JavaRuntimeObject::s_info)) {
    523                 JavaRuntimeObject* runtimeObject = static_cast<JavaRuntimeObject*>(object);
    524                 JavaInstance* runtimeInstance = runtimeObject->getInternalJavaInstance();
    525                 if (!runtimeInstance)
    526                     return 0;
    527 
    528                 return runtimeInstance->javaInstance();
    529             } else {
    530                 nativeHandle = ptr_to_jlong(object);
    531                 rootObject->gcProtect(object);
    532             }
    533         } else {
    534         // All other types will result in an undefined object.
    535             nativeHandle = UndefinedHandle;
    536         }
    537 
    538         // Now create the Java JavaJSObject.  Look for the JavaJSObject in its new (Tiger)
    539         // location and in the original Java 1.4.2 location.
    540         jclass JSObjectClass;
    541 
    542         JSObjectClass = env->FindClass ("sun/plugin/javascript/webkit/JSObject");
    543         if (!JSObjectClass) {
    544             env->ExceptionDescribe();
    545             env->ExceptionClear();
    546             JSObjectClass = env->FindClass ("apple/applet/JSObject");
    547         }
    548 
    549         jmethodID constructorID = env->GetMethodID (JSObjectClass, "<init>", "(J)V");
    550         if (constructorID != NULL) {
    551             result = env->NewObject (JSObjectClass, constructorID, nativeHandle);
    552         }
    553     }
    554 
    555     return result;
    556 }
    557 
    558 JSValue JavaJSObject::convertJObjectToValue(ExecState* exec, jobject theObject) const
    559 {
    560     // Instances of netscape.javascript.JSObject get converted back to
    561     // JavaScript objects.  All other objects are wrapped.  It's not
    562     // possible to pass primitive types from the Java to JavaScript.
    563     // See section 22.7 of 'JavaScript:  The Definitive Guide, 4th Edition',
    564     // figure 22-4.
    565     jobject classOfInstance = callJNIMethod<jobject>(theObject, "getClass", "()Ljava/lang/Class;");
    566     if (!classOfInstance) {
    567         JSLock lock(SilenceAssertionsOnly);
    568         return JavaInstance::create(theObject, _rootObject)->createRuntimeObject(exec);
    569     }
    570 
    571     // Only the sun.plugin.javascript.webkit.JSObject has a member called nativeJSObject. This class is
    572     // created above to wrap internal browser objects. The constructor of this class takes the native
    573     // pointer and stores it in this object, so that it can be retrieved below.
    574     jstring className = (jstring)callJNIMethod<jobject>(classOfInstance, "getName", "()Ljava/lang/String;");
    575     if (!className || (strcmp(JavaString(className).utf8(), "sun.plugin.javascript.webkit.JSObject") != 0)) {
    576         JSLock lock(SilenceAssertionsOnly);
    577         return JavaInstance::create(theObject, _rootObject)->createRuntimeObject(exec);
    578     }
    579 
    580     // Pull the nativeJSObject value from the Java instance.  This is a
    581     // pointer to the JSObject.
    582     JNIEnv *env = getJNIEnv();
    583     jfieldID fieldID = env->GetFieldID((jclass)classOfInstance, "nativeJSObject", "J");
    584     if (fieldID == NULL)
    585         return jsUndefined();
    586     jlong nativeHandle = env->GetLongField(theObject, fieldID);
    587     if (nativeHandle == UndefinedHandle)
    588         return jsUndefined();
    589     JSObject *imp = static_cast<JSObject*>(jlong_to_impptr(nativeHandle));
    590     return imp;
    591 }
    592 
    593 void JavaJSObject::getListFromJArray(ExecState* exec, jobjectArray jArray, MarkedArgumentBuffer& list) const
    594 {
    595     JNIEnv *env = getJNIEnv();
    596     int numObjects = jArray ? env->GetArrayLength(jArray) : 0;
    597 
    598     for (int i = 0; i < numObjects; i++) {
    599         jobject anObject = env->GetObjectArrayElement ((jobjectArray)jArray, i);
    600         if (anObject) {
    601             list.append(convertJObjectToValue(exec, anObject));
    602             env->DeleteLocalRef (anObject);
    603         }
    604         else {
    605             env->ExceptionDescribe();
    606             env->ExceptionClear();
    607         }
    608     }
    609 }
    610 
    611 extern "C" {
    612 
    613 jlong KJS_JSCreateNativeJSObject (JNIEnv*, jclass, jstring, jlong nativeHandle, jboolean)
    614 {
    615     JSObjectCallContext context;
    616     context.type = CreateNative;
    617     context.nativeHandle = nativeHandle;
    618     return JavaJSObject::invoke (&context).j;
    619 }
    620 
    621 void KJS_JSObject_JSFinalize (JNIEnv*, jclass, jlong nativeHandle)
    622 {
    623     JSObjectCallContext context;
    624     context.type = Finalize;
    625     context.nativeHandle = nativeHandle;
    626     JavaJSObject::invoke (&context);
    627 }
    628 
    629 jobject KJS_JSObject_JSObjectCall (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring methodName, jobjectArray args, jboolean)
    630 {
    631     JSObjectCallContext context;
    632     context.type = Call;
    633     context.nativeHandle = nativeHandle;
    634     context.string = methodName;
    635     context.args = args;
    636     return JavaJSObject::invoke (&context).l;
    637 }
    638 
    639 jobject KJS_JSObject_JSObjectEval (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jscript, jboolean)
    640 {
    641     JSObjectCallContext context;
    642     context.type = Eval;
    643     context.nativeHandle = nativeHandle;
    644     context.string = jscript;
    645     return JavaJSObject::invoke (&context).l;
    646 }
    647 
    648 jobject KJS_JSObject_JSObjectGetMember (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jname, jboolean)
    649 {
    650     JSObjectCallContext context;
    651     context.type = GetMember;
    652     context.nativeHandle = nativeHandle;
    653     context.string = jname;
    654     return JavaJSObject::invoke (&context).l;
    655 }
    656 
    657 void KJS_JSObject_JSObjectSetMember (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jname, jobject value, jboolean)
    658 {
    659     JSObjectCallContext context;
    660     context.type = SetMember;
    661     context.nativeHandle = nativeHandle;
    662     context.string = jname;
    663     context.value = value;
    664     JavaJSObject::invoke (&context);
    665 }
    666 
    667 void KJS_JSObject_JSObjectRemoveMember (JNIEnv*, jclass, jlong nativeHandle, jstring, jstring jname, jboolean)
    668 {
    669     JSObjectCallContext context;
    670     context.type = RemoveMember;
    671     context.nativeHandle = nativeHandle;
    672     context.string = jname;
    673     JavaJSObject::invoke (&context);
    674 }
    675 
    676 jobject KJS_JSObject_JSObjectGetSlot (JNIEnv*, jclass, jlong nativeHandle, jstring, jint jindex, jboolean)
    677 {
    678     JSObjectCallContext context;
    679     context.type = GetSlot;
    680     context.nativeHandle = nativeHandle;
    681     context.index = jindex;
    682     return JavaJSObject::invoke (&context).l;
    683 }
    684 
    685 void KJS_JSObject_JSObjectSetSlot (JNIEnv*, jclass, jlong nativeHandle, jstring, jint jindex, jobject value, jboolean)
    686 {
    687     JSObjectCallContext context;
    688     context.type = SetSlot;
    689     context.nativeHandle = nativeHandle;
    690     context.index = jindex;
    691     context.value = value;
    692     JavaJSObject::invoke (&context);
    693 }
    694 
    695 jstring KJS_JSObject_JSObjectToString (JNIEnv*, jclass, jlong nativeHandle)
    696 {
    697     JSObjectCallContext context;
    698     context.type = ToString;
    699     context.nativeHandle = nativeHandle;
    700     return (jstring)JavaJSObject::invoke (&context).l;
    701 }
    702 
    703 }
    704 
    705 #endif // ENABLE(JAVA_BRIDGE)
    706