js/src/jscompartment.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     7 #ifndef jscompartment_h
     8 #define jscompartment_h
    10 #include "mozilla/MemoryReporting.h"
    12 #include "builtin/TypedObject.h"
    13 #include "gc/Zone.h"
    14 #include "vm/GlobalObject.h"
    15 #include "vm/PIC.h"
    16 #include "vm/SavedStacks.h"
    18 namespace js {
    20 namespace jit {
    21 class JitCompartment;
    22 }
    24 namespace gc {
    25 template<class Node> class ComponentFinder;
    26 }
    28 struct NativeIterator;
    30 /*
    31  * A single-entry cache for some base-10 double-to-string conversions. This
    32  * helps date-format-xparb.js.  It also avoids skewing the results for
    33  * v8-splay.js when measured by the SunSpider harness, where the splay tree
    34  * initialization (which includes many repeated double-to-string conversions)
    35  * is erroneously included in the measurement; see bug 562553.
    36  */
    37 class DtoaCache {
    38     double       d;
    39     int          base;
    40     JSFlatString *s;      // if s==nullptr, d and base are not valid
    42   public:
    43     DtoaCache() : s(nullptr) {}
    44     void purge() { s = nullptr; }
    46     JSFlatString *lookup(int base, double d) {
    47         return this->s && base == this->base && d == this->d ? this->s : nullptr;
    48     }
    50     void cache(int base, double d, JSFlatString *s) {
    51         this->base = base;
    52         this->d = d;
    53         this->s = s;
    54     }
    55 };
    57 /* If HashNumber grows, need to change WrapperHasher. */
    58 JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
    60 struct CrossCompartmentKey
    61 {
    62     enum Kind {
    63         ObjectWrapper,
    64         StringWrapper,
    65         DebuggerScript,
    66         DebuggerSource,
    67         DebuggerObject,
    68         DebuggerEnvironment
    69     };
    71     Kind kind;
    72     JSObject *debugger;
    73     js::gc::Cell *wrapped;
    75     CrossCompartmentKey()
    76       : kind(ObjectWrapper), debugger(nullptr), wrapped(nullptr) {}
    77     CrossCompartmentKey(JSObject *wrapped)
    78       : kind(ObjectWrapper), debugger(nullptr), wrapped(wrapped) {}
    79     CrossCompartmentKey(JSString *wrapped)
    80       : kind(StringWrapper), debugger(nullptr), wrapped(wrapped) {}
    81     CrossCompartmentKey(Value wrapped)
    82       : kind(wrapped.isString() ? StringWrapper : ObjectWrapper),
    83         debugger(nullptr),
    84         wrapped((js::gc::Cell *)wrapped.toGCThing()) {}
    85     CrossCompartmentKey(const RootedValue &wrapped)
    86       : kind(wrapped.get().isString() ? StringWrapper : ObjectWrapper),
    87         debugger(nullptr),
    88         wrapped((js::gc::Cell *)wrapped.get().toGCThing()) {}
    89     CrossCompartmentKey(Kind kind, JSObject *dbg, js::gc::Cell *wrapped)
    90       : kind(kind), debugger(dbg), wrapped(wrapped) {}
    91 };
    93 struct WrapperHasher : public DefaultHasher<CrossCompartmentKey>
    94 {
    95     static HashNumber hash(const CrossCompartmentKey &key) {
    96         JS_ASSERT(!IsPoisonedPtr(key.wrapped));
    97         return uint32_t(uintptr_t(key.wrapped)) | uint32_t(key.kind);
    98     }
   100     static bool match(const CrossCompartmentKey &l, const CrossCompartmentKey &k) {
   101         return l.kind == k.kind && l.debugger == k.debugger && l.wrapped == k.wrapped;
   102     }
   103 };
   105 typedef HashMap<CrossCompartmentKey, ReadBarrieredValue,
   106                 WrapperHasher, SystemAllocPolicy> WrapperMap;
   108 } /* namespace js */
   110 namespace JS {
   111 struct TypeInferenceSizes;
   112 }
   114 namespace js {
   115 class AutoDebugModeInvalidation;
   116 class DebugScopes;
   117 class WeakMapBase;
   118 }
   120 struct JSCompartment
   121 {
   122     JS::CompartmentOptions       options_;
   124   private:
   125     JS::Zone                     *zone_;
   126     JSRuntime                    *runtime_;
   128   public:
   129     JSPrincipals                 *principals;
   130     bool                         isSystem;
   131     bool                         isSelfHosting;
   132     bool                         marked;
   134 #ifdef DEBUG
   135     bool                         firedOnNewGlobalObject;
   136 #endif
   138     void mark() { marked = true; }
   140   private:
   141     friend struct JSRuntime;
   142     friend struct JSContext;
   143     friend class js::ExclusiveContext;
   144     js::ReadBarriered<js::GlobalObject> global_;
   146     unsigned                     enterCompartmentDepth;
   148   public:
   149     void enter() { enterCompartmentDepth++; }
   150     void leave() { enterCompartmentDepth--; }
   151     bool hasBeenEntered() { return !!enterCompartmentDepth; }
   153     JS::Zone *zone() { return zone_; }
   154     const JS::Zone *zone() const { return zone_; }
   155     JS::CompartmentOptions &options() { return options_; }
   156     const JS::CompartmentOptions &options() const { return options_; }
   158     JSRuntime *runtimeFromMainThread() {
   159         JS_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
   160         return runtime_;
   161     }
   163     // Note: Unrestricted access to the zone's runtime from an arbitrary
   164     // thread can easily lead to races. Use this method very carefully.
   165     JSRuntime *runtimeFromAnyThread() const {
   166         return runtime_;
   167     }
   169     /*
   170      * Nb: global_ might be nullptr, if (a) it's the atoms compartment, or
   171      * (b) the compartment's global has been collected.  The latter can happen
   172      * if e.g. a string in a compartment is rooted but no object is, and thus
   173      * the global isn't rooted, and thus the global can be finalized while the
   174      * compartment lives on.
   175      *
   176      * In contrast, JSObject::global() is infallible because marking a JSObject
   177      * always marks its global as well.
   178      * TODO: add infallible JSScript::global()
   179      */
   180     inline js::GlobalObject *maybeGlobal() const;
   182     inline void initGlobal(js::GlobalObject &global);
   184   public:
   185     /*
   186      * Moves all data from the allocator |workerAllocator|, which was
   187      * in use by a parallel worker, into the compartment's main
   188      * allocator.  This is used at the end of a parallel section.
   189      */
   190     void adoptWorkerAllocator(js::Allocator *workerAllocator);
   192     bool                         activeAnalysis;
   194     /* Type information about the scripts and objects in this compartment. */
   195     js::types::TypeCompartment   types;
   197     void                         *data;
   199   private:
   200     js::ObjectMetadataCallback   objectMetadataCallback;
   202     js::SavedStacks              savedStacks_;
   204     js::WrapperMap               crossCompartmentWrappers;
   206   public:
   207     /* Last time at which an animation was played for a global in this compartment. */
   208     int64_t                      lastAnimationTime;
   210     js::RegExpCompartment        regExps;
   212     /*
   213      * For generational GC, record whether a write barrier has added this
   214      * compartment's global to the store buffer since the last minor GC.
   215      *
   216      * This is used to avoid adding it to the store buffer on every write, which
   217      * can quickly fill the buffer and also cause performance problems.
   218      */
   219     bool                         globalWriteBarriered;
   221   public:
   222     void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
   223                                 size_t *tiAllocationSiteTables,
   224                                 size_t *tiArrayTypeTables,
   225                                 size_t *tiObjectTypeTables,
   226                                 size_t *compartmentObject,
   227                                 size_t *shapesCompartmentTables,
   228                                 size_t *crossCompartmentWrappers,
   229                                 size_t *regexpCompartment,
   230                                 size_t *debuggeesSet,
   231                                 size_t *savedStacksSet);
   233     /*
   234      * Shared scope property tree, and arena-pool for allocating its nodes.
   235      */
   236     js::PropertyTree             propertyTree;
   238     /* Set of all unowned base shapes in the compartment. */
   239     js::BaseShapeSet             baseShapes;
   240     void sweepBaseShapeTable();
   242     /* Set of initial shapes in the compartment. */
   243     js::InitialShapeSet          initialShapes;
   244     void sweepInitialShapeTable();
   246     /* Set of default 'new' or lazy types in the compartment. */
   247     js::types::TypeObjectWithNewScriptSet newTypeObjects;
   248     js::types::TypeObjectWithNewScriptSet lazyTypeObjects;
   249     void sweepNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet &table);
   250 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
   251     void checkNewTypeObjectTableAfterMovingGC();
   252     void checkInitialShapesTableAfterMovingGC();
   253     void checkWrapperMapAfterMovingGC();
   254 #endif
   256     /*
   257      * Hash table of all manually call site-cloned functions from within
   258      * self-hosted code. Cloning according to call site provides extra
   259      * sensitivity for type specialization and inlining.
   260      */
   261     js::CallsiteCloneTable callsiteClones;
   262     void sweepCallsiteClones();
   264     /*
   265      * Lazily initialized script source object to use for scripts cloned
   266      * from the self-hosting global.
   267      */
   268     js::ReadBarriered<js::ScriptSourceObject> selfHostingScriptSource;
   270     /* During GC, stores the index of this compartment in rt->compartments. */
   271     unsigned                     gcIndex;
   273     /*
   274      * During GC, stores the head of a list of incoming pointers from gray cells.
   275      *
   276      * The objects in the list are either cross-compartment wrappers, or
   277      * debugger wrapper objects.  The list link is either in the second extra
   278      * slot for the former, or a special slot for the latter.
   279      */
   280     JSObject                     *gcIncomingGrayPointers;
   282     /* During GC, list of live array buffers with >1 view accumulated during tracing. */
   283     js::ArrayBufferVector        gcLiveArrayBuffers;
   285     /* Linked list of live weakmaps in this compartment. */
   286     js::WeakMapBase              *gcWeakMapList;
   288   private:
   289     enum {
   290         DebugFromC = 1 << 0,
   291         DebugFromJS = 1 << 1,
   292         DebugNeedDelazification = 1 << 2
   293     };
   295     static const unsigned DebugModeFromMask = DebugFromC | DebugFromJS;
   297     unsigned                     debugModeBits;  // see debugMode() below
   299   public:
   300     JSCompartment(JS::Zone *zone, const JS::CompartmentOptions &options);
   301     ~JSCompartment();
   303     bool init(JSContext *cx);
   305     /* Mark cross-compartment wrappers. */
   306     void markCrossCompartmentWrappers(JSTracer *trc);
   308     inline bool wrap(JSContext *cx, JS::MutableHandleValue vp,
   309                      JS::HandleObject existing = js::NullPtr());
   311     bool wrap(JSContext *cx, JSString **strp);
   312     bool wrap(JSContext *cx, js::HeapPtrString *strp);
   313     bool wrap(JSContext *cx, JS::MutableHandleObject obj,
   314               JS::HandleObject existingArg = js::NullPtr());
   315     bool wrapId(JSContext *cx, jsid *idp);
   316     bool wrap(JSContext *cx, js::PropertyOp *op);
   317     bool wrap(JSContext *cx, js::StrictPropertyOp *op);
   318     bool wrap(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc);
   319     bool wrap(JSContext *cx, js::AutoIdVector &props);
   321     bool putWrapper(JSContext *cx, const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
   323     js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) {
   324         return crossCompartmentWrappers.lookup(wrapped);
   325     }
   327     void removeWrapper(js::WrapperMap::Ptr p) {
   328         crossCompartmentWrappers.remove(p);
   329     }
   331     struct WrapperEnum : public js::WrapperMap::Enum {
   332         WrapperEnum(JSCompartment *c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
   333     };
   335     void trace(JSTracer *trc);
   336     void markRoots(JSTracer *trc);
   337     bool isDiscardingJitCode(JSTracer *trc);
   338     void sweep(js::FreeOp *fop, bool releaseTypes);
   339     void sweepCrossCompartmentWrappers();
   340     void purge();
   341     void clearTables();
   343     bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
   344     void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
   345     bool callObjectMetadataCallback(JSContext *cx, JSObject **obj) const {
   346         return objectMetadataCallback(cx, obj);
   347     }
   349     js::SavedStacks &savedStacks() { return savedStacks_; }
   351     void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone> &finder);
   353     js::DtoaCache dtoaCache;
   355     /* Random number generator state, used by jsmath.cpp. */
   356     uint64_t rngState;
   358   private:
   359     /*
   360      * Weak reference to each global in this compartment that is a debuggee.
   361      * Each global has its own list of debuggers.
   362      */
   363     js::GlobalObjectSet              debuggees;
   365   private:
   366     JSCompartment *thisForCtor() { return this; }
   368   public:
   369     /*
   370      * There are dueling APIs for debug mode. It can be enabled or disabled via
   371      * JS_SetDebugModeForCompartment. It is automatically enabled and disabled
   372      * by Debugger objects. Therefore debugModeBits has the DebugFromC bit set
   373      * if the C API wants debug mode and the DebugFromJS bit set if debuggees
   374      * is non-empty.
   375      *
   376      * When toggling on, DebugNeedDelazification is set to signal that
   377      * Debugger methods which depend on seeing all scripts (like findScripts)
   378      * need to delazify the scripts in the compartment first.
   379      */
   380     bool debugMode() const {
   381         return !!(debugModeBits & DebugModeFromMask);
   382     }
   384     /* True if any scripts from this compartment are on the JS stack. */
   385     bool hasScriptsOnStack();
   387     /*
   388      * Schedule the compartment to be delazified. Called from
   389      * LazyScript::Create.
   390      */
   391     void scheduleDelazificationForDebugMode() {
   392         debugModeBits |= DebugNeedDelazification;
   393     }
   395     /*
   396      * If we scheduled delazification for turning on debug mode, delazify all
   397      * scripts.
   398      */
   399     bool ensureDelazifyScriptsForDebugMode(JSContext *cx);
   401   private:
   403     /* This is called only when debugMode() has just toggled. */
   404     bool updateJITForDebugMode(JSContext *maybecx, js::AutoDebugModeInvalidation &invalidate);
   406   public:
   407     js::GlobalObjectSet &getDebuggees() { return debuggees; }
   408     bool addDebuggee(JSContext *cx, js::GlobalObject *global);
   409     bool addDebuggee(JSContext *cx, js::GlobalObject *global,
   410                      js::AutoDebugModeInvalidation &invalidate);
   411     bool removeDebuggee(JSContext *cx, js::GlobalObject *global,
   412                         js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
   413     bool removeDebuggee(JSContext *cx, js::GlobalObject *global,
   414                         js::AutoDebugModeInvalidation &invalidate,
   415                         js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
   416     void removeDebuggeeUnderGC(js::FreeOp *fop, js::GlobalObject *global,
   417                                js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
   418     void removeDebuggeeUnderGC(js::FreeOp *fop, js::GlobalObject *global,
   419                                js::AutoDebugModeInvalidation &invalidate,
   420                                js::GlobalObjectSet::Enum *debuggeesEnum = nullptr);
   421     bool setDebugModeFromC(JSContext *cx, bool b,
   422                            js::AutoDebugModeInvalidation &invalidate);
   424     void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JS::HandleObject handler);
   425     void clearTraps(js::FreeOp *fop);
   427   private:
   428     void sweepBreakpoints(js::FreeOp *fop);
   430   public:
   431     js::WatchpointMap *watchpointMap;
   433     js::ScriptCountsMap *scriptCountsMap;
   435     js::DebugScriptMap *debugScriptMap;
   437     /* Bookkeeping information for debug scope objects. */
   438     js::DebugScopes *debugScopes;
   440     /*
   441      * List of potentially active iterators that may need deleted property
   442      * suppression.
   443      */
   444     js::NativeIterator *enumerators;
   446     /* Used by memory reporters and invalid otherwise. */
   447     void               *compartmentStats;
   449 #ifdef JS_ION
   450   private:
   451     js::jit::JitCompartment *jitCompartment_;
   453   public:
   454     bool ensureJitCompartmentExists(JSContext *cx);
   455     js::jit::JitCompartment *jitCompartment() {
   456         return jitCompartment_;
   457     }
   458 #endif
   459 };
   461 inline bool
   462 JSRuntime::isAtomsZone(JS::Zone *zone)
   463 {
   464     return zone == atomsCompartment_->zone();
   465 }
   467 // For use when changing the debug mode flag on one or more compartments.
   468 // Invalidate and discard JIT code since debug mode breaks JIT assumptions.
   469 //
   470 // AutoDebugModeInvalidation has two modes: compartment or zone
   471 // invalidation. While it is correct to always use compartment invalidation,
   472 // if you know ahead of time you need to invalidate a whole zone, it is faster
   473 // to invalidate the zone.
   474 //
   475 // Compartment invalidation only invalidates scripts belonging to that
   476 // compartment.
   477 //
   478 // Zone invalidation invalidates all scripts belonging to non-special
   479 // (i.e. those with principals) compartments of the zone.
   480 //
   481 // FIXME: Remove entirely once bug 716647 lands.
   482 //
   483 class js::AutoDebugModeInvalidation
   484 {
   485     JSCompartment *comp_;
   486     JS::Zone *zone_;
   488     enum {
   489         NoNeed = 0,
   490         ToggledOn = 1,
   491         ToggledOff = 2
   492     } needInvalidation_;
   494   public:
   495     explicit AutoDebugModeInvalidation(JSCompartment *comp)
   496       : comp_(comp), zone_(nullptr), needInvalidation_(NoNeed)
   497     { }
   499     explicit AutoDebugModeInvalidation(JS::Zone *zone)
   500       : comp_(nullptr), zone_(zone), needInvalidation_(NoNeed)
   501     { }
   503 #ifdef JS_ION
   504     ~AutoDebugModeInvalidation();
   505 #else
   506     ~AutoDebugModeInvalidation() { }
   507 #endif
   509     bool isFor(JSCompartment *comp) {
   510         if (comp_)
   511             return comp == comp_;
   512         return comp->zone() == zone_;
   513     }
   515     void scheduleInvalidation(bool debugMode) {
   516         // If we are scheduling invalidation for multiple compartments, they
   517         // must all agree on the toggle. This is so we can decide if we need
   518         // to invalidate on-stack scripts.
   519         MOZ_ASSERT_IF(needInvalidation_ != NoNeed,
   520                       needInvalidation_ == (debugMode ? ToggledOn : ToggledOff));
   521         needInvalidation_ = debugMode ? ToggledOn : ToggledOff;
   522     }
   523 };
   525 namespace js {
   527 inline js::Handle<js::GlobalObject*>
   528 ExclusiveContext::global() const
   529 {
   530     /*
   531      * It's safe to use |unsafeGet()| here because any compartment that is
   532      * on-stack will be marked automatically, so there's no need for a read
   533      * barrier on it. Once the compartment is popped, the handle is no longer
   534      * safe to use.
   535      */
   536     MOZ_ASSERT(compartment_, "Caller needs to enter a compartment first");
   537     return Handle<GlobalObject*>::fromMarkedLocation(compartment_->global_.unsafeGet());
   538 }
   540 class AssertCompartmentUnchanged
   541 {
   542   public:
   543     AssertCompartmentUnchanged(JSContext *cx
   544                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
   545       : cx(cx), oldCompartment(cx->compartment())
   546     {
   547         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   548     }
   550     ~AssertCompartmentUnchanged() {
   551         JS_ASSERT(cx->compartment() == oldCompartment);
   552     }
   554   protected:
   555     JSContext * const cx;
   556     JSCompartment * const oldCompartment;
   557     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   558 };
   560 class AutoCompartment
   561 {
   562     ExclusiveContext * const cx_;
   563     JSCompartment * const origin_;
   565   public:
   566     inline AutoCompartment(ExclusiveContext *cx, JSObject *target);
   567     inline AutoCompartment(ExclusiveContext *cx, JSCompartment *target);
   568     inline ~AutoCompartment();
   570     ExclusiveContext *context() const { return cx_; }
   571     JSCompartment *origin() const { return origin_; }
   573   private:
   574     AutoCompartment(const AutoCompartment &) MOZ_DELETE;
   575     AutoCompartment & operator=(const AutoCompartment &) MOZ_DELETE;
   576 };
   578 /*
   579  * Use this to change the behavior of an AutoCompartment slightly on error. If
   580  * the exception happens to be an Error object, copy it to the origin compartment
   581  * instead of wrapping it.
   582  */
   583 class ErrorCopier
   584 {
   585     mozilla::Maybe<AutoCompartment> &ac;
   586     RootedObject scope;
   588   public:
   589     ErrorCopier(mozilla::Maybe<AutoCompartment> &ac, JSObject *scope)
   590       : ac(ac), scope(ac.ref().context(), scope) {}
   591     ~ErrorCopier();
   592 };
   594 /*
   595  * AutoWrapperVector and AutoWrapperRooter can be used to store wrappers that
   596  * are obtained from the cross-compartment map. However, these classes should
   597  * not be used if the wrapper will escape. For example, it should not be stored
   598  * in the heap.
   599  *
   600  * The AutoWrapper rooters are different from other autorooters because their
   601  * wrappers are marked on every GC slice rather than just the first one. If
   602  * there's some wrapper that we want to use temporarily without causing it to be
   603  * marked, we can use these AutoWrapper classes. If we get unlucky and a GC
   604  * slice runs during the code using the wrapper, the GC will mark the wrapper so
   605  * that it doesn't get swept out from under us. Otherwise, the wrapper needn't
   606  * be marked. This is useful in functions like JS_TransplantObject that
   607  * manipulate wrappers in compartments that may no longer be alive.
   608  */
   610 /*
   611  * This class stores the data for AutoWrapperVector and AutoWrapperRooter. It
   612  * should not be used in any other situations.
   613  */
   614 struct WrapperValue
   615 {
   616     /*
   617      * We use unsafeGet() in the constructors to avoid invoking a read barrier
   618      * on the wrapper, which may be dead (see the comment about bug 803376 in
   619      * jsgc.cpp regarding this). If there is an incremental GC while the wrapper
   620      * is in use, the AutoWrapper rooter will ensure the wrapper gets marked.
   621      */
   622     explicit WrapperValue(const WrapperMap::Ptr &ptr)
   623       : value(*ptr->value().unsafeGet())
   624     {}
   626     explicit WrapperValue(const WrapperMap::Enum &e)
   627       : value(*e.front().value().unsafeGet())
   628     {}
   630     Value &get() { return value; }
   631     Value get() const { return value; }
   632     operator const Value &() const { return value; }
   633     JSObject &toObject() const { return value.toObject(); }
   635   private:
   636     Value value;
   637 };
   639 class AutoWrapperVector : public AutoVectorRooter<WrapperValue>
   640 {
   641   public:
   642     explicit AutoWrapperVector(JSContext *cx
   643                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
   644         : AutoVectorRooter<WrapperValue>(cx, WRAPVECTOR)
   645     {
   646         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   647     }
   649     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   650 };
   652 class AutoWrapperRooter : private AutoGCRooter {
   653   public:
   654     AutoWrapperRooter(JSContext *cx, WrapperValue v
   655                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
   656       : AutoGCRooter(cx, WRAPPER), value(v)
   657     {
   658         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
   659     }
   661     operator JSObject *() const {
   662         return value.get().toObjectOrNull();
   663     }
   665     friend void AutoGCRooter::trace(JSTracer *trc);
   667   private:
   668     WrapperValue value;
   669     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   670 };
   672 } /* namespace js */
   674 #endif /* jscompartment_h */

mercurial