Backed out 3 changesets (bug 1763586) foar causing sm bustages. CLOSED TREE

Backed out changeset 02a961432a49 (bug 1763586)
Backed out changeset 3fc84237decb (bug 1763586)
Backed out changeset 365eff56ce0f (bug 1763586)
This commit is contained in:
Marian-Vasile Laza
2022-04-12 09:49:21 -07:00
parent 2137e27ccf
commit a3aadc47df
23 changed files with 268 additions and 63 deletions

View File

@@ -1240,7 +1240,7 @@ nsresult EventListenerManager::CompileEventHandlerInternal(
aElement->OwnerDoc()->NodePrincipal()); aElement->OwnerDoc()->NodePrincipal());
RefPtr<JS::loader::EventScript> eventScript = RefPtr<JS::loader::EventScript> eventScript =
new JS::loader::EventScript(fetchOptions, uri); new JS::loader::EventScript(fetchOptions, uri, aElement);
JS::CompileOptions options(cx); JS::CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1. // Use line 0 to make the function body starts from line 1.

View File

@@ -242,7 +242,8 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateTopLevel(
already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateStaticImport( already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateStaticImport(
nsIURI* aURI, ModuleLoadRequest* aParent) { nsIURI* aURI, ModuleLoadRequest* aParent) {
RefPtr<ScriptLoadContext> newContext = new ScriptLoadContext(); RefPtr<ScriptLoadContext> newContext =
new ScriptLoadContext(aParent->GetLoadContext()->mElement);
newContext->mIsInline = false; newContext->mIsInline = false;
// Propagated Parent values. TODO: allow child modules to use root module's // Propagated Parent values. TODO: allow child modules to use root module's
// script mode. // script mode.
@@ -264,13 +265,15 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateDynamicImport(
MOZ_ASSERT(aSpecifier); MOZ_ASSERT(aSpecifier);
MOZ_ASSERT(aPromise); MOZ_ASSERT(aPromise);
RefPtr<ScriptFetchOptions> options = nullptr; RefPtr<ScriptFetchOptions> options;
nsIURI* baseURL = nullptr; nsIURI* baseURL = nullptr;
RefPtr<ScriptLoadContext> context = new ScriptLoadContext(); RefPtr<ScriptLoadContext> context;
if (aMaybeActiveScript) { if (aMaybeActiveScript) {
options = aMaybeActiveScript->GetFetchOptions(); options = aMaybeActiveScript->GetFetchOptions();
baseURL = aMaybeActiveScript->BaseURL(); baseURL = aMaybeActiveScript->BaseURL();
nsCOMPtr<Element> element = aMaybeActiveScript->GetScriptElement();
context = new ScriptLoadContext(element);
} else { } else {
// We don't have a referencing script so fall back on using // We don't have a referencing script so fall back on using
// options from the document. This can happen when the user // options from the document. This can happen when the user
@@ -283,9 +286,10 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateDynamicImport(
BasePrincipal::Cast(principal)->ContentScriptAddonPolicy()); BasePrincipal::Cast(principal)->ContentScriptAddonPolicy());
MOZ_ASSERT_IF(GetKind() == Normal, principal == document->NodePrincipal()); MOZ_ASSERT_IF(GetKind() == Normal, principal == document->NodePrincipal());
options = new ScriptFetchOptions( options = new ScriptFetchOptions(mozilla::CORS_NONE,
mozilla::CORS_NONE, document->GetReferrerPolicy(), principal, nullptr); document->GetReferrerPolicy(), principal);
baseURL = document->GetDocBaseURI(); baseURL = document->GetDocBaseURI();
context = new ScriptLoadContext(nullptr);
} }
context->mIsInline = false; context->mIsInline = false;

View File

@@ -38,7 +38,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadContext) NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadContext) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoadBlockedDocument, mRequest) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoadBlockedDocument, mRequest, mElement)
if (Runnable* runnable = tmp->mRunnable.exchange(nullptr)) { if (Runnable* runnable = tmp->mRunnable.exchange(nullptr)) {
runnable->Release(); runnable->Release();
} }
@@ -46,13 +46,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadContext) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDocument, mRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDocument, mRequest, mElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadContext) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRACE_END
ScriptLoadContext::ScriptLoadContext() ScriptLoadContext::ScriptLoadContext(Element* aElement)
: mScriptMode(ScriptMode::eBlocking), : mScriptMode(ScriptMode::eBlocking),
mScriptFromHead(false), mScriptFromHead(false),
mIsInline(true), mIsInline(true),
@@ -67,6 +67,7 @@ ScriptLoadContext::ScriptLoadContext()
mRunnable(nullptr), mRunnable(nullptr),
mLineNo(1), mLineNo(1),
mIsPreload(false), mIsPreload(false),
mElement(aElement),
mRequest(nullptr), mRequest(nullptr),
mUnreportedPreloadError(NS_OK) {} mUnreportedPreloadError(NS_OK) {}
@@ -179,8 +180,12 @@ bool ScriptLoadContext::CompileStarted() const {
} }
nsIScriptElement* ScriptLoadContext::GetScriptElement() const { nsIScriptElement* ScriptLoadContext::GetScriptElement() const {
nsCOMPtr<nsIScriptElement> scriptElement = if (mRequest->IsModuleRequest() && !mRequest->IsTopLevel()) {
do_QueryInterface(mRequest->mFetchOptions->mElement); JS::loader::ModuleLoadRequest* root =
mRequest->AsModuleRequest()->GetRootModule();
return root->GetLoadContext()->GetScriptElement();
}
nsCOMPtr<nsIScriptElement> scriptElement = do_QueryInterface(mElement);
return scriptElement; return scriptElement;
} }
@@ -188,9 +193,8 @@ void ScriptLoadContext::SetIsLoadRequest(nsIScriptElement* aElement) {
MOZ_ASSERT(aElement); MOZ_ASSERT(aElement);
MOZ_ASSERT(!GetScriptElement()); MOZ_ASSERT(!GetScriptElement());
MOZ_ASSERT(IsPreload()); MOZ_ASSERT(IsPreload());
// We are not tracking our own element, and are relying on the one in // TODO: How to allow both to access fetch options
// FetchOptions. mElement = do_QueryInterface(aElement);
mRequest->mFetchOptions->mElement = do_QueryInterface(aElement);
mIsPreload = false; mIsPreload = false;
} }

