ext/v8/v8_external.cpp in therubyracer-0.9.0beta4 vs ext/v8/v8_external.cpp in therubyracer-0.9.0beta5

- old
+ new

@@ -7,32 +7,62 @@ namespace { VALUE ExternalClass; VALUE references; + struct Weaklink { + bool finalized_from_rb; + bool finalized_from_v8; + VALUE target; + }; + + VALUE Weaklink_finalized_from_ruby(VALUE object_id, VALUE data) { + Weaklink* link = 0; + Data_Get_Struct(data, struct Weaklink, link); + link->finalized_from_rb = true; + if (link->finalized_from_v8) { + delete link; + } + return Qnil; + } + void Weaklink_finalized_from_v8(Persistent<Value> value, void* data) { + Weaklink* link = (Weaklink*)data; + link->finalized_from_v8 = true; + if (link->finalized_from_rb) { + delete link; + } + value.Dispose(); + } + VALUE New(VALUE self, VALUE value) { HandleScope scope; - return rr_v8_handle_new(self, External::New((void*)value)); + Weaklink* link = new Weaklink(); + link->finalized_from_v8 = false; + link->finalized_from_rb = false; + link->target = value; + Persistent<External> external = Persistent<External>::New(External::New((void*)link)); + external.MakeWeak(link,Weaklink_finalized_from_v8); + VALUE finalizer_data = Data_Wrap_Struct(rb_cObject, 0, 0, link); + rr_define_finalizer(value, (void*)Weaklink_finalized_from_ruby, finalizer_data); + return rr_v8_handle_new(self, external); } - VALUE Unwrap(VALUE self, VALUE value) { + + VALUE _Value(VALUE self) { HandleScope scope; - if (rb_obj_is_kind_of(value, self)) { - return (VALUE)External::Unwrap(rr_v8_handle<External>(self)); - } else { - rb_raise(rb_eArgError, "cannot unwrap %s. It is not a kind of %s", RSTRING_PTR(rb_class_name(rb_class_of(value))), RSTRING_PTR(rb_class_name(self))); + Weaklink* link = (Weaklink*)rr_v8_handle<External>(self)->Value(); + if (link->finalized_from_rb) { + rb_warn("an active v8::External wraps a VALUE that has already been finalized! This is not good.\n"); return Qnil; + } else { + return link->target; } - } - VALUE _Value(VALUE self) { - HandleScope scope; return (VALUE)rr_v8_handle<External>(self)->Value(); } } void rr_init_v8_external() { ExternalClass = rr_define_class("External", rr_v8_value_class()); rr_define_singleton_method(ExternalClass, "New", New, 1); - rr_define_singleton_method(ExternalClass, "Unwrap", Unwrap, 1); rr_define_method(ExternalClass, "Value", _Value, 0); } VALUE rr_reflect_v8_external(Handle<Value> external) { return rr_v8_handle_new(ExternalClass, external);