Bumping manifests a=b2g-bump
[gecko.git] / js / src / jscompartment.h
blob5f91ae01d4203fefb462395c8e6c51c60d3a540a
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/RegExp.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;
24 namespace gc {
25 template<class Node> class ComponentFinder;
28 struct NativeIterator;
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.
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;
50 void cache(int base, double d, JSFlatString* s) {
51 this->base = base;
52 this->d = d;
53 this->s = s;
57 /* If HashNumber grows, need to change WrapperHasher. */
58 JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
60 struct CrossCompartmentKey
62 enum Kind {
63 ObjectWrapper,
64 StringWrapper,
65 DebuggerScript,
66 DebuggerSource,
67 DebuggerObject,
68 DebuggerEnvironment
71 Kind kind;
72 JSObject* debugger;
73 js::gc::Cell* wrapped;
75 explicit CrossCompartmentKey(JSObject* wrapped)
76 : kind(ObjectWrapper), debugger(nullptr), wrapped(wrapped)
78 MOZ_RELEASE_ASSERT(wrapped);
80 explicit CrossCompartmentKey(JSString* wrapped)
81 : kind(StringWrapper), debugger(nullptr), wrapped(wrapped)
83 MOZ_RELEASE_ASSERT(wrapped);
85 explicit CrossCompartmentKey(Value wrappedArg)
86 : kind(wrappedArg.isString() ? StringWrapper : ObjectWrapper),
87 debugger(nullptr),
88 wrapped((js::gc::Cell*)wrappedArg.toGCThing())
90 MOZ_RELEASE_ASSERT(wrappedArg.isString() || wrappedArg.isObject());
91 MOZ_RELEASE_ASSERT(wrapped);
93 explicit CrossCompartmentKey(const RootedValue& wrappedArg)
94 : kind(wrappedArg.get().isString() ? StringWrapper : ObjectWrapper),
95 debugger(nullptr),
96 wrapped((js::gc::Cell*)wrappedArg.get().toGCThing())
98 MOZ_RELEASE_ASSERT(wrappedArg.isString() || wrappedArg.isObject());
99 MOZ_RELEASE_ASSERT(wrapped);
101 CrossCompartmentKey(Kind kind, JSObject* dbg, js::gc::Cell* wrapped)
102 : kind(kind), debugger(dbg), wrapped(wrapped)
104 MOZ_RELEASE_ASSERT(dbg);
105 MOZ_RELEASE_ASSERT(wrapped);
108 private:
109 CrossCompartmentKey() MOZ_DELETE;
112 struct WrapperHasher : public DefaultHasher<CrossCompartmentKey>
114 static HashNumber hash(const CrossCompartmentKey& key) {
115 JS_ASSERT(!IsPoisonedPtr(key.wrapped));
116 return uint32_t(uintptr_t(key.wrapped)) | uint32_t(key.kind);
119 static bool match(const CrossCompartmentKey& l, const CrossCompartmentKey& k) {
120 return l.kind == k.kind && l.debugger == k.debugger && l.wrapped == k.wrapped;
124 typedef HashMap<CrossCompartmentKey, ReadBarrieredValue,
125 WrapperHasher, SystemAllocPolicy> WrapperMap;
127 } /* namespace js */
129 namespace JS {
130 struct TypeInferenceSizes;
133 namespace js {
134 class AutoDebugModeInvalidation;
135 class DebugScopes;
136 class WeakMapBase;
139 struct JSCompartment
141 JS::CompartmentOptions options_;
143 private:
144 JS::Zone* zone_;
145 JSRuntime* runtime_;
147 public:
148 JSPrincipals* principals;
149 bool isSystem;
150 bool isSelfHosting;
151 bool marked;
153 // A null add-on ID means that the compartment is not associated with an
154 // add-on.
155 JSAddonId* addonId;
157 #ifdef DEBUG
158 bool firedOnNewGlobalObject;
159 #endif
161 void mark() { marked = true; }
163 private:
164 friend struct JSRuntime;
165 friend struct JSContext;
166 friend class js::ExclusiveContext;
167 js::ReadBarrieredGlobalObject global_;
169 unsigned enterCompartmentDepth;
171 public:
172 void enter() { enterCompartmentDepth++; }
173 void leave() { enterCompartmentDepth--; }
174 bool hasBeenEntered() { return !!enterCompartmentDepth; }
176 JS::Zone* zone() { return zone_; }
177 const JS::Zone* zone() const { return zone_; }
178 JS::CompartmentOptions& options() { return options_; }
179 const JS::CompartmentOptions& options() const { return options_; }
181 JSRuntime* runtimeFromMainThread() {
182 JS_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
183 return runtime_;
186 // Note: Unrestricted access to the zone's runtime from an arbitrary
187 // thread can easily lead to races. Use this method very carefully.
188 JSRuntime* runtimeFromAnyThread() const {
189 return runtime_;
193 * Nb: global_ might be nullptr, if (a) it's the atoms compartment, or
194 * (b) the compartment's global has been collected. The latter can happen
195 * if e.g. a string in a compartment is rooted but no object is, and thus
196 * the global isn't rooted, and thus the global can be finalized while the
197 * compartment lives on.
199 * In contrast, JSObject::global() is infallible because marking a JSObject
200 * always marks its global as well.
201 * TODO: add infallible JSScript::global()
203 inline js::GlobalObject* maybeGlobal() const;
205 /* An unbarriered getter for use while tracing. */
206 inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
208 inline void initGlobal(js::GlobalObject& global);
210 public:
212 * Moves all data from the allocator |workerAllocator|, which was
213 * in use by a parallel worker, into the compartment's main
214 * allocator. This is used at the end of a parallel section.
216 void adoptWorkerAllocator(js::Allocator* workerAllocator);
218 bool activeAnalysis;
220 /* Type information about the scripts and objects in this compartment. */
221 js::types::TypeCompartment types;
223 void* data;
225 private:
226 js::ObjectMetadataCallback objectMetadataCallback;
228 js::SavedStacks savedStacks_;
230 js::WrapperMap crossCompartmentWrappers;
232 public:
233 /* Last time at which an animation was played for a global in this compartment. */
234 int64_t lastAnimationTime;
236 js::RegExpCompartment regExps;
239 * For generational GC, record whether a write barrier has added this
240 * compartment's global to the store buffer since the last minor GC.
242 * This is used to avoid adding it to the store buffer on every write, which
243 * can quickly fill the buffer and also cause performance problems.
245 bool globalWriteBarriered;
247 public:
248 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
249 size_t* tiAllocationSiteTables,
250 size_t* tiArrayTypeTables,
251 size_t* tiObjectTypeTables,
252 size_t* compartmentObject,
253 size_t* compartmentTables,
254 size_t* crossCompartmentWrappers,
255 size_t* regexpCompartment,
256 size_t* debuggeesSet,
257 size_t* savedStacksSet);
260 * Shared scope property tree, and arena-pool for allocating its nodes.
262 js::PropertyTree propertyTree;
264 /* Set of all unowned base shapes in the compartment. */
265 js::BaseShapeSet baseShapes;
266 void sweepBaseShapeTable();
268 /* Set of initial shapes in the compartment. */
269 js::InitialShapeSet initialShapes;
270 void sweepInitialShapeTable();
272 /* Set of default 'new' or lazy types in the compartment. */
273 js::types::TypeObjectWithNewScriptSet newTypeObjects;
274 js::types::TypeObjectWithNewScriptSet lazyTypeObjects;
275 void sweepNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet& table);
276 #ifdef JSGC_HASH_TABLE_CHECKS
277 void checkTypeObjectTablesAfterMovingGC();
278 void checkTypeObjectTableAfterMovingGC(js::types::TypeObjectWithNewScriptSet& table);
279 void checkInitialShapesTableAfterMovingGC();
280 void checkWrapperMapAfterMovingGC();
281 #endif
284 * Hash table of all manually call site-cloned functions from within
285 * self-hosted code. Cloning according to call site provides extra
286 * sensitivity for type specialization and inlining.
288 js::CallsiteCloneTable callsiteClones;
289 void sweepCallsiteClones();
292 * Lazily initialized script source object to use for scripts cloned
293 * from the self-hosting global.
295 js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
297 /* During GC, stores the index of this compartment in rt->compartments. */
298 unsigned gcIndex;
301 * During GC, stores the head of a list of incoming pointers from gray cells.
303 * The objects in the list are either cross-compartment wrappers, or
304 * debugger wrapper objects. The list link is either in the second extra
305 * slot for the former, or a special slot for the latter.
307 JSObject* gcIncomingGrayPointers;
309 /* During GC, list of live array buffers with >1 view accumulated during tracing. */
310 js::ArrayBufferVector gcLiveArrayBuffers;
312 /* Linked list of live weakmaps in this compartment. */
313 js::WeakMapBase* gcWeakMapList;
315 private:
316 enum {
317 DebugFromC = 1 << 0,
318 DebugFromJS = 1 << 1,
319 DebugNeedDelazification = 1 << 2
322 static const unsigned DebugModeFromMask = DebugFromC | DebugFromJS;
324 unsigned debugModeBits; // see debugMode() below
326 public:
327 JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options);
328 ~JSCompartment();
330 bool init(JSContext* cx);
332 /* Mark cross-compartment wrappers. */
333 void markCrossCompartmentWrappers(JSTracer* trc);
335 inline bool wrap(JSContext* cx, JS::MutableHandleValue vp,
336 JS::HandleObject existing = js::NullPtr());
338 bool wrap(JSContext* cx, JSString** strp);
339 bool wrap(JSContext* cx, js::HeapPtrString* strp);
340 bool wrap(JSContext* cx, JS::MutableHandleObject obj,
341 JS::HandleObject existingArg = js::NullPtr());
342 bool wrap(JSContext* cx, js::PropertyOp* op);
343 bool wrap(JSContext* cx, js::StrictPropertyOp* op);
344 bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
345 bool wrap(JSContext* cx, JS::MutableHandle<js::PropDesc> desc);
347 template<typename T> bool wrap(JSContext* cx, JS::AutoVectorRooter<T>& vec) {
348 for (size_t i = 0; i < vec.length(); ++i) {
349 if (!wrap(cx, vec[i]))
350 return false;
352 return true;
355 bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
357 js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) {
358 return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
361 void removeWrapper(js::WrapperMap::Ptr p) {
362 crossCompartmentWrappers.remove(p);
365 struct WrapperEnum : public js::WrapperMap::Enum {
366 explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
369 void trace(JSTracer* trc);
370 void markRoots(JSTracer* trc);
371 bool isDiscardingJitCode(JSTracer* trc);
372 void sweep(js::FreeOp* fop, bool releaseTypes);
373 void sweepCrossCompartmentWrappers();
374 void purge();
375 void clearTables();
377 #ifdef JSGC_COMPACTING
378 void fixupInitialShapeTable();
379 void fixupNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet& table);
380 void fixupCrossCompartmentWrappers(JSTracer* trc);
381 void fixupAfterMovingGC();
382 void fixupGlobal();
383 #endif
385 bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
386 void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
387 void forgetObjectMetadataCallback() {
388 objectMetadataCallback = nullptr;
390 bool callObjectMetadataCallback(JSContext* cx, JSObject** obj) const {
391 return objectMetadataCallback(cx, obj);
394 js::SavedStacks& savedStacks() { return savedStacks_; }
396 void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone>& finder);
398 js::DtoaCache dtoaCache;
400 /* Random number generator state, used by jsmath.cpp. */
401 uint64_t rngState;
403 private:
405 * Weak reference to each global in this compartment that is a debuggee.
406 * Each global has its own list of debuggers.
408 js::GlobalObjectSet debuggees;
410 private:
411 JSCompartment* thisForCtor() { return this; }
413 public:
415 * There are dueling APIs for debug mode. It can be enabled or disabled via
416 * JS_SetDebugModeForCompartment. It is automatically enabled and disabled
417 * by Debugger objects. Therefore debugModeBits has the DebugFromC bit set
418 * if the C API wants debug mode and the DebugFromJS bit set if debuggees
419 * is non-empty.
421 * When toggling on, DebugNeedDelazification is set to signal that
422 * Debugger methods which depend on seeing all scripts (like findScripts)
423 * need to delazify the scripts in the compartment first.
425 bool debugMode() const {
426 return !!(debugModeBits & DebugModeFromMask);
429 /* True if any scripts from this compartment are on the JS stack. */
430 bool hasScriptsOnStack();
433 * Schedule the compartment to be delazified. Called from
434 * LazyScript::Create.
436 void scheduleDelazificationForDebugMode() {
437 debugModeBits |= DebugNeedDelazification;
441 * If we scheduled delazification for turning on debug mode, delazify all
442 * scripts.
444 bool ensureDelazifyScriptsForDebugMode(JSContext* cx);
446 private:
448 /* This is called only when debugMode() has just toggled. */
449 bool updateJITForDebugMode(JSContext* maybecx, js::AutoDebugModeInvalidation& invalidate);
451 public:
452 js::GlobalObjectSet& getDebuggees() { return debuggees; }
453 bool addDebuggee(JSContext* cx, JS::Handle<js::GlobalObject*> global);
454 bool addDebuggee(JSContext* cx, JS::Handle<js::GlobalObject*> global,
455 js::AutoDebugModeInvalidation& invalidate);
456 bool removeDebuggee(JSContext* cx, js::GlobalObject* global,
457 js::GlobalObjectSet::Enum* debuggeesEnum = nullptr);
458 bool removeDebuggee(JSContext* cx, js::GlobalObject* global,
459 js::AutoDebugModeInvalidation& invalidate,
460 js::GlobalObjectSet::Enum* debuggeesEnum = nullptr);
461 void removeDebuggeeUnderGC(js::FreeOp* fop, js::GlobalObject* global,
462 js::GlobalObjectSet::Enum* debuggeesEnum = nullptr);
463 void removeDebuggeeUnderGC(js::FreeOp* fop, js::GlobalObject* global,
464 js::AutoDebugModeInvalidation& invalidate,
465 js::GlobalObjectSet::Enum* debuggeesEnum = nullptr);
466 bool setDebugModeFromC(JSContext* cx, bool b,
467 js::AutoDebugModeInvalidation& invalidate);
469 void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JS::HandleObject handler);
471 private:
472 void sweepBreakpoints(js::FreeOp* fop);
474 public:
475 js::WatchpointMap* watchpointMap;
477 js::ScriptCountsMap* scriptCountsMap;
479 js::DebugScriptMap* debugScriptMap;
481 /* Bookkeeping information for debug scope objects. */
482 js::DebugScopes* debugScopes;
485 * List of potentially active iterators that may need deleted property
486 * suppression.
488 js::NativeIterator* enumerators;
490 /* Used by memory reporters and invalid otherwise. */
491 void* compartmentStats;
493 // These flags help us to discover if a compartment that shouldn't be alive
494 // manages to outlive a GC.
495 bool scheduledForDestruction;
496 bool maybeAlive;
498 private:
499 js::jit::JitCompartment* jitCompartment_;
501 public:
502 bool ensureJitCompartmentExists(JSContext* cx);
503 js::jit::JitCompartment* jitCompartment() {
504 return jitCompartment_;
508 inline bool
509 JSRuntime::isAtomsZone(JS::Zone* zone)
511 return zone == atomsCompartment_->zone();
514 // For use when changing the debug mode flag on one or more compartments.
515 // Invalidate and discard JIT code since debug mode breaks JIT assumptions.
517 // AutoDebugModeInvalidation has two modes: compartment or zone
518 // invalidation. While it is correct to always use compartment invalidation,
519 // if you know ahead of time you need to invalidate a whole zone, it is faster
520 // to invalidate the zone.
522 // Compartment invalidation only invalidates scripts belonging to that
523 // compartment.
525 // Zone invalidation invalidates all scripts belonging to non-special
526 // (i.e. those with principals) compartments of the zone.
528 // FIXME: Remove entirely once bug 716647 lands.
530 class js::AutoDebugModeInvalidation
532 JSCompartment* comp_;
533 JS::Zone* zone_;
535 enum {
536 NoNeed = 0,
537 ToggledOn = 1,
538 ToggledOff = 2
539 } needInvalidation_;
541 public:
542 explicit AutoDebugModeInvalidation(JSCompartment* comp)
543 : comp_(comp), zone_(nullptr), needInvalidation_(NoNeed)
546 explicit AutoDebugModeInvalidation(JS::Zone* zone)
547 : comp_(nullptr), zone_(zone), needInvalidation_(NoNeed)
550 ~AutoDebugModeInvalidation();
552 bool isFor(JSCompartment* comp) {
553 if (comp_)
554 return comp == comp_;
555 return comp->zone() == zone_;
558 void scheduleInvalidation(bool debugMode) {
559 // If we are scheduling invalidation for multiple compartments, they
560 // must all agree on the toggle. This is so we can decide if we need
561 // to invalidate on-stack scripts.
562 MOZ_ASSERT_IF(needInvalidation_ != NoNeed,
563 needInvalidation_ == (debugMode ? ToggledOn : ToggledOff));
564 needInvalidation_ = debugMode ? ToggledOn : ToggledOff;
568 namespace js {
570 inline js::Handle<js::GlobalObject*>
571 ExclusiveContext::global() const
574 * It's safe to use |unsafeGet()| here because any compartment that is
575 * on-stack will be marked automatically, so there's no need for a read
576 * barrier on it. Once the compartment is popped, the handle is no longer
577 * safe to use.
579 MOZ_ASSERT(compartment_, "Caller needs to enter a compartment first");
580 return Handle<GlobalObject*>::fromMarkedLocation(compartment_->global_.unsafeGet());
583 class AssertCompartmentUnchanged
585 public:
586 explicit AssertCompartmentUnchanged(JSContext* cx
587 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
588 : cx(cx), oldCompartment(cx->compartment())
590 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
593 ~AssertCompartmentUnchanged() {
594 JS_ASSERT(cx->compartment() == oldCompartment);
597 protected:
598 JSContext * const cx;
599 JSCompartment * const oldCompartment;
600 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
603 class AutoCompartment
605 ExclusiveContext * const cx_;
606 JSCompartment * const origin_;
608 public:
609 inline AutoCompartment(ExclusiveContext* cx, JSObject* target);
610 inline AutoCompartment(ExclusiveContext* cx, JSCompartment* target);
611 inline ~AutoCompartment();
613 ExclusiveContext* context() const { return cx_; }
614 JSCompartment* origin() const { return origin_; }
616 private:
617 AutoCompartment(const AutoCompartment&) MOZ_DELETE;
618 AutoCompartment & operator=(const AutoCompartment&) MOZ_DELETE;
622 * Use this to change the behavior of an AutoCompartment slightly on error. If
623 * the exception happens to be an Error object, copy it to the origin compartment
624 * instead of wrapping it.
626 class ErrorCopier
628 mozilla::Maybe<AutoCompartment>& ac;
630 public:
631 explicit ErrorCopier(mozilla::Maybe<AutoCompartment>& ac)
632 : ac(ac) {}
633 ~ErrorCopier();
637 * AutoWrapperVector and AutoWrapperRooter can be used to store wrappers that
638 * are obtained from the cross-compartment map. However, these classes should
639 * not be used if the wrapper will escape. For example, it should not be stored
640 * in the heap.
642 * The AutoWrapper rooters are different from other autorooters because their
643 * wrappers are marked on every GC slice rather than just the first one. If
644 * there's some wrapper that we want to use temporarily without causing it to be
645 * marked, we can use these AutoWrapper classes. If we get unlucky and a GC
646 * slice runs during the code using the wrapper, the GC will mark the wrapper so
647 * that it doesn't get swept out from under us. Otherwise, the wrapper needn't
648 * be marked. This is useful in functions like JS_TransplantObject that
649 * manipulate wrappers in compartments that may no longer be alive.
653 * This class stores the data for AutoWrapperVector and AutoWrapperRooter. It
654 * should not be used in any other situations.
656 struct WrapperValue
659 * We use unsafeGet() in the constructors to avoid invoking a read barrier
660 * on the wrapper, which may be dead (see the comment about bug 803376 in
661 * jsgc.cpp regarding this). If there is an incremental GC while the wrapper
662 * is in use, the AutoWrapper rooter will ensure the wrapper gets marked.
664 explicit WrapperValue(const WrapperMap::Ptr& ptr)
665 : value(*ptr->value().unsafeGet())
668 explicit WrapperValue(const WrapperMap::Enum& e)
669 : value(*e.front().value().unsafeGet())
672 Value& get() { return value; }
673 Value get() const { return value; }
674 operator const Value&() const { return value; }
675 JSObject& toObject() const { return value.toObject(); }
677 private:
678 Value value;
681 class AutoWrapperVector : public AutoVectorRooter<WrapperValue>
683 public:
684 explicit AutoWrapperVector(JSContext* cx
685 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
686 : AutoVectorRooter<WrapperValue>(cx, WRAPVECTOR)
688 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
691 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
694 class AutoWrapperRooter : private JS::AutoGCRooter {
695 public:
696 AutoWrapperRooter(JSContext* cx, WrapperValue v
697 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
698 : JS::AutoGCRooter(cx, WRAPPER), value(v)
700 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
703 operator JSObject*() const {
704 return value.get().toObjectOrNull();
707 friend void JS::AutoGCRooter::trace(JSTracer* trc);
709 private:
710 WrapperValue value;
711 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
714 } /* namespace js */
716 #endif /* jscompartment_h */