diff options
-rw-r--r-- | dom/base/nsJSUtils.cpp | 129 | ||||
-rw-r--r-- | dom/base/nsJSUtils.h | 82 | ||||
-rw-r--r-- | dom/script/ScriptLoader.cpp | 17 | ||||
-rw-r--r-- | js/src/jsapi.cpp | 8 | ||||
-rw-r--r-- | js/src/jsapi.h | 11 | ||||
-rw-r--r-- | js/src/jsscript.cpp | 9 | ||||
-rw-r--r-- | js/src/jsscript.h | 4 | ||||
-rw-r--r-- | js/src/shell/js.cpp | 4 | ||||
-rw-r--r-- | js/src/vm/Xdr.cpp | 4 | ||||
-rw-r--r-- | js/src/vm/Xdr.h | 11 |
10 files changed, 154 insertions, 125 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(); } } } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 192f7e5936..c0bcad81ef 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -7127,21 +7127,21 @@ JS::DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, } JS_PUBLIC_API(bool) -JS::StartIncrementalEncoding(JSContext* cx, TranscodeBuffer& buffer, JS::HandleScript script) +JS::StartIncrementalEncoding(JSContext* cx, JS::HandleScript script) { if (!script) return false; - if (!script->scriptSource()->xdrEncodeTopLevel(cx, buffer, script)) + if (!script->scriptSource()->xdrEncodeTopLevel(cx, script)) return false; return true; } JS_PUBLIC_API(bool) -JS::FinishIncrementalEncoding(JSContext* cx, JS::HandleScript script) +JS::FinishIncrementalEncoding(JSContext* cx, JS::HandleScript script, TranscodeBuffer& buffer) { if (!script) return false; - if (!script->scriptSource()->xdrFinalizeEncoder()) + if (!script->scriptSource()->xdrFinalizeEncoder(buffer)) return false; return true; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 589b281975..a6a5429cf5 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -6209,15 +6209,14 @@ DecodeInterpretedFunction(JSContext* cx, TranscodeBuffer& buffer, JS::MutableHan // an out-param of any of the |Compile| functions, or the result of // |FinishOffThreadScript|. // -// The |buffer| argument should not be used before until -// |FinishIncrementalEncoding| is called on the same script, and returns -// successfully. If any of these functions failed, the |buffer| content is -// undefined. +// The |buffer| argument of |FinishIncrementalEncoding| is used for appending +// the encoded bytecode into the buffer. If any of these functions failed, the +// content of |buffer| would be undefined. extern JS_PUBLIC_API(bool) -StartIncrementalEncoding(JSContext* cx, TranscodeBuffer& buffer, JS::HandleScript script); +StartIncrementalEncoding(JSContext* cx, JS::HandleScript script); extern JS_PUBLIC_API(bool) -FinishIncrementalEncoding(JSContext* cx, JS::HandleScript script); +FinishIncrementalEncoding(JSContext* cx, JS::HandleScript script, TranscodeBuffer& buffer); } /* namespace JS */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index d8248f984a..fce520e5e7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1958,10 +1958,9 @@ ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, } bool -ScriptSource::xdrEncodeTopLevel(ExclusiveContext* cx, JS::TranscodeBuffer& buffer, - HandleScript script) +ScriptSource::xdrEncodeTopLevel(ExclusiveContext* cx, HandleScript script) { - xdrEncoder_ = js::MakeUnique<XDRIncrementalEncoder>(cx, buffer, buffer.length()); + xdrEncoder_ = js::MakeUnique<XDRIncrementalEncoder>(cx); if (!xdrEncoder_) { ReportOutOfMemory(cx); return false; @@ -2003,14 +2002,14 @@ ScriptSource::xdrEncodeFunction(ExclusiveContext* cx, HandleFunction fun, Handle } bool -ScriptSource::xdrFinalizeEncoder() +ScriptSource::xdrFinalizeEncoder(JS::TranscodeBuffer& buffer) { MOZ_ASSERT(hasEncoder()); auto cleanup = mozilla::MakeScopeExit([&] { xdrEncoder_.reset(nullptr); }); - if (!xdrEncoder_->linearize()) + if (!xdrEncoder_->linearize(buffer)) return false; return true; } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 198f96115f..c9f5a927bb 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -588,7 +588,7 @@ class ScriptSource // of the encoding would be available in the |buffer| provided as argument, // as soon as |xdrFinalize| is called and all xdr function calls returned // successfully. - bool xdrEncodeTopLevel(ExclusiveContext* cx, JS::TranscodeBuffer& buffer, HandleScript script); + bool xdrEncodeTopLevel(ExclusiveContext* cx, HandleScript script); // Encode a delazified JSFunction. In case of errors, the XDR encoder is // freed and the |buffer| provided as argument to |xdrEncodeTopLevel| is @@ -602,7 +602,7 @@ class ScriptSource // Linearize the encoded content in the |buffer| provided as argument to // |xdrEncodeTopLevel|, and free the XDR encoder. In case of errors, the // |buffer| is considered undefined. - bool xdrFinalizeEncoder(); + bool xdrFinalizeEncoder(JS::TranscodeBuffer& buffer); }; class ScriptSourceHolder diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 19b77b328b..7a955bf5ab 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1774,7 +1774,7 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp) // register ahead the fact that every JSFunction which is being // delazified should be encoded at the end of the delazification. if (saveIncrementalBytecode) { - if (!StartIncrementalEncoding(cx, saveBuffer, script)) + if (!StartIncrementalEncoding(cx, script)) return false; } @@ -1799,7 +1799,7 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp) // Serialize the encoded bytecode, recorded before the execution, into a // buffer which can be deserialized linearly. if (saveIncrementalBytecode) { - if (!FinishIncrementalEncoding(cx, script)) + if (!FinishIncrementalEncoding(cx, script, saveBuffer)) return false; } } diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index 1c599f0d61..3b34973a11 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -309,7 +309,7 @@ XDRIncrementalEncoder::endSubTree() } bool -XDRIncrementalEncoder::linearize() +XDRIncrementalEncoder::linearize(JS::TranscodeBuffer& buffer) { if (oom_) { ReportOutOfMemory(cx()); @@ -343,7 +343,7 @@ XDRIncrementalEncoder::linearize() // buffer which would be serialized. MOZ_ASSERT(slice.sliceBegin <= slices_.length()); MOZ_ASSERT(slice.sliceBegin + slice.sliceLength <= slices_.length()); - if (!buffer_.append(slices_.begin() + slice.sliceBegin, slice.sliceLength)) { + if (!buffer.append(slices_.begin() + slice.sliceBegin, slice.sliceLength)) { ReportOutOfMemory(cx()); return fail(JS::TranscodeResult_Throw); } diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 494c9b1721..419b0dc86b 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -410,18 +410,15 @@ class XDRIncrementalEncoder : public XDREncoder // Tree of slices. SlicesTree tree_; JS::TranscodeBuffer slices_; - JS::TranscodeBuffer& buffer_; bool oom_; public: - XDRIncrementalEncoder(ExclusiveContext* cx, JS::TranscodeBuffer& buffer, size_t cursor) + XDRIncrementalEncoder(ExclusiveContext* cx) : XDREncoder(cx, slices_, 0), scope_(nullptr), node_(nullptr), - buffer_(buffer), oom_(false) { - MOZ_ASSERT(buffer.length() == cursor, "NYI"); } virtual ~XDRIncrementalEncoder() {} @@ -434,9 +431,9 @@ class XDRIncrementalEncoder : public XDREncoder void createOrReplaceSubTree(AutoXDRTree* child) override; void endSubTree() override; - // In the current XDRBuffer, move replaceable-parts to form a linear - // sequence of bytes. - MOZ_MUST_USE bool linearize(); + // Append the content collected during the incremental encoding into the + // buffer given as argument. + MOZ_MUST_USE bool linearize(JS::TranscodeBuffer& buffer); }; } /* namespace js */ |