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
48using WebCore::Frame;
49
50using namespace JSC::Bindings;
51using namespace JSC;
52using namespace WebCore;
53
54#define UndefinedHandle 1
55
56static CFRunLoopSourceRef _performJavaScriptSource;
57static CFRunLoopRef _performJavaScriptRunLoop;
58
59// May only be set by dispatchToJavaScriptThread().
60static CFRunLoopSourceRef completionSource;
61
62static 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
74static pthread_once_t javaScriptAccessLockOnce = PTHREAD_ONCE_INIT;
75static pthread_mutex_t javaScriptAccessLock;
76static int javaScriptAccessLockCount = 0;
77
78static 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
88static inline void lockJavaScriptAccess()
89{
90    // Perhaps add deadlock detection?
91    pthread_once(&javaScriptAccessLockOnce, initializeJavaScriptAccessLock);
92    pthread_mutex_lock(&javaScriptAccessLock);
93    javaScriptAccessLockCount++;
94}
95
96static inline void unlockJavaScriptAccess()
97{
98    javaScriptAccessLockCount--;
99    pthread_mutex_unlock(&javaScriptAccessLock);
100}
101
102static 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
138static 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.
157void 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
172static bool isJavaScriptThread()
173{
174    return (_performJavaScriptRunLoop == CFRunLoopGetCurrent());
175}
176
177jvalue 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
263JavaJSObject::JavaJSObject(jlong nativeJSObject)
264{
265    _imp = jlong_to_impptr(nativeJSObject);
266
267    ASSERT(_imp);
268    _rootObject = findProtectingRootObject(_imp);
269    ASSERT(_rootObject);
270}
271
272RootObject* JavaJSObject::rootObject() const
273{
274    return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0;
275}
276
277jobject 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
306jobject 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
333jobject 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
349void 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
365void 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
379jobject 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
396void 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
410jstring 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
425void JavaJSObject::finalize() const
426{
427    if (RootObject* rootObject = this->rootObject())
428        rootObject->gcUnprotect(_imp);
429}
430
431static 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.
448jlong 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
474jobject 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
558JSValue 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
593void 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
611extern "C" {
612
613jlong 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
621void 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
629jobject 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
639jobject 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
648jobject 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
657void 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
667void 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
676jobject 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
685void 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
695jstring 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