Tuesday, 11 October 2011

Customize-Reach GC

I've decided on a new strategy for garbage collection- the CM GC, or Customize-Mark GC.

The basic idea behind a GC is to list all the objects you ever allocated off the GC. Then you look through the stack (and static references) and mark off every object referenced. Then you go through the list of new references and mark off every object *they* reference. Rinse and repeat until no new objects referenced. Delete all remaining objects.

However, I've had a genius idea for a GC. One where you can customize the "mark" phase. Consider, for example, a std::vector or boost::variant. These container objects would need a custom reach function so that they can "reach" their container's contents. This also means that it would be possible to "mark" objects which are only referred to externally.

For example, let's consider the WinAPI thread pump. You can associate a custom object with each HWND for use in callbacks. This basically consists of SetWindowLongPtr/GetWindowLongPtr. Obviously, in previous GCs this would be impossible to point to a GC object, because the GC has no way of reaching it and even if it does, then it can't change the object pointer, making it impossible. A custom-mark GC, however, can.

class Window {
    HWND hwnd;
public:
    void mark() { // special function
        struct marker {
            HWND hwnd;
            void operator=(T* ptr) {
                SetWindowLongPtr(hwnd, GWLP_USERDATA, ptr);
            }
            T* operator->() {
                return reinterpret_cast<T*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
            }
        };     
        GC::mark(marker { hwnd });
    }
};

This can tell the GC where to find a custom pointer to an object, and can update it if the GC decides to move the object. This means that the GC implementation can still be compacting, *and* maintain pointers to GC objects that are held externally.

No comments:

Post a Comment