зеркало из https://github.com/mozilla/gecko-dev.git
Bug 984458 - b. Add threading support to NativeJSContainer; r=blassey
This commit is contained in:
Родитель
d291d3bec4
Коммит
1447ea535f
|
@ -10,6 +10,10 @@ import org.mozilla.gecko.mozglue.JNITarget;
|
|||
/**
|
||||
* NativeJSContainer is a wrapper around the SpiderMonkey JSAPI to make it possible to
|
||||
* access Javascript objects in Java.
|
||||
*
|
||||
* A container must only be used on the thread it is attached to. To use it on another
|
||||
* thread, call {@link #clone()} to make a copy, and use the copy on the other thread.
|
||||
* When a copy is first used, it becomes attached to the thread using it.
|
||||
*/
|
||||
@JNITarget
|
||||
public final class NativeJSContainer extends NativeJSObject
|
||||
|
@ -20,6 +24,13 @@ public final class NativeJSContainer extends NativeJSObject
|
|||
mNativeObject = nativeObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a copy of this container for use by another thread. When the copy is first used,
|
||||
* it becomes attached to the thread using it.
|
||||
*/
|
||||
@Override
|
||||
public native NativeJSContainer clone();
|
||||
|
||||
/**
|
||||
* Dispose all associated native objects. Subsequent use of any objects derived from
|
||||
* this container will throw a NullPointerException.
|
||||
|
|
|
@ -571,6 +571,25 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv * ar
|
|||
|
||||
#ifdef JNI_STUBS
|
||||
|
||||
typedef jobject (*Java_org_mozilla_gecko_util_NativeJSContainer_clone_t)(JNIEnv *, jobject);
|
||||
static Java_org_mozilla_gecko_util_NativeJSContainer_clone_t f_Java_org_mozilla_gecko_util_NativeJSContainer_clone;
|
||||
extern "C" NS_EXPORT jobject JNICALL
|
||||
Java_org_mozilla_gecko_util_NativeJSContainer_clone(JNIEnv * arg0, jobject arg1) {
|
||||
if (!f_Java_org_mozilla_gecko_util_NativeJSContainer_clone) {
|
||||
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||
"JNI Function called before it was loaded");
|
||||
return nullptr;
|
||||
}
|
||||
return f_Java_org_mozilla_gecko_util_NativeJSContainer_clone(arg0, arg1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JNI_BINDINGS
|
||||
xul_dlsym("Java_org_mozilla_gecko_util_NativeJSContainer_clone", &f_Java_org_mozilla_gecko_util_NativeJSContainer_clone);
|
||||
#endif
|
||||
|
||||
#ifdef JNI_STUBS
|
||||
|
||||
typedef void (*Java_org_mozilla_gecko_util_NativeJSContainer_dispose_t)(JNIEnv *, jobject);
|
||||
static Java_org_mozilla_gecko_util_NativeJSContainer_dispose_t f_Java_org_mozilla_gecko_util_NativeJSContainer_dispose;
|
||||
extern "C" NS_EXPORT void JNICALL
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "NativeJSContainer.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include "prthread.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
@ -60,6 +61,58 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static jobject CloneInstance(JNIEnv* env, jobject instance) {
|
||||
NativeJSContainer* const container = FromInstance(env, instance);
|
||||
if (!container || !container->EnsureObject(env)) {
|
||||
return nullptr;
|
||||
}
|
||||
JSContext* const cx = container->mThreadContext;
|
||||
JS::RootedObject object(cx, container->mJSObject);
|
||||
MOZ_ASSERT(object);
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (!buffer.write(cx, JS::RootedValue(cx, JS::ObjectValue(*object)))) {
|
||||
AndroidBridge::ThrowException(env,
|
||||
"java/lang/UnsupportedOperationException",
|
||||
"Cannot serialize object");
|
||||
return nullptr;
|
||||
}
|
||||
return CreateInstance(env, new NativeJSContainer(cx, Move(buffer)));
|
||||
}
|
||||
|
||||
// Make sure we have a JSObject and deserialize if necessary/possible
|
||||
bool EnsureObject(JNIEnv* env) {
|
||||
if (mJSObject) {
|
||||
if (PR_GetCurrentThread() != mThread) {
|
||||
AndroidBridge::ThrowException(env,
|
||||
"java/lang/IllegalThreadStateException",
|
||||
"Using NativeJSObject off its thread");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!SwitchContextToCurrentThread()) {
|
||||
AndroidBridge::ThrowException(env,
|
||||
"java/lang/IllegalThreadStateException",
|
||||
"Not available for this thread");
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::RootedValue value(mThreadContext);
|
||||
MOZ_ASSERT(mBuffer.data());
|
||||
MOZ_ALWAYS_TRUE(mBuffer.read(mThreadContext, &value));
|
||||
if (value.isObject()) {
|
||||
mJSObject = &value.toObject();
|
||||
}
|
||||
if (!mJSObject) {
|
||||
AndroidBridge::ThrowException(env,
|
||||
"java/lang/IllegalStateException", "Cannot deserialize data");
|
||||
return false;
|
||||
}
|
||||
mBuffer.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static jclass jNativeJSContainer;
|
||||
static jfieldID jContainerNativeObject;
|
||||
|
@ -77,16 +130,38 @@ private:
|
|||
return newObject;
|
||||
}
|
||||
|
||||
JSContext* const mContext;
|
||||
// Root JS object
|
||||
const JS::Heap<JSObject*> mJSObject;
|
||||
// Thread that the object is valid on
|
||||
PRThread* mThread;
|
||||
// Context that the object is valid in
|
||||
JSContext* mThreadContext;
|
||||
// Deserialized object, or nullptr if object is in serialized form
|
||||
JS::Heap<JSObject*> mJSObject;
|
||||
// Serialized object, or empty if object is in deserialized form
|
||||
JSAutoStructuredCloneBuffer mBuffer;
|
||||
|
||||
// Create a new container containing the given object
|
||||
// Create a new container containing the given deserialized object
|
||||
NativeJSContainer(JSContext* cx, JS::HandleObject object)
|
||||
: mContext(cx)
|
||||
: mThread(PR_GetCurrentThread())
|
||||
, mThreadContext(cx)
|
||||
, mJSObject(object)
|
||||
{
|
||||
}
|
||||
|
||||
// Create a new container containing the given serialized object
|
||||
NativeJSContainer(JSContext* cx, JSAutoStructuredCloneBuffer&& buffer)
|
||||
: mThread(PR_GetCurrentThread())
|
||||
, mThreadContext(cx)
|
||||
, mBuffer(Forward<JSAutoStructuredCloneBuffer>(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool SwitchContextToCurrentThread() {
|
||||
PRThread* const currentThread = PR_GetCurrentThread();
|
||||
if (currentThread == mThread) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
jclass NativeJSContainer::jNativeJSContainer = 0;
|
||||
|
@ -111,4 +186,11 @@ Java_org_mozilla_gecko_util_NativeJSContainer_dispose(JNIEnv* env, jobject insta
|
|||
NativeJSContainer::DisposeInstance(env, instance);
|
||||
}
|
||||
|
||||
NS_EXPORT jobject JNICALL
|
||||
Java_org_mozilla_gecko_util_NativeJSContainer_clone(JNIEnv* env, jobject instance)
|
||||
{
|
||||
MOZ_ASSERT(env);
|
||||
return NativeJSContainer::CloneInstance(env, instance);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
Загрузка…
Ссылка в новой задаче