Skip to content

Commit

Permalink
Merge branch 'master' into try-catch-internal
Browse files Browse the repository at this point in the history
  • Loading branch information
dherman committed Jul 14, 2020
2 parents b4bdf87 + bd2479c commit 93e564d
Show file tree
Hide file tree
Showing 12 changed files with 238 additions and 67 deletions.
16 changes: 12 additions & 4 deletions crates/neon-runtime/src/nan/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ pub unsafe fn throw(_: Isolate, val: Local) {
}

/// Mutates the `out` argument provided to refer to a newly created `Error` object.
pub use neon_sys::Neon_Error_NewError as new_error;
pub unsafe fn new_error(_: Isolate, out: &mut Local, msg: Local) {
neon_sys::Neon_Error_NewError(out, msg)
}

/// Mutates the `out` argument provided to refer to a newly created `TypeError` object.
pub use neon_sys::Neon_Error_NewTypeError as new_type_error;
pub unsafe fn new_type_error(_: Isolate, out: &mut Local, msg: Local) {
neon_sys::Neon_Error_NewTypeError(out, msg)
}

/// Mutates the `out` argument provided to refer to a newly created `RangeError` object.
pub use neon_sys::Neon_Error_NewRangeError as new_range_error;
pub unsafe fn new_range_error(_: Isolate, out: &mut Local, msg: Local) {
neon_sys::Neon_Error_NewRangeError(out, msg)
}

/// Throws an `Error` object in the current context.
pub use neon_sys::Neon_Error_ThrowErrorFromUtf8 as throw_error_from_utf8;
pub unsafe fn throw_error_from_utf8(_: Isolate, msg: *const u8, len: i32) {
neon_sys::Neon_Error_ThrowErrorFromUtf8(msg, len)
}
16 changes: 6 additions & 10 deletions crates/neon-runtime/src/napi/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub unsafe extern "C" fn set_return(_info: FunctionCallbackInfo, _value: Local)

}

pub unsafe extern "C" fn get_isolate(info: FunctionCallbackInfo) -> Env { unimplemented!() }
pub unsafe extern "C" fn get_isolate(_info: FunctionCallbackInfo) -> Env { unimplemented!() }

// FIXME: Remove. This will never be implemented
pub unsafe extern "C" fn current_isolate() -> Env { panic!("current_isolate won't be implemented in n-api") }
Expand Down Expand Up @@ -74,14 +74,11 @@ pub unsafe extern "C" fn len(env: Env, info: FunctionCallbackInfo) -> i32 {
argc as i32
}

