diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index c5ed38dc27..b0732ee51f 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -224,6 +224,7 @@ #include "mozilla/dom/PrimitiveConversions.h" #include "mozilla/dom/WindowBinding.h" #include "nsITabChild.h" +#include "mozilla/dom/ModuleScript.h" #include "mozilla/dom/MediaQueryList.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/NavigatorBinding.h" @@ -12937,9 +12938,6 @@ nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout, RefPtr callback = handler->GetCallback(); if (!callback) { - // Evaluate the timeout expression. - const nsAString& script = handler->GetHandlerText(); - const char* filename = nullptr; uint32_t lineNo = 0, dummyColumn = 0; handler->GetLocation(&filename, &lineNo, &dummyColumn); @@ -12950,9 +12948,22 @@ nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout, AutoEntryScript aes(this, reason, true); JS::CompileOptions options(aes.cx()); options.setFileAndLine(filename, lineNo).setVersion(JSVERSION_DEFAULT); + options.setNoScriptRval(true); JS::Rooted global(aes.cx(), FastGetGlobalJSObject()); - nsresult rv = - nsJSUtils::EvaluateString(aes.cx(), script, global, options); + nsresult rv; + { + nsJSUtils::ExecutionContext exec(aes.cx(), global); + rv = exec.Compile(options, handler->GetHandlerText()); + + if (rv == NS_OK) { + LoadedScript* initiatingScript = handler->GetInitiatingScript(); + if (initiatingScript) { + initiatingScript->AssociateWithScript(exec.GetScript()); + } + + rv = exec.ExecScript(); + } + } if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) { abortIntervalHandler = true; } diff --git a/dom/base/nsIScriptTimeoutHandler.h b/dom/base/nsIScriptTimeoutHandler.h index 9679f70478..b1472ad748 100644 --- a/dom/base/nsIScriptTimeoutHandler.h +++ b/dom/base/nsIScriptTimeoutHandler.h @@ -14,6 +14,7 @@ namespace mozilla { namespace dom { class Function; +class LoadedScript; } // namespace dom } // namespace mozilla @@ -44,6 +45,9 @@ public: // If we have a Function, get the arguments for passing to it. virtual const nsTArray& GetArgs() = 0; + + // If we have an expression, get the initiating script. + virtual mozilla::dom::LoadedScript* GetInitiatingScript() = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptTimeoutHandler, diff --git a/dom/base/nsJSTimeoutHandler.cpp b/dom/base/nsJSTimeoutHandler.cpp index a370fe03f7..5c836694ae 100644 --- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -10,6 +10,7 @@ #include "mozilla/Likely.h" #include "mozilla/Maybe.h" #include "mozilla/dom/FunctionBinding.h" +#include "mozilla/dom/ModuleScript.h" #include "nsAXPCNativeCallContext.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" @@ -44,6 +45,7 @@ public: nsTArray>&& aArguments, ErrorResult& aError); nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow* aWindow, + LoadedScript* aInitiatingScript, const nsAString& aExpression, bool* aAllowEval, ErrorResult& aError); nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate, @@ -77,6 +79,10 @@ public: *aColumn = mColumn; } + virtual LoadedScript* GetInitiatingScript() override { + return mInitiatingScript; + } + virtual void MarkForCC() override { if (mFunction) { @@ -104,6 +110,9 @@ private: // it should be used, else use mExpr. nsString mExpr; RefPtr mFunction; + + // Initiating script for use when evaluating mExpr on the main thread. + RefPtr mInitiatingScript; }; @@ -112,6 +121,8 @@ private: NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSScriptTimeoutHandler) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFunction) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mInitiatingScript) tmp->ReleaseJSObjects(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler) @@ -151,6 +162,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler) if (tmp->mFunction) { NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFunction) } + if (tmp->mInitiatingScript) { + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInitiatingScript) + } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSScriptTimeoutHandler) @@ -243,12 +257,14 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx, nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow, + LoadedScript* aInitiatingScript, const nsAString& aExpression, bool* aAllowEval, ErrorResult& aError) : mLineNo(0) , mColumn(0) , mExpr(aExpression) + , mInitiatingScript(aInitiatingScript) { if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) { // This window was already closed, or never properly initialized, @@ -352,9 +368,11 @@ already_AddRefed NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow, const nsAString& aExpression, ErrorResult& aError) { + LoadedScript* script = ScriptLoader::GetActiveScript(aCx); + bool allowEval = false; RefPtr handler = - new nsJSScriptTimeoutHandler(aCx, aWindow, aExpression, &allowEval, aError); + new nsJSScriptTimeoutHandler(aCx, aWindow, script, aExpression, &allowEval, aError); if (aError.Failed() || !allowEval) { return nullptr; } diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 467a5b0b53..b43f94422d 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -142,6 +142,7 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx, , mRv(NS_OK) , mSkip(false) , mCoerceToString(false) + , mEncodeBytecode(false) #ifdef DEBUG , mWantsReturnValue(false) , mExpectScopeChain(false) @@ -150,7 +151,6 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx, { MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(nsContentUtils::IsInMicroTask()); MOZ_ASSERT(mRetValue.isUndefined()); MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal); @@ -207,7 +207,7 @@ nsJSUtils::ExecutionContext::JoinCompile(void** aOffThreadToken) return mRv; } - if (!StartIncrementalEncoding(mCx, mScript)) { + if (mEncodeBytecode && !StartIncrementalEncoding(mCx, mScript)) { mSkip = true; mRv = EvaluationExceptionToNSResult(mCx); return mRv; @@ -246,7 +246,7 @@ nsJSUtils::ExecutionContext::Compile(JS::CompileOptions& aCompileOptions, return mRv; } - if (!StartIncrementalEncoding(mCx, mScript)) { + if (mEncodeBytecode && !StartIncrementalEncoding(mCx, mScript)) { mSkip = true; mRv = EvaluationExceptionToNSResult(mCx); return mRv; @@ -340,6 +340,19 @@ nsresult nsJSUtils::ExecutionContext::ExecScript() { return NS_OK; } +static bool IsPromiseValue(JSContext* aCx, JS::Handle aValue) { + if (!aValue.isObject()) { + return false; + } + + JS::Rooted obj(aCx, js::CheckedUnwrap(&aValue.toObject())); + if (!obj) { + return false; + } + + return JS::IsPromiseObject(obj); +} + nsresult nsJSUtils::ExecutionContext::ExecScript(JS::MutableHandle aRetValue) { @@ -359,6 +372,15 @@ nsJSUtils::ExecutionContext::ExecScript(JS::MutableHandle aRetValue) #ifdef DEBUG mWantsReturnValue = false; #endif + if (mCoerceToString && IsPromiseValue(mCx, aRetValue)) { + // We're a javascript: url and we should treat Promise return values as + // undefined. + // + // Once bug 1477821 is fixed this code might be able to go away, or will + // become enshrined in the spec, depending. + aRetValue.setUndefined(); + } + if (mCoerceToString && !aRetValue.isUndefined()) { JSString* str = JS::ToString(mCx, aRetValue); if (!str) { diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index b1b2b601a6..8d5ccc95ef 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -90,6 +90,9 @@ public: // Should the result be serialized before being returned. bool mCoerceToString; + // Encode the bytecode before it is being executed. + bool mEncodeBytecode; + #ifdef DEBUG // Should we set the return value. bool mWantsReturnValue; diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index 5db4d69e0d..fe3c12b76a 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -275,10 +275,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, JS::CompileOptions options(cx); options.setFileAndLine(mURL.get(), 1) .setVersion(JSVERSION_DEFAULT); - nsJSUtils::EvaluateOptions evalOptions(cx); - evalOptions.setCoerceToString(true); - rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script), - globalJSObject, options, evalOptions, &v); + { + nsJSUtils::ExecutionContext exec(cx, globalJSObject); + exec.SetCoerceToString(true); + exec.Compile(options, NS_ConvertUTF8toUTF16(script)); + rv = exec.ExecScript(&v); + } + + js::AssertSameCompartment(cx, v); if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) { return NS_ERROR_MALFORMED_URI; diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index da4f09914f..4b02440e20 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -1388,14 +1388,23 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) options.setFileAndLine(spec, 0) .setVersion(JSVERSION_DEFAULT); JS::Rooted rval(cx); - nsJSUtils::EvaluateOptions evalOptions(cx); + JS::AutoObjectVector scopeChain(cx); if (obj != js::GetGlobalForObjectCrossCompartment(obj) && - !evalOptions.scopeChain.append(obj)) { + !scopeChain.append(obj)) { return false; } obj = js::GetGlobalForObjectCrossCompartment(obj); - nsresult rv = nsJSUtils::EvaluateString(cx, utf16script, obj, options, - evalOptions, &rval); + nsresult rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(cx, obj); + exec.SetScopeChain(scopeChain); + exec.Compile(options, utf16script); + rv = exec.ExecScript(&rval); + } + + if (!JS_WrapValue(cx, &rval)) { + return false; + } return NS_SUCCEEDED(rv) && (!result || JSValToNPVariant(npp, cx, rval, result)); diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index f23584c597..d4f76d18b8 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -1072,7 +1072,7 @@ void ScriptLoader::FinishDynamicImport(JSContext* aCx, if (NS_FAILED(aResult)) { MOZ_ASSERT(!JS_IsExceptionPending(aCx)); JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr, - JSMSG_IMPORT_SCRIPT_NOT_FOUND); + JSMSG_DYNAMIC_IMPORT_FAILED); } JS::Rooted referencingScript(aCx, @@ -2374,6 +2374,15 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) return rv; } +/* static */ LoadedScript* ScriptLoader::GetActiveScript(JSContext* aCx) { + JS::Value value = JS::GetScriptedCallerPrivate(aCx); + if (value.isUndefined()) { + return nullptr; + } + + return static_cast(value.toPrivate()); +} + void ScriptLoader::ProcessPendingRequestsAsync() { diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h index 53d5ddb4e0..6cf108e331 100644 --- a/dom/script/ScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -34,6 +34,7 @@ namespace mozilla { namespace dom { class AutoJSAPI; +class LoadedScript; class ModuleLoadRequest; class ModuleScript; class ScriptLoadRequestList; @@ -586,6 +587,12 @@ public: void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest, nsresult aResult); + /* + * Get the currently active script. This is used as the initiating script when + * executing timeout handler scripts. + */ + static LoadedScript* GetActiveScript(JSContext* aCx); + nsIDocument* GetDocument() const { return mDocument; } private: diff --git a/dom/script/moz.build b/dom/script/moz.build index 280850ed4a..125e62545f 100644 --- a/dom/script/moz.build +++ b/dom/script/moz.build @@ -12,6 +12,7 @@ XPIDL_MODULE = 'dom' EXPORTS += ['nsIScriptElement.h'] EXPORTS.mozilla.dom += [ + 'ModuleScript.h', 'ScriptElement.h', 'ScriptLoader.h', 'ScriptSettings.h', diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp index f6baabd935..5bfdc9c176 100644 --- a/dom/worklet/Worklet.cpp +++ b/dom/worklet/Worklet.cpp @@ -202,8 +202,6 @@ public: compileOptions.setVersion(JSVERSION_DEFAULT); compileOptions.setIsRunOnce(true); - // We only need the setNoScriptRval bit when compiling off-thread here, - // since otherwise nsJSUtils::EvaluateString will set it up for us. compileOptions.setNoScriptRval(true); JS::Rooted unused(cx); diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp index b7c04c25ae..2ace609cc9 100644 --- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -434,6 +434,7 @@ nsXBLProtoImplField::InstallField(JS::Handle aBoundNode, JS::CompileOptions options(cx); options.setFileAndLine(uriSpec.get(), mLineNumber) .setVersion(JSVERSION_LATEST); +#if 1 nsJSUtils::EvaluateOptions evalOptions(cx); if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, evalOptions.scopeChain)) { @@ -442,6 +443,21 @@ nsXBLProtoImplField::InstallField(JS::Handle aBoundNode, rv = nsJSUtils::EvaluateString(cx, nsDependentString(mFieldText, mFieldTextLength), scopeObject, options, evalOptions, &result); +#endif +#if 0 + JS::AutoObjectVector scopeChain(cx); + if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, scopeChain)) { + return NS_ERROR_OUT_OF_MEMORY; + } + rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(cx, scopeObject); + exec.SetScopeChain(scopeChain); + exec.Compile(options, nsDependentString(mFieldText, mFieldTextLength)); + rv = exec.ExecScript(&result); + } +#endif + if (NS_FAILED(rv)) { return rv; } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index d49edeb838..1a5d36e104 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -5220,7 +5220,7 @@ template inline typename ParseHandler::Node Parser::importDeclarationOrImportExpr(YieldHandling yieldHandling) { - MOZ_ASSERT(anyChars.isCurrentTokenType(TOK_IMPORT)); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_IMPORT)); TokenKind tt; if (!tokenStream.peekToken(&tt)) @@ -10480,7 +10480,7 @@ template typename ParseHandler::Node Parser::importExpr(YieldHandling yieldHandling) { - MOZ_ASSERT(anyChars.isCurrentTokenType(TOK_IMPORT)); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_IMPORT)); Node importHolder = handler.newPosHolder(pos()); if (!importHolder) diff --git a/js/src/js.msg b/js/src/js.msg index 06915af842..b98e6d860b 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -592,7 +592,7 @@ MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found f MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found") MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status") MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT, 0, JSEXN_SYNTAXERR, "dynamic module import is not implemented") -MSG_DEF(JSMSG_IMPORT_SCRIPT_NOT_FOUND, 0, JSEXN_TYPEERR, "can't find referencing script for dynamic module import") +MSG_DEF(JSMSG_DYNAMIC_IMPORT_FAILED, 0, JSEXN_TYPEERR, "error loading dynamically imported module") MSG_DEF(JSMSG_BAD_MODULE_SPECIFIER, 1, JSEXN_TYPEERR, "error resolving module specifier '{0}'") // Promise diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index aad0756f03..0cd57ab52b 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -366,6 +366,12 @@ js::AssertSameCompartment(JSContext* cx, JSObject* obj) assertSameCompartment(cx, obj); } +JS_FRIEND_API(void) +js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) +{ + assertSameCompartment(cx, v); +} + #ifdef DEBUG JS_FRIEND_API(void) js::AssertSameCompartment(JSObject* objA, JSObject* objB) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index d1c2289634..71c9deb94e 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -659,6 +659,9 @@ GetPrototypeNoProxy(JSObject* obj); JS_FRIEND_API(void) AssertSameCompartment(JSContext* cx, JSObject* obj); +JS_FRIEND_API(void) +AssertSameCompartment(JSContext* cx, JS::HandleValue v); + #ifdef JS_DEBUG JS_FRIEND_API(void) AssertSameCompartment(JSObject* objA, JSObject* objB); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index fce520e5e7..e6308ceb22 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1401,7 +1401,7 @@ const Class ScriptSourceObject::class_ = { }; ScriptSourceObject* -ScriptSourceObject::create(ExclusiveContext* cx, ScriptSource* source) +ScriptSourceObject::createInternal(ExclusiveContext* cx, ScriptSource* source, HandleObject canonical) { RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, nullptr)); if (!object) @@ -1411,6 +1411,12 @@ ScriptSourceObject::create(ExclusiveContext* cx, ScriptSource* source) source->incref(); // The matching decref is in ScriptSourceObject::finalize. sourceObject->initReservedSlot(SOURCE_SLOT, PrivateValue(source)); + if (canonical) { + sourceObject->initReservedSlot(CANONICAL_SLOT, ObjectValue(*canonical)); + } else { + sourceObject->initReservedSlot(CANONICAL_SLOT, ObjectValue(*sourceObject)); + } + // The remaining slots should eventually be populated by a call to // initFromOptions. Poison them until that point. sourceObject->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC)); @@ -1420,6 +1426,20 @@ ScriptSourceObject::create(ExclusiveContext* cx, ScriptSource* source) return sourceObject; } +ScriptSourceObject* +ScriptSourceObject::create(ExclusiveContext* cx, ScriptSource* source) +{ + return createInternal(cx, source, nullptr); +} + +ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const +{ + MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromAnyThread())); + + JSObject* obj = &getReservedSlot(CANONICAL_SLOT).toObject(); + return &UncheckedUnwrap(obj)->as(); +} + /* static */ bool ScriptSourceObject::initFromOptions(JSContext* cx, HandleScriptSource source, const ReadOnlyCompileOptions& options) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index c9f5a927bb..e2225f0cda 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -637,6 +637,14 @@ class ScriptSourceObject : public NativeObject { static const ClassOps classOps_; + static ScriptSourceObject* createInternal(ExclusiveContext* cx, ScriptSource* source, + HandleObject canonical); + + bool isCanonical() const { + return &getReservedSlot(CANONICAL_SLOT).toObject() == this; + } + ScriptSourceObject* unwrappedCanonical() const; + public: static const Class class_; @@ -684,6 +692,7 @@ class ScriptSourceObject : public NativeObject private: enum { SOURCE_SLOT = 0, + CANONICAL_SLOT, ELEMENT_SLOT, ELEMENT_PROPERTY_SLOT, INTRODUCTION_SCRIPT_SLOT, diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp index 7aa5b3759a..124c0251da 100644 --- a/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp +++ b/netwerk/dns/mdns/libmdns/MDNSResponderReply.cpp @@ -6,6 +6,7 @@ #include "MDNSResponderReply.h" #include "mozilla/EndianUtils.h" #include "private/pprio.h" +#include "nsSocketTransportService2.h" namespace mozilla { namespace net { diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp index cec8033d18..9676c64835 100644 --- a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp @@ -8,6 +8,7 @@ #include "nsICancelable.h" #include "nsXULAppAPI.h" #include "private/pprio.h" +#include "MainThreadUtils.h" namespace mozilla { namespace net {