Skip to content

Commit

Permalink
add v8::Isolate::add_message_listener
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed Dec 20, 2019
1 parent 887af28 commit 99fb78a
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 58 deletions.
11 changes: 10 additions & 1 deletion src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ void v8__Isolate__SetCaptureStackTraceForUncaughtExceptions(Isolate* isolate,
isolate->SetCaptureStackTraceForUncaughtExceptions(capture, frame_limit);
}

bool v8__Isolate__AddMessageListener(Isolate& isolate,
v8::MessageCallback callback) {
return isolate.AddMessageListener(callback);
}

Isolate::CreateParams* v8__Isolate__CreateParams__NEW() {
return new Isolate::CreateParams();
}
Expand Down Expand Up @@ -195,10 +200,14 @@ Isolate* v8__Context__GetIsolate(Context& self) { return self.GetIsolate(); }

Object* v8__Context__Global(Context& self) { return *self.Global(); }

v8::String* v8__Message__Get(v8::Message* self) {
v8::String* v8__Message__Get(const v8::Message* self) {
return local_to_ptr(self->Get());
}

v8::Isolate* v8__Message__GetIsolate(const v8::Message* self) {
return self->GetIsolate();
}

v8::Value* v8__Exception__RangeError(v8::Local<v8::String> message) {
return local_to_ptr(v8::Exception::RangeError(message));
}
Expand Down
14 changes: 11 additions & 3 deletions src/exception.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
#![allow(non_snake_case)]

use crate::isolate::Isolate;
use crate::isolate::CxxIsolate;
use crate::isolate::LockedIsolate;
use crate::support::int;
use crate::support::Opaque;
use crate::AssumeLocked;
use crate::Local;
use crate::String;
use crate::Value;

extern "C" {
fn v8__Message__Get(message: *mut Message) -> *mut String;
fn v8__Message__Get(message: *const Message) -> *mut String;
fn v8__Message__GetIsolate(message: *const Message) -> *mut CxxIsolate;

fn v8__StackTrace__GetFrameCount(stack_trace: *mut StackTrace) -> int;

fn v8__Exception__RangeError(message: *mut String) -> *mut Value;
Expand Down Expand Up @@ -43,9 +47,13 @@ impl StackTrace {
pub struct Message(Opaque);

impl Message {
pub fn get(&mut self) -> Local<'_, String> {
pub fn get(&self) -> Local<'_, String> {
unsafe { Local::from_raw(v8__Message__Get(self)) }.unwrap()
}

pub fn get_isolate<'a>(&'_ self) -> impl LockedIsolate + 'a {
unsafe { AssumeLocked::new(&mut *(v8__Message__GetIsolate(self))) }
}
}

/// Create new error objects by calling the corresponding error object
Expand Down
36 changes: 18 additions & 18 deletions src/isolate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ use std::ops::DerefMut;
use std::ptr::NonNull;

use crate::array_buffer::Allocator;
use crate::promise::PromiseRejectMessage;
use crate::exception::Message;
use crate::support::Delete;
use crate::support::Opaque;
use crate::support::UniqueRef;
use crate::Local;
use crate::Value;

type MessageCallback = extern "C" fn(Local<'_, Message>, Local<'_, Value>);

type PromiseRejectCallback = extern "C" fn(PromiseRejectMessage);

Expand All @@ -20,17 +24,18 @@ extern "C" {
caputre: bool,
frame_limit: i32,
);
fn v8__Isolate__SetPromiseRejectCallback(
isolate: *mut Isolate,
callback: PromiseRejectCallback,
);
fn v8__Isolate__AddMessageListener(
this: &mut CxxIsolate,
callback: MessageCallback,
) -> bool;

fn v8__Isolate__CreateParams__NEW() -> *mut CreateParams;
fn v8__Isolate__CreateParams__DELETE(this: &mut CreateParams);
fn v8__Isolate__CreateParams__SET__array_buffer_allocator(
this: &mut CreateParams,
value: *mut Allocator,
);

}

#[repr(C)]
Expand Down Expand Up @@ -89,19 +94,14 @@ impl Isolate {
}
}

/// Set callback to notify about promise reject with no handler, or
/// revocation of such a previous notification once the handler is added.
pub fn set_promise_reject_callback(
&mut self,
callback: PromiseRejectCallback,
) {
unsafe { v8__Isolate__SetPromiseRejectCallback(self, callback) }
}

