mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
Create HandleScopes, Externals from Ruby.
This commit is contained in:
parent
28475caab3
commit
0800d82988
12 changed files with 155 additions and 24 deletions
32
ext/v8/external.cc
Normal file
32
ext/v8/external.cc
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
namespace rr {
|
||||||
|
|
||||||
|
void External::Init() {
|
||||||
|
ClassBuilder("External", "Value").
|
||||||
|
defineSingletonMethod("New", &New).
|
||||||
|
defineMethod("Value", &Value);
|
||||||
|
}
|
||||||
|
VALUE External::New(VALUE self, VALUE data) {
|
||||||
|
Data* holder = new Data(data);
|
||||||
|
v8::Local<v8::External> ext = v8::External::New(holder);
|
||||||
|
v8::Persistent<v8::External>::New(ext).MakeWeak(holder, &release);
|
||||||
|
return External::create(ext, self);
|
||||||
|
}
|
||||||
|
VALUE External::Value(VALUE self) {
|
||||||
|
Data* data = (Data*)(External(self)->Value());
|
||||||
|
return data->value;
|
||||||
|
}
|
||||||
|
void External::release(v8::Persistent<v8::Value> handle, void* parameter) {
|
||||||
|
handle.Dispose();
|
||||||
|
Data* data = (Data*)parameter;
|
||||||
|
delete data;
|
||||||
|
}
|
||||||
|
External::Data::Data(VALUE data) {
|
||||||
|
this->value = data;
|
||||||
|
rb_gc_register_address(&value);
|
||||||
|
}
|
||||||
|
External::Data::~Data() {
|
||||||
|
rb_gc_unregister_address(&value);
|
||||||
|
}
|
||||||
|
}
|
34
ext/v8/handles.cc
Normal file
34
ext/v8/handles.cc
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "rr.h"
|
||||||
|
|
||||||
|
namespace rr {
|
||||||
|
|
||||||
|
void Handles::Init() {
|
||||||
|
VALUE v8 = rb_define_module("V8");
|
||||||
|
VALUE c = rb_define_module_under(v8, "C");
|
||||||
|
rb_define_singleton_method(c, "HandleScope", (VALUE (*)(...))&HandleScope, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE Handles::HandleScope(int argc, VALUE* argv, VALUE self) {
|
||||||
|
if (!rb_block_given_p()) {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
int state = 0;
|
||||||
|
VALUE code;
|
||||||
|
rb_scan_args(argc,argv,"00&", &code);
|
||||||
|
VALUE result = SetupAndCall(&state, code);
|
||||||
|
if (state != 0) {
|
||||||
|
rb_jump_tag(state);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE Handles::SetupAndCall(int* state, VALUE code) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
return rb_protect(&DoCall, code, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE Handles::DoCall(VALUE code) {
|
||||||
|
return rb_funcall(code, rb_intern("call"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,10 +10,12 @@ extern "C" {
|
||||||
void Init_init() {
|
void Init_init() {
|
||||||
GC::Init();
|
GC::Init();
|
||||||
V8::Init();
|
V8::Init();
|
||||||
|
Handles::Init();
|
||||||
Context::Init();
|
Context::Init();
|
||||||
Value::Init();
|
Value::Init();
|
||||||
String::Init();
|
String::Init();
|
||||||
Object::Init();
|
Object::Init();
|
||||||
|
External::Init();
|
||||||
Script::Init();
|
Script::Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -78,16 +78,17 @@ VALUE Object::ForceDelete(VALUE self, VALUE key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// VALUE Object::SetAccessor(int argc, VALUE* argv, VALUE self) {
|
VALUE Object::SetAccessor(int argc, VALUE* argv, VALUE self) {
|
||||||
// VALUE name; VALUE getter; VALUE setter; VALUE data; VALUE settings, VALUE attribs;
|
VALUE name; VALUE getter; VALUE setter; VALUE data; VALUE settings; VALUE attribs;
|
||||||
// rb_scan_args(argc, argv, "24", name, getter, setter, data, settings, attribs);
|
rb_scan_args(argc, argv, "24", name, getter, setter, data, settings, attribs);
|
||||||
// return Convert(Object(self)->SetAccessor(String(name),
|
return Qfalse;
|
||||||
// AccessorGetter(getter),
|
// return Convert(Object(self)->SetAccessor(String(name),
|
||||||
// AccessorSetter(setter),
|
// AccessorGetter(getter),
|
||||||
// Value(data),
|
// AccessorSetter(setter),
|
||||||
// AccessControl(settings),
|
// Value(data),
|
||||||
// PropertyAttribute(attribs)));
|
// AccessControl(settings),
|
||||||
// }
|
// PropertyAttribute(attribs)));
|
||||||
|
}
|
||||||
// V8EXPORT bool SetAccessor(Handle<String> name,
|
// V8EXPORT bool SetAccessor(Handle<String> name,
|
||||||
// AccessorGetter getter,
|
// AccessorGetter getter,
|
||||||
// AccessorSetter setter = 0,
|
// AccessorSetter setter = 0,
|
||||||
|
|
24
ext/v8/rr.h
24
ext/v8/rr.h
|
@ -94,6 +94,15 @@ public:
|
||||||
Holder* holder;
|
Holder* holder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Handles {
|
||||||
|
public:
|
||||||
|
static void Init();
|
||||||
|
static VALUE HandleScope(int argc, VALUE* argv, VALUE self);
|
||||||
|
private:
|
||||||
|
static VALUE SetupAndCall(int* state, VALUE code);
|
||||||
|
static VALUE DoCall(VALUE code);
|
||||||
|
};
|
||||||
|
|
||||||
class Phantom : public Ref<void> {
|
class Phantom : public Ref<void> {
|
||||||
public:
|
public:
|
||||||
inline Phantom(void* reference) : Ref<void>((Ref<void>::Holder*)reference) {}
|
inline Phantom(void* reference) : Ref<void>((Ref<void>::Holder*)reference) {}
|
||||||
|
@ -116,6 +125,21 @@ private:
|
||||||
inline Context(VALUE value) : Ref<v8::Context>(value) {}
|
inline Context(VALUE value) : Ref<v8::Context>(value) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class External: public Ref<v8::External> {
|
||||||
|
public:
|
||||||
|
inline External(VALUE value) : Ref<v8::External>(value) {}
|
||||||
|
static void Init();
|
||||||
|
static VALUE New(VALUE self, VALUE data);
|
||||||
|
static VALUE Value(VALUE self);
|
||||||
|
private:
|
||||||
|
static void release(v8::Persistent<v8::Value> object, void* parameter);
|
||||||
|
struct Data {
|
||||||
|
Data(VALUE data);
|
||||||
|
~Data();
|
||||||
|
VALUE value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
class Script : public Ref<v8::Script> {
|
class Script : public Ref<v8::Script> {
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
|
|
|
@ -9,12 +9,10 @@ void Script::Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE Script::New(VALUE klass, VALUE source, VALUE filename) {
|
VALUE Script::New(VALUE klass, VALUE source, VALUE filename) {
|
||||||
v8::HandleScope scope;
|
|
||||||
return Script::create(v8::Script::New(String(source), Value(filename)), klass);
|
return Script::create(v8::Script::New(String(source), Value(filename)), klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE Script::Run(VALUE self) {
|
VALUE Script::Run(VALUE self) {
|
||||||
v8::HandleScope scope;
|
|
||||||
return Convert(Script(self)->Run());
|
return Convert(Script(self)->Run());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,10 @@ void String::Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE String::New(VALUE StringClass, VALUE string) {
|
VALUE String::New(VALUE StringClass, VALUE string) {
|
||||||
v8::HandleScope h;
|
|
||||||
return String::Convert(v8::String::New(RSTRING_PTR(string), (int)RSTRING_LEN(string)));
|
return String::Convert(v8::String::New(RSTRING_PTR(string), (int)RSTRING_LEN(string)));
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE String::Utf8Value(VALUE self) {
|
VALUE String::Utf8Value(VALUE self) {
|
||||||
v8::HandleScope h;
|
|
||||||
String str(self);
|
String str(self);
|
||||||
return rb_str_new(*v8::String::Utf8Value(str.GetHandle()), str->Utf8Length());
|
return rb_str_new(*v8::String::Utf8Value(str.GetHandle()), str->Utf8Length());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,13 @@ module V8
|
||||||
|
|
||||||
def eval(source, filename = '<eval>', line = 1)
|
def eval(source, filename = '<eval>', line = 1)
|
||||||
@native.Enter()
|
@native.Enter()
|
||||||
source = V8::C::String::New(source.to_s)
|
V8::C::HandleScope() do
|
||||||
filename = V8::C::String::New(filename.to_s)
|
source = V8::C::String::New(source.to_s)
|
||||||
script = V8::C::Script::New(source, filename)
|
filename = V8::C::String::New(filename.to_s)
|
||||||
result = script.Run()
|
script = V8::C::Script::New(source, filename)
|
||||||
result.kind_of?(V8::C::String) ? result.Utf8Value() : result
|
result = script.Run()
|
||||||
|
result.kind_of?(V8::C::String) ? result.Utf8Value() : result
|
||||||
|
end
|
||||||
ensure
|
ensure
|
||||||
@native.Exit()
|
@native.Exit()
|
||||||
end
|
end
|
||||||
|
|
18
spec/c/external_spec.rb
Normal file
18
spec/c/external_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe V8::C::External do
|
||||||
|
before do
|
||||||
|
@cxt = V8::C::Context::New()
|
||||||
|
@cxt.Enter()
|
||||||
|
end
|
||||||
|
after do
|
||||||
|
@cxt.Exit()
|
||||||
|
end
|
||||||
|
it "can store and retrieve a value" do
|
||||||
|
V8::C::HandleScope() do
|
||||||
|
o = Object.new
|
||||||
|
external = V8::C::External::New(o)
|
||||||
|
external.Value().should be(o)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
22
spec/c/handles_spec.rb
Normal file
22
spec/c/handles_spec.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe "setting up handles scopes" do
|
||||||
|
before {@cxt = V8::C::Context::New()}
|
||||||
|
before {@cxt.Enter()}
|
||||||
|
after {@cxt.Exit()}
|
||||||
|
it "can allocate handle scopes" do
|
||||||
|
V8::C::HandleScope() do
|
||||||
|
V8::C::Object::New()
|
||||||
|
end.class.should eql V8::C::Object
|
||||||
|
end
|
||||||
|
|
||||||
|
it "isn't the end of the world if a ruby exception is raised inside a HandleScope" do
|
||||||
|
begin
|
||||||
|
V8::C::HandleScope() do
|
||||||
|
raise "boom!"
|
||||||
|
end
|
||||||
|
rescue StandardError => e
|
||||||
|
e.message.should eql "boom!"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,7 +15,7 @@ describe "A Very blunt test to make sure that we aren't doing stupid leaks" do
|
||||||
it "won't increase process memory by more than 20% no matter how many contexts we create" do
|
it "won't increase process memory by more than 20% no matter how many contexts we create" do
|
||||||
5000.times do
|
5000.times do
|
||||||
V8::Context.new
|
V8::Context.new
|
||||||
gc_completely
|
run_v8_gc
|
||||||
end
|
end
|
||||||
process_memory.should <= @start_memory * 1.2
|
process_memory.should <= @start_memory * 1.2
|
||||||
end
|
end
|
||||||
|
@ -24,9 +24,5 @@ describe "A Very blunt test to make sure that we aren't doing stupid leaks" do
|
||||||
/\w*[ ]*#{Process.pid}[ ]*([.,\d]*)[ ]*([.,\d]*)[ ]*([\d]*)[ ]*([\d]*)/.match(`ps aux`)[4].to_i
|
/\w*[ ]*#{Process.pid}[ ]*([.,\d]*)[ ]*([.,\d]*)[ ]*([\d]*)[ ]*([\d]*)/.match(`ps aux`)[4].to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
def gc_completely
|
|
||||||
loop while !V8::C::V8::IdleNotification()
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
require 'v8'
|
require 'v8'
|
||||||
|
|
||||||
|
def run_v8_gc
|
||||||
|
loop while !V8::C::V8::IdleNotification()
|
||||||
|
end
|
||||||
|
|
||||||
def rputs(msg)
|
def rputs(msg)
|
||||||
puts "<pre>#{ERB::Util.h(msg)}</pre>"
|
puts "<pre>#{ERB::Util.h(msg)}</pre>"
|
||||||
$stdout.flush
|
$stdout.flush
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue