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

add Context#dispose() for explicit teardown.

This commit is contained in:
Charles Lowell 2012-06-19 04:32:58 -05:00
parent 22f21e7c86
commit 8693cddf0a
6 changed files with 116 additions and 5 deletions

View file

@ -9,6 +9,7 @@ void Context::Init() {
defineSingletonMethod("GetEntered", &GetEntered).
defineSingletonMethod("GetCalling", &GetCalling).
defineSingletonMethod("InContext", &InContext).
defineMethod("Dispose", &Dispose).
defineMethod("Global", &Global).
defineMethod("DetachGlobal", &Global).
defineMethod("ReattachGlobal", &ReattachGlobal).
@ -28,6 +29,10 @@ void Context::Init() {
store(&ExtensionConfiguration::Class);
}
VALUE Context::Dispose(VALUE self) {
Void(Context(self).dispose())
}
VALUE Context::Global(VALUE self) {
return Object(Context(self)->Global());
}

View file

@ -131,6 +131,11 @@ public:
return v8::Handle<T>();
}
}
void dispose() {
Holder* holder = NULL;
Data_Get_Struct(this->value, class Holder, holder);
holder->dispose();
}
inline v8::Handle<T> operator->() const { return *this;}
inline v8::Handle<T> operator*() const {return *this;}
@ -153,15 +158,23 @@ public:
friend class Ref;
public:
Holder(v8::Handle<T> handle, VALUE klass) {
this->disposed_p = false;
this->handle = v8::Persistent<T>::New(handle);
this->value = Data_Wrap_Struct(klass, 0, &enqueue, this);
}
virtual ~Holder() {
handle.Dispose();
this->dispose();
}
void dispose() {
if (!this->disposed_p) {
handle.Dispose();
this->disposed_p = true;
}
}
protected:
VALUE value;
v8::Persistent<T> handle;
bool disposed_p;
static void enqueue(Holder* holder) {
holder->value = Qnil;
@ -225,6 +238,7 @@ class Context : public Ref<v8::Context> {
public:
static void Init();
static VALUE New(int argc, VALUE argv[], VALUE self);
static VALUE Dispose(VALUE self);
static VALUE Enter(VALUE self);
static VALUE Exit(VALUE self);
static VALUE Global(VALUE self);
@ -800,6 +814,19 @@ class V8 {
public:
static void Init();
static VALUE IdleNotification(int argc, VALUE argv[], VALUE self);
static VALUE SetFlagsFromString(VALUE self, VALUE string);
static VALUE SetFlagsFromCommandLine(VALUE self, VALUE args, VALUE remove_flags);
static VALUE AdjustAmountOfExternalAllocatedMemory(VALUE self, VALUE change_in_bytes);
static VALUE PauseProfiler(VALUE self);
static VALUE ResumeProfiler(VALUE self);
static VALUE IsProfilerPaused(VALUE self);
static VALUE GetCurrentThreadId(VALUE self);
static VALUE TerminateExecution(VALUE self, VALUE thread_id);
static VALUE IsExecutionTerminating(VALUE self);
static VALUE Dispose(VALUE self);
static VALUE LowMemoryNotification(VALUE self);
static VALUE ContextDisposedNotification(VALUE self);
static VALUE SetCaptureStackTraceForUncaughtExceptions(int argc, VALUE argv[], VALUE self);
static VALUE GetHeapStatistics(VALUE self, VALUE statistics_ptr);
static VALUE GetVersion(VALUE self);

View file

@ -5,7 +5,18 @@ namespace rr {
void V8::Init() {
ClassBuilder("V8").
defineSingletonMethod("IdleNotification", &IdleNotification).
defineSingletonMethod("SetCaptureStackTraceForUncaughtExceptions", &SetCaptureStackTraceForUncaughtExceptions).
defineSingletonMethod("SetFlagsFromString", &SetFlagsFromString).
defineSingletonMethod("SetFlagsFromCommandLine", &SetFlagsFromCommandLine).
defineSingletonMethod("PauseProfiler", &PauseProfiler).
defineSingletonMethod("ResumeProfiler", &ResumeProfiler).
defineSingletonMethod("IsProfilerPaused", &IsProfilerPaused).
defineSingletonMethod("GetCurrentThreadId", &GetCurrentThreadId).
defineSingletonMethod("TerminateExecution", &TerminateExecution).
defineSingletonMethod("IsExecutionTerminating", &IsExecutionTerminating).
defineSingletonMethod("Dispose", &Dispose).
defineSingletonMethod("LowMemoryNotification", &LowMemoryNotification).
defineSingletonMethod("AdjustAmountOfExternalAllocatedMemory", &AdjustAmountOfExternalAllocatedMemory).
defineSingletonMethod("ContextDisposedNotification", &ContextDisposedNotification).
defineSingletonMethod("GetHeapStatistics", &GetHeapStatistics).
defineSingletonMethod("GetVersion", &GetVersion);
}
@ -19,18 +30,56 @@ VALUE V8::IdleNotification(int argc, VALUE argv[], VALUE self) {
return Bool(v8::V8::IdleNotification());
}
}
VALUE V8::SetFlagsFromString(VALUE self, VALUE string) {
Void(v8::V8::SetFlagsFromString(RSTRING_PTR(string), (int)RSTRING_LEN(string)));
}
VALUE V8::SetFlagsFromCommandLine(VALUE self, VALUE args, VALUE remove_flags) {
int argc = RARRAY_LENINT(args);
char* argv[argc];
for(int i = 0; i < argc; i++) {
argv[i] = RSTRING_PTR(rb_ary_entry(args, i));
}
Void(v8::V8::SetFlagsFromCommandLine(&argc, argv, Bool(remove_flags)));
}
VALUE V8::AdjustAmountOfExternalAllocatedMemory(VALUE self, VALUE change_in_bytes) {
return SIZET2NUM(v8::V8::AdjustAmountOfExternalAllocatedMemory(NUM2SIZET(change_in_bytes)));
}
VALUE V8::PauseProfiler(VALUE self) {
Void(v8::V8::PauseProfiler());
}
VALUE V8::ResumeProfiler(VALUE self) {
Void(v8::V8::ResumeProfiler());
}
VALUE V8::IsProfilerPaused(VALUE self) {
return Bool(v8::V8::IsProfilerPaused());
}
VALUE V8::GetCurrentThreadId(VALUE self) {
return INT2FIX(v8::V8::GetCurrentThreadId());
}
VALUE V8::TerminateExecution(VALUE self, VALUE thread_id) {
Void(v8::V8::TerminateExecution(NUM2INT(thread_id)));
}
VALUE V8::IsExecutionTerminating(VALUE self) {
return Bool(v8::V8::IsExecutionTerminating());
}
VALUE V8::Dispose(VALUE self) {
Void(v8::V8::Dispose());
}
VALUE V8::LowMemoryNotification(VALUE self) {
Void(v8::V8::LowMemoryNotification());
}
VALUE V8::ContextDisposedNotification(VALUE self) {
return INT2FIX(v8::V8::ContextDisposedNotification());
}
VALUE V8::SetCaptureStackTraceForUncaughtExceptions(int argc, VALUE argv[], VALUE self) {
VALUE should_capture; VALUE frame_limit; VALUE options;
rb_scan_args(argc, argv, "12", &should_capture, &frame_limit, &options);
int limit = RTEST(frame_limit) ? NUM2INT(frame_limit) : 10;
Void(v8::V8::SetCaptureStackTraceForUncaughtExceptions(Bool(should_capture), limit, Stack::Trace::StackTraceOptions(options)));
}
VALUE V8::GetHeapStatistics(VALUE self, VALUE statistics_ptr) {
Void(v8::V8::GetHeapStatistics(HeapStatistics(statistics_ptr)));
}
VALUE V8::GetVersion(VALUE self) {
return rb_str_new2(v8::V8::GetVersion());
}

View file

@ -42,6 +42,16 @@ module V8
return value
end
def dispose
return unless @native
@native.Dispose()
@native = nil
V8::C::V8::ContextDisposedNotification()
def self.enter
fail "cannot enter a context which has already been disposed"
end
end
def scope
enter { to_ruby @native.Global() }
end

View file

@ -1,6 +1,7 @@
require 'v8'
def run_v8_gc
V8::C::V8::LowMemoryNotification()
while !V8::C::V8::IdleNotification() do
end
end

19
spec/v8/context_spec.rb Normal file
View file

@ -0,0 +1,19 @@
require 'spec_helper'
describe V8::Context do
it "can be disposed of" do
cxt = V8::Context.new
cxt.enter do
cxt['object'] = V8::Object.new
end
cxt.dispose()
lambda {cxt.eval('1 + 1')}.should raise_error
lambda {cxt['object']}.should raise_error
end
it "can be disposed of any number of times" do
cxt = V8::Context.new
10.times {cxt.dispose()}
end
end