tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ScriptLoadContext.cpp (7791B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ScriptLoadContext.h"
      8 
      9 #include "GeckoProfiler.h"
     10 #include "ModuleLoadRequest.h"
     11 #include "js/SourceText.h"
     12 #include "js/loader/LoadContextBase.h"
     13 #include "js/loader/ModuleLoadRequest.h"
     14 #include "mozilla/HoldDropJSObjects.h"
     15 #include "mozilla/StaticPrefs_dom.h"
     16 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
     17 #include "mozilla/dom/Document.h"
     18 #include "nsContentUtils.h"
     19 #include "nsICacheInfoChannel.h"
     20 #include "nsIClassOfService.h"
     21 #include "nsISupportsPriority.h"
     22 
     23 namespace mozilla::dom {
     24 
     25 //////////////////////////////////////////////////////////////
     26 // ScriptLoadContext
     27 //////////////////////////////////////////////////////////////
     28 
     29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadContext)
     30 NS_INTERFACE_MAP_END_INHERITING(JS::loader::LoadContextBase)
     31 
     32 NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadContext)
     33 
     34 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptLoadContext,
     35                                                JS::loader::LoadContextBase)
     36  MOZ_ASSERT(!tmp->mCompileOrDecodeTask);
     37  tmp->MaybeUnblockOnload();
     38  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptElement);
     39 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     40 
     41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ScriptLoadContext,
     42                                                  JS::loader::LoadContextBase)
     43  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDocument)
     44  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptElement);
     45 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     46 
     47 NS_IMPL_ADDREF_INHERITED(ScriptLoadContext, JS::loader::LoadContextBase)
     48 NS_IMPL_RELEASE_INHERITED(ScriptLoadContext, JS::loader::LoadContextBase)
     49 
     50 ScriptLoadContext::ScriptLoadContext(
     51    nsIScriptElement* aScriptElement /* = nullptr */,
     52    const nsAString& aSourceText /* = VoidString() */)
     53    : JS::loader::LoadContextBase(JS::loader::ContextKind::Window),
     54      mScriptMode(ScriptMode::eBlocking),
     55      mScriptFromHead(false),
     56      mIsInline(true),
     57      mInDeferList(false),
     58      mInAsyncList(false),
     59      mIsNonAsyncScriptInserted(false),
     60      mIsXSLT(false),
     61      mInCompilingList(false),
     62      mClassificationFlags({0, 0}),
     63      mWasCompiledOMT(false),
     64      mLineNo(1),
     65      mColumnNo(0),
     66      mIsPreload(false),
     67      mScriptElement(aScriptElement),
     68      mSourceText(aSourceText),
     69      mUnreportedPreloadError(NS_OK) {}
     70 
     71 ScriptLoadContext::~ScriptLoadContext() {
     72  MOZ_ASSERT(NS_IsMainThread());
     73 
     74  // Off-thread parsing must have completed or cancelled by this point.
     75  MOZ_DIAGNOSTIC_ASSERT(!mCompileOrDecodeTask);
     76 
     77  mRequest = nullptr;
     78 
     79  MaybeUnblockOnload();
     80 }
     81 
     82 void ScriptLoadContext::BlockOnload(Document* aDocument) {
     83  MOZ_ASSERT(!mLoadBlockedDocument);
     84  aDocument->BlockOnload();
     85  mLoadBlockedDocument = aDocument;
     86 }
     87 
     88 void ScriptLoadContext::MaybeUnblockOnload() {
     89  if (mLoadBlockedDocument) {
     90    mLoadBlockedDocument->UnblockOnload(false);
     91    mLoadBlockedDocument = nullptr;
     92  }
     93 }
     94 
     95 void ScriptLoadContext::MaybeCancelOffThreadScript() {
     96  MOZ_ASSERT(NS_IsMainThread());
     97 
     98  if (!mCompileOrDecodeTask) {
     99    return;
    100  }
    101 
    102  // Cancel the task if it hasn't been started yet or wait for it to finish.
    103  mCompileOrDecodeTask->Cancel();
    104  mCompileOrDecodeTask = nullptr;
    105 
    106  MaybeUnblockOnload();
    107 }
    108 
    109 void ScriptLoadContext::SetScriptMode(bool aDeferAttr, bool aAsyncAttr,
    110                                      bool aLinkPreload) {
    111  if (aLinkPreload) {
    112    mScriptMode = ScriptMode::eLinkPreload;
    113  } else if (aAsyncAttr) {
    114    mScriptMode = ScriptMode::eAsync;
    115  } else if (aDeferAttr || mRequest->IsModuleRequest()) {
    116    mScriptMode = ScriptMode::eDeferred;
    117  } else {
    118    mScriptMode = ScriptMode::eBlocking;
    119  }
    120 }
    121 
    122 // static
    123 void ScriptLoadContext::PrioritizeAsPreload(nsIChannel* aChannel) {
    124  if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(aChannel)) {
    125    cos->AddClassFlags(nsIClassOfService::Unblocked);
    126  }
    127  if (nsCOMPtr<nsISupportsPriority> sp = do_QueryInterface(aChannel)) {
    128    sp->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
    129  }
    130 }
    131 
    132 bool ScriptLoadContext::IsPreload() const {
    133  if (mRequest->IsModuleRequest() &&
    134      mRequest->AsModuleRequest()->IsStaticImport()) {
    135    JS::loader::ModuleLoadRequest* root =
    136        mRequest->AsModuleRequest()->GetRootModule();
    137    return root->GetScriptLoadContext()->IsPreload();
    138  }
    139 
    140  MOZ_ASSERT_IF(mIsPreload, !HasScriptElement());
    141  return mIsPreload;
    142 }
    143 
    144 bool ScriptLoadContext::CompileStarted() const {
    145  return mRequest->IsCompiling() || (mRequest->IsFinished() && mWasCompiledOMT);
    146 }
    147 
    148 bool ScriptLoadContext::HasScriptElement() const { return !!mScriptElement; }
    149 
    150 void ScriptLoadContext::GetInlineScriptText(nsAString& aText) const {
    151  MOZ_ASSERT(mIsInline);
    152  if (mSourceText.IsVoid()) {
    153    // Lazily retrieve the text of inline script, see bug 1376651.
    154    mScriptElement->GetScriptText(aText);
    155  } else {
    156    aText.Append(mSourceText);
    157  }
    158 }
    159 
    160 void ScriptLoadContext::GetHintCharset(nsAString& aCharset) const {
    161  MOZ_ASSERT(mScriptElement);
    162  mScriptElement->GetScriptCharset(aCharset);
    163 }
    164 
    165 uint32_t ScriptLoadContext::GetScriptLineNumber() const {
    166  if (mScriptElement) {
    167    return mScriptElement->GetScriptLineNumber();
    168  }
    169  return 0;
    170 }
    171 
    172 JS::ColumnNumberOneOrigin ScriptLoadContext::GetScriptColumnNumber() const {
    173  if (mScriptElement) {
    174    return mScriptElement->GetScriptColumnNumber();
    175  }
    176  return JS::ColumnNumberOneOrigin();
    177 }
    178 
    179 void ScriptLoadContext::BeginEvaluatingTopLevel() const {
    180  MOZ_ASSERT(mScriptElement);
    181  mScriptElement->BeginEvaluating();
    182 }
    183 
    184 void ScriptLoadContext::EndEvaluatingTopLevel() const {
    185  MOZ_ASSERT(mScriptElement);
    186  mScriptElement->EndEvaluating();
    187 }
    188 
    189 void ScriptLoadContext::UnblockParser() const {
    190  MOZ_ASSERT(mScriptElement);
    191  mScriptElement->UnblockParser();
    192 }
    193 
    194 void ScriptLoadContext::ContinueParserAsync() const {
    195  MOZ_ASSERT(mScriptElement);
    196  mScriptElement->ContinueParserAsync();
    197 }
    198 
    199 Document* ScriptLoadContext::GetScriptOwnerDocument() const {
    200  nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(mScriptElement));
    201  MOZ_ASSERT(scriptContent);
    202  return scriptContent->OwnerDoc();
    203 }
    204 
    205 void ScriptLoadContext::SetIsLoadRequest(nsIScriptElement* aElement) {
    206  MOZ_ASSERT(aElement);
    207  MOZ_ASSERT(!HasScriptElement());
    208  MOZ_ASSERT(IsPreload());
    209  mScriptElement = aElement;
    210  mIsPreload = false;
    211 }
    212 
    213 void ScriptLoadContext::GetProfilerLabel(nsACString& aOutString) {
    214  if (!profiler_is_active()) {
    215    aOutString.Append("<script> element");
    216    return;
    217  }
    218  aOutString.Append("<script");
    219  if (IsAsyncScript()) {
    220    aOutString.Append(" async");
    221  } else if (IsDeferredScript()) {
    222    aOutString.Append(" defer");
    223  }
    224  if (mRequest->IsModuleRequest()) {
    225    aOutString.Append(" type=\"module\"");
    226  }
    227 
    228  nsAutoCString url;
    229  if (mRequest->URI()) {
    230    mRequest->URI()->GetAsciiSpec(url);
    231  } else {
    232    url = "<unknown>";
    233  }
    234 
    235  if (mIsInline) {
    236    if (GetParserCreated() != NOT_FROM_PARSER) {
    237      aOutString.Append("> inline at line ");
    238      aOutString.AppendInt(mLineNo);
    239      aOutString.Append(" of ");
    240    } else {
    241      aOutString.Append("> inline (dynamically created) in ");
    242    }
    243    aOutString.Append(url);
    244  } else {
    245    aOutString.Append(" src=\"");
    246    aOutString.Append(url);
    247    aOutString.Append("\">");
    248  }
    249 }
    250 
    251 already_AddRefed<JS::Stencil> ScriptLoadContext::StealOffThreadResult(
    252    JSContext* aCx, JS::InstantiationStorage* aInstantiationStorage) {
    253  RefPtr<CompileOrDecodeTask> compileOrDecodeTask =
    254      mCompileOrDecodeTask.forget();
    255 
    256  return compileOrDecodeTask->StealResult(aCx, aInstantiationStorage);
    257 }
    258 
    259 }  // namespace mozilla::dom