tor-browser

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

CompileOptions.h (32523B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /*
      7 * Options for JavaScript compilation.
      8 *
      9 * In the most common use case, a CompileOptions instance is allocated on the
     10 * stack, and holds non-owning references to non-POD option values: strings,
     11 * principals, objects, and so on.  The code declaring the instance guarantees
     12 * that such option values will outlive the CompileOptions itself: objects are
     13 * otherwise rooted, principals have had their reference counts bumped, and
     14 * strings won't be freed until the CompileOptions goes out of scope.  In this
     15 * situation, CompileOptions only refers to things others own, so it can be
     16 * lightweight.
     17 *
     18 * In some cases, however, we need to hold compilation options with a
     19 * non-stack-like lifetime.  For example, JS::CompileOffThread needs to save
     20 * compilation options where a worker thread can find them, then return
     21 * immediately.  The worker thread will come along at some later point, and use
     22 * the options.
     23 *
     24 * The compiler itself just needs to be able to access a collection of options;
     25 * it doesn't care who owns them, or what's keeping them alive.  It does its
     26 * own addrefs/copies/tracing/etc.
     27 *
     28 * Furthermore, in some cases compile options are propagated from one entity to
     29 * another (e.g. from a script to a function defined in that script).  This
     30 * involves copying over some, but not all, of the options.
     31 *
     32 * So we have a class hierarchy that reflects these four use cases:
     33 *
     34 * - TransitiveCompileOptions is the common base class, representing options
     35 *   that should get propagated from a script to functions defined in that
     36 *   script.  This class is abstract and is only ever used as a subclass.
     37 *
     38 * - ReadOnlyCompileOptions is the only subclass of TransitiveCompileOptions,
     39 *   representing a full set of compile options.  It can be used by code that
     40 *   simply needs to access options set elsewhere, like the compiler.  This
     41 *   class too is abstract and is only ever used as a subclass.
     42 *
     43 * - The usual CompileOptions class must be stack-allocated, and holds
     44 *   non-owning references to the filename, element, and so on. It's derived
     45 *   from ReadOnlyCompileOptions, so the compiler can use it.
     46 *
     47 * - OwningCompileOptions roots / copies / reference counts of all its values,
     48 *   and unroots / frees / releases them when it is destructed. It too is
     49 *   derived from ReadOnlyCompileOptions, so the compiler accepts it.
     50 */
     51 
     52 #ifndef js_CompileOptions_h
     53 #define js_CompileOptions_h
     54 
     55 #include "mozilla/Assertions.h"       // MOZ_ASSERT
     56 #include "mozilla/MemoryReporting.h"  // mozilla::MallocSizeOf
     57 
     58 #include <stddef.h>  // size_t
     59 #include <stdint.h>  // uint8_t, uint32_t
     60 
     61 #include "jstypes.h"  // JS_PUBLIC_API
     62 
     63 #include "js/CharacterEncoding.h"  // JS::ConstUTF8CharsZ
     64 #include "js/ColumnNumber.h"       // JS::ColumnNumberOneOrigin
     65 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     66 #  include "js/Prefs.h"  // JS::Prefs::*
     67 #endif
     68 #include "js/TypeDecls.h"  // JS::MutableHandle (fwd)
     69 
     70 namespace js {
     71 class FrontendContext;
     72 }  // namespace js
     73 
     74 namespace JS {
     75 using FrontendContext = js::FrontendContext;
     76 
     77 enum class AsmJSOption : uint8_t {
     78  Enabled,
     79  DisabledByAsmJSPref,
     80  DisabledByLinker,
     81  DisabledByNoWasmCompiler,
     82  DisabledByDebugger,
     83 };
     84 
     85 #define FOREACH_DELAZIFICATION_STRATEGY(_)                                     \
     86  /* Do not delazify anything eagerly. */                                      \
     87  _(OnDemandOnly)                                                              \
     88                                                                               \
     89  /*                                                                           \
     90   * Compare the stencil produced by concurrent depth first delazification and \
     91   * on-demand delazification. Any differences would crash SpiderMonkey with   \
     92   * an assertion.                                                             \
     93   */                                                                          \
     94  _(CheckConcurrentWithOnDemand)                                               \
     95                                                                               \
     96  /*                                                                           \
     97   * Delazifiy functions in a depth first traversal of the functions.          \
     98   */                                                                          \
     99  _(ConcurrentDepthFirst)                                                      \
    100                                                                               \
    101  /*                                                                           \
    102   * Delazifiy functions strating with the largest function first.             \
    103   */                                                                          \
    104  _(ConcurrentLargeFirst)                                                      \
    105                                                                               \
    106  /*                                                                           \
    107   * Parse everything eagerly, from the first parse.                           \
    108   *                                                                           \
    109   * NOTE: Either the Realm configuration or specialized VM operating modes    \
    110   * may disallow syntax-parse altogether. These conditions are checked in the \
    111   * CompileOptions constructor.                                               \
    112   */                                                                          \
    113  _(ParseEverythingEagerly)
    114 
    115 enum class DelazificationOption : uint8_t {
    116 #define _ENUM_ENTRY(Name) Name,
    117  FOREACH_DELAZIFICATION_STRATEGY(_ENUM_ENTRY)
    118 #undef _ENUM_ENTRY
    119 };
    120 
    121 enum class EagerBaselineOption : uint8_t { None, JitHints, Aggressive };
    122 
    123 class JS_PUBLIC_API InstantiateOptions;
    124 class JS_PUBLIC_API ReadOnlyDecodeOptions;
    125 
    126 // Compilation-specific part of JS::ContextOptions which is supposed to be
    127 // configured by user prefs.
    128 class JS_PUBLIC_API PrefableCompileOptions {
    129 public:
    130  PrefableCompileOptions()
    131      : sourcePragmas_(true),
    132 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    133        explicitResourceManagement_(
    134            JS::Prefs::experimental_explicit_resource_management()),
    135 #endif
    136        throwOnAsmJSValidationFailure_(false) {
    137  }
    138 
    139 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    140  bool explicitResourceManagement() const {
    141    return explicitResourceManagement_;
    142  }
    143  PrefableCompileOptions& setExplicitResourceManagement(bool enabled) {
    144    explicitResourceManagement_ = enabled;
    145    return *this;
    146  }
    147 #endif
    148 
    149  // Enable/disable support for parsing '//(#@) source(Mapping)?URL=' pragmas.
    150  bool sourcePragmas() const { return sourcePragmas_; }
    151  PrefableCompileOptions& setSourcePragmas(bool flag) {
    152    sourcePragmas_ = flag;
    153    return *this;
    154  }
    155 
    156  AsmJSOption asmJSOption() const { return asmJSOption_; }
    157  PrefableCompileOptions& setAsmJS(bool flag) {
    158    asmJSOption_ =
    159        flag ? AsmJSOption::Enabled : AsmJSOption::DisabledByAsmJSPref;
    160    return *this;
    161  }
    162  PrefableCompileOptions& setAsmJSOption(AsmJSOption option) {
    163    asmJSOption_ = option;
    164    return *this;
    165  }
    166 
    167  bool throwOnAsmJSValidationFailure() const {
    168    return throwOnAsmJSValidationFailure_;
    169  }
    170  PrefableCompileOptions& setThrowOnAsmJSValidationFailure(bool flag) {
    171    throwOnAsmJSValidationFailure_ = flag;
    172    return *this;
    173  }
    174  PrefableCompileOptions& toggleThrowOnAsmJSValidationFailure() {
    175    throwOnAsmJSValidationFailure_ = !throwOnAsmJSValidationFailure_;
    176    return *this;
    177  }
    178 
    179 #if defined(DEBUG) || defined(JS_JITSPEW)
    180  template <typename Printer>
    181  void dumpWith(Printer& print) const {
    182 #  define PrintFields_(Name) print(#Name, Name)
    183    PrintFields_(sourcePragmas_);
    184    PrintFields_(throwOnAsmJSValidationFailure_);
    185 #  ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    186    PrintFields_(explicitResourceManagement_);
    187 #  endif
    188 #  undef PrintFields_
    189 
    190    switch (asmJSOption_) {
    191      case AsmJSOption::Enabled:
    192        print("asmJSOption_", "AsmJSOption::Enabled");
    193        break;
    194      case AsmJSOption::DisabledByAsmJSPref:
    195        print("asmJSOption_", "AsmJSOption::DisabledByAsmJSPref");
    196        break;
    197      case AsmJSOption::DisabledByLinker:
    198        print("asmJSOption_", "AsmJSOption::DisabledByLinker");
    199        break;
    200      case AsmJSOption::DisabledByNoWasmCompiler:
    201        print("asmJSOption_", "AsmJSOption::DisabledByNoWasmCompiler");
    202        break;
    203      case AsmJSOption::DisabledByDebugger:
    204        print("asmJSOption_", "AsmJSOption::DisabledByDebugger");
    205        break;
    206    }
    207  }
    208 #endif  // defined(DEBUG) || defined(JS_JITSPEW)
    209 
    210 private:
    211  // ==== Syntax-related options. ====
    212 
    213  // The context has specified that source pragmas should be parsed.
    214  bool sourcePragmas_ : 1;
    215 
    216 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    217  // The context has specified that explicit resource management syntax
    218  // should be parsed.
    219  bool explicitResourceManagement_ : 1;
    220 #endif
    221 
    222  // ==== asm.js options. ====
    223  bool throwOnAsmJSValidationFailure_ : 1;
    224 
    225  AsmJSOption asmJSOption_ = AsmJSOption::DisabledByAsmJSPref;
    226 };
    227 
    228 /**
    229 * The common base class for the CompileOptions hierarchy.
    230 *
    231 * Use this in code that needs to propagate compile options from one
    232 * compilation unit to another.
    233 */
    234 class JS_PUBLIC_API TransitiveCompileOptions {
    235  friend class JS_PUBLIC_API ReadOnlyDecodeOptions;
    236 
    237 protected:
    238  // non-POD options:
    239 
    240  JS::ConstUTF8CharsZ filename_;
    241 
    242  JS::ConstUTF8CharsZ introducerFilename_;
    243 
    244  const char16_t* sourceMapURL_ = nullptr;
    245 
    246  // POD options:
    247  // WARNING: When adding new fields, don't forget to add them to
    248  //          copyPODTransitiveOptions.
    249 
    250  /**
    251   * The Web Platform allows scripts to be loaded from arbitrary cross-origin
    252   * sources. This allows an attack by which a malicious website loads a
    253   * sensitive file (say, a bank statement) cross-origin (using the user's
    254   * cookies), and sniffs the generated syntax errors (via a window.onerror
    255   * handler) for juicy morsels of its contents.
    256   *
    257   * To counter this attack, HTML5 specifies that script errors should be
    258   * sanitized ("muted") when the script is not same-origin with the global
    259   * for which it is loaded. Callers should set this flag for cross-origin
    260   * scripts, and it will be propagated appropriately to child scripts and
    261   * passed back in JSErrorReports.
    262   */
    263  bool mutedErrors_ = false;
    264 
    265  // Either the Realm configuration or the compile request may force
    266  // strict-mode.
    267  bool forceStrictMode_ = false;
    268 
    269  // The Realm of this script is configured to use fdlibm math library.
    270  bool alwaysUseFdlibm_ = false;
    271 
    272  // Flag used to bypass the filename validation callback.
    273  // See also SetFilenameValidationCallback.
    274  bool skipFilenameValidation_ = false;
    275 
    276  bool hideScriptFromDebugger_ = false;
    277 
    278  // If set, this script will be hidden from the debugger. The requirement
    279  // is that once compilation is finished, a call to UpdateDebugMetadata will
    280  // be made, which will update the SSO with the appropiate debug metadata,
    281  // and expose the script to the debugger (if hideScriptFromDebugger_ isn't
    282  // set)
    283  bool deferDebugMetadata_ = false;
    284 
    285  // Off-thread delazification strategy is used to tell off-thread tasks how the
    286  // delazification should be performed. Multiple strategies are available in
    287  // order to test different approaches to the concurrent delazification.
    288  DelazificationOption eagerDelazificationStrategy_ =
    289      DelazificationOption::OnDemandOnly;
    290 
    291  // The eager baseline strategy option indicates whether functions should be
    292  // OMT baseline compiled eagerly whenever bytecode is available and whether
    293  // JitHints should be used or not.  Eager baseline compilations are not
    294  // currently enabled for delazifications, and explicitly set to None for
    295  // delazifications.
    296  EagerBaselineOption eagerBaselineStrategy_ = EagerBaselineOption::None;
    297 
    298  friend class JS_PUBLIC_API InstantiateOptions;
    299 
    300 public:
    301  bool selfHostingMode = false;
    302  bool discardSource = false;
    303  bool sourceIsLazy = false;
    304  bool allowHTMLComments = true;
    305  bool nonSyntacticScope = false;
    306 
    307  // Top-level await is enabled by default but is not supported for chrome
    308  // modules loaded with ChromeUtils.importModule.
    309  bool topLevelAwait = true;
    310 
    311  // When decoding from XDR into a Stencil, directly reference data in the
    312  // buffer (where possible) instead of copying it. This is an optional
    313  // performance optimization, and may also reduce memory if the buffer is going
    314  // remain alive anyways.
    315  //
    316  // NOTE: The XDR buffer must remain alive as long as the Stencil does. Special
    317  //       care must be taken that there are no addition shared references to
    318  //       the Stencil.
    319  //
    320  // NOTE: Instantiated GC things may still outlive the buffer as long as the
    321  //       Stencil was cleaned up. This is covers a typical case where a decoded
    322  //       Stencil is instantiated once and then thrown away.
    323  bool borrowBuffer = false;
    324 
    325  // Similar to `borrowBuffer`, but additionally the JSRuntime may directly
    326  // reference data in the buffer for JS bytecode. The `borrowBuffer` flag must
    327  // be set if this is set. This can be a memory optimization in multi-process
    328  // architectures where a (read-only) XDR buffer is mapped into multiple
    329  // processes.
    330  //
    331  // NOTE: When using this mode, the XDR buffer must live until JS_Shutdown is
    332  // called. There is currently no mechanism to release the data sooner.
    333  bool usePinnedBytecode = false;
    334 
    335  PrefableCompileOptions prefableOptions_;
    336 
    337  /**
    338   * |introductionType| is a statically allocated C string. See JSScript.h
    339   * for more information.
    340   */
    341  const char* introductionType = nullptr;
    342 
    343  unsigned introductionLineno = 0;
    344  uint32_t introductionOffset = 0;
    345  bool hasIntroductionInfo = false;
    346 
    347  // WARNING: When adding new fields, don't forget to add them to
    348  //          copyPODTransitiveOptions.
    349 
    350 protected:
    351  TransitiveCompileOptions() = default;
    352 
    353  // Set all POD options (those not requiring reference counts, copies,
    354  // rooting, or other hand-holding) to their values in |rhs|.
    355  void copyPODTransitiveOptions(const TransitiveCompileOptions& rhs);
    356 
    357  bool isEagerDelazificationEqualTo(DelazificationOption val) const {
    358    return eagerDelazificationStrategy() == val;
    359  }
    360 
    361  template <DelazificationOption... Values>
    362  bool eagerDelazificationIsOneOf() const {
    363    return (isEagerDelazificationEqualTo(Values) || ...);
    364  }
    365 
    366 public:
    367  // Read-only accessors for non-POD options. The proper way to set these
    368  // depends on the derived type.
    369  bool mutedErrors() const { return mutedErrors_; }
    370  bool alwaysUseFdlibm() const { return alwaysUseFdlibm_; }
    371  bool forceFullParse() const {
    372    return eagerDelazificationIsOneOf<
    373        DelazificationOption::ParseEverythingEagerly>();
    374  }
    375  bool forceStrictMode() const { return forceStrictMode_; }
    376  bool consumeDelazificationCache() const {
    377    return eagerDelazificationIsOneOf<
    378        DelazificationOption::ConcurrentDepthFirst,
    379        DelazificationOption::ConcurrentLargeFirst>();
    380  }
    381  bool populateDelazificationCache() const {
    382    return eagerDelazificationIsOneOf<
    383        DelazificationOption::CheckConcurrentWithOnDemand,
    384        DelazificationOption::ConcurrentDepthFirst,
    385        DelazificationOption::ConcurrentLargeFirst>();
    386  }
    387  bool waitForDelazificationCache() const {
    388    return eagerDelazificationIsOneOf<
    389        DelazificationOption::CheckConcurrentWithOnDemand>();
    390  }
    391  bool checkDelazificationCache() const {
    392    return eagerDelazificationIsOneOf<
    393        DelazificationOption::CheckConcurrentWithOnDemand>();
    394  }
    395  DelazificationOption eagerDelazificationStrategy() const {
    396    return eagerDelazificationStrategy_;
    397  }
    398  EagerBaselineOption eagerBaselineStrategy() const {
    399    return eagerBaselineStrategy_;
    400  }
    401 
    402  bool sourcePragmas() const { return prefableOptions_.sourcePragmas(); }
    403 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    404  bool explicitResourceManagement() const {
    405    return prefableOptions_.explicitResourceManagement();
    406  }
    407 #endif
    408  bool throwOnAsmJSValidationFailure() const {
    409    return prefableOptions_.throwOnAsmJSValidationFailure();
    410  }
    411  AsmJSOption asmJSOption() const { return prefableOptions_.asmJSOption(); }
    412  void setAsmJSOption(AsmJSOption option) {
    413    prefableOptions_.setAsmJSOption(option);
    414  }
    415 
    416  JS::ConstUTF8CharsZ filename() const { return filename_; }
    417  JS::ConstUTF8CharsZ introducerFilename() const { return introducerFilename_; }
    418  const char16_t* sourceMapURL() const { return sourceMapURL_; }
    419 
    420  const PrefableCompileOptions& prefableOptions() const {
    421    return prefableOptions_;
    422  }
    423 
    424  TransitiveCompileOptions(const TransitiveCompileOptions&) = delete;
    425  TransitiveCompileOptions& operator=(const TransitiveCompileOptions&) = delete;
    426 
    427 #if defined(DEBUG) || defined(JS_JITSPEW)
    428  template <typename Printer>
    429  void dumpWith(Printer& print) const {
    430 #  define PrintFields_(Name) print(#Name, Name)
    431    PrintFields_(filename_);
    432    PrintFields_(introducerFilename_);
    433    PrintFields_(sourceMapURL_);
    434    PrintFields_(mutedErrors_);
    435    PrintFields_(forceStrictMode_);
    436    PrintFields_(alwaysUseFdlibm_);
    437    PrintFields_(skipFilenameValidation_);
    438    PrintFields_(hideScriptFromDebugger_);
    439    PrintFields_(deferDebugMetadata_);
    440    PrintFields_(eagerDelazificationStrategy_);
    441    PrintFields_(eagerBaselineStrategy_);
    442    PrintFields_(selfHostingMode);
    443    PrintFields_(discardSource);
    444    PrintFields_(sourceIsLazy);
    445    PrintFields_(allowHTMLComments);
    446    PrintFields_(nonSyntacticScope);
    447    PrintFields_(topLevelAwait);
    448    PrintFields_(borrowBuffer);
    449    PrintFields_(usePinnedBytecode);
    450    PrintFields_(introductionType);
    451    PrintFields_(introductionLineno);
    452    PrintFields_(introductionOffset);
    453    PrintFields_(hasIntroductionInfo);
    454 #  undef PrintFields_
    455 
    456    prefableOptions_.dumpWith(print);
    457  }
    458 #endif  // defined(DEBUG) || defined(JS_JITSPEW)
    459 };
    460 
    461 /**
    462 * The class representing a full set of compile options.
    463 *
    464 * Use this in code that only needs to access compilation options created
    465 * elsewhere, like the compiler.  Don't instantiate this class (the constructor
    466 * is protected anyway); instead, create instances only of the derived classes:
    467 * CompileOptions and OwningCompileOptions.
    468 */
    469 class JS_PUBLIC_API ReadOnlyCompileOptions : public TransitiveCompileOptions {
    470 public:
    471  // POD options.
    472 
    473  // Line number of the first character (1-origin).
    474  uint32_t lineno = 1;
    475  // Column number of the first character in UTF-16 code units.
    476  JS::ColumnNumberOneOrigin column;
    477 
    478  // The offset within the ScriptSource's full uncompressed text of the first
    479  // character we're presenting for compilation with this CompileOptions.
    480  //
    481  // When we compile a lazy script, we pass the compiler only the substring of
    482  // the source the lazy function occupies. With chunked decompression, we may
    483  // not even have the complete uncompressed source present in memory. But parse
    484  // node positions are offsets within the ScriptSource's full text, and
    485  // BaseScript indicate their substring of the full source by its starting and
    486  // ending offsets within the full text. This scriptSourceOffset field lets the
    487  // frontend convert between these offsets and offsets within the substring
    488  // presented for compilation.
    489  unsigned scriptSourceOffset = 0;
    490 
    491  // These only apply to non-function scripts.
    492  bool isRunOnce = false;
    493  bool noScriptRval = false;
    494 
    495 protected:
    496  ReadOnlyCompileOptions() = default;
    497 
    498  void copyPODNonTransitiveOptions(const ReadOnlyCompileOptions& rhs);
    499 
    500  ReadOnlyCompileOptions(const ReadOnlyCompileOptions&) = delete;
    501  ReadOnlyCompileOptions& operator=(const ReadOnlyCompileOptions&) = delete;
    502 
    503 public:
    504 #if defined(DEBUG) || defined(JS_JITSPEW)
    505  template <typename Printer>
    506  void dumpWith(Printer& print) const {
    507    this->TransitiveCompileOptions::dumpWith(print);
    508 #  define PrintFields_(Name) print(#Name, Name)
    509    PrintFields_(lineno);
    510    print("column", column.oneOriginValue());
    511    PrintFields_(scriptSourceOffset);
    512    PrintFields_(isRunOnce);
    513    PrintFields_(noScriptRval);
    514 #  undef PrintFields_
    515  }
    516 #endif  // defined(DEBUG) || defined(JS_JITSPEW)
    517 };
    518 
    519 class JS_PUBLIC_API OwningDecodeOptions;
    520 
    521 /**
    522 * Compilation options, with dynamic lifetime. An instance of this type
    523 * makes a copy of / holds / roots all dynamically allocated resources
    524 * (principals; elements; strings) that it refers to. Its destructor frees
    525 * / drops / unroots them. This is heavier than CompileOptions, below, but
    526 * unlike CompileOptions, it can outlive any given stack frame.
    527 *
    528 * Note that this *roots* any JS values it refers to - they're live
    529 * unconditionally. Thus, instances of this type can't be owned, directly
    530 * or indirectly, by a JavaScript object: if any value that this roots ever
    531 * comes to refer to the object that owns this, then the whole cycle, and
    532 * anything else it entrains, will never be freed.
    533 */
    534 class JS_PUBLIC_API OwningCompileOptions final : public ReadOnlyCompileOptions {
    535 public:
    536  // A minimal constructor, for use with OwningCompileOptions::copy.
    537  explicit OwningCompileOptions(JSContext* cx);
    538 
    539  struct ForFrontendContext {};
    540  explicit OwningCompileOptions(const ForFrontendContext&)
    541      : ReadOnlyCompileOptions() {}
    542 
    543  ~OwningCompileOptions();
    544 
    545 private:
    546  template <typename ContextT>
    547  bool copyImpl(ContextT* cx, const ReadOnlyCompileOptions& rhs);
    548 
    549 public:
    550  /** Set this to a copy of |rhs|.  Return false on OOM. */
    551  bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs);
    552  bool copy(JS::FrontendContext* fc, const ReadOnlyCompileOptions& rhs);
    553 
    554  void steal(OwningCompileOptions&& rhs);
    555  void steal(OwningDecodeOptions&& rhs);
    556 
    557  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    558 
    559  OwningCompileOptions& setIsRunOnce(bool once) {
    560    isRunOnce = once;
    561    return *this;
    562  }
    563 
    564  OwningCompileOptions& setForceStrictMode() {
    565    forceStrictMode_ = true;
    566    return *this;
    567  }
    568 
    569  OwningCompileOptions& setModule() {
    570    // ES6 10.2.1 Module code is always strict mode code.
    571    setForceStrictMode();
    572    setIsRunOnce(true);
    573    allowHTMLComments = false;
    574    return *this;
    575  }
    576 
    577 private:
    578  void release();
    579 
    580  OwningCompileOptions(const OwningCompileOptions&) = delete;
    581  OwningCompileOptions& operator=(const OwningCompileOptions&) = delete;
    582 };
    583 
    584 /**
    585 * Compilation options stored on the stack. An instance of this type
    586 * simply holds references to dynamically allocated resources (element;
    587 * filename; source map URL) that are owned by something else. If you
    588 * create an instance of this type, it's up to you to guarantee that
    589 * everything you store in it will outlive it.
    590 */
    591 class MOZ_STACK_CLASS JS_PUBLIC_API CompileOptions final
    592    : public ReadOnlyCompileOptions {
    593 public:
    594  // Default options determined using the JSContext.
    595  explicit CompileOptions(JSContext* cx);
    596 
    597  // Copy both the transitive and the non-transitive options from another
    598  // options object.
    599  CompileOptions(JSContext* cx, const ReadOnlyCompileOptions& rhs)
    600      : ReadOnlyCompileOptions() {
    601    copyPODNonTransitiveOptions(rhs);
    602    copyPODTransitiveOptions(rhs);
    603 
    604    filename_ = rhs.filename();
    605    introducerFilename_ = rhs.introducerFilename();
    606    sourceMapURL_ = rhs.sourceMapURL();
    607  }
    608 
    609  // Construct a CompileOption in the context where JSContext is not available.
    610  // prefableOptions should reflect the compilation-specific user prefs.
    611  explicit CompileOptions(const PrefableCompileOptions& prefableOptions)
    612      : ReadOnlyCompileOptions() {
    613    prefableOptions_ = prefableOptions;
    614  }
    615 
    616  CompileOptions& setFile(const char* f) {
    617    filename_ = JS::ConstUTF8CharsZ(f);
    618    return *this;
    619  }
    620 
    621  CompileOptions& setLine(uint32_t l) {
    622    lineno = l;
    623    return *this;
    624  }
    625 
    626  CompileOptions& setFileAndLine(const char* f, uint32_t l) {
    627    filename_ = JS::ConstUTF8CharsZ(f);
    628    lineno = l;
    629    return *this;
    630  }
    631 
    632  CompileOptions& setSourceMapURL(const char16_t* s) {
    633    sourceMapURL_ = s;
    634    return *this;
    635  }
    636 
    637  CompileOptions& setMutedErrors(bool mute) {
    638    mutedErrors_ = mute;
    639    return *this;
    640  }
    641 
    642  CompileOptions& setColumn(JS::ColumnNumberOneOrigin c) {
    643    column = c;
    644    return *this;
    645  }
    646 
    647  CompileOptions& setScriptSourceOffset(unsigned o) {
    648    scriptSourceOffset = o;
    649    return *this;
    650  }
    651 
    652  CompileOptions& setIsRunOnce(bool once) {
    653    isRunOnce = once;
    654    return *this;
    655  }
    656 
    657  CompileOptions& setNoScriptRval(bool nsr) {
    658    noScriptRval = nsr;
    659    return *this;
    660  }
    661 
    662  CompileOptions& setSkipFilenameValidation(bool b) {
    663    skipFilenameValidation_ = b;
    664    return *this;
    665  }
    666 
    667  CompileOptions& setSelfHostingMode(bool shm) {
    668    selfHostingMode = shm;
    669    return *this;
    670  }
    671 
    672  CompileOptions& setSourceIsLazy(bool l) {
    673    sourceIsLazy = l;
    674    return *this;
    675  }
    676 
    677  CompileOptions& setNonSyntacticScope(bool n) {
    678    nonSyntacticScope = n;
    679    return *this;
    680  }
    681 
    682  CompileOptions& setIntroductionType(const char* t) {
    683    introductionType = t;
    684    return *this;
    685  }
    686 
    687  CompileOptions& setDeferDebugMetadata(bool v = true) {
    688    deferDebugMetadata_ = v;
    689    return *this;
    690  }
    691 
    692  CompileOptions& setHideScriptFromDebugger(bool v = true) {
    693    hideScriptFromDebugger_ = v;
    694    return *this;
    695  }
    696 
    697  CompileOptions& setIntroductionInfo(const char* introducerFn,
    698                                      const char* intro, uint32_t line,
    699                                      uint32_t offset) {
    700    introducerFilename_ = JS::ConstUTF8CharsZ(introducerFn);
    701    introductionType = intro;
    702    introductionLineno = line;
    703    introductionOffset = offset;
    704    hasIntroductionInfo = true;
    705    return *this;
    706  }
    707 
    708  // Set introduction information according to any currently executing script.
    709  CompileOptions& setIntroductionInfoToCaller(
    710      JSContext* cx, const char* introductionType,
    711      JS::MutableHandle<JSScript*> introductionScript);
    712 
    713  CompileOptions& setDiscardSource() {
    714    discardSource = true;
    715    return *this;
    716  }
    717 
    718  CompileOptions& setForceFullParse() {
    719    eagerDelazificationStrategy_ = DelazificationOption::ParseEverythingEagerly;
    720    return *this;
    721  }
    722 
    723  void warnAboutConflictingDelazification() const;
    724  CompileOptions& setEagerDelazificationStrategy(
    725      DelazificationOption strategy) {
    726    const auto PEE = DelazificationOption::ParseEverythingEagerly;
    727    if (eagerDelazificationStrategy_ == PEE && strategy != PEE) {
    728      // Parse Everything Eagerly cannot be replaced, do noting.
    729      warnAboutConflictingDelazification();
    730      return *this;
    731    }
    732 
    733    eagerDelazificationStrategy_ = strategy;
    734    return *this;
    735  }
    736 
    737  CompileOptions& setEagerBaselineStrategy(EagerBaselineOption strategy) {
    738    eagerBaselineStrategy_ = strategy;
    739    return *this;
    740  }
    741 
    742  CompileOptions& setForceStrictMode() {
    743    forceStrictMode_ = true;
    744    return *this;
    745  }
    746 
    747  CompileOptions& setModule() {
    748    // ES6 10.2.1 Module code is always strict mode code.
    749    setForceStrictMode();
    750    setIsRunOnce(true);
    751    allowHTMLComments = false;
    752    return *this;
    753  }
    754 
    755  CompileOptions(const CompileOptions& rhs) = delete;
    756  CompileOptions& operator=(const CompileOptions& rhs) = delete;
    757 };
    758 
    759 /**
    760 * Subset of CompileOptions fields used while instantiating Stencils.
    761 */
    762 class JS_PUBLIC_API InstantiateOptions {
    763 public:
    764  bool skipFilenameValidation = false;
    765  bool hideScriptFromDebugger = false;
    766  bool deferDebugMetadata = false;
    767  DelazificationOption eagerDelazificationStrategy_ =
    768      DelazificationOption::OnDemandOnly;
    769 
    770  EagerBaselineOption eagerBaselineStrategy_ = EagerBaselineOption::None;
    771 
    772  InstantiateOptions();
    773 
    774  explicit InstantiateOptions(const ReadOnlyCompileOptions& options)
    775      : skipFilenameValidation(options.skipFilenameValidation_),
    776        hideScriptFromDebugger(options.hideScriptFromDebugger_),
    777        deferDebugMetadata(options.deferDebugMetadata_),
    778        eagerDelazificationStrategy_(options.eagerDelazificationStrategy()),
    779        eagerBaselineStrategy_(options.eagerBaselineStrategy_) {}
    780 
    781  void copyTo(CompileOptions& options) const {
    782    options.skipFilenameValidation_ = skipFilenameValidation;
    783    options.hideScriptFromDebugger_ = hideScriptFromDebugger;
    784    options.deferDebugMetadata_ = deferDebugMetadata;
    785    options.setEagerDelazificationStrategy(eagerDelazificationStrategy_);
    786    options.setEagerBaselineStrategy(eagerBaselineStrategy_);
    787  }
    788 
    789  bool hideFromNewScriptInitial() const {
    790    return deferDebugMetadata || hideScriptFromDebugger;
    791  }
    792 
    793 #ifdef DEBUG
    794  // Assert that all fields have default value.
    795  //
    796  // This can be used when instantiation is performed as separate step than
    797  // compile-to-stencil, and CompileOptions isn't available there.
    798  void assertDefault() const {
    799    MOZ_ASSERT(skipFilenameValidation == false);
    800    MOZ_ASSERT(hideScriptFromDebugger == false);
    801    MOZ_ASSERT(deferDebugMetadata == false);
    802    MOZ_ASSERT(eagerDelazificationStrategy_ ==
    803               DelazificationOption::OnDemandOnly);
    804    MOZ_ASSERT(eagerBaselineStrategy_ == EagerBaselineOption::None);
    805  }
    806 
    807  // Assert that all fields have values compatible with the default value.
    808  //
    809  // This can be used in the same way as assertDefault, in case the
    810  // setForceFullParse() is used on the original compile options.
    811  void assertCompatibleWithDefault() const {
    812    MOZ_ASSERT(skipFilenameValidation == false);
    813    MOZ_ASSERT(hideScriptFromDebugger == false);
    814    MOZ_ASSERT(deferDebugMetadata == false);
    815 
    816    // The instantiation step uses the eagerDelazificationStrategy_ field
    817    // only for TransitiveCompileOptions::populateDelazificationCache().
    818    //
    819    // Both the default OnDemandOnly and
    820    // the ParseEverythingEagerly from setForceFullParse() returns
    821    // false, and they're are compatible.
    822    MOZ_ASSERT(eagerDelazificationStrategy_ ==
    823                   DelazificationOption::OnDemandOnly ||
    824               eagerDelazificationStrategy_ ==
    825                   DelazificationOption::ParseEverythingEagerly);
    826 
    827    MOZ_ASSERT(eagerBaselineStrategy_ == EagerBaselineOption::None);
    828  }
    829 #endif
    830 };
    831 
    832 /**
    833 * Subset of CompileOptions fields used while decoding Stencils.
    834 */
    835 class JS_PUBLIC_API ReadOnlyDecodeOptions {
    836 public:
    837  bool borrowBuffer = false;
    838  bool usePinnedBytecode = false;
    839 
    840 protected:
    841  JS::ConstUTF8CharsZ introducerFilename_;
    842 
    843 public:
    844  // See `TransitiveCompileOptions::introductionType` field for details.
    845  const char* introductionType = nullptr;
    846 
    847  uint32_t introductionLineno = 0;
    848  uint32_t introductionOffset = 0;
    849 
    850 protected:
    851  ReadOnlyDecodeOptions() = default;
    852 
    853  ReadOnlyDecodeOptions(const ReadOnlyDecodeOptions&) = delete;
    854  ReadOnlyDecodeOptions& operator=(const ReadOnlyDecodeOptions&) = delete;
    855 
    856  template <typename T>
    857  void copyPODOptionsFrom(const T& options) {
    858    borrowBuffer = options.borrowBuffer;
    859    usePinnedBytecode = options.usePinnedBytecode;
    860    introductionType = options.introductionType;
    861    introductionLineno = options.introductionLineno;
    862    introductionOffset = options.introductionOffset;
    863  }
    864 
    865  template <typename T>
    866  void copyPODOptionsTo(T& options) const {
    867    options.borrowBuffer = borrowBuffer;
    868    options.usePinnedBytecode = usePinnedBytecode;
    869    options.introductionType = introductionType;
    870    options.introductionLineno = introductionLineno;
    871    options.introductionOffset = introductionOffset;
    872  }
    873 
    874 public:
    875  void copyTo(CompileOptions& options) const {
    876    copyPODOptionsTo(options);
    877    options.introducerFilename_ = introducerFilename_;
    878  }
    879 
    880  JS::ConstUTF8CharsZ introducerFilename() const { return introducerFilename_; }
    881 };
    882 
    883 class MOZ_STACK_CLASS JS_PUBLIC_API DecodeOptions final
    884    : public ReadOnlyDecodeOptions {
    885 public:
    886  DecodeOptions() = default;
    887 
    888  explicit DecodeOptions(const ReadOnlyCompileOptions& options) {
    889    copyPODOptionsFrom(options);
    890 
    891    introducerFilename_ = options.introducerFilename();
    892  }
    893 };
    894 
    895 class JS_PUBLIC_API OwningDecodeOptions final : public ReadOnlyDecodeOptions {
    896  friend class OwningCompileOptions;
    897 
    898 public:
    899  OwningDecodeOptions() = default;
    900 
    901  ~OwningDecodeOptions();
    902 
    903  bool copy(JS::FrontendContext* maybeFc, const ReadOnlyDecodeOptions& rhs);
    904  void infallibleCopy(const ReadOnlyDecodeOptions& rhs);
    905 
    906  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    907 
    908 private:
    909  void release();
    910 
    911  OwningDecodeOptions(const OwningDecodeOptions&) = delete;
    912  OwningDecodeOptions& operator=(const OwningDecodeOptions&) = delete;
    913 };
    914 
    915 }  // namespace JS
    916 
    917 #endif /* js_CompileOptions_h */