diff --git a/dom/script/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp index 153c2063f2ae..d04c0d8cfa1a 100644 --- a/dom/script/ScriptSettings.cpp +++ b/dom/script/ScriptSettings.cpp @@ -50,33 +50,33 @@ namespace mozilla { namespace dom { -JSObject* GetElementCallback(JSContext* aCx, JS::HandleValue aValue) { - JS::RootedValue privateValue(aCx, aValue); - MOZ_ASSERT(!privateValue.isObjectOrNull() && !privateValue.isUndefined()); - LoadedScript* script = static_cast(privateValue.toPrivate()); +JSObject* SourceElementCallback(JSContext* aCx, JS::HandleValue aPrivateValue) { + // NOTE: The result of this is only used by DevTools for matching sources, so + // it is safe to silently ignore any errors and return nullptr for them. + + LoadedScript* script = static_cast(aPrivateValue.toPrivate()); if (!script->GetFetchOptions()) { return nullptr; } - JS::Rooted elementValue(aCx); - { - nsCOMPtr domElement = script->GetFetchOptions()->mElement; - if (!domElement) { - return nullptr; - } - - JSObject* globalObject = - domElement->OwnerDoc()->GetScopeObject()->GetGlobalJSObject(); - JSAutoRealm ar(aCx, globalObject); - - nsresult rv = nsContentUtils::WrapNative(aCx, domElement, &elementValue, - /* aAllowWrapping = */ true); - if (NS_FAILED(rv)) { - return nullptr; - } + nsCOMPtr domElement = script->GetFetchOptions()->mElement; + if (!domElement) { + return nullptr; } - return elementValue.toObjectOrNull(); + + JSObject* globalObject = + domElement->OwnerDoc()->GetScopeObject()->GetGlobalJSObject(); + JSAutoRealm ar(aCx, globalObject); + + JS::Rooted elementValue(aCx); + nsresult rv = nsContentUtils::WrapNative(aCx, domElement, &elementValue, + /* aAllowWrapping = */ true); + if (NS_FAILED(rv)) { + return nullptr; + } + + return &elementValue.toObject(); } static MOZ_THREAD_LOCAL(ScriptSettingsStackEntry*) sScriptSettingsTLS; @@ -340,7 +340,7 @@ void AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal, mOldWarningReporter.emplace(JS::GetWarningReporter(aCx)); JS::SetWarningReporter(aCx, WarningOnlyErrorReporter); - JS::SetGetElementCallback(aCx, &GetElementCallback); + JS::SetSourceElementCallback(aCx, SourceElementCallback); #ifdef DEBUG if (haveException) { diff --git a/js/public/CompilationAndEvaluation.h b/js/public/CompilationAndEvaluation.h index 096e99d046e6..18d5901e9239 100644 --- a/js/public/CompilationAndEvaluation.h +++ b/js/public/CompilationAndEvaluation.h @@ -266,8 +266,13 @@ extern JS_PUBLIC_API bool UpdateDebugMetadata( HandleString elementAttributeName, HandleScript introScript, HandleScript scriptOrModule); -extern JS_PUBLIC_API void SetGetElementCallback(JSContext* cx, - JSGetElementCallback callback); +// The debugger API exposes an optional "element" property on DebuggerSource +// objects. The callback defined here provides that value. SpiderMonkey +// doesn't particularly care about this, but within Firefox the "element" is the +// HTML script tag for the script which DevTools can use for a better debugging +// experience. +extern JS_PUBLIC_API void SetSourceElementCallback( + JSContext* cx, JSSourceElementCallback callback); } /* namespace JS */ diff --git a/js/src/debugger/Source.cpp b/js/src/debugger/Source.cpp index 36a599c07a0a..1dc93d62008b 100644 --- a/js/src/debugger/Source.cpp +++ b/js/src/debugger/Source.cpp @@ -397,14 +397,14 @@ struct DebuggerSourceGetElementMatcher { bool DebuggerSource::CallData::getElement() { DebuggerSourceGetElementMatcher matcher(cx); + RootedValue elementValue(cx); if (JSObject* element = referent.match(matcher)) { - args.rval().setObjectOrNull(element); - if (!obj->owner()->wrapDebuggeeValue(cx, args.rval())) { + elementValue.setObject(*element); + if (!obj->owner()->wrapDebuggeeValue(cx, &elementValue)) { return false; } - } else { - args.rval().setUndefined(); } + args.rval().set(elementValue); return true; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 71b8bcea9bbd..c6c045d2887a 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -99,8 +99,11 @@ class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter { /* Callbacks and their arguments. */ /************************************************************************/ -using JSGetElementCallback = JSObject* (*)(JSContext* aCx, - JS::HandleValue privateValue); + +// Callback for the embedding to map from a ScriptSourceObject private-value to +// an object that is exposed as the source "element" in debugger API. This hook +// must be infallible, but can return nullptr if no such element exists. +using JSSourceElementCallback = JSObject* (*)(JSContext*, JS::HandleValue); using JSInterruptCallback = bool (*)(JSContext*); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 90d706c3b8bd..16a7afe85ae7 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4717,8 +4717,8 @@ static void DestroyShellCompartmentPrivate(JSFreeOp* fop, static void SetWorkerContextOptions(JSContext* cx); static bool ShellBuildId(JS::BuildIdCharVector* buildId); -JSObject* GetElementCallback(JSContext* cx, JS::HandleValue value) { - RootedValue privateValue(cx, value); +static JSObject* ShellSourceElementCallback(JSContext* cx, + JS::HandleValue privateValue) { if (!privateValue.isObject()) { return nullptr; } @@ -4783,7 +4783,7 @@ static void WorkerMain(WorkerInput* input) { DummyHasReleasedWrapperCallback); JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy); JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate); - JS::SetGetElementCallback(cx, &GetElementCallback); + JS::SetSourceElementCallback(cx, ShellSourceElementCallback); js::SetWindowProxyClass(cx, &ShellWindowProxyClass); @@ -12421,7 +12421,7 @@ int main(int argc, char** argv) { JS_SetSecurityCallbacks(cx, &ShellPrincipals::securityCallbacks); JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy); JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate); - JS::SetGetElementCallback(cx, &GetElementCallback); + JS::SetSourceElementCallback(cx, ShellSourceElementCallback); js::SetWindowProxyClass(cx, &ShellWindowProxyClass); diff --git a/js/src/vm/CompilationAndEvaluation.cpp b/js/src/vm/CompilationAndEvaluation.cpp index ff2e3d132d0c..75b70dcb93e6 100644 --- a/js/src/vm/CompilationAndEvaluation.cpp +++ b/js/src/vm/CompilationAndEvaluation.cpp @@ -470,10 +470,10 @@ JS_PUBLIC_API bool JS::UpdateDebugMetadata( return true; } -JS_PUBLIC_API void JS::SetGetElementCallback(JSContext* cx, - JSGetElementCallback callback) { +JS_PUBLIC_API void JS::SetSourceElementCallback( + JSContext* cx, JSSourceElementCallback callback) { MOZ_ASSERT(cx->runtime()); - cx->runtime()->setElementCallback(cx->runtime(), callback); + cx->runtime()->setSourceElementCallback(cx->runtime(), callback); } MOZ_NEVER_INLINE static bool ExecuteScript(JSContext* cx, HandleObject envChain, diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index c45d2bb31062..b564f962732a 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -1741,8 +1741,11 @@ JSObject* ScriptSourceObject::unwrappedElement(JSContext* cx) const { return nullptr; } - MOZ_ASSERT(cx->runtime()->getElementCallback); - return (*cx->runtime()->getElementCallback)(cx, privateValue); + if (cx->runtime()->sourceElementCallback) { + return (*cx->runtime()->sourceElementCallback)(cx, privateValue); + } + + return nullptr; } class ScriptSource::LoadSourceMatcher { diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 5668d6a21096..9a31ef1265dc 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -332,9 +332,9 @@ void JSRuntime::setTelemetryCallback( rt->telemetryCallback = callback; } -void JSRuntime::setElementCallback(JSRuntime* rt, - JSGetElementCallback callback) { - rt->getElementCallback = callback; +void JSRuntime::setSourceElementCallback(JSRuntime* rt, + JSSourceElementCallback callback) { + rt->sourceElementCallback = callback; } void JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter) { diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index c9ca5c7391df..032c577f4ce4 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -307,7 +307,7 @@ struct JSRuntime { /* Call this to accumulate use counter data. */ js::MainThreadData useCounterCallback; - js::MainThreadData getElementCallback; + js::MainThreadData sourceElementCallback; public: // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_* @@ -320,7 +320,8 @@ struct JSRuntime { void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); - void setElementCallback(JSRuntime* rt, JSGetElementCallback callback); + void setSourceElementCallback(JSRuntime* rt, + JSSourceElementCallback callback); // Sets the use counter for a specific feature, measuring the presence or // absence of usage of a feature on a specific web page and document which