Changes between Initial Version and Version 1 of How to not mess up GC


Ignore:
Timestamp:
May 18, 2011 11:00:48 AM (8 years ago)
Author:
oliver@apple.com
Comment:

work in progress

Legend:

Unmodified
Added
Removed
Modified
  • How to not mess up GC

    v1 v1  
     1This 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.
     2
     3When 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:
     4
     5  * Object destruction is performed lazily; and
     6  * Object destruction order is undefined.
     7
     8The 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:
     9
     10{{{
     11HashMap<String, MyAwesomeJSObject*> m_myAwesomeCache;
     12
     13class MyAwesomeJSObject : public JSCell {
     14    String data;
     15    ~MyAwesomeJSObject()
     16    {
     17         m_myAwesomeCache.remove(data);
     18    }
     19};
     20
     21MyAwesomeJSObject* getAwesomeObject(ExecState* exec, String key)
     22{
     23    if (MyAwesomeJSObject* result = m_myAwesomeCache.get(key))
     24        return result;
     25    MyAwesomeJSObject* result = new (exec) MyAwesomeJSObject(key);
     26    m_myAwesomeCache.set(key, result);
     27    return result;
     28}
     29}}}
     30
     31This 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.
     32
     33To 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).
     34
     35
     36The 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.
     37
     38Finalizers are created for objects by making a `Weak<>` handle from the object to itself, with a finalizer specified