This reverts commit1abc6298e1. Revert "Bug 2056134 - Part 5: Add tests. r=bthrall" This reverts commit7bb9240798. Revert "Bug 2056134 - Part 4: Use pre-calculated fallback encoding for the classic script disk cache MIME-Type. r=bthrall" This reverts commit07b098aa0d. Revert "Bug 2056134 - Part 3: Use pre-calculated fallback encoding for the in-memory cache key. r=bthrall" This reverts commit3173e731bf. Revert "Bug 2056134 - Part 2: Pre-calculate the fallback encoding for the classic script source. r=bthrall,dom-worker-reviewers,edenchuang" This reverts commitfd0eb69272. Revert "Bug 2056134 - Part 1: Include the hint charset into the cache key string for the ChromeUtils.getCachedJavaScriptSource. r=bthrall,devtools-reviewers,jdescottes" This reverts commitc0bc4e330d.
350 lines
10 KiB
C++
350 lines
10 KiB
C++
/* 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/dom/ScriptLoadContext.h" // ScriptLoadContext
|
|
#include "mozilla/HoldDropJSObjects.h"
|
|
#include "mozilla/RefPtr.h" // RefPtr, mozilla::MakeRefPtr
|
|
#include "mozilla/Sprintf.h" // SprintfLiteral
|
|
#include "mozilla/UniquePtr.h" // mozilla::UniquePtr, mozilla::MakeUnique
|
|
|
|
#include "jsfriendapi.h"
|
|
#include "LoadContextBase.h" // LoadContextBase
|
|
#include "nsIChannel.h" // nsIChannel
|
|
#include "nsIURI.h" // nsIURI::GetSpecOrDefault
|
|
|
|
#include "js/experimental/JSStencil.h" // JS::SizeOfStencil
|
|
#include "js/Modules.h" // JS::{Get,Set}ModulePrivate
|
|
|
|
namespace JS::loader {
|
|
|
|
NS_IMPL_ISUPPORTS(ScriptFetchInfo, nsISupports);
|
|
|
|
ScriptFetchInfo::ScriptFetchInfo(ScriptKind aKind,
|
|
mozilla::dom::ReferrerPolicy aReferrerPolicy,
|
|
ScriptFetchOptions* aFetchOptions,
|
|
nsIURI* aURI)
|
|
: mKind(aKind),
|
|
mReferrerPolicy(aReferrerPolicy),
|
|
mFetchOptions(aFetchOptions),
|
|
mBaseURL(aURI) {
|
|
MOZ_ASSERT(mFetchOptions);
|
|
}
|
|
|
|
size_t ScriptFetchInfo::SizeOfIncludingThis(
|
|
mozilla::MallocSizeOf aMallocSizeOf) const {
|
|
return aMallocSizeOf(this) +
|
|
mFetchOptions->SizeOfIncludingThis(aMallocSizeOf);
|
|
}
|
|
|
|
static bool IsInternalURIScheme(nsIURI* uri) {
|
|
return uri->SchemeIs("moz-extension") || uri->SchemeIs("resource") ||
|
|
uri->SchemeIs("moz-src") || uri->SchemeIs("chrome");
|
|
}
|
|
|
|
void ScriptFetchInfo::SetBaseURLFromChannelAndOriginalURI(
|
|
nsIChannel* aChannel, nsIURI* aOriginalURI) {
|
|
// Fixup moz-extension: and resource: URIs, because the channel URI will
|
|
// point to file:, which won't be allowed to load.
|
|
if (aOriginalURI && IsInternalURIScheme(aOriginalURI)) {
|
|
mBaseURL = aOriginalURI;
|
|
} else {
|
|
aChannel->GetURI(getter_AddRefs(mBaseURL));
|
|
}
|
|
}
|
|
|
|
void ScriptFetchInfo::AssociateWithScript(JSScript* aScript) {
|
|
// Verify that the rewritten URL is available when manipulating the referrer.
|
|
MOZ_ASSERT(mBaseURL);
|
|
|
|
// Set a JSScript's private value to point to this object. The JS engine will
|
|
// increment our reference count by calling
|
|
// HostAddRefScriptFetchInfo(). This is decremented by
|
|
// HostReleaseScriptFetchInfo() below when the JSScript dies.
|
|
|
|
MOZ_ASSERT(GetScriptPrivate(aScript).isUndefined());
|
|
SetScriptPrivate(aScript, PrivateValue(this));
|
|
}
|
|
|
|
void ScriptFetchInfo::AssociateWithModule(JSObject* aModuleRecord) {
|
|
MOZ_ASSERT(mBaseURL);
|
|
|
|
// Make module's host defined field point to this object. The JS engine
|
|
// will increment our reference count by calling
|
|
// HostAddRefScriptFetchInfo(). This is decremented when the
|
|
// module record dies.
|
|
MOZ_ASSERT(GetModulePrivate(aModuleRecord).isUndefined());
|
|
SetModulePrivate(aModuleRecord, PrivateValue(this));
|
|
}
|
|
|
|
void HostAddRefScriptFetchInfo(const Value& aPrivate) {
|
|
// Increment the reference count of a ScriptFetchInfo object that is
|
|
// now pointed to by a JSScript. The reference count is decremented by
|
|
// HostReleaseScriptFetchInfo() below.
|
|
|
|
auto fetchInfo = static_cast<ScriptFetchInfo*>(aPrivate.toPrivate());
|
|
fetchInfo->AddRef();
|
|
}
|
|
|
|
void HostReleaseScriptFetchInfo(const Value& aPrivate) {
|
|
// Decrement the reference count of a ScriptFetchInfo object that was
|
|
// pointed to by a JSScript. The reference count was originally incremented by
|
|
// HostAddRefScriptFetchInfo() above.
|
|
|
|
auto fetchInfo = static_cast<ScriptFetchInfo*>(aPrivate.toPrivate());
|
|
fetchInfo->Release();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// LoadedScript
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
NS_IMPL_ISUPPORTS(LoadedScript, nsISupports)
|
|
|
|
LoadedScript::LoadedScript(ScriptKind aKind, nsIURI* aURI)
|
|
: mDataType(DataType::eUnknown),
|
|
mKind(aKind),
|
|
mSerializedStencilOffset(0),
|
|
mCacheEntryId(InvalidCacheEntryId),
|
|
mIsDirty(false),
|
|
mTookLongInPreviousRuns(false),
|
|
mIsEverHitFromMemoryCache(false),
|
|
mURI(aURI),
|
|
mReceivedScriptTextLength(0) {
|
|
MOZ_ASSERT(mURI);
|
|
}
|
|
|
|
size_t LoadedScript::SizeOfIncludingThis(
|
|
mozilla::MallocSizeOf aMallocSizeOf) const {
|
|
size_t bytes = aMallocSizeOf(this);
|
|
|
|
if (mSRIMetadata) {
|
|
bytes += mSRIMetadata->SizeOfIncludingThis(aMallocSizeOf);
|
|
}
|
|
|
|
if (IsTextSource()) {
|
|
if (IsUTF16Text()) {
|
|
bytes += ScriptText<char16_t>().sizeOfExcludingThis(aMallocSizeOf);
|
|
} else {
|
|
bytes += ScriptText<Utf8Unit>().sizeOfExcludingThis(aMallocSizeOf);
|
|
}
|
|
}
|
|
|
|
bytes += mSRIAndSerializedStencil.sizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
if (mCachedStencil) {
|
|
bytes += JS::SizeOfStencil(mCachedStencil, aMallocSizeOf);
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
nsresult LoadedScript::GetScriptSource(JSContext* aCx,
|
|
MaybeSourceText* aMaybeSource,
|
|
LoadContextBase* aMaybeLoadContext) {
|
|
// If there's no script text, we try to get it from the element
|
|
bool isWindowContext =
|
|
aMaybeLoadContext && aMaybeLoadContext->IsWindowContext();
|
|
if (isWindowContext && aMaybeLoadContext->AsWindowContext()->mIsInline) {
|
|
nsAutoString inlineData;
|
|
auto* scriptLoadContext = aMaybeLoadContext->AsWindowContext();
|
|
scriptLoadContext->GetInlineScriptText(inlineData);
|
|
|
|
size_t nbytes = inlineData.Length() * sizeof(char16_t);
|
|
UniqueTwoByteChars chars(static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
|
|
if (!chars) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
memcpy(chars.get(), inlineData.get(), nbytes);
|
|
|
|
SourceText<char16_t> srcBuf;
|
|
if (!srcBuf.init(aCx, std::move(chars), inlineData.Length())) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
|
|
return NS_OK;
|
|
}
|
|
|
|
size_t length = ScriptTextLength();
|
|
if (IsUTF16Text()) {
|
|
UniqueTwoByteChars chars;
|
|
chars.reset(ScriptText<char16_t>().extractOrCopyRawBuffer());
|
|
if (!chars) {
|
|
JS_ReportOutOfMemory(aCx);
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
SourceText<char16_t> srcBuf;
|
|
if (!srcBuf.init(aCx, std::move(chars), length)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
|
|
return NS_OK;
|
|
}
|
|
|
|
MOZ_ASSERT(IsUTF8Text());
|
|
mozilla::UniquePtr<Utf8Unit[], FreePolicy> chars;
|
|
chars.reset(ScriptText<Utf8Unit>().extractOrCopyRawBuffer());
|
|
if (!chars) {
|
|
JS_ReportOutOfMemory(aCx);
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
SourceText<Utf8Unit> srcBuf;
|
|
if (!srcBuf.init(aCx, std::move(chars), length)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
aMaybeSource->construct<SourceText<Utf8Unit>>(std::move(srcBuf));
|
|
return NS_OK;
|
|
}
|
|
|
|
void LoadedScript::SetSRIMetadata(
|
|
const mozilla::dom::SRIMetadata& aSRIMetadata) {
|
|
if (aSRIMetadata.IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
mSRIMetadata = mozilla::MakeUnique<mozilla::dom::SRIMetadata>(aSRIMetadata);
|
|
}
|
|
|
|
bool LoadedScript::IsSRIMetadataReusableBy(
|
|
const mozilla::dom::SRIMetadata& aSRIMetadata) {
|
|
if (aSRIMetadata.IsEmpty()) {
|
|
return true;
|
|
}
|
|
|
|
if (!mSRIMetadata) {
|
|
return false;
|
|
}
|
|
|
|
return aSRIMetadata.CanTrustBeDelegatedTo(*mSRIMetadata);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// ModuleScript
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
|
|
tmp->mModuleRecord = nullptr;
|
|
tmp->mParseError.setUndefined();
|
|
tmp->mErrorToRethrow.setUndefined();
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
|
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
|
|
|
|
ModuleScript::ModuleScript(ScriptFetchInfo* aFetchInfo)
|
|
: mFetchInfoForAccessingPreloadFlag(aFetchInfo) {
|
|
MOZ_ASSERT(!ModuleRecord());
|
|
MOZ_ASSERT(!HasParseError());
|
|
MOZ_ASSERT(!HasErrorToRethrow());
|
|
}
|
|
|
|
void ModuleScript::Shutdown() {
|
|
if (mModuleRecord) {
|
|
ClearModuleEnvironment(mModuleRecord);
|
|
}
|
|
|
|
mModuleRecord = nullptr;
|
|
}
|
|
|
|
ModuleScript::~ModuleScript() {
|
|
// The object may be destroyed without being unlinked first.
|
|
mModuleRecord = nullptr;
|
|
mozilla::DropJSObjects(this);
|
|
}
|
|
|
|
void ModuleScript::SetModuleRecord(Handle<JSObject*> aModuleRecord) {
|
|
MOZ_ASSERT(!mModuleRecord);
|
|
MOZ_ASSERT(!HasParseError());
|
|
MOZ_ASSERT(!HasErrorToRethrow());
|
|
|
|
mModuleRecord = aModuleRecord;
|
|
|
|
#ifdef DEBUG
|
|
// Sync the [[PreloadSlot]] in ModuleObject.
|
|
if (mModuleRecord) {
|
|
SetModulePreload(mModuleRecord,
|
|
mFetchInfoForAccessingPreloadFlag->IsForModulePreload());
|
|
}
|
|
#endif
|
|
|
|
mozilla::HoldJSObjects(this);
|
|
}
|
|
|
|
void ModuleScript::SetParseError(const Value& aError) {
|
|
MOZ_ASSERT(!aError.isUndefined());
|
|
MOZ_ASSERT(!HasParseError());
|
|
MOZ_ASSERT(!HasErrorToRethrow());
|
|
|
|
mModuleRecord = nullptr;
|
|
mParseError = aError;
|
|
mozilla::HoldJSObjects(this);
|
|
}
|
|
|
|
void ModuleScript::SetErrorToRethrow(const 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::SetForPreload(bool aValue) {
|
|
mFetchInfoForAccessingPreloadFlag->SetForModulePreload(aValue);
|
|
#ifdef DEBUG
|
|
if (ModuleRecord()) {
|
|
SetModulePreload(ModuleRecord(), aValue);
|
|
}
|
|
#endif
|
|
}
|
|
void ModuleScript::SetHadImportMap(bool aValue) { mHadImportMap = aValue; }
|
|
|
|
ResolvedModuleSet* ModuleScript::GetPreloadedResolvedSet() {
|
|
if (!mPreloadedResolvedSet) {
|
|
mPreloadedResolvedSet = mozilla::MakeUnique<ResolvedModuleSet>();
|
|
}
|
|
|
|
return mPreloadedResolvedSet.get();
|
|
}
|
|
|
|
void ModuleScript::ResetPreload() {
|
|
MOZ_ASSERT(mFetchInfoForAccessingPreloadFlag->IsForModulePreload());
|
|
if (mModuleRecord) {
|
|
ResetPreloadedModule(mModuleRecord);
|
|
}
|
|
|
|
if (HasParseError()) {
|
|
mParseError = UndefinedValue();
|
|
}
|
|
|
|
if (HasErrorToRethrow()) {
|
|
mErrorToRethrow = UndefinedValue();
|
|
}
|
|
}
|
|
|
|
} // namespace JS::loader
|