|
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 js_RootingAPI_h |
|
8 #define js_RootingAPI_h |
|
9 |
|
10 #include "mozilla/Attributes.h" |
|
11 #include "mozilla/GuardObjects.h" |
|
12 #include "mozilla/LinkedList.h" |
|
13 #include "mozilla/NullPtr.h" |
|
14 #include "mozilla/TypeTraits.h" |
|
15 |
|
16 #include "jspubtd.h" |
|
17 |
|
18 #include "js/TypeDecls.h" |
|
19 #include "js/Utility.h" |
|
20 |
|
21 /* |
|
22 * Moving GC Stack Rooting |
|
23 * |
|
24 * A moving GC may change the physical location of GC allocated things, even |
|
25 * when they are rooted, updating all pointers to the thing to refer to its new |
|
26 * location. The GC must therefore know about all live pointers to a thing, |
|
27 * not just one of them, in order to behave correctly. |
|
28 * |
|
29 * The |Rooted| and |Handle| classes below are used to root stack locations |
|
30 * whose value may be held live across a call that can trigger GC. For a |
|
31 * code fragment such as: |
|
32 * |
|
33 * JSObject *obj = NewObject(cx); |
|
34 * DoSomething(cx); |
|
35 * ... = obj->lastProperty(); |
|
36 * |
|
37 * If |DoSomething()| can trigger a GC, the stack location of |obj| must be |
|
38 * rooted to ensure that the GC does not move the JSObject referred to by |
|
39 * |obj| without updating |obj|'s location itself. This rooting must happen |
|
40 * regardless of whether there are other roots which ensure that the object |
|
41 * itself will not be collected. |
|
42 * |
|
43 * If |DoSomething()| cannot trigger a GC, and the same holds for all other |
|
44 * calls made between |obj|'s definitions and its last uses, then no rooting |
|
45 * is required. |
|
46 * |
|
47 * SpiderMonkey can trigger a GC at almost any time and in ways that are not |
|
48 * always clear. For example, the following innocuous-looking actions can |
|
49 * cause a GC: allocation of any new GC thing; JSObject::hasProperty; |
|
50 * JS_ReportError and friends; and ToNumber, among many others. The following |
|
51 * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_, |
|
52 * rt->malloc_, and friends and JS_ReportOutOfMemory. |
|
53 * |
|
54 * The following family of three classes will exactly root a stack location. |
|
55 * Incorrect usage of these classes will result in a compile error in almost |
|
56 * all cases. Therefore, it is very hard to be incorrectly rooted if you use |
|
57 * these classes exclusively. These classes are all templated on the type T of |
|
58 * the value being rooted. |
|
59 * |
|
60 * - Rooted<T> declares a variable of type T, whose value is always rooted. |
|
61 * Rooted<T> may be automatically coerced to a Handle<T>, below. Rooted<T> |
|
62 * should be used whenever a local variable's value may be held live across a |
|
63 * call which can trigger a GC. |
|
64 * |
|
65 * - Handle<T> is a const reference to a Rooted<T>. Functions which take GC |
|
66 * things or values as arguments and need to root those arguments should |
|
67 * generally use handles for those arguments and avoid any explicit rooting. |
|
68 * This has two benefits. First, when several such functions call each other |
|
69 * then redundant rooting of multiple copies of the GC thing can be avoided. |
|
70 * Second, if the caller does not pass a rooted value a compile error will be |
|
71 * generated, which is quicker and easier to fix than when relying on a |
|
72 * separate rooting analysis. |
|
73 * |
|
74 * - MutableHandle<T> is a non-const reference to Rooted<T>. It is used in the |
|
75 * same way as Handle<T> and includes a |set(const T &v)| method to allow |
|
76 * updating the value of the referenced Rooted<T>. A MutableHandle<T> can be |
|
77 * created from a Rooted<T> by using |Rooted<T>::operator&()|. |
|
78 * |
|
79 * In some cases the small performance overhead of exact rooting (measured to |
|
80 * be a few nanoseconds on desktop) is too much. In these cases, try the |
|
81 * following: |
|
82 * |
|
83 * - Move all Rooted<T> above inner loops: this allows you to re-use the root |
|
84 * on each iteration of the loop. |
|
85 * |
|
86 * - Pass Handle<T> through your hot call stack to avoid re-rooting costs at |
|
87 * every invocation. |
|
88 * |
|
89 * The following diagram explains the list of supported, implicit type |
|
90 * conversions between classes of this family: |
|
91 * |
|
92 * Rooted<T> ----> Handle<T> |
|
93 * | ^ |
|
94 * | | |
|
95 * | | |
|
96 * +---> MutableHandle<T> |
|
97 * (via &) |
|
98 * |
|
99 * All of these types have an implicit conversion to raw pointers. |
|
100 */ |
|
101 |
|
102 namespace js { |
|
103 |
|
104 class ScriptSourceObject; |
|
105 |
|
106 template <typename T> |
|
107 struct GCMethods {}; |
|
108 |
|
109 template <typename T> |
|
110 class RootedBase {}; |
|
111 |
|
112 template <typename T> |
|
113 class HandleBase {}; |
|
114 |
|
115 template <typename T> |
|
116 class MutableHandleBase {}; |
|
117 |
|
118 template <typename T> |
|
119 class HeapBase {}; |
|
120 |
|
121 /* |
|
122 * js::NullPtr acts like a nullptr pointer in contexts that require a Handle. |
|
123 * |
|
124 * Handle provides an implicit constructor for js::NullPtr so that, given: |
|
125 * foo(Handle<JSObject*> h); |
|
126 * callers can simply write: |
|
127 * foo(js::NullPtr()); |
|
128 * which avoids creating a Rooted<JSObject*> just to pass nullptr. |
|
129 * |
|
130 * This is the SpiderMonkey internal variant. js::NullPtr should be used in |
|
131 * preference to JS::NullPtr to avoid the GOT access required for JS_PUBLIC_API |
|
132 * symbols. |
|
133 */ |
|
134 struct NullPtr |
|
135 { |
|
136 static void * const constNullValue; |
|
137 }; |
|
138 |
|
139 namespace gc { |
|
140 struct Cell; |
|
141 template<typename T> |
|
142 struct PersistentRootedMarker; |
|
143 } /* namespace gc */ |
|
144 |
|
145 } /* namespace js */ |
|
146 |
|
147 namespace JS { |
|
148 |
|
149 template <typename T> class Rooted; |
|
150 template <typename T> class PersistentRooted; |
|
151 |
|
152 /* This is exposing internal state of the GC for inlining purposes. */ |
|
153 JS_FRIEND_API(bool) isGCEnabled(); |
|
154 |
|
155 /* |
|
156 * JS::NullPtr acts like a nullptr pointer in contexts that require a Handle. |
|
157 * |
|
158 * Handle provides an implicit constructor for JS::NullPtr so that, given: |
|
159 * foo(Handle<JSObject*> h); |
|
160 * callers can simply write: |
|
161 * foo(JS::NullPtr()); |
|
162 * which avoids creating a Rooted<JSObject*> just to pass nullptr. |
|
163 */ |
|
164 struct JS_PUBLIC_API(NullPtr) |
|
165 { |
|
166 static void * const constNullValue; |
|
167 }; |
|
168 |
|
169 /* |
|
170 * The Heap<T> class is a heap-stored reference to a JS GC thing. All members of |
|
171 * heap classes that refer to GC things should use Heap<T> (or possibly |
|
172 * TenuredHeap<T>, described below). |
|
173 * |
|
174 * Heap<T> is an abstraction that hides some of the complexity required to |
|
175 * maintain GC invariants for the contained reference. It uses operator |
|
176 * overloading to provide a normal pointer interface, but notifies the GC every |
|
177 * time the value it contains is updated. This is necessary for generational GC, |
|
178 * which keeps track of all pointers into the nursery. |
|
179 * |
|
180 * Heap<T> instances must be traced when their containing object is traced to |
|
181 * keep the pointed-to GC thing alive. |
|
182 * |
|
183 * Heap<T> objects should only be used on the heap. GC references stored on the |
|
184 * C/C++ stack must use Rooted/Handle/MutableHandle instead. |
|
185 * |
|
186 * Type T must be one of: JS::Value, jsid, JSObject*, JSString*, JSScript* |
|
187 */ |
|
188 template <typename T> |
|
189 class Heap : public js::HeapBase<T> |
|
190 { |
|
191 public: |
|
192 Heap() { |
|
193 static_assert(sizeof(T) == sizeof(Heap<T>), |
|
194 "Heap<T> must be binary compatible with T."); |
|
195 init(js::GCMethods<T>::initial()); |
|
196 } |
|
197 explicit Heap(T p) { init(p); } |
|
198 |
|
199 /* |
|
200 * For Heap, move semantics are equivalent to copy semantics. In C++, a |
|
201 * copy constructor taking const-ref is the way to get a single function |
|
202 * that will be used for both lvalue and rvalue copies, so we can simply |
|
203 * omit the rvalue variant. |
|
204 */ |
|
205 explicit Heap(const Heap<T> &p) { init(p.ptr); } |
|
206 |
|
207 ~Heap() { |
|
208 if (js::GCMethods<T>::needsPostBarrier(ptr)) |
|
209 relocate(); |
|
210 } |
|
211 |
|
212 bool operator==(const Heap<T> &other) { return ptr == other.ptr; } |
|
213 bool operator!=(const Heap<T> &other) { return ptr != other.ptr; } |
|
214 |
|
215 bool operator==(const T &other) const { return ptr == other; } |
|
216 bool operator!=(const T &other) const { return ptr != other; } |
|
217 |
|
218 operator T() const { return ptr; } |
|
219 T operator->() const { return ptr; } |
|
220 const T *address() const { return &ptr; } |
|
221 const T &get() const { return ptr; } |
|
222 |
|
223 T *unsafeGet() { return &ptr; } |
|
224 |
|
225 Heap<T> &operator=(T p) { |
|
226 set(p); |
|
227 return *this; |
|
228 } |
|
229 |
|
230 Heap<T> &operator=(const Heap<T>& other) { |
|
231 set(other.get()); |
|
232 return *this; |
|
233 } |
|
234 |
|
235 void set(T newPtr) { |
|
236 MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr)); |
|
237 if (js::GCMethods<T>::needsPostBarrier(newPtr)) { |
|
238 ptr = newPtr; |
|
239 post(); |
|
240 } else if (js::GCMethods<T>::needsPostBarrier(ptr)) { |
|
241 relocate(); /* Called before overwriting ptr. */ |
|
242 ptr = newPtr; |
|
243 } else { |
|
244 ptr = newPtr; |
|
245 } |
|
246 } |
|
247 |
|
248 /* |
|
249 * Set the pointer to a value which will cause a crash if it is |
|
250 * dereferenced. |
|
251 */ |
|
252 void setToCrashOnTouch() { |
|
253 ptr = reinterpret_cast<T>(crashOnTouchPointer); |
|
254 } |
|
255 |
|
256 bool isSetToCrashOnTouch() { |
|
257 return ptr == crashOnTouchPointer; |
|
258 } |
|
259 |
|
260 private: |
|
261 void init(T newPtr) { |
|
262 MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr)); |
|
263 ptr = newPtr; |
|
264 if (js::GCMethods<T>::needsPostBarrier(ptr)) |
|
265 post(); |
|
266 } |
|
267 |
|
268 void post() { |
|
269 #ifdef JSGC_GENERATIONAL |
|
270 MOZ_ASSERT(js::GCMethods<T>::needsPostBarrier(ptr)); |
|
271 js::GCMethods<T>::postBarrier(&ptr); |
|
272 #endif |
|
273 } |
|
274 |
|
275 void relocate() { |
|
276 #ifdef JSGC_GENERATIONAL |
|
277 js::GCMethods<T>::relocate(&ptr); |
|
278 #endif |
|
279 } |
|
280 |
|
281 enum { |
|
282 crashOnTouchPointer = 1 |
|
283 }; |
|
284 |
|
285 T ptr; |
|
286 }; |
|
287 |
|
288 #ifdef JS_DEBUG |
|
289 /* |
|
290 * For generational GC, assert that an object is in the tenured generation as |
|
291 * opposed to being in the nursery. |
|
292 */ |
|
293 extern JS_FRIEND_API(void) |
|
294 AssertGCThingMustBeTenured(JSObject* obj); |
|
295 #else |
|
296 inline void |
|
297 AssertGCThingMustBeTenured(JSObject *obj) {} |
|
298 #endif |
|
299 |
|
300 /* |
|
301 * The TenuredHeap<T> class is similar to the Heap<T> class above in that it |
|
302 * encapsulates the GC concerns of an on-heap reference to a JS object. However, |
|
303 * it has two important differences: |
|
304 * |
|
305 * 1) Pointers which are statically known to only reference "tenured" objects |
|
306 * can avoid the extra overhead of SpiderMonkey's write barriers. |
|
307 * |
|
308 * 2) Objects in the "tenured" heap have stronger alignment restrictions than |
|
309 * those in the "nursery", so it is possible to store flags in the lower |
|
310 * bits of pointers known to be tenured. TenuredHeap wraps a normal tagged |
|
311 * pointer with a nice API for accessing the flag bits and adds various |
|
312 * assertions to ensure that it is not mis-used. |
|
313 * |
|
314 * GC things are said to be "tenured" when they are located in the long-lived |
|
315 * heap: e.g. they have gained tenure as an object by surviving past at least |
|
316 * one GC. For performance, SpiderMonkey allocates some things which are known |
|
317 * to normally be long lived directly into the tenured generation; for example, |
|
318 * global objects. Additionally, SpiderMonkey does not visit individual objects |
|
319 * when deleting non-tenured objects, so object with finalizers are also always |
|
320 * tenured; for instance, this includes most DOM objects. |
|
321 * |
|
322 * The considerations to keep in mind when using a TenuredHeap<T> vs a normal |
|
323 * Heap<T> are: |
|
324 * |
|
325 * - It is invalid for a TenuredHeap<T> to refer to a non-tenured thing. |
|
326 * - It is however valid for a Heap<T> to refer to a tenured thing. |
|
327 * - It is not possible to store flag bits in a Heap<T>. |
|
328 */ |
|
329 template <typename T> |
|
330 class TenuredHeap : public js::HeapBase<T> |
|
331 { |
|
332 public: |
|
333 TenuredHeap() : bits(0) { |
|
334 static_assert(sizeof(T) == sizeof(TenuredHeap<T>), |
|
335 "TenuredHeap<T> must be binary compatible with T."); |
|
336 } |
|
337 explicit TenuredHeap(T p) : bits(0) { setPtr(p); } |
|
338 explicit TenuredHeap(const TenuredHeap<T> &p) : bits(0) { setPtr(p.getPtr()); } |
|
339 |
|
340 bool operator==(const TenuredHeap<T> &other) { return bits == other.bits; } |
|
341 bool operator!=(const TenuredHeap<T> &other) { return bits != other.bits; } |
|
342 |
|
343 void setPtr(T newPtr) { |
|
344 MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0); |
|
345 MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr)); |
|
346 if (newPtr) |
|
347 AssertGCThingMustBeTenured(newPtr); |
|
348 bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr); |
|
349 } |
|
350 |
|
351 void setFlags(uintptr_t flagsToSet) { |
|
352 MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); |
|
353 bits |= flagsToSet; |
|
354 } |
|
355 |
|
356 void unsetFlags(uintptr_t flagsToUnset) { |
|
357 MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0); |
|
358 bits &= ~flagsToUnset; |
|
359 } |
|
360 |
|
361 bool hasFlag(uintptr_t flag) const { |
|
362 MOZ_ASSERT((flag & ~flagsMask) == 0); |
|
363 return (bits & flag) != 0; |
|
364 } |
|
365 |
|
366 T getPtr() const { return reinterpret_cast<T>(bits & ~flagsMask); } |
|
367 uintptr_t getFlags() const { return bits & flagsMask; } |
|
368 |
|
369 operator T() const { return getPtr(); } |
|
370 T operator->() const { return getPtr(); } |
|
371 |
|
372 TenuredHeap<T> &operator=(T p) { |
|
373 setPtr(p); |
|
374 return *this; |
|
375 } |
|
376 |
|
377 TenuredHeap<T> &operator=(const TenuredHeap<T>& other) { |
|
378 bits = other.bits; |
|
379 return *this; |
|
380 } |
|
381 |
|
382 private: |
|
383 enum { |
|
384 maskBits = 3, |
|
385 flagsMask = (1 << maskBits) - 1, |
|
386 }; |
|
387 |
|
388 uintptr_t bits; |
|
389 }; |
|
390 |
|
391 /* |
|
392 * Reference to a T that has been rooted elsewhere. This is most useful |
|
393 * as a parameter type, which guarantees that the T lvalue is properly |
|
394 * rooted. See "Move GC Stack Rooting" above. |
|
395 * |
|
396 * If you want to add additional methods to Handle for a specific |
|
397 * specialization, define a HandleBase<T> specialization containing them. |
|
398 */ |
|
399 template <typename T> |
|
400 class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T> |
|
401 { |
|
402 friend class JS::MutableHandle<T>; |
|
403 |
|
404 public: |
|
405 /* Creates a handle from a handle of a type convertible to T. */ |
|
406 template <typename S> |
|
407 Handle(Handle<S> handle, |
|
408 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0) |
|
409 { |
|
410 static_assert(sizeof(Handle<T>) == sizeof(T *), |
|
411 "Handle must be binary compatible with T*."); |
|
412 ptr = reinterpret_cast<const T *>(handle.address()); |
|
413 } |
|
414 |
|
415 /* Create a handle for a nullptr pointer. */ |
|
416 Handle(js::NullPtr) { |
|
417 static_assert(mozilla::IsPointer<T>::value, |
|
418 "js::NullPtr overload not valid for non-pointer types"); |
|
419 ptr = reinterpret_cast<const T *>(&js::NullPtr::constNullValue); |
|
420 } |
|
421 |
|
422 /* Create a handle for a nullptr pointer. */ |
|
423 Handle(JS::NullPtr) { |
|
424 static_assert(mozilla::IsPointer<T>::value, |
|
425 "JS::NullPtr overload not valid for non-pointer types"); |
|
426 ptr = reinterpret_cast<const T *>(&JS::NullPtr::constNullValue); |
|
427 } |
|
428 |
|
429 Handle(MutableHandle<T> handle) { |
|
430 ptr = handle.address(); |
|
431 } |
|
432 |
|
433 /* |
|
434 * Take care when calling this method! |
|
435 * |
|
436 * This creates a Handle from the raw location of a T. |
|
437 * |
|
438 * It should be called only if the following conditions hold: |
|
439 * |
|
440 * 1) the location of the T is guaranteed to be marked (for some reason |
|
441 * other than being a Rooted), e.g., if it is guaranteed to be reachable |
|
442 * from an implicit root. |
|
443 * |
|
444 * 2) the contents of the location are immutable, or at least cannot change |
|
445 * for the lifetime of the handle, as its users may not expect its value |
|
446 * to change underneath them. |
|
447 */ |
|
448 static MOZ_CONSTEXPR Handle fromMarkedLocation(const T *p) { |
|
449 return Handle(p, DeliberatelyChoosingThisOverload, |
|
450 ImUsingThisOnlyInFromFromMarkedLocation); |
|
451 } |
|
452 |
|
453 /* |
|
454 * Construct a handle from an explicitly rooted location. This is the |
|
455 * normal way to create a handle, and normally happens implicitly. |
|
456 */ |
|
457 template <typename S> |
|
458 inline |
|
459 Handle(const Rooted<S> &root, |
|
460 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0); |
|
461 |
|
462 template <typename S> |
|
463 inline |
|
464 Handle(const PersistentRooted<S> &root, |
|
465 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0); |
|
466 |
|
467 /* Construct a read only handle from a mutable handle. */ |
|
468 template <typename S> |
|
469 inline |
|
470 Handle(MutableHandle<S> &root, |
|
471 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0); |
|
472 |
|
473 const T *address() const { return ptr; } |
|
474 const T& get() const { return *ptr; } |
|
475 |
|
476 /* |
|
477 * Return a reference so passing a Handle<T> to something that |
|
478 * takes a |const T&| is not a GC hazard. |
|
479 */ |
|
480 operator const T&() const { return get(); } |
|
481 T operator->() const { return get(); } |
|
482 |
|
483 bool operator!=(const T &other) const { return *ptr != other; } |
|
484 bool operator==(const T &other) const { return *ptr == other; } |
|
485 |
|
486 /* Change this handle to point to the same rooted location RHS does. */ |
|
487 void repoint(const Handle &rhs) { ptr = rhs.address(); } |
|
488 |
|
489 private: |
|
490 Handle() {} |
|
491 |
|
492 enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; |
|
493 enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; |
|
494 MOZ_CONSTEXPR Handle(const T *p, Disambiguator, CallerIdentity) : ptr(p) {} |
|
495 |
|
496 const T *ptr; |
|
497 |
|
498 template <typename S> void operator=(S) MOZ_DELETE; |
|
499 void operator=(Handle) MOZ_DELETE; |
|
500 }; |
|
501 |
|
502 /* |
|
503 * Similar to a handle, but the underlying storage can be changed. This is |
|
504 * useful for outparams. |
|
505 * |
|
506 * If you want to add additional methods to MutableHandle for a specific |
|
507 * specialization, define a MutableHandleBase<T> specialization containing |
|
508 * them. |
|
509 */ |
|
510 template <typename T> |
|
511 class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T> |
|
512 { |
|
513 public: |
|
514 inline MutableHandle(Rooted<T> *root); |
|
515 inline MutableHandle(PersistentRooted<T> *root); |
|
516 |
|
517 private: |
|
518 // Disallow true nullptr and emulated nullptr (gcc 4.4/4.5, __null, appears |
|
519 // as int/long [32/64-bit]) for overloading purposes. |
|
520 template<typename N> |
|
521 MutableHandle(N, |
|
522 typename mozilla::EnableIf<mozilla::IsNullPointer<N>::value || |
|
523 mozilla::IsSame<N, int>::value || |
|
524 mozilla::IsSame<N, long>::value, |
|
525 int>::Type dummy = 0) |
|
526 MOZ_DELETE; |
|
527 |
|
528 public: |
|
529 void set(T v) { |
|
530 MOZ_ASSERT(!js::GCMethods<T>::poisoned(v)); |
|
531 *ptr = v; |
|
532 } |
|
533 |
|
534 /* |
|
535 * This may be called only if the location of the T is guaranteed |
|
536 * to be marked (for some reason other than being a Rooted), |
|
537 * e.g., if it is guaranteed to be reachable from an implicit root. |
|
538 * |
|
539 * Create a MutableHandle from a raw location of a T. |
|
540 */ |
|
541 static MutableHandle fromMarkedLocation(T *p) { |
|
542 MutableHandle h; |
|
543 h.ptr = p; |
|
544 return h; |
|
545 } |
|
546 |
|
547 T *address() const { return ptr; } |
|
548 const T& get() const { return *ptr; } |
|
549 |
|
550 /* |
|
551 * Return a reference so passing a MutableHandle<T> to something that takes |
|
552 * a |const T&| is not a GC hazard. |
|
553 */ |
|
554 operator const T&() const { return get(); } |
|
555 T operator->() const { return get(); } |
|
556 |
|
557 private: |
|
558 MutableHandle() {} |
|
559 |
|
560 T *ptr; |
|
561 |
|
562 template <typename S> void operator=(S v) MOZ_DELETE; |
|
563 void operator=(MutableHandle other) MOZ_DELETE; |
|
564 }; |
|
565 |
|
566 #ifdef JSGC_GENERATIONAL |
|
567 JS_FRIEND_API(void) HeapCellPostBarrier(js::gc::Cell **cellp); |
|
568 JS_FRIEND_API(void) HeapCellRelocate(js::gc::Cell **cellp); |
|
569 #endif |
|
570 |
|
571 } /* namespace JS */ |
|
572 |
|
573 namespace js { |
|
574 |
|
575 /* |
|
576 * InternalHandle is a handle to an internal pointer into a gcthing. Use |
|
577 * InternalHandle when you have a pointer to a direct field of a gcthing, or |
|
578 * when you need a parameter type for something that *may* be a pointer to a |
|
579 * direct field of a gcthing. |
|
580 */ |
|
581 template <typename T> |
|
582 class InternalHandle {}; |
|
583 |
|
584 template <typename T> |
|
585 class InternalHandle<T*> |
|
586 { |
|
587 void * const *holder; |
|
588 size_t offset; |
|
589 |
|
590 public: |
|
591 /* |
|
592 * Create an InternalHandle using a Handle to the gcthing containing the |
|
593 * field in question, and a pointer to the field. |
|
594 */ |
|
595 template<typename H> |
|
596 InternalHandle(const JS::Handle<H> &handle, T *field) |
|
597 : holder((void**)handle.address()), offset(uintptr_t(field) - uintptr_t(handle.get())) |
|
598 {} |
|
599 |
|
600 /* |
|
601 * Create an InternalHandle to a field within a Rooted<>. |
|
602 */ |
|
603 template<typename R> |
|
604 InternalHandle(const JS::Rooted<R> &root, T *field) |
|
605 : holder((void**)root.address()), offset(uintptr_t(field) - uintptr_t(root.get())) |
|
606 {} |
|
607 |
|
608 InternalHandle(const InternalHandle<T*>& other) |
|
609 : holder(other.holder), offset(other.offset) {} |
|
610 |
|
611 T *get() const { return reinterpret_cast<T*>(uintptr_t(*holder) + offset); } |
|
612 |
|
613 const T &operator*() const { return *get(); } |
|
614 T *operator->() const { return get(); } |
|
615 |
|
616 static InternalHandle<T*> fromMarkedLocation(T *fieldPtr) { |
|
617 return InternalHandle(fieldPtr); |
|
618 } |
|
619 |
|
620 private: |
|
621 /* |
|
622 * Create an InternalHandle to something that is not a pointer to a |
|
623 * gcthing, and so does not need to be rooted in the first place. Use these |
|
624 * InternalHandles to pass pointers into functions that also need to accept |
|
625 * regular InternalHandles to gcthing fields. |
|
626 * |
|
627 * Make this private to prevent accidental misuse; this is only for |
|
628 * fromMarkedLocation(). |
|
629 */ |
|
630 InternalHandle(T *field) |
|
631 : holder(reinterpret_cast<void * const *>(&js::NullPtr::constNullValue)), |
|
632 offset(uintptr_t(field)) |
|
633 {} |
|
634 |
|
635 void operator=(InternalHandle<T*> other) MOZ_DELETE; |
|
636 }; |
|
637 |
|
638 /* |
|
639 * By default, pointers should use the inheritance hierarchy to find their |
|
640 * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that |
|
641 * Rooted<T> may be used without the class definition being available. |
|
642 */ |
|
643 template <typename T> |
|
644 struct RootKind<T *> |
|
645 { |
|
646 static ThingRootKind rootKind() { return T::rootKind(); } |
|
647 }; |
|
648 |
|
649 template <typename T> |
|
650 struct GCMethods<T *> |
|
651 { |
|
652 static T *initial() { return nullptr; } |
|
653 static ThingRootKind kind() { return RootKind<T *>::rootKind(); } |
|
654 static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); } |
|
655 static bool needsPostBarrier(T *v) { return false; } |
|
656 #ifdef JSGC_GENERATIONAL |
|
657 static void postBarrier(T **vp) {} |
|
658 static void relocate(T **vp) {} |
|
659 #endif |
|
660 }; |
|
661 |
|
662 template <> |
|
663 struct GCMethods<JSObject *> |
|
664 { |
|
665 static JSObject *initial() { return nullptr; } |
|
666 static ThingRootKind kind() { return RootKind<JSObject *>::rootKind(); } |
|
667 static bool poisoned(JSObject *v) { return JS::IsPoisonedPtr(v); } |
|
668 static bool needsPostBarrier(JSObject *v) { return v; } |
|
669 #ifdef JSGC_GENERATIONAL |
|
670 static void postBarrier(JSObject **vp) { |
|
671 JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp)); |
|
672 } |
|
673 static void relocate(JSObject **vp) { |
|
674 JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell **>(vp)); |
|
675 } |
|
676 #endif |
|
677 }; |
|
678 |
|
679 template <> |
|
680 struct GCMethods<JSFunction *> |
|
681 { |
|
682 static JSFunction *initial() { return nullptr; } |
|
683 static ThingRootKind kind() { return RootKind<JSObject *>::rootKind(); } |
|
684 static bool poisoned(JSFunction *v) { return JS::IsPoisonedPtr(v); } |
|
685 static bool needsPostBarrier(JSFunction *v) { return v; } |
|
686 #ifdef JSGC_GENERATIONAL |
|
687 static void postBarrier(JSFunction **vp) { |
|
688 JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp)); |
|
689 } |
|
690 static void relocate(JSFunction **vp) { |
|
691 JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell **>(vp)); |
|
692 } |
|
693 #endif |
|
694 }; |
|
695 |
|
696 #ifdef JS_DEBUG |
|
697 /* This helper allows us to assert that Rooted<T> is scoped within a request. */ |
|
698 extern JS_PUBLIC_API(bool) |
|
699 IsInRequest(JSContext *cx); |
|
700 #endif |
|
701 |
|
702 } /* namespace js */ |
|
703 |
|
704 namespace JS { |
|
705 |
|
706 /* |
|
707 * Local variable of type T whose value is always rooted. This is typically |
|
708 * used for local variables, or for non-rooted values being passed to a |
|
709 * function that requires a handle, e.g. Foo(Root<T>(cx, x)). |
|
710 * |
|
711 * If you want to add additional methods to Rooted for a specific |
|
712 * specialization, define a RootedBase<T> specialization containing them. |
|
713 */ |
|
714 template <typename T> |
|
715 class MOZ_STACK_CLASS Rooted : public js::RootedBase<T> |
|
716 { |
|
717 /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */ |
|
718 template <typename CX> |
|
719 void init(CX *cx) { |
|
720 #ifdef JSGC_TRACK_EXACT_ROOTS |
|
721 js::ThingRootKind kind = js::GCMethods<T>::kind(); |
|
722 this->stack = &cx->thingGCRooters[kind]; |
|
723 this->prev = *stack; |
|
724 *stack = reinterpret_cast<Rooted<void*>*>(this); |
|
725 |
|
726 MOZ_ASSERT(!js::GCMethods<T>::poisoned(ptr)); |
|
727 #endif |
|
728 } |
|
729 |
|
730 public: |
|
731 Rooted(JSContext *cx |
|
732 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
733 : ptr(js::GCMethods<T>::initial()) |
|
734 { |
|
735 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
736 #ifdef JS_DEBUG |
|
737 MOZ_ASSERT(js::IsInRequest(cx)); |
|
738 #endif |
|
739 init(js::ContextFriendFields::get(cx)); |
|
740 } |
|
741 |
|
742 Rooted(JSContext *cx, T initial |
|
743 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
744 : ptr(initial) |
|
745 { |
|
746 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
747 #ifdef JS_DEBUG |
|
748 MOZ_ASSERT(js::IsInRequest(cx)); |
|
749 #endif |
|
750 init(js::ContextFriendFields::get(cx)); |
|
751 } |
|
752 |
|
753 Rooted(js::ContextFriendFields *cx |
|
754 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
755 : ptr(js::GCMethods<T>::initial()) |
|
756 { |
|
757 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
758 init(cx); |
|
759 } |
|
760 |
|
761 Rooted(js::ContextFriendFields *cx, T initial |
|
762 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
763 : ptr(initial) |
|
764 { |
|
765 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
766 init(cx); |
|
767 } |
|
768 |
|
769 Rooted(js::PerThreadDataFriendFields *pt |
|
770 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
771 : ptr(js::GCMethods<T>::initial()) |
|
772 { |
|
773 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
774 init(pt); |
|
775 } |
|
776 |
|
777 Rooted(js::PerThreadDataFriendFields *pt, T initial |
|
778 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
779 : ptr(initial) |
|
780 { |
|
781 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
782 init(pt); |
|
783 } |
|
784 |
|
785 Rooted(JSRuntime *rt |
|
786 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
787 : ptr(js::GCMethods<T>::initial()) |
|
788 { |
|
789 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
790 init(js::PerThreadDataFriendFields::getMainThread(rt)); |
|
791 } |
|
792 |
|
793 Rooted(JSRuntime *rt, T initial |
|
794 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
795 : ptr(initial) |
|
796 { |
|
797 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
798 init(js::PerThreadDataFriendFields::getMainThread(rt)); |
|
799 } |
|
800 |
|
801 // Note that we need to let the compiler generate the default destructor in |
|
802 // non-exact-rooting builds because of a bug in the instrumented PGO builds |
|
803 // using MSVC, see bug 915735 for more details. |
|
804 #ifdef JSGC_TRACK_EXACT_ROOTS |
|
805 ~Rooted() { |
|
806 MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this)); |
|
807 *stack = prev; |
|
808 } |
|
809 #endif |
|
810 |
|
811 #ifdef JSGC_TRACK_EXACT_ROOTS |
|
812 Rooted<T> *previous() { return prev; } |
|
813 #endif |
|
814 |
|
815 /* |
|
816 * Important: Return a reference here so passing a Rooted<T> to |
|
817 * something that takes a |const T&| is not a GC hazard. |
|
818 */ |
|
819 operator const T&() const { return ptr; } |
|
820 T operator->() const { return ptr; } |
|
821 T *address() { return &ptr; } |
|
822 const T *address() const { return &ptr; } |
|
823 T &get() { return ptr; } |
|
824 const T &get() const { return ptr; } |
|
825 |
|
826 T &operator=(T value) { |
|
827 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value)); |
|
828 ptr = value; |
|
829 return ptr; |
|
830 } |
|
831 |
|
832 T &operator=(const Rooted &value) { |
|
833 ptr = value; |
|
834 return ptr; |
|
835 } |
|
836 |
|
837 void set(T value) { |
|
838 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value)); |
|
839 ptr = value; |
|
840 } |
|
841 |
|
842 bool operator!=(const T &other) const { return ptr != other; } |
|
843 bool operator==(const T &other) const { return ptr == other; } |
|
844 |
|
845 private: |
|
846 #ifdef JSGC_TRACK_EXACT_ROOTS |
|
847 Rooted<void*> **stack, *prev; |
|
848 #endif |
|
849 |
|
850 /* |
|
851 * |ptr| must be the last field in Rooted because the analysis treats all |
|
852 * Rooted as Rooted<void*> during the analysis. See bug 829372. |
|
853 */ |
|
854 T ptr; |
|
855 |
|
856 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
857 |
|
858 Rooted(const Rooted &) MOZ_DELETE; |
|
859 }; |
|
860 |
|
861 } /* namespace JS */ |
|
862 |
|
863 namespace js { |
|
864 |
|
865 /* |
|
866 * Augment the generic Rooted<T> interface when T = JSObject* with |
|
867 * class-querying and downcasting operations. |
|
868 * |
|
869 * Given a Rooted<JSObject*> obj, one can view |
|
870 * Handle<StringObject*> h = obj.as<StringObject*>(); |
|
871 * as an optimization of |
|
872 * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>()); |
|
873 * Handle<StringObject*> h = rooted; |
|
874 */ |
|
875 template <> |
|
876 class RootedBase<JSObject*> |
|
877 { |
|
878 public: |
|
879 template <class U> |
|
880 JS::Handle<U*> as() const; |
|
881 }; |
|
882 |
|
883 |
|
884 /* |
|
885 * RootedGeneric<T> allows a class to instantiate its own Rooted type by |
|
886 * including the following two methods: |
|
887 * |
|
888 * static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; } |
|
889 * void trace(JSTracer *trc); |
|
890 * |
|
891 * The trace() method must trace all of the class's fields. |
|
892 * |
|
893 * Implementation: |
|
894 * |
|
895 * RootedGeneric<T> works by placing a pointer to its 'rooter' field into the |
|
896 * usual list of rooters when it is instantiated. When marking, it backs up |
|
897 * from this pointer to find a vtable containing a type-appropriate trace() |
|
898 * method. |
|
899 */ |
|
900 template <typename GCType> |
|
901 class JS_PUBLIC_API(RootedGeneric) |
|
902 { |
|
903 public: |
|
904 JS::Rooted<GCType> rooter; |
|
905 |
|
906 RootedGeneric(js::ContextFriendFields *cx) |
|
907 : rooter(cx) |
|
908 { |
|
909 } |
|
910 |
|
911 RootedGeneric(js::ContextFriendFields *cx, const GCType &initial) |
|
912 : rooter(cx, initial) |
|
913 { |
|
914 } |
|
915 |
|
916 virtual inline void trace(JSTracer *trc); |
|
917 |
|
918 operator const GCType&() const { return rooter.get(); } |
|
919 GCType operator->() const { return rooter.get(); } |
|
920 }; |
|
921 |
|
922 template <typename GCType> |
|
923 inline void RootedGeneric<GCType>::trace(JSTracer *trc) |
|
924 { |
|
925 rooter->trace(trc); |
|
926 } |
|
927 |
|
928 // We will instantiate RootedGeneric<void*> in RootMarking.cpp, and MSVC will |
|
929 // notice that void*s have no trace() method defined on them and complain (even |
|
930 // though it's never called.) MSVC's complaint is not unreasonable, so |
|
931 // specialize for void*. |
|
932 template <> |
|
933 inline void RootedGeneric<void*>::trace(JSTracer *trc) |
|
934 { |
|
935 MOZ_ASSUME_UNREACHABLE("RootedGeneric<void*>::trace()"); |
|
936 } |
|
937 |
|
938 /* Interface substitute for Rooted<T> which does not root the variable's memory. */ |
|
939 template <typename T> |
|
940 class FakeRooted : public RootedBase<T> |
|
941 { |
|
942 public: |
|
943 template <typename CX> |
|
944 FakeRooted(CX *cx |
|
945 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
946 : ptr(GCMethods<T>::initial()) |
|
947 { |
|
948 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
949 } |
|
950 |
|
951 template <typename CX> |
|
952 FakeRooted(CX *cx, T initial |
|
953 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
954 : ptr(initial) |
|
955 { |
|
956 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
957 } |
|
958 |
|
959 operator T() const { return ptr; } |
|
960 T operator->() const { return ptr; } |
|
961 T *address() { return &ptr; } |
|
962 const T *address() const { return &ptr; } |
|
963 T &get() { return ptr; } |
|
964 const T &get() const { return ptr; } |
|
965 |
|
966 FakeRooted<T> &operator=(T value) { |
|
967 MOZ_ASSERT(!GCMethods<T>::poisoned(value)); |
|
968 ptr = value; |
|
969 return *this; |
|
970 } |
|
971 |
|
972 FakeRooted<T> &operator=(const FakeRooted<T> &other) { |
|
973 MOZ_ASSERT(!GCMethods<T>::poisoned(other.ptr)); |
|
974 ptr = other.ptr; |
|
975 return *this; |
|
976 } |
|
977 |
|
978 bool operator!=(const T &other) const { return ptr != other; } |
|
979 bool operator==(const T &other) const { return ptr == other; } |
|
980 |
|
981 private: |
|
982 T ptr; |
|
983 |
|
984 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
985 |
|
986 FakeRooted(const FakeRooted &) MOZ_DELETE; |
|
987 }; |
|
988 |
|
989 /* Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */ |
|
990 template <typename T> |
|
991 class FakeMutableHandle : public js::MutableHandleBase<T> |
|
992 { |
|
993 public: |
|
994 FakeMutableHandle(T *t) { |
|
995 ptr = t; |
|
996 } |
|
997 |
|
998 FakeMutableHandle(FakeRooted<T> *root) { |
|
999 ptr = root->address(); |
|
1000 } |
|
1001 |
|
1002 void set(T v) { |
|
1003 MOZ_ASSERT(!js::GCMethods<T>::poisoned(v)); |
|
1004 *ptr = v; |
|
1005 } |
|
1006 |
|
1007 T *address() const { return ptr; } |
|
1008 T get() const { return *ptr; } |
|
1009 |
|
1010 operator T() const { return get(); } |
|
1011 T operator->() const { return get(); } |
|
1012 |
|
1013 private: |
|
1014 FakeMutableHandle() {} |
|
1015 |
|
1016 T *ptr; |
|
1017 |
|
1018 template <typename S> |
|
1019 void operator=(S v) MOZ_DELETE; |
|
1020 |
|
1021 void operator=(const FakeMutableHandle<T>& other) MOZ_DELETE; |
|
1022 }; |
|
1023 |
|
1024 /* |
|
1025 * Types for a variable that either should or shouldn't be rooted, depending on |
|
1026 * the template parameter allowGC. Used for implementing functions that can |
|
1027 * operate on either rooted or unrooted data. |
|
1028 * |
|
1029 * The toHandle() and toMutableHandle() functions are for calling functions |
|
1030 * which require handle types and are only called in the CanGC case. These |
|
1031 * allow the calling code to type check. |
|
1032 */ |
|
1033 enum AllowGC { |
|
1034 NoGC = 0, |
|
1035 CanGC = 1 |
|
1036 }; |
|
1037 template <typename T, AllowGC allowGC> |
|
1038 class MaybeRooted |
|
1039 { |
|
1040 }; |
|
1041 |
|
1042 template <typename T> class MaybeRooted<T, CanGC> |
|
1043 { |
|
1044 public: |
|
1045 typedef JS::Handle<T> HandleType; |
|
1046 typedef JS::Rooted<T> RootType; |
|
1047 typedef JS::MutableHandle<T> MutableHandleType; |
|
1048 |
|
1049 static inline JS::Handle<T> toHandle(HandleType v) { |
|
1050 return v; |
|
1051 } |
|
1052 |
|
1053 static inline JS::MutableHandle<T> toMutableHandle(MutableHandleType v) { |
|
1054 return v; |
|
1055 } |
|
1056 }; |
|
1057 |
|
1058 template <typename T> class MaybeRooted<T, NoGC> |
|
1059 { |
|
1060 public: |
|
1061 typedef T HandleType; |
|
1062 typedef FakeRooted<T> RootType; |
|
1063 typedef FakeMutableHandle<T> MutableHandleType; |
|
1064 |
|
1065 static inline JS::Handle<T> toHandle(HandleType v) { |
|
1066 MOZ_ASSUME_UNREACHABLE("Bad conversion"); |
|
1067 } |
|
1068 |
|
1069 static inline JS::MutableHandle<T> toMutableHandle(MutableHandleType v) { |
|
1070 MOZ_ASSUME_UNREACHABLE("Bad conversion"); |
|
1071 } |
|
1072 }; |
|
1073 |
|
1074 } /* namespace js */ |
|
1075 |
|
1076 namespace JS { |
|
1077 |
|
1078 template <typename T> template <typename S> |
|
1079 inline |
|
1080 Handle<T>::Handle(const Rooted<S> &root, |
|
1081 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy) |
|
1082 { |
|
1083 ptr = reinterpret_cast<const T *>(root.address()); |
|
1084 } |
|
1085 |
|
1086 template <typename T> template <typename S> |
|
1087 inline |
|
1088 Handle<T>::Handle(const PersistentRooted<S> &root, |
|
1089 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy) |
|
1090 { |
|
1091 ptr = reinterpret_cast<const T *>(root.address()); |
|
1092 } |
|
1093 |
|
1094 template <typename T> template <typename S> |
|
1095 inline |
|
1096 Handle<T>::Handle(MutableHandle<S> &root, |
|
1097 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy) |
|
1098 { |
|
1099 ptr = reinterpret_cast<const T *>(root.address()); |
|
1100 } |
|
1101 |
|
1102 template <typename T> |
|
1103 inline |
|
1104 MutableHandle<T>::MutableHandle(Rooted<T> *root) |
|
1105 { |
|
1106 static_assert(sizeof(MutableHandle<T>) == sizeof(T *), |
|
1107 "MutableHandle must be binary compatible with T*."); |
|
1108 ptr = root->address(); |
|
1109 } |
|
1110 |
|
1111 template <typename T> |
|
1112 inline |
|
1113 MutableHandle<T>::MutableHandle(PersistentRooted<T> *root) |
|
1114 { |
|
1115 static_assert(sizeof(MutableHandle<T>) == sizeof(T *), |
|
1116 "MutableHandle must be binary compatible with T*."); |
|
1117 ptr = root->address(); |
|
1118 } |
|
1119 |
|
1120 /* |
|
1121 * A copyable, assignable global GC root type with arbitrary lifetime, an |
|
1122 * infallible constructor, and automatic unrooting on destruction. |
|
1123 * |
|
1124 * These roots can be used in heap-allocated data structures, so they are not |
|
1125 * associated with any particular JSContext or stack. They are registered with |
|
1126 * the JSRuntime itself, without locking, so they require a full JSContext to be |
|
1127 * constructed, not one of its more restricted superclasses. |
|
1128 * |
|
1129 * Note that you must not use an PersistentRooted in an object owned by a JS |
|
1130 * object: |
|
1131 * |
|
1132 * Whenever one object whose lifetime is decided by the GC refers to another |
|
1133 * such object, that edge must be traced only if the owning JS object is traced. |
|
1134 * This applies not only to JS objects (which obviously are managed by the GC) |
|
1135 * but also to C++ objects owned by JS objects. |
|
1136 * |
|
1137 * If you put a PersistentRooted in such a C++ object, that is almost certainly |
|
1138 * a leak. When a GC begins, the referent of the PersistentRooted is treated as |
|
1139 * live, unconditionally (because a PersistentRooted is a *root*), even if the |
|
1140 * JS object that owns it is unreachable. If there is any path from that |
|
1141 * referent back to the JS object, then the C++ object containing the |
|
1142 * PersistentRooted will not be destructed, and the whole blob of objects will |
|
1143 * not be freed, even if there are no references to them from the outside. |
|
1144 * |
|
1145 * In the context of Firefox, this is a severe restriction: almost everything in |
|
1146 * Firefox is owned by some JS object or another, so using PersistentRooted in |
|
1147 * such objects would introduce leaks. For these kinds of edges, Heap<T> or |
|
1148 * TenuredHeap<T> would be better types. It's up to the implementor of the type |
|
1149 * containing Heap<T> or TenuredHeap<T> members to make sure their referents get |
|
1150 * marked when the object itself is marked. |
|
1151 */ |
|
1152 template<typename T> |
|
1153 class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T> > { |
|
1154 friend class mozilla::LinkedList<PersistentRooted>; |
|
1155 friend class mozilla::LinkedListElement<PersistentRooted>; |
|
1156 |
|
1157 friend class js::gc::PersistentRootedMarker<T>; |
|
1158 |
|
1159 void registerWithRuntime(JSRuntime *rt) { |
|
1160 JS::shadow::Runtime *srt = JS::shadow::Runtime::asShadowRuntime(rt); |
|
1161 srt->getPersistentRootedList<T>().insertBack(this); |
|
1162 } |
|
1163 |
|
1164 public: |
|
1165 PersistentRooted(JSContext *cx) : ptr(js::GCMethods<T>::initial()) |
|
1166 { |
|
1167 registerWithRuntime(js::GetRuntime(cx)); |
|
1168 } |
|
1169 |
|
1170 PersistentRooted(JSContext *cx, T initial) : ptr(initial) |
|
1171 { |
|
1172 registerWithRuntime(js::GetRuntime(cx)); |
|
1173 } |
|
1174 |
|
1175 PersistentRooted(JSRuntime *rt) : ptr(js::GCMethods<T>::initial()) |
|
1176 { |
|
1177 registerWithRuntime(rt); |
|
1178 } |
|
1179 |
|
1180 PersistentRooted(JSRuntime *rt, T initial) : ptr(initial) |
|
1181 { |
|
1182 registerWithRuntime(rt); |
|
1183 } |
|
1184 |
|
1185 PersistentRooted(PersistentRooted &rhs) : ptr(rhs.ptr) |
|
1186 { |
|
1187 /* |
|
1188 * Copy construction takes advantage of the fact that the original |
|
1189 * is already inserted, and simply adds itself to whatever list the |
|
1190 * original was on - no JSRuntime pointer needed. |
|
1191 */ |
|
1192 rhs.setNext(this); |
|
1193 } |
|
1194 |
|
1195 /* |
|
1196 * Important: Return a reference here so passing a Rooted<T> to |
|
1197 * something that takes a |const T&| is not a GC hazard. |
|
1198 */ |
|
1199 operator const T&() const { return ptr; } |
|
1200 T operator->() const { return ptr; } |
|
1201 T *address() { return &ptr; } |
|
1202 const T *address() const { return &ptr; } |
|
1203 T &get() { return ptr; } |
|
1204 const T &get() const { return ptr; } |
|
1205 |
|
1206 T &operator=(T value) { |
|
1207 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value)); |
|
1208 ptr = value; |
|
1209 return ptr; |
|
1210 } |
|
1211 |
|
1212 T &operator=(const PersistentRooted &value) { |
|
1213 ptr = value; |
|
1214 return ptr; |
|
1215 } |
|
1216 |
|
1217 void set(T value) { |
|
1218 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value)); |
|
1219 ptr = value; |
|
1220 } |
|
1221 |
|
1222 bool operator!=(const T &other) const { return ptr != other; } |
|
1223 bool operator==(const T &other) const { return ptr == other; } |
|
1224 |
|
1225 private: |
|
1226 T ptr; |
|
1227 }; |
|
1228 |
|
1229 } /* namespace JS */ |
|
1230 |
|
1231 namespace js { |
|
1232 |
|
1233 /* Base class for automatic read-only object rooting during compilation. */ |
|
1234 class CompilerRootNode |
|
1235 { |
|
1236 protected: |
|
1237 CompilerRootNode(js::gc::Cell *ptr) : next(nullptr), ptr_(ptr) {} |
|
1238 |
|
1239 public: |
|
1240 void **address() { return (void **)&ptr_; } |
|
1241 |
|
1242 public: |
|
1243 CompilerRootNode *next; |
|
1244 |
|
1245 protected: |
|
1246 js::gc::Cell *ptr_; |
|
1247 }; |
|
1248 |
|
1249 } /* namespace js */ |
|
1250 |
|
1251 #endif /* js_RootingAPI_h */ |