tor-browser

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

ScriptLoadContext.h (11159B)


      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 #ifndef mozilla_dom_ScriptLoadContext_h
      8 #define mozilla_dom_ScriptLoadContext_h
      9 
     10 #include "js/AllocPolicy.h"
     11 #include "js/ColumnNumber.h"    // JS::ColumnNumberOneOrigin
     12 #include "js/CompileOptions.h"  // JS::OwningCompileOptions
     13 #include "js/RootingAPI.h"
     14 #include "js/SourceText.h"
     15 #include "js/Transcoding.h"  // JS::TranscodeResult
     16 #include "js/TypeDecls.h"
     17 #include "js/experimental/JSStencil.h"  // JS::FrontendContext, JS::Stencil, JS::InstantiationStorage
     18 #include "js/loader/LoadContextBase.h"
     19 #include "js/loader/ScriptKind.h"
     20 #include "mozilla/AlreadyAddRefed.h"
     21 #include "mozilla/Assertions.h"
     22 #include "mozilla/CORSMode.h"
     23 #include "mozilla/Mutex.h"
     24 #include "mozilla/PreloaderBase.h"
     25 #include "mozilla/RefPtr.h"
     26 #include "mozilla/StaticPrefs_dom.h"
     27 #include "mozilla/TaskController.h"  // mozilla::Task
     28 #include "mozilla/Utf8.h"            // mozilla::Utf8Unit
     29 #include "mozilla/dom/SRIMetadata.h"
     30 #include "mozilla/net/UrlClassifierCommon.h"
     31 #include "nsCOMPtr.h"
     32 #include "nsCycleCollectionParticipant.h"
     33 #include "nsIClassifiedChannel.h"
     34 #include "nsIScriptElement.h"
     35 
     36 class nsICacheInfoChannel;
     37 struct JSContext;
     38 
     39 namespace mozilla::dom {
     40 
     41 class Element;
     42 
     43 /*
     44 * DOM specific ScriptLoadContext.
     45 *
     46 * ScriptLoadContexts augment the loading of a ScriptLoadRequest. They
     47 * describe how a ScriptLoadRequests loading and evaluation needs to be
     48 * augmented, based on the information provided by the loading context. In
     49 * the case of the DOM, the ScriptLoadContext is used to identify how a script
     50 * should be loaded according to information found in the HTML document into
     51 * which it will be loaded. The following fields describe how the
     52 * ScriptLoadRequest will be loaded.
     53 *
     54 *    * mScriptMode
     55 *        stores the mode (Async, Sync, Deferred), and preload, which
     56 *        allows the ScriptLoader to decide if the script should be pushed
     57 *        offThread, or if the preloaded request should be used.
     58 *    * mScriptFromHead
     59 *        Set when the script tag is in the head, and should be treated as
     60 *        a blocking script
     61 *    * mIsInline
     62 *        Set for scripts whose bodies are inline in the html. In this case,
     63 *        the script does not need to be fetched first.
     64 *    * mIsXSLT
     65 *        Set if we are in an XSLT request.
     66 *    * mIsPreload
     67 *        Set for scripts that are preloaded in a
     68 *        <link rel="preload" as="script"> or <link rel="modulepreload">
     69 *        element.
     70 *
     71 * In addition to describing how the ScriptLoadRequest will be loaded by the
     72 * DOM ScriptLoader, the ScriptLoadContext contains fields that facilitate
     73 * those custom behaviors, including support for offthread parsing and preload
     74 * element specific controls.
     75 *
     76 */
     77 
     78 // Base class for the off-thread compile or off-thread decode tasks.
     79 class CompileOrDecodeTask : public mozilla::Task {
     80 protected:
     81  CompileOrDecodeTask();
     82  virtual ~CompileOrDecodeTask();
     83 
     84  nsresult InitFrontendContext();
     85 
     86  void DidRunTask(const MutexAutoLock& aProofOfLock,
     87                  RefPtr<JS::Stencil>&& aStencil);
     88 
     89  bool IsCancelled(const MutexAutoLock& aProofOfLock) const {
     90    return mIsCancelled;
     91  }
     92 
     93 public:
     94  // Returns the result of the compilation or decode if it was successful.
     95  // Returns nullptr otherwise, and sets pending exception on JSContext.
     96  //
     97  // aInstantiationStorage receives the storage allocated off main thread
     98  // on successful case.
     99  already_AddRefed<JS::Stencil> StealResult(
    100      JSContext* aCx, JS::InstantiationStorage* aInstantiationStorage);
    101 
    102  // Cancel the task.
    103  // If the task is already running, this waits for the task to finish.
    104  void Cancel();
    105 
    106 protected:
    107  // This mutex is locked during running the task or cancelling task.
    108  mozilla::Mutex mMutex;
    109 
    110  // The result of decode task, to distinguish throwing case and decode error.
    111  JS::TranscodeResult mResult = JS::TranscodeResult::Ok;
    112 
    113  // An option used to compile the code, or the equivalent for decode.
    114  // This holds the filename pointed by errors reported to JS::FrontendContext.
    115  JS::OwningCompileOptions mOptions;
    116 
    117  // Owning-pointer for the context associated with the script compilation.
    118  //
    119  // The context is allocated on main thread in InitFrontendContext method,
    120  // and is freed on any thread in the destructor.
    121  JS::FrontendContext* mFrontendContext = nullptr;
    122 
    123  bool mIsCancelled = false;
    124 
    125 private:
    126  // The result of the compilation or decode.
    127  RefPtr<JS::Stencil> mStencil;
    128 
    129  JS::InstantiationStorage mInstantiationStorage;
    130 };
    131 
    132 class ScriptLoadContext : public JS::loader::LoadContextBase,
    133                          public PreloaderBase {
    134 protected:
    135  virtual ~ScriptLoadContext();
    136 
    137 public:
    138  explicit ScriptLoadContext(nsIScriptElement* aScriptElement = nullptr,
    139                             const nsAString& aSourceText = VoidString());
    140 
    141  NS_DECL_ISUPPORTS_INHERITED
    142  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ScriptLoadContext,
    143                                           JS::loader::LoadContextBase)
    144 
    145  static void PrioritizeAsPreload(nsIChannel* aChannel);
    146 
    147  bool IsPreload() const override;
    148 
    149  bool CompileStarted() const;
    150 
    151  net::ClassificationFlags& GetClassificationFlags() {
    152    return mClassificationFlags;
    153  }
    154  void SetClassificationFlags(
    155      const net::ClassificationFlags& aClassificationFlags) {
    156    mClassificationFlags = aClassificationFlags;
    157  }
    158 
    159  void BlockOnload(Document* aDocument);
    160 
    161  void MaybeUnblockOnload();
    162 
    163  enum class ScriptMode : uint8_t {
    164    eBlocking,
    165    eDeferred,
    166    eAsync,
    167    eLinkPreload  // this is a load initiated by <link rel="preload"
    168                  // as="script"> or <link rel="modulepreload"> tag
    169  };
    170 
    171  void SetScriptMode(bool aDeferAttr, bool aAsyncAttr, bool aLinkPreload);
    172 
    173  bool IsLinkPreloadScript() const {
    174    return mScriptMode == ScriptMode::eLinkPreload;
    175  }
    176 
    177  bool IsBlockingScript() const { return mScriptMode == ScriptMode::eBlocking; }
    178 
    179  bool IsDeferredScript() const { return mScriptMode == ScriptMode::eDeferred; }
    180 
    181  bool IsAsyncScript() const { return mScriptMode == ScriptMode::eAsync; }
    182 
    183  // Accessors for the script element, for each purpose.
    184  //
    185  // The script element reference is guaranteed to be available only for:
    186  //   * inline/external classic script
    187  //   * inline/external top-level module
    188  //
    189  // The reference is valid only for specific purpose explained below.
    190 
    191  // For aLoadingNode parameter of a new channel.
    192  // TODO: This is basically unnecessary and a document can be used instead.
    193  //       Remove this.
    194  inline nsIScriptElement* GetScriptElementForLoadingNode() const {
    195    MOZ_ASSERT(mScriptElement);
    196    return mScriptElement;
    197  }
    198 
    199  // For TRACE_FOR_TEST macros.
    200  // NOTE: This is called also for imported modules.
    201  //       The consumer allows nullptr.
    202  inline nsIScriptElement* GetScriptElementForTrace() const {
    203    return mScriptElement;
    204  }
    205 
    206  // For ScriptLoader::mCurrentParserInsertedScript.
    207  inline nsIScriptElement* GetScriptElementForCurrentParserInsertedScript()
    208      const {
    209    MOZ_ASSERT(mScriptElement);
    210    return mScriptElement;
    211  }
    212 
    213  // For nsIScriptLoaderObserver.
    214  inline nsIScriptElement* GetScriptElementForObserver() const {
    215    MOZ_ASSERT(mScriptElement);
    216    return mScriptElement;
    217  }
    218 
    219  // For URL classifier.
    220  inline nsIScriptElement* GetScriptElementForUrlClassifier() const {
    221    return mScriptElement;
    222  }
    223 
    224  // For AutoCurrentScriptUpdater.
    225  // This is valid only for classic script.
    226  inline nsIScriptElement* GetScriptElementForCurrentScript() const {
    227    MOZ_ASSERT(mScriptElement);
    228    return mScriptElement;
    229  }
    230 
    231  bool HasScriptElement() const;
    232 
    233  void GetInlineScriptText(nsAString& aText) const;
    234 
    235  void GetHintCharset(nsAString& aCharset) const;
    236 
    237  // TODO: Reimplement with mLineNo/mColumnNo.
    238  uint32_t GetScriptLineNumber() const;
    239  JS::ColumnNumberOneOrigin GetScriptColumnNumber() const;
    240 
    241  void BeginEvaluatingTopLevel() const;
    242  void EndEvaluatingTopLevel() const;
    243 
    244  void UnblockParser() const;
    245  void ContinueParserAsync() const;
    246 
    247  Document* GetScriptOwnerDocument() const;
    248 
    249  // Make this request a preload (speculative) request.
    250  void SetIsPreloadRequest() {
    251    MOZ_ASSERT(!HasScriptElement());
    252    MOZ_ASSERT(!IsPreload());
    253    mIsPreload = true;
    254  }
    255 
    256  // Make a preload request into an actual load request for the given element.
    257  void SetIsLoadRequest(nsIScriptElement* aElement);
    258 
    259  FromParser GetParserCreated() const {
    260    if (!mScriptElement) {
    261      return NOT_FROM_PARSER;
    262    }
    263    return mScriptElement->GetParserCreated();
    264  }
    265 
    266  // Used to output a string for the Gecko Profiler.
    267  void GetProfilerLabel(nsACString& aOutString) override;
    268 
    269  void MaybeCancelOffThreadScript();
    270 
    271  // Finish the off-main-thread compilation and return the result, or
    272  // convert the compilation error to runtime error.
    273  already_AddRefed<JS::Stencil> StealOffThreadResult(
    274      JSContext* aCx, JS::InstantiationStorage* aInstantiationStorage);
    275 
    276  ScriptMode mScriptMode;  // Whether this is a blocking, defer or async script.
    277  bool mScriptFromHead;    // Synchronous head script block loading of other non
    278                           // js/css content.
    279  bool mIsInline;          // Is the script inline or loaded?
    280  bool mInDeferList;       // True if we live in mDeferRequests.
    281  bool mInAsyncList;       // True if we live in mLoadingAsyncRequests or
    282                           // mLoadedAsyncRequests.
    283  bool mIsNonAsyncScriptInserted;  // True if we live in
    284                                   // mNonAsyncExternalScriptInsertedRequests
    285  bool mIsXSLT;                    // True if we live in mXSLTRequests.
    286  bool mInCompilingList;     // True if we are in mOffThreadCompilingRequests.
    287  net::ClassificationFlags   // Classification flags
    288      mClassificationFlags;  // of the source of the script.
    289  bool mWasCompiledOMT;      // True if the script has been compiled off main
    290                             // thread.
    291 
    292  // Task that performs off-thread compilation or off-thread decode.
    293  // This field is used to take the result of the task, or cancel the task.
    294  //
    295  // Set to non-null on the task creation, and set to null when taking the
    296  // result or cancelling the task.
    297  RefPtr<CompileOrDecodeTask> mCompileOrDecodeTask;
    298 
    299  uint32_t mLineNo;
    300  JS::ColumnNumberOneOrigin mColumnNo;
    301 
    302  // Set on scripts and top level modules.
    303  bool mIsPreload;
    304 
    305  // Non-null if there is a document that this request is blocking from loading.
    306  RefPtr<Document> mLoadBlockedDocument;
    307 
    308  // The script element which trigerred this script load.
    309  // This is valid only for classic script and top-level module script.
    310  nsCOMPtr<nsIScriptElement> mScriptElement;
    311 
    312  nsString mSourceText;
    313 
    314  // For preload requests, we defer reporting errors to the console until the
    315  // request is used.
    316  nsresult mUnreportedPreloadError;
    317 };
    318 
    319 }  // namespace mozilla::dom
    320 
    321 #endif  // mozilla_dom_ScriptLoadContext_h