/// Mutates the `out` argument provided to refer to the `napi_value` of the `i`th argument
/// passed to the function.
pub unsafe extern "C" fn get(env: Env, info: FunctionCallbackInfo, i: i32, out: &mut Local) {
// TODO make this not allocate: https://github.com/neon-bindings/neon/issues/530
// Instead, we can probably get all the arguments at once in `neon` itself?
let mut args = vec![null_mut(); (i + 1) as usize];
/// Returns the function arguments as a `Vec<Local>`
pub unsafe extern "C" fn argv(env: Env, info: FunctionCallbackInfo) -> Vec<Local> {
let len = len(env, info);
let mut args = vec![null_mut(); len as usize];
let mut num_args = args.len();

let status = napi::napi_get_cb_info(
env,
info,
Expand All @@ -91,6 +88,5 @@ pub unsafe extern "C" fn get(env: Env, info: FunctionCallbackInfo, i: i32, out:
null_mut(),
);
assert_eq!(status, napi::napi_status::napi_ok);
assert!(num_args > i as usize);
*out = args[i as usize];
args
}
108 changes: 92 additions & 16 deletions crates/neon-runtime/src/napi/error.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
use std::mem::MaybeUninit;
use raw::{Env, Local};
use std::ptr;

use nodejs_sys as napi;

pub unsafe extern "C" fn throw(env: Env, val: Local) {
let status = napi::napi_throw(env, val);

assert_eq!(status, napi::napi_status::napi_ok);
}

pub unsafe extern "C" fn new_error(_out: &mut Local, _msg: Local) { unimplemented!() }

pub unsafe extern "C" fn new_type_error(_out: &mut Local, _msg: Local) { unimplemented!() }

pub unsafe extern "C" fn new_range_error(_out: &mut Local, _msg: Local) { unimplemented!() }

pub unsafe extern "C" fn throw_error_from_utf8(_msg: *const u8, _len: i32) { unimplemented!() }
use raw::{Env, Local};

pub unsafe extern "C" fn is_throwing(env: Env) -> bool {
pub unsafe fn is_throwing(env: Env) -> bool {
let mut b: MaybeUninit<bool> = MaybeUninit::zeroed();

let status = napi::napi_is_exception_pending(env, b.as_mut_ptr());
Expand All @@ -27,7 +15,7 @@ pub unsafe extern "C" fn is_throwing(env: Env) -> bool {
b.assume_init()
}

pub unsafe extern "C" fn catch_error(env: Env, error: *mut Local) -> bool {
pub unsafe fn catch_error(env: Env, error: *mut Local) -> bool {
if !is_throwing(env) {
return false;
}
Expand All @@ -38,3 +26,91 @@ pub unsafe extern "C" fn catch_error(env: Env, error: *mut Local) -> bool {

true
}

pub unsafe fn clear_exception(env: Env) {
let mut result = MaybeUninit::uninit();
let status = napi::napi_is_exception_pending(env, result.as_mut_ptr());

assert_eq!(status, napi::napi_status::napi_ok);

if !result.assume_init() {
return;
}

let mut result = MaybeUninit::uninit();
let status = napi::napi_get_and_clear_last_exception(env, result.as_mut_ptr());

assert_eq!(status, napi::napi_status::napi_ok);
}

pub unsafe fn throw(env: Env, val: Local) {
let status = napi::napi_throw(env, val);

assert_eq!(status, napi::napi_status::napi_ok);
}

pub unsafe fn new_error(env: Env, out: &mut Local, msg: Local) {
let mut result = MaybeUninit::uninit();
let status = napi::napi_create_error(
env,
ptr::null_mut(),
msg,
result.as_mut_ptr(),
);

assert_eq!(status, napi::napi_status::napi_ok);

*out = result.assume_init();
}

pub unsafe fn new_type_error(env: Env, out: &mut Local, msg: Local) {
let mut result = MaybeUninit::uninit();
let status = napi::napi_create_type_error(
env,
ptr::null_mut(),
msg,
result.as_mut_ptr(),
);

assert_eq!(status, napi::napi_status::napi_ok);

*out = result.assume_init();
}

pub unsafe fn new_range_error(env: Env, out: &mut Local, msg: Local) {
let mut result = MaybeUninit::uninit();
let status = napi::napi_create_range_error(
env,
ptr::null_mut(),
msg,
result.as_mut_ptr(),
);

assert_eq!(status, napi::napi_status::napi_ok);

*out = result.assume_init();
}

pub unsafe fn throw_error_from_utf8(env: Env, msg: *const u8, len: i32) {
let mut out = MaybeUninit::uninit();
let status = napi::napi_create_string_utf8(
env,
msg as *const i8,
len as usize,
out.as_mut_ptr(),
);

assert_eq!(status, napi::napi_status::napi_ok);

let mut err = MaybeUninit::uninit();
let status = napi::napi_create_error(
env,
ptr::null_mut(),
out.assume_init(),
err.as_mut_ptr(),
);

assert_eq!(status, napi::napi_status::napi_ok);

throw(env, err.assume_init());
}
2 changes: 1 addition & 1 deletion crates/neon-runtime/src/napi/fun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub unsafe extern "C" fn new_template(_out: &mut Local, _env: Env, _callback: CC
unimplemented!()
}

pub unsafe extern "C" fn get_dynamic_callback(env: Env, data: *mut c_void) -> *mut c_void {
pub unsafe extern "C" fn get_dynamic_callback(_env: Env, data: *mut c_void) -> *mut c_void {
data
}

Expand Down
48 changes: 36 additions & 12 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ impl CallbackInfo<'_> {
}
}

#[cfg(feature = "legacy-runtime")]
pub fn get<'b, C: Context<'b>>(&self, cx: &mut C, i: i32) -> Option<Handle<'b, JsValue>> {
if i < 0 || i >= self.len(cx) {
return None;
Expand All @@ -72,14 +73,10 @@ impl CallbackInfo<'_> {
}
}

pub fn require<'b, C: Context<'b>>(&self, cx: &mut C, i: i32) -> JsResult<'b, JsValue> {
if i < 0 || i >= self.len(cx) {
return cx.throw_type_error("not enough arguments");
}
#[cfg(feature = "napi-runtime")]
pub fn argv<'b, C: Context<'b>>(&self, cx: &mut C) -> Vec<raw::Local> {
unsafe {
let mut local: raw::Local = std::mem::zeroed();
neon_runtime::call::get(cx.env().to_raw(), self.info, i, &mut local);
Ok(Handle::new_internal(JsValue::from_raw(local)))
neon_runtime::call::argv(cx.env().to_raw(), self.info)
}
}

Expand Down Expand Up @@ -357,8 +354,13 @@ impl<'a> UnwindSafe for ModuleContext<'a> { }

impl<'a> ModuleContext<'a> {
pub(crate) fn with<T, F: for<'b> FnOnce(ModuleContext<'b>) -> T>(env: Env, exports: Handle<'a, JsObject>, f: F) -> T {
debug_assert!(unsafe { neon_runtime::scope::size() } <= std::mem::size_of::<raw::HandleScope>());
debug_assert!(unsafe { neon_runtime::scope::alignment() } <= std::mem::align_of::<raw::HandleScope>());
// These assertions ensure the proper amount of space is reserved on the rust stack
// This is only necessary in the legacy runtime.
#[cfg(feature = "legacy-runtime")]
{
debug_assert!(unsafe { neon_runtime::scope::size() } <= std::mem::size_of::<raw::HandleScope>());
debug_assert!(unsafe { neon_runtime::scope::alignment() } <= std::mem::align_of::<raw::HandleScope>());
}
Scope::with(env, |scope| {
f(ModuleContext {
scope,
Expand Down Expand Up @@ -457,6 +459,8 @@ impl<'a, 'b> Context<'a> for ComputeContext<'a, 'b> { }
pub struct CallContext<'a, T: This> {
scope: Scope<'a, raw::HandleScope>,
info: &'a CallbackInfo<'a>,
#[cfg(feature = "napi-runtime")]
arguments: Option<Vec<raw::Local>>,
phantom_type: PhantomData<T>
}

Expand All @@ -471,6 +475,8 @@ impl<'a, T: This> CallContext<'a, T> {
f(CallContext {
scope,
info,
#[cfg(feature = "napi-runtime")]
arguments: None,
phantom_type: PhantomData
})
})
Expand All @@ -481,13 +487,31 @@ impl<'a, T: This> CallContext<'a, T> {

/// Produces the `i`th argument, or `None` if `i` is greater than or equal to `self.len()`.
pub fn argument_opt(&mut self, i: i32) -> Option<Handle<'a, JsValue>> {
self.info.get(self, i)
#[cfg(feature = "legacy-runtime")]
{ self.info.get(self, i) }

#[cfg(feature = "napi-runtime")]
{
let local = if let Some(arguments) = &self.arguments {
arguments.get(i as usize).cloned()
} else {
let arguments = self.info.argv(self);
let local = arguments.get(i as usize).cloned();

self.arguments = Some(arguments);
local
};

local.map(|local| Handle::new_internal(JsValue::from_raw(local)))
}
}

/// Produces the `i`th argument and casts it to the type `V`, or throws an exception if `i` is greater than or equal to `self.len()` or cannot be cast to `V`.
pub fn argument<V: Value>(&mut self, i: i32) -> JsResult<'a, V> {
let a = self.info.require(self, i)?;
a.downcast_or_throw(self)
match self.argument_opt(i) {
Some(v) => v.downcast_or_throw(self),
None => self.throw_type_error("not enough arguments")
}
}

/// Produces a handle to the `this`-binding.
Expand Down
8 changes: 4 additions & 4 deletions src/object/class/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl<T: Class> Callback<()> for MethodCallback<T> {
};
let dynamic_callback: fn(CallContext<T>) -> JsResult<JsValue> =
mem::transmute(neon_runtime::fun::get_dynamic_callback(cx.env().to_raw(), data));
if let Ok(value) = convert_panics(|| { dynamic_callback(cx) }) {
if let Ok(value) = convert_panics(env, || { dynamic_callback(cx) }) {
info.set_return(value);
}
})
Expand Down Expand Up @@ -71,7 +71,7 @@ impl Callback<()> for ConstructorCallCallback {
let data = info.data(cx.env());
let kernel: fn(CallContext<JsValue>) -> JsResult<JsValue> =
mem::transmute(neon_runtime::class::get_call_kernel(data));
if let Ok(value) = convert_panics(|| { kernel(cx) }) {
if let Ok(value) = convert_panics(env, || { kernel(cx) }) {
info.set_return(value);
}
})
Expand All @@ -93,7 +93,7 @@ impl<T: Class> Callback<*mut c_void> for AllocateCallback<T> {
let data = info.data(cx.env());
let kernel: fn(CallContext<JsUndefined>) -> NeonResult<T::Internals> =
mem::transmute(neon_runtime::class::get_allocate_kernel(data));
if let Ok(value) = convert_panics(|| { kernel(cx) }) {
if let Ok(value) = convert_panics(env, || { kernel(cx) }) {
let p = Box::into_raw(Box::new(value));
mem::transmute(p)
} else {
Expand All @@ -118,7 +118,7 @@ impl<T: Class> Callback<bool> for ConstructCallback<T> {
let data = info.data(cx.env());
let kernel: fn(CallContext<T>) -> NeonResult<Option<Handle<JsObject>>> =
mem::transmute(neon_runtime::class::get_construct_kernel(data));
match convert_panics(|| { kernel(cx) }) {
match convert_panics(env, || { kernel(cx) }) {
Ok(None) => true,
Ok(Some(obj)) => {
info.set_return(obj);
Expand Down
12 changes: 7 additions & 5 deletions src/types/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl JsError {
pub fn error<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, msg: S) -> NeonResult<Handle<'a, JsError>> {
let msg = cx.string(msg.as_ref());
build(|out| unsafe {
neon_runtime::error::new_error(out, msg.to_raw());
neon_runtime::error::new_error(cx.env().to_raw(), out, msg.to_raw());
true
})
}
Expand All @@ -49,7 +49,7 @@ impl JsError {
pub fn type_error<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, msg: S) -> NeonResult<Handle<'a, JsError>> {
let msg = cx.string(msg.as_ref());
build(|out| unsafe {
neon_runtime::error::new_type_error(out, msg.to_raw());
neon_runtime::error::new_type_error(cx.env().to_raw(), out, msg.to_raw());
true
})
}
Expand All @@ -58,13 +58,13 @@ impl JsError {
pub fn range_error<'a, C: Context<'a>, S: AsRef<str>>(cx: &mut C, msg: S) -> NeonResult<Handle<'a, JsError>> {
let msg = cx.string(msg.as_ref());
build(|out| unsafe {
neon_runtime::error::new_range_error(out, msg.to_raw());
neon_runtime::error::new_range_error(cx.env().to_raw(), out, msg.to_raw());
true
})
}
}

pub(crate) fn convert_panics<T, F: UnwindSafe + FnOnce() -> NeonResult<T>>(f: F) -> NeonResult<T> {
pub(crate) fn convert_panics<T, F: UnwindSafe + FnOnce() -> NeonResult<T>>(env: Env, f: F) -> NeonResult<T> {
match catch_unwind(|| { f() }) {
Ok(result) => result,
Err(panic) => {
Expand All @@ -77,7 +77,9 @@ pub(crate) fn convert_panics<T, F: UnwindSafe + FnOnce() -> NeonResult<T>>(f: F)
};
let (data, len) = Utf8::from(&msg[..]).truncate().lower();
unsafe {
neon_runtime::error::throw_error_from_utf8(data, len);
#[cfg(feature = "napi-runtime")]
neon_runtime::error::clear_exception(env.to_raw());
neon_runtime::error::throw_error_from_utf8(env.to_raw(), data, len);
Err(Throw)
}
}
Expand Down
Loading

0 comments on commit 93e564d

Please sign in to comment.