wiki:How to not mess up GC

This page details some of the rules for creating objects using JSC's internal types without being GC unsound. Using the JSC API itself is much safer for use if you don't want to be continually maintaining your code.

When creating an object using the builtin API there are two very important things that need to be understood about the behaviour of JSC's GC:

  • Object destruction is performed lazily; and
  • Object destruction order is undefined.

The first basically means that there is a window of time in which a GC allocated object will be dead, but it's destructor will not have been called. This means that any code that removes an entry from a map of GC objects during a GC object destructor is almost certainly unsafe, for example this pseudo object:

HashMap<String, MyAwesomeJSObject*> m_myAwesomeCache;

class MyAwesomeJSObject : public JSCell {
    String data;
    ~MyAwesomeJSObject()
    {
         m_myAwesomeCache.remove(data);
    }
};

MyAwesomeJSObject* getAwesomeObject(ExecState* exec, String key)
{
    if (MyAwesomeJSObject* result = m_myAwesomeCache.get(key))
        return result;
    MyAwesomeJSObject* result = new (exec) MyAwesomeJSObject(key);
    m_myAwesomeCache.set(key, result);
    return result;
}

This is unsafe as it is possible for getAwesomeObject to return a dead object, and therefore make any code that depends on an object being an instance of MyAwesomeJSObject broken. The dead object can be returned due to the window between becoming dead, and the destructor being run, this window results in m_myAwesomeCache referencing a dead object.

To avoid this problem m_myAwesomeCache should be either a WeakGCMap which handles this use case entirely automatically, or a HashMap<String, Weak<MyAwesomeJSObject> > (which is slightly less efficient, but allows greater flexibility in behaviour).

The second issue to be aware of is indeterminate order of object destruction. This has a very simple result: In an object's destructor you cannot depend on _any_ GC allocated object be in a live or valid state. This includes the object's structure so questions like "Am I using inline storage?", "What is my classinfo?", etc are not safe or valid during destruction. If you need to be able to access GC objects from the destructor (like your structure), you need to do that work in a finalizer.

Finalizers are created for objects by making a Weak<> handle from the object to itself, with a finalizer specified

Last modified 14 years ago Last modified on May 18, 2011, 11:00:48 AM
Note: See TracWiki for help on using the wiki.