summaryrefslogtreecommitdiff
path: root/dom
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-04-20 10:15:52 -0500
committerBrian Smith <brian@dbsoft.org>2023-04-27 13:34:48 -0500
commite29f4488b1d8d33f3ca04531177d1c1690f57577 (patch)
tree9a96ac5db0e3c7b8b2edf2cc416eebd3bf61ffad /dom
parent8431e52405bf4cd9d34eae9940cb665c7faa2c7e (diff)
downloaduxp-e29f4488b1d8d33f3ca04531177d1c1690f57577.tar.gz
Issue #1691 - Part 7f: Split up compile and execute so we can use ClassicScript.
https://bugzilla.mozilla.org/show_bug.cgi?id=1342012 Refactor nsJSUtils::ExecutionContext to separate compilation and execution steps and allow extraction of compiled JSScript. https://bugzilla.mozilla.org/show_bug.cgi?id=1366773 Move buffer argument from JS::StartIncrementalEncoding to JS::FinishIncrementalEncoding. (cherry picked from commit d4b520b08b958e116dfeeffdc61f3425610d1ce9)
Diffstat (limited to 'dom')
-rw-r--r--dom/base/nsJSUtils.cpp129
-rw-r--r--dom/base/nsJSUtils.h82
-rw-r--r--dom/script/ScriptLoader.cpp17
3 files changed, 131 insertions, 97 deletions
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
index efd2614caf..467a5b0b53 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -138,12 +138,14 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
, mCompartment(aCx, aGlobal)
, mRetValue(aCx)
, mScopeChain(aCx)
+ , mScript(aCx)
, mRv(NS_OK)
, mSkip(false)
, mCoerceToString(false)
#ifdef DEBUG
, mWantsReturnValue(false)
, mExpectScopeChain(false)
+ , mScriptUsed(false)
#endif
{
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
@@ -188,8 +190,7 @@ nsJSUtils::ExecutionContext::SetScopeChain(
}
nsresult
-nsJSUtils::ExecutionContext::JoinAndExec(void **aOffThreadToken,
- JS::MutableHandle<JSScript*> aScript)
+nsJSUtils::ExecutionContext::JoinCompile(void** aOffThreadToken)
{
if (mSkip) {
return mRv;
@@ -197,45 +198,66 @@ nsJSUtils::ExecutionContext::JoinAndExec(void **aOffThreadToken,
MOZ_ASSERT(!mWantsReturnValue);
MOZ_ASSERT(!mExpectScopeChain);
- aScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken));
+ MOZ_ASSERT(!mScript);
+ mScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken));
*aOffThreadToken = nullptr; // Mark the token as having been finished.
- if (!aScript || !JS_ExecuteScript(mCx, mScopeChain, aScript)) {
+ if (!mScript) {
mSkip = true;
mRv = EvaluationExceptionToNSResult(mCx);
return mRv;
}
+ if (!StartIncrementalEncoding(mCx, mScript)) {
+ mSkip = true;
+ mRv = EvaluationExceptionToNSResult(mCx);
+ return mRv;
+ }
+
return NS_OK;
}
nsresult
-nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
- JS::SourceBufferHolder& aSrcBuf)
+nsJSUtils::ExecutionContext::Compile(JS::CompileOptions& aCompileOptions,
+ JS::SourceBufferHolder& aSrcBuf)
{
if (mSkip) {
return mRv;
}
-
- MOZ_ASSERT_IF(aCompileOptions.versionSet,
- aCompileOptions.version != JSVERSION_UNKNOWN);
+
MOZ_ASSERT(aSrcBuf.get());
MOZ_ASSERT(mRetValue.isUndefined());
#ifdef DEBUG
mWantsReturnValue = !aCompileOptions.noScriptRval;
#endif
- MOZ_ASSERT(!mCoerceToString || mWantsReturnValue);
- if (!JS::Evaluate(mCx, mScopeChain, aCompileOptions, aSrcBuf, &mRetValue)) {
+
+ MOZ_ASSERT(!mScript);
+ bool compiled = true;
+ if (mScopeChain.length() == 0) {
+ compiled = JS::Compile(mCx, aCompileOptions, aSrcBuf, &mScript);
+ } else {
+ compiled = JS::CompileForNonSyntacticScope(mCx, aCompileOptions, aSrcBuf,
+ &mScript);
+ }
+
+ MOZ_ASSERT_IF(compiled, mScript);
+ if (!compiled) {
mSkip = true;
mRv = EvaluationExceptionToNSResult(mCx);
return mRv;
}
-
+
+ if (!StartIncrementalEncoding(mCx, mScript)) {
+ mSkip = true;
+ mRv = EvaluationExceptionToNSResult(mCx);
+ return mRv;
+ }
+
return NS_OK;
}
nsresult
-nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
- const nsAString& aScript)
+nsJSUtils::ExecutionContext::Compile(JS::CompileOptions& aCompileOptions,
+ const nsAString& aScript)
{
if (mSkip) {
return mRv;
@@ -244,21 +266,20 @@ nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
const nsPromiseFlatString& flatScript = PromiseFlatString(aScript);
JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(),
JS::SourceBufferHolder::NoOwnership);
- return CompileAndExec(aCompileOptions, srcBuf);
+ return Compile(aCompileOptions, srcBuf);
}
nsresult
-nsJSUtils::ExecutionContext::DecodeAndExec(JS::CompileOptions& aCompileOptions,
- mozilla::Vector<uint8_t>& aBytecodeBuf,
- size_t aBytecodeIndex)
+nsJSUtils::ExecutionContext::Decode(JS::CompileOptions& aCompileOptions,
+ mozilla::Vector<uint8_t>& aBytecodeBuf,
+ size_t aBytecodeIndex)
{
if (mSkip) {
return mRv;
}
MOZ_ASSERT(!mWantsReturnValue);
- JS::Rooted<JSScript*> script(mCx);
- JS::TranscodeResult tr = JS::DecodeScript(mCx, aBytecodeBuf, &script, aBytecodeIndex);
+ JS::TranscodeResult tr = JS::DecodeScript(mCx, aBytecodeBuf, &mScript, aBytecodeIndex);
// These errors are external parameters which should be handled before the
// decoding phase, and which are the only reasons why you might want to
// fallback on decoding failures.
@@ -270,17 +291,11 @@ nsJSUtils::ExecutionContext::DecodeAndExec(JS::CompileOptions& aCompileOptions,
return mRv;
}
- if (!JS_ExecuteScript(mCx, mScopeChain, script)) {
- mSkip = true;
- mRv = EvaluationExceptionToNSResult(mCx);
- return mRv;
- }
-
return mRv;
}
nsresult
-nsJSUtils::ExecutionContext::DecodeJoinAndExec(void **aOffThreadToken)
+nsJSUtils::ExecutionContext::JoinDecode(void **aOffThreadToken)
{
if (mSkip) {
return mRv;
@@ -288,10 +303,9 @@ nsJSUtils::ExecutionContext::DecodeJoinAndExec(void **aOffThreadToken)
MOZ_ASSERT(!mWantsReturnValue);
MOZ_ASSERT(!mExpectScopeChain);
- JS::Rooted<JSScript*> script(mCx);
- script.set(JS::FinishOffThreadScriptDecoder(mCx, *aOffThreadToken));
+ mScript.set(JS::FinishOffThreadScriptDecoder(mCx, *aOffThreadToken));
*aOffThreadToken = nullptr; // Mark the token as having been finished.
- if (!script || !JS_ExecuteScript(mCx, mScopeChain, script)) {
+ if (!mScript) {
mSkip = true;
mRv = EvaluationExceptionToNSResult(mCx);
return mRv;
@@ -300,54 +314,53 @@ nsJSUtils::ExecutionContext::DecodeJoinAndExec(void **aOffThreadToken)
return NS_OK;
}
-nsresult
-nsJSUtils::ExecutionContext::JoinEncodeAndExec(void **aOffThreadToken,
- mozilla::Vector<uint8_t>& aBytecodeBuf,
- JS::MutableHandle<JSScript*> aScript)
-{
- MOZ_ASSERT_IF(aOffThreadToken, !mWantsReturnValue);
- aScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken));
- *aOffThreadToken = nullptr; // Mark the token as having been finished.
- if (!aScript) {
- mSkip = true;
- mRv = EvaluationExceptionToNSResult(mCx);
- return mRv;
- }
+JSScript* nsJSUtils::ExecutionContext::GetScript() {
+#ifdef DEBUG
+ MOZ_ASSERT(!mSkip);
+ MOZ_ASSERT(mScript);
+ mScriptUsed = true;
+#endif
- if (!StartIncrementalEncoding(mCx, aBytecodeBuf, aScript)) {
- mSkip = true;
- mRv = EvaluationExceptionToNSResult(mCx);
+ return mScript;
+}
+
+nsresult nsJSUtils::ExecutionContext::ExecScript() {
+ if (mSkip) {
return mRv;
}
- if (!JS_ExecuteScript(mCx, mScopeChain, aScript)) {
+ MOZ_ASSERT(mScript);
+
+ if (!JS_ExecuteScript(mCx, mScopeChain, mScript)) {
mSkip = true;
mRv = EvaluationExceptionToNSResult(mCx);
return mRv;
}
- return mRv;
+ return NS_OK;
}
nsresult
-nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle<JS::Value> aRetValue)
+nsJSUtils::ExecutionContext::ExecScript(JS::MutableHandle<JS::Value> aRetValue)
{
- MOZ_ASSERT(aRetValue.isUndefined());
if (mSkip) {
- // Repeat earlier result, as NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW are not
- // failures cases.
-#ifdef DEBUG
- mWantsReturnValue = false;
-#endif
- return mRv;
+ return mRv;
}
+ MOZ_ASSERT(mScript);
MOZ_ASSERT(mWantsReturnValue);
+
+ if (!JS_ExecuteScript(mCx, mScopeChain, mScript, aRetValue)) {
+ mSkip = true;
+ mRv = EvaluationExceptionToNSResult(mCx);
+ return mRv;
+ }
+
#ifdef DEBUG
mWantsReturnValue = false;
#endif
- if (mCoerceToString && !mRetValue.isUndefined()) {
- JSString* str = JS::ToString(mCx, mRetValue);
+ if (mCoerceToString && !aRetValue.isUndefined()) {
+ JSString* str = JS::ToString(mCx, aRetValue);
if (!str) {
// ToString can be a function call, so an exception can be raised while
// executing the function.
diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
index ce6f5a2283..b1b2b601a6 100644
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -76,6 +76,9 @@ public:
// Scope chain in which the execution takes place.
JS::AutoObjectVector mScopeChain;
+ // The compiled script.
+ JS::Rooted<JSScript*> mScript;
+
// returned value forwarded when we have to interupt the execution eagerly
// with mSkip.
nsresult mRv;
@@ -92,6 +95,8 @@ public:
bool mWantsReturnValue;
bool mExpectScopeChain;
+
+ bool mScriptUsed;
#endif
public:
@@ -105,8 +110,12 @@ public:
ExecutionContext(ExecutionContext&&) = delete;
~ExecutionContext() {
- // This flag is resetted, when the returned value is extracted.
- MOZ_ASSERT(!mWantsReturnValue);
+ // This flag is reset when the returned value is extracted.
+ MOZ_ASSERT_IF(!mSkip, !mWantsReturnValue);
+
+ // If encoding was started we expect the script to have been
+ // used when ending the encoding.
+ MOZ_ASSERT_IF(mEncodeBytecode && mScript && mRv == NS_OK, mScriptUsed);
}
// The returned value would be converted to a string if the
@@ -119,10 +128,41 @@ public:
// Set the scope chain in which the code should be executed.
void SetScopeChain(const JS::AutoObjectVector& aScopeChain);
- // Copy the returned value in the mutable handle argument, in case of a
+ // After getting a notification that an off-thread compilation terminated,
+ // this function will take the result of the parser and move it to the main
+ // thread.
+ MOZ_MUST_USE nsresult JoinCompile(void** aOffThreadToken);
+
+ // Compile a script contained in a SourceText.
+ nsresult Compile(JS::CompileOptions& aCompileOptions,
+ JS::SourceBufferHolder& aSrcBuf);
+
+ // Compile a script contained in a string.
+ nsresult Compile(JS::CompileOptions& aCompileOptions,
+ const nsAString& aScript);
+
+ // Decode a script contained in a buffer.
+ nsresult Decode(JS::CompileOptions& aCompileOptions,
+ mozilla::Vector<uint8_t>& aBytecodeBuf,
+ size_t aBytecodeIndex);
+
+ // After getting a notification that an off-thread decoding terminated, this
+ // function will get the result of the decoder and move it to the main
+ // thread.
+ nsresult JoinDecode(void** aOffThreadToken);
+
+ // Get a successfully compiled script.
+ JSScript* GetScript();
+
+ // Execute the compiled script and ignore the return value.
+ MOZ_MUST_USE nsresult ExecScript();
+
+ // Execute the compiled script a get the return value.
+ //
+ // Copy the returned value into the mutable handle argument. In case of a
// evaluation failure either during the execution or the conversion of the
- // result to a string, the nsresult would be set to the corresponding result
- // code, and the mutable handle argument would remain unchanged.
+ // result to a string, the nsresult is be set to the corresponding result
+ // code and the mutable handle argument remains unchanged.
//
// The value returned in the mutable handle argument is part of the
// compartment given as argument to the ExecutionContext constructor. If the
@@ -131,37 +171,7 @@ public:
MOZ_MUST_USE nsresult
ExtractReturnValue(JS::MutableHandle<JS::Value> aRetValue);
- // After getting a notification that an off-thread compilation terminated,
- // this function will take the result of the parser by moving it to the main
- // thread before starting the execution of the script.
- //
- // The compiled script would be returned in the |aScript| out-param.
- MOZ_MUST_USE nsresult JoinAndExec(void **aOffThreadToken,
- JS::MutableHandle<JSScript*> aScript);
-
- // Compile a script contained in a SourceBuffer, and execute it.
- nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
- JS::SourceBufferHolder& aSrcBuf);
-
- // Compile a script contained in a string, and execute it.
- nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
- const nsAString& aScript);
-
- // Decode a script contained in a buffer, and execute it.
- MOZ_MUST_USE nsresult DecodeAndExec(JS::CompileOptions& aCompileOptions,
- mozilla::Vector<uint8_t>& aBytecodeBuf,
- size_t aBytecodeIndex);
-
- // After getting a notification that an off-thread decoding terminated, this
- // function will get the result of the decoder by moving it to the main
- // thread before starting the execution of the script.
- MOZ_MUST_USE nsresult DecodeJoinAndExec(void **aOffThreadToken);
-
- // Similar to JoinAndExec, except that in addition to fecthing the source,
- // we register the fact that we plan to encode its bytecode later.
- MOZ_MUST_USE nsresult JoinEncodeAndExec(void **aOffThreadToken,
- mozilla::Vector<uint8_t>& aBytecodeBuf,
- JS::MutableHandle<JSScript*> aScript);
+ MOZ_MUST_USE nsresult ExecScript(JS::MutableHandle<JS::Value> aRetValue);
};
struct MOZ_STACK_CLASS EvaluateOptions {
diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
index a260f49055..2fd94a3dd9 100644
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -2347,12 +2347,23 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
{
nsJSUtils::ExecutionContext exec(cx, global);
if (aRequest->mOffThreadToken) {
- JS::Rooted<JSScript*> script(cx);
- rv = exec.JoinAndExec(&aRequest->mOffThreadToken, &script);
+ rv = exec.JoinDecode(&aRequest->mOffThreadToken);
} else {
nsAutoString inlineData;
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
- rv = exec.CompileAndExec(options, srcBuf);
+ rv = exec.Compile(options, srcBuf);
+ }
+ if (rv == NS_OK) {
+ JS::Rooted<JSScript*> script(cx);
+ script = exec.GetScript();
+
+ // Create a ClassicScript object and associate it with the
+ // JSScript.
+ RefPtr<ClassicScript> classicScript = new ClassicScript(
+ aRequest->mFetchOptions, aRequest->mBaseURL);
+ classicScript->AssociateWithScript(script);
+
+ rv = exec.ExecScript();
}
}
}