This PR takes care of the case where an Isolate was disposed but there were still references outstanding to objects that depended on it. Let's say, for example, that we have
@isolate = V8::C::Isolate::New()
@cxt1 = V8::C::Context::New(@isolate)
@cxt2 = V8::C::Context::New(@isolate)
These objects could be garbage collected in any order, and so it is not safe to delete the underlying Isolate::IsolateData* in the C++ layer, because they are all using the queues contained in it it to coordinate garbage collection.
To solve this, we take a "last one out the door turns off the lights" approach. A concurrent queue is used to track all the outstanding references. Every time a reference is added, an item is pushed onto the queue, and every time a reference is removed, an item is popped off the queue. The last object to get garbage collected will delete the isolate data.
Therefore, the isolate data does not belong to the isolate, but rather to it and all of the Ref<*> objects collectively.
This PR takes care of the case where an Isolate was disposed but there were still references outstanding to objects that depended on it. Let's say, for example, that we have
@isolate = V8::C::Isolate::New() @cxt1 = V8::C::Context::New(@isolate) @cxt2 = V8::C::Context::New(@isolate) These objects could be garbage collected in any order, and so it is not safe to delete the underlying Isolate::IsolateData* in the C++ layer, because they are all using the queues contained in it it to coordinate garbage collection.
To solve this, we take a "last one out the door turns off the lights" approach. A concurrent queue is used to track all the outstanding references. Every time a reference is added, an item is pushed onto the queue, and every time a reference is removed, an item is popped off the queue. The last object to get garbage collected will delete the isolate data.
Therefore, the isolate data does not belong to the isolate, but rather to it and all of the Ref<*> objects collectively.