/// Disposes the isolate. The isolate must not be entered by any
/// thread to be disposable.
pub unsafe fn dispose(&mut self) {
v8__Isolate__Dispose(self)
/// Adds a message listener (errors only).
///
/// The same message listener can be added more than once and in that
/// case it will be called more than once for each message.
///
/// The exception object will be passed to the callback.
pub fn add_message_listener(&mut self, callback: MessageCallback) -> bool {
unsafe { v8__Isolate__AddMessageListener(self.0, callback) }
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ pub mod V8;

pub use context::Context;
pub use exception::Exception;
pub use exception::Message;
pub use function::{Function, FunctionCallbackInfo, FunctionTemplate};
pub use handle_scope::HandleScope;
pub use isolate::Isolate;
pub use isolate::OwnedIsolate;
pub use json::JSON;
pub use local::Local;
pub use locker::Locker;
pub use locker::{AssumeLocked, Locker};
pub use number::{Integer, Number};
pub use object::Object;
pub use primitives::*;
Expand Down
34 changes: 1 addition & 33 deletions src/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,7 @@ use std::ops::Deref;
use std::ops::DerefMut;
use std::ptr::NonNull;

/// An object reference managed by the v8 garbage collector.
///
/// All objects returned from v8 have to be tracked by the garbage
/// collector so that it knows that the objects are still alive. Also,
/// because the garbage collector may move objects, it is unsafe to
/// point directly to an object. Instead, all objects are stored in
/// handles which are known by the garbage collector and updated
/// whenever an object moves. Handles should always be passed by value
/// (except in cases like out-parameters) and they should never be
/// allocated on the heap.
///
/// There are two types of handles: local and persistent handles.
///
/// Local handles are light-weight and transient and typically used in
/// local operations. They are managed by HandleScopes. That means that a
/// HandleScope must exist on the stack when they are created and that they are
/// only valid inside of the HandleScope active during their creation.
/// For passing a local handle to an outer HandleScope, an EscapableHandleScope
/// and its Escape() method must be used.
///
/// Persistent handles can be used when storing objects across several
/// independent operations and have to be explicitly deallocated when they're no
/// longer used.
///
/// It is safe to extract the object stored in the handle by
/// dereferencing the handle (for instance, to extract the *Object from
/// a Local<Object>); the value will still be governed by a handle
/// behind the scenes and the same rules apply to these values as to
/// their handles.
///
/// Note: Local handles in Rusty V8 differ from the V8 C++ API in that they are
/// never empty. In situations where empty handles are needed, use
/// Option<Local>.
#[repr(C)]
pub struct Local<'sc, T>(NonNull<T>, PhantomData<&'sc ()>);

impl<'sc, T> Copy for Local<'sc, T> {}
Expand Down
21 changes: 21 additions & 0 deletions src/locker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,24 @@ impl<'a> Drop for Locker<'a> {
unsafe { v8__Locker__DESTRUCT(self) }
}
}

impl<'a> LockedIsolate for Locker<'a> {
fn cxx_isolate(&mut self) -> &mut CxxIsolate {
self.isolate
}
}

#[repr(transparent)]
pub struct AssumeLocked<'a>(&'a mut CxxIsolate);

impl<'a> AssumeLocked<'a> {
pub unsafe fn new(isolate: &'a mut CxxIsolate) -> Self {
Self(isolate)
}
}

impl<'a> LockedIsolate for AssumeLocked<'a> {
fn cxx_isolate(&mut self) -> &mut CxxIsolate {
&mut self.0
}
}
34 changes: 32 additions & 2 deletions tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,44 @@ fn test_string() {
}

#[test]
fn isolate_new() {
fn isolate_add_message_listener() {
let g = setup();
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(
v8::array_buffer::Allocator::new_default_allocator(),
);
let mut isolate = v8::Isolate::new(params);
isolate.set_capture_stack_trace_for_uncaught_exceptions(true, 32);

use std::sync::atomic::{AtomicUsize, Ordering};
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);

extern "C" fn check_message_0(
message: Local<'_, v8::Message>,
_exception: Local<'_, v8::Value>,
) {
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
let isolate = message.get_isolate();
v8::HandleScope::enter(&isolate, |s| {
let message_str = message.get();
assert_eq!(message_str.to_rust_string_lossy(&isolate), "Uncaught foo");
// assert!(data.is_none());
});
}
isolate.add_message_listener(check_message_0);

let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_s| {
let mut context = v8::Context::new(&isolate);
context.enter();
let source =
v8::String::new(&isolate, "throw 'foo'", Default::default()).unwrap();
let mut script = v8::Script::compile(context, source, None).unwrap();
assert!(script.run(context).is_none());
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
context.exit();
});
drop(locker);
drop(g);
}

Expand Down Expand Up @@ -291,7 +321,7 @@ fn exception() {
v8::Exception::SyntaxError(local);
v8::Exception::TypeError(local);
let exception = v8::Exception::Error(local);
let mut msg = v8::Exception::CreateMessage(&isolate, exception);
let msg = v8::Exception::CreateMessage(scope, exception);
let msg_string = msg.get();
let rust_msg_string = msg_string.to_rust_string_lossy(&isolate);
assert_eq!(
Expand Down

0 comments on commit 99fb78a

Please sign in to comment.