diff --git a/src/binding.cc b/src/binding.cc index 2d265bcb..8ebe6577 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -88,6 +88,11 @@ bool v8__Isolate__AddMessageListener(v8::Isolate& isolate, return isolate.AddMessageListener(callback); } +v8::Value* v8__Isolate__ThrowException(v8::Isolate& isolate, + v8::Value* exception) { + return local_to_ptr(isolate.ThrowException(ptr_to_local(exception))); +} + v8::Isolate::CreateParams* v8__Isolate__CreateParams__NEW() { return new v8::Isolate::CreateParams(); } diff --git a/src/isolate.rs b/src/isolate.rs index 82d2b887..4bbd7279 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -33,6 +33,10 @@ extern "C" { isolate: *mut Isolate, callback: PromiseRejectCallback, ); + fn v8__Isolate__ThrowException( + isolate: &Isolate, + exception: &Value, + ) -> *mut Value; fn v8__Isolate__CreateParams__NEW() -> *mut CreateParams; fn v8__Isolate__CreateParams__DELETE(this: &mut CreateParams); @@ -124,6 +128,20 @@ impl Isolate { unsafe { v8__Isolate__SetPromiseRejectCallback(self, callback) } } + /// Schedules an exception to be thrown when returning to JavaScript. When an + /// exception has been scheduled it is illegal to invoke any JavaScript + /// operation; the caller must return immediately and only after the exception + /// has been handled does it become legal to invoke JavaScript operations. + pub fn throw_exception<'sc>( + &self, + exception: Local<'_, Value>, + ) -> Local<'sc, Value> { + unsafe { + let ptr = v8__Isolate__ThrowException(self, &exception); + Local::from_raw(ptr).unwrap() + } + } + /// Disposes the isolate. The isolate must not be entered by any /// thread to be disposable. pub unsafe fn dispose(&mut self) { diff --git a/tests/test_api.rs b/tests/test_api.rs index 2567d287..3c629308 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -282,6 +282,30 @@ fn try_catch() { }); } +#[test] +fn throw_exception() { + let _g = setup(); + let mut params = v8::Isolate::create_params(); + params.set_array_buffer_allocator(v8::Allocator::new_default_allocator()); + let isolate = v8::Isolate::new(params); + let mut locker = v8::Locker::new(&isolate); + v8::HandleScope::enter(&mut locker, |scope| { + let mut context = v8::Context::new(scope); + context.enter(); + { + let mut try_catch = v8::TryCatch::new(scope); + let tc = try_catch.enter(); + isolate.throw_exception(v8_str(scope, "boom").into()); + assert!(tc.has_caught()); + assert!(tc + .exception() + .unwrap() + .strict_equals(v8_str(scope, "boom").into())); + }; + context.exit(); + }); +} + #[test] fn isolate_add_message_listener() { let g = setup();