mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 901291 - Get WebIDL callbacks working on Workers. r=khuey
This commit is contained in:
parent
f7153b838b
commit
5e1c3cf276
@ -1534,6 +1534,7 @@ public:
|
||||
|
||||
static JSContext *GetCurrentJSContext();
|
||||
static JSContext *GetSafeJSContext();
|
||||
static JSContext *GetDefaultJSContextForThread();
|
||||
|
||||
/**
|
||||
* Case insensitive comparison between two strings. However it only ignores
|
||||
|
@ -1766,6 +1766,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
extern bool IsCurrentThreadRunningChromeWorker();
|
||||
extern JSContext* GetCurrentThreadJSContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5197,6 +5198,17 @@ nsContentUtils::GetSafeJSContext()
|
||||
return sXPConnect->GetSafeJSContext();
|
||||
}
|
||||
|
||||
/* static */
|
||||
JSContext *
|
||||
nsContentUtils::GetDefaultJSContextForThread()
|
||||
{
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
return GetSafeJSContext();
|
||||
} else {
|
||||
return workers::GetCurrentThreadJSContext();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsContentUtils::ASCIIToLower(nsAString& aStr)
|
||||
|
@ -673,6 +673,28 @@ NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
|
||||
bool aAllowNativeWrapper)
|
||||
{
|
||||
nsresult rv;
|
||||
// Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need
|
||||
// on all threads.
|
||||
nsWrapperCache *cache = aHelper.GetWrapperCache();
|
||||
|
||||
if (cache && cache->IsDOMBinding()) {
|
||||
JS::RootedObject obj(aCx, cache->GetWrapper());
|
||||
if (!obj) {
|
||||
obj = cache->WrapObject(aCx, aScope);
|
||||
}
|
||||
|
||||
if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, obj.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj) {
|
||||
*aRetval = JS::ObjectValue(*obj);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!XPCConvert::NativeInterface2JSObject(aRetval, NULL, aHelper, aIID,
|
||||
NULL, aAllowNativeWrapper, &rv)) {
|
||||
// I can't tell if NativeInterface2JSObject throws JS exceptions
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -49,7 +50,11 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
, mCompartment(aCompartment)
|
||||
, mErrorResult(aRv)
|
||||
, mExceptionHandling(aExceptionHandling)
|
||||
, mIsMainThread(NS_IsMainThread())
|
||||
{
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::EnterMicroTask();
|
||||
}
|
||||
// We need to produce a useful JSContext here. Ideally one that the callback
|
||||
// is in some sense associated with, so that we can sort of treat it as a
|
||||
// "script entry point". Though once we actually have script entry points,
|
||||
@ -58,46 +63,50 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
|
||||
// First, find the real underlying callback.
|
||||
JSObject* realCallback = js::UncheckedUnwrap(aCallback);
|
||||
|
||||
// Now get the nsIScriptGlobalObject for this callback.
|
||||
JSContext* cx = nullptr;
|
||||
nsIScriptContext* ctx = nullptr;
|
||||
nsIScriptGlobalObject* sgo = nsJSUtils::GetStaticScriptGlobal(realCallback);
|
||||
if (sgo) {
|
||||
// Make sure that if this is a window it's the current inner, since the
|
||||
// nsIScriptContext and hence JSContext are associated with the outer
|
||||
// window. Which means that if someone holds on to a function from a
|
||||
// now-unloaded document we'd have the new document as the script entry
|
||||
// point...
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(sgo);
|
||||
if (win) {
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
nsPIDOMWindow* outer = win->GetOuterWindow();
|
||||
if (!outer || win != outer->GetCurrentInnerWindow()) {
|
||||
// Just bail out from here
|
||||
return;
|
||||
|
||||
if (mIsMainThread) {
|
||||
// Now get the nsIScriptGlobalObject for this callback.
|
||||
nsIScriptContext* ctx = nullptr;
|
||||
nsIScriptGlobalObject* sgo = nsJSUtils::GetStaticScriptGlobal(realCallback);
|
||||
if (sgo) {
|
||||
// Make sure that if this is a window it's the current inner, since the
|
||||
// nsIScriptContext and hence JSContext are associated with the outer
|
||||
// window. Which means that if someone holds on to a function from a
|
||||
// now-unloaded document we'd have the new document as the script entry
|
||||
// point...
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(sgo);
|
||||
if (win) {
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
nsPIDOMWindow* outer = win->GetOuterWindow();
|
||||
if (!outer || win != outer->GetCurrentInnerWindow()) {
|
||||
// Just bail out from here
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if not a window at all, just press on
|
||||
|
||||
ctx = sgo->GetContext();
|
||||
if (ctx) {
|
||||
// We don't check whether scripts are enabled on ctx, because
|
||||
// CheckFunctionAccess will do that anyway... and because we ignore them
|
||||
// being disabled if the callee is system.
|
||||
cx = ctx->GetNativeContext();
|
||||
}
|
||||
}
|
||||
// if not a window at all, just press on
|
||||
|
||||
ctx = sgo->GetContext();
|
||||
if (ctx) {
|
||||
// We don't check whether scripts are enabled on ctx, because
|
||||
// CheckFunctionAccess will do that anyway... and because we ignore them
|
||||
// being disabled if the callee is system.
|
||||
cx = ctx->GetNativeContext();
|
||||
if (!cx) {
|
||||
// We didn't manage to hunt down a script global to work with. Just fall
|
||||
// back on using the safe context.
|
||||
cx = nsContentUtils::GetSafeJSContext();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cx) {
|
||||
// We didn't manage to hunt down a script global to work with. Just fall
|
||||
// back on using the safe context.
|
||||
cx = nsContentUtils::GetSafeJSContext();
|
||||
// Make sure our JSContext is pushed on the stack.
|
||||
mCxPusher.Push(cx);
|
||||
} else {
|
||||
cx = workers::GetCurrentThreadJSContext();
|
||||
}
|
||||
|
||||
// Make sure our JSContext is pushed on the stack.
|
||||
mCxPusher.Push(cx);
|
||||
|
||||
// Unmark the callable, and stick it in a Rooted before it can go gray again.
|
||||
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
||||
// until here it do the unmark. This allows us to order the following two
|
||||
@ -109,16 +118,18 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
|
||||
JS::ExposeObjectToActiveJS(aCallback);
|
||||
mRootedCallable.construct(cx, aCallback);
|
||||
|
||||
// Check that it's ok to run this callback at all.
|
||||
// FIXME: Bug 807371: we want a less silly check here.
|
||||
// Make sure to unwrap aCallback before passing it in, because
|
||||
// getting principals from wrappers is silly.
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->
|
||||
CheckFunctionAccess(cx, js::UncheckedUnwrap(aCallback), nullptr);
|
||||
if (mIsMainThread) {
|
||||
// Check that it's ok to run this callback at all.
|
||||
// FIXME: Bug 807371: we want a less silly check here.
|
||||
// Make sure to unwrap aCallback before passing it in, because
|
||||
// getting principals from wrappers is silly.
|
||||
nsresult rv = nsContentUtils::GetSecurityManager()->
|
||||
CheckFunctionAccess(cx, js::UncheckedUnwrap(aCallback), nullptr);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// Security check failed. We're done here.
|
||||
return;
|
||||
if (NS_FAILED(rv)) {
|
||||
// Security check failed. We're done here.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Enter the compartment of our callback, so we can actually work with it.
|
||||
@ -204,12 +215,19 @@ CallbackObject::CallSetup::~CallSetup()
|
||||
|
||||
// Popping an nsCxPusher is safe even if it never got pushed.
|
||||
mCxPusher.Pop();
|
||||
|
||||
// It is important that this is the last thing we do, after leaving the
|
||||
// compartment and popping the context.
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::LeaveMicroTask();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
CallbackObjectHolderBase::ToXPCOMCallback(CallbackObject* aCallback,
|
||||
const nsIID& aIID) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!aCallback) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -151,10 +151,6 @@ protected:
|
||||
|
||||
// And now members whose construction/destruction order we need to control.
|
||||
|
||||
// Put our nsAutoMicrotask first, so it gets destroyed after everything else
|
||||
// is gone
|
||||
nsAutoMicroTask mMt;
|
||||
|
||||
nsCxPusher mCxPusher;
|
||||
|
||||
// Constructed the rooter within the scope of mCxPusher above, so that it's
|
||||
@ -172,6 +168,7 @@ protected:
|
||||
ErrorResult& mErrorResult;
|
||||
const ExceptionHandling mExceptionHandling;
|
||||
uint32_t mSavedJSContextOptions;
|
||||
const bool mIsMainThread;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -827,7 +827,7 @@ XPCConvert::NativeInterface2JSObject(jsval* d,
|
||||
return false;
|
||||
|
||||
// First, see if this object supports the wrapper cache.
|
||||
// Note: If |cache->IsProxy()| is true, then it means that the object
|
||||
// Note: If |cache->IsDOMBinding()| is true, then it means that the object
|
||||
// implementing it doesn't want a wrapped native as its JS Object, but
|
||||
// instead it provides its own proxy object. In that case, the object
|
||||
// to use is found as cache->GetWrapper(). If that is null, then the
|
||||
@ -862,7 +862,7 @@ XPCConvert::NativeInterface2JSObject(jsval* d,
|
||||
if (cpow) {
|
||||
if (!JS_WrapObject(cx, cpow.address()))
|
||||
return false;
|
||||
*d = OBJECT_TO_JSVAL(cpow);
|
||||
*d = JS::ObjectValue(*cpow);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user