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() {
|
||||
GC::Init();
|
||||
V8::Init();
|
||||
Handles::Init();
|
||||
Context::Init();
|
||||
Value::Init();
|
||||
String::Init();
|
||||
Object::Init();
|
||||
External::Init();
|
||||
Script::Init();
|
||||
}
|
||||
}
|
|
@ -78,16 +78,17 @@ VALUE Object::ForceDelete(VALUE self, VALUE key) {
|
|||
}
|
||||
|
||||
|
||||
// VALUE Object::SetAccessor(int argc, VALUE* argv, VALUE self) {
|
||||
// VALUE name; VALUE getter; VALUE setter; VALUE data; VALUE settings, VALUE attribs;
|
||||
// rb_scan_args(argc, argv, "24", name, getter, setter, data, settings, attribs);
|
||||
// return Convert(Object(self)->SetAccessor(String(name),
|
||||
// AccessorGetter(getter),
|
||||
// AccessorSetter(setter),
|
||||
// Value(data),
|
||||
// AccessControl(settings),
|
||||
// PropertyAttribute(attribs)));
|
||||
// }
|
||||
VALUE Object::SetAccessor(int argc, VALUE* argv, VALUE self) {
|
||||
VALUE name; VALUE getter; VALUE setter; VALUE data; VALUE settings; VALUE attribs;
|
||||
rb_scan_args(argc, argv, "24", name, getter, setter, data, settings, attribs);
|
||||
return Qfalse;
|
||||
// return Convert(Object(self)->SetAccessor(String(name),
|
||||
// AccessorGetter(getter),
|
||||
// AccessorSetter(setter),
|
||||
// Value(data),
|
||||
// AccessControl(settings),
|
||||
// PropertyAttribute(attribs)));
|
||||
}
|
||||
// V8EXPORT bool SetAccessor(Handle<String> name,
|
||||
// AccessorGetter getter,
|
||||
// AccessorSetter setter = 0,
|
||||
|
|
24
ext/v8/rr.h
24
ext/v8/rr.h
|
@ -94,6 +94,15 @@ public:
|
|||
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> {
|
||||
public:
|
||||
inline Phantom(void* reference) : Ref<void>((Ref<void>::Holder*)reference) {}
|
||||
|
@ -116,6 +125,21 @@ private:
|
|||
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> {
|
||||
public:
|
||||
static void Init();
|
||||
|
|
|
@ -9,12 +9,10 @@ void Script::Init() {
|
|||
}
|
||||
|
||||
VALUE Script::New(VALUE klass, VALUE source, VALUE filename) {
|
||||
v8::HandleScope scope;
|
||||
return Script::create(v8::Script::New(String(source), Value(filename)), klass);
|
||||
}
|
||||
|
||||
VALUE Script::Run(VALUE self) {
|
||||
v8::HandleScope scope;
|
||||
return Convert(Script(self)->Run());
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,10 @@ void String::Init() {
|
|||
}
|
||||
|
||||
VALUE String::New(VALUE StringClass, VALUE string) {
|
||||
v8::HandleScope h;
|
||||
return String::Convert(v8::String::New(RSTRING_PTR(string), (int)RSTRING_LEN(string)));
|
||||
}
|
||||
|
||||
VALUE String::Utf8Value(VALUE self) {
|
||||
v8::HandleScope h;
|
||||
String str(self);
|
||||
return rb_str_new(*v8::String::Utf8Value(str.GetHandle()), str->Utf8Length());
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@ module V8
|
|||
|
||||
def eval(source, filename = '<eval>', line = 1)
|
||||
@native.Enter()
|
||||
source = V8::C::String::New(source.to_s)
|
||||
filename = V8::C::String::New(filename.to_s)
|
||||
script = V8::C::Script::New(source, filename)
|
||||
result = script.Run()
|
||||
result.kind_of?(V8::C::String) ? result.Utf8Value() : result
|
||||
V8::C::HandleScope() do
|
||||
source = V8::C::String::New(source.to_s)
|
||||
filename = V8::C::String::New(filename.to_s)
|
||||
script = V8::C::Script::New(source, filename)
|
||||
result = script.Run()
|
||||
result.kind_of?(V8::C::String) ? result.Utf8Value() : result
|
||||
end
|
||||
ensure
|
||||
@native.Exit()
|
||||
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
|
||||
5000.times do
|
||||
V8::Context.new
|
||||
gc_completely
|
||||
run_v8_gc
|
||||
end
|
||||
process_memory.should <= @start_memory * 1.2
|
||||
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
|
||||
end
|
||||
|
||||
def gc_completely
|
||||
loop while !V8::C::V8::IdleNotification()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
require 'v8'
|
||||
|
||||
def run_v8_gc
|
||||
loop while !V8::C::V8::IdleNotification()
|
||||
end
|
||||
|
||||
def rputs(msg)
|
||||
puts "<pre>#{ERB::Util.h(msg)}</pre>"
|
||||
$stdout.flush
|
||||
|
|
Loading…
Reference in a new issue