support for accessors, equivalence classes

This commit is contained in:
Charles Lowell 2012-05-22 12:12:08 -05:00
parent 72068651f9
commit 7f659ef385
7 changed files with 457 additions and 26 deletions

190
benchmarks.rb Normal file
View File

@ -0,0 +1,190 @@
require "v8"
require "Benchmark"
TIMES=10
OBJECTS=100
js= <<JS
function createTest()
{
var test = {};
test.objects = [];
test.seed = 49734321;
test.summ;
test.random = function()
{
// Robert Jenkins' 32 bit integer hash function.
test.seed = ((test.seed + 0x7ed55d16) + (test.seed << 12)) & 0xffffffff;
test.seed = ((test.seed ^ 0xc761c23c) ^ (test.seed >>> 19)) & 0xffffffff;
test.seed = ((test.seed + 0x165667b1) + (test.seed << 5)) & 0xffffffff;
test.seed = ((test.seed + 0xd3a2646c) ^ (test.seed << 9)) & 0xffffffff;
test.seed = ((test.seed + 0xfd7046c5) + (test.seed << 3)) & 0xffffffff;
test.seed = ((test.seed ^ 0xb55a4f09) ^ (test.seed >>> 16)) & 0xffffffff;
return (test.seed & 0xfffffff) / 0x10000000;
};
test.init = function()
{
test.objects = [];
for(var i=0; i<#{OBJECTS}; i++)
{
var hash = {};
for(var j=0; j<10; j++)
{
var isString = test.random();
var key = "str" + test.random();
var value;
if(isString < 0.5)
value = "str" + test.random();
else
value = test.random();
hash[key] = value;
}
test.objects[i] = hash;
}
return test.objects.length;
}
test.findSum = function()
{
test.summ = 0;
var length = test.objects.length;
for(var i=0; i<length; i++)
{
var hash = test.objects[i];
for (var k in hash)
{
if (hash.hasOwnProperty(k) && (typeof(hash[k]) == "number"))
{
test.summ += hash[k];
}
}
}
return test.summ;
};
test.finalCheck = function()
{
var summ = 0;
var length = test.objects.length;
for(var i=0; i<length; i++)
{
var hash = test.objects[i];
for (var k in hash)
{
if (hash.hasOwnProperty(k) && (typeof(hash[k]) == "number"))
{
summ += hash[k];
}
}
}
return summ == -test.summ;
};
test.getObject = function(index)
{
if(!test.objects[index]) return {};
return test.objects[index];
}
test.setObject = function(index, object)
{
test.objects[index] = object;
}
return test;
}
JS
def profile
# RubyProf.profile do
Benchmark.realtime do
yield
end
end
def get_res result
#result.threads[0].top_method.total_time
result.to_f
end
def call_test(suite, name, times = 1)
cxt = nil
V8::C::HandleScope() do
cxt = suite.CreationContext()
cxt.Enter()
times.times do
test = suite.Get(V8::C::String::New(name))
test.Call(suite, 0, [])
end
end
ensure
cxt.Exit() if cxt
end
#RubyProf.measure_mode = RubyProf::CPU_TIME
puts "init js context..."
cxt = V8::Context.new
cxt.eval(js)
suite = cxt.eval('var test = createTest(); test;')
puts "run init test"
result =profile do
call_test suite, 'init', TIMES
end
puts "init time: #{get_res(result) / TIMES} sec."
puts "run findSum test"
call_test(suite, 'init')
result =profile do
call_test suite, 'findSum', TIMES
end
puts "findSum time: #{get_res(result) / TIMES} sec."
puts "run Objects iversion in ruby test"
call_test suite, 'init'
result =profile do
cxt.native.Enter()
V8::C::HandleScope() do
TIMES.times do |j|
for i in 0..(OBJECTS-1) do
obj = suite.Get(V8::C::String::New("objects")).Get(i)
names = obj.GetPropertyNames()
for k in 0..names.Length() - 1 do
name = names.Get(k)
value = obj.Get(name)
if value.instance_of? Float
value = value * -1
end
suite.Get(V8::C::String::New("objects")).Set(i, obj)
end
end
end
end
cxt.native.Exit()
end
puts "Objects time: #{get_res(result) / TIMES} sec."
puts "run finalCheck test"
call_test suite, 'init'
result =profile do
call_test suite, 'finalCheck', TIMES
end
puts "final check time: #{get_res(result) / TIMES} sec."

View File

@ -12,9 +12,14 @@ namespace rr {
store(&Info::Class);
}
Accessor::Accessor(VALUE get, VALUE set, VALUE data) {
Accessor::Accessor(VALUE getter, VALUE setter, VALUE data_) : get(getter), set(setter), data(data_) {}
Accessor::Accessor(VALUE get, VALUE set, VALUE query, VALUE deleter, VALUE enumerator, VALUE data) {
this->get = get;
this->set = set;
this->query = query;
this->deleter = deleter;
this->enumerator = enumerator;
this->data = data;
}
@ -28,14 +33,6 @@ namespace rr {
}
}
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);
@ -55,6 +52,7 @@ namespace rr {
return External::unwrap(external);
}
VALUE Accessor::Info::This(VALUE self) {
return Object(Info(self)->This());
}
@ -67,13 +65,44 @@ namespace rr {
return Accessor(Info(self)->Data()).data;
}
v8::Handle<v8::Value> Accessor::Getter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
v8::Handle<v8::Value> Accessor::AccessorGetter(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) {
void Accessor::AccessorSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
Info(info).set(property, value);
}
v8::Handle<v8::Value> Accessor::NamedPropertyGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
return Info(info).get(property);
}
v8::Handle<v8::Value> Accessor::NamedPropertySetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
return Info(info).set(property, value);
}
v8::Handle<v8::Integer> Accessor::NamedPropertyQuery(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
return Info(info).query(property);
}
v8::Handle<v8::Boolean> Accessor::NamedPropertyDeleter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
return Info(info).remove(property);
}
v8::Handle<v8::Array> Accessor::NamedPropertyEnumerator(const v8::AccessorInfo& info) {
return Info(info).enumerateNames();
}
v8::Handle<v8::Value> Accessor::IndexedPropertyGetter(uint32_t index, const v8::AccessorInfo& info) {
return Info(info).get(index);
}
v8::Handle<v8::Value> Accessor::IndexedPropertySetter(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
return Info(info).set(index, value);
}
v8::Handle<v8::Integer> Accessor::IndexedPropertyQuery(uint32_t index, const v8::AccessorInfo& info) {
return Info(info).query(index);
}
v8::Handle<v8::Boolean> Accessor::IndexedPropertyDeleter(uint32_t index, const v8::AccessorInfo& info) {
return Info(info).remove(index);
}
v8::Handle<v8::Array> Accessor::IndexedPropertyEnumerator(const v8::AccessorInfo& info) {
return Info(info).enumerateIndices();
}
Accessor::Info::Info(const v8::AccessorInfo& info) {
this->info = &info;
@ -88,10 +117,51 @@ namespace rr {
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) {
v8::Handle<v8::Value> 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);
return Value(rb_funcall(accessor.set, rb_intern("call"), 3, (VALUE)String(property), (VALUE)Value(value), (VALUE)*this));
}
v8::Handle<v8::Integer> Accessor::Info::query(v8::Local<v8::String> property) {
Accessor accessor(info->Data());
return v8::Integer::New(Int(rb_funcall(accessor.query, rb_intern("call"), 2, (VALUE)String(property), (VALUE)*this)));
}
v8::Handle<v8::Boolean> Accessor::Info::remove(v8::Local<v8::String> property) {
Accessor accessor(info->Data());
return v8::Boolean::New(Bool(rb_funcall(accessor.deleter, rb_intern("call"), 2, (VALUE)String(property), (VALUE)*this)));
}
v8::Handle<v8::Array> Accessor::Info::enumerateNames() {
Accessor accessor(info->Data());
return Array(rb_funcall(accessor.enumerator, rb_intern("call"), 1, (VALUE)*this));
}
v8::Handle<v8::Value> Accessor::Info::get(uint32_t index) {
Accessor accessor(info->Data());
return Value(rb_funcall(accessor.get, rb_intern("call"), 2, (VALUE)String(index), (VALUE)*this));
}
v8::Handle<v8::Value> Accessor::Info::set(uint32_t index, v8::Local<v8::Value> value) {
Accessor accessor(info->Data());
return Value(rb_funcall(accessor.set, rb_intern("call"), 3, UINT2NUM(index), (VALUE)Value(value), (VALUE)*this));
}
v8::Handle<v8::Integer> Accessor::Info::query(uint32_t index) {
Accessor accessor(info->Data());
return v8::Integer::New(Int(rb_funcall(accessor.query, rb_intern("call"), 2, UINT2NUM(index), (VALUE)*this)));
}
v8::Handle<v8::Boolean> Accessor::Info::remove(uint32_t index) {
Accessor accessor(info->Data());
return v8::Boolean::New(Bool(rb_funcall(accessor.deleter, rb_intern("call"), 2, UINT2NUM(index), (VALUE)*this)));
}
v8::Handle<v8::Array> Accessor::Info::enumerateIndices() {
Accessor accessor(info->Data());
return Array(rb_funcall(accessor.enumerator, rb_intern("call"), 1, (VALUE)*this));
}
Accessor::Info::operator VALUE() {
return Data_Wrap_Struct(Class, 0, 0, (void*)this->info);
}

