mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
commit
6475e7a21d
@ -234,6 +234,7 @@
|
||||
#include "mozilla/dom/PrimitiveConversions.h"
|
||||
#include "mozilla/dom/WindowBinding.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "mozilla/dom/LoadedScript.h"
|
||||
#include "mozilla/dom/MediaQueryList.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/NavigatorBinding.h"
|
||||
@ -5983,8 +5984,6 @@ bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
|
||||
|
||||
if (!callback) {
|
||||
// Evaluate the timeout expression.
|
||||
const nsAString& script = handler->GetHandlerText();
|
||||
|
||||
const char* filename = nullptr;
|
||||
uint32_t lineNo = 0, dummyColumn = 0;
|
||||
handler->GetLocation(&filename, &lineNo, &dummyColumn);
|
||||
@ -6001,7 +6000,16 @@ bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout,
|
||||
nsresult rv;
|
||||
{
|
||||
nsJSUtils::ExecutionContext exec(aes.cx(), global);
|
||||
rv = exec.CompileAndExec(options, script);
|
||||
rv = exec.Compile(options, handler->GetHandlerText());
|
||||
|
||||
if (rv == NS_OK) {
|
||||
LoadedScript* initiatingScript = handler->GetInitiatingScript();
|
||||
if (initiatingScript) {
|
||||
initiatingScript->AssociateWithScript(exec.GetScript());
|
||||
}
|
||||
|
||||
rv = exec.ExecScript();
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Function;
|
||||
class LoadedScript;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@ -46,6 +47,9 @@ class nsIScriptTimeoutHandler : public nsITimeoutHandler {
|
||||
|
||||
// If we have a Function, get the arguments for passing to it.
|
||||
virtual const nsTArray<JS::Value>& GetArgs() = 0;
|
||||
|
||||
// If we have an expression, get the initiating script.
|
||||
virtual mozilla::dom::LoadedScript* GetInitiatingScript() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptTimeoutHandler,
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/CSPEvalChecker.h"
|
||||
#include "mozilla/dom/FunctionBinding.h"
|
||||
#include "mozilla/dom/LoadedScript.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -39,6 +40,7 @@ class nsJSScriptTimeoutHandler final : public nsIScriptTimeoutHandler {
|
||||
nsTArray<JS::Heap<JS::Value>>&& aArguments,
|
||||
ErrorResult& aError);
|
||||
nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindowInner* aWindow,
|
||||
LoadedScript* aInitiatingScript,
|
||||
const nsAString& aExpression, bool* aAllowEval,
|
||||
ErrorResult& aError);
|
||||
nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
@ -63,6 +65,10 @@ class nsJSScriptTimeoutHandler final : public nsIScriptTimeoutHandler {
|
||||
*aColumn = mColumn;
|
||||
}
|
||||
|
||||
virtual LoadedScript* GetInitiatingScript() override {
|
||||
return mInitiatingScript;
|
||||
}
|
||||
|
||||
virtual void MarkForCC() override {
|
||||
if (mFunction) {
|
||||
mFunction->MarkForCC();
|
||||
@ -88,6 +94,9 @@ class nsJSScriptTimeoutHandler final : public nsIScriptTimeoutHandler {
|
||||
// it should be used, else use mExpr.
|
||||
nsString mExpr;
|
||||
RefPtr<Function> mFunction;
|
||||
|
||||
// Initiating script for use when evaluating mExpr on the main thread.
|
||||
RefPtr<LoadedScript> mInitiatingScript;
|
||||
};
|
||||
|
||||
// nsJSScriptTimeoutHandler
|
||||
@ -95,8 +104,11 @@ class nsJSScriptTimeoutHandler final : public nsIScriptTimeoutHandler {
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSScriptTimeoutHandler)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSScriptTimeoutHandler)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFunction)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInitiatingScript)
|
||||
tmp->ReleaseJSObjects();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
|
||||
if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
|
||||
nsAutoCString name("nsJSScriptTimeoutHandler");
|
||||
@ -134,6 +146,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
|
||||
if (tmp->mFunction) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFunction)
|
||||
}
|
||||
if (tmp->mInitiatingScript) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInitiatingScript)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSScriptTimeoutHandler)
|
||||
@ -167,12 +182,14 @@ nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(
|
||||
Init(aCx, std::move(aArguments));
|
||||
}
|
||||
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(JSContext* aCx,
|
||||
nsGlobalWindowInner* aWindow,
|
||||
const nsAString& aExpression,
|
||||
bool* aAllowEval,
|
||||
ErrorResult& aError)
|
||||
: mLineNo(0), mColumn(0), mExpr(aExpression) {
|
||||
nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler(
|
||||
JSContext* aCx, nsGlobalWindowInner* aWindow,
|
||||
LoadedScript* aInitiatingScript, const nsAString& aExpression,
|
||||
bool* aAllowEval, ErrorResult& aError)
|
||||
: mLineNo(0),
|
||||
mColumn(0),
|
||||
mExpr(aExpression),
|
||||
mInitiatingScript(aInitiatingScript) {
|
||||
if (!aWindow->GetContextInternal() || !aWindow->FastGetGlobalJSObject()) {
|
||||
// This window was already closed, or never properly initialized,
|
||||
// don't let a timer be scheduled on such a window.
|
||||
@ -260,9 +277,11 @@ already_AddRefed<nsIScriptTimeoutHandler> NS_CreateJSTimeoutHandler(
|
||||
already_AddRefed<nsIScriptTimeoutHandler> NS_CreateJSTimeoutHandler(
|
||||
JSContext* aCx, nsGlobalWindowInner* aWindow, const nsAString& aExpression,
|
||||
ErrorResult& aError) {
|
||||
LoadedScript* script = ScriptLoader::GetActiveScript(aCx);
|
||||
|
||||
bool allowEval = false;
|
||||
RefPtr<nsJSScriptTimeoutHandler> handler = new nsJSScriptTimeoutHandler(
|
||||
aCx, aWindow, aExpression, &allowEval, aError);
|
||||
aCx, aWindow, script, aExpression, &allowEval, aError);
|
||||
if (aError.Failed() || !allowEval) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
|
||||
mRealm(aCx, aGlobal),
|
||||
mRetValue(aCx),
|
||||
mScopeChain(aCx),
|
||||
mScript(aCx),
|
||||
mRv(NS_OK),
|
||||
mSkip(false),
|
||||
mCoerceToString(false),
|
||||
@ -131,7 +132,8 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
|
||||
#ifdef DEBUG
|
||||
,
|
||||
mWantsReturnValue(false),
|
||||
mExpectScopeChain(false)
|
||||
mExpectScopeChain(false),
|
||||
mScriptUsed(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
||||
@ -174,30 +176,24 @@ void nsJSUtils::ExecutionContext::SetScopeChain(
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::JoinAndExec(
|
||||
JS::OffThreadToken** aOffThreadToken,
|
||||
JS::MutableHandle<JSScript*> aScript) {
|
||||
nsresult nsJSUtils::ExecutionContext::JoinCompile(
|
||||
JS::OffThreadToken** aOffThreadToken) {
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!mScript) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, aScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (!JS_ExecuteScript(mCx, mScopeChain, aScript)) {
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, mScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
@ -206,9 +202,8 @@ nsresult nsJSUtils::ExecutionContext::JoinAndExec(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::CompileAndExec(
|
||||
JS::CompileOptions& aCompileOptions, JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::MutableHandle<JSScript*> aScript) {
|
||||
nsresult nsJSUtils::ExecutionContext::Compile(
|
||||
JS::CompileOptions& aCompileOptions, JS::SourceText<char16_t>& aSrcBuf) {
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
}
|
||||
@ -219,29 +214,23 @@ nsresult nsJSUtils::ExecutionContext::CompileAndExec(
|
||||
mWantsReturnValue = !aCompileOptions.noScriptRval;
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(!mScript);
|
||||
bool compiled = true;
|
||||
if (mScopeChain.length() == 0) {
|
||||
compiled = JS::Compile(mCx, aCompileOptions, aSrcBuf, aScript);
|
||||
compiled = JS::Compile(mCx, aCompileOptions, aSrcBuf, &mScript);
|
||||
} else {
|
||||
compiled =
|
||||
JS::CompileForNonSyntacticScope(mCx, aCompileOptions, aSrcBuf, aScript);
|
||||
compiled = JS::CompileForNonSyntacticScope(mCx, aCompileOptions, aSrcBuf,
|
||||
&mScript);
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(compiled, aScript);
|
||||
MOZ_ASSERT_IF(compiled, mScript);
|
||||
if (!compiled) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, aScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mCoerceToString || mWantsReturnValue);
|
||||
if (!JS_ExecuteScript(mCx, mScopeChain, aScript, &mRetValue)) {
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, mScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
@ -250,10 +239,8 @@ nsresult nsJSUtils::ExecutionContext::CompileAndExec(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::CompileAndExec(
|
||||
nsresult nsJSUtils::ExecutionContext::Compile(
|
||||
JS::CompileOptions& aCompileOptions, const nsAString& aScript) {
|
||||
MOZ_ASSERT(!mEncodeBytecode,
|
||||
"A JSScript is needed for calling FinishIncrementalEncoding");
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
}
|
||||
@ -267,23 +254,19 @@ nsresult nsJSUtils::ExecutionContext::CompileAndExec(
|
||||
return mRv;
|
||||
}
|
||||
|
||||
JS::Rooted<JSScript*> script(mCx);
|
||||
return CompileAndExec(aCompileOptions, srcBuf, &script);
|
||||
return Compile(aCompileOptions, srcBuf);
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::DecodeAndExec(
|
||||
nsresult nsJSUtils::ExecutionContext::Decode(
|
||||
JS::CompileOptions& aCompileOptions, mozilla::Vector<uint8_t>& aBytecodeBuf,
|
||||
size_t aBytecodeIndex) {
|
||||
MOZ_ASSERT(!mEncodeBytecode,
|
||||
"A JSScript is needed for calling FinishIncrementalEncoding");
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mWantsReturnValue);
|
||||
JS::Rooted<JSScript*> script(mCx);
|
||||
JS::TranscodeResult tr =
|
||||
JS::DecodeScript(mCx, aBytecodeBuf, &script, aBytecodeIndex);
|
||||
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.
|
||||
@ -295,16 +278,10 @@ nsresult nsJSUtils::ExecutionContext::DecodeAndExec(
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (!JS_ExecuteScript(mCx, mScopeChain, script)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
return mRv;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::DecodeJoinAndExec(
|
||||
nsresult nsJSUtils::ExecutionContext::JoinDecode(
|
||||
JS::OffThreadToken** aOffThreadToken) {
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
@ -312,10 +289,9 @@ nsresult nsJSUtils::ExecutionContext::DecodeJoinAndExec(
|
||||
|
||||
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;
|
||||
@ -324,9 +300,8 @@ nsresult nsJSUtils::ExecutionContext::DecodeJoinAndExec(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::DecodeBinASTJoinAndExec(
|
||||
JS::OffThreadToken** aOffThreadToken,
|
||||
JS::MutableHandle<JSScript*> aScript) {
|
||||
nsresult nsJSUtils::ExecutionContext::JoinDecodeBinAST(
|
||||
JS::OffThreadToken** aOffThreadToken) {
|
||||
#ifdef JS_BUILD_BINAST
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
@ -335,22 +310,16 @@ nsresult nsJSUtils::ExecutionContext::DecodeBinASTJoinAndExec(
|
||||
MOZ_ASSERT(!mWantsReturnValue);
|
||||
MOZ_ASSERT(!mExpectScopeChain);
|
||||
|
||||
aScript.set(JS::FinishOffThreadBinASTDecode(mCx, *aOffThreadToken));
|
||||
mScript.set(JS::FinishOffThreadBinASTDecode(mCx, *aOffThreadToken));
|
||||
*aOffThreadToken = nullptr; // Mark the token as having been finished.
|
||||
|
||||
if (!aScript) {
|
||||
if (!mScript) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, aScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (!JS_ExecuteScript(mCx, mScopeChain, aScript)) {
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, mScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
@ -362,9 +331,8 @@ nsresult nsJSUtils::ExecutionContext::DecodeBinASTJoinAndExec(
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::DecodeBinASTAndExec(
|
||||
JS::CompileOptions& aCompileOptions, const uint8_t* aBuf, size_t aLength,
|
||||
JS::MutableHandle<JSScript*> aScript) {
|
||||
nsresult nsJSUtils::ExecutionContext::DecodeBinAST(
|
||||
JS::CompileOptions& aCompileOptions, const uint8_t* aBuf, size_t aLength) {
|
||||
#ifdef JS_BUILD_BINAST
|
||||
MOZ_ASSERT(mScopeChain.length() == 0,
|
||||
"BinAST decoding is not supported in non-syntactic scopes");
|
||||
@ -379,22 +347,15 @@ nsresult nsJSUtils::ExecutionContext::DecodeBinASTAndExec(
|
||||
mWantsReturnValue = !aCompileOptions.noScriptRval;
|
||||
#endif
|
||||
|
||||
aScript.set(JS::DecodeBinAST(mCx, aCompileOptions, aBuf, aLength));
|
||||
mScript.set(JS::DecodeBinAST(mCx, aCompileOptions, aBuf, aLength));
|
||||
|
||||
if (!aScript) {
|
||||
if (!mScript) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, aScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mCoerceToString || mWantsReturnValue);
|
||||
if (!JS_ExecuteScript(mCx, mScopeChain, aScript, &mRetValue)) {
|
||||
if (mEncodeBytecode && !StartIncrementalEncoding(mCx, mScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
@ -406,6 +367,32 @@ nsresult nsJSUtils::ExecutionContext::DecodeBinASTAndExec(
|
||||
#endif
|
||||
}
|
||||
|
||||
JSScript* nsJSUtils::ExecutionContext::GetScript() {
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!mSkip);
|
||||
MOZ_ASSERT(mScript);
|
||||
mScriptUsed = true;
|
||||
#endif
|
||||
|
||||
return mScript;
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::ExecScript() {
|
||||
if (mSkip) {
|
||||
return mRv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mScript);
|
||||
|
||||
if (!JS_ExecuteScript(mCx, mScopeChain, mScript)) {
|
||||
mSkip = true;
|
||||
mRv = EvaluationExceptionToNSResult(mCx);
|
||||
return mRv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool IsPromiseValue(JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
if (!aValue.isObject()) {
|
||||
return false;
|
||||
@ -419,43 +406,45 @@ static bool IsPromiseValue(JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
return JS::IsPromiseObject(obj);
|
||||
}
|
||||
|
||||
nsresult nsJSUtils::ExecutionContext::ExtractReturnValue(
|
||||
nsresult 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
|
||||
aRetValue.setUndefined();
|
||||
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 && IsPromiseValue(mCx, mRetValue)) {
|
||||
if (mCoerceToString && IsPromiseValue(mCx, aRetValue)) {
|
||||
// We're a javascript: url and we should treat Promise return values as
|
||||
// undefined.
|
||||
//
|
||||
// Once bug 1477821 is fixed this code might be able to go away, or will
|
||||
// become enshrined in the spec, depending.
|
||||
mRetValue.setUndefined();
|
||||
aRetValue.setUndefined();
|
||||
}
|
||||
|
||||
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.
|
||||
mSkip = true;
|
||||
return EvaluationExceptionToNSResult(mCx);
|
||||
}
|
||||
mRetValue.set(JS::StringValue(str));
|
||||
aRetValue.set(JS::StringValue(str));
|
||||
}
|
||||
|
||||
aRetValue.set(mRetValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -465,7 +454,6 @@ nsresult nsJSUtils::CompileModule(JSContext* aCx,
|
||||
JS::CompileOptions& aCompileOptions,
|
||||
JS::MutableHandle<JSObject*> aModule) {
|
||||
AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
|
||||
|
||||
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
||||
MOZ_ASSERT(aSrcBuf.get());
|
||||
MOZ_ASSERT(JS_IsGlobalObject(aEvaluationGlobal));
|
||||
|
@ -81,6 +81,9 @@ class nsJSUtils {
|
||||
// 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;
|
||||
@ -100,6 +103,8 @@ class nsJSUtils {
|
||||
bool mWantsReturnValue;
|
||||
|
||||
bool mExpectScopeChain;
|
||||
|
||||
bool mScriptUsed;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@ -111,8 +116,12 @@ class nsJSUtils {
|
||||
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
|
||||
@ -134,54 +143,53 @@ class nsJSUtils {
|
||||
// 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(JS::OffThreadToken** aOffThreadToken);
|
||||
|
||||
// Compile a script contained in a SourceText.
|
||||
nsresult Compile(JS::CompileOptions& aCompileOptions,
|
||||
JS::SourceText<char16_t>& 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(JS::OffThreadToken** aOffThreadToken);
|
||||
|
||||
nsresult JoinDecodeBinAST(JS::OffThreadToken** aOffThreadToken);
|
||||
|
||||
// Decode a BinAST encoded script contained in a buffer.
|
||||
nsresult DecodeBinAST(JS::CompileOptions& aCompileOptions,
|
||||
const uint8_t* aBuf, size_t aLength);
|
||||
|
||||
// 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
|
||||
// caller is in a different compartment, then the out-param value should be
|
||||
// wrapped by calling |JS_WrapValue|.
|
||||
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(JS::OffThreadToken** aOffThreadToken,
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
|
||||
// Compile a script contained in a SourceText, and execute it.
|
||||
nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
|
||||
JS::SourceText<char16_t>& aSrcBuf,
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
|
||||
// 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(JS::OffThreadToken** aOffThreadToken);
|
||||
|
||||
MOZ_MUST_USE nsresult
|
||||
DecodeBinASTJoinAndExec(JS::OffThreadToken** aOffThreadToken,
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
|
||||
// Decode a BinAST encoded script contained in a buffer, and execute it.
|
||||
nsresult DecodeBinASTAndExec(JS::CompileOptions& aCompileOptions,
|
||||
const uint8_t* aBuf, size_t aLength,
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
MOZ_MUST_USE nsresult ExecScript(JS::MutableHandle<JS::Value> aRetValue);
|
||||
};
|
||||
|
||||
static nsresult CompileModule(JSContext* aCx,
|
||||
|
@ -22,7 +22,9 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "mozilla/dom/LoadedScript.h"
|
||||
#include "mozilla/dom/PopupBlocker.h"
|
||||
#include "mozilla/dom/ScriptLoader.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/TouchEvent.h"
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
@ -990,6 +992,15 @@ nsresult EventListenerManager::CompileEventHandlerInternal(
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
|
||||
|
||||
JS::Rooted<JSFunction*> func(cx, JS_GetObjectFunction(handler));
|
||||
MOZ_ASSERT(func);
|
||||
JS::Rooted<JSScript*> jsScript(cx, JS_GetFunctionScript(cx, func));
|
||||
MOZ_ASSERT(jsScript);
|
||||
RefPtr<LoadedScript> loaderScript = ScriptLoader::GetActiveScript(cx);
|
||||
if (loaderScript) {
|
||||
loaderScript->AssociateWithScript(jsScript);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(handler, cx));
|
||||
JS::Rooted<JSObject*> handlerGlobal(cx, JS::CurrentGlobalOrNull(cx));
|
||||
|
||||
|
@ -254,8 +254,8 @@ nsresult nsJSThunk::EvaluateScript(
|
||||
{
|
||||
nsJSUtils::ExecutionContext exec(cx, globalJSObject);
|
||||
exec.SetCoerceToString(true);
|
||||
exec.CompileAndExec(options, NS_ConvertUTF8toUTF16(script));
|
||||
rv = exec.ExtractReturnValue(&v);
|
||||
exec.Compile(options, NS_ConvertUTF8toUTF16(script));
|
||||
rv = exec.ExecScript(&v);
|
||||
}
|
||||
|
||||
js::AssertSameCompartment(cx, v);
|
||||
|
@ -998,8 +998,8 @@ bool _evaluate(NPP npp, NPObject *npobj, NPString *script, NPVariant *result) {
|
||||
{
|
||||
nsJSUtils::ExecutionContext exec(cx, obj);
|
||||
exec.SetScopeChain(scopeChain);
|
||||
exec.CompileAndExec(options, utf16script);
|
||||
rv = exec.ExtractReturnValue(&rval);
|
||||
exec.Compile(options, utf16script);
|
||||
rv = exec.ExecScript(&rval);
|
||||
}
|
||||
|
||||
if (!JS_WrapValue(cx, &rval)) {
|
||||
|
184
dom/script/LoadedScript.cpp
Normal file
184
dom/script/LoadedScript.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "LoadedScript.h"
|
||||
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "ScriptLoader.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// LoadedScript
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadedScript)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
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_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LoadedScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(LoadedScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
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) {
|
||||
MOZ_ASSERT(mFetchOptions);
|
||||
MOZ_ASSERT(mBaseURL);
|
||||
}
|
||||
|
||||
LoadedScript::~LoadedScript() { DropJSObjects(this); }
|
||||
|
||||
void LoadedScript::AssociateWithScript(JSScript* aScript) {
|
||||
// Set a JSScript's private value to point to this object and
|
||||
// increment our reference count. This is decremented by
|
||||
// HostFinalizeTopLevelScript() below when the JSScript dies.
|
||||
|
||||
MOZ_ASSERT(JS::GetScriptPrivate(aScript).isUndefined());
|
||||
JS::SetScriptPrivate(aScript, JS::PrivateValue(this));
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate) {
|
||||
// Decrement the reference count of a LoadedScript object that is
|
||||
// pointed to by a dying JSScript. The reference count was
|
||||
// originally incremented by AssociateWithScript() above.
|
||||
|
||||
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (script->IsModuleScript()) {
|
||||
JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet();
|
||||
MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate);
|
||||
}
|
||||
#endif
|
||||
|
||||
script->Release();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ClassicScript
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
ClassicScript::ClassicScript(ScriptFetchOptions* aFetchOptions,
|
||||
nsIURI* aBaseURL)
|
||||
: LoadedScript(ScriptKind::eClassic, aFetchOptions, aBaseURL) {}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ModuleScript
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
|
||||
NS_INTERFACE_MAP_END_INHERITING(LoadedScript)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleScript, LoadedScript)
|
||||
tmp->UnlinkModuleRecord();
|
||||
tmp->mParseError.setUndefined();
|
||||
tmp->mErrorToRethrow.setUndefined();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleScript, LoadedScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleScript, LoadedScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
|
||||
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),
|
||||
mSourceElementAssociated(false) {
|
||||
MOZ_ASSERT(!ModuleRecord());
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
}
|
||||
|
||||
void ModuleScript::UnlinkModuleRecord() {
|
||||
// Remove the module record's pointer to this object if present and
|
||||
// decrement our reference count. The reference is added by
|
||||
// SetModuleRecord() below.
|
||||
if (mModuleRecord) {
|
||||
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() == this);
|
||||
JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
|
||||
mModuleRecord = nullptr;
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
ModuleScript::~ModuleScript() {
|
||||
// The object may be destroyed without being unlinked first.
|
||||
UnlinkModuleRecord();
|
||||
}
|
||||
|
||||
void ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) {
|
||||
MOZ_ASSERT(!mModuleRecord);
|
||||
MOZ_ASSERT_IF(IsModuleScript(), !AsModuleScript()->HasParseError());
|
||||
MOZ_ASSERT_IF(IsModuleScript(), !AsModuleScript()->HasErrorToRethrow());
|
||||
|
||||
mModuleRecord = aModuleRecord;
|
||||
|
||||
// Make module's host defined field point to this object and
|
||||
// increment our reference count. This is decremented by
|
||||
// UnlinkModuleRecord() above.
|
||||
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined());
|
||||
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
|
||||
|
||||
HoldJSObjects(this);
|
||||
AddRef();
|
||||
}
|
||||
|
||||
void ModuleScript::SetParseError(const JS::Value& aError) {
|
||||
MOZ_ASSERT(!aError.isUndefined());
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
UnlinkModuleRecord();
|
||||
mParseError = aError;
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
|
||||
void ModuleScript::SetErrorToRethrow(const JS::Value& aError) {
|
||||
MOZ_ASSERT(!aError.isUndefined());
|
||||
|
||||
// This is only called after SetModuleRecord() or SetParseError() so we don't
|
||||
// need to call HoldJSObjects() here.
|
||||
MOZ_ASSERT(ModuleRecord() || HasParseError());
|
||||
|
||||
mErrorToRethrow = aError;
|
||||
}
|
||||
|
||||
void ModuleScript::SetSourceElementAssociated() {
|
||||
MOZ_ASSERT(ModuleRecord());
|
||||
MOZ_ASSERT(!mSourceElementAssociated);
|
||||
|
||||
mSourceElementAssociated = true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
108
dom/script/LoadedScript.h
Normal file
108
dom/script/LoadedScript.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_LoadedScript_h
|
||||
#define mozilla_dom_LoadedScript_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "jsapi.h"
|
||||
#include "ScriptLoadRequest.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScriptLoader;
|
||||
|
||||
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate);
|
||||
|
||||
class ClassicScript;
|
||||
class ModuleScript;
|
||||
|
||||
class LoadedScript : public nsISupports {
|
||||
ScriptKind mKind;
|
||||
RefPtr<ScriptFetchOptions> mFetchOptions;
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
|
||||
protected:
|
||||
LoadedScript(ScriptKind aKind, ScriptFetchOptions* aFetchOptions,
|
||||
nsIURI* aBaseURL);
|
||||
|
||||
virtual ~LoadedScript();
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(LoadedScript)
|
||||
|
||||
bool IsModuleScript() const { return mKind == ScriptKind::eModule; }
|
||||
|
||||
inline ClassicScript* AsClassicScript();
|
||||
inline ModuleScript* AsModuleScript();
|
||||
|
||||
ScriptFetchOptions* FetchOptions() const { return mFetchOptions; }
|
||||
nsIURI* BaseURL() const { return mBaseURL; }
|
||||
|
||||
void AssociateWithScript(JSScript* aScript);
|
||||
};
|
||||
|
||||
class ClassicScript final : public LoadedScript {
|
||||
~ClassicScript() = default;
|
||||
|
||||
public:
|
||||
ClassicScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL);
|
||||
};
|
||||
|
||||
// A single module script. May be used to satisfy multiple load requests.
|
||||
|
||||
class ModuleScript final : public LoadedScript {
|
||||
JS::Heap<JSObject*> mModuleRecord;
|
||||
JS::Heap<JS::Value> mParseError;
|
||||
JS::Heap<JS::Value> mErrorToRethrow;
|
||||
bool mSourceElementAssociated;
|
||||
|
||||
~ModuleScript();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleScript,
|
||||
LoadedScript)
|
||||
|
||||
ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL);
|
||||
|
||||
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||
void SetParseError(const JS::Value& aError);
|
||||
void SetErrorToRethrow(const JS::Value& aError);
|
||||
void SetSourceElementAssociated();
|
||||
|
||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||
|
||||
JS::Value ParseError() const { return mParseError; }
|
||||
JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
|
||||
bool HasParseError() const { return !mParseError.isUndefined(); }
|
||||
bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
|
||||
bool SourceElementAssociated() const { return mSourceElementAssociated; }
|
||||
|
||||
void UnlinkModuleRecord();
|
||||
|
||||
friend void HostFinalizeTopLevelScript(JSFreeOp*, const JS::Value&);
|
||||
};
|
||||
|
||||
ClassicScript* LoadedScript::AsClassicScript() {
|
||||
MOZ_ASSERT(!IsModuleScript());
|
||||
return static_cast<ClassicScript*>(this);
|
||||
}
|
||||
|
||||
ModuleScript* LoadedScript::AsModuleScript() {
|
||||
MOZ_ASSERT(IsModuleScript());
|
||||
return static_cast<ModuleScript*>(this);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_LoadedScript_h
|
@ -5,7 +5,10 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ModuleLoadRequest.h"
|
||||
#include "ModuleScript.h"
|
||||
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
|
||||
#include "LoadedScript.h"
|
||||
#include "ScriptLoader.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -18,35 +21,91 @@ namespace dom {
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleLoadRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest,
|
||||
mBaseURL, mLoader, mModuleScript, mImports)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleLoadRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest,
|
||||
ScriptLoadRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader, mModuleScript, mImports)
|
||||
tmp->ClearDynamicImport();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest,
|
||||
ScriptLoadRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader, mModuleScript, mImports)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest,
|
||||
ScriptLoadRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicReferencingPrivate)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
|
||||
NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
|
||||
|
||||
ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI,
|
||||
ScriptFetchOptions* aFetchOptions,
|
||||
const SRIMetadata& aIntegrity,
|
||||
nsIURI* aReferrer, ScriptLoader* aLoader)
|
||||
static VisitedURLSet* NewVisitedSetForTopLevelImport(nsIURI* aURI) {
|
||||
auto set = new VisitedURLSet();
|
||||
set->PutEntry(aURI);
|
||||
return set;
|
||||
}
|
||||
|
||||
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateTopLevel(
|
||||
nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
|
||||
const SRIMetadata& aIntegrity, nsIURI* aReferrer, ScriptLoader* aLoader) {
|
||||
return new ModuleLoadRequest(aURI, aFetchOptions, aIntegrity, aReferrer,
|
||||
true, /* is top level */
|
||||
false, /* is dynamic import */
|
||||
aLoader, NewVisitedSetForTopLevelImport(aURI));
|
||||
}
|
||||
|
||||
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateStaticImport(
|
||||
nsIURI* aURI, ModuleLoadRequest* aParent) {
|
||||
auto request =
|
||||
new ModuleLoadRequest(aURI, aParent->mFetchOptions, SRIMetadata(),
|
||||
aParent->mURI, false, /* is top level */
|
||||
false, /* is dynamic import */
|
||||
aParent->mLoader, aParent->mVisitedSet);
|
||||
|
||||
request->mIsInline = false;
|
||||
request->mScriptMode = aParent->mScriptMode;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/* static */ ModuleLoadRequest* ModuleLoadRequest::CreateDynamicImport(
|
||||
nsIURI* aURI, ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
|
||||
ScriptLoader* aLoader, JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSString*> aSpecifier, JS::Handle<JSObject*> aPromise) {
|
||||
MOZ_ASSERT(aSpecifier);
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
auto request = new ModuleLoadRequest(
|
||||
aURI, aFetchOptions, SRIMetadata(), aBaseURL, true, /* is top level */
|
||||
true, /* is dynamic import */
|
||||
aLoader, NewVisitedSetForTopLevelImport(aURI));
|
||||
|
||||
request->mIsInline = false;
|
||||
request->mScriptMode = ScriptMode::eAsync;
|
||||
request->mDynamicReferencingPrivate = aReferencingPrivate;
|
||||
request->mDynamicSpecifier = aSpecifier;
|
||||
request->mDynamicPromise = aPromise;
|
||||
|
||||
HoldJSObjects(request);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
ModuleLoadRequest::ModuleLoadRequest(
|
||||
nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
|
||||
const SRIMetadata& aIntegrity, nsIURI* aReferrer, bool aIsTopLevel,
|
||||
bool aIsDynamicImport, ScriptLoader* aLoader, VisitedURLSet* aVisitedSet)
|
||||
: ScriptLoadRequest(ScriptKind::eModule, aURI, aFetchOptions, aIntegrity,
|
||||
aReferrer),
|
||||
mIsTopLevel(true),
|
||||
mIsTopLevel(aIsTopLevel),
|
||||
mIsDynamicImport(aIsDynamicImport),
|
||||
mLoader(aLoader),
|
||||
mVisitedSet(new VisitedURLSet()) {
|
||||
mVisitedSet->PutEntry(aURI);
|
||||
}
|
||||
|
||||
ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI, ModuleLoadRequest* aParent)
|
||||
: ScriptLoadRequest(ScriptKind::eModule, aURI, aParent->mFetchOptions,
|
||||
SRIMetadata(), aParent->mURI),
|
||||
mIsTopLevel(false),
|
||||
mLoader(aParent->mLoader),
|
||||
mVisitedSet(aParent->mVisitedSet) {
|
||||
MOZ_ASSERT(mVisitedSet->Contains(aURI));
|
||||
|
||||
mIsInline = false;
|
||||
mScriptMode = aParent->mScriptMode;
|
||||
}
|
||||
mVisitedSet(aVisitedSet) {}
|
||||
|
||||
void ModuleLoadRequest::Cancel() {
|
||||
ScriptLoadRequest::Cancel();
|
||||
@ -138,5 +197,11 @@ void ModuleLoadRequest::LoadFinished() {
|
||||
mLoader = nullptr;
|
||||
}
|
||||
|
||||
void ModuleLoadRequest::ClearDynamicImport() {
|
||||
mDynamicReferencingPrivate = JS::UndefinedValue();
|
||||
mDynamicSpecifier = nullptr;
|
||||
mDynamicPromise = nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -36,22 +36,40 @@ class ModuleLoadRequest final : public ScriptLoadRequest {
|
||||
ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete;
|
||||
ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
|
||||
|
||||
// Create a top-level module load request.
|
||||
ModuleLoadRequest(nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
|
||||
const SRIMetadata& aIntegrity, nsIURI* aReferrer,
|
||||
ScriptLoader* aLoader);
|
||||
bool aIsTopLevel, bool aIsDynamicImport,
|
||||
ScriptLoader* aLoader, VisitedURLSet* aVisitedSet);
|
||||
|
||||
// Create a module load request for an imported module.
|
||||
ModuleLoadRequest(nsIURI* aURI, ModuleLoadRequest* aParent);
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleLoadRequest,
|
||||
ScriptLoadRequest)
|
||||
|
||||
// Create a top-level module load request.
|
||||
static ModuleLoadRequest* CreateTopLevel(nsIURI* aURI,
|
||||
ScriptFetchOptions* aFetchOptions,
|
||||
const SRIMetadata& aIntegrity,
|
||||
nsIURI* aReferrer,
|
||||
ScriptLoader* aLoader);
|
||||
|
||||
// Create a module load request for a static module import.
|
||||
static ModuleLoadRequest* CreateStaticImport(nsIURI* aURI,
|
||||
ModuleLoadRequest* aParent);
|
||||
|
||||
// Create a module load request for dynamic module import.
|
||||
static ModuleLoadRequest* CreateDynamicImport(
|
||||
nsIURI* aURI, ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
|
||||
ScriptLoader* aLoader, JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSString*> aSpecifier, JS::Handle<JSObject*> aPromise);
|
||||
|
||||
bool IsTopLevel() const override { return mIsTopLevel; }
|
||||
|
||||
bool IsDynamicImport() const { return mIsDynamicImport; }
|
||||
|
||||
void SetReady() override;
|
||||
void Cancel() override;
|
||||
void ClearDynamicImport();
|
||||
|
||||
void ModuleLoaded();
|
||||
void ModuleErrored();
|
||||
@ -66,8 +84,8 @@ class ModuleLoadRequest final : public ScriptLoadRequest {
|
||||
// Is this a request for a top level module script or an import?
|
||||
const bool mIsTopLevel;
|
||||
|
||||
// The base URL used for resolving relative module imports.
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
// Is this the top level request for a dynamic module import?
|
||||
const bool mIsDynamicImport;
|
||||
|
||||
// Pointer to the script loader, used to trigger actions when the module load
|
||||
// finishes.
|
||||
@ -88,6 +106,11 @@ class ModuleLoadRequest final : public ScriptLoadRequest {
|
||||
// Set of module URLs visited while fetching the module graph this request is
|
||||
// part of.
|
||||
RefPtr<VisitedURLSet> mVisitedSet;
|
||||
|
||||
// For dynamic imports, the details to pass to FinishDynamicImport.
|
||||
JS::Heap<JS::Value> mDynamicReferencingPrivate;
|
||||
JS::Heap<JSString*> mDynamicSpecifier;
|
||||
JS::Heap<JSObject*> mDynamicPromise;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -1,108 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ModuleScript.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "ScriptLoader.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// A single module script. May be used to satisfy multiple load requests.
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
||||
tmp->UnlinkModuleRecord();
|
||||
tmp->mParseError.setUndefined();
|
||||
tmp->mErrorToRethrow.setUndefined();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
||||
|
||||
ModuleScript::ModuleScript(ScriptLoader* aLoader, nsIURI* aBaseURL)
|
||||
: mLoader(aLoader), mBaseURL(aBaseURL), mSourceElementAssociated(false) {
|
||||
MOZ_ASSERT(mLoader);
|
||||
MOZ_ASSERT(mBaseURL);
|
||||
MOZ_ASSERT(!mModuleRecord);
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
}
|
||||
|
||||
void ModuleScript::UnlinkModuleRecord() {
|
||||
// Remove module's back reference to this object request if present.
|
||||
if (mModuleRecord) {
|
||||
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).toPrivate() == this);
|
||||
JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
|
||||
mModuleRecord = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ModuleScript::~ModuleScript() {
|
||||
// The object may be destroyed without being unlinked first.
|
||||
UnlinkModuleRecord();
|
||||
DropJSObjects(this);
|
||||
}
|
||||
|
||||
void ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) {
|
||||
MOZ_ASSERT(!mModuleRecord);
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
mModuleRecord = aModuleRecord;
|
||||
|
||||
// Make module's host defined field point to this module script object.
|
||||
// This is cleared in the UnlinkModuleRecord().
|
||||
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
|
||||
void ModuleScript::SetParseError(const JS::Value& aError) {
|
||||
MOZ_ASSERT(!aError.isUndefined());
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
UnlinkModuleRecord();
|
||||
mParseError = aError;
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
|
||||
void ModuleScript::SetErrorToRethrow(const JS::Value& aError) {
|
||||
MOZ_ASSERT(!aError.isUndefined());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
// This is only called after SetModuleRecord() or SetParseError() so we don't
|
||||
// need to call HoldJSObjects() here.
|
||||
MOZ_ASSERT(mModuleRecord || HasParseError());
|
||||
|
||||
mErrorToRethrow = aError;
|
||||
}
|
||||
|
||||
void ModuleScript::SetSourceElementAssociated() {
|
||||
MOZ_ASSERT(mModuleRecord);
|
||||
MOZ_ASSERT(!mSourceElementAssociated);
|
||||
|
||||
mSourceElementAssociated = true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,57 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ModuleScript_h
|
||||
#define mozilla_dom_ModuleScript_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScriptLoader;
|
||||
|
||||
class ModuleScript final : public nsISupports {
|
||||
RefPtr<ScriptLoader> mLoader;
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
JS::Heap<JSObject*> mModuleRecord;
|
||||
JS::Heap<JS::Value> mParseError;
|
||||
JS::Heap<JS::Value> mErrorToRethrow;
|
||||
bool mSourceElementAssociated;
|
||||
|
||||
~ModuleScript();
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
|
||||
|
||||
ModuleScript(ScriptLoader* aLoader, nsIURI* aBaseURL);
|
||||
|
||||
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||
void SetParseError(const JS::Value& aError);
|
||||
void SetErrorToRethrow(const JS::Value& aError);
|
||||
void SetSourceElementAssociated();
|
||||
|
||||
ScriptLoader* Loader() const { return mLoader; }
|
||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||
nsIURI* BaseURL() const { return mBaseURL; }
|
||||
JS::Value ParseError() const { return mParseError; }
|
||||
JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
|
||||
bool HasParseError() const { return !mParseError.isUndefined(); }
|
||||
bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
|
||||
bool SourceElementAssociated() const { return mSourceElementAssociated; }
|
||||
|
||||
void UnlinkModuleRecord();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ModuleScript_h
|
@ -4,7 +4,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ModuleLoadRequest.h"
|
||||
#include "ScriptLoadRequest.h"
|
||||
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@ -30,6 +30,7 @@ ScriptFetchOptions::ScriptFetchOptions(
|
||||
nsIScriptElement* aElement, nsIPrincipal* aTriggeringPrincipal)
|
||||
: mCORSMode(aCORSMode),
|
||||
mReferrerPolicy(aReferrerPolicy),
|
||||
mIsPreload(false),
|
||||
mElement(aElement),
|
||||
mTriggeringPrincipal(aTriggeringPrincipal) {
|
||||
MOZ_ASSERT(mTriggeringPrincipal);
|
||||
@ -50,14 +51,13 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheInfo)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions, mCacheInfo)
|
||||
tmp->mScript = nullptr;
|
||||
tmp->DropBytecodeCacheReferences();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheInfo)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions, mCacheInfo)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadRequest)
|
||||
@ -105,6 +105,8 @@ ScriptLoadRequest::~ScriptLoadRequest() {
|
||||
if (mScript) {
|
||||
DropBytecodeCacheReferences();
|
||||
}
|
||||
|
||||
DropJSObjects(this);
|
||||
}
|
||||
|
||||
void ScriptLoadRequest::SetReady() {
|
||||
@ -207,6 +209,12 @@ void ScriptLoadRequest::ClearScriptSource() {
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptLoadRequest::SetScript(JSScript* aScript) {
|
||||
MOZ_ASSERT(!mScript);
|
||||
mScript = aScript;
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// ScriptLoadRequestList
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
@ -50,6 +50,7 @@ class ScriptFetchOptions {
|
||||
|
||||
const mozilla::CORSMode mCORSMode;
|
||||
const mozilla::net::ReferrerPolicy mReferrerPolicy;
|
||||
bool mIsPreload;
|
||||
nsCOMPtr<nsIScriptElement> mElement;
|
||||
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||
};
|
||||
@ -91,7 +92,10 @@ class ScriptLoadRequest
|
||||
Element()->ScriptEvaluated(aResult, Element(), mIsInline);
|
||||
}
|
||||
|
||||
bool IsPreload() { return Element() == nullptr; }
|
||||
bool IsPreload() const {
|
||||
MOZ_ASSERT_IF(mFetchOptions->mIsPreload, !Element());
|
||||
return mFetchOptions->mIsPreload;
|
||||
}
|
||||
|
||||
virtual void Cancel();
|
||||
|
||||
@ -199,17 +203,36 @@ class ScriptLoadRequest
|
||||
return mFetchOptions->mTriggeringPrincipal;
|
||||
}
|
||||
|
||||
void SetElement(nsIScriptElement* aElement) {
|
||||
// Called when a preload request is later used for an actual request.
|
||||
// Make this request a preload (speculative) request.
|
||||
void SetIsPreloadRequest() {
|
||||
MOZ_ASSERT(!Element());
|
||||
MOZ_ASSERT(!IsPreload());
|
||||
mFetchOptions->mIsPreload = true;
|
||||
}
|
||||
|
||||
// Make a preload request into an actual load request for the given element.
|
||||
void SetIsLoadRequest(nsIScriptElement* aElement) {
|
||||
MOZ_ASSERT(aElement);
|
||||
MOZ_ASSERT(!Element());
|
||||
MOZ_ASSERT(IsPreload());
|
||||
mFetchOptions->mElement = aElement;
|
||||
mFetchOptions->mIsPreload = false;
|
||||
}
|
||||
|
||||
FromParser GetParserCreated() const {
|
||||
nsIScriptElement* element = Element();
|
||||
if (!element) {
|
||||
return NOT_FROM_PARSER;
|
||||
}
|
||||
return element->GetParserCreated();
|
||||
}
|
||||
|
||||
bool ShouldAcceptBinASTEncoding() const;
|
||||
|
||||
void ClearScriptSource();
|
||||
|
||||
void SetScript(JSScript* aScript);
|
||||
|
||||
void MaybeCancelOffThreadScript();
|
||||
void DropBytecodeCacheReferences();
|
||||
|
||||
@ -271,6 +294,9 @@ class ScriptLoadRequest
|
||||
// Holds the Cache information, which is used to register the bytecode
|
||||
// on the cache entry, such that we can load it the next time.
|
||||
nsCOMPtr<nsICacheInfoChannel> mCacheInfo;
|
||||
|
||||
// The base URL used for resolving relative module imports.
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
};
|
||||
|
||||
class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest> {
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include "ScriptLoadHandler.h"
|
||||
#include "ScriptLoadRequest.h"
|
||||
#include "ScriptTrace.h"
|
||||
#include "LoadedScript.h"
|
||||
#include "ModuleLoadRequest.h"
|
||||
#include "ModuleScript.h"
|
||||
|
||||
#include "prsystem.h"
|
||||
#include "jsapi.h"
|
||||
@ -17,6 +17,7 @@
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/MemoryFunctions.h"
|
||||
#include "js/OffThreadScriptCompilation.h"
|
||||
#include "js/Realm.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/Utility.h"
|
||||
#include "xpcpublic.h"
|
||||
@ -29,6 +30,7 @@
|
||||
#include "mozilla/dom/SRILogHelper.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
@ -113,9 +115,9 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(ScriptLoader, mNonAsyncExternalScriptInsertedRequests,
|
||||
mLoadingAsyncRequests, mLoadedAsyncRequests,
|
||||
mDeferRequests, mXSLTRequests, mParserBlockingRequest,
|
||||
mBytecodeEncodingQueue, mPreloads,
|
||||
mPendingChildLoaders, mFetchedModules)
|
||||
mDeferRequests, mXSLTRequests, mDynamicImportRequests,
|
||||
mParserBlockingRequest, mBytecodeEncodingQueue,
|
||||
mPreloads, mPendingChildLoaders, mFetchedModules)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoader)
|
||||
@ -133,6 +135,7 @@ ScriptLoader::ScriptLoader(nsIDocument* aDocument)
|
||||
mGiveUpEncoding(false),
|
||||
mReporter(new ConsoleReportCollector()) {
|
||||
LOG(("ScriptLoader::ScriptLoader %p", this));
|
||||
EnsureModuleHooksInitialized();
|
||||
}
|
||||
|
||||
ScriptLoader::~ScriptLoader() {
|
||||
@ -164,6 +167,11 @@ ScriptLoader::~ScriptLoader() {
|
||||
req->FireScriptAvailable(NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
for (ScriptLoadRequest* req =
|
||||
mNonAsyncExternalScriptInsertedRequests.getFirst();
|
||||
req; req = req->getNext()) {
|
||||
@ -204,8 +212,6 @@ static void CollectScriptTelemetry(ScriptLoadRequest* aRequest) {
|
||||
if (aRequest->IsLoadingSource()) {
|
||||
if (aRequest->mIsInline) {
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
|
||||
nsAutoString inlineData;
|
||||
aRequest->Element()->GetScriptText(inlineData);
|
||||
} else if (aRequest->IsTextSource()) {
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::SourceFallback);
|
||||
}
|
||||
@ -471,7 +477,7 @@ nsresult ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) {
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
||||
|
||||
RefPtr<ModuleScript> moduleScript =
|
||||
new ModuleScript(this, aRequest->mBaseURL);
|
||||
new ModuleScript(aRequest->mFetchOptions, aRequest->mBaseURL);
|
||||
aRequest->mModuleScript = moduleScript;
|
||||
|
||||
if (!module) {
|
||||
@ -541,7 +547,7 @@ static nsresult HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
||||
}
|
||||
|
||||
static already_AddRefed<nsIURI> ResolveModuleSpecifier(
|
||||
ModuleScript* aScript, const nsAString& aSpecifier) {
|
||||
ScriptLoader* aLoader, LoadedScript* aScript, const nsAString& aSpecifier) {
|
||||
// The following module specifiers are allowed by the spec:
|
||||
// - a valid absolute URL
|
||||
// - a valid relative URL that starts with "/", "./" or "../"
|
||||
@ -565,7 +571,15 @@ static already_AddRefed<nsIURI> ResolveModuleSpecifier(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, aScript->BaseURL());
|
||||
// Get the document's base URL if we don't have a referencing script here.
|
||||
nsCOMPtr<nsIURI> baseURL;
|
||||
if (aScript) {
|
||||
baseURL = aScript->BaseURL();
|
||||
} else {
|
||||
baseURL = aLoader->GetDocument()->GetDocBaseURI();
|
||||
}
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(uri), aSpecifier, nullptr, baseURL);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return uri.forget();
|
||||
}
|
||||
@ -609,7 +623,8 @@ static nsresult ResolveRequestedModules(ModuleLoadRequest* aRequest,
|
||||
|
||||
// Let url be the result of resolving a module specifier given module script
|
||||
// and requested.
|
||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
|
||||
nsCOMPtr<nsIURI> uri =
|
||||
ResolveModuleSpecifier(aRequest->mLoader, ms, specifier);
|
||||
if (!uri) {
|
||||
uint32_t lineNumber = 0;
|
||||
uint32_t columnNumber = 0;
|
||||
@ -689,7 +704,8 @@ RefPtr<GenericPromise> ScriptLoader::StartFetchingModuleAndDependencies(
|
||||
ModuleLoadRequest* aParent, nsIURI* aURI) {
|
||||
MOZ_ASSERT(aURI);
|
||||
|
||||
RefPtr<ModuleLoadRequest> childRequest = new ModuleLoadRequest(aURI, aParent);
|
||||
RefPtr<ModuleLoadRequest> childRequest =
|
||||
ModuleLoadRequest::CreateStaticImport(aURI, aParent);
|
||||
|
||||
aParent->mImports.AppendElement(childRequest);
|
||||
|
||||
@ -720,23 +736,81 @@ RefPtr<GenericPromise> ScriptLoader::StartFetchingModuleAndDependencies(
|
||||
return ready;
|
||||
}
|
||||
|
||||
static ScriptLoader* GetCurrentScriptLoader(JSContext* aCx) {
|
||||
JSObject* object = JS::CurrentGlobalOrNull(aCx);
|
||||
if (!object) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(object);
|
||||
if (!global) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global);
|
||||
nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(win);
|
||||
if (!innerWindow) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIDocument* document = innerWindow->GetDocument();
|
||||
if (!document) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScriptLoader* loader = document->ScriptLoader();
|
||||
if (!loader) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
static LoadedScript* GetLoadedScriptOrNull(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate) {
|
||||
if (aReferencingPrivate.isUndefined()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto script = static_cast<LoadedScript*>(aReferencingPrivate.toPrivate());
|
||||
MOZ_ASSERT_IF(
|
||||
script->IsModuleScript(),
|
||||
JS::GetModulePrivate(script->AsModuleScript()->ModuleRecord()) ==
|
||||
aReferencingPrivate);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
|
||||
JSObject* HostResolveImportedModule(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSString*> aSpecifier) {
|
||||
// Let referencing module script be referencingModule.[[HostDefined]].
|
||||
auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
|
||||
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) ==
|
||||
aReferencingPrivate);
|
||||
JS::Rooted<JSObject*> module(aCx);
|
||||
ScriptLoader::ResolveImportedModule(aCx, aReferencingPrivate, aSpecifier,
|
||||
&module);
|
||||
return module;
|
||||
}
|
||||
|
||||
/* static */ void ScriptLoader::ResolveImportedModule(
|
||||
JSContext* aCx, JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSString*> aSpecifier, JS::MutableHandle<JSObject*> aModuleOut) {
|
||||
MOZ_ASSERT(!aModuleOut);
|
||||
|
||||
RefPtr<LoadedScript> script(GetLoadedScriptOrNull(aCx, aReferencingPrivate));
|
||||
|
||||
// Let url be the result of resolving a module specifier given referencing
|
||||
// module script and specifier.
|
||||
nsAutoJSString string;
|
||||
if (!string.init(aCx, aSpecifier)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
|
||||
RefPtr<ScriptLoader> loader = GetCurrentScriptLoader(aCx);
|
||||
if (!loader) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(loader, script, string);
|
||||
|
||||
// This cannot fail because resolving a module specifier must have been
|
||||
// previously successful with these same two arguments.
|
||||
@ -744,19 +818,20 @@ JSObject* HostResolveImportedModule(JSContext* aCx,
|
||||
|
||||
// Let resolved module script be moduleMap[url]. (This entry must exist for us
|
||||
// to have gotten to this point.)
|
||||
ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
|
||||
ModuleScript* ms = loader->GetFetchedModule(uri);
|
||||
MOZ_ASSERT(ms, "Resolved module not found in module map");
|
||||
|
||||
MOZ_ASSERT(!ms->HasParseError());
|
||||
MOZ_ASSERT(ms->ModuleRecord());
|
||||
|
||||
return ms->ModuleRecord();
|
||||
aModuleOut.set(ms->ModuleRecord());
|
||||
}
|
||||
|
||||
bool HostPopulateImportMeta(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSObject*> aMetaObject) {
|
||||
auto script = static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
|
||||
RefPtr<ModuleScript> script =
|
||||
static_cast<ModuleScript*>(aReferencingPrivate.toPrivate());
|
||||
MOZ_ASSERT(script->IsModuleScript());
|
||||
MOZ_ASSERT(JS::GetModulePrivate(script->ModuleRecord()) ==
|
||||
aReferencingPrivate);
|
||||
|
||||
@ -774,14 +849,128 @@ bool HostPopulateImportMeta(JSContext* aCx,
|
||||
JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
static void EnsureModuleResolveHook(JSContext* aCx) {
|
||||
JSRuntime* rt = JS_GetRuntime(aCx);
|
||||
bool HostImportModuleDynamically(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSString*> aSpecifier,
|
||||
JS::Handle<JSObject*> aPromise) {
|
||||
RefPtr<LoadedScript> script(GetLoadedScriptOrNull(aCx, aReferencingPrivate));
|
||||
|
||||
// Attempt to resolve the module specifier.
|
||||
nsAutoJSString string;
|
||||
if (!string.init(aCx, aSpecifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<ScriptLoader> loader = GetCurrentScriptLoader(aCx);
|
||||
if (!loader) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(loader, script, string);
|
||||
if (!uri) {
|
||||
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
|
||||
JSMSG_BAD_MODULE_SPECIFIER, string.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new top-level load request.
|
||||
ScriptFetchOptions* options;
|
||||
nsIURI* baseURL;
|
||||
if (script) {
|
||||
options = script->FetchOptions();
|
||||
baseURL = script->BaseURL();
|
||||
} else {
|
||||
// We don't have a referencing script so fall back on using
|
||||
// options from the document. This can happen when the user
|
||||
// triggers an inline event handler, as there is no active script
|
||||
// there.
|
||||
nsIDocument* document = loader->GetDocument();
|
||||
options = new ScriptFetchOptions(mozilla::CORS_NONE,
|
||||
document->GetReferrerPolicy(), nullptr,
|
||||
document->NodePrincipal());
|
||||
baseURL = document->GetDocBaseURI();
|
||||
}
|
||||
|
||||
RefPtr<ModuleLoadRequest> request = ModuleLoadRequest::CreateDynamicImport(
|
||||
uri, options, baseURL, loader, aReferencingPrivate, aSpecifier, aPromise);
|
||||
|
||||
loader->StartDynamicImport(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptLoader::StartDynamicImport(ModuleLoadRequest* aRequest) {
|
||||
LOG(("ScriptLoadRequest (%p): Start dynamic import", aRequest));
|
||||
|
||||
mDynamicImportRequests.AppendElement(aRequest);
|
||||
|
||||
nsresult rv = StartLoad(aRequest);
|
||||
if (NS_FAILED(rv)) {
|
||||
FinishDynamicImport(aRequest, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptLoader::FinishDynamicImport(ModuleLoadRequest* aRequest,
|
||||
nsresult aResult) {
|
||||
AutoJSAPI jsapi;
|
||||
MOZ_ALWAYS_TRUE(jsapi.Init(aRequest->mDynamicPromise));
|
||||
FinishDynamicImport(jsapi.cx(), aRequest, aResult);
|
||||
}
|
||||
|
||||
void ScriptLoader::FinishDynamicImport(JSContext* aCx,
|
||||
ModuleLoadRequest* aRequest,
|
||||
nsresult aResult) {
|
||||
LOG(("ScriptLoadRequest (%p): Finish dynamic import %x %d", aRequest,
|
||||
unsigned(aResult), JS_IsExceptionPending(aCx)));
|
||||
|
||||
// Complete the dynamic import, report failures indicated by aResult or as a
|
||||
// pending exception on the context.
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
||||
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
|
||||
JSMSG_DYNAMIC_IMPORT_FAILED);
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> referencingScript(aCx,
|
||||
aRequest->mDynamicReferencingPrivate);
|
||||
JS::Rooted<JSString*> specifier(aCx, aRequest->mDynamicSpecifier);
|
||||
JS::Rooted<JSObject*> promise(aCx, aRequest->mDynamicPromise);
|
||||
|
||||
JS::FinishDynamicModuleImport(aCx, referencingScript, specifier, promise);
|
||||
|
||||
// FinishDynamicModuleImport clears any pending exception.
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
|
||||
|
||||
aRequest->ClearDynamicImport();
|
||||
}
|
||||
|
||||
static void DynamicImportPrefChangedCallback(const char* aPrefName,
|
||||
void* aClosure) {
|
||||
bool enabled = Preferences::GetBool(aPrefName);
|
||||
JS::ModuleDynamicImportHook hook =
|
||||
enabled ? HostImportModuleDynamically : nullptr;
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
|
||||
JS::SetModuleDynamicImportHook(rt, hook);
|
||||
}
|
||||
|
||||
void ScriptLoader::EnsureModuleHooksInitialized() {
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSRuntime* rt = JS_GetRuntime(jsapi.cx());
|
||||
if (JS::GetModuleResolveHook(rt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::SetModuleResolveHook(rt, HostResolveImportedModule);
|
||||
JS::SetModuleMetadataHook(rt, HostPopulateImportMeta);
|
||||
JS::SetScriptPrivateFinalizeHook(rt, HostFinalizeTopLevelScript);
|
||||
|
||||
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
|
||||
"javascript.options.dynamicImport",
|
||||
(void*)nullptr);
|
||||
}
|
||||
|
||||
void ScriptLoader::CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest) {
|
||||
@ -815,18 +1004,34 @@ class ScriptRequestProcessor : public Runnable {
|
||||
: Runnable("dom::ScriptRequestProcessor"),
|
||||
mLoader(aLoader),
|
||||
mRequest(aRequest) {}
|
||||
NS_IMETHOD Run() override { return mLoader->ProcessRequest(mRequest); }
|
||||
NS_IMETHOD Run() override {
|
||||
if (mRequest->IsModuleRequest() &&
|
||||
mRequest->AsModuleRequest()->IsDynamicImport()) {
|
||||
mLoader->ProcessDynamicImport(mRequest->AsModuleRequest());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mLoader->ProcessRequest(mRequest);
|
||||
}
|
||||
};
|
||||
|
||||
void ScriptLoader::RunScriptWhenSafe(ScriptLoadRequest* aRequest) {
|
||||
auto runnable = new ScriptRequestProcessor(this, aRequest);
|
||||
nsContentUtils::AddScriptRunner(runnable);
|
||||
}
|
||||
|
||||
void ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) {
|
||||
MOZ_ASSERT(aRequest->IsReadyToRun());
|
||||
|
||||
if (aRequest->IsTopLevel()) {
|
||||
if (aRequest->mIsInline &&
|
||||
aRequest->Element()->GetParserCreated() == NOT_FROM_PARSER) {
|
||||
if (aRequest->IsDynamicImport()) {
|
||||
MOZ_ASSERT(aRequest->isInList());
|
||||
RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
|
||||
RunScriptWhenSafe(req);
|
||||
} else if (aRequest->mIsInline &&
|
||||
aRequest->GetParserCreated() == NOT_FROM_PARSER) {
|
||||
MOZ_ASSERT(!aRequest->isInList());
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new ScriptRequestProcessor(this, aRequest));
|
||||
RunScriptWhenSafe(aRequest);
|
||||
} else {
|
||||
MaybeMoveToLoadedList(aRequest);
|
||||
ProcessPendingRequests();
|
||||
@ -884,8 +1089,6 @@ bool ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureModuleResolveHook(jsapi.cx());
|
||||
|
||||
JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
|
||||
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
|
||||
|
||||
@ -924,10 +1127,12 @@ nsresult ScriptLoader::AssociateSourceElementsForModuleTree(
|
||||
JS::Rooted<JSObject*> module(aCx, moduleScript->ModuleRecord());
|
||||
MOZ_ASSERT(module);
|
||||
|
||||
nsresult rv =
|
||||
nsJSUtils::InitModuleSourceElement(aCx, module, aRequest->Element());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
moduleScript->SetSourceElementAssociated();
|
||||
nsIScriptElement* element = aRequest->Element();
|
||||
if (element) {
|
||||
nsresult rv = nsJSUtils::InitModuleSourceElement(aCx, module, element);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
moduleScript->SetSourceElementAssociated();
|
||||
}
|
||||
|
||||
// The script is now ready to be exposed to the debugger.
|
||||
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(module));
|
||||
@ -1210,7 +1415,8 @@ ScriptLoadRequest* ScriptLoader::CreateLoadRequest(
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aKind == ScriptKind::eModule);
|
||||
return new ModuleLoadRequest(aURI, fetchOptions, aIntegrity, referrer, this);
|
||||
return ModuleLoadRequest::CreateTopLevel(aURI, fetchOptions, aIntegrity,
|
||||
referrer, this);
|
||||
}
|
||||
|
||||
bool ScriptLoader::ProcessScriptElement(nsIScriptElement* aElement) {
|
||||
@ -1505,10 +1711,10 @@ bool ScriptLoader::ProcessInlineScript(nsIScriptElement* aElement,
|
||||
LOG(("ScriptLoadRequest (%p): Created request for inline script",
|
||||
request.get()));
|
||||
|
||||
request->mBaseURL = mDocument->GetDocBaseURI();
|
||||
|
||||
if (request->IsModuleRequest()) {
|
||||
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
||||
modReq->mBaseURL = mDocument->GetDocBaseURI();
|
||||
|
||||
if (aElement->GetParserCreated() != NOT_FROM_PARSER) {
|
||||
if (aElement->GetScriptAsync()) {
|
||||
AddAsyncRequest(modReq);
|
||||
@ -1538,7 +1744,7 @@ bool ScriptLoader::ProcessInlineScript(nsIScriptElement* aElement,
|
||||
NS_ASSERTION(
|
||||
!nsContentUtils::IsSafeToRunScript(),
|
||||
"A script-inserted script is inserted without an update batch?");
|
||||
nsContentUtils::AddScriptRunner(new ScriptRequestProcessor(this, request));
|
||||
RunScriptWhenSafe(request);
|
||||
return false;
|
||||
}
|
||||
if (aElement->GetParserCreated() == FROM_PARSER_NETWORK &&
|
||||
@ -1576,7 +1782,7 @@ ScriptLoadRequest* ScriptLoader::LookupPreloadRequest(
|
||||
// Found preloaded request. Note that a script-inserted script can steal a
|
||||
// preload!
|
||||
RefPtr<ScriptLoadRequest> request = mPreloads[i].mRequest;
|
||||
request->SetElement(aElement);
|
||||
request->SetIsLoadRequest(aElement);
|
||||
nsString preloadCharset(mPreloads[i].mCharset);
|
||||
mPreloads.RemoveElementAt(i);
|
||||
|
||||
@ -1915,8 +2121,7 @@ nsresult ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) {
|
||||
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||
if (request->mModuleScript &&
|
||||
!request->mModuleScript->HasErrorToRethrow()) {
|
||||
if (request->mModuleScript) {
|
||||
if (!InstantiateModuleTree(request)) {
|
||||
request->mModuleScript = nullptr;
|
||||
}
|
||||
@ -1939,7 +2144,7 @@ nsresult ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) {
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptElement> oldParserInsertedScript;
|
||||
uint32_t parserCreated = aRequest->Element()->GetParserCreated();
|
||||
uint32_t parserCreated = aRequest->GetParserCreated();
|
||||
if (parserCreated) {
|
||||
oldParserInsertedScript = mCurrentParserInsertedScript;
|
||||
mCurrentParserInsertedScript = aRequest->Element();
|
||||
@ -2018,6 +2223,25 @@ nsresult ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
void ScriptLoader::ProcessDynamicImport(ModuleLoadRequest* aRequest) {
|
||||
if (aRequest->mModuleScript) {
|
||||
if (!InstantiateModuleTree(aRequest)) {
|
||||
aRequest->mModuleScript = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (aRequest->mModuleScript) {
|
||||
rv = EvaluateScript(aRequest);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
FinishDynamicImport(aRequest, rv);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ScriptLoader::FireScriptAvailable(nsresult aResult,
|
||||
ScriptLoadRequest* aRequest) {
|
||||
for (int32_t i = 0; i < mObservers.Count(); i++) {
|
||||
@ -2062,7 +2286,7 @@ already_AddRefed<nsIScriptGlobalObject> ScriptLoader::GetScriptGlobalObject() {
|
||||
}
|
||||
|
||||
nsresult ScriptLoader::FillCompileOptionsForRequest(
|
||||
const AutoJSAPI& jsapi, ScriptLoadRequest* aRequest,
|
||||
const mozilla::dom::AutoJSAPI& jsapi, ScriptLoadRequest* aRequest,
|
||||
JS::Handle<JSObject*> aScopeChain, JS::CompileOptions* aOptions) {
|
||||
// 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.
|
||||
@ -2203,6 +2427,32 @@ nsresult ScriptLoader::FillCompileOptionsForRequest(
|
||||
return true;
|
||||
}
|
||||
|
||||
class MOZ_RAII AutoSetProcessingScriptTag {
|
||||
nsCOMPtr<nsIScriptContext> mContext;
|
||||
bool mOldTag;
|
||||
|
||||
public:
|
||||
explicit AutoSetProcessingScriptTag(nsIScriptContext* aContext)
|
||||
: mContext(aContext), mOldTag(mContext->GetProcessingScriptTag()) {
|
||||
mContext->SetProcessingScriptTag(true);
|
||||
}
|
||||
|
||||
~AutoSetProcessingScriptTag() { mContext->SetProcessingScriptTag(mOldTag); }
|
||||
};
|
||||
|
||||
static nsresult ExecuteCompiledScript(JSContext* aCx,
|
||||
ScriptLoadRequest* aRequest,
|
||||
nsJSUtils::ExecutionContext& aExec) {
|
||||
JS::Rooted<JSScript*> script(aCx, aExec.GetScript());
|
||||
|
||||
// Create a ClassicScript object and associate it with the JSScript.
|
||||
RefPtr<ClassicScript> classicScript = new ClassicScript(
|
||||
aRequest->mFetchOptions, aRequest->mBaseURL);
|
||||
classicScript->AssociateWithScript(script);
|
||||
|
||||
return aExec.ExecScript();
|
||||
}
|
||||
|
||||
nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
using namespace mozilla::Telemetry;
|
||||
MOZ_ASSERT(aRequest->IsReadyToRun());
|
||||
@ -2212,16 +2462,18 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->Element()));
|
||||
nsIDocument* ownerDoc = scriptContent->OwnerDoc();
|
||||
if (ownerDoc != mDocument) {
|
||||
// Willful violation of HTML5 as of 2010-12-01
|
||||
return NS_ERROR_FAILURE;
|
||||
bool isDynamicImport = aRequest->IsModuleRequest() &&
|
||||
aRequest->AsModuleRequest()->IsDynamicImport();
|
||||
if (!isDynamicImport) {
|
||||
nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->Element()));
|
||||
MOZ_ASSERT(scriptContent);
|
||||
nsIDocument* ownerDoc = scriptContent->OwnerDoc();
|
||||
if (ownerDoc != mDocument) {
|
||||
// Willful violation of HTML5 as of 2010-12-01
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the script-type to be used by this element.
|
||||
NS_ASSERTION(scriptContent, "no content - what is default script-type?");
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObject = GetScriptGlobalObject();
|
||||
if (!globalObject) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -2242,8 +2494,8 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
|
||||
context->SetProcessingScriptTag(true);
|
||||
AutoSetProcessingScriptTag setProcessingScriptTag(context);
|
||||
|
||||
nsresult rv;
|
||||
{
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
@ -2255,8 +2507,6 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
// currentScript is set to null for modules.
|
||||
AutoCurrentScriptUpdater scriptUpdater(this, nullptr);
|
||||
|
||||
EnsureModuleResolveHook(cx);
|
||||
|
||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||
MOZ_ASSERT(request->mModuleScript);
|
||||
MOZ_ASSERT(!request->mOffThreadToken);
|
||||
@ -2267,7 +2517,13 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
aRequest));
|
||||
JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow());
|
||||
JS_SetPendingException(cx, error);
|
||||
return NS_OK; // An error is reported by AutoEntryScript.
|
||||
|
||||
// For a dynamic import, the promise is rejected. Otherwise an error is
|
||||
// either reported by AutoEntryScript.
|
||||
if (request->IsDynamicImport()) {
|
||||
FinishDynamicImport(cx, request, NS_OK);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
|
||||
@ -2280,9 +2536,16 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
|
||||
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest));
|
||||
rv = NS_OK; // An error is reported by AutoEntryScript.
|
||||
// For a dynamic import, the promise is rejected. Otherwise an error is
|
||||
// either reported by AutoEntryScript.
|
||||
rv = NS_OK;
|
||||
}
|
||||
|
||||
if (request->IsDynamicImport()) {
|
||||
FinishDynamicImport(cx, request, rv);
|
||||
}
|
||||
|
||||
aRequest->mCacheInfo = nullptr;
|
||||
@ -2300,13 +2563,18 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
if (aRequest->mOffThreadToken) {
|
||||
LOG(("ScriptLoadRequest (%p): Decode Bytecode & Join and Execute",
|
||||
aRequest));
|
||||
rv = exec.DecodeJoinAndExec(&aRequest->mOffThreadToken);
|
||||
rv = exec.JoinDecode(&aRequest->mOffThreadToken);
|
||||
} else {
|
||||
LOG(("ScriptLoadRequest (%p): Decode Bytecode and Execute",
|
||||
aRequest));
|
||||
rv = exec.DecodeAndExec(options, aRequest->mScriptBytecode,
|
||||
aRequest->mBytecodeOffset);
|
||||
rv = exec.Decode(options, aRequest->mScriptBytecode,
|
||||
aRequest->mBytecodeOffset);
|
||||
}
|
||||
|
||||
if (rv == NS_OK) {
|
||||
rv = ExecuteCompiledScript(cx, aRequest, exec);
|
||||
}
|
||||
|
||||
// We do not expect to be saving anything when we already have some
|
||||
// bytecode.
|
||||
MOZ_ASSERT(!aRequest->mCacheInfo);
|
||||
@ -2326,36 +2594,39 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
"Execute",
|
||||
aRequest));
|
||||
if (aRequest->IsBinASTSource()) {
|
||||
rv = exec.DecodeBinASTJoinAndExec(&aRequest->mOffThreadToken,
|
||||
&script);
|
||||
rv = exec.JoinDecodeBinAST(&aRequest->mOffThreadToken);
|
||||
} else {
|
||||
MOZ_ASSERT(aRequest->IsTextSource());
|
||||
rv = exec.JoinAndExec(&aRequest->mOffThreadToken, &script);
|
||||
rv = exec.JoinCompile(&aRequest->mOffThreadToken);
|
||||
}
|
||||
} else {
|
||||
// Main thread parsing (inline and small scripts)
|
||||
LOG(("ScriptLoadRequest (%p): Compile And Exec", aRequest));
|
||||
if (aRequest->IsBinASTSource()) {
|
||||
rv = exec.DecodeBinASTAndExec(
|
||||
options, aRequest->ScriptBinASTData().begin(),
|
||||
aRequest->ScriptBinASTData().length(), &script);
|
||||
rv = exec.DecodeBinAST(options,
|
||||
aRequest->ScriptBinASTData().begin(),
|
||||
aRequest->ScriptBinASTData().length());
|
||||
} else {
|
||||
MOZ_ASSERT(aRequest->IsTextSource());
|
||||
auto srcBuf = GetScriptSource(cx, aRequest);
|
||||
|
||||
if (srcBuf) {
|
||||
rv = exec.CompileAndExec(options, *srcBuf, &script);
|
||||
rv = exec.Compile(options, *srcBuf);
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == NS_OK) {
|
||||
script = exec.GetScript();
|
||||
rv = ExecuteCompiledScript(cx, aRequest, exec);
|
||||
}
|
||||
}
|
||||
|
||||
// Queue the current script load request to later save the bytecode.
|
||||
if (script && encodeBytecode) {
|
||||
aRequest->mScript = script;
|
||||
HoldJSObjects(aRequest);
|
||||
aRequest->SetScript(script);
|
||||
TRACE_FOR_TEST(aRequest->Element(), "scriptloader_encode");
|
||||
MOZ_ASSERT(aRequest->mBytecodeOffset ==
|
||||
aRequest->mScriptBytecode.length());
|
||||
@ -2379,10 +2650,18 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
|
||||
MaybeTriggerBytecodeEncoding();
|
||||
}
|
||||
|
||||
context->SetProcessingScriptTag(oldProcessingScriptTag);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */ LoadedScript* ScriptLoader::GetActiveScript(JSContext* aCx) {
|
||||
JS::Value value = JS::GetScriptedCallerPrivate(aCx);
|
||||
if (value.isUndefined()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return static_cast<LoadedScript*>(value.toPrivate());
|
||||
}
|
||||
|
||||
void ScriptLoader::RegisterForBytecodeEncoding(ScriptLoadRequest* aRequest) {
|
||||
MOZ_ASSERT(aRequest->mCacheInfo);
|
||||
MOZ_ASSERT(aRequest->mScript);
|
||||
@ -2567,7 +2846,8 @@ bool ScriptLoader::HasPendingRequests() {
|
||||
return mParserBlockingRequest || !mXSLTRequests.isEmpty() ||
|
||||
!mLoadedAsyncRequests.isEmpty() ||
|
||||
!mNonAsyncExternalScriptInsertedRequests.isEmpty() ||
|
||||
!mDeferRequests.isEmpty() || !mPendingChildLoaders.IsEmpty();
|
||||
!mDeferRequests.isEmpty() || !mDynamicImportRequests.isEmpty() ||
|
||||
!mPendingChildLoaders.IsEmpty();
|
||||
}
|
||||
|
||||
void ScriptLoader::ProcessPendingRequestsAsync() {
|
||||
@ -2909,7 +3189,7 @@ void ScriptLoader::ReportErrorToConsole(ScriptLoadRequest* aRequest,
|
||||
nsresult aResult) const {
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
if (!aRequest->Element()) {
|
||||
if (aRequest->IsPreload()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2929,8 +3209,9 @@ void ScriptLoader::ReportErrorToConsole(ScriptLoadRequest* aRequest,
|
||||
NS_ConvertUTF8toUTF16 url(aRequest->mURI->GetSpecOrDefault());
|
||||
const char16_t* params[] = {url.get()};
|
||||
|
||||
uint32_t lineNo = aRequest->Element()->GetScriptLineNumber();
|
||||
uint32_t columnNo = aRequest->Element()->GetScriptColumnNumber();
|
||||
nsIScriptElement* element = aRequest->Element();
|
||||
uint32_t lineNo = element ? element->GetScriptLineNumber() : 0;
|
||||
uint32_t columnNo = element ? element->GetScriptColumnNumber() : 0;
|
||||
|
||||
nsContentUtils::ReportToConsole(
|
||||
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Script Loader"),
|
||||
@ -2980,12 +3261,31 @@ void ScriptLoader::HandleLoadError(ScriptLoadRequest* aRequest,
|
||||
RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(aRequest);
|
||||
FireScriptAvailable(aResult, req);
|
||||
}
|
||||
} else if (aRequest->IsModuleRequest() && !aRequest->IsPreload()) {
|
||||
} else if (aRequest->IsPreload()) {
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
aRequest->Cancel();
|
||||
}
|
||||
if (aRequest->IsTopLevel()) {
|
||||
MOZ_ALWAYS_TRUE(
|
||||
mPreloads.RemoveElement(aRequest, PreloadRequestComparator()));
|
||||
}
|
||||
MOZ_ASSERT(!aRequest->isInList());
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::LoadError);
|
||||
} else if (aRequest->IsModuleRequest()) {
|
||||
ModuleLoadRequest* modReq = aRequest->AsModuleRequest();
|
||||
MOZ_ASSERT(!modReq->IsTopLevel());
|
||||
MOZ_ASSERT(!modReq->isInList());
|
||||
modReq->Cancel();
|
||||
// A single error is fired for the top level module.
|
||||
if (modReq->IsDynamicImport()) {
|
||||
MOZ_ASSERT(modReq->IsTopLevel());
|
||||
if (aRequest->isInList()) {
|
||||
RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
|
||||
modReq->Cancel();
|
||||
FinishDynamicImport(modReq, aResult);
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(!modReq->IsTopLevel());
|
||||
MOZ_ASSERT(!modReq->isInList());
|
||||
modReq->Cancel();
|
||||
// The error is handled for the top level module.
|
||||
}
|
||||
} else if (mParserBlockingRequest == aRequest) {
|
||||
MOZ_ASSERT(!aRequest->isInList());
|
||||
mParserBlockingRequest = nullptr;
|
||||
@ -3000,16 +3300,6 @@ void ScriptLoader::HandleLoadError(ScriptLoadRequest* aRequest,
|
||||
FireScriptAvailable(aResult, aRequest);
|
||||
ContinueParserAsync(aRequest);
|
||||
mCurrentParserInsertedScript = oldParserInsertedScript;
|
||||
} else if (aRequest->IsPreload()) {
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
aRequest->Cancel();
|
||||
}
|
||||
if (aRequest->IsTopLevel()) {
|
||||
MOZ_ALWAYS_TRUE(
|
||||
mPreloads.RemoveElement(aRequest, PreloadRequestComparator()));
|
||||
}
|
||||
MOZ_ASSERT(!aRequest->isInList());
|
||||
AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::LoadError);
|
||||
} else {
|
||||
// This happens for blocking requests cancelled by ParsingComplete().
|
||||
MOZ_ASSERT(aRequest->IsCanceled());
|
||||
@ -3110,13 +3400,26 @@ nsresult ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
||||
mLoadingAsyncRequests.Contains(aRequest) ||
|
||||
mNonAsyncExternalScriptInsertedRequests.Contains(aRequest) ||
|
||||
mXSLTRequests.Contains(aRequest) ||
|
||||
mDynamicImportRequests.Contains(aRequest) ||
|
||||
(aRequest->IsModuleRequest() &&
|
||||
!aRequest->AsModuleRequest()->IsTopLevel() &&
|
||||
!aRequest->isInList()) ||
|
||||
mPreloads.Contains(aRequest, PreloadRequestComparator()) ||
|
||||
mParserBlockingRequest,
|
||||
mParserBlockingRequest == aRequest,
|
||||
"aRequest should be pending!");
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = channel->GetOriginalURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Fixup moz-extension: and resource: URIs, because the channel URI will
|
||||
// point to file:, which won't be allowed to load.
|
||||
if (uri && IsInternalURIScheme(uri)) {
|
||||
aRequest->mBaseURL = uri;
|
||||
} else {
|
||||
channel->GetURI(getter_AddRefs(aRequest->mBaseURL));
|
||||
}
|
||||
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
MOZ_ASSERT(aRequest->IsSource());
|
||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||
@ -3130,18 +3433,6 @@ nsresult ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = channel->GetOriginalURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Fixup moz-extension: and resource: URIs, because the channel URI will
|
||||
// point to file:, which won't be allowed to load.
|
||||
if (uri && IsInternalURIScheme(uri)) {
|
||||
request->mBaseURL = uri;
|
||||
} else {
|
||||
channel->GetURI(getter_AddRefs(request->mBaseURL));
|
||||
}
|
||||
|
||||
// Attempt to compile off main thread.
|
||||
bool couldCompile = false;
|
||||
rv = AttemptAsyncScriptCompile(request, &couldCompile);
|
||||
@ -3191,6 +3482,13 @@ void ScriptLoader::ParsingComplete(bool aTerminated) {
|
||||
mLoadedAsyncRequests.Clear();
|
||||
mNonAsyncExternalScriptInsertedRequests.Clear();
|
||||
mXSLTRequests.Clear();
|
||||
|
||||
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
|
||||
req = req->getNext()) {
|
||||
req->Cancel();
|
||||
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
if (mParserBlockingRequest) {
|
||||
mParserBlockingRequest->Cancel();
|
||||
mParserBlockingRequest = nullptr;
|
||||
@ -3245,6 +3543,7 @@ void ScriptLoader::PreloadURI(
|
||||
request->mIsInline = false;
|
||||
request->mScriptFromHead = aScriptFromHead;
|
||||
request->SetScriptMode(aDefer, aAsync);
|
||||
request->SetIsPreloadRequest();
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsAutoCString url;
|
||||
|
@ -42,6 +42,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AutoJSAPI;
|
||||
class LoadedScript;
|
||||
class ModuleLoadRequest;
|
||||
class ModuleScript;
|
||||
class ScriptLoadHandler;
|
||||
@ -310,9 +311,41 @@ class ScriptLoader final : public nsISupports {
|
||||
*/
|
||||
void Destroy() { GiveUpBytecodeEncoding(); }
|
||||
|
||||
/**
|
||||
* Implement the HostResolveImportedModule abstract operation.
|
||||
*
|
||||
* Resolve a module specifier string and look this up in the module
|
||||
* map, returning the result. This is only called for previously
|
||||
* loaded modules and always succeeds.
|
||||
*
|
||||
* @param aReferencingPrivate A JS::Value which is either undefined
|
||||
* or contains a LoadedScript private pointer.
|
||||
* @param aSpecifier The module specifier.
|
||||
* @param aModuleOut This is set to the module found.
|
||||
*/
|
||||
static void ResolveImportedModule(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aReferencingPrivate,
|
||||
JS::Handle<JSString*> aSpecifier,
|
||||
JS::MutableHandle<JSObject*> aModuleOut);
|
||||
|
||||
void StartDynamicImport(ModuleLoadRequest* aRequest);
|
||||
void FinishDynamicImport(ModuleLoadRequest* aRequest, nsresult aResult);
|
||||
void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest,
|
||||
nsresult aResult);
|
||||
|
||||
/*
|
||||
* Get the currently active script. This is used as the initiating script when
|
||||
* executing timeout handler scripts.
|
||||
*/
|
||||
static LoadedScript* GetActiveScript(JSContext* aCx);
|
||||
|
||||
nsIDocument* GetDocument() const { return mDocument; }
|
||||
|
||||
private:
|
||||
virtual ~ScriptLoader();
|
||||
|
||||
void EnsureModuleHooksInitialized();
|
||||
|
||||
ScriptLoadRequest* CreateLoadRequest(
|
||||
ScriptKind aKind, nsIURI* aURI, nsIScriptElement* aElement,
|
||||
nsIPrincipal* aTriggeringPrincipal, mozilla::CORSMode aCORSMode,
|
||||
@ -419,6 +452,7 @@ class ScriptLoader final : public nsISupports {
|
||||
nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
|
||||
bool* aCouldCompileOut);
|
||||
nsresult ProcessRequest(ScriptLoadRequest* aRequest);
|
||||
void ProcessDynamicImport(ModuleLoadRequest* aRequest);
|
||||
nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
|
||||
void FireScriptAvailable(nsresult aResult, ScriptLoadRequest* aRequest);
|
||||
void FireScriptEvaluated(nsresult aResult, ScriptLoadRequest* aRequest);
|
||||
@ -500,6 +534,8 @@ class ScriptLoader final : public nsISupports {
|
||||
nsresult AssociateSourceElementsForModuleTree(JSContext* aCx,
|
||||
ModuleLoadRequest* aRequest);
|
||||
|
||||
void RunScriptWhenSafe(ScriptLoadRequest* aRequest);
|
||||
|
||||
nsIDocument* mDocument; // [WEAK]
|
||||
nsCOMArray<nsIScriptLoaderObserver> mObservers;
|
||||
ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
|
||||
@ -509,6 +545,7 @@ class ScriptLoader final : public nsISupports {
|
||||
ScriptLoadRequestList mLoadedAsyncRequests;
|
||||
ScriptLoadRequestList mDeferRequests;
|
||||
ScriptLoadRequestList mXSLTRequests;
|
||||
ScriptLoadRequestList mDynamicImportRequests;
|
||||
RefPtr<ScriptLoadRequest> mParserBlockingRequest;
|
||||
|
||||
// List of script load request that are holding a buffer which has to be saved
|
||||
@ -560,6 +597,7 @@ class ScriptLoader final : public nsISupports {
|
||||
nsCOMPtr<nsIConsoleReportCollector> mReporter;
|
||||
|
||||
// Logging
|
||||
public:
|
||||
static LazyLogModule gCspPRLog;
|
||||
static LazyLogModule gScriptLoaderLog;
|
||||
};
|
||||
|
@ -18,6 +18,7 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'LoadedScript.h',
|
||||
'ScriptElement.h',
|
||||
'ScriptLoader.h',
|
||||
'ScriptLoadRequest.h',
|
||||
@ -25,8 +26,8 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'LoadedScript.cpp',
|
||||
'ModuleLoadRequest.cpp',
|
||||
'ModuleScript.cpp',
|
||||
'ScriptElement.cpp',
|
||||
'ScriptLoader.cpp',
|
||||
'ScriptLoadHandler.cpp',
|
||||
|
@ -415,9 +415,8 @@ nsresult nsXBLProtoImplField::InstallField(
|
||||
{
|
||||
nsJSUtils::ExecutionContext exec(cx, scopeObject);
|
||||
exec.SetScopeChain(scopeChain);
|
||||
exec.CompileAndExec(options,
|
||||
nsDependentString(mFieldText, mFieldTextLength));
|
||||
rv = exec.ExtractReturnValue(&result);
|
||||
exec.Compile(options, nsDependentString(mFieldText, mFieldTextLength));
|
||||
rv = exec.ExecScript(&result);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -625,6 +625,11 @@ struct ImplicitEdgeHolderType<JSScript*> {
|
||||
typedef JSScript* Type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ImplicitEdgeHolderType<LazyScript*> {
|
||||
typedef LazyScript* Type;
|
||||
};
|
||||
|
||||
void GCMarker::markEphemeronValues(gc::Cell* markedCell,
|
||||
WeakEntryVector& values) {
|
||||
DebugOnly<size_t> initialLen = values.length();
|
||||
@ -838,6 +843,7 @@ void GCMarker::traverse(JSString* thing) {
|
||||
template <>
|
||||
void GCMarker::traverse(LazyScript* thing) {
|
||||
markAndScan(thing);
|
||||
markImplicitEdges(thing);
|
||||
}
|
||||
template <>
|
||||
void GCMarker::traverse(Shape* thing) {
|
||||
|
13
js/src/jit-test/tests/gc/bug-1515993.js
Normal file
13
js/src/jit-test/tests/gc/bug-1515993.js
Normal file
@ -0,0 +1,13 @@
|
||||
function checkGetOffsetsCoverage() {
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var topLevel;
|
||||
dbg.onNewScript = function(s) {
|
||||
topLevel = s;
|
||||
};
|
||||
g.eval(`import(() => 1)`);
|
||||
topLevel.getChildScripts();
|
||||
}
|
||||
checkGetOffsetsCoverage();
|
||||
gczeal(14, 10);
|
||||
Object.defineProperty(this, "fuzzutils", {});
|
@ -619,7 +619,8 @@ MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found f
|
||||
MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found")
|
||||
MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status")
|
||||
MSG_DEF(JSMSG_NO_DYNAMIC_IMPORT, 0, JSEXN_SYNTAXERR, "dynamic module import is not implemented")
|
||||
MSG_DEF(JSMSG_IMPORT_SCRIPT_NOT_FOUND, 0, JSEXN_TYPEERR, "can't find referencing script for dynamic module import")
|
||||
MSG_DEF(JSMSG_DYNAMIC_IMPORT_FAILED, 0, JSEXN_TYPEERR, "error loading dynamically imported module")
|
||||
MSG_DEF(JSMSG_BAD_MODULE_SPECIFIER, 1, JSEXN_TYPEERR, "error resolving module specifier '{0}'")
|
||||
|
||||
// Promise
|
||||
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
||||
|
@ -3740,7 +3740,7 @@ JS_PUBLIC_API void JS::SetModulePrivate(JSObject* module,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::Value JS::GetModulePrivate(JSObject* module) {
|
||||
return module->as<ModuleObject>().scriptSourceObject()->unwrappedPrivate();
|
||||
return module->as<ModuleObject>().scriptSourceObject()->canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
|
||||
@ -3749,7 +3749,31 @@ JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script,
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) {
|
||||
return script->sourceObject()->unwrappedPrivate();
|
||||
return script->sourceObject()->canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::Value JS::GetScriptedCallerPrivate(JSContext* cx) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
|
||||
NonBuiltinFrameIter iter(cx, cx->realm()->principals());
|
||||
if (iter.done() || !iter.hasScript()) {
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
return FindScriptOrModulePrivateForScript(iter.script());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::ScriptPrivateFinalizeHook JS::GetScriptPrivateFinalizeHook(
|
||||
JSRuntime* rt) {
|
||||
AssertHeapIsIdle();
|
||||
return rt->scriptPrivateFinalizeHook;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS::SetScriptPrivateFinalizeHook(
|
||||
JSRuntime* rt, JS::ScriptPrivateFinalizeHook func) {
|
||||
AssertHeapIsIdle();
|
||||
rt->scriptPrivateFinalizeHook = func;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS::ModuleInstantiate(JSContext* cx,
|
||||
|
@ -3104,13 +3104,17 @@ using ModuleDynamicImportHook = bool (*)(JSContext* cx,
|
||||
HandleObject promise);
|
||||
|
||||
/**
|
||||
* Get the HostResolveImportedModule hook for the runtime.
|
||||
* Get the HostImportModuleDynamically hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API ModuleDynamicImportHook
|
||||
GetModuleDynamicImportHook(JSRuntime* rt);
|
||||
|
||||
/**
|
||||
* Set the HostResolveImportedModule hook for the runtime to the given function.
|
||||
* Set the HostImportModuleDynamically hook for the runtime to the given
|
||||
* function.
|
||||
*
|
||||
* If this hook is not set (or set to nullptr) then the JS engine will throw an
|
||||
* exception if dynamic module import is attempted.
|
||||
*/
|
||||
extern JS_PUBLIC_API void SetModuleDynamicImportHook(
|
||||
JSRuntime* rt, ModuleDynamicImportHook func);
|
||||
@ -3152,6 +3156,32 @@ extern JS_PUBLIC_API void SetScriptPrivate(JSScript* script,
|
||||
*/
|
||||
extern JS_PUBLIC_API JS::Value GetScriptPrivate(JSScript* script);
|
||||
|
||||
/*
|
||||
* Return the private value associated with currently executing script or
|
||||
* module, or undefined if there is no such script.
|
||||
*/
|
||||
extern JS_PUBLIC_API JS::Value GetScriptedCallerPrivate(JSContext* cx);
|
||||
|
||||
/**
|
||||
* A hook that's called whenever a script or module which has a private value
|
||||
* set with SetScriptPrivate() or SetModulePrivate() is finalized. This can be
|
||||
* used to clean up the private state. The private value is passed as an
|
||||
* argument.
|
||||
*/
|
||||
using ScriptPrivateFinalizeHook = void (*)(JSFreeOp*, const JS::Value&);
|
||||
|
||||
/**
|
||||
* Get the script private finalize hook for the runtime.
|
||||
*/
|
||||
extern JS_PUBLIC_API ScriptPrivateFinalizeHook
|
||||
GetScriptPrivateFinalizeHook(JSRuntime* rt);
|
||||
|
||||
/**
|
||||
* Set the script private finalize hook for the runtime to the given function.
|
||||
*/
|
||||
extern JS_PUBLIC_API void SetScriptPrivateFinalizeHook(
|
||||
JSRuntime* rt, ScriptPrivateFinalizeHook func);
|
||||
|
||||
/*
|
||||
* Perform the ModuleInstantiate operation on the given source text module
|
||||
* record.
|
||||
|
@ -1404,6 +1404,14 @@ JS_FRIEND_API void js::LogDtor(void* self, const char* type, uint32_t sz) {
|
||||
}
|
||||
}
|
||||
|
||||
JS_FRIEND_API JS::Value js::MaybeGetScriptPrivate(JSObject* object) {
|
||||
if (!object->is<ScriptSourceObject>()) {
|
||||
return UndefinedValue();
|
||||
}
|
||||
|
||||
return object->as<ScriptSourceObject>().canonicalPrivate();
|
||||
}
|
||||
|
||||
JS_FRIEND_API uint64_t js::GetGCHeapUsageForObjectZone(JSObject* obj) {
|
||||
return obj->zone()->usage.gcBytes();
|
||||
}
|
||||
|
@ -106,6 +106,22 @@ extern JS_FRIEND_API bool JS_IsDeadWrapper(JSObject* obj);
|
||||
extern JS_FRIEND_API JSObject* JS_NewDeadWrapper(
|
||||
JSContext* cx, JSObject* origObject = nullptr);
|
||||
|
||||
namespace js {
|
||||
|
||||
/**
|
||||
* Get the script private value associated with an object, if any.
|
||||
*
|
||||
* The private value is set with SetScriptPrivate() or SetModulePrivate() and is
|
||||
* internally stored on the relevant ScriptSourceObject.
|
||||
*
|
||||
* This is used by the cycle collector to trace through
|
||||
* ScriptSourceObjects. This allows private values to contain an nsISupports
|
||||
* pointer and hence support references to cycle collected C++ objects.
|
||||
*/
|
||||
JS_FRIEND_API JS::Value MaybeGetScriptPrivate(JSObject* object);
|
||||
|
||||
} // namespace js
|
||||
|
||||
/*
|
||||
* Used by the cycle collector to trace through a shape or object group and
|
||||
* all cycle-participating data it reaches, using bounded stack space.
|
||||
|
@ -3365,15 +3365,17 @@ ModuleObject* js::GetModuleObjectForScript(JSScript* script) {
|
||||
}
|
||||
|
||||
Value js::FindScriptOrModulePrivateForScript(JSScript* script) {
|
||||
while (script) {
|
||||
ScriptSourceObject* sso = script->sourceObject();
|
||||
Value value = sso->unwrappedPrivate();
|
||||
MOZ_ASSERT(script);
|
||||
ScriptSourceObject* sso = script->sourceObject();
|
||||
while (sso) {
|
||||
Value value = sso->canonicalPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sso->unwrappedIntroductionScript() != script);
|
||||
script = sso->unwrappedIntroductionScript();
|
||||
ScriptSourceObject* parent = sso->unwrappedIntroductionSourceObject();
|
||||
MOZ_ASSERT(parent != sso);
|
||||
sso = parent;
|
||||
}
|
||||
|
||||
return UndefinedValue();
|
||||
|
@ -1317,6 +1317,16 @@ void ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj) {
|
||||
MOZ_ASSERT(fop->onMainThread());
|
||||
ScriptSourceObject* sso = &obj->as<ScriptSourceObject>();
|
||||
sso->source()->decref();
|
||||
|
||||
Value value = sso->canonicalPrivate();
|
||||
if (!value.isUndefined()) {
|
||||
// The embedding may need to dispose of its private data.
|
||||
JS::AutoSuppressGCAnalysis suppressGC;
|
||||
if (JS::ScriptPrivateFinalizeHook hook =
|
||||
fop->runtime()->scriptPrivateFinalizeHook) {
|
||||
hook(fop, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptSourceObject::trace(JSTracer* trc, JSObject* obj) {
|
||||
@ -1372,6 +1382,7 @@ ScriptSourceObject* ScriptSourceObject::createInternal(JSContext* cx,
|
||||
obj->initReservedSlot(ELEMENT_SLOT, MagicValue(JS_GENERIC_MAGIC));
|
||||
obj->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC));
|
||||
obj->initReservedSlot(INTRODUCTION_SCRIPT_SLOT, MagicValue(JS_GENERIC_MAGIC));
|
||||
obj->initReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT, MagicValue(JS_GENERIC_MAGIC));
|
||||
|
||||
return obj;
|
||||
}
|
||||
@ -1410,6 +1421,8 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
|
||||
source->getReservedSlot(ELEMENT_PROPERTY_SLOT).isMagic(JS_GENERIC_MAGIC));
|
||||
MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SCRIPT_SLOT)
|
||||
.isMagic(JS_GENERIC_MAGIC));
|
||||
MOZ_ASSERT(source->getReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT)
|
||||
.isMagic(JS_GENERIC_MAGIC));
|
||||
|
||||
RootedObject element(cx, options.element());
|
||||
RootedString elementAttributeName(cx, options.elementAttributeName());
|
||||
@ -1420,14 +1433,20 @@ ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
|
||||
// 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. In that case, simply don't bother to retain the introduction
|
||||
// script.
|
||||
Value introductionScript = UndefinedValue();
|
||||
if (options.introductionScript() &&
|
||||
options.introductionScript()->compartment() == cx->compartment()) {
|
||||
introductionScript.setPrivateGCThing(options.introductionScript());
|
||||
// forbidden. We can still store a CCW to the script source object though.
|
||||
RootedValue introdutionScript(cx);
|
||||
RootedValue introdutionSource(cx);
|
||||
if (options.introductionScript()) {
|
||||
if (options.introductionScript()->compartment() == cx->compartment()) {
|
||||
introdutionScript.setPrivateGCThing(options.introductionScript());
|
||||
}
|
||||
introdutionSource.setObject(*options.introductionScript()->sourceObject());
|
||||
if (!cx->compartment()->wrap(cx, &introdutionSource)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introductionScript);
|
||||
source->setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introdutionScript);
|
||||
source->setReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT, introdutionSource);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1170,14 +1170,24 @@ class ScriptSourceObject : public NativeObject {
|
||||
}
|
||||
return value.toGCThing()->as<JSScript>();
|
||||
}
|
||||
ScriptSourceObject* unwrappedIntroductionSourceObject() const {
|
||||
Value value =
|
||||
unwrappedCanonical()->getReservedSlot(INTRODUCTION_SOURCE_OBJECT_SLOT);
|
||||
if (value.isUndefined()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &UncheckedUnwrap(&value.toObject())->as<ScriptSourceObject>();
|
||||
}
|
||||
|
||||
void setPrivate(const Value& value) {
|
||||
MOZ_ASSERT(isCanonical());
|
||||
setReservedSlot(PRIVATE_SLOT, value);
|
||||
}
|
||||
|
||||
Value unwrappedPrivate() const {
|
||||
return unwrappedCanonical()->getReservedSlot(PRIVATE_SLOT);
|
||||
Value canonicalPrivate() const {
|
||||
Value value = getReservedSlot(PRIVATE_SLOT);
|
||||
MOZ_ASSERT_IF(!isCanonical(), value.isUndefined());
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1187,6 +1197,7 @@ class ScriptSourceObject : public NativeObject {
|
||||
ELEMENT_SLOT,
|
||||
ELEMENT_PROPERTY_SLOT,
|
||||
INTRODUCTION_SCRIPT_SLOT,
|
||||
INTRODUCTION_SOURCE_OBJECT_SLOT,
|
||||
PRIVATE_SLOT,
|
||||
RESERVED_SLOTS
|
||||
};
|
||||
|
@ -163,7 +163,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
wasmInstances(mutexid::WasmRuntimeInstances),
|
||||
moduleResolveHook(),
|
||||
moduleMetadataHook(),
|
||||
moduleDynamicImportHook() {
|
||||
moduleDynamicImportHook(),
|
||||
scriptPrivateFinalizeHook() {
|
||||
JS_COUNT_CTOR(JSRuntime);
|
||||
liveRuntimesCount++;
|
||||
|
||||
|
@ -975,6 +975,9 @@ struct JSRuntime : public js::MallocProvider<JSRuntime> {
|
||||
// module import and can accessed by off-thread parsing.
|
||||
mozilla::Atomic<JS::ModuleDynamicImportHook> moduleDynamicImportHook;
|
||||
|
||||
// A hook called on script finalization.
|
||||
js::MainThreadData<JS::ScriptPrivateFinalizeHook> scriptPrivateFinalizeHook;
|
||||
|
||||
public:
|
||||
#if defined(JS_BUILD_BINAST)
|
||||
js::BinaryASTSupport& binast() { return binast_; }
|
||||
|
@ -1584,6 +1584,9 @@ pref("javascript.options.streams", true);
|
||||
// BigInt API
|
||||
pref("javascript.options.bigint", false);
|
||||
|
||||
// Dynamic module import.
|
||||
pref("javascript.options.dynamicImport", false);
|
||||
|
||||
// advanced prefs
|
||||
pref("advanced.mailftp", false);
|
||||
pref("image.animation_mode", "normal");
|
||||
|
@ -1 +1,2 @@
|
||||
lsan-allowed: [Init, nsHostResolver::ResolveHost]
|
||||
prefs: [javascript.options.dynamicImport:true, security.csp.experimentalEnabled:true]
|
||||
|
@ -1,4 +0,0 @@
|
||||
[dynamic-imports-fetch-error.sub.html]
|
||||
[import(): error cases occuring during fetching]
|
||||
expected: FAIL
|
||||
bug: 1342012
|
@ -1,3 +0,0 @@
|
||||
[dynamic-imports-script-error.html]
|
||||
[import(): error cases caused by the imported module script]
|
||||
expected: FAIL
|
@ -1,7 +0,0 @@
|
||||
[dynamic-imports.html]
|
||||
[Basic dynamic imports]
|
||||
expected: FAIL
|
||||
|
||||
[Dynamic imports should resolve module.]
|
||||
expected: FAIL
|
||||
|
@ -1,5 +0,0 @@
|
||||
[inline-event-handler.html]
|
||||
expected: ERROR
|
||||
[dynamic import should work when triggered from inline event handlers]
|
||||
expected: TIMEOUT
|
||||
|
@ -1,10 +0,0 @@
|
||||
[propagate-nonce-external-classic.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[propagate-nonce-external-classic]
|
||||
expected: FAIL
|
||||
|
||||
[Dynamically imported module should eval when imported from script w/ a valid nonce.]
|
||||
expected: FAIL
|
||||
|
@ -1,10 +0,0 @@
|
||||
[propagate-nonce-external-module.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[propagate-nonce-external-module]
|
||||
expected: FAIL
|
||||
|
||||
[Dynamically imported module should eval when imported from script w/ a valid nonce.]
|
||||
expected: FAIL
|
||||
|
@ -1,10 +0,0 @@
|
||||
[propagate-nonce-inline-classic.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[propagate-nonce-inline-classic]
|
||||
expected: FAIL
|
||||
|
||||
[Dynamically imported module should eval when imported from script w/ a valid nonce.]
|
||||
expected: FAIL
|
||||
|
@ -1,10 +0,0 @@
|
||||
[propagate-nonce-inline-module.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[propagate-nonce-inline-module]
|
||||
expected: FAIL
|
||||
|
||||
[Dynamically imported module should eval when imported from script w/ a valid nonce.]
|
||||
expected: FAIL
|
||||
|
@ -1,17 +0,0 @@
|
||||
[string-compilation-base-url-external-classic.html]
|
||||
expected: ERROR
|
||||
[setTimeout should successfully import]
|
||||
expected: TIMEOUT
|
||||
|
||||
[eval should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[Function should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected-inline-event-handlers should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline-event-handlers-UA-code should successfully import]
|
||||
expected: NOTRUN
|
||||
|
@ -1,17 +0,0 @@
|
||||
[string-compilation-base-url-external-module.html]
|
||||
expected: ERROR
|
||||
[setTimeout should successfully import]
|
||||
expected: TIMEOUT
|
||||
|
||||
[eval should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[Function should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected-inline-event-handlers should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline-event-handlers-UA-code should successfully import]
|
||||
expected: NOTRUN
|
||||
|
@ -1,17 +0,0 @@
|
||||
[string-compilation-base-url-inline-classic.html]
|
||||
expected: ERROR
|
||||
[setTimeout should successfully import]
|
||||
expected: TIMEOUT
|
||||
|
||||
[eval should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[the Function constructor should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected inline event handlers should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline event handlers triggered via UA code should successfully import]
|
||||
expected: NOTRUN
|
||||
|
@ -1,17 +0,0 @@
|
||||
[string-compilation-base-url-inline-module.html]
|
||||
expected: ERROR
|
||||
[setTimeout should successfully import]
|
||||
expected: TIMEOUT
|
||||
|
||||
[eval should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[the Function constructor should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected inline event handlers should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline event handlers triggered via UA code should successfully import]
|
||||
expected: NOTRUN
|
||||
|
@ -1,17 +0,0 @@
|
||||
[string-compilation-classic.html]
|
||||
expected: ERROR
|
||||
[eval should successfully import]
|
||||
expected: FAIL
|
||||
|
||||
[setTimeout should successfully import]
|
||||
expected: TIMEOUT
|
||||
|
||||
[the Function constructor should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected inline event handlers should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline event handlers triggered via UA code should successfully import]
|
||||
expected: NOTRUN
|
||||
|
@ -1,17 +0,0 @@
|
||||
[string-compilation-module.html]
|
||||
expected: ERROR
|
||||
[eval should successfully import]
|
||||
expected: FAIL
|
||||
|
||||
[setTimeout should successfully import]
|
||||
expected: TIMEOUT
|
||||
|
||||
[the Function constructor should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected inline event handlers should successfully import]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline event handlers triggered via UA code should successfully import]
|
||||
expected: NOTRUN
|
||||
|
@ -1,20 +1,4 @@
|
||||
[string-compilation-nonce-classic.html]
|
||||
expected: ERROR
|
||||
[setTimeout must inherit the nonce from the triggering script, thus execute]
|
||||
expected: TIMEOUT
|
||||
|
||||
[direct eval must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[indirect eval must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[the Function constructor must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected inline event handlers must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline event handlers triggered via UA code must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1,20 +1,3 @@
|
||||
[string-compilation-nonce-module.html]
|
||||
expected: ERROR
|
||||
[setTimeout must inherit the nonce from the triggering script, thus execute]
|
||||
expected: TIMEOUT
|
||||
|
||||
[direct eval must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[indirect eval must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[the Function constructor must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[reflected inline event handlers must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
[inline event handlers triggered via UA code must inherit the nonce from the triggering script, thus execute]
|
||||
expected: NOTRUN
|
||||
|
||||
expected: FAIL
|
||||
|
@ -1,13 +0,0 @@
|
||||
[string-compilation-of-promise-result.html]
|
||||
[Evaled the script via eval, successful import]
|
||||
expected: FAIL
|
||||
|
||||
[Evaled the script via eval, failed import]
|
||||
expected: FAIL
|
||||
|
||||
[Evaled the script via Function, successful import]
|
||||
expected: FAIL
|
||||
|
||||
[Evaled the script via Function, failed import]
|
||||
expected: FAIL
|
||||
|
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<div id="dummy"></div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,58 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Check import() works when active script is in another document</title>
|
||||
<link rel="author" title="Jon Coppeard" href="mailto:jcoppeard@mozilla.com">
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
|
||||
<iframe id="frame" src="resources/empty-iframe.html"></iframe>
|
||||
|
||||
<script>
|
||||
|
||||
function startTest() {
|
||||
const otherWindow = document.getElementById("frame").contentWindow;
|
||||
const otherDiv = otherWindow.document.getElementById("dummy");
|
||||
|
||||
function createTestPromise() {
|
||||
return new Promise((resolve, reject) => {
|
||||
otherWindow.continueTest = resolve;
|
||||
otherWindow.errorTest = reject;
|
||||
});
|
||||
}
|
||||
|
||||
const evaluators = {
|
||||
eval: otherWindow.eval,
|
||||
setTimeout: otherWindow.setTimeout,
|
||||
"the Function constructor"(x) {
|
||||
otherWindow.Function(x)();
|
||||
},
|
||||
"reflected inline event handlers"(x) {
|
||||
otherDiv.setAttribute("onclick", x);
|
||||
otherDiv.onclick();
|
||||
},
|
||||
"inline event handlers triggered by JS"(x) {
|
||||
otherDiv.setAttribute("onclick", x);
|
||||
otherDiv.click(); // different from .**on**click()
|
||||
}
|
||||
};
|
||||
|
||||
for (const [label, evaluator] of Object.entries(evaluators)) {
|
||||
promise_test(t => {
|
||||
t.add_cleanup(() => {
|
||||
otherDiv.removeAttribute("onclick");
|
||||
delete otherWindow.evaluated_imports_a;
|
||||
});
|
||||
|
||||
const promise = createTestPromise();
|
||||
|
||||
evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
|
||||
|
||||
return promise.then(module => {
|
||||
assert_true(otherWindow.evaluated_imports_a, "The module must have been evaluated");
|
||||
assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
|
||||
});
|
||||
}, label + " should successfully import");
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<body onLoad="startTest()"></body>
|
@ -75,6 +75,7 @@
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "js/Debug.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
@ -627,28 +628,36 @@ void CycleCollectedJSRuntime::NoteGCThingXPCOMChildren(
|
||||
// Nothing else to do!
|
||||
return;
|
||||
}
|
||||
|
||||
// XXX This test does seem fragile, we should probably whitelist classes
|
||||
// that do hold a strong reference, but that might not be possible.
|
||||
else if (aClasp->flags & JSCLASS_HAS_PRIVATE &&
|
||||
aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
|
||||
if (aClasp->flags & JSCLASS_HAS_PRIVATE &&
|
||||
aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "js::GetObjectPrivate(obj)");
|
||||
aCb.NoteXPCOMChild(static_cast<nsISupports*>(js::GetObjectPrivate(aObj)));
|
||||
} else {
|
||||
const DOMJSClass* domClass = GetDOMClass(aObj);
|
||||
if (domClass) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)");
|
||||
// It's possible that our object is an unforgeable holder object, in
|
||||
// which case it doesn't actually have a C++ DOM object associated with
|
||||
// it. Use UnwrapPossiblyNotInitializedDOMObject, which produces null in
|
||||
// that case, since NoteXPCOMChild/NoteNativeChild are null-safe.
|
||||
if (domClass->mDOMObjectIsISupports) {
|
||||
aCb.NoteXPCOMChild(
|
||||
UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObj));
|
||||
} else if (domClass->mParticipant) {
|
||||
aCb.NoteNativeChild(UnwrapPossiblyNotInitializedDOMObject<void>(aObj),
|
||||
domClass->mParticipant);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const DOMJSClass* domClass = GetDOMClass(aObj);
|
||||
if (domClass) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)");
|
||||
// It's possible that our object is an unforgeable holder object, in
|
||||
// which case it doesn't actually have a C++ DOM object associated with
|
||||
// it. Use UnwrapPossiblyNotInitializedDOMObject, which produces null in
|
||||
// that case, since NoteXPCOMChild/NoteNativeChild are null-safe.
|
||||
if (domClass->mDOMObjectIsISupports) {
|
||||
aCb.NoteXPCOMChild(
|
||||
UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObj));
|
||||
} else if (domClass->mParticipant) {
|
||||
aCb.NoteNativeChild(UnwrapPossiblyNotInitializedDOMObject<void>(aObj),
|
||||
domClass->mParticipant);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Value value = js::MaybeGetScriptPrivate(aObj);
|
||||
if (!value.isUndefined()) {
|
||||
aCb.NoteXPCOMChild(static_cast<nsISupports*>(value.toPrivate()));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user