mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 19:37:15 +00:00
Backed out 3 changesets (bug 1763586) for causing mochitest-chrome failures on test_Debugger.Source.prototype.element.html.
Backed out changeset f6b6ccfce3d1 (bug 1763586) Backed out changeset ca0157c919a9 (bug 1763586) Backed out changeset e0294a6f9f9f (bug 1763586)
This commit is contained in:
parent
54f7c29a1d
commit
2844dc6b1f
@ -1240,7 +1240,7 @@ nsresult EventListenerManager::CompileEventHandlerInternal(
|
||||
aElement->OwnerDoc()->NodePrincipal());
|
||||
|
||||
RefPtr<JS::loader::EventScript> eventScript =
|
||||
new JS::loader::EventScript(fetchOptions, uri);
|
||||
new JS::loader::EventScript(fetchOptions, uri, aElement);
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
// Use line 0 to make the function body starts from line 1.
|
||||
|
@ -242,7 +242,8 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateTopLevel(
|
||||
|
||||
already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateStaticImport(
|
||||
nsIURI* aURI, ModuleLoadRequest* aParent) {
|
||||
RefPtr<ScriptLoadContext> newContext = new ScriptLoadContext();
|
||||
RefPtr<ScriptLoadContext> newContext =
|
||||
new ScriptLoadContext(aParent->GetLoadContext()->mElement);
|
||||
newContext->mIsInline = false;
|
||||
// Propagated Parent values. TODO: allow child modules to use root module's
|
||||
// script mode.
|
||||
@ -264,13 +265,15 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateDynamicImport(
|
||||
MOZ_ASSERT(aSpecifier);
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
RefPtr<ScriptFetchOptions> options = nullptr;
|
||||
RefPtr<ScriptFetchOptions> options;
|
||||
nsIURI* baseURL = nullptr;
|
||||
RefPtr<ScriptLoadContext> context = new ScriptLoadContext();
|
||||
RefPtr<ScriptLoadContext> context;
|
||||
|
||||
if (aMaybeActiveScript) {
|
||||
options = aMaybeActiveScript->GetFetchOptions();
|
||||
baseURL = aMaybeActiveScript->BaseURL();
|
||||
nsCOMPtr<Element> element = aMaybeActiveScript->GetScriptElement();
|
||||
context = new ScriptLoadContext(element);
|
||||
} else {
|
||||
// We don't have a referencing script so fall back on using
|
||||
// options from the document. This can happen when the user
|
||||
@ -283,9 +286,10 @@ already_AddRefed<ModuleLoadRequest> ModuleLoader::CreateDynamicImport(
|
||||
BasePrincipal::Cast(principal)->ContentScriptAddonPolicy());
|
||||
MOZ_ASSERT_IF(GetKind() == Normal, principal == document->NodePrincipal());
|
||||
|
||||
options = new ScriptFetchOptions(
|
||||
mozilla::CORS_NONE, document->GetReferrerPolicy(), principal, nullptr);
|
||||
options = new ScriptFetchOptions(mozilla::CORS_NONE,
|
||||
document->GetReferrerPolicy(), principal);
|
||||
baseURL = document->GetDocBaseURI();
|
||||
context = new ScriptLoadContext(nullptr);
|
||||
}
|
||||
|
||||
context->mIsInline = false;
|
||||
|
@ -38,7 +38,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(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)) {
|
||||
runnable->Release();
|
||||
}
|
||||
@ -46,13 +46,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
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_TRACE_BEGIN(ScriptLoadContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
ScriptLoadContext::ScriptLoadContext()
|
||||
ScriptLoadContext::ScriptLoadContext(Element* aElement)
|
||||
: mScriptMode(ScriptMode::eBlocking),
|
||||
mScriptFromHead(false),
|
||||
mIsInline(true),
|
||||
@ -67,6 +67,7 @@ ScriptLoadContext::ScriptLoadContext()
|
||||
mRunnable(nullptr),
|
||||
mLineNo(1),
|
||||
mIsPreload(false),
|
||||
mElement(aElement),
|
||||
mRequest(nullptr),
|
||||
mUnreportedPreloadError(NS_OK) {}
|
||||
|
||||
@ -179,8 +180,12 @@ bool ScriptLoadContext::CompileStarted() const {
|
||||
}
|
||||
|
||||
nsIScriptElement* ScriptLoadContext::GetScriptElement() const {
|
||||
nsCOMPtr<nsIScriptElement> scriptElement =
|
||||
do_QueryInterface(mRequest->mFetchOptions->mElement);
|
||||
if (mRequest->IsModuleRequest() && !mRequest->IsTopLevel()) {
|
||||
JS::loader::ModuleLoadRequest* root =
|
||||
mRequest->AsModuleRequest()->GetRootModule();
|
||||
return root->GetLoadContext()->GetScriptElement();
|
||||
}
|
||||
nsCOMPtr<nsIScriptElement> scriptElement = do_QueryInterface(mElement);
|
||||
return scriptElement;
|
||||
}
|
||||
|
||||
@ -188,9 +193,8 @@ void ScriptLoadContext::SetIsLoadRequest(nsIScriptElement* aElement) {
|
||||
MOZ_ASSERT(aElement);
|
||||
MOZ_ASSERT(!GetScriptElement());
|
||||
MOZ_ASSERT(IsPreload());
|
||||
// We are not tracking our own element, and are relying on the one in
|
||||
// FetchOptions.
|
||||
mRequest->mFetchOptions->mElement = do_QueryInterface(aElement);
|
||||
// TODO: How to allow both to access fetch options
|
||||
mElement = do_QueryInterface(aElement);
|
||||
mIsPreload = false;
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ class ScriptLoadContext : public PreloaderBase {
|
||||
virtual ~ScriptLoadContext();
|
||||
|
||||
public:
|
||||
explicit ScriptLoadContext();
|
||||
explicit ScriptLoadContext(Element* aElement);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadContext)
|
||||
@ -187,6 +187,7 @@ class ScriptLoadContext : public PreloaderBase {
|
||||
|
||||
// Set on scripts and top level modules.
|
||||
bool mIsPreload;
|
||||
nsCOMPtr<Element> mElement;
|
||||
|
||||
RefPtr<JS::loader::ScriptLoadRequest> mRequest;
|
||||
|
||||
|
@ -817,14 +817,13 @@ already_AddRefed<ScriptLoadRequest> ScriptLoader::CreateLoadRequest(
|
||||
const SRIMetadata& aIntegrity, ReferrerPolicy aReferrerPolicy) {
|
||||
nsIURI* referrer = mDocument->GetDocumentURIAsReferrer();
|
||||
nsCOMPtr<Element> domElement = do_QueryInterface(aElement);
|
||||
RefPtr<ScriptFetchOptions> fetchOptions = new ScriptFetchOptions(
|
||||
aCORSMode, aReferrerPolicy, aTriggeringPrincipal, domElement);
|
||||
RefPtr<ScriptLoadContext> context = new ScriptLoadContext();
|
||||
RefPtr<ScriptFetchOptions> fetchOptions =
|
||||
new ScriptFetchOptions(aCORSMode, aReferrerPolicy, aTriggeringPrincipal);
|
||||
RefPtr<ScriptLoadContext> context = new ScriptLoadContext(domElement);
|
||||
|
||||
if (aKind == ScriptKind::eClassic) {
|
||||
RefPtr<ScriptLoadRequest> aRequest =
|
||||
new ScriptLoadRequest(aKind, aURI, fetchOptions, aIntegrity, referrer,
|
||||
new ScriptLoadContext());
|
||||
RefPtr<ScriptLoadRequest> aRequest = new ScriptLoadRequest(
|
||||
aKind, aURI, fetchOptions, aIntegrity, referrer, context);
|
||||
|
||||
return aRequest.forget();
|
||||
}
|
||||
@ -2268,7 +2267,8 @@ nsresult ScriptLoader::EvaluateScript(nsIGlobalObject* aGlobalObject,
|
||||
|
||||
// Create a ClassicScript object and associate it with the JSScript.
|
||||
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::CompileOptions options(cx);
|
||||
|
@ -51,6 +51,34 @@
|
||||
namespace mozilla {
|
||||
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;
|
||||
|
||||
class ScriptSettingsStack {
|
||||
@ -312,6 +340,7 @@ void AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal,
|
||||
mOldWarningReporter.emplace(JS::GetWarningReporter(aCx));
|
||||
|
||||
JS::SetWarningReporter(aCx, WarningOnlyErrorReporter);
|
||||
JS::SetSourceElementCallback(aCx, SourceElementCallback);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (haveException) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "LoadedScript.h"
|
||||
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#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(mFetchOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
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_TRACE_BEGIN(LoadedScript)
|
||||
@ -38,8 +40,11 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadedScript)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadedScript)
|
||||
|
||||
LoadedScript::LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions,
|
||||
nsIURI* aBaseURL)
|
||||
: mKind(aKind), mFetchOptions(aFetchOptions), mBaseURL(aBaseURL) {
|
||||
nsIURI* aBaseURL, mozilla::dom::Element* aElement)
|
||||
: mKind(aKind),
|
||||
mFetchOptions(aFetchOptions),
|
||||
mBaseURL(aBaseURL),
|
||||
mElement(aElement) {
|
||||
MOZ_ASSERT(mFetchOptions);
|
||||
MOZ_ASSERT(mBaseURL);
|
||||
}
|
||||
@ -89,16 +94,17 @@ void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
|
||||
// EventScript
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
EventScript::EventScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL)
|
||||
: LoadedScript(ScriptKind::eEvent, aFetchOptions, aBaseURL) {}
|
||||
EventScript::EventScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
|
||||
mozilla::dom::Element* aElement)
|
||||
: LoadedScript(ScriptKind::eEvent, aFetchOptions, aBaseURL, aElement) {}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ClassicScript
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
ClassicScript::ClassicScript(ScriptFetchOptions* aFetchOptions,
|
||||
nsIURI* aBaseURL)
|
||||
: LoadedScript(ScriptKind::eClassic, aFetchOptions, aBaseURL) {}
|
||||
nsIURI* aBaseURL, mozilla::dom::Element* aElement)
|
||||
: LoadedScript(ScriptKind::eClassic, aFetchOptions, aBaseURL, aElement) {}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ModuleScript
|
||||
@ -127,8 +133,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
NS_IMPL_ADDREF_INHERITED(ModuleScript, LoadedScript)
|
||||
NS_IMPL_RELEASE_INHERITED(ModuleScript, LoadedScript)
|
||||
|
||||
ModuleScript::ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL)
|
||||
: LoadedScript(ScriptKind::eModule, aFetchOptions, aBaseURL),
|
||||
ModuleScript::ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
|
||||
mozilla::dom::Element* aElement)
|
||||
: LoadedScript(ScriptKind::eModule, aFetchOptions, aBaseURL, aElement),
|
||||
mDebuggerDataInitialized(false) {
|
||||
MOZ_ASSERT(!ModuleRecord());
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
|
@ -27,10 +27,11 @@ class LoadedScript : public nsISupports {
|
||||
ScriptKind mKind;
|
||||
RefPtr<ScriptFetchOptions> mFetchOptions;
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
RefPtr<mozilla::dom::Element> mElement;
|
||||
|
||||
protected:
|
||||
LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions,
|
||||
nsIURI* aBaseURL);
|
||||
nsIURI* aBaseURL, mozilla::dom::Element* aElement);
|
||||
|
||||
virtual ~LoadedScript();
|
||||
|
||||
@ -48,6 +49,9 @@ class LoadedScript : public nsISupports {
|
||||
// Used to propagate Fetch Options to child modules
|
||||
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; }
|
||||
|
||||
void AssociateWithScript(JSScript* aScript);
|
||||
@ -57,14 +61,16 @@ class ClassicScript final : public LoadedScript {
|
||||
~ClassicScript() = default;
|
||||
|
||||
public:
|
||||
ClassicScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL);
|
||||
ClassicScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
|
||||
mozilla::dom::Element* aElement);
|
||||
};
|
||||
|
||||
class EventScript final : public LoadedScript {
|
||||
~EventScript() = default;
|
||||
|
||||
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.
|
||||
@ -82,7 +88,8 @@ class ModuleScript final : public LoadedScript {
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleScript,
|
||||
LoadedScript)
|
||||
|
||||
ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL);
|
||||
ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
|
||||
mozilla::dom::Element* aElement);
|
||||
|
||||
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||
void SetParseError(const JS::Value& aError);
|
||||
|
@ -491,7 +491,8 @@ nsresult ModuleLoaderBase::CreateModuleScript(ModuleLoadRequest* aRequest) {
|
||||
}
|
||||
|
||||
RefPtr<ModuleScript> moduleScript =
|
||||
new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL);
|
||||
new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL,
|
||||
aRequest->mLoadContext->mElement);
|
||||
aRequest->mModuleScript = moduleScript;
|
||||
|
||||
if (!module) {
|
||||
|
@ -32,18 +32,17 @@ namespace JS::loader {
|
||||
// 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_UNROOT_NATIVE(ScriptFetchOptions, Release)
|
||||
|
||||
ScriptFetchOptions::ScriptFetchOptions(
|
||||
mozilla::CORSMode aCORSMode, mozilla::dom::ReferrerPolicy aReferrerPolicy,
|
||||
nsIPrincipal* aTriggeringPrincipal, mozilla::dom::Element* aElement)
|
||||
nsIPrincipal* aTriggeringPrincipal)
|
||||
: mCORSMode(aCORSMode),
|
||||
mReferrerPolicy(aReferrerPolicy),
|
||||
mTriggeringPrincipal(aTriggeringPrincipal),
|
||||
mElement(aElement) {
|
||||
mTriggeringPrincipal(aTriggeringPrincipal) {
|
||||
MOZ_ASSERT(mTriggeringPrincipal);
|
||||
}
|
||||
|
||||
|
@ -53,16 +53,10 @@ class ScriptLoadRequestList;
|
||||
* with the exception of the following properties:
|
||||
* cryptographic nonce
|
||||
* The cryptographic nonce metadata used for the initial fetch and for
|
||||
* fetching any imported modules. As this is populated by a DOM element,
|
||||
* 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.
|
||||
* fetching any imported modules. This is handled by the principal.
|
||||
* parser metadata
|
||||
* The parser metadata used for the initial fetch and for fetching any
|
||||
* imported modules. This is populated from a mozilla::dom::Element and is
|
||||
* handled by the field mElement. The default value is an empty string,
|
||||
* and is indicated when this field is a nullptr.
|
||||
* imported modules. This is not implemented.
|
||||
* integrity metadata
|
||||
* The integrity metadata used for the initial fetch. This is
|
||||
* implemented in ScriptLoadRequest, as it changes for every
|
||||
@ -83,8 +77,7 @@ class ScriptFetchOptions {
|
||||
|
||||
ScriptFetchOptions(mozilla::CORSMode aCORSMode,
|
||||
enum mozilla::dom::ReferrerPolicy aReferrerPolicy,
|
||||
nsIPrincipal* aTriggeringPrincipal,
|
||||
mozilla::dom::Element* aElement = nullptr);
|
||||
nsIPrincipal* aTriggeringPrincipal);
|
||||
|
||||
/*
|
||||
* The credentials mode used for the initial fetch (for module scripts)
|
||||
@ -100,16 +93,9 @@ class ScriptFetchOptions {
|
||||
const enum mozilla::dom::ReferrerPolicy mReferrerPolicy;
|
||||
|
||||
/*
|
||||
* Used to determine CSP
|
||||
* Related to cryptographic nonce, used to determine CSP
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -90,6 +90,11 @@ extern JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
|
||||
JS::HandleObjectVector envChain,
|
||||
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 {
|
||||
|
||||
/**
|
||||
@ -246,6 +251,14 @@ extern JS_PUBLIC_API bool UpdateDebugMetadata(
|
||||
HandleValue privateValue, HandleString elementAttributeName,
|
||||
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 */
|
||||
|
||||
#endif /* js_CompilationAndEvaluation_h */
|
||||
|
@ -171,6 +171,7 @@ struct MOZ_STACK_CLASS DebuggerSource::CallData {
|
||||
bool getStartLine();
|
||||
bool getId();
|
||||
bool getDisplayURL();
|
||||
bool getElement();
|
||||
bool getElementProperty();
|
||||
bool getIntroductionScript();
|
||||
bool getIntroductionOffset();
|
||||
@ -383,6 +384,29 @@ bool DebuggerSource::CallData::getDisplayURL() {
|
||||
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 {
|
||||
using ReturnType = Value;
|
||||
ReturnType match(HandleScriptSourceObject sourceObject) {
|
||||
@ -650,6 +674,7 @@ const JSPropertySpec DebuggerSource::properties_[] = {
|
||||
JS_DEBUG_PSG("url", getURL),
|
||||
JS_DEBUG_PSG("startLine", getStartLine),
|
||||
JS_DEBUG_PSG("id", getId),
|
||||
JS_DEBUG_PSG("element", getElement),
|
||||
JS_DEBUG_PSG("displayURL", getDisplayURL),
|
||||
JS_DEBUG_PSG("introductionScript", getIntroductionScript),
|
||||
JS_DEBUG_PSG("introductionOffset", getIntroductionOffset),
|
||||
|
@ -1,6 +1,13 @@
|
||||
// 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.
|
||||
// Source.prototype.element can be an object or undefined.
|
||||
|
||||
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");
|
||||
|
6
js/src/jit-test/tests/debug/Source-element-02.js
Normal file
6
js/src/jit-test/tests/debug/Source-element-02.js
Normal 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: {} });
|
29
js/src/jit-test/tests/debug/Source-element-03.js
Normal file
29
js/src/jit-test/tests/debug/Source-element-03.js
Normal 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');
|
13
js/src/jit-test/tests/debug/Source-element-04.js
Normal file
13
js/src/jit-test/tests/debug/Source-element-04.js
Normal 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);
|
11
js/src/jit-test/tests/debug/Source-element-05.js
Normal file
11
js/src/jit-test/tests/debug/Source-element-05.js
Normal 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);
|
||||
}
|
32
js/src/jit-test/tests/xdr/debug-metadata.js
Normal file
32
js/src/jit-test/tests/xdr/debug-metadata.js
Normal file
@ -0,0 +1,32 @@
|
||||
var g = newGlobal({ newCompartment: true });
|
||||
var dbg = new Debugger(g);
|
||||
var count = 0;
|
||||
|
||||
dbg.onNewScript = script => {
|
||||
var source = script.source;
|
||||
assertEq(source.element.getOwnPropertyDescriptor("name").value, "hello");
|
||||
assertEq(source.elementAttributeName, "world");
|
||||
count++;
|
||||
};
|
||||
|
||||
var stencil = g.compileToStencil(`"a"`);
|
||||
g.evalStencil(stencil, {
|
||||
element: { name: "hello" },
|
||||
elementAttributeName: "world",
|
||||
});
|
||||
assertEq(count, 1);
|
||||
|
||||
count = 0;
|
||||
dbg.onNewScript = script => {
|
||||
var source = script.source;
|
||||
assertEq(source.element.getOwnPropertyDescriptor("name").value, "HELLO");
|
||||
assertEq(source.elementAttributeName, "WORLD");
|
||||
count++;
|
||||
};
|
||||
|
||||
var stencilXDR = g.compileToStencilXDR(`"b"`);
|
||||
g.evalStencilXDR(stencilXDR, {
|
||||
element: { name: "HELLO" },
|
||||
elementAttributeName: "WORLD",
|
||||
});
|
||||
assertEq(count, 1);
|
@ -4444,6 +4444,38 @@ static void DestroyShellCompartmentPrivate(JS::GCContext* gcx,
|
||||
static void SetWorkerContextOptions(JSContext* cx);
|
||||
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 void WorkerMain(UniquePtr<WorkerInput> input) {
|
||||
@ -4479,6 +4511,7 @@ static void WorkerMain(UniquePtr<WorkerInput> input) {
|
||||
DummyHasReleasedWrapperCallback);
|
||||
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
|
||||
JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate);
|
||||
JS::SetSourceElementCallback(cx, ShellSourceElementCallback);
|
||||
|
||||
js::SetWindowProxyClass(cx, &ShellWindowProxyClass);
|
||||
|
||||
@ -12541,6 +12574,7 @@ int main(int argc, char** argv) {
|
||||
JS_SetSecurityCallbacks(cx, &ShellPrincipals::securityCallbacks);
|
||||
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
|
||||
JS_SetDestroyCompartmentCallback(cx, DestroyShellCompartmentPrivate);
|
||||
JS::SetSourceElementCallback(cx, ShellSourceElementCallback);
|
||||
|
||||
js::SetWindowProxyClass(cx, &ShellWindowProxyClass);
|
||||
|
||||
|
@ -494,6 +494,12 @@ JS_PUBLIC_API bool JS::UpdateDebugMetadata(
|
||||
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,
|
||||
HandleScript script,
|
||||
MutableHandleValue rval) {
|
||||
|
@ -830,6 +830,19 @@ void ScriptSourceObject::setPrivate(JSRuntime* rt, const Value& 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 {
|
||||
JSContext* const cx_;
|
||||
ScriptSource* const ss_;
|
||||
|
@ -322,6 +322,11 @@ void JSRuntime::setTelemetryCallback(
|
||||
rt->telemetryCallback = callback;
|
||||
}
|
||||
|
||||
void JSRuntime::setSourceElementCallback(JSRuntime* rt,
|
||||
JSSourceElementCallback callback) {
|
||||
rt->sourceElementCallback = callback;
|
||||
}
|
||||
|
||||
void JSRuntime::setUseCounter(JSObject* obj, JSUseCounter counter) {
|
||||
if (useCounterCallback) {
|
||||
(*useCounterCallback)(obj, counter);
|
||||
|
@ -319,6 +319,8 @@ struct JSRuntime {
|
||||
/* Call this to accumulate use counter data. */
|
||||
js::MainThreadData<JSSetUseCounterCallback> useCounterCallback;
|
||||
|
||||
js::MainThreadData<JSSourceElementCallback> sourceElementCallback;
|
||||
|
||||
public:
|
||||
// Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
|
||||
// histogram. |key| provides an additional key to identify the histogram.
|
||||
@ -330,6 +332,9 @@ struct JSRuntime {
|
||||
void setTelemetryCallback(JSRuntime* rt,
|
||||
JSAccumulateTelemetryDataCallback 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
|
||||
// the passed JSObject belongs to.
|
||||
|
Loading…
x
Reference in New Issue
Block a user