diff --git a/dom/events/EventDispatcher.cpp b/dom/events/EventDispatcher.cpp index 9dfb644379bc..263d75ab8b47 100644 --- a/dom/events/EventDispatcher.cpp +++ b/dom/events/EventDispatcher.cpp @@ -25,6 +25,7 @@ #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" #include "mozilla/InternalMutationEvent.h" +#include "mozilla/ipc/MessageChannel.h" #include "mozilla/MiscEvents.h" #include "mozilla/MouseEvents.h" #include "mozilla/TextEvents.h" @@ -400,6 +401,10 @@ EventDispatcher::Dispatch(nsISupports* aTarget, NS_ERROR_DOM_INVALID_STATE_ERR); NS_ASSERTION(!aTargets || !aEvent->message, "Wrong parameters!"); +#ifdef NIGHTLY_BUILD + MOZ_RELEASE_ASSERT(!mozilla::ipc::ProcessingUrgentMessages()); +#endif + // If we're dispatching an already created DOMEvent object, make // sure it is initialized! // If aTargets is non-null, the event isn't going to be dispatched. diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 41e475da12ed..0455454b2d27 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -36,6 +36,8 @@ struct RunnableMethodTraits DebugAbort(__FILE__, __LINE__, #_cond,## __VA_ARGS__); \ } while (0) +static uintptr_t gDispatchingUrgentMessageCount; + namespace mozilla { namespace ipc { @@ -1099,9 +1101,13 @@ MessageChannel::DispatchUrgentMessage(const Message& aMsg) Message *reply = nullptr; + MOZ_ASSERT(NS_IsMainThread()); + + gDispatchingUrgentMessageCount++; mDispatchingUrgentMessageCount++; Result rv = mListener->OnCallReceived(aMsg, reply); mDispatchingUrgentMessageCount--; + gDispatchingUrgentMessageCount--; if (!MaybeHandleError(rv, "DispatchUrgentMessage")) { delete reply; @@ -1752,5 +1758,11 @@ MessageChannel::DumpInterruptStack(const char* const pfx) const } } +bool +ProcessingUrgentMessages() +{ + return gDispatchingUrgentMessageCount > 0; +} + } // ipc } // mozilla diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index dd771406d0e3..11123b1f3291 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -641,6 +641,9 @@ class MessageChannel : HasResultCodes bool mAbortOnError; }; +bool +ProcessingUrgentMessages(); + } // namespace ipc } // namespace mozilla diff --git a/js/ipc/JavaScriptChild.cpp b/js/ipc/JavaScriptChild.cpp index 42921787544f..a8d65997637c 100644 --- a/js/ipc/JavaScriptChild.cpp +++ b/js/ipc/JavaScriptChild.cpp @@ -8,10 +8,12 @@ #include "JavaScriptChild.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/ipc/MessageChannel.h" #include "nsContentUtils.h" #include "xpcprivate.h" #include "jsfriendapi.h" #include "nsCxPusher.h" +#include "AccessCheck.h" using namespace JS; using namespace mozilla; @@ -19,6 +21,17 @@ using namespace mozilla::jsipc; using mozilla::AutoSafeJSContext; +#ifdef NIGHTLY_BUILD +static void +UrgentMessageCheck(JSContext *cx, HandleScript script) +{ + // We're only allowed to enter chrome JS code while processing urgent + // messages. + if (ipc::ProcessingUrgentMessages()) + MOZ_RELEASE_ASSERT(xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))); +} +#endif + static void FinalizeChild(JSFreeOp *fop, JSFinalizeStatus status, bool isCompartment, void *data) { @@ -31,6 +44,9 @@ JavaScriptChild::JavaScriptChild(JSRuntime *rt) : JavaScriptShared(rt), JavaScriptBase(rt) { +#ifdef NIGHTLY_BUILD + js::SetAssertOnScriptEntryHook(rt, UrgentMessageCheck); +#endif } JavaScriptChild::~JavaScriptChild() diff --git a/js/ipc/moz.build b/js/ipc/moz.build index d13d32f43bcf..4d322e7762d2 100644 --- a/js/ipc/moz.build +++ b/js/ipc/moz.build @@ -30,5 +30,6 @@ LOCAL_INCLUDES += [ '/js/ipc', '/js/public', '/js/xpconnect/src', + '/js/xpconnect/wrappers', ] diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 37f61eb3aee7..ab5d475e3f8e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -63,6 +63,14 @@ js::ForgetSourceHook(JSRuntime *rt) return Move(rt->sourceHook); } +#ifdef NIGHTLY_BUILD +JS_FRIEND_API(void) +js::SetAssertOnScriptEntryHook(JSRuntime *rt, AssertOnScriptEntryHook hook) +{ + rt->assertOnScriptEntryHook_ = hook; +} +#endif + JS_FRIEND_API(void) JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index ba649c413aa8..70f63ecd58b7 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -422,6 +422,13 @@ SetSourceHook(JSRuntime *rt, mozilla::UniquePtr hook); extern JS_FRIEND_API(mozilla::UniquePtr) ForgetSourceHook(JSRuntime *rt); +#ifdef NIGHTLY_BUILD +typedef void (*AssertOnScriptEntryHook)(JSContext *cx, JS::HandleScript script); + +extern JS_FRIEND_API(void) +SetAssertOnScriptEntryHook(JSRuntime *rt, AssertOnScriptEntryHook hook); +#endif + extern JS_FRIEND_API(JS::Zone *) GetCompartmentZone(JSCompartment *comp); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index b33b05678609..9a54519a7ef9 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -374,6 +374,11 @@ js::RunScript(JSContext *cx, RunState &state) { JS_CHECK_RECURSION(cx, return false); +#ifdef NIGHTLY_BUILD + if (AssertOnScriptEntryHook hook = cx->runtime()->assertOnScriptEntryHook_) + (*hook)(cx, state.script()); +#endif + SPSEntryMarker marker(cx->runtime(), state.script()); state.script()->ensureNonLazyCanonicalFunction(cx); diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 45ba88091ffe..ad38683ff761 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -203,7 +203,7 @@ class RunState return (GeneratorState *)this; } - JSScript *script() const { return script_; } + JS::HandleScript script() const { return script_; } virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx) = 0; virtual void setReturnValue(Value v) = 0; diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index ad7195dada68..6a8a4c3aa7c5 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -172,6 +172,9 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime) negativeInfinityValue(DoubleValue(NegativeInfinity())), positiveInfinityValue(DoubleValue(PositiveInfinity())), emptyString(nullptr), +#ifdef NIGHTLY_BUILD + assertOnScriptEntryHook_(nullptr), +#endif debugMode(false), spsProfiler(thisFromCtor()), profilingScripts(false), diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 5608ae100017..9364cc13dc11 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -993,6 +993,10 @@ struct JSRuntime : public JS::shadow::Runtime, mozilla::UniquePtr sourceHook; +#ifdef NIGHTLY_BUILD + js::AssertOnScriptEntryHook assertOnScriptEntryHook_; +#endif + /* If true, new compartments are initially in debug mode. */ bool debugMode; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index fbb22843de9a..8654a119a9a1 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -4341,6 +4341,8 @@ inline static mozilla::HangMonitor::ActivityType ActivityTypeForMessage(UINT msg // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + MOZ_RELEASE_ASSERT(!ipc::ProcessingUrgentMessages()); + HangMonitor::NotifyActivity(ActivityTypeForMessage(msg)); return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam); diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index f3f7fe2d1ade..a5e28d8db577 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -25,6 +25,7 @@ #include "nsIObserverService.h" #include "mozilla/HangMonitor.h" #include "mozilla/IOInterposer.h" +#include "mozilla/ipc/MessageChannel.h" #include "mozilla/Services.h" #include "nsXPCOMPrivate.h" #include "mozilla/ChaosMode.h" @@ -686,6 +687,9 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) { LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, aMayWait, mRunningEvent)); + // If we're on the main thread, we shouldn't be dispatching CPOWs. + MOZ_RELEASE_ASSERT(mIsMainThread != MAIN_THREAD || !ipc::ProcessingUrgentMessages()); + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) { return NS_ERROR_NOT_SAME_THREAD; }