View File

@@ -84,7 +84,7 @@ class ScriptLoadContext : public PreloaderBase {
virtual ~ScriptLoadContext(); virtual ~ScriptLoadContext();
public: public:
explicit ScriptLoadContext(); explicit ScriptLoadContext(Element* aElement);
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadContext) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadContext)
@@ -187,6 +187,7 @@ class ScriptLoadContext : public PreloaderBase {
// Set on scripts and top level modules. // Set on scripts and top level modules.
bool mIsPreload; bool mIsPreload;
nsCOMPtr<Element> mElement;
RefPtr<JS::loader::ScriptLoadRequest> mRequest; RefPtr<JS::loader::ScriptLoadRequest> mRequest;

View File

@@ -817,14 +817,13 @@ already_AddRefed<ScriptLoadRequest> ScriptLoader::CreateLoadRequest(
const SRIMetadata& aIntegrity, ReferrerPolicy aReferrerPolicy) { const SRIMetadata& aIntegrity, ReferrerPolicy aReferrerPolicy) {
nsIURI* referrer = mDocument->GetDocumentURIAsReferrer(); nsIURI* referrer = mDocument->GetDocumentURIAsReferrer();
nsCOMPtr<Element> domElement = do_QueryInterface(aElement); nsCOMPtr<Element> domElement = do_QueryInterface(aElement);
RefPtr<ScriptFetchOptions> fetchOptions = new ScriptFetchOptions( RefPtr<ScriptFetchOptions> fetchOptions =
aCORSMode, aReferrerPolicy, aTriggeringPrincipal, domElement); new ScriptFetchOptions(aCORSMode, aReferrerPolicy, aTriggeringPrincipal);
RefPtr<ScriptLoadContext> context = new ScriptLoadContext(); RefPtr<ScriptLoadContext> context = new ScriptLoadContext(domElement);
if (aKind == ScriptKind::eClassic) { if (aKind == ScriptKind::eClassic) {
RefPtr<ScriptLoadRequest> aRequest = RefPtr<ScriptLoadRequest> aRequest = new ScriptLoadRequest(
new ScriptLoadRequest(aKind, aURI, fetchOptions, aIntegrity, referrer, aKind, aURI, fetchOptions, aIntegrity, referrer, context);
new ScriptLoadContext());
return aRequest.forget(); return aRequest.forget();
} }
@@ -2268,7 +2267,8 @@ nsresult ScriptLoader::EvaluateScript(nsIGlobalObject* aGlobalObject,
// Create a ClassicScript object and associate it with the JSScript. // Create a ClassicScript object and associate it with the JSScript.
RefPtr<ClassicScript> classicScript = RefPtr<ClassicScript> classicScript =
new ClassicScript(aRequest->mFetchOptions, aRequest->mBaseURL); new ClassicScript(aRequest->mFetchOptions, aRequest->mBaseURL,
aRequest->GetLoadContext()->mElement);
JS::RootedValue classicScriptValue(cx, JS::PrivateValue(classicScript)); JS::RootedValue classicScriptValue(cx, JS::PrivateValue(classicScript));
JS::CompileOptions options(cx); JS::CompileOptions options(cx);

View File

@@ -51,6 +51,34 @@
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
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.
JS::loader::LoadedScript* script =
static_cast<JS::loader::LoadedScript*>(aPrivateValue.toPrivate());
JS::Rooted<JS::Value> elementValue(aCx);
{
nsCOMPtr<Element> domElement = script->GetScriptElement();
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;
}
}
return &elementValue.toObject();
}
static MOZ_THREAD_LOCAL(ScriptSettingsStackEntry*) sScriptSettingsTLS; static MOZ_THREAD_LOCAL(ScriptSettingsStackEntry*) sScriptSettingsTLS;
class ScriptSettingsStack { class ScriptSettingsStack {
@@ -312,6 +340,7 @@ void AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal,
mOldWarningReporter.emplace(JS::GetWarningReporter(aCx)); mOldWarningReporter.emplace(JS::GetWarningReporter(aCx));
JS::SetWarningReporter(aCx, WarningOnlyErrorReporter); JS::SetWarningReporter(aCx, WarningOnlyErrorReporter);
JS::SetSourceElementCallback(aCx, SourceElementCallback);
#ifdef DEBUG #ifdef DEBUG
if (haveException) { if (haveException) {

View File

@@ -7,6 +7,7 @@
#include "LoadedScript.h" #include "LoadedScript.h"
#include "mozilla/HoldDropJSObjects.h" #include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/Element.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "js/Modules.h" // JS::{Get,Set}ModulePrivate #include "js/Modules.h" // JS::{Get,Set}ModulePrivate
@@ -25,10 +26,11 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(LoadedScript)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LoadedScript) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LoadedScript)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LoadedScript) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LoadedScript)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions, mElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(LoadedScript) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(LoadedScript)
@@ -38,8 +40,11 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadedScript)
NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadedScript) NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadedScript)
LoadedScript::LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions, LoadedScript::LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions,
nsIURI* aBaseURL) nsIURI* aBaseURL, mozilla::dom::Element* aElement)
: mKind(aKind), mFetchOptions(aFetchOptions), mBaseURL(aBaseURL) { : mKind(aKind),
mFetchOptions(aFetchOptions),
mBaseURL(aBaseURL),
mElement(aElement) {
MOZ_ASSERT(mFetchOptions); MOZ_ASSERT(mFetchOptions);
MOZ_ASSERT(mBaseURL); MOZ_ASSERT(mBaseURL);
} }
@@ -89,16 +94,17 @@ void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
// EventScript // EventScript
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
EventScript::EventScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL) EventScript::EventScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
: LoadedScript(ScriptKind::eEvent, aFetchOptions, aBaseURL) {} mozilla::dom::Element* aElement)
: LoadedScript(ScriptKind::eEvent, aFetchOptions, aBaseURL, aElement) {}
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// ClassicScript // ClassicScript
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
ClassicScript::ClassicScript(ScriptFetchOptions* aFetchOptions, ClassicScript::ClassicScript(ScriptFetchOptions* aFetchOptions,
nsIURI* aBaseURL) nsIURI* aBaseURL, mozilla::dom::Element* aElement)
: LoadedScript(ScriptKind::eClassic, aFetchOptions, aBaseURL) {} : LoadedScript(ScriptKind::eClassic, aFetchOptions, aBaseURL, aElement) {}
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// ModuleScript // ModuleScript
@@ -127,8 +133,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_ADDREF_INHERITED(ModuleScript, LoadedScript) NS_IMPL_ADDREF_INHERITED(ModuleScript, LoadedScript)
NS_IMPL_RELEASE_INHERITED(ModuleScript, LoadedScript) NS_IMPL_RELEASE_INHERITED(ModuleScript, LoadedScript)
ModuleScript::ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL) ModuleScript::ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
: LoadedScript(ScriptKind::eModule, aFetchOptions, aBaseURL), mozilla::dom::Element* aElement)
: LoadedScript(ScriptKind::eModule, aFetchOptions, aBaseURL, aElement),
mDebuggerDataInitialized(false) { mDebuggerDataInitialized(false) {
MOZ_ASSERT(!ModuleRecord()); MOZ_ASSERT(!ModuleRecord());
MOZ_ASSERT(!HasParseError()); MOZ_ASSERT(!HasParseError());

View File

@@ -27,10 +27,11 @@ class LoadedScript : public nsISupports {
ScriptKind mKind; ScriptKind mKind;
RefPtr<ScriptFetchOptions> mFetchOptions; RefPtr<ScriptFetchOptions> mFetchOptions;
nsCOMPtr<nsIURI> mBaseURL; nsCOMPtr<nsIURI> mBaseURL;
RefPtr<mozilla::dom::Element> mElement;
protected: protected:
LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions, LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions,
nsIURI* aBaseURL); nsIURI* aBaseURL, mozilla::dom::Element* aElement);
virtual ~LoadedScript(); virtual ~LoadedScript();
@@ -48,6 +49,9 @@ class LoadedScript : public nsISupports {
// Used to propagate Fetch Options to child modules // Used to propagate Fetch Options to child modules
ScriptFetchOptions* GetFetchOptions() const { return mFetchOptions; } ScriptFetchOptions* GetFetchOptions() const { return mFetchOptions; }
// Used by the Debugger to get the associated Script Element
mozilla::dom::Element* GetScriptElement() const { return mElement; }
nsIURI* BaseURL() const { return mBaseURL; } nsIURI* BaseURL() const { return mBaseURL; }
void AssociateWithScript(JSScript* aScript); void AssociateWithScript(JSScript* aScript);
@@ -57,14 +61,16 @@ class ClassicScript final : public LoadedScript {
~ClassicScript() = default; ~ClassicScript() = default;
public: public:
ClassicScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL); ClassicScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
mozilla::dom::Element* aElement);
}; };
class EventScript final : public LoadedScript { class EventScript final : public LoadedScript {
~EventScript() = default; ~EventScript() = default;
public: public:
EventScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL); EventScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
mozilla::dom::Element* aElement);
}; };
// A single module script. May be used to satisfy multiple load requests. // A single module script. May be used to satisfy multiple load requests.
@@ -82,7 +88,8 @@ class ModuleScript final : public LoadedScript {
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleScript, NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleScript,
LoadedScript) LoadedScript)
ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL); ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
mozilla::dom::Element* aElement);
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord); void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
void SetParseError(const JS::Value& aError); void SetParseError(const JS::Value& aError);

