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