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