mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
eschew heap allocated accessor callbacks
This changes the accessor code to push as much object allocation onto Ruby as possible. Instead the C++ layer acts strictly as glue using stack allocated variables to convert v8 value to ruby objects at the moment it passes them off to Ruby.
This commit is contained in:
parent
c66e43e438
commit
72068651f9
4 changed files with 112 additions and 127 deletions
|
@ -2,105 +2,97 @@
|
|||
|
||||
namespace rr {
|
||||
|
||||
VALUE Accessor::Class;
|
||||
VALUE Accessor::Info::Class;
|
||||
|
||||
void Accessor::Init() {
|
||||
ClassBuilder("AccessorInfo").
|
||||
defineMethod("This", &This).
|
||||
defineMethod("Holder", &Holder).
|
||||
defineMethod("Data", &Data).
|
||||
store(&Class);
|
||||
defineMethod("This", &Info::This).
|
||||
defineMethod("Holder", &Info::Holder).
|
||||
defineMethod("Data", &Info::Data).
|
||||
store(&Info::Class);
|
||||
}
|
||||
|
||||
Accessor::Accessor(const v8::AccessorInfo& info) {
|
||||
this->thisObject = Object(info.This());
|
||||
this->holder = Object(info.Holder());
|
||||
this->value = Data_Wrap_Struct(Class, &mark, &sweep, this);
|
||||
this->info = new Info(info.Data());
|
||||
}
|
||||
Accessor::~Accessor() {
|
||||
delete info;
|
||||
}
|
||||
Accessor* Accessor::accessor(VALUE wrap) {
|
||||
Accessor* info = 0;
|
||||
Data_Get_Struct(wrap, class Accessor, info);
|
||||
return info;
|
||||
}
|
||||
Accessor::operator VALUE() {
|
||||
return this->value;
|
||||
}
|
||||
VALUE Accessor::This(VALUE self) {
|
||||
return accessor(self)->thisObject;
|
||||
}
|
||||
|
||||
VALUE Accessor::Holder(VALUE self) {
|
||||
return accessor(self)->holder;
|
||||
}
|
||||
VALUE Accessor::Data(VALUE self) {
|
||||
return accessor(self)->info->data;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::get(v8::Local<v8::String> property) {
|
||||
return Value(rb_funcall(info->getter, rb_intern("call"), 2, (VALUE)String(property), this->value));
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::set(v8::Local<v8::String> property, v8::Local<v8::Value> value) {
|
||||
return Value(rb_funcall(info->setter, rb_intern("call"), 3, (VALUE)String(property), (VALUE)Value(value), this->value));
|
||||
}
|
||||
void Accessor::mark(Accessor* acc) {
|
||||
rb_gc_mark(acc->thisObject);
|
||||
rb_gc_mark(acc->holder);
|
||||
acc->info->mark();
|
||||
}
|
||||
void Accessor::sweep(Accessor* acc) {
|
||||
delete acc;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::AccessorGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
|
||||
Accessor* getter = new Accessor(info);
|
||||
return getter->get(property);
|
||||
}
|
||||
|
||||
void Accessor::AccessorSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
|
||||
Accessor* accessor = new Accessor(info);
|
||||
accessor->set(property, value);
|
||||
}
|
||||
|
||||
Accessor::Info::Info(VALUE getter, VALUE setter, VALUE data) {
|
||||
this->getter = getter;
|
||||
this->setter = setter;
|
||||
Accessor::Accessor(VALUE get, VALUE set, VALUE data) {
|
||||
this->get = get;
|
||||
this->set = set;
|
||||
this->data = data;
|
||||
}
|
||||
Accessor::Info::Info(v8::Local<v8::Value> data) {
|
||||
v8::Local<v8::Object> wrapper = data->ToObject();
|
||||
this->getter = unwrap(wrapper, 0);
|
||||
this->setter = unwrap(wrapper, 1);
|
||||
this->data = unwrap(wrapper, 2);
|
||||
}
|
||||
Accessor::Info::operator v8::Handle<v8::Value>() {
|
||||
v8::Local<v8::Object> wrapper = v8::Object::New();
|
||||
wrap(wrapper, 0, this->getter);
|
||||
wrap(wrapper, 1, this->setter);
|
||||
wrap(wrapper, 2, this->data);
|
||||
return wrapper;
|
||||
}
|
||||
void Accessor::Info::wrap(v8::Handle<v8::Object> wrapper, uint32_t index, VALUE value) {
|
||||
wrapper->Set(index, External::wrap(value));
|
||||
}
|
||||
VALUE Accessor::Info::unwrap(v8::Handle<v8::Object> wrapper, uint32_t index) {
|
||||
v8::Local<v8::External> holder = v8::External::Cast(*(wrapper->Get(index)));
|
||||
return External::unwrap(holder);
|
||||
}
|
||||
v8::AccessorGetter Accessor::Info::Getter() {
|
||||
return &Accessor::AccessorGetter;
|
||||
}
|
||||
v8::AccessorSetter Accessor::Info::Setter() {
|
||||
return RTEST(this->setter) ? &Accessor::AccessorSetter : 0;
|
||||
|
||||
Accessor::Accessor(v8::Handle<v8::Value> value) {
|
||||
v8::Local<v8::Object> wrapper = value->ToObject();
|
||||
this->get = unwrap(wrapper, 0);
|
||||
this->set = unwrap(wrapper, 1);
|
||||
v8::Handle<v8::Value> data = wrapper->Get(2);
|
||||
if (!data.IsEmpty()) {
|
||||
this->data = Value(data);
|
||||
}
|
||||
}
|
||||
|
||||
void Accessor::Info::mark() {
|
||||
rb_gc_mark(getter);
|
||||
rb_gc_mark(setter);
|
||||
rb_gc_mark(data);
|
||||
Accessor::operator v8::AccessorGetter() {
|
||||
return &Getter;
|
||||
}
|
||||
|
||||
Accessor::operator v8::AccessorSetter() {
|
||||
return RTEST(this->set) ? &Setter : 0;
|
||||
}
|
||||
|
||||
Accessor::operator v8::Handle<v8::Value>() {
|
||||
v8::Local<v8::Object> wrapper = v8::Object::New();
|
||||
wrap(wrapper, 0, this->get);
|
||||
wrap(wrapper, 1, this->set);
|
||||
if (RTEST(this->data)) {
|
||||
wrapper->Set(2, Value(this->data));
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
void Accessor::wrap(v8::Handle<v8::Object> wrapper, int index, VALUE value) {
|
||||
wrapper->Set(index, External::wrap(value));
|
||||
}
|
||||
|
||||
VALUE Accessor::unwrap(v8::Handle<v8::Object> wrapper, int index) {
|
||||
v8::Handle<v8::External> external(v8::External::Cast(*wrapper->Get(index)));
|
||||
return External::unwrap(external);
|
||||
}
|
||||
|
||||
VALUE Accessor::Info::This(VALUE self) {
|
||||
return Object(Info(self)->This());
|
||||
}
|
||||
|
||||
VALUE Accessor::Info::Holder(VALUE self) {
|
||||
return Object(Info(self)->Holder());
|
||||
}
|
||||
|
||||
VALUE Accessor::Info::Data(VALUE self) {
|
||||
return Accessor(Info(self)->Data()).data;
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::Getter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
|
||||
return Info(info).get(property);
|
||||
}
|
||||
|
||||
void Accessor::Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
|
||||
Info(info).set(property, value);
|
||||
}
|
||||
|
||||
Accessor::Info::Info(const v8::AccessorInfo& info) {
|
||||
this->info = &info;
|
||||
}
|
||||
|
||||
Accessor::Info::Info(VALUE value) {
|
||||
Data_Get_Struct(value, class v8::AccessorInfo, info);
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Accessor::Info::get(v8::Local<v8::String> property) {
|
||||
Accessor accessor(info->Data());
|
||||
return Value(rb_funcall(accessor.get, rb_intern("call"), 2, (VALUE)String(property), (VALUE)*this));
|
||||
}
|
||||
|
||||
void Accessor::Info::set(v8::Local<v8::String> property, v8::Local<v8::Value> value) {
|
||||
Accessor accessor(info->Data());
|
||||
rb_funcall(accessor.set, rb_intern("call"), 3, (VALUE)String(property), (VALUE)Value(value), (VALUE)*this);
|
||||
}
|
||||
Accessor::Info::operator VALUE() {
|
||||
return Data_Wrap_Struct(Class, 0, 0, (void*)this->info);
|
||||
}
|
||||
}
|
|
@ -120,13 +120,8 @@ VALUE Object::ForceDelete(VALUE self, VALUE key) {
|
|||
VALUE Object::SetAccessor(int argc, VALUE* argv, VALUE self) {
|
||||
VALUE name; VALUE get; VALUE set; VALUE data; VALUE settings; VALUE attribs;
|
||||
rb_scan_args(argc, argv, "24", &name, &get, &set, &data, &settings, &attribs);
|
||||
Accessor::Info accessor(get, set, data);
|
||||
return Bool(Object(self)->SetAccessor(String(name),
|
||||
accessor.Getter(),
|
||||
accessor.Setter(),
|
||||
accessor,
|
||||
AccessControl(settings),
|
||||
PropertyAttribute(attribs)));
|
||||
Accessor access(get, set, data);
|
||||
return Bool(Object(self)->SetAccessor(String(name), access, access, access, AccessControl(settings), PropertyAttribute(attribs)));
|
||||
}
|
||||
|
||||
Object::operator VALUE() {
|
||||
|
|
54
ext/v8/rr.h
54
ext/v8/rr.h
|
@ -223,41 +223,37 @@ public:
|
|||
class Accessor {
|
||||
public:
|
||||
static void Init();
|
||||
Accessor(const v8::AccessorInfo& info);
|
||||
~Accessor();
|
||||
static VALUE This(VALUE self);
|
||||
static VALUE Holder(VALUE self);
|
||||
static VALUE Data(VALUE self);
|
||||
operator VALUE();
|
||||
v8::Handle<v8::Value> get(v8::Local<v8::String> property);
|
||||
v8::Handle<v8::Value> set(v8::Local<v8::String> property, v8::Local<v8::Value> value);
|
||||
static v8::Handle<v8::Value> AccessorGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
||||
static void AccessorSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
|
||||
Accessor(VALUE get, VALUE set, VALUE data);
|
||||
Accessor(v8::Handle<v8::Value> value);
|
||||
operator v8::AccessorGetter();
|
||||
operator v8::AccessorSetter();
|
||||
operator v8::Handle<v8::Value>();
|
||||
static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
|
||||
static void Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
|
||||
|
||||
class Info {
|
||||
public:
|
||||
Info(VALUE getter, VALUE setter, VALUE data);
|
||||
Info(v8::Local<v8::Value> value);
|
||||
operator v8::Handle<v8::Value>();
|
||||
void mark();
|
||||
v8::AccessorGetter Getter();
|
||||
v8::AccessorSetter Setter();
|
||||
VALUE getter;
|
||||
VALUE setter;
|
||||
VALUE data;
|
||||
Info(const v8::AccessorInfo& info);
|
||||
Info(VALUE value);
|
||||
static VALUE This(VALUE self);
|
||||
static VALUE Holder(VALUE self);
|
||||
static VALUE Data(VALUE self);
|
||||
operator VALUE();
|
||||
inline const v8::AccessorInfo* operator->() {return this->info;}
|
||||
v8::Handle<v8::Value> get(v8::Local<v8::String> property);
|
||||
void set(v8::Local<v8::String> property, v8::Local<v8::Value> value);
|
||||
|
||||
static VALUE Class;
|
||||
private:
|
||||
void wrap(v8::Handle<v8::Object> wrapper, uint32_t index, VALUE value);
|
||||
VALUE unwrap(v8::Handle<v8::Object> wrapper, uint32_t index);
|
||||
const v8::AccessorInfo* info;
|
||||
};
|
||||
friend class Info;
|
||||
private:
|
||||
VALUE thisObject;
|
||||
VALUE holder;
|
||||
VALUE value;
|
||||
Info* info;
|
||||
static void mark(Accessor* accessor);
|
||||
static void sweep(Accessor* accessor);
|
||||
static Accessor* accessor(VALUE self);
|
||||
static VALUE Class;
|
||||
void wrap(v8::Handle<v8::Object> wrapper, int index, VALUE value);
|
||||
VALUE unwrap(v8::Handle<v8::Object> wrapper, int index);
|
||||
VALUE get;
|
||||
VALUE set;
|
||||
VALUE data;
|
||||
};
|
||||
|
||||
class Invocation {
|
||||
|
|
|
@ -36,6 +36,8 @@ describe V8::C::Object do
|
|||
callback_data = V8::C::String::New("I am Legend")
|
||||
left = V8::C::String::New("Yo! ")
|
||||
getter = proc do |name, info|
|
||||
info.This().StrictEquals(o).should be_true
|
||||
info.Holder().StrictEquals(o).should be_true
|
||||
V8::C::String::Concat(left, info.Data())
|
||||
end
|
||||
setter = proc do |name, value, info|
|
||||
|
|
Loading…
Add table
Reference in a new issue