Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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> ∾
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 */