This article covers features introduced in SpiderMonkey 31
A copyable, assignable global GC root type with arbitrary lifetime, an infallible constructor, and automatic unrooting on destruction.
Syntax
JS::PersistentRooted<T> var; // Added in SpiderMonkey 38 JS::PersistentRooted<T> var(cx); JS::PersistentRooted<T> var(cx, initial); JS::PersistentRooted<T> var(rt); JS::PersistentRooted<T> var(rt, initial);
Name | Type | Description |
---|---|---|
cx |
JSContext * |
The context to get the runtime in which to add the root |
rt |
JSRuntime * |
The runtime in which to add the root. |
initial |
T |
An initial value for the persistent rooted variable. |
Methods
Here, ptr
represents the private member of JS::PersistentRooted<T>
, typed with T
.
Method | Description |
---|---|
void init(JSContext* cx) |
Initialize with optional initial value (if not provided, it will be initialized with the initial value of the type). Added in SpiderMonkey 38 |
void init(JSContext* cx, T initial) |
|
void init(JSRuntime* rt) |
|
void init(JSRuntime* rt, T initial) |
|
void reset() |
Reset the value to initial value of the type. Added in SpiderMonkey 38 |
T& get() |
Returns ptr . |
const T& get() const |
|
operator const T&() const |
|
const T& operator->() const |
|
T* address() |
Returns a pointer to ptr . |
const T* address() const |
|
PersistentRooted<T>& operator=(const T& p) |
Sets the value of ptr . |
PersistentRooted<T>& operator=(const PersistentRooted<T>& other) |
|
bool operator!=(const T& other) const |
Compares ptr and other . |
bool operator==(const T& other) const |
Description
JS::PersistentRooted<T>
declares a variable of type T
whose value is always rooted. This is typically used for global variables.
JS::PersistentRooted<T>
is a copyable, assignable global GC root type with arbitrary lifetime, an infallible constructor, and automatic unrooting on destruction.
These roots can be used in heap-allocated data structures, so they are not associated with any particular JSContext
or stack. They are registered with the JSRuntime
itself, without locking, so they require a full JSContext
to be initialized, not one of its more restricted superclasses. Initialization may take place on construction, or in two phases if the no-argument constructor is called followed by init()
.
Note that you must not use an PersistentRooted
in an object owned by a JS object:
Whenever one object whose lifetime is decided by the GC refers to another such object, that edge must be traced only if the owning JS object is traced. This applies not only to JS objects (which obviously are managed by the GC) but also to C++ objects owned by JS objects.
If you put a PersistentRooted in such a C++ object, that is almost certainly a leak. When a GC begins, the referent of the PersistentRooted
is treated as live, unconditionally (because a PersistentRooted
is a *root*), even if the JS object that owns it is unreachable. If there is any path from that referent back to the JS object, then the C++ object containing the PersistentRooted will not be destructed, and the whole blob of objects will not be freed, even if there are no references to them from the outside.
In the context of Firefox, this is a severe restriction: almost everything in Firefox is owned by some JS object or another, so using PersistentRooted in such objects would introduce leaks. For these kinds of edges, Heap<T>
or TenuredHeap<T>
would be better types. It's up to the implementor of the type containing Heap<T>
or TenuredHeap<T>
members to make sure their referents get marked when the object itself is marked.
JS::PersistentRooted<T>
may be automatically coerced to a JS::Handle<T>
and JS::MutableHandle<T>
.
Before SpiderMonkey 38, PersistentRooted<T>
itself cannot be a global variable, but from SpiderMonkey38, it can be declared as a global variable, and initialized later with init()
method (bug 1107639).
There are typedefs available for the main types:
namespace JS { typedef PersistentRooted<JSFunction*> PersistentRootedFunction; typedef PersistentRooted<jsid> PersistentRootedId; typedef PersistentRooted<JSObject*> PersistentRootedObject; typedef PersistentRooted<JSScript*> PersistentRootedScript; typedef PersistentRooted<JSString*> PersistentRootedString; typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol; // Added in SpiderMonkey 38 typedef PersistentRooted<Value> PersistentRootedValue; }
Example
Following example allocates PersistentRootedValue, and provides two functions for setting and getting it from JavaScript.
// To use Maybe. #include <mozilla/Maybe.h> // Declare global variable. // [SpiderMonkey 31] JS::PersistentRootedValue itself cannot be a global variable. mozilla::Maybe<JS::PersistentRootedValue> persistentVal; // You can also declare it just as a pointer, instead of using Maybe. // JS::PersistentRootedValue* persistentVal; // [SpiderMonkey 38] JS::PersistentRootedValue itself can be a global variable. // JS::PersistentRootedValue persistentVal; static bool SetPersistent(JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); // Set persistent value. persistentVal.ref() = args.get(0); // or // *persistentVal = args.get(0); // [SpiderMonkey 38] // persistentVal = args.get(0); args.rval().setUndefined(); return true; } static bool GetPersistent(JSContext* cx, unsigned argc, JS::Value* vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); // Get persistent value. JS::RootedValue val(cx, persistentVal.ref()); // or // JS::RootedValue val(cx, *persistentVal); // [SpiderMonkey 38] // JS::RootedValue val(cx, persistentVal); args.rval().set(val); return true; } static const JSFunctionSpec functions[] = { JS_FN("getPersistent", GetPersistent, 1, 0), JS_FN("setPersistent", SetPersistent, 0, 0), JS_FS_END }; int main(int argc, const char* argv[]) { // Initialize runtime // ... // Initialize here persistentVal.construct(rt, JS::NullValue()); // or // persistentVal = new JS::PersistentRootedValue(rt, JS::NullValue()); // [SpiderMonkey 38] // persistentVal.init(rt, JS::NullValue()); // Initialize context and global // ... if (!JS_DefineFunctions(cx, glob, functions)) return 1; // Use those function in JavaScript. // Destroy context. // ... // Destroy here // Required because of Maybe or pointer. // PersistentRooted itself doesn't require explicit destruction. persistentVal.destroy(); // or // delete persistentVal; // [SpiderMonkey 38] // destruction is not required. // Destroy runtime. // ... }
See Also
- MXR ID Search for
JS::PersistentRooted
- MXR ID Search for
JS::PersistentRootedFunction
- MXR ID Search for
JS::PersistentRootedId
- MXR ID Search for
JS::PersistentRootedObject
- MXR ID Search for
JS::PersistentRootedScript
- MXR ID Search for
JS::PersistentRootedString
- MXR ID Search for
JS::PersistentRootedSymbol
- MXR ID Search for
JS::PersistentRootedValue
JS::Rooted
JS::Handle
JS::MutableHandle
- GC Rooting Guide
- bug 892643
- bug 1107639 -- Added two phase construction.