1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

Never access V8 from within Ruby GC.

This commit is contained in:
Charles Lowell 2011-06-15 08:37:58 -05:00
parent ac42a9e295
commit 05e4c5766f
6 changed files with 42 additions and 14 deletions

View file

@ -10,13 +10,11 @@ v8_handle::v8_handle(Handle<void> handle) : handle(Persistent<void>::New(handle)
this->dead = false; this->dead = false;
} }
v8_handle::~v8_handle() { v8_handle::~v8_handle() {}
handle.Dispose();
handle.Clear();
dead = true;
}
namespace { namespace {
VALUE handle_queue;
void v8_handle_mark(v8_handle* handle) { void v8_handle_mark(v8_handle* handle) {
rb_gc_mark(handle->weakref_callback); rb_gc_mark(handle->weakref_callback);
rb_gc_mark(handle->weakref_callback_parameters); rb_gc_mark(handle->weakref_callback_parameters);
@ -26,6 +24,21 @@ namespace {
delete handle; delete handle;
} }
void v8_handle_enqueue(v8_handle* handle) {
handle->dead = true;
VALUE zombie = Data_Wrap_Struct(rr_v8_handle_class(), 0, v8_handle_free, handle);
rb_ary_unshift(handle_queue, zombie);
}
void v8_handle_dequeue(GCType type, GCCallbackFlags flags) {
for (VALUE handle = rb_ary_pop(handle_queue); RTEST(handle); handle = rb_ary_pop(handle_queue)) {
v8_handle* dead = NULL;
Data_Get_Struct(handle, struct v8_handle, dead);
dead->handle.Dispose();
dead->handle.Clear();
}
}
VALUE New(VALUE self, VALUE handle) { VALUE New(VALUE self, VALUE handle) {
if (RTEST(handle)) { if (RTEST(handle)) {
Persistent<void> that = rr_v8_handle<void>(handle); Persistent<void> that = rr_v8_handle<void>(handle);
@ -101,11 +114,15 @@ void rr_init_handle() {
rr_define_method(HandleClass, "ClearWeak", ClearWeak, 0); rr_define_method(HandleClass, "ClearWeak", ClearWeak, 0);
rr_define_method(HandleClass, "IsNearDeath", IsNearDeath, 0); rr_define_method(HandleClass, "IsNearDeath", IsNearDeath, 0);
rr_define_method(HandleClass, "IsWeak", IsWeak, 0); rr_define_method(HandleClass, "IsWeak", IsWeak, 0);
handle_queue = rb_ary_new();
rb_gc_register_address(&handle_queue);
V8::AddGCPrologueCallback(v8_handle_dequeue);
} }
VALUE rr_v8_handle_new(VALUE klass, v8::Handle<void> handle) { VALUE rr_v8_handle_new(VALUE klass, v8::Handle<void> handle) {
v8_handle* new_handle = new v8_handle(handle); v8_handle* new_handle = new v8_handle(handle);
return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_free, new_handle); return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_enqueue, new_handle);
} }
VALUE rr_v8_handle_class() { VALUE rr_v8_handle_class() {

View file

@ -66,8 +66,8 @@ namespace {
* For details on V8 locking semantics, see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html} * For details on V8 locking semantics, see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
* @return [V8::C::Unocker] the new locker * @return [V8::C::Unocker] the new locker
*/ */
VALUE New(VALUE UnockerClass) { VALUE New(VALUE UnlockerClass) {
Unlocker unlocker = new Unlocker(); Unlocker* unlocker = new Unlocker();
return Data_Wrap_Struct(UnlockerClass, 0, 0, (void*)unlocker); return Data_Wrap_Struct(UnlockerClass, 0, 0, (void*)unlocker);
} }
@ -80,7 +80,7 @@ namespace {
*/ */
VALUE Delete(VALUE self) { VALUE Delete(VALUE self) {
Unlocker* unlocker; Unlocker* unlocker;
Data_Get_Struct(self, class Locker, locker); Data_Get_Struct(self, class Unlocker, unlocker);
delete unlocker; delete unlocker;
} }
} }
@ -126,7 +126,6 @@ namespace {
} }
void rr_init_v8_locker() { void rr_init_v8_locker() {
VALUE V8 = rb_define_module("V8");
VALUE LockerClass = rr_define_class("Locker"); VALUE LockerClass = rr_define_class("Locker");
VALUE UnlockerClass = rr_define_class("Unlocker"); VALUE UnlockerClass = rr_define_class("Unlocker");
rr_define_singleton_method(LockerClass, "new", Lock::New, 0); rr_define_singleton_method(LockerClass, "new", Lock::New, 0);

View file

@ -4,6 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
module V8 module V8
require 'v8/version' require 'v8/version'
require 'v8/v8' #native glue require 'v8/v8' #native glue
require 'v8/c/locker'
require 'v8/portal' require 'v8/portal'
require 'v8/portal/caller' require 'v8/portal/caller'
require 'v8/portal/proxies' require 'v8/portal/proxies'

View file

@ -43,7 +43,6 @@ module V8
@js_proxies_js2rb[proxy] = target @js_proxies_js2rb[proxy] = target
@js_proxies_rb2js[target] = proxy @js_proxies_rb2js[target] = proxy
proxy.MakeWeak(nil, @clear_js_proxy) proxy.MakeWeak(nil, @clear_js_proxy)
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(16 * 1024)
end end
# Lookup the JavaScript proxy for a natively Ruby object # Lookup the JavaScript proxy for a natively Ruby object
@ -66,7 +65,6 @@ module V8
@rb_proxies_rb2js[proxy.object_id] = target @rb_proxies_rb2js[proxy.object_id] = target
@rb_proxies_js2rb[target] = proxy.object_id @rb_proxies_js2rb[target] = proxy.object_id
ObjectSpace.define_finalizer(proxy, @clear_rb_proxy) ObjectSpace.define_finalizer(proxy, @clear_rb_proxy)
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(8 * 1024)
end end
# Looks up the Ruby proxy for an object that is natively JavaScript # Looks up the Ruby proxy for an object that is natively JavaScript
@ -115,7 +113,6 @@ module V8
rb = @js2rb[proxy] rb = @js2rb[proxy]
@js2rb.delete(proxy) @js2rb.delete(proxy)
@rb2js.delete(rb) @rb2js.delete(rb)
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-16 * 1024)
end end
end end
@ -146,7 +143,6 @@ module V8
if js = @rb2js[proxy_id] if js = @rb2js[proxy_id]
@rb2js.delete(proxy_id) @rb2js.delete(proxy_id)
@js2rb.delete(js) @js2rb.delete(js)
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-8 * 1024)
end end
end end
end end

View file

@ -0,0 +1,2 @@
require Pathname(__FILE__).dirname.join('../spec/spec_helper')

View file

@ -0,0 +1,13 @@
require 'spec_helper'
describe "using v8 from multiple threads" do
it "is possible" do
Thread.new do
require 'v8'
V8::Context.new
end.join
V8::Context.new
end
end