mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
protect access to embedded VALUEs in a struct that will clear be aware if the VALUE has become garbage collected.
This commit is contained in:
parent
cfa2570e3f
commit
a6c7757b6e
1 changed files with 41 additions and 11 deletions
|
@ -9,21 +9,52 @@ namespace {
|
||||||
VALUE ExternalClass;
|
VALUE ExternalClass;
|
||||||
VALUE references;
|
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) {
|
VALUE New(VALUE self, VALUE value) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
return rr_v8_handle_new(self, External::New((void*)value));
|
Weaklink* link = new Weaklink();
|
||||||
}
|
link->finalized_from_v8 = false;
|
||||||
VALUE Unwrap(VALUE self, VALUE value) {
|
link->finalized_from_rb = false;
|
||||||
HandleScope scope;
|
link->target = value;
|
||||||
if (rb_obj_is_kind_of(value, self)) {
|
Persistent<External> external = Persistent<External>::New(External::New((void*)link));
|
||||||
return (VALUE)External::Unwrap(rr_v8_handle<External>(self));
|
external.MakeWeak(link,Weaklink_finalized_from_v8);
|
||||||
} else {
|
VALUE finalizer_data = Data_Wrap_Struct(rb_cObject, 0, 0, link);
|
||||||
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)));
|
rr_define_finalizer(value, (void*)Weaklink_finalized_from_ruby, finalizer_data);
|
||||||
return Qnil;
|
return rr_v8_handle_new(self, external);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE _Value(VALUE self) {
|
VALUE _Value(VALUE self) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
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;
|
||||||
|
}
|
||||||
return (VALUE)rr_v8_handle<External>(self)->Value();
|
return (VALUE)rr_v8_handle<External>(self)->Value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +62,6 @@ namespace {
|
||||||
void rr_init_v8_external() {
|
void rr_init_v8_external() {
|
||||||
ExternalClass = rr_define_class("External", rr_v8_value_class());
|
ExternalClass = rr_define_class("External", rr_v8_value_class());
|
||||||
rr_define_singleton_method(ExternalClass, "New", New, 1);
|
rr_define_singleton_method(ExternalClass, "New", New, 1);
|
||||||
rr_define_singleton_method(ExternalClass, "Unwrap", Unwrap, 1);
|
|
||||||
rr_define_method(ExternalClass, "Value", _Value, 0);
|
rr_define_method(ExternalClass, "Value", _Value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue