From c9b43ff46c2e8c255cef34c32cce942db8456518 Mon Sep 17 00:00:00 2001 From: Charles Lowell <cowboyd@frontside.io> Date: Wed, 12 Aug 2015 20:18:55 +0300 Subject: [PATCH] Throw JavaScript exceptions from Ruby --- ext/v8/exception.h | 50 ++++++++++++++++++++++++++++++++++++++++ ext/v8/init.cc | 2 +- ext/v8/isolate.cc | 8 ++++++- ext/v8/isolate.h | 1 + ext/v8/rr.h | 1 + spec/c/try_catch_spec.rb | 10 +++++++- 6 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 ext/v8/exception.h diff --git a/ext/v8/exception.h b/ext/v8/exception.h new file mode 100644 index 0000000..37bc602 --- /dev/null +++ b/ext/v8/exception.h @@ -0,0 +1,50 @@ +// -*- mode: c++ -*- +#ifndef RR_EXCEPTION_H +#define RR_EXCEPTION_H +#include "rr.h" + +namespace rr { + class Exception { + public: + static inline void Init() { + ClassBuilder("Exception"). + defineSingletonMethod("RangeError", &RangeError). + defineSingletonMethod("ReferenceError", &ReferenceError). + defineSingletonMethod("SyntaxError", &SyntaxError). + defineSingletonMethod("TypeError", &TypeError). + defineSingletonMethod("Error", &Error); + } + + static VALUE RangeError(VALUE self, VALUE rb_message) { + String message(rb_message); + Locker lock(message); + return Value(message, v8::Exception::RangeError(message)); + } + + static VALUE ReferenceError(VALUE self, VALUE rb_message) { + String message(rb_message); + Locker lock(message); + return Value(message, v8::Exception::ReferenceError(message)); + } + + static VALUE SyntaxError(VALUE self, VALUE rb_message) { + String message(rb_message); + Locker lock(message); + return Value(message, v8::Exception::SyntaxError(message)); + } + + static VALUE TypeError(VALUE self, VALUE rb_message) { + String message(rb_message); + Locker lock(message); + return Value(message, v8::Exception::TypeError(message)); + } + + static VALUE Error(VALUE self, VALUE rb_message) { + String message(rb_message); + Locker lock(message); + return Value(message, v8::Exception::Error(message)); + } + }; +} + +#endif /* RR_EXCEPTION_H */ diff --git a/ext/v8/init.cc b/ext/v8/init.cc index 41c97d9..0a0a9a2 100644 --- a/ext/v8/init.cc +++ b/ext/v8/init.cc @@ -46,12 +46,12 @@ extern "C" { StackFrame::Init(); StackTrace::Init(); Message::Init(); + Exception::Init(); TryCatch::Init(); // Invocation::Init(); // Constants::Init(); // Template::Init(); - // Exception::Init(); // ResourceConstraints::Init(); // HeapStatistics::Init(); } diff --git a/ext/v8/isolate.cc b/ext/v8/isolate.cc index 2a63e21..97808d5 100644 --- a/ext/v8/isolate.cc +++ b/ext/v8/isolate.cc @@ -9,7 +9,7 @@ namespace rr { rb_eval_string("require 'v8/retained_objects'"); ClassBuilder("Isolate"). defineSingletonMethod("New", &New). - + defineMethod("ThrowException", &ThrowException). defineMethod("SetCaptureStackTraceForUncaughtExceptions", &SetCaptureStackTraceForUncaughtExceptions). defineMethod("IdleNotificationDeadline", &IdleNotificationDeadline). @@ -33,6 +33,12 @@ namespace rr { return Isolate(isolate); } + VALUE Isolate::ThrowException(VALUE self, VALUE error) { + Isolate isolate(self); + Locker lock(isolate); + return Value(isolate, isolate->ThrowException(Value(error))); + } + VALUE Isolate::SetCaptureStackTraceForUncaughtExceptions(VALUE self, VALUE capture, VALUE stack_limit, VALUE options) { Isolate isolate(self); Locker lock(isolate); diff --git a/ext/v8/isolate.h b/ext/v8/isolate.h index 0837bdb..9899a86 100644 --- a/ext/v8/isolate.h +++ b/ext/v8/isolate.h @@ -31,6 +31,7 @@ namespace rr { static VALUE New(VALUE self); static VALUE SetCaptureStackTraceForUncaughtExceptions(VALUE self, VALUE capture, VALUE stack_limit, VALUE options); + static VALUE ThrowException(VALUE self, VALUE error); inline Isolate(IsolateData* data_) : data(data_) {} inline Isolate(v8::Isolate* isolate) : diff --git a/ext/v8/rr.h b/ext/v8/rr.h index 0d1d8c6..37a5e4d 100644 --- a/ext/v8/rr.h +++ b/ext/v8/rr.h @@ -72,6 +72,7 @@ inline VALUE not_implemented(const char* message) { #include "stack-frame.h" #include "stack-trace.h" #include "message.h" +#include "exception.h" #include "try-catch.h" #endif diff --git a/spec/c/try_catch_spec.rb b/spec/c/try_catch_spec.rb index cab4cca..d33ccf0 100644 --- a/spec/c/try_catch_spec.rb +++ b/spec/c/try_catch_spec.rb @@ -60,11 +60,19 @@ describe V8::C::TryCatch do end end + it "sees JavaScript exceptions thrown from Ruby" do + V8::C::TryCatch(@isolate) do |trycatch| + message = V8::C::String::NewFromUtf8(@isolate, "boom!") + @isolate.ThrowException(V8::C::Exception::Error(message)) + expect(trycatch.HasCaught).to be_truthy + end + end + it "won't die on a ruby exception" do expect { V8::C::TryCatch(@isolate) do |trycatch| fail "boom!" end - }.to raise_error + }.to raise_error RuntimeError, "boom!" end end