SpiderMonkey’s conservative collector still needs some rooting

December 20, 2010 § 2 Comments

We’ve just landed the definition in <jsapi.h> of a new template type, js::Anchor, in TraceMonkey. Developers writing code against the JSAPI will need to understand it to avoid garbage collection hazards. The need for js::Anchor became clear in bug 614138, but I’ll let the comments from <jsapi.h> tell the story:

Protecting non-jsval, non-JSObject *, non-JSString * values from collection

Most of the time, the garbage collector’s conservative stack scanner works behind the scenes, finding all live values and protecting them from being collected. However, when JSAPI client code obtains a pointer to data the scanner does not know about, owned by an object the scanner does know about, Care Must Be Taken.

The scanner recognizes only a select set of types: pointers to JSObjects and similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals. So while the scanner finds all live JSString pointers, it does not notice jschar pointers.

So suppose we have:

  void f(JSString *str) {
    const jschar *ch = JS_GetStringCharsZ(str);
    ... do stuff with ch, but no uses of str ...
  }

After the call to JS_GetStringCharsZ, there are no further uses of str, which means that the compiler is within its rights to not store it anywhere. But because the stack scanner will not notice ch, there is no longer any live value in this frame that would keep the string alive. If str is the last reference to that JSString, and the collector runs while we are using ch, the string’s array of jschars may be freed out from under us.

Note that there is only an issue when 1) we extract a thing X the scanner doesn’t recognize from 2) a thing Y the scanner does recognize, and 3) if Y gets garbage-collected, then X gets freed. If we have code like this:

  void g(JSObject *obj) {
    jsval x;
    JS_GetProperty(obj, "x", &x);
    ... do stuff with x ...
  }

there’s no problem, because the value we’ve extracted, x, is a jsval, a type that the conservative scanner recognizes.

Conservative GC frees us from the obligation to explicitly root the types it knows about, but when we work with derived values like ch, we must root their owners, as the derived value alone won’t keep them alive.

A js::Anchor is a kind of GC root that allows us to keep the owners of derived values like ch alive throughout the Anchor’s lifetime. We could fix the above code as follows:

  void f(JSString *str) {
    js::Anchor<JSString *> a_str(str);
    const jschar *ch = JS_GetStringCharsZ(str);
    ... do stuff with ch, but no uses of str ...
  }

This simply ensures that str will be live until a_str goes out of scope. As long as we don’t retain a pointer to the string’s characters for longer than that, we have avoided all garbage collection hazards.

Update: Of course, this belongs in the JSAPI docs, not a blog post or a header file. I’ll get it up there shortly; third try’s a charm.

§ 2 Responses to SpiderMonkey’s conservative collector still needs some rooting

Leave a comment

What’s this?

You are currently reading SpiderMonkey’s conservative collector still needs some rooting at It Could Be So Much Better.

meta