Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add v8::Isolate::add_message_listener #78

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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