diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index f6e02d219186..cd61f60e1660 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -2074,7 +2074,9 @@ ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, aOptions->setMutedErrors(!subsumes); } - if (!aRequest->IsModuleRequest()) { + if (aRequest->IsModuleRequest()) { + aOptions->hideScriptFromDebugger = true; + } else { JSContext* cx = jsapi.cx(); JS::Rooted elementVal(cx); MOZ_ASSERT(aRequest->mElement); @@ -2245,6 +2247,10 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->mElement); NS_ENSURE_SUCCESS(rv, rv); moduleScript->SetSourceElementAssociated(); + + // The script is now ready to be exposed to the debugger. + JS::Rooted script(cx, JS::GetModuleScript(module)); + JS::ExposeScriptToDebugger(cx, script); } rv = nsJSUtils::ModuleEvaluate(cx, module); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 41be31996cfd..d709c7dc9400 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3993,6 +3993,7 @@ JS::TransitiveCompileOptions::copyPODTransitiveOptions(const TransitiveCompileOp introductionOffset = rhs.introductionOffset; hasIntroductionInfo = rhs.hasIntroductionInfo; isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode; + hideScriptFromDebugger = rhs.hideScriptFromDebugger; }; void @@ -4678,6 +4679,17 @@ JS::InitScriptSourceElement(JSContext* cx, HandleScript script, return ScriptSourceObject::initElementProperties(cx, sso, element, elementAttrName); } +JS_PUBLIC_API(void) +JS::ExposeScriptToDebugger(JSContext* cx, HandleScript script) +{ + MOZ_ASSERT(cx); + MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); + + MOZ_ASSERT(script->hideScriptFromDebugger()); + script->clearHideScriptFromDebugger(); + Debugger::onNewScript(cx, script); +} + JS_PUBLIC_API(JSString*) JS_DecompileScript(JSContext* cx, HandleScript script) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 8c71d3922b7d..dc8642b5d6d6 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3565,6 +3565,7 @@ class JS_FRIEND_API(TransitiveCompileOptions) sourceIsLazy(false), allowHTMLComments(true), isProbablySystemOrAddonCode(false), + hideScriptFromDebugger(false), introductionType(nullptr), introductionLineno(0), introductionOffset(0), @@ -3600,6 +3601,7 @@ class JS_FRIEND_API(TransitiveCompileOptions) bool sourceIsLazy; bool allowHTMLComments; bool isProbablySystemOrAddonCode; + bool hideScriptFromDebugger; // |introductionType| is a statically allocated C string: // one of "eval", "Function", or "GeneratorFunction". @@ -4007,6 +4009,13 @@ extern JS_PUBLIC_API(bool) InitScriptSourceElement(JSContext* cx, HandleScript script, HandleObject element, HandleString elementAttrName = nullptr); +/* + * For a script compiled with the hideScriptFromDebugger option, expose the + * script to the debugger by calling the debugger's onNewScript hook. + */ +extern JS_PUBLIC_API(void) +ExposeScriptToDebugger(JSContext* cx, HandleScript script); + } /* namespace JS */ extern JS_PUBLIC_API(JSString*) diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 7c868ac23ce2..b11b01c9cb47 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -1800,6 +1800,11 @@ Debugger::onNewScript(JSContext* cx, HandleScript script) MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() && !script->selfHosted(), script->compartment()->firedOnNewGlobalObject); + + // The script may not be ready to be interrogated by the debugger. + if (script->hideScriptFromDebugger()) + return; + if (script->compartment()->isDebuggee()) slowPathOnNewScript(cx, script); } diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index f6ec4fa3eef1..ba4d72c04226 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -2732,6 +2732,8 @@ JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options, script->toStringStart_ = toStringStart; script->toStringEnd_ = toStringEnd; + script->hideScriptFromDebugger_ = options.hideScriptFromDebugger; + #ifdef MOZ_VTUNE script->vtuneMethodId_ = vtune::GenerateUniqueMethodID(); #endif @@ -3625,6 +3627,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, dst->isAsync_ = src->isAsync_; dst->hasRest_ = src->hasRest_; dst->isExprBody_ = src->isExprBody_; + dst->hideScriptFromDebugger_ = src->hideScriptFromDebugger_; if (nconsts != 0) { GCPtrValue* vector = Rebase(dst, src, src->consts()->vector); diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h index 984e09dcfa5b..86d2679fe3f6 100644 --- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -1142,6 +1142,9 @@ class JSScript : public js::gc::TenuredCell bool hasRest_:1; bool isExprBody_:1; + // True if the debugger's onNewScript hook has not yet been called. + bool hideScriptFromDebugger_:1; + // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. protected: @@ -1463,6 +1466,13 @@ class JSScript : public js::gc::TenuredCell isExprBody_ = true; } + bool hideScriptFromDebugger() const { + return hideScriptFromDebugger_; + } + void clearHideScriptFromDebugger() { + hideScriptFromDebugger_ = false; + } + void setNeedsHomeObject() { needsHomeObject_ = true; }