View File

@@ -491,7 +491,8 @@ nsresult ModuleLoaderBase::CreateModuleScript(ModuleLoadRequest* aRequest) {
} }
RefPtr<ModuleScript> moduleScript = RefPtr<ModuleScript> moduleScript =
new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL); new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL,
aRequest->mLoadContext->mElement);
aRequest->mModuleScript = moduleScript; aRequest->mModuleScript = moduleScript;
if (!module) { if (!module) {

View File

@@ -32,18 +32,17 @@ namespace JS::loader {
// ScriptFetchOptions // ScriptFetchOptions
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions, mTriggeringPrincipal, mElement) NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions, mTriggeringPrincipal)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ScriptFetchOptions, AddRef) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(ScriptFetchOptions, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ScriptFetchOptions, Release) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(ScriptFetchOptions, Release)
ScriptFetchOptions::ScriptFetchOptions( ScriptFetchOptions::ScriptFetchOptions(
mozilla::CORSMode aCORSMode, mozilla::dom::ReferrerPolicy aReferrerPolicy, mozilla::CORSMode aCORSMode, mozilla::dom::ReferrerPolicy aReferrerPolicy,
nsIPrincipal* aTriggeringPrincipal, mozilla::dom::Element* aElement) nsIPrincipal* aTriggeringPrincipal)
: mCORSMode(aCORSMode), : mCORSMode(aCORSMode),
mReferrerPolicy(aReferrerPolicy), mReferrerPolicy(aReferrerPolicy),
mTriggeringPrincipal(aTriggeringPrincipal), mTriggeringPrincipal(aTriggeringPrincipal) {
mElement(aElement) {
MOZ_ASSERT(mTriggeringPrincipal); MOZ_ASSERT(mTriggeringPrincipal);
} }

