Line data Source code
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/. */
6 :
7 : #ifndef jscompartmentinlines_h
8 : #define jscompartmentinlines_h
9 :
10 : #include "jscompartment.h"
11 : #include "jsiter.h"
12 :
13 : #include "gc/Barrier.h"
14 :
15 : #include "jscntxtinlines.h"
16 :
17 : inline void
18 311 : JSCompartment::initGlobal(js::GlobalObject& global)
19 : {
20 311 : MOZ_ASSERT(global.compartment() == this);
21 311 : MOZ_ASSERT(!global_);
22 311 : global_.set(&global);
23 311 : }
24 :
25 : js::GlobalObject*
26 15613 : JSCompartment::maybeGlobal() const
27 : {
28 15613 : MOZ_ASSERT_IF(global_, global_->compartment() == this);
29 15613 : return global_;
30 : }
31 :
32 : js::GlobalObject*
33 124745 : JSCompartment::unsafeUnbarrieredMaybeGlobal() const
34 : {
35 124745 : return *global_.unsafeGet();
36 : }
37 :
38 : template <typename T>
39 21012 : js::AutoCompartment::AutoCompartment(JSContext* cx, const T& target)
40 : : cx_(cx),
41 21012 : origin_(cx->compartment()),
42 42024 : maybeLock_(nullptr)
43 : {
44 21012 : cx_->enterCompartmentOf(target);
45 21012 : }
46 :
47 : // Protected constructor that bypasses assertions in enterCompartmentOf. Used
48 : // only for entering the atoms compartment.
49 62625 : js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target,
50 62625 : js::AutoLockForExclusiveAccess& lock)
51 : : cx_(cx),
52 62625 : origin_(cx->compartment()),
53 125250 : maybeLock_(&lock)
54 : {
55 62625 : MOZ_ASSERT(target->isAtomsCompartment());
56 62625 : cx_->enterAtomsCompartment(target, lock);
57 62625 : }
58 :
59 : // Protected constructor that bypasses assertions in enterCompartmentOf. Should
60 : // not be used to enter the atoms compartment.
61 13101 : js::AutoCompartment::AutoCompartment(JSContext* cx, JSCompartment* target)
62 : : cx_(cx),
63 13101 : origin_(cx->compartment()),
64 26202 : maybeLock_(nullptr)
65 : {
66 13101 : MOZ_ASSERT(!target->isAtomsCompartment());
67 13101 : cx_->enterNonAtomsCompartment(target);
68 13101 : }
69 :
70 193483 : js::AutoCompartment::~AutoCompartment()
71 : {
72 96740 : cx_->leaveCompartment(origin_, maybeLock_);
73 96743 : }
74 :
75 62625 : js::AutoAtomsCompartment::AutoAtomsCompartment(JSContext* cx,
76 62625 : js::AutoLockForExclusiveAccess& lock)
77 62625 : : AutoCompartment(cx, cx->atomsCompartment(lock), lock)
78 62625 : {}
79 :
80 13101 : js::AutoCompartmentUnchecked::AutoCompartmentUnchecked(JSContext* cx, JSCompartment* target)
81 13101 : : AutoCompartment(cx, target)
82 13101 : {}
83 :
84 : inline bool
85 40415 : JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp)
86 : {
87 : /* Only GC things have to be wrapped or copied. */
88 40415 : if (!vp.isGCThing())
89 11180 : return true;
90 :
91 : /*
92 : * Symbols are GC things, but never need to be wrapped or copied because
93 : * they are always allocated in the atoms compartment. They still need to
94 : * be marked in the new compartment's zone, however.
95 : */
96 29235 : if (vp.isSymbol()) {
97 0 : cx->markAtomValue(vp);
98 0 : return true;
99 : }
100 :
101 : /* Handle strings. */
102 29235 : if (vp.isString()) {
103 10894 : JS::RootedString str(cx, vp.toString());
104 5447 : if (!wrap(cx, &str))
105 0 : return false;
106 5447 : vp.setString(str);
107 5447 : return true;
108 : }
109 :
110 23788 : MOZ_ASSERT(vp.isObject());
111 :
112 : /*
113 : * All that's left are objects.
114 : *
115 : * Object wrapping isn't the fastest thing in the world, in part because
116 : * we have to unwrap and invoke the prewrap hook to find the identity
117 : * object before we even start checking the cache. Neither of these
118 : * operations are needed in the common case, where we're just wrapping
119 : * a plain JS object from the wrappee's side of the membrane to the
120 : * wrapper's side.
121 : *
122 : * To optimize this, we note that the cache should only ever contain
123 : * identity objects - that is to say, objects that serve as the
124 : * canonical representation for a unique object identity observable by
125 : * script. Unwrap and prewrap are both steps that we take to get to the
126 : * identity of an incoming objects, and as such, they shuld never map
127 : * one identity object to another object. This means that we can safely
128 : * check the cache immediately, and only risk false negatives. Do this
129 : * in opt builds, and do both in debug builds so that we can assert
130 : * that we get the same answer.
131 : */
132 : #ifdef DEBUG
133 23788 : MOZ_ASSERT(JS::ValueIsNotGray(vp));
134 47576 : JS::RootedObject cacheResult(cx);
135 : #endif
136 47576 : JS::RootedValue v(cx, vp);
137 23788 : if (js::WrapperMap::Ptr p = crossCompartmentWrappers.lookup(js::CrossCompartmentKey(v))) {
138 : #ifdef DEBUG
139 5607 : cacheResult = &p->value().get().toObject();
140 : #else
141 : vp.set(p->value().get());
142 : return true;
143 : #endif
144 : }
145 :
146 47576 : JS::RootedObject obj(cx, &vp.toObject());
147 23788 : if (!wrap(cx, &obj))
148 0 : return false;
149 23788 : vp.setObject(*obj);
150 23788 : MOZ_ASSERT_IF(cacheResult, obj == cacheResult);
151 23788 : return true;
152 : }
153 :
154 : MOZ_ALWAYS_INLINE bool
155 888 : JSCompartment::objectMaybeInIteration(JSObject* obj)
156 : {
157 888 : MOZ_ASSERT(obj->compartment() == this);
158 :
159 : // If the list is empty we're not iterating any objects.
160 888 : js::NativeIterator* next = enumerators->next();
161 888 : if (enumerators == next)
162 882 : return false;
163 :
164 : // If the list contains a single object, check if it's |obj|.
165 6 : if (next->next() == enumerators)
166 6 : return next->obj == obj;
167 :
168 0 : return true;
169 : }
170 :
171 : #endif /* jscompartmentinlines_h */
|