tor-browser

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

Realm.h (34751B)


      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 vm_Realm_h
      8 #define vm_Realm_h
      9 
     10 #include "mozilla/Array.h"
     11 #include "mozilla/Maybe.h"
     12 #include "mozilla/MemoryReporting.h"
     13 #include "mozilla/TimeStamp.h"
     14 #include "mozilla/XorShift128PlusRNG.h"
     15 
     16 #include <stddef.h>
     17 
     18 #include "builtin/Array.h"
     19 #include "ds/IdValuePair.h"
     20 #include "gc/Barrier.h"
     21 #include "gc/WeakMap.h"
     22 #include "jit/BaselineCompileQueue.h"
     23 #include "js/GCVariant.h"
     24 #include "js/RealmOptions.h"
     25 #include "js/TelemetryTimers.h"
     26 #include "js/UniquePtr.h"
     27 #include "vm/ArrayBufferObject.h"
     28 #include "vm/GuardFuse.h"
     29 #include "vm/InvalidatingFuse.h"
     30 #include "vm/JSContext.h"
     31 #include "vm/RealmFuses.h"
     32 #include "vm/SavedStacks.h"
     33 #include "wasm/WasmRealm.h"
     34 
     35 namespace js {
     36 
     37 namespace coverage {
     38 class LCovRealm;
     39 }  // namespace coverage
     40 
     41 namespace jit {
     42 class BaselineCompileQueue;
     43 }  // namespace jit
     44 
     45 class AutoRestoreRealmDebugMode;
     46 class DateTimeInfo;
     47 class Debugger;
     48 class GlobalObject;
     49 class GlobalObjectData;
     50 class GlobalLexicalEnvironmentObject;
     51 class NonSyntacticLexicalEnvironmentObject;
     52 struct IdValuePair;
     53 struct NativeIterator;
     54 
     55 /*
     56 * A single-entry cache for some base-10 double-to-string conversions. This
     57 * helps date-format-xparb.js.  It also avoids skewing the results for
     58 * v8-splay.js when measured by the SunSpider harness, where the splay tree
     59 * initialization (which includes many repeated double-to-string conversions)
     60 * is erroneously included in the measurement; see bug 562553.
     61 */
     62 class DtoaCache {
     63  double dbl;
     64  int base;
     65  JSLinearString* str;  // if str==nullptr, dbl and base are not valid
     66 
     67 public:
     68  DtoaCache() : str(nullptr) {}
     69  void purge() { str = nullptr; }
     70 
     71  JSLinearString* lookup(int b, double d) {
     72    return str && b == base && d == dbl ? str : nullptr;
     73  }
     74 
     75  void cache(int b, double d, JSLinearString* s) {
     76    base = b;
     77    dbl = d;
     78    str = s;
     79  }
     80 
     81 #ifdef JSGC_HASH_TABLE_CHECKS
     82  void checkCacheAfterMovingGC();
     83 #endif
     84 };
     85 
     86 // Cache to speed up the group/shape lookup in ProxyObject::create. A proxy's
     87 // shape is only determined by the Class + proto, so a small cache for this is
     88 // very effective in practice.
     89 class NewProxyCache {
     90  struct Entry {
     91    Shape* shape;
     92  };
     93  static const size_t NumEntries = 4;
     94  mozilla::UniquePtr<Entry[], JS::FreePolicy> entries_;
     95 
     96 public:
     97  MOZ_ALWAYS_INLINE bool lookup(const JSClass* clasp, TaggedProto proto,
     98                                Shape** shape) const {
     99    if (!entries_) {
    100      return false;
    101    }
    102    for (size_t i = 0; i < NumEntries; i++) {
    103      const Entry& entry = entries_[i];
    104      if (entry.shape && entry.shape->getObjectClass() == clasp &&
    105          entry.shape->proto() == proto) {
    106        *shape = entry.shape;
    107        return true;
    108      }
    109    }
    110    return false;
    111  }
    112  void add(Shape* shape) {
    113    MOZ_ASSERT(shape);
    114    if (!entries_) {
    115      entries_.reset(js_pod_calloc<Entry>(NumEntries));
    116      if (!entries_) {
    117        return;
    118      }
    119    } else {
    120      for (size_t i = NumEntries - 1; i > 0; i--) {
    121        entries_[i] = entries_[i - 1];
    122      }
    123    }
    124    entries_[0].shape = shape;
    125  }
    126  void purge() { entries_.reset(); }
    127 };
    128 
    129 // Cache for NewPlainObjectWithProperties. When the list of properties matches
    130 // a recently created object's shape, we can use this shape directly.
    131 class NewPlainObjectWithPropsCache {
    132  static const size_t NumEntries = 4;
    133  mozilla::Array<SharedShape*, NumEntries> entries_;
    134 
    135 public:
    136  NewPlainObjectWithPropsCache() { purge(); }
    137 
    138  SharedShape* lookup(Handle<IdValueVector> properties) const;
    139  void add(SharedShape* shape);
    140 
    141  void purge() {
    142    for (size_t i = 0; i < NumEntries; i++) {
    143      entries_[i] = nullptr;
    144    }
    145  }
    146 };
    147 
    148 // Cache for Object.assign's fast path for two plain objects. It's used to
    149 // optimize:
    150 //
    151 //   Object.assign(to, from)
    152 //
    153 // If the |to| object has shape |emptyToShape_| (shape with no properties) and
    154 // the |from| object has shape |fromShape_|, we can use |newToShape_| for |to|
    155 // and copy all (data)) properties from the |from| object.
    156 //
    157 // This is a one-entry cache for now. It has a hit rate of > 90% on both
    158 // Speedometer 2 and Speedometer 3.
    159 class MOZ_NON_TEMPORARY_CLASS PlainObjectAssignCache {
    160  SharedShape* emptyToShape_ = nullptr;
    161  SharedShape* fromShape_ = nullptr;
    162  SharedShape* newToShape_ = nullptr;
    163 
    164 #ifdef DEBUG
    165  void assertValid() const;
    166 #else
    167  void assertValid() const {}
    168 #endif
    169 
    170 public:
    171  PlainObjectAssignCache() = default;
    172  PlainObjectAssignCache(const PlainObjectAssignCache&) = delete;
    173  void operator=(const PlainObjectAssignCache&) = delete;
    174 
    175  SharedShape* lookup(Shape* emptyToShape, Shape* fromShape) const {
    176    if (emptyToShape_ == emptyToShape && fromShape_ == fromShape) {
    177      assertValid();
    178      return newToShape_;
    179    }
    180    return nullptr;
    181  }
    182  void fill(SharedShape* emptyToShape, SharedShape* fromShape,
    183            SharedShape* newToShape) {
    184    emptyToShape_ = emptyToShape;
    185    fromShape_ = fromShape;
    186    newToShape_ = newToShape;
    187    assertValid();
    188  }
    189  void purge() {
    190    emptyToShape_ = nullptr;
    191    fromShape_ = nullptr;
    192    newToShape_ = nullptr;
    193  }
    194 };
    195 
    196 // [SMDOC] Object MetadataBuilder API
    197 //
    198 // We must ensure that all newly allocated JSObjects get their metadata
    199 // set. However, metadata builders may require the new object be in a sane
    200 // state (eg, have its reserved slots initialized so they can get the
    201 // sizeOfExcludingThis of the object). Therefore, for objects of certain
    202 // JSClasses (those marked with JSCLASS_DELAY_METADATA_BUILDER), it is not safe
    203 // for the allocation paths to call the object metadata builder
    204 // immediately. Instead, the JSClass-specific "constructor" C++ function up the
    205 // stack makes a promise that it will ensure that the new object has its
    206 // metadata set after the object is initialized.
    207 //
    208 // The js::AutoSetNewObjectMetadata RAII class provides an ergonomic way for
    209 // constructor functions to do this.
    210 //
    211 // In the presence of internal errors, we do not set the new object's metadata
    212 // (if it was even allocated).
    213 
    214 class PropertyIteratorObject;
    215 
    216 struct IteratorHashPolicy {
    217  struct Lookup {
    218    Shape* objShape;
    219    Shape** protoShapes;
    220    size_t numProtoShapes;
    221    HashNumber shapesHash;
    222 
    223    Lookup(Shape* objShape, Shape** protoShapes, size_t numProtoShapes,
    224           HashNumber shapesHash)
    225        : objShape(objShape),
    226          protoShapes(protoShapes),
    227          numProtoShapes(numProtoShapes),
    228          shapesHash(shapesHash) {
    229      MOZ_ASSERT(objShape);
    230    }
    231  };
    232  static HashNumber hash(const Lookup& lookup) { return lookup.shapesHash; }
    233  static bool match(PropertyIteratorObject* obj, const Lookup& lookup);
    234 };
    235 
    236 class DebugEnvironments;
    237 class NonSyntacticVariablesObject;
    238 class WithEnvironmentObject;
    239 
    240 // ObjectRealm stores various tables and other state associated with particular
    241 // objects in a realm. To make sure the correct ObjectRealm is used for an
    242 // object, use of the ObjectRealm::get(obj) static method is required.
    243 class ObjectRealm {
    244  // All non-syntactic lexical environments in the realm. These are kept in a
    245  // map because when loading scripts into a non-syntactic environment, we
    246  // need to use the same lexical environment to persist lexical bindings.
    247  using NonSyntacticLexialEnvironmentsMap =
    248      WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
    249  js::UniquePtr<NonSyntacticLexialEnvironmentsMap>
    250      nonSyntacticLexicalEnvironments_;
    251 
    252  ObjectRealm(const ObjectRealm&) = delete;
    253  void operator=(const ObjectRealm&) = delete;
    254 
    255 public:
    256  // Map from array buffers to views sharing that storage.
    257  JS::WeakCache<js::InnerViewTable> innerViews;
    258 
    259  // Keep track of the metadata objects which can be associated with each JS
    260  // object. Both keys and values are in this realm.
    261  using ObjectMetadataTable = WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
    262  js::UniquePtr<ObjectMetadataTable> objectMetadataTable;
    263 
    264  using IteratorCache =
    265      js::HashSet<js::PropertyIteratorObject*, js::IteratorHashPolicy,
    266                  js::ZoneAllocPolicy>;
    267  IteratorCache iteratorCache;
    268 
    269  static inline ObjectRealm& get(const JSObject* obj);
    270 
    271  explicit ObjectRealm(JS::Zone* zone);
    272 
    273  void finishRoots();
    274  void trace(JSTracer* trc);
    275  void sweepAfterMinorGC(JSTracer* trc);
    276 
    277  void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
    278                              size_t* innerViewsArg,
    279                              size_t* objectMetadataTablesArg,
    280                              size_t* nonSyntacticLexicalEnvironmentsArg);
    281 
    282  NonSyntacticLexicalEnvironmentObject*
    283  getOrCreateNonSyntacticLexicalEnvironment(
    284      JSContext* cx, Handle<NonSyntacticVariablesObject*> enclosing);
    285 
    286  NonSyntacticLexicalEnvironmentObject*
    287  getOrCreateNonSyntacticLexicalEnvironment(
    288      JSContext* cx, Handle<WithEnvironmentObject*> enclosing);
    289 
    290  NonSyntacticLexicalEnvironmentObject*
    291  getOrCreateNonSyntacticLexicalEnvironment(
    292      JSContext* cx, Handle<WithEnvironmentObject*> enclosing,
    293      Handle<NonSyntacticVariablesObject*> key);
    294 
    295 private:
    296  NonSyntacticLexicalEnvironmentObject*
    297  getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx,
    298                                            HandleObject enclosing,
    299                                            HandleObject key,
    300                                            HandleObject thisv);
    301 
    302 public:
    303  NonSyntacticLexicalEnvironmentObject* getNonSyntacticLexicalEnvironment(
    304      JSObject* key) const;
    305 };
    306 
    307 }  // namespace js
    308 
    309 class JS::Realm : public JS::shadow::Realm {
    310  JS::Zone* zone_;
    311  JSRuntime* runtime_;
    312 
    313  const JS::RealmCreationOptions creationOptions_;
    314  JS::RealmBehaviors behaviors_;
    315 
    316  friend struct ::JSContext;
    317  js::WeakHeapPtr<js::GlobalObject*> global_;
    318 
    319  // Note: this is private to enforce use of ObjectRealm::get(obj).
    320  js::ObjectRealm objects_;
    321  friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*);
    322 
    323  // See the "Object MetadataBuilder API" comment.
    324  JSObject* objectPendingMetadata_ = nullptr;
    325 #ifdef DEBUG
    326  uint32_t numActiveAutoSetNewObjectMetadata_ = 0;
    327 #endif
    328 
    329  // Random number generator for Math.random().
    330  mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG>
    331      randomNumberGenerator_;
    332 
    333  // Random number generator for randomHashCodeScrambler().
    334  mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_;
    335 
    336  JSPrincipals* principals_ = nullptr;
    337 
    338  js::jit::BaselineCompileQueue baselineCompileQueue_;
    339 
    340  // Bookkeeping information for debug scope objects.
    341  js::UniquePtr<js::DebugEnvironments> debugEnvs_;
    342 
    343  js::SavedStacks savedStacks_;
    344 
    345  // Used by memory reporters and invalid otherwise.
    346  JS::RealmStats* realmStats_ = nullptr;
    347 
    348  const js::AllocationMetadataBuilder* allocationMetadataBuilder_ = nullptr;
    349  void* realmPrivate_ = nullptr;
    350 
    351 #if JS_HAS_INTL_API
    352  // Date-time info for realms with non-default time zones.
    353  js::UniquePtr<js::DateTimeInfo> dateTimeInfo_;
    354 #endif
    355 
    356  // There are two ways to enter a realm:
    357  //
    358  // (1) AutoRealm (and JSAutoRealm, JS::EnterRealm)
    359  // (2) When calling a cross-realm (but same-compartment) function in JIT
    360  //     code.
    361  //
    362  // This field only accounts for (1), to keep the JIT code as simple as
    363  // possible.
    364  //
    365  // An important invariant is that the JIT can only switch to a different
    366  // realm within the same compartment, so whenever that happens there must
    367  // always be a same-compartment realm with enterRealmDepthIgnoringJit_ > 0.
    368  // This lets us set Compartment::hasEnteredRealm without walking the
    369  // stack.
    370  unsigned enterRealmDepthIgnoringJit_ = 0;
    371 
    372 public:
    373  // Various timers for collecting time spent delazifying, jit compiling,
    374  // executing, etc
    375  JS::JSTimers timers;
    376 
    377  struct DebuggerVectorEntry {
    378    // The debugger relies on iterating through the DebuggerVector to know what
    379    // debuggers to notify about certain actions, which it does using this
    380    // pointer. We need an explicit Debugger* because the JSObject* from
    381    // the DebuggerDebuggeeLink to the Debugger is only set some of the time.
    382    // This `Debugger*` pointer itself could also live on the
    383    // DebuggerDebuggeeLink itself, but that would then require all of the
    384    // places that iterate over the realm's DebuggerVector to also traverse
    385    // the CCW which seems like it would be needlessly complicated.
    386    js::WeakHeapPtr<js::Debugger*> dbg;
    387 
    388    // This links to the debugger's DebuggerDebuggeeLink object, via a CCW.
    389    // Tracing this link from the realm allows the debugger to define
    390    // whether pieces of the debugger should be held live by a given realm.
    391    js::HeapPtr<JSObject*> debuggerLink;
    392 
    393    DebuggerVectorEntry(js::Debugger* dbg_, JSObject* link);
    394  };
    395  using DebuggerVector =
    396      js::Vector<DebuggerVectorEntry, 0, js::ZoneAllocPolicy>;
    397 
    398 private:
    399  DebuggerVector debuggers_;
    400 
    401  enum {
    402    IsDebuggee = 1 << 0,
    403    DebuggerObservesAllExecution = 1 << 1,
    404    DebuggerObservesAsmJS = 1 << 2,
    405    DebuggerObservesCoverage = 1 << 3,
    406    DebuggerObservesWasm = 1 << 4,
    407    DebuggerObservesNativeCall = 1 << 5,
    408  };
    409  uint32_t debugModeBits_ = 0;
    410  friend class js::AutoRestoreRealmDebugMode;
    411 
    412  bool isSystem_ = false;
    413  bool allocatedDuringIncrementalGC_;
    414  bool initializingGlobal_ = true;
    415 
    416  // Indicates that we are tracing all execution within this realm, i.e.,
    417  // recording every entrance into exit from each function, among other
    418  // things. See ExecutionTracer.h for where the bulk of this work
    419  // happens.
    420  bool isTracingExecution_ = false;
    421 
    422  js::UniquePtr<js::coverage::LCovRealm> lcovRealm_ = nullptr;
    423 
    424 public:
    425  // WebAssembly state for the realm.
    426  js::wasm::Realm wasm;
    427 
    428  js::DtoaCache dtoaCache;
    429  js::NewProxyCache newProxyCache;
    430  js::NewPlainObjectWithPropsCache newPlainObjectWithPropsCache;
    431  js::PlainObjectAssignCache plainObjectAssignCache;
    432 
    433  // Last time at which an animation was played for this realm.
    434  js::MainThreadData<mozilla::TimeStamp> lastAnimationTime;
    435 
    436  /*
    437   * For generational GC, record whether a write barrier has added this
    438   * realm's global to the store buffer since the last minor GC.
    439   *
    440   * This is used to avoid calling into the VM every time a nursery object is
    441   * written to a property of the global.
    442   */
    443  uint32_t globalWriteBarriered = 0;
    444 
    445  // Counter for shouldCaptureStackForThrow.
    446  uint16_t numStacksCapturedForThrow_ = 0;
    447 
    448  // Count the number of allocation sites pretenured, for testing purposes.
    449  uint16_t numAllocSitesPretenured = 0;
    450 
    451 #ifdef DEBUG
    452  bool firedOnNewGlobalObject = false;
    453 #endif
    454 
    455  // True if all incoming wrappers have been nuked. This happens when
    456  // NukeCrossCompartmentWrappers is called with the NukeAllReferences option.
    457  // This prevents us from creating new wrappers for the compartment.
    458  bool nukedIncomingWrappers = false;
    459 
    460  // Enable async stack capturing for this realm even if
    461  // JS::ContextOptions::asyncStackCaptureDebuggeeOnly_ is true.
    462  //
    463  // No-op when JS::ContextOptions::asyncStack_ is false, or
    464  // JS::ContextOptions::asyncStackCaptureDebuggeeOnly_ is false.
    465  //
    466  // This can be used as a lightweight alternative for making the global
    467  // debuggee, if the async stack capturing is necessary but no other debugging
    468  // features are used.
    469  bool isAsyncStackCapturingEnabled = false;
    470 
    471  // Allow to collect more than 50 stack traces for throw even if the global is
    472  // not a debuggee.
    473  //
    474  // Similarly to isAsyncStackCapturingEnabled, this is a lightweight
    475  // alternative for making the global a debuggee, when no actual debugging
    476  // features are required.
    477  bool isUnlimitedStacksCapturingEnabled = false;
    478 
    479 private:
    480  void updateDebuggerObservesFlag(unsigned flag);
    481  void restoreDebugModeBitsOnOOM(uint32_t bits);
    482 
    483  Realm(const Realm&) = delete;
    484  void operator=(const Realm&) = delete;
    485 
    486 public:
    487  Realm(JS::Compartment* comp, const JS::RealmOptions& options);
    488  ~Realm();
    489 
    490  void init(JSContext* cx, JSPrincipals* principals);
    491  void destroy(JS::GCContext* gcx);
    492 
    493  void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
    494                              size_t* realmObject, size_t* realmTables,
    495                              size_t* innerViewsArg,
    496                              size_t* objectMetadataTablesArg,
    497                              size_t* savedStacksSet,
    498                              size_t* nonSyntacticLexicalEnvironmentsArg);
    499 
    500  JS::Zone* zone() { return zone_; }
    501  const JS::Zone* zone() const { return zone_; }
    502 
    503  JSRuntime* runtimeFromMainThread() const {
    504    MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
    505    return runtime_;
    506  }
    507 
    508  // Note: Unrestricted access to the runtime from an arbitrary thread
    509  // can easily lead to races. Use this method very carefully.
    510  JSRuntime* runtimeFromAnyThread() const { return runtime_; }
    511 
    512  const JS::RealmCreationOptions& creationOptions() const {
    513    return creationOptions_;
    514  }
    515 
    516  // NOTE: Do not provide accessor for mutable reference.
    517  // Modifying RealmBehaviors after creating a realm can result in
    518  // inconsistency.
    519  const JS::RealmBehaviors& behaviors() const { return behaviors_; }
    520 
    521  void setNonLive() { behaviors_.setNonLive(); }
    522  void setReduceTimerPrecisionCallerType(JS::RTPCallerTypeToken type) {
    523    behaviors_.setReduceTimerPrecisionCallerType(type);
    524  }
    525 
    526  /* Whether to preserve JIT code on non-shrinking GCs. */
    527  bool preserveJitCode() { return creationOptions_.preserveJitCode(); }
    528 
    529  /* The global object for this realm.
    530   *
    531   * Note: the global_ field is null briefly during GC, after the global
    532   * object is collected; but when that happens the Realm is destroyed during
    533   * the same GC.)
    534   *
    535   * In contrast, JSObject::global() is infallible because marking a JSObject
    536   * always marks its global as well.
    537   */
    538  inline js::GlobalObject* maybeGlobal() const;
    539 
    540  /* An unbarriered getter for use while tracing. */
    541  js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const {
    542    return global_.unbarrieredGet();
    543  }
    544 
    545  /* True if a global exists and it's not being collected. */
    546  inline bool hasLiveGlobal() const;
    547 
    548  /* True if a global exists and has been successfully initialized. */
    549  inline bool hasInitializedGlobal() const;
    550 
    551  inline void initGlobal(js::GlobalObject& global);
    552  void clearInitializingGlobal() { initializingGlobal_ = false; }
    553 
    554  /*
    555   * This method traces data that is live iff we know that this realm's
    556   * global is still live.
    557   */
    558  void traceGlobalData(JSTracer* trc);
    559 
    560  void traceWeakGlobalEdge(JSTracer* trc);
    561 
    562  /*
    563   * This method traces Realm-owned GC roots that are considered live
    564   * regardless of whether the realm's global is still live.
    565   */
    566  void traceRoots(JSTracer* trc,
    567                  js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark);
    568  /*
    569   * This method clears out tables of roots in preparation for the final GC.
    570   */
    571  void finishRoots();
    572 
    573  void sweepAfterMinorGC(JSTracer* trc);
    574  void traceWeakDebugEnvironmentEdges(JSTracer* trc);
    575 
    576  void clearScriptCounts();
    577  void clearScriptLCov();
    578 
    579  void purge();
    580 
    581  void fixupAfterMovingGC(JSTracer* trc);
    582 
    583  void enter() { enterRealmDepthIgnoringJit_++; }
    584  void leave() {
    585    MOZ_ASSERT(enterRealmDepthIgnoringJit_ > 0);
    586    enterRealmDepthIgnoringJit_--;
    587  }
    588  bool hasBeenEnteredIgnoringJit() const {
    589    return enterRealmDepthIgnoringJit_ > 0;
    590  }
    591  bool shouldTraceGlobal() const {
    592    // If we entered this realm in JIT code, there must be a script and
    593    // function on the stack for this realm, so the global will definitely
    594    // be traced and it's safe to return false here.
    595    return hasBeenEnteredIgnoringJit();
    596  }
    597 
    598  bool hasAllocationMetadataBuilder() const {
    599    return allocationMetadataBuilder_;
    600  }
    601  const js::AllocationMetadataBuilder* getAllocationMetadataBuilder() const {
    602    return allocationMetadataBuilder_;
    603  }
    604  const void* addressOfMetadataBuilder() const {
    605    return &allocationMetadataBuilder_;
    606  }
    607  bool isRecordingAllocations();
    608  void setAllocationMetadataBuilder(
    609      const js::AllocationMetadataBuilder* builder);
    610  void forgetAllocationMetadataBuilder();
    611  void setNewObjectMetadata(JSContext* cx, JS::HandleObject obj);
    612 
    613  bool hasObjectPendingMetadata() const {
    614    MOZ_ASSERT_IF(objectPendingMetadata_, hasAllocationMetadataBuilder());
    615    return objectPendingMetadata_ != nullptr;
    616  }
    617  void setObjectPendingMetadata(JSObject* obj) {
    618    MOZ_ASSERT(numActiveAutoSetNewObjectMetadata_ > 0,
    619               "Must not use JSCLASS_DELAY_METADATA_BUILDER without "
    620               "AutoSetNewObjectMetadata");
    621    MOZ_ASSERT(!objectPendingMetadata_);
    622    MOZ_ASSERT(obj);
    623    if (MOZ_UNLIKELY(hasAllocationMetadataBuilder())) {
    624      objectPendingMetadata_ = obj;
    625    }
    626  }
    627  JSObject* getAndClearObjectPendingMetadata() {
    628    MOZ_ASSERT(hasAllocationMetadataBuilder());
    629    JSObject* obj = objectPendingMetadata_;
    630    objectPendingMetadata_ = nullptr;
    631    return obj;
    632  }
    633 
    634 #ifdef DEBUG
    635  bool hasActiveAutoSetNewObjectMetadata() const {
    636    return numActiveAutoSetNewObjectMetadata_ > 0;
    637  }
    638  void incNumActiveAutoSetNewObjectMetadata() {
    639    numActiveAutoSetNewObjectMetadata_++;
    640  }
    641  void decNumActiveAutoSetNewObjectMetadata() {
    642    MOZ_ASSERT(numActiveAutoSetNewObjectMetadata_ > 0);
    643    numActiveAutoSetNewObjectMetadata_--;
    644  }
    645 #endif
    646 
    647  void* realmPrivate() const { return realmPrivate_; }
    648  void setRealmPrivate(void* p) { realmPrivate_ = p; }
    649 
    650  // This should only be called when it is non-null, i.e. during memory
    651  // reporting.
    652  JS::RealmStats& realmStats() {
    653    // We use MOZ_RELEASE_ASSERT here because in bug 1132502 there was some
    654    // (inconclusive) evidence that realmStats_ can be nullptr unexpectedly.
    655    MOZ_RELEASE_ASSERT(realmStats_);
    656    return *realmStats_;
    657  }
    658  void nullRealmStats() {
    659    MOZ_ASSERT(realmStats_);
    660    realmStats_ = nullptr;
    661  }
    662  void setRealmStats(JS::RealmStats* newStats) {
    663    MOZ_ASSERT(!realmStats_ && newStats);
    664    realmStats_ = newStats;
    665  }
    666 
    667  inline bool marked() const;
    668  void clearAllocatedDuringGC() { allocatedDuringIncrementalGC_ = false; }
    669 
    670  /*
    671   * The principals associated with this realm. Note that the same several
    672   * realms may share the same principals and that a realm may change
    673   * principals during its lifetime (e.g. in case of lazy parsing).
    674   */
    675  JSPrincipals* principals() { return principals_; }
    676  void setPrincipals(JSPrincipals* principals) { principals_ = principals; }
    677 
    678  bool isSystem() const { return isSystem_; }
    679  //
    680  // The Debugger observes execution on a frame-by-frame basis. The
    681  // invariants of Realm's debug mode bits, JSScript::isDebuggee,
    682  // InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
    683  // enumerated below.
    684  //
    685  // 1. When a realm's isDebuggee() == true, relazification and lazy
    686  //    parsing are disabled.
    687  //
    688  //    Whether AOT wasm is disabled is togglable by the Debugger API. By
    689  //    default it is disabled. See debuggerObservesAsmJS below.
    690  //
    691  // 2. When a realm's debuggerObservesAllExecution() == true, all of
    692  //    the realm's scripts are considered debuggee scripts.
    693  //
    694  // 3. A script is considered a debuggee script either when, per above, its
    695  //    realm is observing all execution, or if it has breakpoints set.
    696  //
    697  // 4. A debuggee script always pushes a debuggee frame.
    698  //
    699  // 5. A debuggee frame calls all slow path Debugger hooks in the
    700  //    Interpreter and Baseline. A debuggee frame implies that its script's
    701  //    BaselineScript, if extant, has been compiled with debug hook calls.
    702  //
    703  // 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
    704  //    that the compiled BaselineScript is compiled with debug hook calls
    705  //    when attempting to enter Baseline.
    706  //
    707  // 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
    708  //    attempt to enter Ion.
    709  //
    710  // Note that a debuggee frame may exist without its script being a
    711  // debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
    712  // frame in which it is evaluating as a debuggee frame.
    713  //
    714 
    715  // True if this realm's global is a debuggee of some Debugger
    716  // object.
    717  bool isDebuggee() const { return !!(debugModeBits_ & IsDebuggee); }
    718 
    719  void setIsDebuggee();
    720  void unsetIsDebuggee();
    721 
    722  bool isTracingExecution() { return isTracingExecution_; }
    723 
    724  void enableExecutionTracing() {
    725    MOZ_ASSERT(!debuggerObservesCoverage());
    726 
    727    isTracingExecution_ = true;
    728    setIsDebuggee();
    729    updateDebuggerObservesAllExecution();
    730  }
    731 
    732  void disableExecutionTracing() {
    733    if (!isTracingExecution_) {
    734      return;
    735    }
    736 
    737    isTracingExecution_ = false;
    738    // updateDebuggerObservesAllExecution always wants isDebuggee to be true,
    739    // so we just have weird ordering here to play nicely with it
    740    updateDebuggerObservesAllExecution();
    741    if (!hasDebuggers()) {
    742      unsetIsDebuggee();
    743    }
    744  }
    745 
    746  DebuggerVector& getDebuggers(const JS::AutoRequireNoGC& nogc) {
    747    return debuggers_;
    748  };
    749  bool hasDebuggers() const { return !debuggers_.empty(); }
    750 
    751  // True if this compartment's global is a debuggee of some Debugger
    752  // object with a live hook that observes all execution; e.g.,
    753  // onEnterFrame.
    754  bool debuggerObservesAllExecution() const {
    755    static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution;
    756    return (debugModeBits_ & Mask) == Mask;
    757  }
    758  void updateDebuggerObservesAllExecution() {
    759    updateDebuggerObservesFlag(DebuggerObservesAllExecution);
    760  }
    761 
    762  // True if this realm's global is a debuggee of some Debugger object
    763  // whose allowUnobservedAsmJS flag is false.
    764  bool debuggerObservesAsmJS() const {
    765    static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS;
    766    return (debugModeBits_ & Mask) == Mask;
    767  }
    768  void updateDebuggerObservesAsmJS() {
    769    updateDebuggerObservesFlag(DebuggerObservesAsmJS);
    770  }
    771 
    772  // True if this realm's global is a debuggee of some Debugger object
    773  // whose allowUnobservedWasm flag is false.
    774  //
    775  // Note that since AOT wasm functions cannot bail out, this flag really
    776  // means "observe wasm from this point forward". We cannot make
    777  // already-compiled wasm code observable to Debugger.
    778  bool debuggerObservesWasm() const {
    779    static const unsigned Mask = IsDebuggee | DebuggerObservesWasm;
    780    return (debugModeBits_ & Mask) == Mask;
    781  }
    782  void updateDebuggerObservesWasm() {
    783    updateDebuggerObservesFlag(DebuggerObservesWasm);
    784  }
    785 
    786  // True if this compartment's global is a debuggee of some Debugger
    787  // object with a live hook that observes native calls.
    788  // (has a onNativeCall function registered)
    789  bool debuggerObservesNativeCall() const {
    790    static const unsigned Mask = IsDebuggee | DebuggerObservesNativeCall;
    791    return (debugModeBits_ & Mask) == Mask;
    792  }
    793  void updateDebuggerObservesNativeCall() {
    794    updateDebuggerObservesFlag(DebuggerObservesNativeCall);
    795  }
    796 
    797  // True if this realm's global is a debuggee of some Debugger object
    798  // whose collectCoverageInfo flag is true.
    799  bool debuggerObservesCoverage() const {
    800    static const unsigned Mask = DebuggerObservesCoverage;
    801    return (debugModeBits_ & Mask) == Mask;
    802  }
    803  void updateDebuggerObservesCoverage();
    804 
    805  // Returns true if the Debugger API is collecting code coverage data for this
    806  // realm or if the process-wide LCov option is enabled.
    807  bool collectCoverageForDebug() const;
    808 
    809  // Get or allocate the associated LCovRealm.
    810  js::coverage::LCovRealm* lcovRealm();
    811 
    812  bool shouldCaptureStackForThrow();
    813 
    814  // Returns the locale for this realm. (Pointer must NOT be freed!)
    815  const char* getLocale() const;
    816 
    817  // Set the locale for this realm. Reset to the system default locale when the
    818  // input is |nullptr|.
    819  void setLocaleOverride(const char* locale);
    820 
    821  // Returns the date-time info for this realm. Returns nullptr unless a time
    822  // zone override was specified in the realm creation options.
    823  js::DateTimeInfo* getDateTimeInfo();
    824 
    825  // Set the time zone for this realm. Reset to the system default time zone
    826  // when the input is |nullptr|.
    827  void setTimeZoneOverride(const char* timeZone);
    828 
    829  // Initializes randomNumberGenerator if needed.
    830  mozilla::non_crypto::XorShift128PlusRNG& getOrCreateRandomNumberGenerator();
    831 
    832  const mozilla::non_crypto::XorShift128PlusRNG*
    833  addressOfRandomNumberGenerator() const {
    834    return randomNumberGenerator_.ptr();
    835  }
    836 
    837  mozilla::HashCodeScrambler randomHashCodeScrambler();
    838 
    839  js::jit::BaselineCompileQueue& baselineCompileQueue() {
    840    return baselineCompileQueue_;
    841  }
    842  static constexpr size_t offsetOfBaselineCompileQueue() {
    843    return offsetof(Realm, baselineCompileQueue_);
    844  }
    845  void removeFromCompileQueue(JSScript* script);
    846 
    847  js::DebugEnvironments* debugEnvs() { return debugEnvs_.get(); }
    848  js::UniquePtr<js::DebugEnvironments>& debugEnvsRef() { return debugEnvs_; }
    849 
    850  js::SavedStacks& savedStacks() { return savedStacks_; }
    851 
    852  // Recompute the probability with which this realm should record
    853  // profiling data (stack traces, allocations log, etc.) about each
    854  // allocation. We first consult the JS runtime to see if it is recording
    855  // allocations, and if not then check the probabilities requested by the
    856  // Debugger instances observing us, if any.
    857  void chooseAllocationSamplingProbability() {
    858    savedStacks_.chooseSamplingProbability(this);
    859  }
    860 
    861  void traceWeakSavedStacks(JSTracer* trc);
    862 
    863  static constexpr size_t offsetOfCompartment() {
    864    return offsetof(JS::Realm, compartment_);
    865  }
    866  static constexpr size_t offsetOfAllocationMetadataBuilder() {
    867    return offsetof(JS::Realm, allocationMetadataBuilder_);
    868  }
    869  static constexpr size_t offsetOfDebugModeBits() {
    870    return offsetof(JS::Realm, debugModeBits_);
    871  }
    872  static constexpr uint32_t debugModeIsDebuggeeBit() { return IsDebuggee; }
    873 
    874  // Note: similar to cx->global(), JIT code can omit the read barrier for the
    875  // context's active global.
    876  static constexpr size_t offsetOfActiveGlobal() {
    877    static_assert(sizeof(global_) == sizeof(uintptr_t),
    878                  "JIT code assumes field is pointer-sized");
    879    return offsetof(JS::Realm, global_);
    880  }
    881 
    882  js::RealmFuses realmFuses;
    883 
    884  // Allocation site used by binding code to provide feedback
    885  // on allocation heap for DOM allocation functions.
    886  //
    887  // See  CallIRGenerator::tryAttachCallNative
    888  js::gc::AllocSite* localAllocSite = nullptr;
    889 
    890  static size_t offsetOfLocalAllocSite() {
    891    return offsetof(JS::Realm, localAllocSite);
    892  }
    893 };
    894 
    895 inline js::Handle<js::GlobalObject*> JSContext::global() const {
    896  /*
    897   * It's safe to use |unbarrieredGet()| here because any realm that is on-stack
    898   * will be marked automatically, so there's no need for a read barrier on
    899   * it. Once the realm is popped, the handle is no longer safe to use.
    900   */
    901  MOZ_ASSERT(realm_, "Caller needs to enter a realm first");
    902  return js::Handle<js::GlobalObject*>::fromMarkedLocation(
    903      realm_->global_.unbarrieredAddress());
    904 }
    905 
    906 namespace js {
    907 
    908 class MOZ_RAII AssertRealmUnchanged {
    909 public:
    910  explicit AssertRealmUnchanged(JSContext* cx)
    911      : cx(cx), oldRealm(cx->realm()) {}
    912 
    913  ~AssertRealmUnchanged() { MOZ_ASSERT(cx->realm() == oldRealm); }
    914 
    915 protected:
    916  JSContext* const cx;
    917  JS::Realm* const oldRealm;
    918 };
    919 
    920 // AutoRealm can be used to enter the realm of a JSObject or JSScript. It must
    921 // not be used with cross-compartment wrappers, because CCWs are not associated
    922 // with a single realm.
    923 class AutoRealm {
    924  JSContext* const cx_;
    925  JS::Realm* const origin_;
    926 
    927 public:
    928  template <typename T>
    929  inline AutoRealm(JSContext* cx, const T& target);
    930  inline ~AutoRealm();
    931 
    932  JSContext* context() const { return cx_; }
    933  JS::Realm* origin() const { return origin_; }
    934 
    935 protected:
    936  inline AutoRealm(JSContext* cx, JS::Realm* target);
    937 
    938 private:
    939  AutoRealm(const AutoRealm&) = delete;
    940  AutoRealm& operator=(const AutoRealm&) = delete;
    941 };
    942 
    943 class MOZ_RAII AutoAllocInAtomsZone {
    944  JSContext* const cx_;
    945  JS::Realm* const origin_;
    946  AutoAllocInAtomsZone(const AutoAllocInAtomsZone&) = delete;
    947  AutoAllocInAtomsZone& operator=(const AutoAllocInAtomsZone&) = delete;
    948 
    949 public:
    950  inline explicit AutoAllocInAtomsZone(JSContext* cx);
    951  inline ~AutoAllocInAtomsZone();
    952 };
    953 
    954 // During GC we sometimes need to enter a realm when we may have been allocating
    955 // in the the atoms zone. This leaves the atoms zone temporarily.
    956 class MOZ_RAII AutoMaybeLeaveAtomsZone {
    957  JSContext* const cx_;
    958  bool wasInAtomsZone_;
    959  AutoMaybeLeaveAtomsZone(const AutoMaybeLeaveAtomsZone&) = delete;
    960  AutoMaybeLeaveAtomsZone& operator=(const AutoMaybeLeaveAtomsZone&) = delete;
    961 
    962 public:
    963  inline explicit AutoMaybeLeaveAtomsZone(JSContext* cx);
    964  inline ~AutoMaybeLeaveAtomsZone();
    965 };
    966 
    967 // Enter a realm directly. Only use this where there's no target GC thing
    968 // to pass to AutoRealm or where you need to avoid the assertions in
    969 // JS::Compartment::enterCompartmentOf().
    970 class AutoRealmUnchecked : protected AutoRealm {
    971 public:
    972  inline AutoRealmUnchecked(JSContext* cx, JS::Realm* target);
    973 };
    974 
    975 // Similar to AutoRealm, but this uses GetFunctionRealm in the spec, and
    976 // handles both bound functions and proxies.
    977 //
    978 // If GetFunctionRealm fails for the following reasons, this does nothing:
    979 //   * `fun` is revoked proxy
    980 //   * unwrapping failed because of a security wrapper
    981 class AutoFunctionOrCurrentRealm {
    982  mozilla::Maybe<AutoRealmUnchecked> ar_;
    983 
    984 public:
    985  inline AutoFunctionOrCurrentRealm(JSContext* cx, js::HandleObject fun);
    986  ~AutoFunctionOrCurrentRealm() = default;
    987 
    988 private:
    989  AutoFunctionOrCurrentRealm(const AutoFunctionOrCurrentRealm&) = delete;
    990  AutoFunctionOrCurrentRealm& operator=(const AutoFunctionOrCurrentRealm&) =
    991      delete;
    992 };
    993 
    994 /*
    995 * Use this to change the behavior of an AutoRealm slightly on error. If
    996 * the exception happens to be an Error object, copy it to the origin
    997 * compartment instead of wrapping it.
    998 */
    999 class ErrorCopier {
   1000  mozilla::Maybe<AutoRealm>& ar;
   1001 
   1002 public:
   1003  explicit ErrorCopier(mozilla::Maybe<AutoRealm>& ar) : ar(ar) {}
   1004  ~ErrorCopier();
   1005 };
   1006 
   1007 // See the "Object MetadataBuilder API" comment.
   1008 class MOZ_RAII AutoSetNewObjectMetadata {
   1009  JSContext* cx_;
   1010 
   1011  AutoSetNewObjectMetadata(const AutoSetNewObjectMetadata& aOther) = delete;
   1012  void operator=(const AutoSetNewObjectMetadata& aOther) = delete;
   1013 
   1014  void setPendingMetadata();
   1015 
   1016 public:
   1017  explicit inline AutoSetNewObjectMetadata(JSContext* cx) : cx_(cx) {
   1018 #ifdef DEBUG
   1019    MOZ_ASSERT(!cx->realm()->hasObjectPendingMetadata());
   1020    cx_->realm()->incNumActiveAutoSetNewObjectMetadata();
   1021 #endif
   1022  }
   1023  inline ~AutoSetNewObjectMetadata() {
   1024 #ifdef DEBUG
   1025    cx_->realm()->decNumActiveAutoSetNewObjectMetadata();
   1026 #endif
   1027    if (MOZ_UNLIKELY(cx_->realm()->hasAllocationMetadataBuilder())) {
   1028      setPendingMetadata();
   1029    }
   1030  }
   1031 };
   1032 
   1033 } /* namespace js */
   1034 
   1035 #endif /* vm_Realm_h */