View File

@@ -53,16 +53,10 @@ class ScriptLoadRequestList;
* with the exception of the following properties: * with the exception of the following properties:
* cryptographic nonce * cryptographic nonce
* The cryptographic nonce metadata used for the initial fetch and for * The cryptographic nonce metadata used for the initial fetch and for
* fetching any imported modules. As this is populated by a DOM element, * fetching any imported modules. This is handled by the principal.
* this is implemented via mozilla::dom::Element as the field
* mElement. The default value is an empty string, and is indicated
* when this field is a nullptr. Nonce is not represented on the dom
* side as per bug 1374612.
* parser metadata * parser metadata
* The parser metadata used for the initial fetch and for fetching any * The parser metadata used for the initial fetch and for fetching any
* imported modules. This is populated from a mozilla::dom::Element and is * imported modules. This is not implemented.
* handled by the field mElement. The default value is an empty string,
* and is indicated when this field is a nullptr.
* integrity metadata * integrity metadata
* The integrity metadata used for the initial fetch. This is * The integrity metadata used for the initial fetch. This is
* implemented in ScriptLoadRequest, as it changes for every * implemented in ScriptLoadRequest, as it changes for every
@@ -83,8 +77,7 @@ class ScriptFetchOptions {
ScriptFetchOptions(mozilla::CORSMode aCORSMode, ScriptFetchOptions(mozilla::CORSMode aCORSMode,
enum mozilla::dom::ReferrerPolicy aReferrerPolicy, enum mozilla::dom::ReferrerPolicy aReferrerPolicy,
nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aTriggeringPrincipal);
mozilla::dom::Element* aElement = nullptr);
/* /*
* The credentials mode used for the initial fetch (for module scripts) * The credentials mode used for the initial fetch (for module scripts)
@@ -100,16 +93,9 @@ class ScriptFetchOptions {
const enum mozilla::dom::ReferrerPolicy mReferrerPolicy; const enum mozilla::dom::ReferrerPolicy mReferrerPolicy;
/* /*
* Used to determine CSP * Related to cryptographic nonce, used to determine CSP
*/ */
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
/*
* Represents fields populated by DOM elements (nonce, parser metadata)
* Leave this field as a nullptr for any fetch that requires the
* default classic script options.
* (https://html.spec.whatwg.org/multipage/webappapis.html#default-classic-script-fetch-options)
*/
nsCOMPtr<mozilla::dom::Element> mElement;
}; };
/* /*

View File

@@ -90,6 +90,11 @@ extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
JS::HandleObjectVector envChain, JS::HandleObjectVector envChain,
JS::Handle<JSScript*> script); JS::Handle<JSScript*> script);
// 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);
namespace JS { namespace JS {
/** /**
@@ -246,6 +251,14 @@ extern JS_PUBLIC_API bool UpdateDebugMetadata(
HandleValue privateValue, HandleString elementAttributeName, HandleValue privateValue, HandleString elementAttributeName,
HandleScript introScript, HandleScript scriptOrModule); HandleScript introScript, HandleScript scriptOrModule);
// 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 */ } /* namespace JS */
#endif /* js_CompilationAndEvaluation_h */ #endif /* js_CompilationAndEvaluation_h */

