Bumping manifests a=b2g-bump
[gecko.git] / js / src / jscompartment.h
blob68332bc939a86952ffb0960d7521ed8b90726159
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 "prmjtime.h"
13 #include "builtin/RegExp.h"
14 #include "gc/Zone.h"
15 #include "vm/GlobalObject.h"
16 #include "vm/PIC.h"
17 #include "vm/SavedStacks.h"
19 namespace js {
21 namespace jit {
22 class JitCompartment;
25 namespace gc {
26 template<class Node> class ComponentFinder;
29 struct NativeIterator;
32 * A single-entry cache for some base-10 double-to-string conversions. This
33 * helps date-format-xparb.js. It also avoids skewing the results for
34 * v8-splay.js when measured by the SunSpider harness, where the splay tree
35 * initialization (which includes many repeated double-to-string conversions)
36 * is erroneously included in the measurement; see bug 562553.
38 class DtoaCache {
39 double d;
40 int base;
41 JSFlatString* s; // if s==nullptr, d and base are not valid
43 public:
44 DtoaCache() : s(nullptr) {}
45 void purge() { s = nullptr; }
47 JSFlatString* lookup(int base, double d) {
48 return this->s && base == this->base && d == this->d ? this->s : nullptr;
51 void cache(int base, double d, JSFlatString* s) {
52 this->base = base;
53 this->d = d;
54 this->s = s;
58 struct CrossCompartmentKey
60 enum Kind {
61 ObjectWrapper,
62 StringWrapper,
63 DebuggerScript,
64 DebuggerSource,
65 DebuggerObject,
66 DebuggerEnvironment
69 Kind kind;
70 JSObject* debugger;
71 js::gc::Cell* wrapped;
73 explicit CrossCompartmentKey(JSObject* wrapped)
74 : kind(ObjectWrapper), debugger(nullptr), wrapped(wrapped)
76 MOZ_RELEASE_ASSERT(wrapped);
78 explicit CrossCompartmentKey(JSString* wrapped)
79 : kind(StringWrapper), debugger(nullptr), wrapped(wrapped)
81 MOZ_RELEASE_ASSERT(wrapped);
83 explicit CrossCompartmentKey(Value wrappedArg)
84 : kind(wrappedArg.isString() ? StringWrapper : ObjectWrapper),
85 debugger(nullptr),
86 wrapped((js::gc::Cell*)wrappedArg.toGCThing())
88 MOZ_RELEASE_ASSERT(wrappedArg.isString() || wrappedArg.isObject());
89 MOZ_RELEASE_ASSERT(wrapped);
91 explicit CrossCompartmentKey(const RootedValue& wrappedArg)
92 : kind(wrappedArg.get().isString() ? StringWrapper : ObjectWrapper),
93 debugger(nullptr),
94 wrapped((js::gc::Cell*)wrappedArg.get().toGCThing())
96 MOZ_RELEASE_ASSERT(wrappedArg.isString() || wrappedArg.isObject());
97 MOZ_RELEASE_ASSERT(wrapped);
99 CrossCompartmentKey(Kind kind, JSObject* dbg, js::gc::Cell* wrapped)
100 : kind(kind), debugger(dbg), wrapped(wrapped)
102 MOZ_RELEASE_ASSERT(dbg);
103 MOZ_RELEASE_ASSERT(wrapped);
106 private:
107 CrossCompartmentKey() = delete;
110 struct WrapperHasher : public DefaultHasher<CrossCompartmentKey>
112 static HashNumber hash(const CrossCompartmentKey& key) {
113 MOZ_ASSERT(!IsPoisonedPtr(key.wrapped));
114 static_assert(sizeof(HashNumber) == sizeof(uint32_t),
115 "subsequent code assumes a four-byte hash");
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 DebugScopes;
135 class LazyArrayBufferTable;
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;
170 int64_t startInterval;
172 public:
173 int64_t totalTime;
174 void enter() {
175 if (addonId && !enterCompartmentDepth) {
176 startInterval = PRMJ_Now();
178 enterCompartmentDepth++;
180 void leave() {
181 enterCompartmentDepth--;
182 if (addonId && !enterCompartmentDepth) {
183 totalTime += (PRMJ_Now() - startInterval);
186 bool hasBeenEntered() { return !!enterCompartmentDepth; }
188 JS::Zone* zone() { return zone_; }
189 const JS::Zone* zone() const { return zone_; }
190 JS::CompartmentOptions& options() { return options_; }
191 const JS::CompartmentOptions& options() const { return options_; }
193 JSRuntime* runtimeFromMainThread() {
194 MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
195 return runtime_;
198 // Note: Unrestricted access to the zone's runtime from an arbitrary
199 // thread can easily lead to races. Use this method very carefully.
200 JSRuntime* runtimeFromAnyThread() const {
201 return runtime_;
205 * Nb: global_ might be nullptr, if (a) it's the atoms compartment, or
206 * (b) the compartment's global has been collected. The latter can happen
207 * if e.g. a string in a compartment is rooted but no object is, and thus
208 * the global isn't rooted, and thus the global can be finalized while the
209 * compartment lives on.
211 * In contrast, JSObject::global() is infallible because marking a JSObject
212 * always marks its global as well.
213 * TODO: add infallible JSScript::global()
215 inline js::GlobalObject* maybeGlobal() const;
217 /* An unbarriered getter for use while tracing. */
218 inline js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const;
220 inline void initGlobal(js::GlobalObject& global);
222 public:
224 * Moves all data from the allocator |workerAllocator|, which was
225 * in use by a parallel worker, into the compartment's main
226 * allocator. This is used at the end of a parallel section.
228 void adoptWorkerAllocator(js::Allocator* workerAllocator);
230 /* Type information about the scripts and objects in this compartment. */
231 js::types::TypeCompartment types;
233 void* data;
235 private:
236 js::ObjectMetadataCallback objectMetadataCallback;
238 js::SavedStacks savedStacks_;
240 js::WrapperMap crossCompartmentWrappers;
242 public:
243 /* Last time at which an animation was played for a global in this compartment. */
244 int64_t lastAnimationTime;
246 js::RegExpCompartment regExps;
249 * For generational GC, record whether a write barrier has added this
250 * compartment's global to the store buffer since the last minor GC.
252 * This is used to avoid adding it to the store buffer on every write, which
253 * can quickly fill the buffer and also cause performance problems.
255 bool globalWriteBarriered;
257 // Non-zero if any typed objects in this compartment might be neutered.
258 int32_t neuteredTypedObjects;
260 public:
261 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
262 size_t* tiAllocationSiteTables,
263 size_t* tiArrayTypeTables,
264 size_t* tiObjectTypeTables,
265 size_t* compartmentObject,
266 size_t* compartmentTables,
267 size_t* innerViews,
268 size_t* lazyArrayBuffers,
269 size_t* crossCompartmentWrappers,
270 size_t* regexpCompartment,
271 size_t* savedStacksSet);
274 * Shared scope property tree, and arena-pool for allocating its nodes.
276 js::PropertyTree propertyTree;
278 /* Set of all unowned base shapes in the compartment. */
279 js::BaseShapeSet baseShapes;
280 void sweepBaseShapeTable();
282 /* Set of initial shapes in the compartment. */
283 js::InitialShapeSet initialShapes;
284 void sweepInitialShapeTable();
286 /* Set of default 'new' or lazy types in the compartment. */
287 js::types::NewTypeObjectTable newTypeObjects;
288 js::types::NewTypeObjectTable lazyTypeObjects;
289 void sweepNewTypeObjectTable(js::types::NewTypeObjectTable& table);
291 #ifdef JSGC_HASH_TABLE_CHECKS
292 void checkTypeObjectTablesAfterMovingGC();
293 void checkTypeObjectTableAfterMovingGC(js::types::NewTypeObjectTable& table);
294 void checkInitialShapesTableAfterMovingGC();
295 void checkWrapperMapAfterMovingGC();
296 void checkBaseShapeTableAfterMovingGC();
297 #endif
300 * Hash table of all manually call site-cloned functions from within
301 * self-hosted code. Cloning according to call site provides extra
302 * sensitivity for type specialization and inlining.
304 js::CallsiteCloneTable callsiteClones;
305 void sweepCallsiteClones();
308 * Lazily initialized script source object to use for scripts cloned
309 * from the self-hosting global.
311 js::ReadBarrieredScriptSourceObject selfHostingScriptSource;
313 // Map from array buffers to views sharing that storage.
314 js::InnerViewTable innerViews;
316 // Map from typed objects to array buffers lazily created for them.
317 js::LazyArrayBufferTable* lazyArrayBuffers;
319 /* During GC, stores the index of this compartment in rt->compartments. */
320 unsigned gcIndex;
323 * During GC, stores the head of a list of incoming pointers from gray cells.
325 * The objects in the list are either cross-compartment wrappers, or
326 * debugger wrapper objects. The list link is either in the second extra
327 * slot for the former, or a special slot for the latter.
329 JSObject* gcIncomingGrayPointers;
331 /* Linked list of live weakmaps in this compartment. */
332 js::WeakMapBase* gcWeakMapList;
334 private:
335 /* Whether to preserve JIT code on non-shrinking GCs. */
336 bool gcPreserveJitCode;
338 enum {
339 DebugMode = 1 << 0,
340 DebugObservesAllExecution = 1 << 1,
341 DebugNeedDelazification = 1 << 2
344 // DebugObservesAllExecution is a submode of DebugMode, and is only valid
345 // when DebugMode is also set.
346 static const unsigned DebugExecutionMask = DebugMode | DebugObservesAllExecution;
348 unsigned debugModeBits;
350 public:
351 JSCompartment(JS::Zone* zone, const JS::CompartmentOptions& options);
352 ~JSCompartment();
354 bool init(JSContext* cx);
356 /* Mark cross-compartment wrappers. */
357 void markCrossCompartmentWrappers(JSTracer* trc);
359 inline bool wrap(JSContext* cx, JS::MutableHandleValue vp,
360 JS::HandleObject existing = js::NullPtr());
362 bool wrap(JSContext* cx, js::MutableHandleString strp);
363 bool wrap(JSContext* cx, JS::MutableHandleObject obj,
364 JS::HandleObject existingArg = js::NullPtr());
365 bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
366 bool wrap(JSContext* cx, JS::MutableHandle<js::PropDesc> desc);
368 template<typename T> bool wrap(JSContext* cx, JS::AutoVectorRooter<T>& vec) {
369 for (size_t i = 0; i < vec.length(); ++i) {
370 if (!wrap(cx, vec[i]))
371 return false;
373 return true;
376 bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
378 js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) {
379 return crossCompartmentWrappers.lookup(js::CrossCompartmentKey(wrapped));
382 void removeWrapper(js::WrapperMap::Ptr p) {
383 crossCompartmentWrappers.remove(p);
386 struct WrapperEnum : public js::WrapperMap::Enum {
387 explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
390 void trace(JSTracer* trc);
391 void markRoots(JSTracer* trc);
392 bool preserveJitCode() { return gcPreserveJitCode; }
394 void sweepInnerViews();
395 void sweepCrossCompartmentWrappers();
396 void sweepTypeObjectTables();
397 void sweepSavedStacks();
398 void sweepGlobalObject(js::FreeOp* fop);
399 void sweepSelfHostingScriptSource();
400 void sweepJitCompartment(js::FreeOp* fop);
401 void sweepRegExps();
402 void sweepDebugScopes();
403 void sweepWeakMaps();
404 void sweepNativeIterators();
406 void purge();
407 void clearTables();
409 #ifdef JSGC_COMPACTING
410 void fixupInitialShapeTable();
411 void fixupNewTypeObjectTable(js::types::NewTypeObjectTable& table);
412 void fixupAfterMovingGC();
413 void fixupGlobal();
414 void fixupBaseShapeTable();
415 #endif
417 bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
418 void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
419 void forgetObjectMetadataCallback() {
420 objectMetadataCallback = nullptr;
422 bool callObjectMetadataCallback(JSContext* cx, JSObject** obj) const {
423 return objectMetadataCallback(cx, obj);
425 const void* addressOfMetadataCallback() const {
426 return &objectMetadataCallback;
429 js::SavedStacks& savedStacks() { return savedStacks_; }
431 void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone>& finder);
433 js::DtoaCache dtoaCache;
435 /* Random number generator state, used by jsmath.cpp. */
436 uint64_t rngState;
438 private:
439 JSCompartment* thisForCtor() { return this; }
441 public:
443 // The Debugger observes execution on a frame-by-frame basis. The
444 // invariants of JSCompartment's debug mode bits, JSScript::isDebuggee,
445 // InterpreterFrame::isDebuggee, and Baseline::isDebuggee are enumerated
446 // below.
448 // 1. When a compartment's isDebuggee() == true, relazification, lazy
449 // parsing, and asm.js are disabled.
451 // 2. When a compartment's debugObservesAllExecution() == true, all of the
452 // compartment's scripts are considered debuggee scripts.
454 // 3. A script is considered a debuggee script either when, per above, its
455 // compartment is observing all execution, or if it has breakpoints set.
457 // 4. A debuggee script always pushes a debuggee frame.
459 // 5. A debuggee frame calls all slow path Debugger hooks in the
460 // Interpreter and Baseline. A debuggee frame implies that its script's
461 // BaselineScript, if extant, has been compiled with debug hook calls.
463 // 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures
464 // that the compiled BaselineScript is compiled with debug hook calls
465 // when attempting to enter Baseline.
467 // 7. A debuggee script or a debuggee frame (i.e., during OSR) does not
468 // attempt to enter Ion.
470 // Note that a debuggee frame may exist without its script being a
471 // debuggee script. e.g., Debugger.Frame.prototype.eval only marks the
472 // frame in which it is evaluating as a debuggee frame.
475 // True if this compartment's global is a debuggee of some Debugger
476 // object.
477 bool isDebuggee() const { return !!(debugModeBits & DebugMode); }
478 void setIsDebuggee() { debugModeBits |= DebugMode; }
479 void unsetIsDebuggee();
481 // True if an this compartment's global is a debuggee of some Debugger
482 // object with a live hook that observes all execution; e.g.,
483 // onEnterFrame.
484 bool debugObservesAllExecution() const {
485 return (debugModeBits & DebugExecutionMask) == DebugExecutionMask;
487 void setDebugObservesAllExecution() {
488 MOZ_ASSERT(isDebuggee());
489 debugModeBits |= DebugObservesAllExecution;
491 void unsetDebugObservesAllExecution() {
492 MOZ_ASSERT(isDebuggee());
493 debugModeBits &= ~DebugObservesAllExecution;
497 * Schedule the compartment to be delazified. Called from
498 * LazyScript::Create.
500 void scheduleDelazificationForDebugMode() { debugModeBits |= DebugNeedDelazification; }
503 * If we scheduled delazification for turning on debug mode, delazify all
504 * scripts.
506 bool ensureDelazifyScriptsForDebugMode(JSContext* cx);
508 void clearBreakpointsIn(js::FreeOp* fop, js::Debugger* dbg, JS::HandleObject handler);
510 private:
511 void sweepBreakpoints(js::FreeOp* fop);
513 public:
514 js::WatchpointMap* watchpointMap;
516 js::ScriptCountsMap* scriptCountsMap;
518 js::DebugScriptMap* debugScriptMap;
520 /* Bookkeeping information for debug scope objects. */
521 js::DebugScopes* debugScopes;
524 * List of potentially active iterators that may need deleted property
525 * suppression.
527 js::NativeIterator* enumerators;
529 /* Used by memory reporters and invalid otherwise. */
530 void* compartmentStats;
532 // These flags help us to discover if a compartment that shouldn't be alive
533 // manages to outlive a GC.
534 bool scheduledForDestruction;
535 bool maybeAlive;
537 private:
538 js::jit::JitCompartment* jitCompartment_;
540 public:
541 bool ensureJitCompartmentExists(JSContext* cx);
542 js::jit::JitCompartment* jitCompartment() {
543 return jitCompartment_;
547 inline bool
548 JSRuntime::isAtomsZone(JS::Zone* zone)
550 return zone == atomsCompartment_->zone();
553 namespace js {
555 inline js::Handle<js::GlobalObject*>
556 ExclusiveContext::global() const
559 * It's safe to use |unsafeGet()| here because any compartment that is
560 * on-stack will be marked automatically, so there's no need for a read
561 * barrier on it. Once the compartment is popped, the handle is no longer
562 * safe to use.
564 MOZ_ASSERT(compartment_, "Caller needs to enter a compartment first");
565 return Handle<GlobalObject*>::fromMarkedLocation(compartment_->global_.unsafeGet());
568 class AssertCompartmentUnchanged
570 public:
571 explicit AssertCompartmentUnchanged(JSContext* cx
572 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
573 : cx(cx), oldCompartment(cx->compartment())
575 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
578 ~AssertCompartmentUnchanged() {
579 MOZ_ASSERT(cx->compartment() == oldCompartment);
582 protected:
583 JSContext * const cx;
584 JSCompartment * const oldCompartment;
585 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
588 class AutoCompartment
590 ExclusiveContext * const cx_;
591 JSCompartment * const origin_;
593 public:
594 inline AutoCompartment(ExclusiveContext* cx, JSObject* target);
595 inline AutoCompartment(ExclusiveContext* cx, JSCompartment* target);
596 inline ~AutoCompartment();
598 ExclusiveContext* context() const { return cx_; }
599 JSCompartment* origin() const { return origin_; }
601 private:
602 AutoCompartment(const AutoCompartment&) = delete;
603 AutoCompartment & operator=(const AutoCompartment&) = delete;
607 * Use this to change the behavior of an AutoCompartment slightly on error. If
608 * the exception happens to be an Error object, copy it to the origin compartment
609 * instead of wrapping it.
611 class ErrorCopier
613 mozilla::Maybe<AutoCompartment>& ac;
615 public:
616 explicit ErrorCopier(mozilla::Maybe<AutoCompartment>& ac)
617 : ac(ac) {}
618 ~ErrorCopier();
622 * AutoWrapperVector and AutoWrapperRooter can be used to store wrappers that
623 * are obtained from the cross-compartment map. However, these classes should
624 * not be used if the wrapper will escape. For example, it should not be stored
625 * in the heap.
627 * The AutoWrapper rooters are different from other autorooters because their
628 * wrappers are marked on every GC slice rather than just the first one. If
629 * there's some wrapper that we want to use temporarily without causing it to be
630 * marked, we can use these AutoWrapper classes. If we get unlucky and a GC
631 * slice runs during the code using the wrapper, the GC will mark the wrapper so
632 * that it doesn't get swept out from under us. Otherwise, the wrapper needn't
633 * be marked. This is useful in functions like JS_TransplantObject that
634 * manipulate wrappers in compartments that may no longer be alive.
638 * This class stores the data for AutoWrapperVector and AutoWrapperRooter. It
639 * should not be used in any other situations.
641 struct WrapperValue
644 * We use unsafeGet() in the constructors to avoid invoking a read barrier
645 * on the wrapper, which may be dead (see the comment about bug 803376 in
646 * jsgc.cpp regarding this). If there is an incremental GC while the wrapper
647 * is in use, the AutoWrapper rooter will ensure the wrapper gets marked.
649 explicit WrapperValue(const WrapperMap::Ptr& ptr)
650 : value(*ptr->value().unsafeGet())
653 explicit WrapperValue(const WrapperMap::Enum& e)
654 : value(*e.front().value().unsafeGet())
657 Value& get() { return value; }
658 Value get() const { return value; }
659 operator const Value&() const { return value; }
660 JSObject& toObject() const { return value.toObject(); }
662 private:
663 Value value;
666 class AutoWrapperVector : public AutoVectorRooter<WrapperValue>
668 public:
669 explicit AutoWrapperVector(JSContext* cx
670 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
671 : AutoVectorRooter<WrapperValue>(cx, WRAPVECTOR)
673 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
676 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
679 class AutoWrapperRooter : private JS::AutoGCRooter {
680 public:
681 AutoWrapperRooter(JSContext* cx, WrapperValue v
682 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
683 : JS::AutoGCRooter(cx, WRAPPER), value(v)
685 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
688 operator JSObject*() const {
689 return value.get().toObjectOrNull();
692 friend void JS::AutoGCRooter::trace(JSTracer* trc);
694 private:
695 WrapperValue value;
696 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
699 } /* namespace js */
701 #endif /* jscompartment_h */