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/Maybe.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/Variant.h"
13 #include "mozilla/XorShift128PlusRNG.h"
14 
15 #include "builtin/RegExp.h"
16 #include "gc/Barrier.h"
17 #include "gc/Zone.h"
18 #include "vm/GlobalObject.h"
19 #include "vm/PIC.h"
20 #include "vm/SavedStacks.h"
21 #include "vm/Time.h"
22 
23 namespace js {
24 
25 namespace jit {
26 class JitCompartment;
27 } // namespace jit
28 
29 namespace gc {
30 template<class Node> class ComponentFinder;
31 } // namespace gc
32 
33 struct NativeIterator;
34 class ClonedBlockObject;
35 
36 /*
37  * A single-entry cache for some base-10 double-to-string conversions. This
38  * helps date-format-xparb.js.  It also avoids skewing the results for
39  * v8-splay.js when measured by the SunSpider harness, where the splay tree
40  * initialization (which includes many repeated double-to-string conversions)
41  * is erroneously included in the measurement; see bug 562553.
42  */
43 class DtoaCache {
44     double       d;
45     int          base;
46     JSFlatString* s;      // if s==nullptr, d and base are not valid
47 
48   public:
DtoaCache()49     DtoaCache() : s(nullptr) {}
purge()50     void purge() { s = nullptr; }
51 
lookup(int base,double d)52     JSFlatString* lookup(int base, double d) {
53         return this->s && base == this->base && d == this->d ? this->s : nullptr;
54     }
55 
cache(int base,double d,JSFlatString * s)56     void cache(int base, double d, JSFlatString* s) {
57         this->base = base;
58         this->d = d;
59         this->s = s;
60     }
61 };
62 
63 struct CrossCompartmentKey
64 {
65     enum Kind {
66         ObjectWrapper,
67         StringWrapper,
68         DebuggerScript,
69         DebuggerSource,
70         DebuggerObject,
71         DebuggerEnvironment
72     };
73 
74     Kind kind;
75     JSObject* debugger;
76     js::gc::Cell* wrapped;
77 
CrossCompartmentKeyCrossCompartmentKey78     explicit CrossCompartmentKey(JSObject* wrapped)
79       : kind(ObjectWrapper), debugger(nullptr), wrapped(wrapped)
80     {
81         MOZ_RELEASE_ASSERT(wrapped);
82     }
CrossCompartmentKeyCrossCompartmentKey83     explicit CrossCompartmentKey(JSString* wrapped)
84       : kind(StringWrapper), debugger(nullptr), wrapped(wrapped)
85     {
86         MOZ_RELEASE_ASSERT(wrapped);
87     }
CrossCompartmentKeyCrossCompartmentKey88     explicit CrossCompartmentKey(Value wrappedArg)
89       : kind(wrappedArg.isString() ? StringWrapper : ObjectWrapper),
90         debugger(nullptr),
91         wrapped((js::gc::Cell*)wrappedArg.toGCThing())
92     {
93         MOZ_RELEASE_ASSERT(wrappedArg.isString() || wrappedArg.isObject());
94         MOZ_RELEASE_ASSERT(wrapped);
95     }
CrossCompartmentKeyCrossCompartmentKey96     explicit CrossCompartmentKey(const RootedValue& wrappedArg)
97       : kind(wrappedArg.get().isString() ? StringWrapper : ObjectWrapper),
98         debugger(nullptr),
99         wrapped((js::gc::Cell*)wrappedArg.get().toGCThing())
100     {
101         MOZ_RELEASE_ASSERT(wrappedArg.isString() || wrappedArg.isObject());
102         MOZ_RELEASE_ASSERT(wrapped);
103     }
CrossCompartmentKeyCrossCompartmentKey104     CrossCompartmentKey(Kind kind, JSObject* dbg, js::gc::Cell* wrapped)
105       : kind(kind), debugger(dbg), wrapped(wrapped)
106     {
107         MOZ_RELEASE_ASSERT(dbg);
108         MOZ_RELEASE_ASSERT(wrapped);
109     }
110 
111   private:
112     CrossCompartmentKey() = delete;
113 };
114 
115 struct WrapperHasher : public DefaultHasher<CrossCompartmentKey>
116 {
hashWrapperHasher117     static HashNumber hash(const CrossCompartmentKey& key) {
118         static_assert(sizeof(HashNumber) == sizeof(uint32_t),
119                       "subsequent code assumes a four-byte hash");
120         return uint32_t(uintptr_t(key.wrapped)) | uint32_t(key.kind);
121     }
122 
matchWrapperHasher123     static bool match(const CrossCompartmentKey& l, const CrossCompartmentKey& k) {
124         return l.kind == k.kind && l.debugger == k.debugger && l.wrapped == k.wrapped;
125     }
126 };
127 
128 typedef HashMap<CrossCompartmentKey, ReadBarrieredValue,
129                 WrapperHasher, SystemAllocPolicy> WrapperMap;
130 
131 // We must ensure that all newly allocated JSObjects get their metadata
132 // set. However, metadata callbacks may require the new object be in a sane
133 // state (eg, have its reserved slots initialized so they can get the
134 // sizeOfExcludingThis of the object). Therefore, for objects of certain
135 // JSClasses (those marked with JSCLASS_DELAY_METADATA_CALLBACK), it is not safe
136 // for the allocation paths to call the object metadata callback
137 // immediately. Instead, the JSClass-specific "constructor" C++ function up the
138 // stack makes a promise that it will ensure that the new object has its
139 // metadata set after the object is initialized.
140 //
141 // To help those constructor functions keep their promise of setting metadata,
142 // each compartment is in one of three states at any given time:
143 //
144 // * ImmediateMetadata: Allocators should set new object metadata immediately,
145 //                      as usual.
146 //
147 // * DelayMetadata: Allocators should *not* set new object metadata, it will be
148 //                  handled after reserved slots are initialized by custom code
149 //                  for the object's JSClass. The newly allocated object's
150 //                  JSClass *must* have the JSCLASS_DELAY_METADATA_CALLBACK flag
151 //                  set.
152 //
153 // * PendingMetadata: This object has been allocated and is still pending its
154 //                    metadata. This should never be the case when we begin an
155 //                    allocation, as a constructor function was supposed to have
156 //                    set the metadata of the previous object *before*
157 //                    allocating another object.
158 //
159 // The js::AutoSetNewObjectMetadata RAII class provides an ergonomic way for
160 // constructor functions to navigate state transitions, and its instances
161 // collectively maintain a stack of previous states. The stack is required to
162 // support the lazy resolution and allocation of global builtin constructors and
163 // prototype objects. The initial (and intuitively most common) state is
164 // ImmediateMetadata.
165 //
166 // Without the presence of internal errors (such as OOM), transitions between
167 // the states are as follows:
168 //
169 //     ImmediateMetadata                 .----- previous state on stack
170 //           |                           |          ^
171 //           | via constructor           |          |
172 //           |                           |          | via setting the new
173 //           |        via constructor    |          | object's metadata
174 //           |   .-----------------------'          |
175 //           |   |                                  |
176 //           V   V                                  |
177 //     DelayMetadata -------------------------> PendingMetadata
178 //                         via allocation
179 //
180 // In the presence of internal errors, we do not set the new object's metadata
181 // (if it was even allocated) and reset to the previous state on the stack.
182 
183 struct ImmediateMetadata { };
184 struct DelayMetadata { };
185 using PendingMetadata = ReadBarrieredObject;
186 
187 using NewObjectMetadataState = mozilla::Variant<ImmediateMetadata,
188                                                 DelayMetadata,
189                                                 PendingMetadata>;
190 
191 class MOZ_RAII AutoSetNewObjectMetadata : private JS::CustomAutoRooter
192 {
193     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER;
194 
195     JSContext* cx_;
196     NewObjectMetadataState prevState_;
197 
198     AutoSetNewObjectMetadata(const AutoSetNewObjectMetadata& aOther) = delete;
199     void operator=(const AutoSetNewObjectMetadata& aOther) = delete;
200 
201   protected:
trace(JSTracer * trc)202     virtual void trace(JSTracer* trc) override {
203         if (prevState_.is<PendingMetadata>()) {
204             TraceRoot(trc,
205                       prevState_.as<PendingMetadata>().unsafeUnbarrieredForTracing(),
206                       "Object pending metadata");
207         }
208     }
209 
210   public:
211     explicit AutoSetNewObjectMetadata(ExclusiveContext* ecx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
212     ~AutoSetNewObjectMetadata();
213 };
214 
215 } /* namespace js */
216 
217 namespace js {
218 class DebugScopes;
219 class ObjectWeakMap;
220 class WatchpointMap;
221 class WeakMapBase;
222 } // namespace js
223 
224 struct JSCompartment
225 {
226     JS::CompartmentOptions       options_;
227 
228   private:
229     JS::Zone*                    zone_;
230     JSRuntime*                   runtime_;
231 
232   public:
233     /*
234      * The principals associated with this compartment. Note that the
235      * same several compartments may share the same principals and
236      * that a compartment may change principals during its lifetime
237      * (e.g. in case of lazy parsing).
238      */
principalsJSCompartment239     inline JSPrincipals* principals() {
240         return principals_;
241     }
setPrincipalsJSCompartment242     inline void setPrincipals(JSPrincipals* principals) {
243         if (principals_ == principals)
244             return;
245 
246         // If we change principals, we need to unlink immediately this
247         // compartment from its PerformanceGroup. For one thing, the
248         // performance data we collect should not be improperly associated
249         // with a group to which we do not belong anymore. For another thing,
250         // we use `principals()` as part of the key to map compartments
251         // to a `PerformanceGroup`, so if we do not unlink now, this will
252         // be too late once we have updated `principals_`.
253         performanceMonitoring.unlink();
254         principals_ = principals;
255     }
isSystemJSCompartment256     inline bool isSystem() const {
257         return isSystem_;
258     }
setIsSystemJSCompartment259     inline void setIsSystem(bool isSystem) {
260         if (isSystem_ == isSystem)
261             return;
262 
263         // If we change `isSystem*(`, we need to unlink immediately this
264         // compartment from its PerformanceGroup. For one thing, the
265         // performance data we collect should not be improperly associated
266         // to a group to which we do not belong anymore. For another thing,
267         // we use `isSystem()` as part of the key to map compartments
268         // to a `PerformanceGroup`, so if we do not unlink now, this will
269         // be too late once we have updated `isSystem_`.
270         performanceMonitoring.unlink();
271         isSystem_ = isSystem;
272     }
273 
isAtomsCompartmentJSCompartment274     bool isAtomsCompartment() const {
275         return isAtomsCompartment_;
276     }
setIsAtomsCompartmentJSCompartment277     void setIsAtomsCompartment() {
278         isAtomsCompartment_ = true;
279     }
280 
281   private:
282     JSPrincipals*                principals_;
283     bool                         isSystem_;
284     bool                         isAtomsCompartment_;
285 
286   public:
287     bool                         isSelfHosting;
288     bool                         marked;
289     bool                         warnedAboutFlagsArgument;
290     bool                         warnedAboutExprClosure;
291 
292     // A null add-on ID means that the compartment is not associated with an
293     // add-on.
294     JSAddonId*                   const addonId;
295 
296 #ifdef DEBUG
297     bool                         firedOnNewGlobalObject;
298 #endif
299 
markJSCompartment300     void mark() { marked = true; }
301 
302   private:
303     friend struct JSRuntime;
304     friend struct JSContext;
305     friend class js::ExclusiveContext;
306     js::ReadBarrieredGlobalObject global_;
307 
308     unsigned                     enterCompartmentDepth;
309     int64_t                      startInterval;
310 
311   public:
312     js::PerformanceGroupHolder performanceMonitoring;
313 
enterJSCompartment314     void enter() {
315         enterCompartmentDepth++;
316     }
leaveJSCompartment317     void leave() {
318         enterCompartmentDepth--;
319     }
hasBeenEnteredJSCompartment320     bool hasBeenEntered() { return !!enterCompartmentDepth; }
321 
zoneJSCompartment322     JS::Zone* zone() { return zone_; }
zoneJSCompartment323     const JS::Zone* zone() const { return zone_; }
optionsJSCompartment324     JS::CompartmentOptions& options() { return options_; }
optionsJSCompartment325     const JS::CompartmentOptions& options() const { return options_; }
326 
runtimeFromMainThreadJSCompartment327     JSRuntime* runtimeFromMainThread() {
328         MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
329         return runtime_;
330     }
331 
332     // Note: Unrestricted access to the zone's runtime from an arbitrary
333     // thread can easily lead to races. Use this method very carefully.
runtimeFromAnyThreadJSCompartment334     JSRuntime* runtimeFromAnyThread() const {
335         return runtime_;
336     }
337 
338     /*
339      * Nb: global_ might be nullptr, if (a) it's the atoms compartment, or
340      * (b) the compartment's global has been collected.  The latter can happen
341      * if e.g. a string in a compartment is rooted but no object is, and thus
342      * the global isn't rooted, and thus the global can be finalized while the
343      * compartment lives on.
344      *
345      * In contrast, JSObject::global() is infallible because marking a JSObject
346      * always marks its global as well.
347      * TODO: add infallible JSScript::global()
348      */
349     inline js::GlobalObject* maybeGlobal() const;
350 
351     /* An unbarriered getter for use while tracing. */
352     inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
353 
354     inline void initGlobal(js::GlobalObject& global);
355 
356   public:
357     void*                        data;
358 
359   private:
360     js::ObjectMetadataCallback   objectMetadataCallback;
361 
362     js::SavedStacks              savedStacks_;
363 
364     js::WrapperMap               crossCompartmentWrappers;
365 
366   public:
367     /* Last time at which an animation was played for a global in this compartment. */
368     int64_t                      lastAnimationTime;
369 
370     js::RegExpCompartment        regExps;
371 
372     /*
373      * For generational GC, record whether a write barrier has added this
374      * compartment's global to the store buffer since the last minor GC.
375      *
376      * This is used to avoid adding it to the store buffer on every write, which
377      * can quickly fill the buffer and also cause performance problems.
378      */
379     bool                         globalWriteBarriered;
380 
381     // Non-zero if any typed objects in this compartment might be neutered.
382     int32_t                      neuteredTypedObjects;
383 
384   private:
385     friend class js::AutoSetNewObjectMetadata;
386     js::NewObjectMetadataState objectMetadataState;
387 
388   public:
389     // Recompute the probability with which this compartment should record
390     // profiling data (stack traces, allocations log, etc.) about each
391     // allocation. We consult the probabilities requested by the Debugger
392     // instances observing us, if any.
chooseAllocationSamplingProbabilityJSCompartment393     void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
394 
hasObjectPendingMetadataJSCompartment395     bool hasObjectPendingMetadata() const { return objectMetadataState.is<js::PendingMetadata>(); }
396 
setObjectPendingMetadataJSCompartment397     void setObjectPendingMetadata(JSContext* cx, JSObject* obj) {
398         MOZ_ASSERT(objectMetadataState.is<js::DelayMetadata>());
399         objectMetadataState = js::NewObjectMetadataState(js::PendingMetadata(obj));
400     }
401 
setObjectPendingMetadataJSCompartment402     void setObjectPendingMetadata(js::ExclusiveContext* ecx, JSObject* obj) {
403         if (JSContext* cx = ecx->maybeJSContext())
404             setObjectPendingMetadata(cx, obj);
405     }
406 
407   public:
408     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
409                                 size_t* tiAllocationSiteTables,
410                                 size_t* tiArrayTypeTables,
411                                 size_t* tiObjectTypeTables,
412                                 size_t* compartmentObject,
413                                 size_t* compartmentTables,
414                                 size_t* innerViews,
415                                 size_t* lazyArrayBuffers,
416                                 size_t* objectMetadataTables,
417                                 size_t* crossCompartmentWrappers,
418                                 size_t* regexpCompartment,
419                                 size_t* savedStacksSet,
420                                 size_t* nonSyntacticLexicalScopes);
421 
422     /*
423      * Shared scope property tree, and arena-pool for allocating its nodes.
424      */
425     js::PropertyTree             propertyTree;
426 
427     /* Set of all unowned base shapes in the compartment. */
428     js::BaseShapeSet             baseShapes;
429     void sweepBaseShapeTable();
430 
431     /* Set of initial shapes in the compartment. */
432     js::InitialShapeSet          initialShapes;
433     void sweepInitialShapeTable();
434 
435     // Object group tables and other state in the compartment.
436     js::ObjectGroupCompartment   objectGroups;
437 
438 #ifdef JSGC_HASH_TABLE_CHECKS
439     void checkInitialShapesTableAfterMovingGC();
440     void checkWrapperMapAfterMovingGC();
441     void checkBaseShapeTableAfterMovingGC();
442 #endif
443 
444     /*
445      * Lazily initialized script source object to use for scripts cloned
446      * from the self-hosting global.
447      */
448     js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
449 
450     // Keep track of the metadata objects which can be associated with each JS
451     // object. Both keys and values are in this compartment.
452     js::ObjectWeakMap* objectMetadataTable;
453 
454     // Map from array buffers to views sharing that storage.
455     js::InnerViewTable innerViews;
456 
457     // Inline transparent typed objects do not initially have an array buffer,
458     // but can have that buffer created lazily if it is accessed later. This
459     // table manages references from such typed objects to their buffers.
460     js::ObjectWeakMap* lazyArrayBuffers;
461 
462     // All unboxed layouts in the compartment.
463     mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
464 
465   private:
466     // All non-syntactic lexical scopes in the compartment. These are kept in
467     // a map because when loading scripts into a non-syntactic scope, we need
468     // to use the same lexical scope to persist lexical bindings.
469     js::ObjectWeakMap* nonSyntacticLexicalScopes_;
470 
471   public:
472     /* During GC, stores the index of this compartment in rt->compartments. */
473     unsigned                     gcIndex;
474 
475     /*
476      * During GC, stores the head of a list of incoming pointers from gray cells.
477      *
478      * The objects in the list are either cross-compartment wrappers, or
479      * debugger wrapper objects.  The list link is either in the second extra
480      * slot for the former, or a special slot for the latter.
481      */
482     JSObject*                    gcIncomingGrayPointers;
483 
484   private:
485     /* Whether to preserve JIT code on non-shrinking GCs. */
486     bool                         gcPreserveJitCode;
487 
488     enum {
489         IsDebuggee = 1 << 0,
490         DebuggerObservesAllExecution = 1 << 1,
491         DebuggerObservesAsmJS = 1 << 2,
492         DebuggerObservesCoverage = 1 << 3,
493         DebuggerNeedsDelazification = 1 << 4
494     };
495 
496     unsigned                     debugModeBits;
497 
498     static const unsigned DebuggerObservesMask = IsDebuggee |
499                                                  DebuggerObservesAllExecution |
500                                                  DebuggerObservesCoverage |
501                                                  DebuggerObservesAsmJS;
502 
503     void updateDebuggerObservesFlag(unsigned flag);
504 
505   public:
506     JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options);
507     ~JSCompartment();
508 
509     bool init(JSContext* maybecx);
510 
511     inline bool wrap(JSContext* cx, JS::MutableHandleValue vp,
512                      JS::HandleObject existing = nullptr);
513 
514     bool wrap(JSContext* cx, js::MutableHandleString strp);
515     bool wrap(JSContext* cx, JS::MutableHandleObject obj,
516               JS::HandleObject existingArg = nullptr);
517     bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
518 
wrapJSCompartment519     template<typename T> bool wrap(JSContext* cx, JS::AutoVectorRooter<T>& vec) {
520         for (size_t i = 0; i < vec.length(); ++i) {
521             if (!wrap(cx, vec[i]))
522                 return false;
523         }
524         return true;
525     };
526 
527     bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
528 
lookupWrapperJSCompartment529     js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) const {
530         return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
531     }
532 
removeWrapperJSCompartment533     void removeWrapper(js::WrapperMap::Ptr p) {
534         crossCompartmentWrappers.remove(p);
535     }
536 
537     struct WrapperEnum : public js::WrapperMap::Enum {
WrapperEnumJSCompartment::WrapperEnum538         explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
539     };
540 
541     js::ClonedBlockObject* getOrCreateNonSyntacticLexicalScope(JSContext* cx,
542                                                                js::HandleObject enclosingStatic,
543                                                                js::HandleObject enclosingScope);
544     js::ClonedBlockObject* getNonSyntacticLexicalScope(JSObject* enclosingScope) const;
545 
546     /*
547      * This method traces data that is live iff we know that this compartment's
548      * global is still live.
549      */
550     void trace(JSTracer* trc);
551     /*
552      * This method traces JSCompartment-owned GC roots that are considered live
553      * regardless of whether the JSCompartment itself is still live.
554      */
555     void traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark);
556     /*
557      * These methods mark pointers that cross compartment boundaries. They are
558      * called in per-zone GCs to prevent the wrappers' outgoing edges from
559      * dangling (full GCs naturally follow pointers across compartments) and
560      * when compacting to update cross-compartment pointers.
561      */
562     void traceOutgoingCrossCompartmentWrappers(JSTracer* trc);
563     static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc);
564 
preserveJitCodeJSCompartment565     bool preserveJitCode() { return gcPreserveJitCode; }
566 
567     void sweepAfterMinorGC();
568 
569     void sweepInnerViews();
570     void sweepCrossCompartmentWrappers();
571     void sweepSavedStacks();
572     void sweepGlobalObject(js::FreeOp* fop);
573     void sweepObjectPendingMetadata();
574     void sweepSelfHostingScriptSource();
575     void sweepJitCompartment(js::FreeOp* fop);
576     void sweepRegExps();
577     void sweepDebugScopes();
578     void sweepNativeIterators();
579     void sweepTemplateObjects();
580 
581     void purge();
582     void clearTables();
583 
584     static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
585     void fixupInitialShapeTable();
586     void fixupAfterMovingGC();
587     void fixupGlobal();
588 
hasObjectMetadataCallbackJSCompartment589     bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
getObjectMetadataCallbackJSCompartment590     js::ObjectMetadataCallback getObjectMetadataCallback() const { return objectMetadataCallback; }
591     void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
forgetObjectMetadataCallbackJSCompartment592     void forgetObjectMetadataCallback() {
593         objectMetadataCallback = nullptr;
594     }
595     void setNewObjectMetadata(JSContext* cx, JSObject* obj);
596     void clearObjectMetadata();
addressOfMetadataCallbackJSCompartment597     const void* addressOfMetadataCallback() const {
598         return &objectMetadataCallback;
599     }
600 
savedStacksJSCompartment601     js::SavedStacks& savedStacks() { return savedStacks_; }
602 
603     void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone>& finder);
604 
605     MOZ_MUST_USE bool findDeadProxyZoneEdges(bool* foundAny);
606 
607     js::DtoaCache dtoaCache;
608 
609     // Random number generator for Math.random().
610     mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomNumberGenerator;
611 
612     // Initialize randomNumberGenerator if needed.
613     void ensureRandomNumberGenerator();
614 
615   private:
616     mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_;
617 
618   public:
619     js::HashNumber randomHashCode();
620 
621     mozilla::HashCodeScrambler randomHashCodeScrambler();
622 
623   private:
thisForCtorJSCompartment624     JSCompartment* thisForCtor() { return this; }
625 
626   public:
627     //
628     // The Debugger observes execution on a frame-by-frame basis. The
629     // invariants of JSCompartment's debug mode bits, JSScript::isDebuggee,
630     // InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are
631     // enumerated below.
632     //
633     // 1. When a compartment's isDebuggee() == true, relazification and lazy
634     //    parsing are disabled.
635     //
636     //    Whether AOT asm.js is disabled is togglable by the Debugger API. By
637     //    default it is disabled. See debuggerObservesAsmJS below.
638     //
639     // 2. When a compartment's debuggerObservesAllExecution() == true, all of
640     //    the compartment's scripts are considered debuggee scripts.
641     //
642     // 3. A script is considered a debuggee script either when, per above, its
643     //    compartment is observing all execution, or if it has breakpoints set.
644     //
645     // 4. A debuggee script always pushes a debuggee frame.
646     //
647     // 5. A debuggee frame calls all slow path Debugger hooks in the
648     //    Interpreter and Baseline. A debuggee frame implies that its script's
649     //    BaselineScript, if extant, has been compiled with debug hook calls.
650     //
651     // 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
652     //    that the compiled BaselineScript is compiled with debug hook calls
653     //    when attempting to enter Baseline.
654     //
655     // 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
656     //    attempt to enter Ion.
657     //
658     // Note that a debuggee frame may exist without its script being a
659     // debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
660     // frame in which it is evaluating as a debuggee frame.
661     //
662 
663     // True if this compartment's global is a debuggee of some Debugger
664     // object.
isDebuggeeJSCompartment665     bool isDebuggee() const { return !!(debugModeBits & IsDebuggee); }
setIsDebuggeeJSCompartment666     void setIsDebuggee() { debugModeBits |= IsDebuggee; }
667     void unsetIsDebuggee();
668 
669     // True if this compartment's global is a debuggee of some Debugger
670     // object with a live hook that observes all execution; e.g.,
671     // onEnterFrame.
debuggerObservesAllExecutionJSCompartment672     bool debuggerObservesAllExecution() const {
673         static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution;
674         return (debugModeBits & Mask) == Mask;
675     }
updateDebuggerObservesAllExecutionJSCompartment676     void updateDebuggerObservesAllExecution() {
677         updateDebuggerObservesFlag(DebuggerObservesAllExecution);
678     }
679 
680     // True if this compartment's global is a debuggee of some Debugger object
681     // whose allowUnobservedAsmJS flag is false.
682     //
683     // Note that since AOT asm.js functions cannot bail out, this flag really
684     // means "observe asm.js from this point forward". We cannot make
685     // already-compiled asm.js code observable to Debugger.
debuggerObservesAsmJSJSCompartment686     bool debuggerObservesAsmJS() const {
687         static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS;
688         return (debugModeBits & Mask) == Mask;
689     }
updateDebuggerObservesAsmJSJSCompartment690     void updateDebuggerObservesAsmJS() {
691         updateDebuggerObservesFlag(DebuggerObservesAsmJS);
692     }
693 
694     // True if this compartment's global is a debuggee of some Debugger object
695     // whose collectCoverageInfo flag is true.
debuggerObservesCoverageJSCompartment696     bool debuggerObservesCoverage() const {
697         static const unsigned Mask = DebuggerObservesCoverage;
698         return (debugModeBits & Mask) == Mask;
699     }
700     void updateDebuggerObservesCoverage();
701 
702     // The code coverage can be enabled either for each compartment, with the
703     // Debugger API, or for the entire runtime.
704     bool collectCoverage() const;
705     void clearScriptCounts();
706 
needsDelazificationForDebuggerJSCompartment707     bool needsDelazificationForDebugger() const {
708         return debugModeBits & DebuggerNeedsDelazification;
709     }
710 
711     /*
712      * Schedule the compartment to be delazified. Called from
713      * LazyScript::Create.
714      */
scheduleDelazificationForDebuggerJSCompartment715     void scheduleDelazificationForDebugger() { debugModeBits |= DebuggerNeedsDelazification; }
716 
717     /*
718      * If we scheduled delazification for turning on debug mode, delazify all
719      * scripts.
720      */
721     bool ensureDelazifyScriptsForDebugger(JSContext* cx);
722 
723     void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JS::HandleObject handler);
724 
725   private:
726     void sweepBreakpoints(js::FreeOp* fop);
727 
728   public:
729     js::WatchpointMap* watchpointMap;
730 
731     js::ScriptCountsMap* scriptCountsMap;
732 
733     js::DebugScriptMap* debugScriptMap;
734 
735     /* Bookkeeping information for debug scope objects. */
736     js::DebugScopes* debugScopes;
737 
738     /*
739      * List of potentially active iterators that may need deleted property
740      * suppression.
741      */
742     js::NativeIterator* enumerators;
743 
744     /* Used by memory reporters and invalid otherwise. */
745     void*              compartmentStats;
746 
747     // These flags help us to discover if a compartment that shouldn't be alive
748     // manages to outlive a GC.
749     bool scheduledForDestruction;
750     bool maybeAlive;
751 
752   private:
753     js::jit::JitCompartment* jitCompartment_;
754 
755     js::ReadBarriered<js::ArgumentsObject*> mappedArgumentsTemplate_;
756     js::ReadBarriered<js::ArgumentsObject*> unmappedArgumentsTemplate_;
757 
758   public:
759     bool ensureJitCompartmentExists(JSContext* cx);
jitCompartmentJSCompartment760     js::jit::JitCompartment* jitCompartment() {
761         return jitCompartment_;
762     }
763 
764     enum DeprecatedLanguageExtension {
765         DeprecatedForEach = 0,              // JS 1.6+
766         // NO LONGER USING 1
767         DeprecatedLegacyGenerator = 2,      // JS 1.7+
768         DeprecatedExpressionClosure = 3,    // Added in JS 1.8
769         // NO LONGER USING 4
770         // NO LONGER USING 5
771         // NO LONGER USING 6
772         DeprecatedFlagsArgument = 7,        // JS 1.3 or older
773         // NO LONGER USING 8
774         // NO LONGER USING 9
775         DeprecatedLanguageExtensionCount
776     };
777 
778     js::ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx, bool mapped);
779 
780   private:
781     // Used for collecting telemetry on SpiderMonkey's deprecated language extensions.
782     bool sawDeprecatedLanguageExtension[DeprecatedLanguageExtensionCount];
783 
784     void reportTelemetry();
785 
786   public:
787     void addTelemetry(const char* filename, DeprecatedLanguageExtension e);
788 
789   public:
790     // Aggregated output used to collect JSScript hit counts when code coverage
791     // is enabled.
792     js::coverage::LCovCompartment lcovOutput;
793 };
794 
795 inline bool
isAtomsZone(const JS::Zone * zone)796 JSRuntime::isAtomsZone(const JS::Zone* zone) const
797 {
798     return zone == atomsCompartment_->zone();
799 }
800 
801 namespace js {
802 
803 // We only set the maybeAlive flag for objects and scripts. It's assumed that,
804 // if a compartment is alive, then it will have at least some live object or
805 // script it in. Even if we get this wrong, the worst that will happen is that
806 // scheduledForDestruction will be set on the compartment, which will cause
807 // some extra GC activity to try to free the compartment.
SetMaybeAliveFlag(T * thing)808 template<typename T> inline void SetMaybeAliveFlag(T* thing) {}
SetMaybeAliveFlag(JSObject * thing)809 template<> inline void SetMaybeAliveFlag(JSObject* thing) {thing->compartment()->maybeAlive = true;}
SetMaybeAliveFlag(JSScript * thing)810 template<> inline void SetMaybeAliveFlag(JSScript* thing) {thing->compartment()->maybeAlive = true;}
811 
812 inline js::Handle<js::GlobalObject*>
global()813 ExclusiveContext::global() const
814 {
815     /*
816      * It's safe to use |unsafeGet()| here because any compartment that is
817      * on-stack will be marked automatically, so there's no need for a read
818      * barrier on it. Once the compartment is popped, the handle is no longer
819      * safe to use.
820      */
821     MOZ_ASSERT(compartment_, "Caller needs to enter a compartment first");
822     return Handle<GlobalObject*>::fromMarkedLocation(compartment_->global_.unsafeGet());
823 }
824 
825 class MOZ_RAII AssertCompartmentUnchanged
826 {
827   public:
AssertCompartmentUnchanged(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)828     explicit AssertCompartmentUnchanged(JSContext* cx
829                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
830       : cx(cx), oldCompartment(cx->compartment())
831     {
832         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
833     }
834 
~AssertCompartmentUnchanged()835     ~AssertCompartmentUnchanged() {
836         MOZ_ASSERT(cx->compartment() == oldCompartment);
837     }
838 
839   protected:
840     JSContext * const cx;
841     JSCompartment * const oldCompartment;
842     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
843 };
844 
845 class AutoCompartment
846 {
847     ExclusiveContext * const cx_;
848     JSCompartment * const origin_;
849 
850   public:
851     inline AutoCompartment(ExclusiveContext* cx, JSObject* target);
852     inline AutoCompartment(ExclusiveContext* cx, JSCompartment* target);
853     inline ~AutoCompartment();
854 
context()855     ExclusiveContext* context() const { return cx_; }
origin()856     JSCompartment* origin() const { return origin_; }
857 
858   private:
859     AutoCompartment(const AutoCompartment&) = delete;
860     AutoCompartment & operator=(const AutoCompartment&) = delete;
861 };
862 
863 /*
864  * Use this to change the behavior of an AutoCompartment slightly on error. If
865  * the exception happens to be an Error object, copy it to the origin compartment
866  * instead of wrapping it.
867  */
868 class ErrorCopier
869 {
870     mozilla::Maybe<AutoCompartment>& ac;
871 
872   public:
ErrorCopier(mozilla::Maybe<AutoCompartment> & ac)873     explicit ErrorCopier(mozilla::Maybe<AutoCompartment>& ac)
874       : ac(ac) {}
875     ~ErrorCopier();
876 };
877 
878 /*
879  * AutoWrapperVector and AutoWrapperRooter can be used to store wrappers that
880  * are obtained from the cross-compartment map. However, these classes should
881  * not be used if the wrapper will escape. For example, it should not be stored
882  * in the heap.
883  *
884  * The AutoWrapper rooters are different from other autorooters because their
885  * wrappers are marked on every GC slice rather than just the first one. If
886  * there's some wrapper that we want to use temporarily without causing it to be
887  * marked, we can use these AutoWrapper classes. If we get unlucky and a GC
888  * slice runs during the code using the wrapper, the GC will mark the wrapper so
889  * that it doesn't get swept out from under us. Otherwise, the wrapper needn't
890  * be marked. This is useful in functions like JS_TransplantObject that
891  * manipulate wrappers in compartments that may no longer be alive.
892  */
893 
894 /*
895  * This class stores the data for AutoWrapperVector and AutoWrapperRooter. It
896  * should not be used in any other situations.
897  */
898 struct WrapperValue
899 {
900     /*
901      * We use unsafeGet() in the constructors to avoid invoking a read barrier
902      * on the wrapper, which may be dead (see the comment about bug 803376 in
903      * jsgc.cpp regarding this). If there is an incremental GC while the wrapper
904      * is in use, the AutoWrapper rooter will ensure the wrapper gets marked.
905      */
WrapperValueWrapperValue906     explicit WrapperValue(const WrapperMap::Ptr& ptr)
907       : value(*ptr->value().unsafeGet())
908     {}
909 
WrapperValueWrapperValue910     explicit WrapperValue(const WrapperMap::Enum& e)
911       : value(*e.front().value().unsafeGet())
912     {}
913 
getWrapperValue914     Value& get() { return value; }
getWrapperValue915     Value get() const { return value; }
916     operator const Value&() const { return value; }
toObjectWrapperValue917     JSObject& toObject() const { return value.toObject(); }
918 
919   private:
920     Value value;
921 };
922 
923 class MOZ_RAII AutoWrapperVector : public JS::AutoVectorRooterBase<WrapperValue>
924 {
925   public:
AutoWrapperVector(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)926     explicit AutoWrapperVector(JSContext* cx
927                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
928         : AutoVectorRooterBase<WrapperValue>(cx, WRAPVECTOR)
929     {
930         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
931     }
932 
933     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
934 };
935 
936 class MOZ_RAII AutoWrapperRooter : private JS::AutoGCRooter {
937   public:
AutoWrapperRooter(JSContext * cx,WrapperValue v MOZ_GUARD_OBJECT_NOTIFIER_PARAM)938     AutoWrapperRooter(JSContext* cx, WrapperValue v
939                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
940       : JS::AutoGCRooter(cx, WRAPPER), value(v)
941     {
942         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
943     }
944 
945     operator JSObject*() const {
946         return value.get().toObjectOrNull();
947     }
948 
949     friend void JS::AutoGCRooter::trace(JSTracer* trc);
950 
951   private:
952     WrapperValue value;
953     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
954 };
955 
956 } /* namespace js */
957 
958 #endif /* jscompartment_h */
959