View File

@@ -171,6 +171,7 @@ struct MOZ_STACK_CLASS DebuggerSource::CallData {
bool getStartLine(); bool getStartLine();
bool getId(); bool getId();
bool getDisplayURL(); bool getDisplayURL();
bool getElement();
bool getElementProperty(); bool getElementProperty();
bool getIntroductionScript(); bool getIntroductionScript();
bool getIntroductionOffset(); bool getIntroductionOffset();
@@ -383,6 +384,29 @@ bool DebuggerSource::CallData::getDisplayURL() {
return true; return true;
} }
struct DebuggerSourceGetElementMatcher {
JSContext* mCx = nullptr;
explicit DebuggerSourceGetElementMatcher(JSContext* cx_) : mCx(cx_) {}
using ReturnType = JSObject*;
ReturnType match(HandleScriptSourceObject sourceObject) {
return sourceObject->unwrappedElement(mCx);
}
ReturnType match(Handle<WasmInstanceObject*> wasmInstance) { return nullptr; }
};
bool DebuggerSource::CallData::getElement() {
DebuggerSourceGetElementMatcher matcher(cx);
RootedValue elementValue(cx);
if (JSObject* element = referent.match(matcher)) {
elementValue.setObject(*element);
if (!obj->owner()->wrapDebuggeeValue(cx, &elementValue)) {
return false;
}
}
args.rval().set(elementValue);
return true;
}
struct DebuggerSourceGetElementPropertyMatcher { struct DebuggerSourceGetElementPropertyMatcher {
using ReturnType = Value; using ReturnType = Value;
ReturnType match(HandleScriptSourceObject sourceObject) { ReturnType match(HandleScriptSourceObject sourceObject) {
@@ -650,6 +674,7 @@ const JSPropertySpec DebuggerSource::properties_[] = {
JS_DEBUG_PSG("url", getURL), JS_DEBUG_PSG("url", getURL),
JS_DEBUG_PSG("startLine", getStartLine), JS_DEBUG_PSG("startLine", getStartLine),
JS_DEBUG_PSG("id", getId), JS_DEBUG_PSG("id", getId),
JS_DEBUG_PSG("element", getElement),
JS_DEBUG_PSG("displayURL", getDisplayURL), JS_DEBUG_PSG("displayURL", getDisplayURL),
JS_DEBUG_PSG("introductionScript", getIntroductionScript), JS_DEBUG_PSG("introductionScript", getIntroductionScript),
JS_DEBUG_PSG("introductionOffset", getIntroductionOffset), JS_DEBUG_PSG("introductionOffset", getIntroductionOffset),

View File

@@ -1,6 +1,13 @@
// Specifying an owning element in a cross-global evaluation shouldn't crash. // Source.prototype.element can be an object or undefined.
// That is, when 'evaluate' switches compartments, it should properly wrap
// the CompileOptions members that will become cross-compartment
// references.
evaluate('42 + 1729', { global: newGlobal(), element: {} }); var g = newGlobal({newCompartment: true});
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
g.evaluate("function f(x) { return 2*x; }", {element: { foo: "bar" }});
var fw = gw.getOwnPropertyDescriptor('f').value;
assertEq(typeof fw.script.source.element, "object");
assertEq(fw.script.source.element instanceof Debugger.Object, true);
assertEq(fw.script.source.element.getOwnPropertyDescriptor("foo").value, "bar");
g.evaluate("function f(x) { return 2*x; }");
var fw = gw.getOwnPropertyDescriptor('f').value;
assertEq(typeof fw.script.source.element, "undefined");

View File

@@ -0,0 +1,6 @@
// Specifying an owning element in a cross-global evaluation shouldn't crash.
// That is, when 'evaluate' switches compartments, it should properly wrap
// the CompileOptions members that will become cross-compartment
// references.
evaluate('42 + 1729', { global: newGlobal(), element: {} });

View File

@@ -0,0 +1,29 @@
// |jit-test| skip-if: helperThreadCount() === 0
// Owning elements and attribute names are attached to scripts compiled
// off-thread.
var g = newGlobal({ newCompartment: true });
var dbg = new Debugger;
var gDO = dbg.addDebuggee(g);
var elt = new g.Object;
var eltDO = gDO.makeDebuggeeValue(elt);
var log = '';
dbg.onDebuggerStatement = function (frame) {
log += 'd';
var source = frame.script.source;
assertEq(source.element, eltDO);
assertEq(source.elementAttributeName, 'mass');
};
var job = g.offThreadCompileToStencil('debugger;');
var stencil = g.finishOffThreadCompileToStencil(job);
log += 'o';
g.evalStencil(stencil,
{
element: elt,
elementAttributeName: 'mass'
});
assertEq(log, 'od');

View File

@@ -0,0 +1,13 @@
// source.element is undefined if the script was introduced using eval() or Function().
var g = newGlobal({newCompartment: true});
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
g.eval("function f(x) { return 2*x; }");
var fw = gw.getOwnPropertyDescriptor('f').value;
assertEq(fw.script.source.element, undefined);
g.x = g.Function("return 13;");
var xw = gw.getOwnPropertyDescriptor('x').value;
assertEq(xw.script.source.element, undefined);

View File

@@ -0,0 +1,11 @@
// source.element is undefined when bad values are passed to evaluate().
var g = newGlobal({newCompartment: true});
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
for (let nonObject of [32, "[object Object]", null, undefined]) {
g.evaluate("function f(x) { return 2*x; }", {element: nonObject});
var fw = gw.getOwnPropertyDescriptor('f').value;
assertEq(fw.script.source.element, undefined);
}

View File

@@ -4444,6 +4444,38 @@ static void DestroyShellCompartmentPrivate(JS::GCContext* gcx,
static void SetWorkerContextOptions(JSContext* cx); static void SetWorkerContextOptions(JSContext* cx);
static bool ShellBuildId(JS::BuildIdCharVector* buildId); static bool ShellBuildId(JS::BuildIdCharVector* buildId);
static JSObject* ShellSourceElementCallback(JSContext* cx,
JS::HandleValue privateValue) {
if (!privateValue.isObject()) {
return nullptr;
}
// Due to nukeCCW shenanigans in the shell, we need to check for dead-proxy
// objects that may have replaced an CCW. Otherwise the GetProperty below
// would throw an exception which we do not want to support in this callback.
if (js::IsDeadProxyObject(&privateValue.toObject())) {
return nullptr;
}
RootedObject infoObject(cx,
CheckedUnwrapStatic(privateValue.toObjectOrNull()));
AutoRealm ar(cx, infoObject);
RootedValue elementValue(cx);
if (!JS_GetProperty(cx, infoObject, "element", &elementValue)) {
// This shouldn't happen in the shell, as ParseDebugMetadata always
// creates the infoObject with this property. In any case, this callback
// must not leave an exception pending, so:
MOZ_CRASH("error getting source element");
}
if (elementValue.isObject()) {
return &elementValue.toObject();
}
return nullptr;
}
static constexpr size_t gWorkerStackSize = 2 * 128 * sizeof(size_t) * 1024; static constexpr size_t gWorkerStackSize = 2 * 128 * sizeof(size_t) * 1024;
static void WorkerMain(UniquePtr<WorkerInput> input) { static void WorkerMain(UniquePtr<WorkerInput> input) {
@@ -4479,6 +4511,7 @@ static void WorkerMain(UniquePtr<WorkerInput> input) {
DummyHasReleasedWrapperCallback); DummyHasReleasedWrapperCallback);
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy); JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate); JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate);
JS::SetSourceElementCallback(cx, ShellSourceElementCallback);
js::SetWindowProxyClass(cx, &ShellWindowProxyClass); js::SetWindowProxyClass(cx, &ShellWindowProxyClass);
@@ -12541,6 +12574,7 @@ int main(int argc, char** argv) {
JS_SetSecurityCallbacks(cx, &ShellPrincipals::securityCallbacks); JS_SetSecurityCallbacks(cx, &ShellPrincipals::securityCallbacks);
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy); JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate); JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate);
JS::SetSourceElementCallback(cx, ShellSourceElementCallback);
js::SetWindowProxyClass(cx, &ShellWindowProxyClass); js::SetWindowProxyClass(cx, &ShellWindowProxyClass);

View File

@@ -494,6 +494,12 @@ JS_PUBLIC_API bool JS::UpdateDebugMetadata(
return true; return true;
} }
JS_PUBLIC_API void JS::SetSourceElementCallback(
JSContext* cx, JSSourceElementCallback callback) {
MOZ_ASSERT(cx->runtime());
cx->runtime()->setSourceElementCallback(cx->runtime(), callback);
}
MOZ_NEVER_INLINE static bool ExecuteScript(JSContext* cx, HandleObject envChain, MOZ_NEVER_INLINE static bool ExecuteScript(JSContext* cx, HandleObject envChain,
HandleScript script, HandleScript script,
MutableHandleValue rval) { MutableHandleValue rval) {

View File

@@ -830,6 +830,19 @@ void ScriptSourceObject::setPrivate(JSRuntime* rt, const Value& value) {
rt->addRefScriptPrivate(value); rt->addRefScriptPrivate(value);
} }
JSObject* ScriptSourceObject::unwrappedElement(JSContext* cx) const {
JS::RootedValue privateValue(cx, getPrivate());
if (privateValue.isUndefined()) {
return nullptr;
}
if (cx->runtime()->sourceElementCallback) {
return (*cx->runtime()->sourceElementCallback)(cx, privateValue);
}
return nullptr;
}
class ScriptSource::LoadSourceMatcher { class ScriptSource::LoadSourceMatcher {
JSContext* const cx_; JSContext* const cx_;
ScriptSource* const ss_; ScriptSource* const ss_;

View File

@@ -322,6 +322,11 @@ void JSRuntime::setTelemetryCallback(
rt->telemetryCallback = callback; rt->telemetryCallback = callback;
} }
void JSRuntime::setSourceElementCallback(JSRuntime* rt,
JSSourceElementCallback callback) {
rt->sourceElementCallback = callback;
}
void JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter) { void JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter) {
if (useCounterCallback) { if (useCounterCallback) {
(*useCounterCallback)(obj, counter); (*useCounterCallback)(obj, counter);

View File

@@ -319,6 +319,8 @@ struct JSRuntime {
/* Call this to accumulate use counter data. */ /* Call this to accumulate use counter data. */
js::MainThreadData<JSSetUseCounterCallback> useCounterCallback; js::MainThreadData<JSSetUseCounterCallback> useCounterCallback;
js::MainThreadData<JSSourceElementCallback> sourceElementCallback;
public: public:
// Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_* // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
// histogram. |key| provides an additional key to identify the histogram. // histogram. |key| provides an additional key to identify the histogram.
@@ -330,6 +332,9 @@ struct JSRuntime {
void setTelemetryCallback(JSRuntime* rt, void setTelemetryCallback(JSRuntime* rt,
JSAccumulateTelemetryDataCallback callback); JSAccumulateTelemetryDataCallback callback);
void setSourceElementCallback(JSRuntime* rt,
JSSourceElementCallback callback);
// Sets the use counter for a specific feature, measuring the presence or // 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 // absence of usage of a feature on a specific web page and document which
// the passed JSObject belongs to. // the passed JSObject belongs to.