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"
14 #include "vm/GlobalObject.h"
16 #include "vm/SavedStacks.h"
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.
40 JSFlatString
*s
; // if s==nullptr, d and base are not valid
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
) {
57 /* If HashNumber grows, need to change WrapperHasher. */
58 JS_STATIC_ASSERT(sizeof(HashNumber
) == 4);
60 struct CrossCompartmentKey
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
),
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
),
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
);
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
;
130 struct TypeInferenceSizes
;
134 class AutoDebugModeInvalidation
;
141 JS::CompartmentOptions options_
;
148 JSPrincipals
*principals
;
153 // A null add-on ID means that the compartment is not associated with an
158 bool firedOnNewGlobalObject
;
161 void mark() { marked
= true; }
164 friend struct JSRuntime
;
165 friend struct JSContext
;
166 friend class js::ExclusiveContext
;
167 js::ReadBarrieredGlobalObject global_
;
169 unsigned enterCompartmentDepth
;
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_
));
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 {
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
);
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
);
220 /* Type information about the scripts and objects in this compartment. */
221 js::types::TypeCompartment types
;
226 js::ObjectMetadataCallback objectMetadataCallback
;
228 js::SavedStacks savedStacks_
;
230 js::WrapperMap crossCompartmentWrappers
;
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
;
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();
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. */
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
;
318 DebugFromJS
= 1 << 1,
319 DebugNeedDelazification
= 1 << 2
322 static const unsigned DebugModeFromMask
= DebugFromC
| DebugFromJS
;
324 unsigned debugModeBits
; // see debugMode() below
327 JSCompartment(JS::Zone
*zone
, const JS::CompartmentOptions
&options
);
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
]))
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();
377 #ifdef JSGC_COMPACTING
378 void fixupInitialShapeTable();
379 void fixupNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet
&table
);
380 void fixupCrossCompartmentWrappers(JSTracer
*trc
);
381 void fixupAfterMovingGC();
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. */
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
;
411 JSCompartment
*thisForCtor() { return this; }
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
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
444 bool ensureDelazifyScriptsForDebugMode(JSContext
*cx
);
448 /* This is called only when debugMode() has just toggled. */
449 bool updateJITForDebugMode(JSContext
*maybecx
, js::AutoDebugModeInvalidation
&invalidate
);
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
);
472 void sweepBreakpoints(js::FreeOp
*fop
);
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
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
;
499 js::jit::JitCompartment
*jitCompartment_
;
502 bool ensureJitCompartmentExists(JSContext
*cx
);
503 js::jit::JitCompartment
*jitCompartment() {
504 return jitCompartment_
;
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
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_
;
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
) {
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
;
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
579 MOZ_ASSERT(compartment_
, "Caller needs to enter a compartment first");
580 return Handle
<GlobalObject
*>::fromMarkedLocation(compartment_
->global_
.unsafeGet());
583 class AssertCompartmentUnchanged
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
);
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_
;
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_
; }
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.
628 mozilla::Maybe
<AutoCompartment
> &ac
;
631 explicit ErrorCopier(mozilla::Maybe
<AutoCompartment
> &ac
)
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
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.
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(); }
681 class AutoWrapperVector
: public AutoVectorRooter
<WrapperValue
>
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
{
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
);
711 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
716 #endif /* jscompartment_h */