📄 jni_jsobject.mm
字号:
/* * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "jni_jsobject.h"#if ENABLE(MAC_JAVA_BRIDGE)#include "Frame.h"#include "WebCoreFrameView.h"#include "jni_runtime.h"#include "jni_utility.h"#include "ScriptController.h"#include "runtime_object.h"#include "runtime_root.h"#include <interpreter/CallFrame.h>#include <runtime/JSGlobalObject.h>#include <runtime/JSLock.h>#include <runtime/Completion.h>#include <runtime/Completion.h>#include <wtf/Assertions.h>#include <parser/SourceProvider.h>using WebCore::Frame;using namespace JSC::Bindings;using namespace JSC;#ifdef NDEBUG#define JS_LOG(formatAndArgs...) ((void)0)#else#define JS_LOG(formatAndArgs...) { \ fprintf (stderr, "%s(%p,%p): ", __PRETTY_FUNCTION__, _performJavaScriptRunLoop, CFRunLoopGetCurrent()); \ fprintf(stderr, formatAndArgs); \}#endif#define UndefinedHandle 1static CFRunLoopSourceRef _performJavaScriptSource;static CFRunLoopRef _performJavaScriptRunLoop;// May only be set by dispatchToJavaScriptThread().static CFRunLoopSourceRef completionSource;static void completedJavaScriptAccess (void *i){ assert (CFRunLoopGetCurrent() != _performJavaScriptRunLoop); JSObjectCallContext *callContext = (JSObjectCallContext *)i; CFRunLoopRef runLoop = (CFRunLoopRef)callContext->originatingLoop; assert (CFRunLoopGetCurrent() == runLoop); CFRunLoopStop(runLoop);}static pthread_once_t javaScriptAccessLockOnce = PTHREAD_ONCE_INIT;static pthread_mutex_t javaScriptAccessLock;static int javaScriptAccessLockCount = 0;static void initializeJavaScriptAccessLock(){ pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&javaScriptAccessLock, &attr);}static inline void lockJavaScriptAccess(){ // Perhaps add deadlock detection? pthread_once(&javaScriptAccessLockOnce, initializeJavaScriptAccessLock); pthread_mutex_lock(&javaScriptAccessLock); javaScriptAccessLockCount++;}static inline void unlockJavaScriptAccess(){ javaScriptAccessLockCount--; pthread_mutex_unlock(&javaScriptAccessLock);}static void dispatchToJavaScriptThread(JSObjectCallContext *context){ // This lock guarantees that only one thread can invoke // at a time, and also guarantees that completionSource; // won't get clobbered. lockJavaScriptAccess(); CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent(); assert (currentRunLoop != _performJavaScriptRunLoop); // Setup a source to signal once the invocation of the JavaScript // call completes. // // FIXME: This could be a potential performance issue. Creating and // adding run loop sources is expensive. We could create one source // per thread, as needed, instead. context->originatingLoop = currentRunLoop; CFRunLoopSourceContext sourceContext = {0, context, NULL, NULL, NULL, NULL, NULL, NULL, NULL, completedJavaScriptAccess}; completionSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext); CFRunLoopAddSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode); // Wakeup JavaScript access thread and make it do it's work. CFRunLoopSourceSignal(_performJavaScriptSource); if (CFRunLoopIsWaiting(_performJavaScriptRunLoop)) CFRunLoopWakeUp(_performJavaScriptRunLoop); // Wait until the JavaScript access thread is done. CFRunLoopRun (); CFRunLoopRemoveSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode); CFRelease (completionSource); unlockJavaScriptAccess();}static void performJavaScriptAccess(void*){ assert (CFRunLoopGetCurrent() == _performJavaScriptRunLoop); // Dispatch JavaScript calls here. CFRunLoopSourceContext sourceContext; CFRunLoopSourceGetContext (completionSource, &sourceContext); JSObjectCallContext *callContext = (JSObjectCallContext *)sourceContext.info; CFRunLoopRef originatingLoop = callContext->originatingLoop; JavaJSObject::invoke (callContext); // Signal the originating thread that we're done. CFRunLoopSourceSignal (completionSource); if (CFRunLoopIsWaiting(originatingLoop)) CFRunLoopWakeUp(originatingLoop);}// Must be called from the thread that will be used to access JavaScript.void JavaJSObject::initializeJNIThreading() { // Should only be called once. ASSERT(!_performJavaScriptRunLoop); // Assume that we can retain this run loop forever. It'll most // likely (always?) be the main loop. _performJavaScriptRunLoop = (CFRunLoopRef)CFRetain(CFRunLoopGetCurrent()); // Setup a source the other threads can use to signal the _runLoop // thread that a JavaScript call needs to be invoked. CFRunLoopSourceContext sourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, performJavaScriptAccess}; _performJavaScriptSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext); CFRunLoopAddSource(_performJavaScriptRunLoop, _performJavaScriptSource, kCFRunLoopDefaultMode);}static bool isJavaScriptThread(){ return (_performJavaScriptRunLoop == CFRunLoopGetCurrent());}jvalue JavaJSObject::invoke(JSObjectCallContext *context){ jvalue result; bzero ((void *)&result, sizeof(jvalue)); if (!isJavaScriptThread()) { // Send the call context to the thread that is allowed to // call JavaScript. dispatchToJavaScriptThread(context); result = context->result; } else { jlong nativeHandle = context->nativeHandle; if (nativeHandle == UndefinedHandle || nativeHandle == 0) { return result; } if (context->type == CreateNative) { result.j = JavaJSObject::createNative(nativeHandle); } else { JSObject *imp = jlong_to_impptr(nativeHandle); if (!findProtectingRootObject(imp)) { fprintf (stderr, "%s:%d: Attempt to access JavaScript from destroyed applet, type %d.\n", __FILE__, __LINE__, context->type); return result; } switch (context->type){ case Call: { result.l = JavaJSObject(nativeHandle).call(context->string, context->args); break; } case Eval: { result.l = JavaJSObject(nativeHandle).eval(context->string); break; } case GetMember: { result.l = JavaJSObject(nativeHandle).getMember(context->string); break; } case SetMember: { JavaJSObject(nativeHandle).setMember(context->string, context->value); break; } case RemoveMember: { JavaJSObject(nativeHandle).removeMember(context->string); break; } case GetSlot: { result.l = JavaJSObject(nativeHandle).getSlot(context->index); break; } case SetSlot: { JavaJSObject(nativeHandle).setSlot(context->index, context->value); break; } case ToString: { result.l = (jobject) JavaJSObject(nativeHandle).toString(); break; } case Finalize: { JavaJSObject(nativeHandle).finalize(); break; } default: { fprintf (stderr, "%s: invalid JavaScript call\n", __PRETTY_FUNCTION__); } } } context->result = result; } return result;}JavaJSObject::JavaJSObject(jlong nativeJSObject){ _imp = jlong_to_impptr(nativeJSObject); ASSERT(_imp); _rootObject = findProtectingRootObject(_imp); ASSERT(_rootObject);}RootObject* JavaJSObject::rootObject() const{ return _rootObject && _rootObject->isValid() ? _rootObject.get() : 0; }jobject JavaJSObject::call(jstring methodName, jobjectArray args) const{ JS_LOG ("methodName = %s\n", JavaString(methodName).UTF8String()); RootObject* rootObject = this->rootObject(); if (!rootObject) return 0; // Lookup the function object. ExecState* exec = rootObject->globalObject()->globalExec(); JSLock lock(false); Identifier identifier(exec, JavaString(methodName)); JSValuePtr function = _imp->get(exec, identifier); CallData callData; CallType callType = function.getCallData(callData); if (callType == CallTypeNone) return 0; // Call the function object. ArgList argList; getListFromJArray(exec, args, argList); rootObject->globalObject()->globalData()->timeoutChecker.start(); JSValuePtr result = JSC::call(exec, function, callType, callData, _imp, argList); rootObject->globalObject()->globalData()->timeoutChecker.stop(); return convertValueToJObject(result);}jobject JavaJSObject::eval(jstring script) const{ JS_LOG ("script = %s\n", JavaString(script).UTF8String()); JSValuePtr result; JSLock lock(false); RootObject* rootObject = this->rootObject(); if (!rootObject) return 0; rootObject->globalObject()->globalData()->timeoutChecker.start(); Completion completion = JSC::evaluate(rootObject->globalObject()->globalExec(), rootObject->globalObject()->globalScopeChain(), makeSource(JavaString(script))); rootObject->globalObject()->globalData()->timeoutChecker.stop(); ComplType type = completion.complType(); if (type == Normal) { result = completion.value(); if (!result) result = jsUndefined(); } else result = jsUndefined(); return convertValueToJObject (result);}jobject JavaJSObject::getMember(jstring memberName) const{ JS_LOG ("(%p) memberName = %s\n", _imp, JavaString(memberName).UTF8String()); RootObject* rootObject = this->rootObject(); if (!rootObject) return 0; ExecState* exec = rootObject->globalObject()->globalExec(); JSLock lock(false); JSValuePtr result = _imp->get(exec, Identifier(exec, JavaString(memberName))); return convertValueToJObject(result);}void JavaJSObject::setMember(jstring memberName, jobject value) const{ JS_LOG ("memberName = %s, value = %p\n", JavaString(memberName).UTF8String(), value); RootObject* rootObject = this->rootObject(); if (!rootObject) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -