mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
avoid race condition in object back reference.
This commit is contained in:
parent
21e69ecf93
commit
7f967d0c5e
3 changed files with 35 additions and 50 deletions
|
@ -2,47 +2,32 @@
|
|||
|
||||
namespace rr {
|
||||
|
||||
VALUE Backref::WeakRef;
|
||||
VALUE Backref::Storage;
|
||||
ID Backref::_new;
|
||||
ID Backref::__getobj__;
|
||||
ID Backref::__setobj__;
|
||||
ID Backref::__weakref_alive;
|
||||
ID Backref::access;
|
||||
|
||||
void Backref::Init() {
|
||||
WeakRef = rb_eval_string("require 'weakref'; WeakRef");
|
||||
rb_gc_register_address(&WeakRef);
|
||||
Storage = rb_eval_string("require 'v8/util/weakcell'; V8::Util::Weakcell::Storage");
|
||||
rb_gc_register_address(&Storage);
|
||||
_new = rb_intern("new");
|
||||
__getobj__ = rb_intern("__getobj__");
|
||||
__setobj__ = rb_intern("__setobj__");
|
||||
__weakref_alive = rb_intern("weakref_alive?");
|
||||
access = rb_intern("access");
|
||||
}
|
||||
|
||||
Backref::Backref(VALUE initial) {
|
||||
this->ref = rb_funcall(WeakRef, _new, 1, initial);
|
||||
rb_gc_register_address(&ref);
|
||||
Backref::Backref() {
|
||||
this->storage = rb_funcall(Storage, _new, 0);
|
||||
rb_gc_register_address(&storage);
|
||||
}
|
||||
|
||||
Backref::~Backref() {
|
||||
rb_gc_unregister_address(&ref);
|
||||
rb_gc_unregister_address(&storage);
|
||||
}
|
||||
|
||||
VALUE Backref::get() {
|
||||
if (alive_p()) {
|
||||
return rb_funcall(ref, __getobj__, 0);
|
||||
} else {
|
||||
return Qnil;
|
||||
}
|
||||
VALUE Backref::get(VALUE (*populate)(ANYARGS), VALUE data) {
|
||||
VALUE args[0];
|
||||
return rb_block_call(storage, access, 0, args, populate, data);
|
||||
}
|
||||
|
||||
void Backref::set(VALUE value) {
|
||||
rb_funcall(ref, __setobj__, 1, value);
|
||||
}
|
||||
|
||||
bool Backref::alive_p() {
|
||||
return RTEST(rb_funcall(ref, __weakref_alive, 0));
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Backref::to_external() {
|
||||
v8::Handle<v8::Value> Backref::toExternal() {
|
||||
v8::Local<v8::Value> wrapper = v8::External::Wrap(this);
|
||||
v8::Persistent<v8::Value>::New(wrapper).MakeWeak(this, &release);
|
||||
return wrapper;
|
||||
|
|
|
@ -138,23 +138,26 @@ Object::operator VALUE() {
|
|||
VALUE value;
|
||||
Backref* backref;
|
||||
v8::Local<v8::String> key(v8::String::NewSymbol("rr::Backref"));
|
||||
v8::Local<v8::Value> holder = handle->GetHiddenValue(key);
|
||||
if (holder.IsEmpty()) {
|
||||
value = downcast();
|
||||
backref = new Backref(value);
|
||||
handle->SetHiddenValue(key, backref->to_external());
|
||||
v8::Local<v8::Value> external = handle->GetHiddenValue(key);
|
||||
if (external.IsEmpty()) {
|
||||
backref = new Backref();
|
||||
handle->SetHiddenValue(key, backref->toExternal());
|
||||
} else {
|
||||
backref = (Backref*)v8::External::Unwrap(holder);
|
||||
if (backref->alive_p()) {
|
||||
value = backref->get();
|
||||
} else {
|
||||
value = downcast();
|
||||
backref->set(value);
|
||||
}
|
||||
backref = (Backref*)v8::External::Unwrap(external);
|
||||
}
|
||||
return backref->get((VALUE (*)(...))&toVALUE, Data_Wrap_Struct(rb_cObject, 0, 0, this));
|
||||
return value;
|
||||
}
|
||||
|
||||
VALUE Object::toVALUE(VALUE yield, VALUE wrapper) {
|
||||
if (!RTEST(wrapper)) {
|
||||
fprintf(stderr, "WTF?");
|
||||
}
|
||||
Object* object(NULL);
|
||||
Data_Get_Struct(wrapper, class Object, object);
|
||||
return object->downcast();
|
||||
}
|
||||
|
||||
VALUE Object::downcast() {
|
||||
if (handle->IsFunction()) {
|
||||
return Function((v8::Handle<v8::Function>) v8::Function::Cast(*handle));
|
||||
|
|
17
ext/v8/rr.h
17
ext/v8/rr.h
|
@ -206,20 +206,16 @@ template <class T> VALUE Ref<T>::Class;
|
|||
class Backref {
|
||||
public:
|
||||
static void Init();
|
||||
Backref(VALUE initial);
|
||||
Backref();
|
||||
virtual ~Backref();
|
||||
VALUE get();
|
||||
void set(VALUE);
|
||||
bool alive_p();
|
||||
v8::Handle<v8::Value> to_external();
|
||||
VALUE get(VALUE (*populate)(ANYARGS), VALUE data);
|
||||
v8::Handle<v8::Value> toExternal();
|
||||
static void release(v8::Persistent<v8::Value> handle, void* data);
|
||||
private:
|
||||
VALUE ref;
|
||||
static VALUE WeakRef;
|
||||
VALUE storage;
|
||||
static VALUE Storage;
|
||||
static ID _new;
|
||||
static ID __getobj__;
|
||||
static ID __setobj__;
|
||||
static ID __weakref_alive;
|
||||
static ID access;
|
||||
};
|
||||
class Handles {
|
||||
public:
|
||||
|
@ -564,6 +560,7 @@ public:
|
|||
inline Object(VALUE value) : Ref<v8::Object>(value) {}
|
||||
inline Object(v8::Handle<v8::Object> object) : Ref<v8::Object>(object) {}
|
||||
virtual operator VALUE();
|
||||
static VALUE toVALUE(VALUE yield, VALUE wrapper);
|
||||
|
||||
protected:
|
||||
VALUE downcast();
|
||||
|
|
Loading…
Add table
Reference in a new issue