LCOV - code coverage report
Current view: top level - js/src - jscompartment.h (source / functions) Hit Total Coverage
Test: output.info Lines: 274 373 73.5 %
Date: 2017-07-14 16:53:18 Functions: 128 222 57.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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 jscompartment_h
       8             : #define jscompartment_h
       9             : 
      10             : #include "mozilla/LinkedList.h"
      11             : #include "mozilla/Maybe.h"
      12             : #include "mozilla/MemoryReporting.h"
      13             : #include "mozilla/Tuple.h"
      14             : #include "mozilla/Variant.h"
      15             : #include "mozilla/XorShift128PlusRNG.h"
      16             : 
      17             : #include <stddef.h>
      18             : 
      19             : #include "frontend/LanguageExtensions.h"
      20             : #include "gc/Barrier.h"
      21             : #include "gc/NurseryAwareHashMap.h"
      22             : #include "gc/Zone.h"
      23             : #include "vm/PIC.h"
      24             : #include "vm/RegExpShared.h"
      25             : #include "vm/SavedStacks.h"
      26             : #include "vm/TemplateRegistry.h"
      27             : #include "vm/Time.h"
      28             : #include "wasm/WasmCompartment.h"
      29             : 
      30             : namespace js {
      31             : 
      32             : namespace jit {
      33             : class JitCompartment;
      34             : } // namespace jit
      35             : 
      36             : namespace gc {
      37             : template <typename Node, typename Derived> class ComponentFinder;
      38             : } // namespace gc
      39             : 
      40             : class GlobalObject;
      41             : class LexicalEnvironmentObject;
      42             : class ScriptSourceObject;
      43             : struct NativeIterator;
      44             : 
      45             : /*
      46             :  * A single-entry cache for some base-10 double-to-string conversions. This
      47             :  * helps date-format-xparb.js.  It also avoids skewing the results for
      48             :  * v8-splay.js when measured by the SunSpider harness, where the splay tree
      49             :  * initialization (which includes many repeated double-to-string conversions)
      50             :  * is erroneously included in the measurement; see bug 562553.
      51             :  */
      52             : class DtoaCache {
      53             :     double       d;
      54             :     int          base;
      55             :     JSFlatString* s;      // if s==nullptr, d and base are not valid
      56             : 
      57             :   public:
      58         315 :     DtoaCache() : s(nullptr) {}
      59         223 :     void purge() { s = nullptr; }
      60             : 
      61         452 :     JSFlatString* lookup(int base, double d) {
      62         452 :         return this->s && base == this->base && d == this->d ? this->s : nullptr;
      63             :     }
      64             : 
      65         451 :     void cache(int base, double d, JSFlatString* s) {
      66         451 :         this->base = base;
      67         451 :         this->d = d;
      68         451 :         this->s = s;
      69         451 :     }
      70             : 
      71             : #ifdef JSGC_HASH_TABLE_CHECKS
      72             :     void checkCacheAfterMovingGC();
      73             : #endif
      74             : };
      75             : 
      76             : // Cache to speed up the group/shape lookup in ProxyObject::create. A proxy's
      77             : // group/shape is only determined by the Class + proto, so a small cache for
      78             : // this is very effective in practice.
      79         315 : class NewProxyCache
      80             : {
      81             :     struct Entry {
      82             :         ObjectGroup* group;
      83             :         Shape* shape;
      84             :     };
      85             :     static const size_t NumEntries = 4;
      86             :     mozilla::UniquePtr<Entry[], JS::FreePolicy> entries_;
      87             : 
      88             :   public:
      89        9333 :     MOZ_ALWAYS_INLINE bool lookup(const Class* clasp, TaggedProto proto,
      90             :                                   ObjectGroup** group, Shape** shape) const
      91             :     {
      92        9333 :         if (!entries_)
      93         290 :             return false;
      94        9540 :         for (size_t i = 0; i < NumEntries; i++) {
      95        9500 :             const Entry& entry = entries_[i];
      96        9500 :             if (entry.group && entry.group->clasp() == clasp && entry.group->proto() == proto) {
      97        9003 :                 *group = entry.group;
      98        9003 :                 *shape = entry.shape;
      99        9003 :                 return true;
     100             :             }
     101             :         }
     102          40 :         return false;
     103             :     }
     104         330 :     void add(ObjectGroup* group, Shape* shape) {
     105         330 :         MOZ_ASSERT(group && shape);
     106         330 :         if (!entries_) {
     107         290 :             entries_.reset(js_pod_calloc<Entry>(NumEntries));
     108         290 :             if (!entries_)
     109           0 :                 return;
     110             :         } else {
     111         160 :             for (size_t i = NumEntries - 1; i > 0; i--)
     112         120 :                 entries_[i] = entries_[i - 1];
     113             :         }
     114         330 :         entries_[0].group = group;
     115         330 :         entries_[0].shape = shape;
     116             :     }
     117         223 :     void purge() {
     118         223 :         entries_.reset();
     119         223 :     }
     120             : };
     121             : 
     122      112705 : class CrossCompartmentKey
     123             : {
     124             :   public:
     125             :     enum DebuggerObjectKind : uint8_t { DebuggerSource, DebuggerEnvironment, DebuggerObject,
     126             :                                         DebuggerWasmScript, DebuggerWasmSource };
     127             :     using DebuggerAndObject = mozilla::Tuple<NativeObject*, JSObject*, DebuggerObjectKind>;
     128             :     using DebuggerAndScript = mozilla::Tuple<NativeObject*, JSScript*>;
     129             :     using WrappedType = mozilla::Variant<
     130             :         JSObject*,
     131             :         JSString*,
     132             :         DebuggerAndScript,
     133             :         DebuggerAndObject>;
     134             : 
     135         565 :     explicit CrossCompartmentKey(JSObject* obj) : wrapped(obj) { MOZ_RELEASE_ASSERT(obj); }
     136             :     explicit CrossCompartmentKey(JSString* str) : wrapped(str) { MOZ_RELEASE_ASSERT(str); }
     137       57434 :     explicit CrossCompartmentKey(const JS::Value& v)
     138       57434 :       : wrapped(v.isString() ? WrappedType(v.toString()) : WrappedType(&v.toObject()))
     139       57434 :     {}
     140           0 :     explicit CrossCompartmentKey(NativeObject* debugger, JSObject* obj, DebuggerObjectKind kind)
     141           0 :       : wrapped(DebuggerAndObject(debugger, obj, kind))
     142             :     {
     143           0 :         MOZ_RELEASE_ASSERT(debugger);
     144           0 :         MOZ_RELEASE_ASSERT(obj);
     145           0 :     }
     146           0 :     explicit CrossCompartmentKey(NativeObject* debugger, JSScript* script)
     147           0 :       : wrapped(DebuggerAndScript(debugger, script))
     148             :     {
     149           0 :         MOZ_RELEASE_ASSERT(debugger);
     150           0 :         MOZ_RELEASE_ASSERT(script);
     151           0 :     }
     152             : 
     153           0 :     bool operator==(const CrossCompartmentKey& other) const { return wrapped == other.wrapped; }
     154        2101 :     bool operator!=(const CrossCompartmentKey& other) const { return wrapped != other.wrapped; }
     155             : 
     156       28864 :     template <typename T> bool is() const { return wrapped.is<T>(); }
     157          37 :     template <typename T> const T& as() const { return wrapped.as<T>(); }
     158             : 
     159             :     template <typename F>
     160       76351 :     auto applyToWrapped(F f) -> decltype(f(static_cast<JSObject**>(nullptr))) {
     161             :         using ReturnType = decltype(f(static_cast<JSObject**>(nullptr)));
     162             :         struct WrappedMatcher {
     163             :             F f_;
     164       76351 :             explicit WrappedMatcher(F f) : f_(f) {}
     165       75352 :             ReturnType match(JSObject*& obj) { return f_(&obj); }
     166         999 :             ReturnType match(JSString*& str) { return f_(&str); }
     167           0 :             ReturnType match(DebuggerAndScript& tpl) { return f_(&mozilla::Get<1>(tpl)); }
     168           0 :             ReturnType match(DebuggerAndObject& tpl) { return f_(&mozilla::Get<1>(tpl)); }
     169       76351 :         } matcher(f);
     170       76351 :         return wrapped.match(matcher);
     171             :     }
     172             : 
     173             :     template <typename F>
     174        2101 :     auto applyToDebugger(F f) -> decltype(f(static_cast<NativeObject**>(nullptr))) {
     175             :         using ReturnType = decltype(f(static_cast<NativeObject**>(nullptr)));
     176             :         struct DebuggerMatcher {
     177             :             F f_;
     178        2101 :             explicit DebuggerMatcher(F f) : f_(f) {}
     179        2101 :             ReturnType match(JSObject*& obj) { return ReturnType(); }
     180           0 :             ReturnType match(JSString*& str) { return ReturnType(); }
     181           0 :             ReturnType match(DebuggerAndScript& tpl) { return f_(&mozilla::Get<0>(tpl)); }
     182           0 :             ReturnType match(DebuggerAndObject& tpl) { return f_(&mozilla::Get<0>(tpl)); }
     183        2101 :         } matcher(f);
     184        2101 :         return wrapped.match(matcher);
     185             :     }
     186             : 
     187       64641 :     JSCompartment* compartment() {
     188             :         struct GetCompartmentFunctor {
     189       63972 :             JSCompartment* operator()(JSObject** tp) const { return (*tp)->compartment(); }
     190           0 :             JSCompartment* operator()(JSScript** tp) const { return (*tp)->compartment(); }
     191         669 :             JSCompartment* operator()(JSString** tp) const { return nullptr; }
     192             :         };
     193       64641 :         return applyToWrapped(GetCompartmentFunctor());
     194             :     }
     195             : 
     196             :     struct Hasher : public DefaultHasher<CrossCompartmentKey>
     197             :     {
     198             :         struct HashFunctor {
     199       57451 :             HashNumber match(JSObject* obj) { return DefaultHasher<JSObject*>::hash(obj); }
     200         655 :             HashNumber match(JSString* str) { return DefaultHasher<JSString*>::hash(str); }
     201           0 :             HashNumber match(const DebuggerAndScript& tpl) {
     202           0 :                 return DefaultHasher<NativeObject*>::hash(mozilla::Get<0>(tpl)) ^
     203           0 :                        DefaultHasher<JSScript*>::hash(mozilla::Get<1>(tpl));
     204             :             }
     205           0 :             HashNumber match(const DebuggerAndObject& tpl) {
     206           0 :                 return DefaultHasher<NativeObject*>::hash(mozilla::Get<0>(tpl)) ^
     207           0 :                        DefaultHasher<JSObject*>::hash(mozilla::Get<1>(tpl)) ^
     208           0 :                        (mozilla::Get<2>(tpl) << 5);
     209             :             }
     210             :         };
     211       58106 :         static HashNumber hash(const CrossCompartmentKey& key) {
     212       58106 :             return key.wrapped.match(HashFunctor());
     213             :         }
     214             : 
     215       26321 :         static bool match(const CrossCompartmentKey& l, const CrossCompartmentKey& k) {
     216       26321 :             return l.wrapped == k.wrapped;
     217             :         }
     218             :     };
     219             : 
     220        9609 :     bool isTenured() const {
     221             :         struct IsTenuredFunctor {
     222             :             using ReturnType = bool;
     223        9279 :             ReturnType operator()(JSObject** tp) { return !IsInsideNursery(*tp); }
     224           0 :             ReturnType operator()(JSScript** tp) { return true; }
     225         330 :             ReturnType operator()(JSString** tp) { return true; }
     226             :         };
     227        9609 :         return const_cast<CrossCompartmentKey*>(this)->applyToWrapped(IsTenuredFunctor());
     228             :     }
     229             : 
     230             :     void trace(JSTracer* trc);
     231             :     bool needsSweep();
     232             : 
     233             :   private:
     234             :     CrossCompartmentKey() = delete;
     235             :     WrappedType wrapped;
     236             : };
     237             : 
     238             : // The data structure for storing CCWs, which has a map per target compartment
     239             : // so we can access them easily. Note string CCWs are stored separately from the
     240             : // others because they have target compartment nullptr.
     241         315 : class WrapperMap
     242             : {
     243             :     static const size_t InitialInnerMapSize = 4;
     244             : 
     245             :     using InnerMap = NurseryAwareHashMap<CrossCompartmentKey,
     246             :                                          JS::Value,
     247             :                                          CrossCompartmentKey::Hasher,
     248             :                                          SystemAllocPolicy>;
     249             :     using OuterMap = GCHashMap<JSCompartment*,
     250             :                                InnerMap,
     251             :                                DefaultHasher<JSCompartment*>,
     252             :                                SystemAllocPolicy>;
     253             : 
     254             :     OuterMap map;
     255             : 
     256             :   public:
     257         624 :     class Enum
     258             :     {
     259             :       public:
     260             :         enum SkipStrings : bool {
     261             :             WithStrings = false,
     262             :             WithoutStrings = true
     263             :         };
     264             : 
     265             :       private:
     266             :         Enum(const Enum&) = delete;
     267             :         void operator=(const Enum&) = delete;
     268             : 
     269        1491 :         void goToNext() {
     270        1491 :             if (outer.isNothing())
     271          11 :                 return;
     272        1506 :             for (; !outer->empty(); outer->popFront()) {
     273        1266 :                 JSCompartment* c = outer->front().key();
     274             :                 // Need to skip string at first, because the filter may not be
     275             :                 // happy with a nullptr.
     276        1266 :                 if (!c && skipStrings)
     277          13 :                     continue;
     278        1253 :                 if (filter && !filter->match(c))
     279           0 :                     continue;
     280        1253 :                 InnerMap& m = outer->front().value();
     281        1253 :                 if (!m.empty()) {
     282        1253 :                     if (inner.isSome())
     283        1053 :                         inner.reset();
     284        1253 :                     inner.emplace(m);
     285        1253 :                     outer->popFront();
     286        1253 :                     return;
     287             :                 }
     288             :             }
     289             :         }
     290             : 
     291             :         mozilla::Maybe<OuterMap::Enum> outer;
     292             :         mozilla::Maybe<InnerMap::Enum> inner;
     293             :         const CompartmentFilter* filter;
     294             :         SkipStrings skipStrings;
     295             : 
     296             :       public:
     297         211 :         explicit Enum(WrapperMap& m, SkipStrings s = WithStrings) :
     298         211 :                 filter(nullptr), skipStrings(s) {
     299         211 :             outer.emplace(m.map);
     300         211 :             goToNext();
     301         211 :         }
     302             : 
     303          16 :         Enum(WrapperMap& m, const CompartmentFilter& f, SkipStrings s = WithStrings) :
     304          16 :                 filter(&f), skipStrings(s) {
     305          16 :             outer.emplace(m.map);
     306          16 :             goToNext();
     307          16 :         }
     308             : 
     309         397 :         Enum(WrapperMap& m, JSCompartment* target) {
     310             :             // Leave the outer map as nothing and only iterate the inner map we
     311             :             // find here.
     312         397 :             auto p = m.map.lookup(target);
     313         397 :             if (p)
     314          12 :                 inner.emplace(p->value());
     315         397 :         }
     316             : 
     317       13982 :         bool empty() const {
     318       17148 :             return (outer.isNothing() || outer->empty()) &&
     319       18654 :                    (inner.isNothing() || inner->empty());
     320             :         }
     321             : 
     322        6716 :         InnerMap::Entry& front() const {
     323        6716 :             MOZ_ASSERT(inner.isSome() && !inner->empty());
     324        6716 :             return inner->front();
     325             :         }
     326             : 
     327        6679 :         void popFront() {
     328        6679 :             MOZ_ASSERT(!empty());
     329        6679 :             if (!inner->empty()) {
     330        6679 :                 inner->popFront();
     331        6679 :                 if (!inner->empty())
     332        5415 :                     return;
     333             :             }
     334        1264 :             goToNext();
     335             :         }
     336             : 
     337          34 :         void removeFront() {
     338          34 :             MOZ_ASSERT(inner.isSome());
     339          34 :             inner->removeFront();
     340          34 :         }
     341             :     };
     342             : 
     343             :     class Ptr : public InnerMap::Ptr
     344             :     {
     345             :         friend class WrapperMap;
     346             : 
     347             :         InnerMap* map;
     348             : 
     349       28257 :         Ptr() : InnerMap::Ptr(), map(nullptr) {}
     350       20133 :         Ptr(const InnerMap::Ptr& p, InnerMap& m) : InnerMap::Ptr(p), map(&m) {}
     351             :     };
     352             : 
     353         315 :     MOZ_MUST_USE bool init(uint32_t len) { return map.init(len); }
     354             : 
     355          15 :     bool empty() {
     356          15 :         if (map.empty())
     357          15 :             return true;
     358           0 :         for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
     359           0 :             if (!e.front().value().empty())
     360           0 :                 return false;
     361             :         }
     362           0 :         return true;
     363             :     }
     364             : 
     365       48390 :     Ptr lookup(const CrossCompartmentKey& k) const {
     366       48390 :         auto op = map.lookup(const_cast<CrossCompartmentKey&>(k).compartment());
     367       48390 :         if (op) {
     368       40220 :             auto ip = op->value().lookup(k);
     369       40220 :             if (ip)
     370       20133 :                 return Ptr(ip, op->value());
     371             :         }
     372       28257 :         return Ptr();
     373             :     }
     374             : 
     375          10 :     void remove(Ptr p) {
     376          10 :         if (p)
     377          10 :             p.map->remove(p);
     378          10 :     }
     379             : 
     380        9609 :     MOZ_MUST_USE bool put(const CrossCompartmentKey& k, const JS::Value& v) {
     381        9609 :         JSCompartment* c = const_cast<CrossCompartmentKey&>(k).compartment();
     382        9609 :         MOZ_ASSERT(k.is<JSString*>() == !c);
     383        9609 :         auto p = map.lookupForAdd(c);
     384        9609 :         if (!p) {
     385        3362 :             InnerMap m;
     386        1681 :             if (!m.init(InitialInnerMapSize) || !map.add(p, c, mozilla::Move(m)))
     387           0 :                 return false;
     388             :         }
     389        9609 :         return p->value().put(k, v);
     390             :     }
     391             : 
     392           0 :     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
     393           0 :         size_t size = map.sizeOfExcludingThis(mallocSizeOf);
     394           0 :         for (OuterMap::Enum e(map); !e.empty(); e.popFront())
     395           0 :             size += e.front().value().sizeOfExcludingThis(mallocSizeOf);
     396           0 :         return size;
     397             :     }
     398             :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
     399             :         size_t size = map.sizeOfIncludingThis(mallocSizeOf);
     400             :         for (OuterMap::Enum e(map); !e.empty(); e.popFront())
     401             :             size += e.front().value().sizeOfIncludingThis(mallocSizeOf);
     402             :         return size;
     403             :     }
     404             : 
     405          16 :     bool hasNurseryAllocatedWrapperEntries(const CompartmentFilter& f) {
     406          16 :         for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
     407           0 :             JSCompartment* c = e.front().key();
     408           0 :             if (c && !f.match(c))
     409           0 :                 continue;
     410           0 :             InnerMap& m = e.front().value();
     411           0 :             if (m.hasNurseryEntries())
     412           0 :                 return true;
     413             :         }
     414          16 :         return false;
     415             :     }
     416             : 
     417        2415 :     void sweepAfterMinorGC(JSTracer* trc) {
     418       14843 :         for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
     419       12428 :             InnerMap& m = e.front().value();
     420       12428 :             m.sweepAfterMinorGC(trc);
     421       12428 :             if (m.empty())
     422          31 :                 e.removeFront();
     423             :         }
     424        2415 :     }
     425             : 
     426           0 :     void sweep() {
     427           0 :         for (OuterMap::Enum e(map); !e.empty(); e.popFront()) {
     428           0 :             InnerMap& m = e.front().value();
     429           0 :             m.sweep();
     430           0 :             if (m.empty())
     431           0 :                 e.removeFront();
     432             :         }
     433           0 :     }
     434             : };
     435             : 
     436             : // We must ensure that all newly allocated JSObjects get their metadata
     437             : // set. However, metadata builders may require the new object be in a sane
     438             : // state (eg, have its reserved slots initialized so they can get the
     439             : // sizeOfExcludingThis of the object). Therefore, for objects of certain
     440             : // JSClasses (those marked with JSCLASS_DELAY_METADATA_BUILDER), it is not safe
     441             : // for the allocation paths to call the object metadata builder
     442             : // immediately. Instead, the JSClass-specific "constructor" C++ function up the
     443             : // stack makes a promise that it will ensure that the new object has its
     444             : // metadata set after the object is initialized.
     445             : //
     446             : // To help those constructor functions keep their promise of setting metadata,
     447             : // each compartment is in one of three states at any given time:
     448             : //
     449             : // * ImmediateMetadata: Allocators should set new object metadata immediately,
     450             : //                      as usual.
     451             : //
     452             : // * DelayMetadata: Allocators should *not* set new object metadata, it will be
     453             : //                  handled after reserved slots are initialized by custom code
     454             : //                  for the object's JSClass. The newly allocated object's
     455             : //                  JSClass *must* have the JSCLASS_DELAY_METADATA_BUILDER flag
     456             : //                  set.
     457             : //
     458             : // * PendingMetadata: This object has been allocated and is still pending its
     459             : //                    metadata. This should never be the case when we begin an
     460             : //                    allocation, as a constructor function was supposed to have
     461             : //                    set the metadata of the previous object *before*
     462             : //                    allocating another object.
     463             : //
     464             : // The js::AutoSetNewObjectMetadata RAII class provides an ergonomic way for
     465             : // constructor functions to navigate state transitions, and its instances
     466             : // collectively maintain a stack of previous states. The stack is required to
     467             : // support the lazy resolution and allocation of global builtin constructors and
     468             : // prototype objects. The initial (and intuitively most common) state is
     469             : // ImmediateMetadata.
     470             : //
     471             : // Without the presence of internal errors (such as OOM), transitions between
     472             : // the states are as follows:
     473             : //
     474             : //     ImmediateMetadata                 .----- previous state on stack
     475             : //           |                           |          ^
     476             : //           | via constructor           |          |
     477             : //           |                           |          | via setting the new
     478             : //           |        via constructor    |          | object's metadata
     479             : //           |   .-----------------------'          |
     480             : //           |   |                                  |
     481             : //           V   V                                  |
     482             : //     DelayMetadata -------------------------> PendingMetadata
     483             : //                         via allocation
     484             : //
     485             : // In the presence of internal errors, we do not set the new object's metadata
     486             : // (if it was even allocated) and reset to the previous state on the stack.
     487             : 
     488             : struct ImmediateMetadata { };
     489             : struct DelayMetadata { };
     490             : using PendingMetadata = JSObject*;
     491             : 
     492             : using NewObjectMetadataState = mozilla::Variant<ImmediateMetadata,
     493             :                                                 DelayMetadata,
     494             :                                                 PendingMetadata>;
     495             : 
     496             : class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter
     497             : {
     498             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
     499             : 
     500             :     JSContext* cx_;
     501             :     NewObjectMetadataState prevState_;
     502             : 
     503             :     AutoSetNewObjectMetadata(const AutoSetNewObjectMetadata& aOther) = delete;
     504             :     void operator=(const AutoSetNewObjectMetadata& aOther) = delete;
     505             : 
     506             :   protected:
     507           0 :     virtual void trace(JSTracer* trc) override {
     508           0 :         if (prevState_.is<PendingMetadata>()) {
     509             :             TraceRoot(trc,
     510           0 :                       &prevState_.as<PendingMetadata>(),
     511           0 :                       "Object pending metadata");
     512             :         }
     513           0 :     }
     514             : 
     515             :   public:
     516             :     explicit AutoSetNewObjectMetadata(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     517             :     ~AutoSetNewObjectMetadata();
     518             : };
     519             : 
     520             : } /* namespace js */
     521             : 
     522             : namespace js {
     523             : class DebugEnvironments;
     524             : class ObjectWeakMap;
     525             : class WatchpointMap;
     526             : class WeakMapBase;
     527             : } // namespace js
     528             : 
     529             : struct JSCompartment
     530             : {
     531             :     const JS::CompartmentCreationOptions creationOptions_;
     532             :     JS::CompartmentBehaviors behaviors_;
     533             : 
     534             :   private:
     535             :     JS::Zone*                    zone_;
     536             :     JSRuntime*                   runtime_;
     537             : 
     538             :   public:
     539             :     /*
     540             :      * The principals associated with this compartment. Note that the
     541             :      * same several compartments may share the same principals and
     542             :      * that a compartment may change principals during its lifetime
     543             :      * (e.g. in case of lazy parsing).
     544             :      */
     545      109275 :     inline JSPrincipals* principals() {
     546      109275 :         return principals_;
     547             :     }
     548         308 :     inline void setPrincipals(JSPrincipals* principals) {
     549         308 :         if (principals_ == principals)
     550           0 :             return;
     551             : 
     552             :         // If we change principals, we need to unlink immediately this
     553             :         // compartment from its PerformanceGroup. For one thing, the
     554             :         // performance data we collect should not be improperly associated
     555             :         // with a group to which we do not belong anymore. For another thing,
     556             :         // we use `principals()` as part of the key to map compartments
     557             :         // to a `PerformanceGroup`, so if we do not unlink now, this will
     558             :         // be too late once we have updated `principals_`.
     559         308 :         performanceMonitoring.unlink();
     560         308 :         principals_ = principals;
     561             :     }
     562       17614 :     inline bool isSystem() const {
     563       17614 :         return isSystem_;
     564             :     }
     565         315 :     inline void setIsSystem(bool isSystem) {
     566         315 :         if (isSystem_ == isSystem)
     567          28 :             return;
     568             : 
     569             :         // If we change `isSystem*(`, we need to unlink immediately this
     570             :         // compartment from its PerformanceGroup. For one thing, the
     571             :         // performance data we collect should not be improperly associated
     572             :         // to a group to which we do not belong anymore. For another thing,
     573             :         // we use `isSystem()` as part of the key to map compartments
     574             :         // to a `PerformanceGroup`, so if we do not unlink now, this will
     575             :         // be too late once we have updated `isSystem_`.
     576         287 :         performanceMonitoring.unlink();
     577         287 :         isSystem_ = isSystem;
     578             :     }
     579             : 
     580     1036278 :     bool isAtomsCompartment() const {
     581     1036278 :         return isAtomsCompartment_;
     582             :     }
     583           4 :     void setIsAtomsCompartment() {
     584           4 :         isAtomsCompartment_ = true;
     585           4 :     }
     586             : 
     587             :     // Used to approximate non-content code when reporting telemetry.
     588       21274 :     inline bool isProbablySystemOrAddonCode() const {
     589       21274 :         if (creationOptions_.addonIdOrNull())
     590         285 :             return true;
     591             : 
     592       20989 :         return isSystem_;
     593             :     }
     594             :   private:
     595             :     JSPrincipals*                principals_;
     596             :     bool                         isSystem_;
     597             :     bool                         isAtomsCompartment_;
     598             : 
     599             :   public:
     600             :     bool                         isSelfHosting;
     601             :     bool                         marked;
     602             :     bool                         warnedAboutDateToLocaleFormat;
     603             :     bool                         warnedAboutExprClosure;
     604             :     bool                         warnedAboutForEach;
     605             :     uint32_t                     warnedAboutStringGenericsMethods;
     606             : 
     607             : #ifdef DEBUG
     608             :     bool                         firedOnNewGlobalObject;
     609             : #endif
     610             : 
     611         764 :     void mark() { marked = true; }
     612             : 
     613             :   private:
     614             :     friend struct JSRuntime;
     615             :     friend struct JSContext;
     616             :     js::ReadBarrieredGlobalObject global_;
     617             : 
     618             :     unsigned                     enterCompartmentDepth;
     619             : 
     620             :   public:
     621             :     js::PerformanceGroupHolder performanceMonitoring;
     622             : 
     623      146046 :     void enter() {
     624      146046 :         enterCompartmentDepth++;
     625      146046 :     }
     626      146038 :     void leave() {
     627      146038 :         enterCompartmentDepth--;
     628      146038 :     }
     629      574201 :     bool hasBeenEntered() { return !!enterCompartmentDepth; }
     630             : 
     631     4750983 :     JS::Zone* zone() { return zone_; }
     632             :     const JS::Zone* zone() const { return zone_; }
     633             : 
     634        2809 :     const JS::CompartmentCreationOptions& creationOptions() const { return creationOptions_; }
     635       31697 :     JS::CompartmentBehaviors& behaviors() { return behaviors_; }
     636             :     const JS::CompartmentBehaviors& behaviors() const { return behaviors_; }
     637             : 
     638         323 :     JSRuntime* runtimeFromActiveCooperatingThread() const {
     639         323 :         MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
     640         323 :         return runtime_;
     641             :     }
     642             : 
     643             :     // Note: Unrestricted access to the zone's runtime from an arbitrary
     644             :     // thread can easily lead to races. Use this method very carefully.
     645      694217 :     JSRuntime* runtimeFromAnyThread() const {
     646      694217 :         return runtime_;
     647             :     }
     648             : 
     649             :     /*
     650             :      * Nb: global_ might be nullptr, if (a) it's the atoms compartment, or
     651             :      * (b) the compartment's global has been collected.  The latter can happen
     652             :      * if e.g. a string in a compartment is rooted but no object is, and thus
     653             :      * the global isn't rooted, and thus the global can be finalized while the
     654             :      * compartment lives on.
     655             :      *
     656             :      * In contrast, JSObject::global() is infallible because marking a JSObject
     657             :      * always marks its global as well.
     658             :      * TODO: add infallible JSScript::global()
     659             :      */
     660             :     inline js::GlobalObject* maybeGlobal() const;
     661             : 
     662             :     /* An unbarriered getter for use while tracing. */
     663             :     inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
     664             : 
     665             :     inline void initGlobal(js::GlobalObject& global);
     666             : 
     667             :   public:
     668             :     void*                        data;
     669             : 
     670             :   private:
     671             :     const js::AllocationMetadataBuilder *allocationMetadataBuilder;
     672             : 
     673             :     js::SavedStacks              savedStacks_;
     674             : 
     675             :     js::WrapperMap               crossCompartmentWrappers;
     676             : 
     677             :     using CCKeyVector = mozilla::Vector<js::CrossCompartmentKey, 0, js::SystemAllocPolicy>;
     678             :     CCKeyVector                  nurseryCCKeys;
     679             : 
     680             :     // The global environment record's [[VarNames]] list that contains all
     681             :     // names declared using FunctionDeclaration, GeneratorDeclaration, and
     682             :     // VariableDeclaration declarations in global code in this compartment.
     683             :     // Names are only removed from this list by a |delete IdentifierReference|
     684             :     // that successfully removes that global property.
     685             :     JS::GCHashSet<JSAtom*,
     686             :                   js::DefaultHasher<JSAtom*>,
     687             :                   js::SystemAllocPolicy> varNames_;
     688             : 
     689             :   public:
     690             :     /* Last time at which an animation was played for a global in this compartment. */
     691             :     int64_t                      lastAnimationTime;
     692             : 
     693             :     js::RegExpCompartment        regExps;
     694             : 
     695             :     /*
     696             :      * For generational GC, record whether a write barrier has added this
     697             :      * compartment's global to the store buffer since the last minor GC.
     698             :      *
     699             :      * This is used to avoid calling into the VM every time a nursery object is
     700             :      * written to a property of the global.
     701             :      */
     702             :     uint32_t                     globalWriteBarriered;
     703             : 
     704             :     // Non-zero if the storage underlying any typed object in this compartment
     705             :     // might be detached.
     706             :     int32_t                      detachedTypedObjects;
     707             : 
     708             :   private:
     709             :     friend class js::AutoSetNewObjectMetadata;
     710             :     js::NewObjectMetadataState objectMetadataState;
     711             : 
     712             :   public:
     713             :     // Recompute the probability with which this compartment should record
     714             :     // profiling data (stack traces, allocations log, etc.) about each
     715             :     // allocation. We consult the probabilities requested by the Debugger
     716             :     // instances observing us, if any.
     717           0 :     void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
     718             : 
     719      325519 :     bool hasObjectPendingMetadata() const { return objectMetadataState.is<js::PendingMetadata>(); }
     720             : 
     721       16470 :     void setObjectPendingMetadata(JSContext* cx, JSObject* obj) {
     722       16470 :         if (!cx->helperThread()) {
     723       16167 :             MOZ_ASSERT(objectMetadataState.is<js::DelayMetadata>());
     724       16167 :             objectMetadataState = js::NewObjectMetadataState(js::PendingMetadata(obj));
     725             :         }
     726       16470 :     }
     727             : 
     728             :   public:
     729             :     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
     730             :                                 size_t* tiAllocationSiteTables,
     731             :                                 size_t* tiArrayTypeTables,
     732             :                                 size_t* tiObjectTypeTables,
     733             :                                 size_t* compartmentObject,
     734             :                                 size_t* compartmentTables,
     735             :                                 size_t* innerViews,
     736             :                                 size_t* lazyArrayBuffers,
     737             :                                 size_t* objectMetadataTables,
     738             :                                 size_t* crossCompartmentWrappers,
     739             :                                 size_t* savedStacksSet,
     740             :                                 size_t* varNamesSet,
     741             :                                 size_t* nonSyntacticLexicalScopes,
     742             :                                 size_t* templateLiteralMap,
     743             :                                 size_t* jitCompartment,
     744             :                                 size_t* privateData);
     745             : 
     746             :     // Object group tables and other state in the compartment.
     747             :     js::ObjectGroupCompartment   objectGroups;
     748             : 
     749             : #ifdef JSGC_HASH_TABLE_CHECKS
     750             :     void checkWrapperMapAfterMovingGC();
     751             :     void checkScriptMapsAfterMovingGC();
     752             : #endif
     753             : 
     754             :     /*
     755             :      * Lazily initialized script source object to use for scripts cloned
     756             :      * from the self-hosting global.
     757             :      */
     758             :     js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
     759             : 
     760             :     // Keep track of the metadata objects which can be associated with each JS
     761             :     // object. Both keys and values are in this compartment.
     762             :     js::ObjectWeakMap* objectMetadataTable;
     763             : 
     764             :     // Map from array buffers to views sharing that storage.
     765             :     JS::WeakCache<js::InnerViewTable> innerViews;
     766             : 
     767             :     // Inline transparent typed objects do not initially have an array buffer,
     768             :     // but can have that buffer created lazily if it is accessed later. This
     769             :     // table manages references from such typed objects to their buffers.
     770             :     js::ObjectWeakMap* lazyArrayBuffers;
     771             : 
     772             :     // All unboxed layouts in the compartment.
     773             :     mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
     774             : 
     775             :     // WebAssembly state for the compartment.
     776             :     js::wasm::Compartment wasm;
     777             : 
     778             :   private:
     779             :     // All non-syntactic lexical environments in the compartment. These are kept in
     780             :     // a map because when loading scripts into a non-syntactic environment, we need
     781             :     // to use the same lexical environment to persist lexical bindings.
     782             :     js::ObjectWeakMap* nonSyntacticLexicalEnvironments_;
     783             : 
     784             :     // The realm's [[TemplateMap]], used for mapping template literals to
     785             :     // unique template objects used in evaluation of tagged template literals.
     786             :     //
     787             :     // See ES 12.2.9.3.
     788             :     js::TemplateRegistry templateLiteralMap_;
     789             : 
     790             :   public:
     791             :     /* During GC, stores the index of this compartment in rt->compartments. */
     792             :     unsigned                     gcIndex;
     793             : 
     794             :     /*
     795             :      * During GC, stores the head of a list of incoming pointers from gray cells.
     796             :      *
     797             :      * The objects in the list are either cross-compartment wrappers, or
     798             :      * debugger wrapper objects.  The list link is either in the second extra
     799             :      * slot for the former, or a special slot for the latter.
     800             :      */
     801             :     JSObject*                    gcIncomingGrayPointers;
     802             : 
     803             :   private:
     804             :     enum {
     805             :         IsDebuggee = 1 << 0,
     806             :         DebuggerObservesAllExecution = 1 << 1,
     807             :         DebuggerObservesAsmJS = 1 << 2,
     808             :         DebuggerObservesCoverage = 1 << 3,
     809             :         DebuggerObservesBinarySource = 1 << 4,
     810             :         DebuggerNeedsDelazification = 1 << 5
     811             :     };
     812             : 
     813             :     unsigned debugModeBits;
     814             :     friend class AutoRestoreCompartmentDebugMode;
     815             : 
     816             :     static const unsigned DebuggerObservesMask = IsDebuggee |
     817             :                                                  DebuggerObservesAllExecution |
     818             :                                                  DebuggerObservesCoverage |
     819             :                                                  DebuggerObservesAsmJS |
     820             :                                                  DebuggerObservesBinarySource;
     821             : 
     822             :     void updateDebuggerObservesFlag(unsigned flag);
     823             : 
     824             :     bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj);
     825             :     bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj);
     826             : 
     827             :   private:
     828             :     // This pointer is controlled by the embedder. If it is non-null, and if
     829             :     // cx->enableAccessValidation is true, then we assert that *validAccessPtr
     830             :     // is true before running any code in this compartment.
     831             :     bool* validAccessPtr;
     832             : 
     833             :   public:
     834         794 :     bool isAccessValid() const { return validAccessPtr ? *validAccessPtr : true; }
     835           4 :     void setValidAccessPtr(bool* accessp) { validAccessPtr = accessp; }
     836             : 
     837             :   public:
     838             :     JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options);
     839             :     ~JSCompartment();
     840             : 
     841             :     MOZ_MUST_USE bool init(JSContext* maybecx);
     842             : 
     843             :     MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
     844             : 
     845             :     MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
     846             :     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj);
     847             :     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
     848             :     MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<JS::GCVector<JS::Value>> vec);
     849             :     MOZ_MUST_USE bool rewrap(JSContext* cx, JS::MutableHandleObject obj, JS::HandleObject existing);
     850             : 
     851             :     MOZ_MUST_USE bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped,
     852             :                                  const js::Value& wrapper);
     853             : 
     854         353 :     js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) const {
     855         353 :         return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
     856             :     }
     857             : 
     858         553 :     js::WrapperMap::Ptr lookupWrapper(JSObject* obj) const {
     859         553 :         return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(obj));
     860             :     }
     861             : 
     862          10 :     void removeWrapper(js::WrapperMap::Ptr p) {
     863          10 :         crossCompartmentWrappers.remove(p);
     864          10 :     }
     865             : 
     866          16 :     bool hasNurseryAllocatedWrapperEntries(const js::CompartmentFilter& f) {
     867          16 :         return crossCompartmentWrappers.hasNurseryAllocatedWrapperEntries(f);
     868             :     }
     869             : 
     870           0 :     struct WrapperEnum : public js::WrapperMap::Enum {
     871           0 :         explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
     872             :     };
     873             : 
     874         624 :     struct NonStringWrapperEnum : public js::WrapperMap::Enum {
     875         211 :         explicit NonStringWrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers, WithoutStrings) {}
     876          16 :         explicit NonStringWrapperEnum(JSCompartment* c, const js::CompartmentFilter& f) : js::WrapperMap::Enum(c->crossCompartmentWrappers, f, WithoutStrings) {}
     877         397 :         explicit NonStringWrapperEnum(JSCompartment* c, JSCompartment* target) : js::WrapperMap::Enum(c->crossCompartmentWrappers, target) { MOZ_ASSERT(target); }
     878             :     };
     879             : 
     880           0 :     struct StringWrapperEnum : public js::WrapperMap::Enum {
     881           0 :         explicit StringWrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers, nullptr) {}
     882             :     };
     883             : 
     884             :     js::LexicalEnvironmentObject*
     885             :     getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, js::HandleObject enclosing);
     886             :     js::LexicalEnvironmentObject* getNonSyntacticLexicalEnvironment(JSObject* enclosing) const;
     887             : 
     888             :     /*
     889             :      * This method traces data that is live iff we know that this compartment's
     890             :      * global is still live.
     891             :      */
     892             :     void traceGlobal(JSTracer* trc);
     893             :     /*
     894             :      * This method traces JSCompartment-owned GC roots that are considered live
     895             :      * regardless of whether the compartment's global is still live.
     896             :      */
     897             :     void traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark);
     898             :     /*
     899             :      * This method clears out tables of roots in preparation for the final GC.
     900             :      */
     901             :     void finishRoots();
     902             :     /*
     903             :      * These methods mark pointers that cross compartment boundaries. They are
     904             :      * called in per-zone GCs to prevent the wrappers' outgoing edges from
     905             :      * dangling (full GCs naturally follow pointers across compartments) and
     906             :      * when compacting to update cross-compartment pointers.
     907             :      */
     908             :     void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
     909             :     static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
     910             : 
     911             :     /* Whether to preserve JIT code on non-shrinking GCs. */
     912         223 :     bool preserveJitCode() { return creationOptions_.preserveJitCode(); }
     913             : 
     914             :     void sweepAfterMinorGC(JSTracer* trc);
     915             : 
     916             :     void sweepCrossCompartmentWrappers();
     917             :     void sweepSavedStacks();
     918             :     void sweepTemplateLiteralMap();
     919             :     void sweepGlobalObject();
     920             :     void sweepSelfHostingScriptSource();
     921             :     void sweepJitCompartment(js::FreeOp* fop);
     922             :     void sweepRegExps();
     923             :     void sweepDebugEnvironments();
     924             :     void sweepNativeIterators();
     925             :     void sweepTemplateObjects();
     926             :     void sweepVarNames();
     927             :     void sweepWatchpoints();
     928             : 
     929             :     void purge();
     930             :     void clearTables();
     931             : 
     932             :     static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
     933             :     void fixupAfterMovingGC();
     934             :     void fixupGlobal();
     935             :     void fixupScriptMapsAfterMovingGC();
     936             : 
     937      160904 :     bool hasAllocationMetadataBuilder() const { return allocationMetadataBuilder; }
     938           0 :     const js::AllocationMetadataBuilder* getAllocationMetadataBuilder() const {
     939           0 :         return allocationMetadataBuilder;
     940             :     }
     941             :     void setAllocationMetadataBuilder(const js::AllocationMetadataBuilder* builder);
     942           0 :     void forgetAllocationMetadataBuilder() {
     943           0 :         allocationMetadataBuilder = nullptr;
     944           0 :     }
     945             :     void setNewObjectMetadata(JSContext* cx, JS::HandleObject obj);
     946             :     void clearObjectMetadata();
     947          78 :     const void* addressOfMetadataBuilder() const {
     948          78 :         return &allocationMetadataBuilder;
     949             :     }
     950             : 
     951       32864 :     js::SavedStacks& savedStacks() { return savedStacks_; }
     952             : 
     953             :     // Add a name to [[VarNames]].  Reports OOM on failure.
     954             :     MOZ_MUST_USE bool addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name);
     955             : 
     956           0 :     void removeFromVarNames(JS::Handle<JSAtom*> name) {
     957           0 :         varNames_.remove(name);
     958           0 :     }
     959             : 
     960             :     // Whether the given name is in [[VarNames]].
     961        4398 :     bool isInVarNames(JS::Handle<JSAtom*> name) {
     962        4398 :         return varNames_.has(name);
     963             :     }
     964             : 
     965             :     // Get a unique template object given a JS array of raw template strings
     966             :     // and a template object. If a template object is found in template
     967             :     // registry, that object is returned. Otherwise, the passed-in templateObj
     968             :     // is added to the registry.
     969             :     bool getTemplateLiteralObject(JSContext* cx, js::HandleObject rawStrings,
     970             :                                   js::MutableHandleObject templateObj);
     971             : 
     972             :     // Per above, but an entry must already exist in the template registry.
     973             :     JSObject* getExistingTemplateLiteralObject(JSObject* rawStrings);
     974             : 
     975             :     void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
     976             : 
     977             :     js::DtoaCache dtoaCache;
     978             :     js::NewProxyCache newProxyCache;
     979             : 
     980             :     // Random number generator for Math.random().
     981             :     mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator;
     982             : 
     983             :     // Initialize randomNumberGenerator if needed.
     984             :     void ensureRandomNumberGenerator();
     985             : 
     986             :   private:
     987             :     mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_;
     988             : 
     989             :   public:
     990             :     js::HashNumber randomHashCode();
     991             : 
     992             :     mozilla::HashCodeScrambler randomHashCodeScrambler();
     993             : 
     994           0 :     static size_t offsetOfRegExps() {
     995           0 :         return offsetof(JSCompartment, regExps);
     996             :     }
     997             : 
     998             :   private:
     999             :     JSCompartment* thisForCtor() { return this; }
    1000             : 
    1001             :   public:
    1002             :     //
    1003             :     // The Debugger observes execution on a frame-by-frame basis. The
    1004             :     // invariants of JSCompartment's debug mode bits, JSScript::isDebuggee,
    1005             :     // InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
    1006             :     // enumerated below.
    1007             :     //
    1008             :     // 1. When a compartment's isDebuggee() == true, relazification and lazy
    1009             :     //    parsing are disabled.
    1010             :     //
    1011             :     //    Whether AOT wasm is disabled is togglable by the Debugger API. By
    1012             :     //    default it is disabled. See debuggerObservesAsmJS below.
    1013             :     //
    1014             :     // 2. When a compartment's debuggerObservesAllExecution() == true, all of
    1015             :     //    the compartment's scripts are considered debuggee scripts.
    1016             :     //
    1017             :     // 3. A script is considered a debuggee script either when, per above, its
    1018             :     //    compartment is observing all execution, or if it has breakpoints set.
    1019             :     //
    1020             :     // 4. A debuggee script always pushes a debuggee frame.
    1021             :     //
    1022             :     // 5. A debuggee frame calls all slow path Debugger hooks in the
    1023             :     //    Interpreter and Baseline. A debuggee frame implies that its script's
    1024             :     //    BaselineScript, if extant, has been compiled with debug hook calls.
    1025             :     //
    1026             :     // 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
    1027             :     //    that the compiled BaselineScript is compiled with debug hook calls
    1028             :     //    when attempting to enter Baseline.
    1029             :     //
    1030             :     // 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
    1031             :     //    attempt to enter Ion.
    1032             :     //
    1033             :     // Note that a debuggee frame may exist without its script being a
    1034             :     // debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
    1035             :     // frame in which it is evaluating as a debuggee frame.
    1036             :     //
    1037             : 
    1038             :     // True if this compartment's global is a debuggee of some Debugger
    1039             :     // object.
    1040       37371 :     bool isDebuggee() const { return !!(debugModeBits & IsDebuggee); }
    1041           0 :     void setIsDebuggee() { debugModeBits |= IsDebuggee; }
    1042             :     void unsetIsDebuggee();
    1043             : 
    1044             :     // True if this compartment's global is a debuggee of some Debugger
    1045             :     // object with a live hook that observes all execution; e.g.,
    1046             :     // onEnterFrame.
    1047       45234 :     bool debuggerObservesAllExecution() const {
    1048             :         static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution;
    1049       45234 :         return (debugModeBits & Mask) == Mask;
    1050             :     }
    1051           0 :     void updateDebuggerObservesAllExecution() {
    1052           0 :         updateDebuggerObservesFlag(DebuggerObservesAllExecution);
    1053           0 :     }
    1054             : 
    1055             :     // True if this compartment's global is a debuggee of some Debugger object
    1056             :     // whose allowUnobservedAsmJS flag is false.
    1057             :     //
    1058             :     // Note that since AOT wasm functions cannot bail out, this flag really
    1059             :     // means "observe wasm from this point forward". We cannot make
    1060             :     // already-compiled wasm code observable to Debugger.
    1061       21274 :     bool debuggerObservesAsmJS() const {
    1062             :         static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS;
    1063       21274 :         return (debugModeBits & Mask) == Mask;
    1064             :     }
    1065           0 :     void updateDebuggerObservesAsmJS() {
    1066           0 :         updateDebuggerObservesFlag(DebuggerObservesAsmJS);
    1067           0 :     }
    1068             : 
    1069           0 :     bool debuggerObservesBinarySource() const {
    1070             :         static const unsigned Mask = IsDebuggee | DebuggerObservesBinarySource;
    1071           0 :         return (debugModeBits & Mask) == Mask;
    1072             :     }
    1073             : 
    1074           0 :     void updateDebuggerObservesBinarySource() {
    1075           0 :         updateDebuggerObservesFlag(DebuggerObservesBinarySource);
    1076           0 :     }
    1077             : 
    1078             :     // True if this compartment's global is a debuggee of some Debugger object
    1079             :     // whose collectCoverageInfo flag is true.
    1080       11796 :     bool debuggerObservesCoverage() const {
    1081             :         static const unsigned Mask = DebuggerObservesCoverage;
    1082       11796 :         return (debugModeBits & Mask) == Mask;
    1083             :     }
    1084             :     void updateDebuggerObservesCoverage();
    1085             : 
    1086             :     // The code coverage can be enabled either for each compartment, with the
    1087             :     // Debugger API, or for the entire runtime.
    1088             :     bool collectCoverage() const;
    1089             :     bool collectCoverageForDebug() const;
    1090             :     bool collectCoverageForPGO() const;
    1091             :     void clearScriptCounts();
    1092             :     void clearScriptNames();
    1093             : 
    1094          15 :     bool needsDelazificationForDebugger() const {
    1095          15 :         return debugModeBits & DebuggerNeedsDelazification;
    1096             :     }
    1097             : 
    1098             :     /*
    1099             :      * Schedule the compartment to be delazified. Called from
    1100             :      * LazyScript::Create.
    1101             :      */
    1102        4170 :     void scheduleDelazificationForDebugger() { debugModeBits |= DebuggerNeedsDelazification; }
    1103             : 
    1104             :     /*
    1105             :      * If we scheduled delazification for turning on debug mode, delazify all
    1106             :      * scripts.
    1107             :      */
    1108             :     bool ensureDelazifyScriptsForDebugger(JSContext* cx);
    1109             : 
    1110             :     void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JS::HandleObject handler);
    1111             : 
    1112             :   private:
    1113             :     void sweepBreakpoints(js::FreeOp* fop);
    1114             : 
    1115             :   public:
    1116             :     js::WatchpointMap* watchpointMap;
    1117             : 
    1118             :     js::ScriptCountsMap* scriptCountsMap;
    1119             :     js::ScriptNameMap* scriptNameMap;
    1120             : 
    1121             :     js::DebugScriptMap* debugScriptMap;
    1122             : 
    1123             :     /* Bookkeeping information for debug scope objects. */
    1124             :     js::DebugEnvironments* debugEnvs;
    1125             : 
    1126             :     /*
    1127             :      * List of potentially active iterators that may need deleted property
    1128             :      * suppression.
    1129             :      */
    1130             :     js::NativeIterator* enumerators;
    1131             : 
    1132             :     /* Native iterator most recently started. */
    1133             :     js::PropertyIteratorObject* lastCachedNativeIterator;
    1134             : 
    1135             :   private:
    1136             :     /* Used by memory reporters and invalid otherwise. */
    1137             :     JS::CompartmentStats* compartmentStats_;
    1138             : 
    1139             :   public:
    1140             :     // This should only be called when it is non-null, i.e. during memory
    1141             :     // reporting.
    1142           0 :     JS::CompartmentStats& compartmentStats() {
    1143             :         // We use MOZ_RELEASE_ASSERT here because in bug 1132502 there was some
    1144             :         // (inconclusive) evidence that compartmentStats_ can be nullptr
    1145             :         // unexpectedly.
    1146           0 :         MOZ_RELEASE_ASSERT(compartmentStats_);
    1147           0 :         return *compartmentStats_;
    1148             :     }
    1149           0 :     void nullCompartmentStats() {
    1150           0 :         MOZ_ASSERT(compartmentStats_);
    1151           0 :         compartmentStats_ = nullptr;
    1152           0 :     }
    1153           0 :     void setCompartmentStats(JS::CompartmentStats* newStats) {
    1154           0 :         MOZ_ASSERT(!compartmentStats_ && newStats);
    1155           0 :         compartmentStats_ = newStats;
    1156           0 :     }
    1157             : 
    1158             :     MOZ_ALWAYS_INLINE bool objectMaybeInIteration(JSObject* obj);
    1159             : 
    1160             :     // These flags help us to discover if a compartment that shouldn't be alive
    1161             :     // manages to outlive a GC.
    1162             :     bool scheduledForDestruction;
    1163             :     bool maybeAlive;
    1164             : 
    1165             :   private:
    1166             :     js::jit::JitCompartment* jitCompartment_;
    1167             : 
    1168             :     js::ReadBarriered<js::ArgumentsObject*> mappedArgumentsTemplate_;
    1169             :     js::ReadBarriered<js::ArgumentsObject*> unmappedArgumentsTemplate_;
    1170             : 
    1171             :   public:
    1172             :     bool ensureJitCompartmentExists(JSContext* cx);
    1173       44896 :     js::jit::JitCompartment* jitCompartment() {
    1174       44896 :         return jitCompartment_;
    1175             :     }
    1176             : 
    1177             :     js::ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped);
    1178             : 
    1179             :     js::ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const;
    1180             : 
    1181             :   private:
    1182             :     // Used for collecting telemetry on SpiderMonkey's deprecated language extensions.
    1183             :     bool sawDeprecatedLanguageExtension[size_t(js::DeprecatedLanguageExtension::Count)];
    1184             : 
    1185             :     void reportTelemetry();
    1186             : 
    1187             :   public:
    1188             :     void addTelemetry(const char* filename, js::DeprecatedLanguageExtension e);
    1189             : 
    1190             :   public:
    1191             :     // Aggregated output used to collect JSScript hit counts when code coverage
    1192             :     // is enabled.
    1193             :     js::coverage::LCovCompartment lcovOutput;
    1194             : };
    1195             : 
    1196             : namespace js {
    1197             : 
    1198             : // We only set the maybeAlive flag for objects and scripts. It's assumed that,
    1199             : // if a compartment is alive, then it will have at least some live object or
    1200             : // script it in. Even if we get this wrong, the worst that will happen is that
    1201             : // scheduledForDestruction will be set on the compartment, which will cause
    1202             : // some extra GC activity to try to free the compartment.
    1203       25344 : template<typename T> inline void SetMaybeAliveFlag(T* thing) {}
    1204       12882 : template<> inline void SetMaybeAliveFlag(JSObject* thing) {thing->compartment()->maybeAlive = true;}
    1205         904 : template<> inline void SetMaybeAliveFlag(JSScript* thing) {thing->compartment()->maybeAlive = true;}
    1206             : 
    1207             : } // namespace js
    1208             : 
    1209             : inline js::Handle<js::GlobalObject*>
    1210      522013 : JSContext::global() const
    1211             : {
    1212             :     /*
    1213             :      * It's safe to use |unsafeGet()| here because any compartment that is
    1214             :      * on-stack will be marked automatically, so there's no need for a read
    1215             :      * barrier on it. Once the compartment is popped, the handle is no longer
    1216             :      * safe to use.
    1217             :      */
    1218      522013 :     MOZ_ASSERT(compartment_, "Caller needs to enter a compartment first");
    1219      522013 :     return js::Handle<js::GlobalObject*>::fromMarkedLocation(compartment_->global_.unsafeGet());
    1220             : }
    1221             : 
    1222             : namespace js {
    1223             : 
    1224             : class MOZ_RAII AssertCompartmentUnchanged
    1225             : {
    1226             :   public:
    1227        7673 :     explicit AssertCompartmentUnchanged(JSContext* cx
    1228             :                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1229        7673 :       : cx(cx), oldCompartment(cx->compartment())
    1230             :     {
    1231        7673 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1232        7673 :     }
    1233             : 
    1234       15346 :     ~AssertCompartmentUnchanged() {
    1235        7673 :         MOZ_ASSERT(cx->compartment() == oldCompartment);
    1236        7673 :     }
    1237             : 
    1238             :   protected:
    1239             :     JSContext * const cx;
    1240             :     JSCompartment * const oldCompartment;
    1241             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    1242             : };
    1243             : 
    1244             : class AutoCompartment
    1245             : {
    1246             :     JSContext * const cx_;
    1247             :     JSCompartment * const origin_;
    1248             :     const AutoLockForExclusiveAccess* maybeLock_;
    1249             : 
    1250             :   public:
    1251             :     template <typename T>
    1252             :     inline AutoCompartment(JSContext* cx, const T& target);
    1253             :     inline ~AutoCompartment();
    1254             : 
    1255           0 :     JSContext* context() const { return cx_; }
    1256           0 :     JSCompartment* origin() const { return origin_; }
    1257             : 
    1258             :   protected:
    1259             :     inline AutoCompartment(JSContext* cx, JSCompartment* target);
    1260             : 
    1261             :     // Used only for entering the atoms compartment.
    1262             :     inline AutoCompartment(JSContext* cx, JSCompartment* target,
    1263             :                            AutoLockForExclusiveAccess& lock);
    1264             : 
    1265             :   private:
    1266             :     AutoCompartment(const AutoCompartment&) = delete;
    1267             :     AutoCompartment & operator=(const AutoCompartment&) = delete;
    1268             : };
    1269             : 
    1270       62625 : class AutoAtomsCompartment : protected AutoCompartment
    1271             : {
    1272             :   public:
    1273             :     inline AutoAtomsCompartment(JSContext* cx, AutoLockForExclusiveAccess& lock);
    1274             : };
    1275             : 
    1276             : // Enter a compartment directly. Only use this where there's no target GC thing
    1277             : // to pass to AutoCompartment or where you need to avoid the assertions in
    1278             : // JS::Compartment::enterCompartmentOf().
    1279       13101 : class AutoCompartmentUnchecked : protected AutoCompartment
    1280             : {
    1281             :   public:
    1282             :     inline AutoCompartmentUnchecked(JSContext* cx, JSCompartment* target);
    1283             : };
    1284             : 
    1285             : /*
    1286             :  * Use this to change the behavior of an AutoCompartment slightly on error. If
    1287             :  * the exception happens to be an Error object, copy it to the origin compartment
    1288             :  * instead of wrapping it.
    1289             :  */
    1290             : class ErrorCopier
    1291             : {
    1292             :     mozilla::Maybe<AutoCompartment>& ac;
    1293             : 
    1294             :   public:
    1295           0 :     explicit ErrorCopier(mozilla::Maybe<AutoCompartment>& ac)
    1296           0 :       : ac(ac) {}
    1297             :     ~ErrorCopier();
    1298             : };
    1299             : 
    1300             : /*
    1301             :  * AutoWrapperVector and AutoWrapperRooter can be used to store wrappers that
    1302             :  * are obtained from the cross-compartment map. However, these classes should
    1303             :  * not be used if the wrapper will escape. For example, it should not be stored
    1304             :  * in the heap.
    1305             :  *
    1306             :  * The AutoWrapper rooters are different from other autorooters because their
    1307             :  * wrappers are marked on every GC slice rather than just the first one. If
    1308             :  * there's some wrapper that we want to use temporarily without causing it to be
    1309             :  * marked, we can use these AutoWrapper classes. If we get unlucky and a GC
    1310             :  * slice runs during the code using the wrapper, the GC will mark the wrapper so
    1311             :  * that it doesn't get swept out from under us. Otherwise, the wrapper needn't
    1312             :  * be marked. This is useful in functions like JS_TransplantObject that
    1313             :  * manipulate wrappers in compartments that may no longer be alive.
    1314             :  */
    1315             : 
    1316             : /*
    1317             :  * This class stores the data for AutoWrapperVector and AutoWrapperRooter. It
    1318             :  * should not be used in any other situations.
    1319             :  */
    1320             : struct WrapperValue
    1321             : {
    1322             :     /*
    1323             :      * We use unsafeGet() in the constructors to avoid invoking a read barrier
    1324             :      * on the wrapper, which may be dead (see the comment about bug 803376 in
    1325             :      * jsgc.cpp regarding this). If there is an incremental GC while the wrapper
    1326             :      * is in use, the AutoWrapper rooter will ensure the wrapper gets marked.
    1327             :      */
    1328          10 :     explicit WrapperValue(const WrapperMap::Ptr& ptr)
    1329          10 :       : value(*ptr->value().unsafeGet())
    1330          10 :     {}
    1331             : 
    1332          37 :     explicit WrapperValue(const WrapperMap::Enum& e)
    1333          37 :       : value(*e.front().value().unsafeGet())
    1334          37 :     {}
    1335             : 
    1336           0 :     Value& get() { return value; }
    1337          34 :     Value get() const { return value; }
    1338             :     operator const Value&() const { return value; }
    1339          10 :     JSObject& toObject() const { return value.toObject(); }
    1340             : 
    1341             :   private:
    1342             :     Value value;
    1343             : };
    1344             : 
    1345           6 : class MOZ_RAII AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue>
    1346             : {
    1347             :   public:
    1348           6 :     explicit AutoWrapperVector(JSContext* cx
    1349             :                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1350           6 :         : AutoVectorRooterBase<WrapperValue>(cx, WRAPVECTOR)
    1351             :     {
    1352           6 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1353           6 :     }
    1354             : 
    1355             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    1356             : };
    1357             : 
    1358          37 : class MOZ_RAII AutoWrapperRooter : private JS::AutoGCRooter {
    1359             :   public:
    1360          37 :     AutoWrapperRooter(JSContext* cx, const WrapperValue& v
    1361             :                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
    1362          37 :       : JS::AutoGCRooter(cx, WRAPPER), value(v)
    1363             :     {
    1364          37 :         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
    1365          37 :     }
    1366             : 
    1367          34 :     operator JSObject*() const {
    1368          34 :         return value.get().toObjectOrNull();
    1369             :     }
    1370             : 
    1371             :     friend void JS::AutoGCRooter::trace(JSTracer* trc);
    1372             : 
    1373             :   private:
    1374             :     WrapperValue value;
    1375             :     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
    1376             : };
    1377             : 
    1378             : class MOZ_RAII AutoSuppressAllocationMetadataBuilder {
    1379             :     JS::Zone* zone;
    1380             :     bool saved;
    1381             : 
    1382             :   public:
    1383      122973 :     explicit AutoSuppressAllocationMetadataBuilder(JSContext* cx)
    1384      122973 :       : AutoSuppressAllocationMetadataBuilder(cx->compartment()->zone())
    1385      122973 :     { }
    1386             : 
    1387      122974 :     explicit AutoSuppressAllocationMetadataBuilder(JS::Zone* zone)
    1388      122974 :       : zone(zone),
    1389      122974 :         saved(zone->suppressAllocationMetadataBuilder)
    1390             :     {
    1391      122972 :         zone->suppressAllocationMetadataBuilder = true;
    1392      122973 :     }
    1393             : 
    1394      245945 :     ~AutoSuppressAllocationMetadataBuilder() {
    1395      122972 :         zone->suppressAllocationMetadataBuilder = saved;
    1396      122973 :     }
    1397             : };
    1398             : 
    1399             : } /* namespace js */
    1400             : 
    1401             : namespace JS {
    1402             : template <>
    1403             : struct GCPolicy<js::CrossCompartmentKey> : public StructGCPolicy<js::CrossCompartmentKey> {
    1404        9609 :     static bool isTenured(const js::CrossCompartmentKey& key) { return key.isTenured(); }
    1405             : };
    1406             : } // namespace JS
    1407             : 
    1408             : #endif /* jscompartment_h */

Generated by: LCOV version 1.13