JS::PersistentRooted

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&lt;T&gt; and JS::MutableHandle&lt;T&gt;.

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