View File

@ -21,12 +21,12 @@ namespace rr {
} else {
VALUE argc; VALUE argv;
rb_scan_args(i,v,"2", &argc, &argv);
std::vector< v8::Handle<v8::Value> > arguments(Int(argc));
std::vector< v8::Handle<v8::Value> > arguments(Int(argc).toInt());
return Object(Function(self)->NewInstance(Int(argc), Value::array(argv, arguments)));
}
}
VALUE Function::Call(VALUE self, VALUE receiver, VALUE argc, VALUE argv) {
std::vector< v8::Handle<v8::Value> > arguments(Int(argc));
std::vector< v8::Handle<v8::Value> > arguments(Int(argc).toInt());
return Value(Function(self)->Call(Object(receiver), Int(argc), Value::array(argv, arguments)));
}

View File

@ -121,7 +121,14 @@ 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 access(get, set, data);
return Bool(Object(self)->SetAccessor(String(name), access, access, access, AccessControl(settings), PropertyAttribute(attribs)));
return Bool(Object(self)->SetAccessor(
String(name),
access.accessorGetter(),
access.accessorSetter(),
access,
AccessControl(settings),
PropertyAttribute(attribs))
);
}
Object::operator VALUE() {

View File

@ -8,12 +8,38 @@
namespace rr {
#define Void(expr) expr; return Qnil;
VALUE Bool(bool b);
int Int(VALUE v);
uint32_t UInt32(VALUE num);
VALUE not_implemented(const char* message);
class Equiv {
public:
Equiv(VALUE val) : value(val) {}
inline operator VALUE() {return value;}
protected:
VALUE value;
};
class Bool : public Equiv {
public:
Bool(VALUE val) : Equiv(val) {}
Bool(bool b) : Equiv(b ? Qtrue : Qfalse) {}
inline operator bool() {return RTEST(value);}
};
class Int : public Equiv {
public:
Int(VALUE val) : Equiv(val) {}
Int(int i) : Equiv(INT2FIX(i)) {}
inline operator int() {return RTEST(value) ? NUM2INT(value) : 0;}
inline int toInt() {return (int)*this;}
};
class UInt32 : public Equiv {
public:
UInt32(VALUE val) : Equiv(val) {}
UInt32(uint32_t ui) : Equiv(UINT2NUM(ui)) {}
inline operator uint32_t() {return RTEST(value) ? NUM2UINT(value) : 0;}
};
class GC {
public:
class Queue {
@ -224,12 +250,25 @@ class Accessor {
public:
static void Init();
Accessor(VALUE get, VALUE set, VALUE data);
Accessor(VALUE get, VALUE set, VALUE query, VALUE deleter, VALUE enumerator, VALUE data);
Accessor(v8::Handle<v8::Value> value);
operator v8::AccessorGetter();
operator v8::AccessorSetter();
inline v8::AccessorGetter accessorGetter() {return &AccessorGetter;}
inline v8::AccessorSetter accessorSetter() {return RTEST(set) ? &AccessorSetter : 0;}
inline v8::NamedPropertyGetter namedPropertyGetter() {return &NamedPropertyGetter;}
inline v8::NamedPropertySetter namedPropertySetter() {return RTEST(set) ? &NamedPropertySetter : 0;}
inline v8::NamedPropertyQuery namedPropertyQuery() {return RTEST(query) ? &NamedPropertyQuery : 0;}
inline v8::NamedPropertyDeleter namedPropertyDeleter() {return RTEST(deleter) ? &NamedPropertyDeleter : 0;}
inline v8::NamedPropertyEnumerator namedPropertyEnumerator() {return RTEST(enumerator) ? &NamedPropertyEnumerator : 0;}
inline v8::IndexedPropertyGetter indexedPropertyGetter() {return &IndexedPropertyGetter;}
inline v8::IndexedPropertySetter indexedPropertySetter() {return RTEST(set) ? &IndexedPropertySetter : 0;}
inline v8::IndexedPropertyQuery indexedPropertyQuery() {return RTEST(query) ? &IndexedPropertyQuery : 0;}
inline v8::IndexedPropertyDeleter indexedPropertyDeleter() {return RTEST(deleter) ? &IndexedPropertyDeleter : 0;}
inline v8::IndexedPropertyEnumerator indexedPropertyEnumerator() {return RTEST(enumerator) ? &IndexedPropertyEnumerator : 0;}
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:
@ -241,7 +280,15 @@ public:
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);
v8::Handle<v8::Value> set(v8::Local<v8::String> property, v8::Local<v8::Value> value);
v8::Handle<v8::Integer> query(v8::Local<v8::String> property);
v8::Handle<v8::Boolean> remove(v8::Local<v8::String> property);
v8::Handle<v8::Array> enumerateNames();
v8::Handle<v8::Value> get(uint32_t index);
v8::Handle<v8::Value> set(uint32_t index, v8::Local<v8::Value> value);
v8::Handle<v8::Integer> query(uint32_t index);
v8::Handle<v8::Boolean> remove(uint32_t index);
v8::Handle<v8::Array> enumerateIndices();
static VALUE Class;
private:
@ -249,10 +296,28 @@ public:
};
friend class Info;
private:
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);
static v8::Handle<v8::Value> NamedPropertyGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
static v8::Handle<v8::Value> NamedPropertySetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
static v8::Handle<v8::Integer> NamedPropertyQuery(v8::Local<v8::String> property, const v8::AccessorInfo& info);
static v8::Handle<v8::Boolean> NamedPropertyDeleter(v8::Local<v8::String> property, const v8::AccessorInfo& info);
static v8::Handle<v8::Array> NamedPropertyEnumerator(const v8::AccessorInfo& info);
static v8::Handle<v8::Value> IndexedPropertyGetter(uint32_t index, const v8::AccessorInfo& info);
static v8::Handle<v8::Value> IndexedPropertySetter(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
static v8::Handle<v8::Integer> IndexedPropertyQuery(uint32_t index, const v8::AccessorInfo& info);
static v8::Handle<v8::Boolean> IndexedPropertyDeleter(uint32_t index, const v8::AccessorInfo& info);
static v8::Handle<v8::Array> IndexedPropertyEnumerator(const v8::AccessorInfo& info);
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 query;
VALUE deleter;
VALUE enumerator;
VALUE data;
};
@ -392,6 +457,16 @@ public:
class ObjectTemplate : public Ref<v8::ObjectTemplate> {
public:
static void Init();
static VALUE New(VALUE self);
static VALUE NewInstance(VALUE self);
static VALUE SetAccessor(int argc, VALUE argv[], VALUE self);
static VALUE SetNamedPropertyHandler(int argc, VALUE argv[], VALUE self);
static VALUE SetIndexedPropertyHandler(int argc, VALUE argv[], VALUE self);
static VALUE SetCallAsFunctionHandler(int argc, VALUE argv[], VALUE self);
static VALUE MarkAsUndetectable(VALUE self);
static VALUE SetAccessCheckCallbacks(int argc, VALUE argv[], VALUE self);
static VALUE InternalFieldCount(VALUE self);
static VALUE SetInternalFieldCount(VALUE self, VALUE count);
inline ObjectTemplate(VALUE value) : Ref<v8::ObjectTemplate>(value) {}
inline ObjectTemplate(v8::Handle<v8::ObjectTemplate> t) : Ref<v8::ObjectTemplate>(t) {}

View File

@ -10,7 +10,7 @@ namespace rr {
VALUE Signature::New(int length, VALUE args[], VALUE self) {
VALUE receiver; VALUE argc; VALUE argv;
rb_scan_args(length, args, "03", &receiver, &argc, &argv);
std::vector< v8::Handle<v8::FunctionTemplate> > parameters(Int(argc));
std::vector< v8::Handle<v8::FunctionTemplate> > parameters(Int(argc).toInt());
return Signature(v8::Signature::New(FunctionTemplate(receiver), Int(argc), FunctionTemplate::array(argv, parameters)));
}
}

View File

@ -9,9 +9,98 @@ namespace rr {
void ObjectTemplate::Init() {
ClassBuilder("ObjectTemplate", "Template").
defineSingletonMethod("New", &New).
defineMethod("NewInstance", &NewInstance).
defineMethod("SetAccessor", &SetAccessor).
defineMethod("SetNamedPropertyHandler", &SetNamedPropertyHandler).
defineMethod("SetIndexedPropertyHandler", &SetIndexedPropertyHandler).
defineMethod("SetCallAsFunctionHandler", &SetCallAsFunctionHandler).
defineMethod("MarkAsUndetectable", &MarkAsUndetectable).
defineMethod("SetAccessCheckCallbacks", &SetAccessCheckCallbacks).
defineMethod("InternalFieldCount", &InternalFieldCount).
defineMethod("SetInternalFieldCount", &SetInternalFieldCount).
store(&Class);
}
VALUE ObjectTemplate::New(VALUE self) {
return ObjectTemplate(v8::ObjectTemplate::New());
}
VALUE ObjectTemplate::NewInstance(VALUE self) {
return Object(ObjectTemplate(self)->NewInstance());
}
VALUE ObjectTemplate::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 accessor(get, set, data);
ObjectTemplate(self)->SetAccessor(
String(name),
accessor.accessorGetter(),
accessor.accessorSetter(),
accessor,
AccessControl(settings),
PropertyAttribute(attribs)
);
Void();
}
VALUE ObjectTemplate::SetNamedPropertyHandler(int argc, VALUE argv[], VALUE self) {
VALUE get; VALUE set; VALUE query; VALUE deleter; VALUE enumerator; VALUE data;
rb_scan_args(argc, argv, "15", &get, &set, &query, &deleter, &enumerator, &data);
Accessor accessor(get,set,query,deleter,enumerator,data);
ObjectTemplate(self)->SetNamedPropertyHandler(
accessor.namedPropertyGetter(),
accessor.namedPropertySetter(),
accessor.namedPropertyQuery(),
accessor.namedPropertyDeleter(),
accessor.namedPropertyEnumerator(),
accessor
);
Void();
}
VALUE ObjectTemplate::SetIndexedPropertyHandler(int argc, VALUE argv[], VALUE self) {
VALUE get; VALUE set; VALUE query; VALUE deleter; VALUE enumerator; VALUE data;
rb_scan_args(argc, argv, "15", &get, &set, &query, &deleter, &enumerator, &data);
Accessor accessor(get,set,query,deleter,enumerator,data);
ObjectTemplate(self)->SetIndexedPropertyHandler(
accessor.indexedPropertyGetter(),
accessor.indexedPropertySetter(),
accessor.indexedPropertyQuery(),
accessor.indexedPropertyDeleter(),
accessor.indexedPropertyEnumerator(),
accessor
);
Void();
}
VALUE ObjectTemplate::SetCallAsFunctionHandler(int argc, VALUE argv[], VALUE self) {
VALUE callback; VALUE data;
rb_scan_args(argc, argv, "11", &callback, &data);
Invocation invocation(callback, data);
Void(ObjectTemplate(self)->SetCallAsFunctionHandler(invocation, invocation));
}
VALUE ObjectTemplate::MarkAsUndetectable(VALUE self) {
Void(ObjectTemplate(self)->MarkAsUndetectable());
}
VALUE ObjectTemplate::SetAccessCheckCallbacks(int argc, VALUE argv[], VALUE self) {
VALUE named_handler; VALUE indexed_handler; VALUE data; VALUE turned_on_by_default;
rb_scan_args(argc, argv, "22", &named_handler, &indexed_handler, &data, &turned_on_by_default);
return not_implemented("ObjectTemplate::SetAccessCheckCallbacks");
}
VALUE ObjectTemplate::InternalFieldCount(VALUE self) {
return INT2FIX(ObjectTemplate(self)->InternalFieldCount());
}
VALUE ObjectTemplate::SetInternalFieldCount(VALUE self, VALUE count) {
Void(ObjectTemplate(self)->SetInternalFieldCount(Int(count)));
}
void FunctionTemplate::Init() {
ClassBuilder("FunctionTemplate", "Template").
defineSingletonMethod("New", &New).