зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1702278 - Defer setting debug metadata until after script compilation is finished. r=tcampbell,smaug
Differential Revision: https://phabricator.services.mozilla.com/D110459
This commit is contained in:
Родитель
ac23d0ea49
Коммит
810f80185c
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/dom/JSExecutionContext.h"
|
||||
|
||||
#include <utility>
|
||||
#include "ErrorList.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/CompileOptions.h"
|
||||
|
@ -47,9 +48,11 @@ static nsresult EvaluationExceptionToNSResult(JSContext* aCx) {
|
|||
return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE;
|
||||
}
|
||||
|
||||
JSExecutionContext::JSExecutionContext(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGlobal,
|
||||
JS::CompileOptions& aCompileOptions)
|
||||
JSExecutionContext::JSExecutionContext(
|
||||
JSContext* aCx, JS::Handle<JSObject*> aGlobal,
|
||||
JS::CompileOptions& aCompileOptions,
|
||||
JS::Handle<JS::Value> aDebuggerPrivateValue,
|
||||
JS::Handle<JSScript*> aDebuggerIntroductionScript)
|
||||
:
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
mAutoProfilerLabel("JSExecutionContext",
|
||||
|
@ -61,6 +64,8 @@ JSExecutionContext::JSExecutionContext(JSContext* aCx,
|
|||
mRetValue(aCx),
|
||||
mScript(aCx),
|
||||
mCompileOptions(aCompileOptions),
|
||||
mDebuggerPrivateValue(aCx, aDebuggerPrivateValue),
|
||||
mDebuggerIntroductionScript(aCx, aDebuggerIntroductionScript),
|
||||
mRv(NS_OK),
|
||||
mSkip(false),
|
||||
mCoerceToString(false),
|
||||
|
@ -105,6 +110,9 @@ nsresult JSExecutionContext::JoinCompile(JS::OffThreadToken** aOffThreadToken) {
|
|||
return mRv;
|
||||
}
|
||||
|
||||
if (!UpdateDebugMetadata()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -135,6 +143,10 @@ nsresult JSExecutionContext::InternalCompile(JS::SourceText<Unit>& aSrcBuf) {
|
|||
return mRv;
|
||||
}
|
||||
|
||||
if (!UpdateDebugMetadata()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -183,9 +195,22 @@ nsresult JSExecutionContext::Decode(mozilla::Vector<uint8_t>& aBytecodeBuf,
|
|||
return mRv;
|
||||
}
|
||||
|
||||
if (!UpdateDebugMetadata()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return mRv;
|
||||
}
|
||||
|
||||
bool JSExecutionContext::UpdateDebugMetadata() {
|
||||
if (!mCompileOptions.deferDebugMetadata) {
|
||||
return true;
|
||||
}
|
||||
return JS::UpdateDebugMetadata(mCx, mScript, mCompileOptions,
|
||||
mDebuggerPrivateValue, nullptr,
|
||||
mDebuggerIntroductionScript, nullptr);
|
||||
}
|
||||
|
||||
nsresult JSExecutionContext::JoinDecode(JS::OffThreadToken** aOffThreadToken) {
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
|
@ -200,6 +225,10 @@ nsresult JSExecutionContext::JoinDecode(JS::OffThreadToken** aOffThreadToken) {
|
|||
return mRv;
|
||||
}
|
||||
|
||||
if (!UpdateDebugMetadata()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "GeckoProfiler.h"
|
||||
#include "js/GCVector.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
@ -47,6 +48,14 @@ class MOZ_STACK_CLASS JSExecutionContext final {
|
|||
// The compilation options applied throughout
|
||||
JS::CompileOptions& mCompileOptions;
|
||||
|
||||
// Debug Metadata: Values managed for the benefit of the debugger when
|
||||
// inspecting code.
|
||||
//
|
||||
// For more details see CompilationAndEvaluation.h, and the comments on
|
||||
// UpdateDebugMetadata
|
||||
JS::Rooted<JS::Value> mDebuggerPrivateValue;
|
||||
JS::Rooted<JSScript*> mDebuggerIntroductionScript;
|
||||
|
||||
// returned value forwarded when we have to interupt the execution eagerly
|
||||
// with mSkip.
|
||||
nsresult mRv;
|
||||
|
@ -68,6 +77,8 @@ class MOZ_STACK_CLASS JSExecutionContext final {
|
|||
bool mScriptUsed;
|
||||
#endif
|
||||
|
||||
bool UpdateDebugMetadata();
|
||||
|
||||
private:
|
||||
// Compile a script contained in a SourceText.
|
||||
template <typename Unit>
|
||||
|
@ -76,8 +87,14 @@ class MOZ_STACK_CLASS JSExecutionContext final {
|
|||
public:
|
||||
// Enter compartment in which the code would be executed. The JSContext
|
||||
// must come from an AutoEntryScript.
|
||||
JSExecutionContext(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
|
||||
JS::CompileOptions& aCompileOptions);
|
||||
//
|
||||
// The JS engine can associate metadata for the debugger with scripts at
|
||||
// compile time. The optional last arguments here cover that metadata.
|
||||
JSExecutionContext(
|
||||
JSContext* aCx, JS::Handle<JSObject*> aGlobal,
|
||||
JS::CompileOptions& aCompileOptions,
|
||||
JS::Handle<JS::Value> aDebuggerPrivateValue = JS::UndefinedHandleValue,
|
||||
JS::Handle<JSScript*> aDebuggerIntroductionScript = nullptr);
|
||||
|
||||
JSExecutionContext(const JSExecutionContext&) = delete;
|
||||
JSExecutionContext(JSExecutionContext&&) = delete;
|
||||
|
|
|
@ -74,6 +74,29 @@ uint64_t nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext) {
|
|||
return win ? win->WindowID() : 0;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::UpdateFunctionDebugMetadata(
|
||||
AutoJSAPI& jsapi, JS::Handle<JSObject*> aFun, JS::CompileOptions& aOptions,
|
||||
JS::Handle<JSString*> aElementAttributeName,
|
||||
JS::Handle<JS::Value> aPrivateValue) {
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(aFun));
|
||||
if (!fun) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JS::RootedScript script(cx, JS_GetFunctionScript(cx, fun));
|
||||
if (!script) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!JS::UpdateDebugMetadata(cx, script, aOptions, aPrivateValue,
|
||||
aElementAttributeName, nullptr, nullptr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
|
||||
JS::HandleVector<JSObject*> aScopeChain,
|
||||
JS::CompileOptions& aOptions,
|
||||
|
|
|
@ -63,6 +63,11 @@ class nsJSUtils {
|
|||
const nsAString& aBody,
|
||||
JSObject** aFunctionObject);
|
||||
|
||||
static nsresult UpdateFunctionDebugMetadata(
|
||||
mozilla::dom::AutoJSAPI& jsapi, JS::Handle<JSObject*> aFun,
|
||||
JS::CompileOptions& aOptions, JS::Handle<JSString*> aElementAttributeName,
|
||||
JS::Handle<JS::Value> aPrivateValue);
|
||||
|
||||
static nsresult CompileModule(JSContext* aCx,
|
||||
JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::Handle<JSObject*> aEvaluationGlobal,
|
||||
|
|
|
@ -1044,8 +1044,7 @@ nsresult EventListenerManager::CompileEventHandlerInternal(
|
|||
// Use line 0 to make the function body starts from line 1.
|
||||
options.setIntroductionType("eventHandler")
|
||||
.setFileAndLine(url.get(), 0)
|
||||
.setElementAttributeName(jsStr)
|
||||
.setPrivateValue(JS::PrivateValue(eventScript));
|
||||
.setdeferDebugMetadata(true);
|
||||
|
||||
JS::Rooted<JSObject*> handler(cx);
|
||||
result = nsJSUtils::CompileFunction(jsapi, scopeChain, options,
|
||||
|
@ -1054,6 +1053,11 @@ nsresult EventListenerManager::CompileEventHandlerInternal(
|
|||
NS_ENSURE_SUCCESS(result, result);
|
||||
NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
|
||||
|
||||
JS::Rooted<JS::Value> privateValue(cx, JS::PrivateValue(eventScript));
|
||||
result = nsJSUtils::UpdateFunctionDebugMetadata(jsapi, handler, options,
|
||||
jsStr, privateValue);
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(handler, cx));
|
||||
JS::Rooted<JSObject*> handlerGlobal(cx, JS::CurrentGlobalOrNull(cx));
|
||||
|
||||
|
|
|
@ -652,18 +652,19 @@ nsresult ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) {
|
|||
{
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> module(cx);
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
if (aRequest->mWasCompiledOMT) {
|
||||
module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
|
||||
aRequest->mOffThreadToken = nullptr;
|
||||
rv = module ? NS_OK : NS_ERROR_FAILURE;
|
||||
} else {
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
JS::CompileOptions options(cx);
|
||||
JS::RootedScript introductionScript(cx);
|
||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options,
|
||||
&introductionScript);
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aRequest->mWasCompiledOMT) {
|
||||
module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
|
||||
aRequest->mOffThreadToken = nullptr;
|
||||
rv = module ? NS_OK : NS_ERROR_FAILURE;
|
||||
} else {
|
||||
MaybeSourceText maybeSource;
|
||||
rv = GetScriptSource(cx, aRequest, &maybeSource);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -680,6 +681,15 @@ nsresult ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) {
|
|||
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
||||
|
||||
if (module) {
|
||||
JS::RootedValue privateValue(cx);
|
||||
JS::RootedScript moduleScript(cx, JS::GetModuleScript(module));
|
||||
if (!JS::UpdateDebugMetadata(cx, moduleScript, options, privateValue,
|
||||
nullptr, introductionScript, nullptr)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<ModuleScript> moduleScript =
|
||||
new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL);
|
||||
aRequest->mModuleScript = moduleScript;
|
||||
|
@ -2542,7 +2552,11 @@ nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
|
|||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
JS::CompileOptions options(cx);
|
||||
|
||||
nsresult rv = FillCompileOptionsForRequest(jsapi, aRequest, global, &options);
|
||||
// Introduction script will actually be computed and set when the script is
|
||||
// collected from offthread
|
||||
JS::RootedScript dummyIntroductionScript(cx);
|
||||
nsresult rv = FillCompileOptionsForRequest(jsapi, aRequest, global, &options,
|
||||
&dummyIntroductionScript);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2908,7 +2922,8 @@ already_AddRefed<nsIScriptGlobalObject> ScriptLoader::GetScriptGlobalObject(
|
|||
|
||||
nsresult ScriptLoader::FillCompileOptionsForRequest(
|
||||
const mozilla::dom::AutoJSAPI& jsapi, ScriptLoadRequest* aRequest,
|
||||
JS::Handle<JSObject*> aScopeChain, JS::CompileOptions* aOptions) {
|
||||
JS::Handle<JSObject*> aScopeChain, JS::CompileOptions* aOptions,
|
||||
JS::MutableHandle<JSScript*> aIntroductionScript) {
|
||||
// It's very important to use aRequest->mURI, not the final URI of the channel
|
||||
// aRequest ended up getting script data from, as the script filename.
|
||||
nsresult rv = aRequest->mURI->GetSpec(aRequest->mURL);
|
||||
|
@ -2931,7 +2946,8 @@ nsresult ScriptLoader::FillCompileOptionsForRequest(
|
|||
} else {
|
||||
introductionType = "injectedScript";
|
||||
}
|
||||
aOptions->setIntroductionInfoToCaller(jsapi.cx(), introductionType);
|
||||
aOptions->setIntroductionInfoToCaller(jsapi.cx(), introductionType,
|
||||
aIntroductionScript);
|
||||
aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
|
||||
aOptions->setIsRunOnce(true);
|
||||
aOptions->setNoScriptRval(true);
|
||||
|
@ -2948,6 +2964,8 @@ nsresult ScriptLoader::FillCompileOptionsForRequest(
|
|||
aOptions->hideScriptFromDebugger = true;
|
||||
}
|
||||
|
||||
aOptions->setdeferDebugMetadata(true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3240,15 +3258,18 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
|||
// Create a ClassicScript object and associate it with the JSScript.
|
||||
RefPtr<ClassicScript> classicScript =
|
||||
new ClassicScript(aRequest->mFetchOptions, aRequest->mBaseURL);
|
||||
JS::RootedValue classicScriptValue(cx, JS::PrivateValue(classicScript));
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
||||
options.setPrivateValue(JS::PrivateValue(classicScript));
|
||||
JS::RootedScript introductionScript(cx);
|
||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options,
|
||||
&introductionScript);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aRequest->IsBytecode()) {
|
||||
TRACE_FOR_TEST(aRequest->GetScriptElement(), "scriptloader_execute");
|
||||
JSExecutionContext exec(cx, global, options);
|
||||
JSExecutionContext exec(cx, global, options, classicScriptValue,
|
||||
introductionScript);
|
||||
if (aRequest->mOffThreadToken) {
|
||||
LOG(("ScriptLoadRequest (%p): Decode Bytecode & Join and Execute",
|
||||
aRequest));
|
||||
|
@ -3280,7 +3301,8 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
|||
bool encodeBytecode = ShouldCacheBytecode(aRequest);
|
||||
|
||||
{
|
||||
JSExecutionContext exec(cx, global, options);
|
||||
JSExecutionContext exec(cx, global, options, classicScriptValue,
|
||||
introductionScript);
|
||||
exec.SetEncodeBytecode(encodeBytecode);
|
||||
TRACE_FOR_TEST(aRequest->GetScriptElement(),
|
||||
"scriptloader_execute");
|
||||
|
|
|
@ -637,10 +637,12 @@ class ScriptLoader final : public nsISupports {
|
|||
already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject(
|
||||
WebExtGlobal aWebExtGlobal);
|
||||
|
||||
nsresult FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI& jsapi,
|
||||
ScriptLoadRequest* aRequest,
|
||||
JS::Handle<JSObject*> aScopeChain,
|
||||
JS::CompileOptions* aOptions);
|
||||
// Fill in CompileOptions, as well as produce the introducer script for
|
||||
// subsequent calls to UpdateDebuggerMetadata
|
||||
nsresult FillCompileOptionsForRequest(
|
||||
const mozilla::dom::AutoJSAPI& jsapi, ScriptLoadRequest* aRequest,
|
||||
JS::Handle<JSObject*> aScopeChain, JS::CompileOptions* aOptions,
|
||||
JS::MutableHandle<JSScript*> aIntroductionScript);
|
||||
|
||||
uint32_t NumberOfProcessors();
|
||||
nsresult PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
||||
|
|
|
@ -242,6 +242,30 @@ extern JS_PUBLIC_API JSFunction* CompileFunctionUtf8(
|
|||
extern JS_PUBLIC_API void ExposeScriptToDebugger(JSContext* cx,
|
||||
Handle<JSScript*> script);
|
||||
|
||||
/*
|
||||
* JSScripts have associated with them (via their ScriptSourceObjects) some
|
||||
* metadata used by the debugger. The following API functions are used to set
|
||||
* that metadata on scripts, functions and modules.
|
||||
*
|
||||
* The metadata consists of:
|
||||
* - A privateValue, which is used to keep some object value associated
|
||||
* with the script.
|
||||
* - The elementAttributeName is used by Gecko
|
||||
* - The introductionScript is used by the debugger to identify which
|
||||
* script created which. Only set for dynamicaly generated scripts.
|
||||
* - scriptOrModule is used to transfer private value metadata from
|
||||
* script to script
|
||||
*
|
||||
* Callers using UpdateDebugMetaData need to have set deferDebugMetadata
|
||||
* in the compile options; this hides the script from the debugger until
|
||||
* the debug metadata is provided by the UpdateDebugMetadata call.
|
||||
*/
|
||||
extern JS_PUBLIC_API bool UpdateDebugMetadata(
|
||||
JSContext* cx, Handle<JSScript*> script,
|
||||
const ReadOnlyCompileOptions& options, HandleValue privateValue,
|
||||
HandleString elementAttributeName, HandleScript introScript,
|
||||
HandleScript scriptOrModule);
|
||||
|
||||
extern JS_PUBLIC_API void SetGetElementCallback(JSContext* cx,
|
||||
JSGetElementCallback callback);
|
||||
|
||||
|
|
|
@ -128,6 +128,17 @@ class JS_PUBLIC_API TransitiveCompileOptions {
|
|||
bool sourceIsLazy = false;
|
||||
bool allowHTMLComments = true;
|
||||
bool hideScriptFromDebugger = false;
|
||||
|
||||
// If set, this script will be hidden from the debugger. The requirement
|
||||
// is that once compilation is finished, a call to UpdateDebugMetadata will
|
||||
// be made, which will update the SSO with the appropiate debug metadata,
|
||||
// and expose the script to the debugger (if hideScriptFromDebugger isn't set)
|
||||
bool deferDebugMetadata = false;
|
||||
|
||||
bool hideFromNewScriptInitial() const {
|
||||
return deferDebugMetadata || hideScriptFromDebugger;
|
||||
}
|
||||
|
||||
bool nonSyntacticScope = false;
|
||||
bool privateClassFields = false;
|
||||
bool privateClassMethods = false;
|
||||
|
@ -172,18 +183,6 @@ class JS_PUBLIC_API TransitiveCompileOptions {
|
|||
const char* filename() const { return filename_; }
|
||||
const char* introducerFilename() const { return introducerFilename_; }
|
||||
const char16_t* sourceMapURL() const { return sourceMapURL_; }
|
||||
virtual Value privateValue() const = 0;
|
||||
virtual JSString* elementAttributeName() const = 0;
|
||||
virtual JSScript* introductionScript() const = 0;
|
||||
|
||||
// For some compilations the spec requires the ScriptOrModule field of the
|
||||
// resulting script to be set to the currently executing script. This can be
|
||||
// achieved by setting this option with setScriptOrModule() below.
|
||||
//
|
||||
// Note that this field doesn't explicitly exist in our implementation;
|
||||
// instead the ScriptSourceObject's private value is set to that associated
|
||||
// with the specified script.
|
||||
virtual JSScript* scriptOrModule() const = 0;
|
||||
|
||||
TransitiveCompileOptions(const TransitiveCompileOptions&) = delete;
|
||||
TransitiveCompileOptions& operator=(const TransitiveCompileOptions&) = delete;
|
||||
|
@ -243,25 +242,11 @@ class JS_PUBLIC_API ReadOnlyCompileOptions : public TransitiveCompileOptions {
|
|||
* anything else it entrains, will never be freed.
|
||||
*/
|
||||
class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
|
||||
PersistentRooted<JSString*> elementAttributeNameRoot;
|
||||
PersistentRooted<JSScript*> introductionScriptRoot;
|
||||
PersistentRooted<JSScript*> scriptOrModuleRoot;
|
||||
PersistentRooted<Value> privateValueRoot;
|
||||
|
||||
public:
|
||||
// A minimal constructor, for use with OwningCompileOptions::copy.
|
||||
explicit OwningCompileOptions(JSContext* cx);
|
||||
~OwningCompileOptions();
|
||||
|
||||
Value privateValue() const override { return privateValueRoot; }
|
||||
JSString* elementAttributeName() const override {
|
||||
return elementAttributeNameRoot;
|
||||
}
|
||||
JSScript* introductionScript() const override {
|
||||
return introductionScriptRoot;
|
||||
}
|
||||
JSScript* scriptOrModule() const override { return scriptOrModuleRoot; }
|
||||
|
||||
/** Set this to a copy of |rhs|. Return false on OOM. */
|
||||
bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs);
|
||||
|
||||
|
@ -301,12 +286,6 @@ class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
|
|||
*/
|
||||
class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
|
||||
: public ReadOnlyCompileOptions {
|
||||
private:
|
||||
Rooted<JSString*> elementAttributeNameRoot;
|
||||
Rooted<JSScript*> introductionScriptRoot;
|
||||
Rooted<JSScript*> scriptOrModuleRoot;
|
||||
Rooted<Value> privateValueRoot;
|
||||
|
||||
public:
|
||||
// Default options determined using the JSContext.
|
||||
explicit CompileOptions(JSContext* cx);
|
||||
|
@ -314,35 +293,15 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
|
|||
// Copy both the transitive and the non-transitive options from another
|
||||
// options object.
|
||||
CompileOptions(JSContext* cx, const ReadOnlyCompileOptions& rhs)
|
||||
: ReadOnlyCompileOptions(),
|
||||
elementAttributeNameRoot(cx),
|
||||
introductionScriptRoot(cx),
|
||||
scriptOrModuleRoot(cx),
|
||||
privateValueRoot(cx) {
|
||||
: ReadOnlyCompileOptions() {
|
||||
copyPODNonTransitiveOptions(rhs);
|
||||
copyPODTransitiveOptions(rhs);
|
||||
|
||||
filename_ = rhs.filename();
|
||||
introducerFilename_ = rhs.introducerFilename();
|
||||
sourceMapURL_ = rhs.sourceMapURL();
|
||||
privateValueRoot = rhs.privateValue();
|
||||
elementAttributeNameRoot = rhs.elementAttributeName();
|
||||
introductionScriptRoot = rhs.introductionScript();
|
||||
scriptOrModuleRoot = rhs.scriptOrModule();
|
||||
}
|
||||
|
||||
Value privateValue() const override { return privateValueRoot; }
|
||||
|
||||
JSString* elementAttributeName() const override {
|
||||
return elementAttributeNameRoot;
|
||||
}
|
||||
|
||||
JSScript* introductionScript() const override {
|
||||
return introductionScriptRoot;
|
||||
}
|
||||
|
||||
JSScript* scriptOrModule() const override { return scriptOrModuleRoot; }
|
||||
|
||||
CompileOptions& setFile(const char* f) {
|
||||
filename_ = f;
|
||||
return *this;
|
||||
|
@ -364,21 +323,6 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
|
|||
return *this;
|
||||
}
|
||||
|
||||
CompileOptions& setPrivateValue(const Value& v) {
|
||||
privateValueRoot = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompileOptions& setElementAttributeName(JSString* p) {
|
||||
elementAttributeNameRoot = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompileOptions& setScriptOrModule(JSScript* s) {
|
||||
scriptOrModuleRoot = s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompileOptions& setMutedErrors(bool mute) {
|
||||
mutedErrors_ = mute;
|
||||
return *this;
|
||||
|
@ -429,21 +373,26 @@ class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
|
|||
return *this;
|
||||
}
|
||||
|
||||
CompileOptions& setdeferDebugMetadata(bool v = true) {
|
||||
deferDebugMetadata = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompileOptions& setIntroductionInfo(const char* introducerFn,
|
||||
const char* intro, unsigned line,
|
||||
JSScript* script, uint32_t offset) {
|
||||
uint32_t offset) {
|
||||
introducerFilename_ = introducerFn;
|
||||
introductionType = intro;
|
||||
introductionLineno = line;
|
||||
introductionScriptRoot = script;
|
||||
introductionOffset = offset;
|
||||
hasIntroductionInfo = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Set introduction information according to any currently executing script.
|
||||
CompileOptions& setIntroductionInfoToCaller(JSContext* cx,
|
||||
const char* introductionType);
|
||||
CompileOptions& setIntroductionInfoToCaller(
|
||||
JSContext* cx, const char* introductionType,
|
||||
JS::MutableHandle<JSScript*> introductionScript);
|
||||
|
||||
CompileOptions& setForceFullParse() {
|
||||
forceFullParse_ = true;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "ds/LifoAlloc.h"
|
||||
#include "frontend/BytecodeCompilation.h"
|
||||
#include "gc/HashUtil.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/friend/JSMEnvironment.h" // JS::NewJSMEnvironment, JS::ExecuteInJSMEnvironment, JS::GetJSMEnvironmentOfScriptedCaller, JS::IsJSMEnvironment
|
||||
#include "js/friend/WindowProxy.h" // js::IsWindowProxy
|
||||
|
@ -300,7 +301,9 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
|
|||
options.setIsRunOnce(true)
|
||||
.setNoScriptRval(false)
|
||||
.setMutedErrors(mutedErrors)
|
||||
.setScriptOrModule(maybeScript);
|
||||
.setdeferDebugMetadata();
|
||||
|
||||
RootedScript introScript(cx);
|
||||
|
||||
if (evalType == DIRECT_EVAL && IsStrictEvalPC(pc)) {
|
||||
options.setForceStrictMode();
|
||||
|
@ -308,8 +311,8 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
|
|||
|
||||
if (introducerFilename) {
|
||||
options.setFileAndLine(filename, 1);
|
||||
options.setIntroductionInfo(introducerFilename, "eval", lineno,
|
||||
maybeScript, pcOffset);
|
||||
options.setIntroductionInfo(introducerFilename, "eval", lineno, pcOffset);
|
||||
introScript = maybeScript;
|
||||
} else {
|
||||
options.setFileAndLine("eval", 1);
|
||||
options.setIntroductionType("eval");
|
||||
|
@ -332,12 +335,18 @@ static bool EvalKernel(JSContext* cx, HandleValue v, EvalType evalType,
|
|||
return false;
|
||||
}
|
||||
|
||||
JSScript* script =
|
||||
frontend::CompileEvalScript(cx, options, srcBuf, enclosing, env);
|
||||
RootedScript script(
|
||||
cx, frontend::CompileEvalScript(cx, options, srcBuf, enclosing, env));
|
||||
if (!script) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue undefValue(cx);
|
||||
if (!JS::UpdateDebugMetadata(cx, script, options, undefValue, nullptr,
|
||||
introScript, maybeScript)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
esg.setNewScript(script);
|
||||
}
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@ bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input,
|
|||
}
|
||||
|
||||
Rooted<JSScript*> script(cx, gcOutput.script);
|
||||
if (!input.options.hideScriptFromDebugger) {
|
||||
if (!input.options.hideFromNewScriptInitial()) {
|
||||
DebugAPI::onNewScript(cx, script);
|
||||
}
|
||||
}
|
||||
|
@ -1219,7 +1219,7 @@ static JSFunction* CompileStandaloneFunction(
|
|||
MOZ_ASSERT(!cx->isHelperThreadContext());
|
||||
|
||||
Rooted<JSScript*> script(cx, gcOutput.get().script);
|
||||
if (!options.hideScriptFromDebugger) {
|
||||
if (!options.hideFromNewScriptInitial()) {
|
||||
DebugAPI::onNewScript(cx, script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
offThreadCompileScript("Error()");
|
||||
assertEq(!!runOffThreadScript().stack.match(/^@<string>:1:1\n/), true);
|
||||
|
||||
offThreadCompileScript("Error()", { fileName: "candelabra", lineNumber: 6502 });
|
||||
offThreadCompileScript("Error()", { fileName: "candelabra", lineNumber: 6502 });
|
||||
assertEq(!!runOffThreadScript().stack.match(/^@candelabra:6502:1\n/), true);
|
||||
|
||||
var element = {};
|
||||
offThreadCompileScript("Error()", { element }); // shouldn't crash
|
||||
runOffThreadScript();
|
||||
var job = offThreadCompileScript("Error()"); // shouldn't crash
|
||||
runOffThreadScript(job, { element });
|
||||
|
||||
var elementAttributeName = "molybdenum";
|
||||
elementAttributeName +=
|
||||
elementAttributeName + elementAttributeName + elementAttributeName;
|
||||
offThreadCompileScript("Error()", {
|
||||
job = offThreadCompileScript("Error()"); // shouldn't crash
|
||||
runOffThreadScript(job, {
|
||||
elementAttributeName,
|
||||
}); // shouldn't crash
|
||||
runOffThreadScript();
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// Owning elements and attribute names are attached to scripts compiled
|
||||
// off-thread.
|
||||
|
||||
var g = newGlobal({newCompartment: true});
|
||||
var g = newGlobal({ newCompartment: true });
|
||||
var dbg = new Debugger;
|
||||
var gDO = dbg.addDebuggee(g);
|
||||
|
||||
|
@ -18,9 +18,11 @@ dbg.onDebuggerStatement = function (frame) {
|
|||
assertEq(source.elementAttributeName, 'mass');
|
||||
};
|
||||
|
||||
g.offThreadCompileScript('debugger;',
|
||||
{ element: elt,
|
||||
elementAttributeName: 'mass' });
|
||||
var job = g.offThreadCompileScript('debugger;');
|
||||
log += 'o';
|
||||
g.runOffThreadScript();
|
||||
g.runOffThreadScript(job,
|
||||
{
|
||||
element: elt,
|
||||
elementAttributeName: 'mass'
|
||||
});
|
||||
assertEq(log, 'od');
|
||||
|
|
|
@ -3464,6 +3464,7 @@ void JS::TransitiveCompileOptions::copyPODTransitiveOptions(
|
|||
introductionOffset = rhs.introductionOffset;
|
||||
hasIntroductionInfo = rhs.hasIntroductionInfo;
|
||||
hideScriptFromDebugger = rhs.hideScriptFromDebugger;
|
||||
deferDebugMetadata = rhs.deferDebugMetadata;
|
||||
nonSyntacticScope = rhs.nonSyntacticScope;
|
||||
privateClassFields = rhs.privateClassFields;
|
||||
privateClassMethods = rhs.privateClassMethods;
|
||||
|
@ -3482,11 +3483,7 @@ void JS::ReadOnlyCompileOptions::copyPODNonTransitiveOptions(
|
|||
}
|
||||
|
||||
JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx)
|
||||
: ReadOnlyCompileOptions(),
|
||||
elementAttributeNameRoot(cx),
|
||||
introductionScriptRoot(cx),
|
||||
scriptOrModuleRoot(cx),
|
||||
privateValueRoot(cx) {}
|
||||
: ReadOnlyCompileOptions() {}
|
||||
|
||||
void JS::OwningCompileOptions::release() {
|
||||
// OwningCompileOptions always owns these, so these casts are okay.
|
||||
|
@ -3515,11 +3512,6 @@ bool JS::OwningCompileOptions::copy(JSContext* cx,
|
|||
copyPODNonTransitiveOptions(rhs);
|
||||
copyPODTransitiveOptions(rhs);
|
||||
|
||||
elementAttributeNameRoot = rhs.elementAttributeName();
|
||||
introductionScriptRoot = rhs.introductionScript();
|
||||
scriptOrModuleRoot = rhs.scriptOrModule();
|
||||
privateValueRoot = rhs.privateValue();
|
||||
|
||||
if (rhs.filename()) {
|
||||
filename_ = DuplicateString(cx, rhs.filename()).release();
|
||||
if (!filename_) {
|
||||
|
@ -3545,12 +3537,7 @@ bool JS::OwningCompileOptions::copy(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
JS::CompileOptions::CompileOptions(JSContext* cx)
|
||||
: ReadOnlyCompileOptions(),
|
||||
elementAttributeNameRoot(cx),
|
||||
introductionScriptRoot(cx),
|
||||
scriptOrModuleRoot(cx),
|
||||
privateValueRoot(cx) {
|
||||
JS::CompileOptions::CompileOptions(JSContext* cx) : ReadOnlyCompileOptions() {
|
||||
discardSource = cx->realm()->behaviors().discardSource();
|
||||
if (!cx->options().asmJS()) {
|
||||
asmJSOption = AsmJSOption::Disabled;
|
||||
|
@ -3583,7 +3570,8 @@ JS::CompileOptions::CompileOptions(JSContext* cx)
|
|||
}
|
||||
|
||||
CompileOptions& CompileOptions::setIntroductionInfoToCaller(
|
||||
JSContext* cx, const char* introductionType) {
|
||||
JSContext* cx, const char* introductionType,
|
||||
MutableHandle<JSScript*> introductionScript) {
|
||||
RootedScript maybeScript(cx);
|
||||
const char* filename;
|
||||
unsigned lineno;
|
||||
|
@ -3592,11 +3580,10 @@ CompileOptions& CompileOptions::setIntroductionInfoToCaller(
|
|||
DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno,
|
||||
&pcOffset, &mutedErrors);
|
||||
if (filename) {
|
||||
return setIntroductionInfo(filename, introductionType, lineno, maybeScript,
|
||||
pcOffset);
|
||||
} else {
|
||||
return setIntroductionType(introductionType);
|
||||
introductionScript.set(maybeScript);
|
||||
return setIntroductionInfo(filename, introductionType, lineno, pcOffset);
|
||||
}
|
||||
return setIntroductionType(introductionType);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script) {
|
||||
|
|
|
@ -1989,14 +1989,58 @@ static bool LoadScriptRelativeToScript(JSContext* cx, unsigned argc,
|
|||
return LoadScript(cx, argc, vp, true);
|
||||
}
|
||||
|
||||
static bool ParseDebugMetadata(JSContext* cx, HandleObject opts,
|
||||
MutableHandleValue privateValue,
|
||||
MutableHandleString elementAttributeName) {
|
||||
RootedValue v(cx);
|
||||
RootedString s(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "element", &v)) {
|
||||
return false;
|
||||
}
|
||||
if (v.isObject()) {
|
||||
RootedObject infoObject(cx, CreateScriptPrivate(cx));
|
||||
if (!infoObject) {
|
||||
return false;
|
||||
}
|
||||
RootedValue elementValue(cx, v);
|
||||
if (!JS_WrapValue(cx, &elementValue)) {
|
||||
return false;
|
||||
}
|
||||
if (!JS_DefineProperty(cx, infoObject, "element", elementValue, 0)) {
|
||||
return false;
|
||||
}
|
||||
privateValue.set(ObjectValue(*infoObject));
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "elementAttributeName", &v)) {
|
||||
return false;
|
||||
}
|
||||
if (!v.isUndefined()) {
|
||||
s = ToString(cx, v);
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
elementAttributeName.set(s);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Populate |options| with the options given by |opts|'s properties. If we
|
||||
// need to convert a filename to a C string, let fileNameBytes own the
|
||||
// bytes.
|
||||
static bool ParseCompileOptions(JSContext* cx, CompileOptions& options,
|
||||
HandleObject opts, UniqueChars* fileNameBytes) {
|
||||
HandleObject opts, UniqueChars* fileNameBytes,
|
||||
MutableHandleValue privateValue,
|
||||
MutableHandleString elementAttributeName) {
|
||||
RootedValue v(cx);
|
||||
RootedString s(cx);
|
||||
|
||||
if (!ParseDebugMetadata(cx, opts, privateValue, elementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "isRunOnce", &v)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2037,35 +2081,6 @@ static bool ParseCompileOptions(JSContext* cx, CompileOptions& options,
|
|||
options.setSkipFilenameValidation(ToBoolean(v));
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "element", &v)) {
|
||||
return false;
|
||||
}
|
||||
if (v.isObject()) {
|
||||
RootedObject infoObject(cx, CreateScriptPrivate(cx));
|
||||
if (!infoObject) {
|
||||
return false;
|
||||
}
|
||||
RootedValue elementValue(cx, v);
|
||||
if (!JS_WrapValue(cx, &elementValue)) {
|
||||
return false;
|
||||
}
|
||||
if (!JS_DefineProperty(cx, infoObject, "element", elementValue, 0)) {
|
||||
return false;
|
||||
}
|
||||
options.setPrivateValue(ObjectValue(*infoObject));
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "elementAttributeName", &v)) {
|
||||
return false;
|
||||
}
|
||||
if (!v.isUndefined()) {
|
||||
s = ToString(cx, v);
|
||||
if (!s) {
|
||||
return false;
|
||||
}
|
||||
options.setElementAttributeName(s);
|
||||
}
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "lineNumber", &v)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2374,16 +2389,21 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
CacheOptionSet optionSet;
|
||||
|
||||
options.setIntroductionType("js shell evaluate")
|
||||
.setFileAndLine("@evaluate", 1);
|
||||
.setFileAndLine("@evaluate", 1)
|
||||
.setdeferDebugMetadata();
|
||||
|
||||
global = JS::CurrentGlobalOrNull(cx);
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
RootedValue privateValue(cx);
|
||||
RootedString elementAttributeName(cx);
|
||||
|
||||
if (args.length() == 2) {
|
||||
RootedObject opts(cx, &args[1].toObject());
|
||||
RootedValue v(cx);
|
||||
|
||||
if (!ParseCompileOptions(cx, options, opts, &fileNameBytes)) {
|
||||
if (!ParseCompileOptions(cx, options, opts, &fileNameBytes, &privateValue,
|
||||
&elementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2675,6 +2695,11 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!JS::UpdateDebugMetadata(cx, script, options, privateValue,
|
||||
elementAttributeName, nullptr, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!transcodeOnly) {
|
||||
if (!(envChain.empty()
|
||||
? JS_ExecuteScript(cx, script, args.rval())
|
||||
|
@ -5438,7 +5463,10 @@ static bool Compile(JSContext* cx, unsigned argc, Value* vp) {
|
|||
options.setIntroductionType("js shell compile")
|
||||
.setFileAndLine("<string>", 1)
|
||||
.setIsRunOnce(true)
|
||||
.setNoScriptRval(true);
|
||||
.setNoScriptRval(true)
|
||||
.setdeferDebugMetadata();
|
||||
RootedValue privateValue(cx);
|
||||
RootedString elementAttributeName(cx);
|
||||
|
||||
if (args.length() >= 2) {
|
||||
if (args[1].isPrimitive()) {
|
||||
|
@ -5448,7 +5476,8 @@ static bool Compile(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
RootedObject opts(cx, &args[1].toObject());
|
||||
if (!ParseCompileOptions(cx, options, opts, nullptr)) {
|
||||
if (!ParseCompileOptions(cx, options, opts, nullptr, &privateValue,
|
||||
&elementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -5464,6 +5493,11 @@ static bool Compile(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!JS::UpdateDebugMetadata(cx, script, options, privateValue,
|
||||
elementAttributeName, nullptr, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
@ -5853,8 +5887,10 @@ static bool FrontendTest(JSContext* cx, unsigned argc, Value* vp,
|
|||
typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ParseCompileOptions(cx, options, objOptions, nullptr)) {
|
||||
RootedValue dummyValue(cx);
|
||||
RootedString dummyAttributeName(cx);
|
||||
if (!ParseCompileOptions(cx, options, objOptions, nullptr, &dummyValue,
|
||||
&dummyAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6148,7 +6184,8 @@ static bool OffThreadCompileScript(JSContext* cx, unsigned argc, Value* vp) {
|
|||
UniqueChars fileNameBytes;
|
||||
CompileOptions options(cx);
|
||||
options.setIntroductionType("js shell offThreadCompileScript")
|
||||
.setFileAndLine("<string>", 1);
|
||||
.setFileAndLine("<string>", 1)
|
||||
.setdeferDebugMetadata();
|
||||
|
||||
if (args.length() >= 2) {
|
||||
if (args[1].isPrimitive()) {
|
||||
|
@ -6157,8 +6194,13 @@ static bool OffThreadCompileScript(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Offthread compilation requires that the debug metadata be set when the
|
||||
// script is collected from offthread, rather than when compiled.
|
||||
RootedValue dummyPrivateValue(cx);
|
||||
RootedString dummyElementAttributeName(cx);
|
||||
RootedObject opts(cx, &args[1].toObject());
|
||||
if (!ParseCompileOptions(cx, options, opts, &fileNameBytes)) {
|
||||
if (!ParseCompileOptions(cx, options, opts, &fileNameBytes,
|
||||
&dummyPrivateValue, &dummyElementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -6242,6 +6284,28 @@ static bool runOffThreadScript(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedValue privateValue(cx);
|
||||
RootedString elementAttributeName(cx);
|
||||
|
||||
if (args.length() >= 2) {
|
||||
if (args[1].isPrimitive()) {
|
||||
JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr,
|
||||
JSSMSG_INVALID_ARGS, "compile");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject opts(cx, &args[1].toObject());
|
||||
if (!ParseDebugMetadata(cx, opts, &privateValue, &elementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CompileOptions dummyOptions(cx);
|
||||
if (!JS::UpdateDebugMetadata(cx, script, dummyOptions, privateValue,
|
||||
elementAttributeName, nullptr, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return JS_ExecuteScript(cx, script, args.rval());
|
||||
}
|
||||
|
||||
|
@ -6383,7 +6447,10 @@ static bool OffThreadDecodeScript(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
|
||||
RootedObject opts(cx, &args[1].toObject());
|
||||
if (!ParseCompileOptions(cx, options, opts, &fileNameBytes)) {
|
||||
RootedValue dummyValue(cx);
|
||||
RootedString dummyAttributeName(cx);
|
||||
if (!ParseCompileOptions(cx, options, opts, &fileNameBytes, &dummyValue,
|
||||
&dummyAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -421,6 +421,55 @@ JS_PUBLIC_API void JS::ExposeScriptToDebugger(JSContext* cx,
|
|||
DebugAPI::onNewScript(cx, script);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS::UpdateDebugMetadata(
|
||||
JSContext* cx, Handle<JSScript*> script,
|
||||
const ReadOnlyCompileOptions& options, HandleValue privateValue,
|
||||
HandleString elementAttributeName, HandleScript introScript,
|
||||
HandleScript scriptOrModule) {
|
||||
RootedScriptSourceObject sso(cx, script->sourceObject());
|
||||
|
||||
if (!ScriptSourceObject::initElementProperties(cx, sso,
|
||||
elementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There is no equivalent of cross-compartment wrappers for scripts. If the
|
||||
// introduction script and ScriptSourceObject are in different compartments,
|
||||
// we would be creating a cross-compartment script reference, which is
|
||||
// forbidden. We can still store a CCW to the script source object though.
|
||||
RootedValue introductionScript(cx);
|
||||
if (introScript) {
|
||||
if (introScript->compartment() == cx->compartment()) {
|
||||
introductionScript.setPrivateGCThing(introScript);
|
||||
}
|
||||
}
|
||||
sso->setIntroductionScript(introductionScript);
|
||||
|
||||
RootedValue privateValueStore(cx, UndefinedValue());
|
||||
if (privateValue.isUndefined()) {
|
||||
// Set the private value to that of the script or module that this source is
|
||||
// part of, if any.
|
||||
if (scriptOrModule) {
|
||||
privateValueStore = scriptOrModule->sourceObject()->canonicalPrivate();
|
||||
}
|
||||
} else {
|
||||
privateValueStore = privateValue;
|
||||
}
|
||||
|
||||
if (!privateValueStore.isUndefined()) {
|
||||
if (!JS_WrapValue(cx, &privateValueStore)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
sso->setPrivate(cx->runtime(), privateValueStore);
|
||||
|
||||
if (!options.hideScriptFromDebugger) {
|
||||
JS::ExposeScriptToDebugger(cx, script);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS::SetGetElementCallback(JSContext* cx,
|
||||
JSGetElementCallback callback) {
|
||||
MOZ_ASSERT(cx->runtime());
|
||||
|
|
|
@ -2109,7 +2109,7 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
|
|||
|
||||
// The Debugger only needs to be told about the topmost script that was
|
||||
// compiled.
|
||||
if (!parseTask->options.hideScriptFromDebugger) {
|
||||
if (!parseTask->options.hideFromNewScriptInitial()) {
|
||||
DebugAPI::onNewScript(cx, script);
|
||||
}
|
||||
} else {
|
||||
|
@ -2187,7 +2187,7 @@ bool GlobalHelperThreadState::finishMultiParseTask(
|
|||
|
||||
// The Debugger only needs to be told about the topmost scripts that were
|
||||
// compiled.
|
||||
if (!parseTask->options.hideScriptFromDebugger) {
|
||||
if (!parseTask->options.hideFromNewScriptInitial()) {
|
||||
JS::RootedScript rooted(cx);
|
||||
for (auto& script : scripts) {
|
||||
MOZ_ASSERT(script->isGlobalCode());
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "jit/InlinableNatives.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "js/CallNonGenericMethod.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/CompileOptions.h"
|
||||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
|
||||
|
@ -1676,8 +1677,8 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
|
|||
.setFileAndLine(filename, 1)
|
||||
.setNoScriptRval(false)
|
||||
.setIntroductionInfo(introducerFilename, introductionType, lineno,
|
||||
maybeScript, pcOffset)
|
||||
.setScriptOrModule(maybeScript);
|
||||
pcOffset)
|
||||
.setdeferDebugMetadata();
|
||||
|
||||
JSStringBuilder sb(cx);
|
||||
|
||||
|
@ -1812,6 +1813,13 @@ static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args,
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedValue undefValue(cx);
|
||||
RootedScript funScript(cx, JS_GetFunctionScript(cx, fun));
|
||||
if (funScript && !UpdateDebugMetadata(cx, funScript, options, undefValue,
|
||||
nullptr, maybeScript, maybeScript)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fun->isInterpreted()) {
|
||||
fun->initEnvironment(&cx->global()->lexicalEnvironment());
|
||||
}
|
||||
|
|
|
@ -1226,7 +1226,8 @@ XDRResult js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
|
|||
}
|
||||
|
||||
/* see BytecodeEmitter::tellDebuggerAboutCompiledScript */
|
||||
if (!isFunctionScript && !cx->isHelperThreadContext()) {
|
||||
if (!isFunctionScript && !cx->isHelperThreadContext() &&
|
||||
!xdr->options().hideFromNewScriptInitial()) {
|
||||
DebugAPI::onNewScript(cx, script);
|
||||
}
|
||||
}
|
||||
|
@ -1686,41 +1687,21 @@ bool ScriptSourceObject::initFromOptions(
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedString elementAttributeName(cx, options.elementAttributeName());
|
||||
if (options.deferDebugMetadata) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize the element attribute slot and introduction script slot
|
||||
// this marks the SSO as initialized for asserts.
|
||||
|
||||
RootedString elementAttributeName(cx);
|
||||
if (!initElementProperties(cx, source, elementAttributeName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There is no equivalent of cross-compartment wrappers for scripts. If the
|
||||
// introduction script and ScriptSourceObject are in different compartments,
|
||||
// we would be creating a cross-compartment script reference, which is
|
||||
// forbidden. We can still store a CCW to the script source object though.
|
||||
RootedValue introductionScript(cx);
|
||||
if (JSScript* script = options.introductionScript()) {
|
||||
if (script->compartment() == cx->compartment()) {
|
||||
introductionScript.setPrivateGCThing(options.introductionScript());
|
||||
}
|
||||
}
|
||||
source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introductionScript);
|
||||
|
||||
RootedValue privateValue(cx, UndefinedValue());
|
||||
if (options.privateValue().isUndefined()) {
|
||||
// Set the private value to that of the script or module that this source is
|
||||
// part of, if any.
|
||||
if (JSScript* script = options.scriptOrModule()) {
|
||||
privateValue = script->sourceObject()->canonicalPrivate();
|
||||
}
|
||||
} else {
|
||||
privateValue = options.privateValue();
|
||||
}
|
||||
|
||||
if (!privateValue.isUndefined()) {
|
||||
if (!JS_WrapValue(cx, &privateValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
source->setPrivate(cx->runtime(), privateValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1134,6 +1134,10 @@ class ScriptSourceObject : public NativeObject {
|
|||
|
||||
void setPrivate(JSRuntime* rt, const Value& value);
|
||||
|
||||
void setIntroductionScript(const Value& introductionScript) {
|
||||
setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introductionScript);
|
||||
}
|
||||
|
||||
Value canonicalPrivate() const {
|
||||
MOZ_ASSERT(isInitialized());
|
||||
Value value = getReservedSlot(PRIVATE_SLOT);
|
||||
|
|
Загрузка…
Ссылка в новой задаче