0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-01-12 17:09:28 -05:00

Integrate 'TryCatch' in the scope system (#406)

This commit is contained in:
Bert Belder 2020-06-26 01:40:53 +02:00
parent 3b6ed67f5e
commit de2cca4c7f
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
8 changed files with 457 additions and 315 deletions

View file

@ -61,7 +61,6 @@ mod snapshot;
mod string; mod string;
mod support; mod support;
mod template; mod template;
mod try_catch;
mod uint8_array; mod uint8_array;
mod value; mod value;
@ -105,6 +104,7 @@ pub use scope::CallbackScope;
pub use scope::ContextScope; pub use scope::ContextScope;
pub use scope::EscapableHandleScope; pub use scope::EscapableHandleScope;
pub use scope::HandleScope; pub use scope::HandleScope;
pub use scope::TryCatch;
pub use script::ScriptOrigin; pub use script::ScriptOrigin;
pub use snapshot::FunctionCodeHandling; pub use snapshot::FunctionCodeHandling;
pub use snapshot::SnapshotCreator; pub use snapshot::SnapshotCreator;
@ -115,7 +115,6 @@ pub use support::SharedRef;
pub use support::UniquePtr; pub use support::UniquePtr;
pub use support::UniqueRef; pub use support::UniqueRef;
pub use template::*; pub use template::*;
pub use try_catch::{TryCatch, TryCatchScope};
// TODO(piscisaureus): Ideally this trait would not be exported. // TODO(piscisaureus): Ideally this trait would not be exported.
pub use support::MapFnTo; pub use support::MapFnTo;

View file

@ -48,6 +48,16 @@
//! - A `Context` is available; any type of value can be created. //! - A `Context` is available; any type of value can be created.
//! - Derefs to `HandleScope<'s>`. //! - Derefs to `HandleScope<'s>`.
//! //!
//! - `TryCatch<'s, P>`
//! - 's = lifetime of the TryCatch scope.
//! - `P` is either a `HandleScope` or an `EscapableHandleScope`. This type
//! also determines for how long the values returned by `TryCatch` methods
//! `exception()`, `message()`, and `stack_trace()` are valid.
//! - Derefs to `P`.
//! - Creating a new scope inside the `TryCatch` block makes its methods
//! inaccessible until the inner scope is dropped. However, the `TryCatch`
//! object will nonetheless catch all exception thrown during its lifetime.
//!
//! - `CallbackScope<'s>` //! - `CallbackScope<'s>`
//! - 's = lifetime of local handles created in this scope, and the value //! - 's = lifetime of local handles created in this scope, and the value
//! returned from the callback, and of the scope itself. //! returned from the callback, and of the scope itself.
@ -226,6 +236,161 @@ impl<'s, 'e: 's, C> EscapableHandleScope<'s, 'e, C> {
} }
} }
/// An external exception handler.
pub struct TryCatch<'s, P> {
data: NonNull<data::ScopeData>,
_phantom: PhantomData<&'s mut P>,
}
impl<'s, P: param::NewTryCatch<'s>> TryCatch<'s, P> {
#[allow(clippy::new_ret_no_self)]
pub fn new(param: &'s mut P) -> P::NewScope {
param.get_scope_data_mut().new_try_catch_data().as_scope()
}
}
impl<'s, P> TryCatch<'s, P> {
/// Returns true if an exception has been caught by this try/catch block.
pub fn has_caught(&self) -> bool {
unsafe { raw::v8__TryCatch__HasCaught(self.get_raw()) }
}
/// For certain types of exceptions, it makes no sense to continue execution.
///
/// If CanContinue returns false, the correct action is to perform any C++
/// cleanup needed and then return. If CanContinue returns false and
/// HasTerminated returns true, it is possible to call
/// CancelTerminateExecution in order to continue calling into the engine.
pub fn can_continue(&self) -> bool {
unsafe { raw::v8__TryCatch__CanContinue(self.get_raw()) }
}
/// Returns true if an exception has been caught due to script execution
/// being terminated.
///
/// There is no JavaScript representation of an execution termination
/// exception. Such exceptions are thrown when the TerminateExecution
/// methods are called to terminate a long-running script.
///
/// If such an exception has been thrown, HasTerminated will return true,
/// indicating that it is possible to call CancelTerminateExecution in order
/// to continue calling into the engine.
pub fn has_terminated(&self) -> bool {
unsafe { raw::v8__TryCatch__HasTerminated(self.get_raw()) }
}
/// Returns true if verbosity is enabled.
pub fn is_verbose(&self) -> bool {
unsafe { raw::v8__TryCatch__IsVerbose(self.get_raw()) }
}
/// Set verbosity of the external exception handler.
///
/// By default, exceptions that are caught by an external exception
/// handler are not reported. Call SetVerbose with true on an
/// external exception handler to have exceptions caught by the
/// handler reported as if they were not caught.
pub fn set_verbose(&mut self, value: bool) {
unsafe { raw::v8__TryCatch__SetVerbose(self.get_raw_mut(), value) };
}
/// Set whether or not this TryCatch should capture a Message object
/// which holds source information about where the exception
/// occurred. True by default.
pub fn set_capture_message(&mut self, value: bool) {
unsafe { raw::v8__TryCatch__SetCaptureMessage(self.get_raw_mut(), value) };
}
/// Clears any exceptions that may have been caught by this try/catch block.
/// After this method has been called, HasCaught() will return false. Cancels
/// the scheduled exception if it is caught and ReThrow() is not called
/// before.
///
/// It is not necessary to clear a try/catch block before using it again; if
/// another exception is thrown the previously caught exception will just be
/// overwritten. However, it is often a good idea since it makes it easier
/// to determine which operation threw a given exception.
pub fn reset(&mut self) {
unsafe { raw::v8__TryCatch__Reset(self.get_raw_mut()) };
}
fn get_raw(&self) -> &raw::TryCatch {
data::ScopeData::get(self).get_try_catch()
}
fn get_raw_mut(&mut self) -> &mut raw::TryCatch {
data::ScopeData::get_mut(self).get_try_catch_mut()
}
}
impl<'s, 'p: 's, P> TryCatch<'s, P>
where
Self: AsMut<HandleScope<'p, ()>>,
{
/// Returns the exception caught by this try/catch block. If no exception has
/// been caught an empty handle is returned.
///
/// Note: v8.h states that "the returned handle is valid until this TryCatch
/// block has been destroyed". This is incorrect; the return value lives
/// no longer and no shorter than the active HandleScope at the time this
/// method is called. An issue has been opened about this in the V8 bug
/// tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537.
pub fn exception(&mut self) -> Option<Local<'p, Value>> {
unsafe {
self
.as_mut()
.cast_local(|sd| raw::v8__TryCatch__Exception(sd.get_try_catch()))
}
}
/// Returns the message associated with this exception. If there is
/// no message associated an empty handle is returned.
///
/// Note: the remark about the lifetime for the `exception()` return value
/// applies here too.
pub fn message(&mut self) -> Option<Local<'p, Message>> {
unsafe {
self
.as_mut()
.cast_local(|sd| raw::v8__TryCatch__Message(sd.get_try_catch()))
}
}
/// Throws the exception caught by this TryCatch in a way that avoids
/// it being caught again by this same TryCatch. As with ThrowException
/// it is illegal to execute any JavaScript operations after calling
/// ReThrow; the caller must return immediately to where the exception
/// is caught.
///
/// This function returns the `undefined` value when successful, or `None` if
/// no exception was caught and therefore there was nothing to rethrow.
pub fn rethrow(&mut self) -> Option<Local<'_, Value>> {
unsafe {
self
.as_mut()
.cast_local(|sd| raw::v8__TryCatch__ReThrow(sd.get_try_catch_mut()))
}
}
}
impl<'s, 'p: 's, P> TryCatch<'s, P>
where
Self: AsMut<HandleScope<'p>>,
{
/// Returns the .stack property of the thrown object. If no .stack
/// property is present an empty handle is returned.
pub fn stack_trace(&mut self) -> Option<Local<'p, Value>> {
unsafe {
self.as_mut().cast_local(|sd| {
raw::v8__TryCatch__StackTrace(
sd.get_try_catch(),
sd.get_current_context(),
)
})
}
}
}
/// A `CallbackScope` can be used to bootstrap a `HandleScope` and /// A `CallbackScope` can be used to bootstrap a `HandleScope` and
/// `ContextScope` inside a callback function that gets called by V8. /// `ContextScope` inside a callback function that gets called by V8.
/// Bootstrapping a scope inside a callback is the only valid use case of this /// Bootstrapping a scope inside a callback is the only valid use case of this
@ -295,25 +460,40 @@ macro_rules! impl_as {
impl_as!(<'s, 'p, P> ContextScope<'s, P> as Isolate); impl_as!(<'s, 'p, P> ContextScope<'s, P> as Isolate);
impl_as!(<'s, C> HandleScope<'s, C> as Isolate); impl_as!(<'s, C> HandleScope<'s, C> as Isolate);
impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as Isolate); impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as Isolate);
impl_as!(<'s, P> TryCatch<'s, P> as Isolate);
impl_as!(<'s> CallbackScope<'s> as Isolate); impl_as!(<'s> CallbackScope<'s> as Isolate);
impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p, ()>); impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p, ()>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p, ()>); impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p, ()>);
impl_as!(<'s, C> HandleScope<'s, C> as HandleScope<'s, ()>); impl_as!(<'s, C> HandleScope<'s, C> as HandleScope<'s, ()>);
impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as HandleScope<'s, ()>); impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as HandleScope<'s, ()>);
impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as HandleScope<'p, ()>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>);
impl_as!(<'s> CallbackScope<'s> as HandleScope<'s, ()>); impl_as!(<'s> CallbackScope<'s> as HandleScope<'s, ()>);
impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>); impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>);
impl_as!(<'s> HandleScope<'s> as HandleScope<'s>); impl_as!(<'s> HandleScope<'s> as HandleScope<'s>);
impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>); impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>);
impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>);
impl_as!(<'s> CallbackScope<'s> as HandleScope<'s>); impl_as!(<'s> CallbackScope<'s> as HandleScope<'s>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e, ()>); impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e, ()>);
impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as EscapableHandleScope<'s, 'e, ()>); impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as EscapableHandleScope<'s, 'e, ()>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>);
impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as EscapableHandleScope<'s, 'e>); impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as EscapableHandleScope<'s, 'e>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as TryCatch<'s, HandleScope<'p, ()>>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, HandleScope<'p, ()>>);
impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, EscapableHandleScope<'p, 'e, ()>>);
impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as TryCatch<'s, HandleScope<'p>>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, HandleScope<'p>>);
impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, EscapableHandleScope<'p, 'e>>);
macro_rules! impl_deref { macro_rules! impl_deref {
(<$($params:tt),+> $src_type:ty as $tgt_type:ty) => { (<$($params:tt),+> $src_type:ty as $tgt_type:ty) => {
@ -341,6 +521,11 @@ impl_deref!(<'s> HandleScope<'s> as HandleScope<'s, ()>);
impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e, ()> as HandleScope<'s, ()>); impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e, ()> as HandleScope<'s, ()>);
impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>); impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>);
impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>);
impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>);
impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>);
impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
impl_deref!(<'s> CallbackScope<'s> as HandleScope<'s>); impl_deref!(<'s> CallbackScope<'s> as HandleScope<'s>);
macro_rules! impl_scope_drop { macro_rules! impl_scope_drop {
@ -358,6 +543,7 @@ macro_rules! impl_scope_drop {
impl_scope_drop!(<'s, 'p, P> ContextScope<'s, P>); impl_scope_drop!(<'s, 'p, P> ContextScope<'s, P>);
impl_scope_drop!(<'s, C> HandleScope<'s, C> ); impl_scope_drop!(<'s, C> HandleScope<'s, C> );
impl_scope_drop!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> ); impl_scope_drop!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> );
impl_scope_drop!(<'s, P> TryCatch<'s, P> );
impl_scope_drop!(<'s> CallbackScope<'s> ); impl_scope_drop!(<'s> CallbackScope<'s> );
pub unsafe trait Scope: Sized {} pub unsafe trait Scope: Sized {}
@ -413,6 +599,12 @@ mod param {
type NewScope = ContextScope<'s, EscapableHandleScope<'p, 'e>>; type NewScope = ContextScope<'s, EscapableHandleScope<'p, 'e>>;
} }
impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s>
for TryCatch<'p, P>
{
type NewScope = <P as NewContextScope<'s>>::NewScope;
}
impl<'s, 'p: 's> NewContextScope<'s> for CallbackScope<'p> { impl<'s, 'p: 's> NewContextScope<'s> for CallbackScope<'p> {
type NewScope = ContextScope<'s, HandleScope<'p>>; type NewScope = ContextScope<'s, HandleScope<'p>>;
} }
@ -445,6 +637,10 @@ mod param {
type NewScope = EscapableHandleScope<'s, 'e, C>; type NewScope = EscapableHandleScope<'s, 'e, C>;
} }
impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> for TryCatch<'p, P> {
type NewScope = <P as NewHandleScope<'s>>::NewScope;
}
impl<'s, 'p: 's> NewHandleScope<'s> for CallbackScope<'p> { impl<'s, 'p: 's> NewHandleScope<'s> for CallbackScope<'p> {
type NewScope = HandleScope<'s>; type NewScope = HandleScope<'s>;
} }
@ -469,10 +665,42 @@ mod param {
type NewScope = EscapableHandleScope<'s, 'p, C>; type NewScope = EscapableHandleScope<'s, 'p, C>;
} }
impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>>
NewEscapableHandleScope<'s, 'e> for TryCatch<'p, P>
{
type NewScope = <P as NewEscapableHandleScope<'s, 'e>>::NewScope;
}
impl<'s, 'p: 's> NewEscapableHandleScope<'s, 'p> for CallbackScope<'p> { impl<'s, 'p: 's> NewEscapableHandleScope<'s, 'p> for CallbackScope<'p> {
type NewScope = EscapableHandleScope<'s, 'p>; type NewScope = EscapableHandleScope<'s, 'p>;
} }
pub trait NewTryCatch<'s>: data::GetScopeData {
type NewScope: Scope;
}
impl<'s, 'p: 's, P: NewTryCatch<'s>> NewTryCatch<'s> for ContextScope<'p, P> {
type NewScope = <P as NewTryCatch<'s>>::NewScope;
}
impl<'s, 'p: 's, C> NewTryCatch<'s> for HandleScope<'p, C> {
type NewScope = TryCatch<'s, HandleScope<'p, C>>;
}
impl<'s, 'p: 's, 'e: 'p, C> NewTryCatch<'s>
for EscapableHandleScope<'p, 'e, C>
{
type NewScope = TryCatch<'s, EscapableHandleScope<'p, 'e, C>>;
}
impl<'s, 'p: 's, P> NewTryCatch<'s> for TryCatch<'p, P> {
type NewScope = TryCatch<'s, P>;
}
impl<'s, 'p: 's> NewTryCatch<'s> for CallbackScope<'p> {
type NewScope = TryCatch<'s, HandleScope<'p>>;
}
pub trait NewCallbackScope<'s>: Copy + Sized { pub trait NewCallbackScope<'s>: Copy + Sized {
fn maybe_get_current_context(self) -> Option<Local<'s, Context>> { fn maybe_get_current_context(self) -> Option<Local<'s, Context>> {
None None
@ -548,6 +776,7 @@ pub(crate) mod data {
// (eiter current or shadowed -- not free). // (eiter current or shadowed -- not free).
context: Cell<Option<NonNull<Context>>>, context: Cell<Option<NonNull<Context>>>,
escape_slot: Option<NonNull<Option<raw::EscapeSlot>>>, escape_slot: Option<NonNull<Option<raw::EscapeSlot>>>,
try_catch: Option<NonNull<raw::TryCatch>>,
scope_type_specific_data: ScopeTypeSpecificData, scope_type_specific_data: ScopeTypeSpecificData,
} }
@ -660,6 +889,24 @@ pub(crate) mod data {
}) })
} }
pub(super) fn new_try_catch_data(&mut self) -> &mut Self {
self.new_scope_data_with(|data| {
let isolate = data.isolate;
data.scope_type_specific_data.init_with(|| {
ScopeTypeSpecificData::TryCatch {
raw_try_catch: unsafe { raw::TryCatch::uninit() },
}
});
match &mut data.scope_type_specific_data {
ScopeTypeSpecificData::TryCatch { raw_try_catch } => {
unsafe { raw_try_catch.init(isolate) };
data.try_catch.replace(raw_try_catch.into());
}
_ => unreachable!(),
}
})
}
pub(super) fn new_callback_scope_data<'s>( pub(super) fn new_callback_scope_data<'s>(
&'s mut self, &'s mut self,
maybe_current_context: Option<Local<'s, Context>>, maybe_current_context: Option<Local<'s, Context>>,
@ -893,6 +1140,22 @@ pub(crate) mod data {
.map(|escape_slot_nn| unsafe { escape_slot_nn.as_mut() }) .map(|escape_slot_nn| unsafe { escape_slot_nn.as_mut() })
} }
pub(super) fn get_try_catch(&self) -> &raw::TryCatch {
self
.try_catch
.as_ref()
.map(|try_catch_nn| unsafe { try_catch_nn.as_ref() })
.unwrap()
}
pub(super) fn get_try_catch_mut(&mut self) -> &mut raw::TryCatch {
self
.try_catch
.as_mut()
.map(|try_catch_nn| unsafe { try_catch_nn.as_mut() })
.unwrap()
}
/// Returns a new `Box<ScopeData>` with the `isolate` field set as specified /// Returns a new `Box<ScopeData>` with the `isolate` field set as specified
/// by the first parameter, and the other fields initialized to their /// by the first parameter, and the other fields initialized to their
/// default values. This function exists solely because it turns out that /// default values. This function exists solely because it turns out that
@ -911,6 +1174,7 @@ pub(crate) mod data {
status: Default::default(), status: Default::default(),
context: Default::default(), context: Default::default(),
escape_slot: Default::default(), escape_slot: Default::default(),
try_catch: Default::default(),
scope_type_specific_data: Default::default(), scope_type_specific_data: Default::default(),
}, },
); );
@ -944,6 +1208,9 @@ pub(crate) mod data {
raw_handle_scope: raw::HandleScope, raw_handle_scope: raw::HandleScope,
raw_escape_slot: Option<raw::EscapeSlot>, raw_escape_slot: Option<raw::EscapeSlot>,
}, },
TryCatch {
raw_try_catch: raw::TryCatch,
},
} }
impl Default for ScopeTypeSpecificData { impl Default for ScopeTypeSpecificData {
@ -1081,6 +1348,34 @@ mod raw {
} }
} }
#[repr(C)]
pub(super) struct TryCatch([usize; 6]);
impl TryCatch {
/// This function is marked unsafe because the caller must ensure that the
/// returned value isn't dropped before `init()` has been called.
pub unsafe fn uninit() -> Self {
// This is safe because there is no combination of bits that would produce
// an invalid `[usize; 6]`.
#[allow(clippy::uninit_assumed_init)]
Self(MaybeUninit::uninit().assume_init())
}
/// This function is marked unsafe because `init()` must be called exactly
/// once, no more and no less, after creating a `TryCatch` value with
/// `TryCatch::uninit()`.
pub unsafe fn init(&mut self, isolate: NonNull<Isolate>) {
let buf = NonNull::from(self).cast();
v8__TryCatch__CONSTRUCT(buf.as_ptr(), isolate.as_ptr());
}
}
impl Drop for TryCatch {
fn drop(&mut self) {
unsafe { v8__TryCatch__DESTRUCT(self) };
}
}
extern "C" { extern "C" {
pub(super) fn v8__Isolate__GetCurrentContext( pub(super) fn v8__Isolate__GetCurrentContext(
isolate: *mut Isolate, isolate: *mut Isolate,
@ -1114,6 +1409,33 @@ mod raw {
) -> *const Data; ) -> *const Data;
pub(super) fn v8__Undefined(isolate: *mut Isolate) -> *const Primitive; pub(super) fn v8__Undefined(isolate: *mut Isolate) -> *const Primitive;
pub(super) fn v8__TryCatch__CONSTRUCT(
buf: *mut MaybeUninit<TryCatch>,
isolate: *mut Isolate,
);
pub(super) fn v8__TryCatch__DESTRUCT(this: *mut TryCatch);
pub(super) fn v8__TryCatch__HasCaught(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__CanContinue(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__HasTerminated(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__IsVerbose(this: *const TryCatch) -> bool;
pub(super) fn v8__TryCatch__SetVerbose(this: *mut TryCatch, value: bool);
pub(super) fn v8__TryCatch__SetCaptureMessage(
this: *mut TryCatch,
value: bool,
);
pub(super) fn v8__TryCatch__Reset(this: *mut TryCatch);
pub(super) fn v8__TryCatch__Exception(
this: *const TryCatch,
) -> *const Value;
pub(super) fn v8__TryCatch__StackTrace(
this: *const TryCatch,
context: *const Context,
) -> *const Value;
pub(super) fn v8__TryCatch__Message(
this: *const TryCatch,
) -> *const Message;
pub(super) fn v8__TryCatch__ReThrow(this: *mut TryCatch) -> *const Value;
pub(super) fn v8__Message__GetIsolate(this: *const Message) pub(super) fn v8__Message__GetIsolate(this: *const Message)
-> *mut Isolate; -> *mut Isolate;
pub(super) fn v8__Object__GetIsolate(this: *const Object) -> *mut Isolate; pub(super) fn v8__Object__GetIsolate(this: *const Object) -> *mut Isolate;
@ -1178,9 +1500,20 @@ mod tests {
let d = d.deref_mut(); let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>(); AssertTypeOf(d).is::<Isolate>();
} }
{
let l3_tc = &mut TryCatch::new(l2_cxs);
AssertTypeOf(l3_tc).is::<TryCatch<HandleScope>>();
let d = l3_tc.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
{ {
let l3_ehs = &mut EscapableHandleScope::new(l2_cxs); let l3_ehs = &mut EscapableHandleScope::new(l2_cxs);
AssertTypeOf(l3_ehs).is::<EscapableHandleScope>(); AssertTypeOf(l3_ehs).is::<EscapableHandleScope>();
{
let l4_cxs = &mut ContextScope::new(l3_ehs, context); let l4_cxs = &mut ContextScope::new(l3_ehs, context);
AssertTypeOf(l4_cxs).is::<ContextScope<EscapableHandleScope>>(); AssertTypeOf(l4_cxs).is::<ContextScope<EscapableHandleScope>>();
let d = l4_cxs.deref_mut(); let d = l4_cxs.deref_mut();
@ -1192,11 +1525,36 @@ mod tests {
let d = d.deref_mut(); let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>(); AssertTypeOf(d).is::<Isolate>();
} }
{
let l4_tc = &mut TryCatch::new(l3_ehs);
AssertTypeOf(l4_tc).is::<TryCatch<EscapableHandleScope>>();
let d = l4_tc.deref_mut();
AssertTypeOf(d).is::<EscapableHandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
}
}
}
{
let l2_tc = &mut TryCatch::new(l1_hs);
AssertTypeOf(l2_tc).is::<TryCatch<HandleScope<()>>>();
let d = l2_tc.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>();
} }
{ {
let l2_ehs = &mut EscapableHandleScope::new(l1_hs); let l2_ehs = &mut EscapableHandleScope::new(l1_hs);
AssertTypeOf(l2_ehs).is::<EscapableHandleScope<()>>(); AssertTypeOf(l2_ehs).is::<EscapableHandleScope<()>>();
let d = l2_ehs.deref_mut(); let l3_tc = &mut TryCatch::new(l2_ehs);
AssertTypeOf(l3_tc).is::<TryCatch<EscapableHandleScope<()>>>();
let d = l3_tc.deref_mut();
AssertTypeOf(d).is::<EscapableHandleScope<()>>();
let d = d.deref_mut();
AssertTypeOf(d).is::<HandleScope<()>>(); AssertTypeOf(d).is::<HandleScope<()>>();
let d = d.deref_mut(); let d = d.deref_mut();
AssertTypeOf(d).is::<Isolate>(); AssertTypeOf(d).is::<Isolate>();
@ -1235,6 +1593,7 @@ mod tests {
AssertTypeOf(&HandleScope::new(l2_cxs)).is::<HandleScope>(); AssertTypeOf(&HandleScope::new(l2_cxs)).is::<HandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l2_cxs)) AssertTypeOf(&EscapableHandleScope::new(l2_cxs))
.is::<EscapableHandleScope>(); .is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l2_cxs)).is::<TryCatch<HandleScope>>();
} }
{ {
let l2_ehs = &mut EscapableHandleScope::new(l1_hs); let l2_ehs = &mut EscapableHandleScope::new(l1_hs);
@ -1250,8 +1609,40 @@ mod tests {
AssertTypeOf(&HandleScope::new(l3_cxs)).is::<EscapableHandleScope>(); AssertTypeOf(&HandleScope::new(l3_cxs)).is::<EscapableHandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_cxs)) AssertTypeOf(&EscapableHandleScope::new(l3_cxs))
.is::<EscapableHandleScope>(); .is::<EscapableHandleScope>();
{
let l4_tc = &mut TryCatch::new(l3_cxs);
AssertTypeOf(l4_tc).is::<TryCatch<EscapableHandleScope>>();
AssertTypeOf(&ContextScope::new(l4_tc, context))
.is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&HandleScope::new(l4_tc)).is::<EscapableHandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l4_tc))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l4_tc))
.is::<TryCatch<EscapableHandleScope>>();
} }
} }
{
let l3_tc = &mut TryCatch::new(l2_ehs);
AssertTypeOf(l3_tc).is::<TryCatch<EscapableHandleScope<()>>>();
AssertTypeOf(&ContextScope::new(l3_tc, context))
.is::<ContextScope<EscapableHandleScope>>();
AssertTypeOf(&HandleScope::new(l3_tc)).is::<EscapableHandleScope<()>>();
AssertTypeOf(&EscapableHandleScope::new(l3_tc))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&TryCatch::new(l3_tc))
.is::<TryCatch<EscapableHandleScope<()>>>();
}
}
{
let l2_tc = &mut TryCatch::new(l1_hs);
AssertTypeOf(l2_tc).is::<TryCatch<HandleScope<()>>>();
AssertTypeOf(&ContextScope::new(l2_tc, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l2_tc)).is::<HandleScope<()>>();
AssertTypeOf(&EscapableHandleScope::new(l2_tc))
.is::<EscapableHandleScope<()>>();
AssertTypeOf(&TryCatch::new(l2_tc)).is::<TryCatch<HandleScope<()>>>();
}
{ {
let l2_cbs = &mut unsafe { CallbackScope::new(context) }; let l2_cbs = &mut unsafe { CallbackScope::new(context) };
AssertTypeOf(l2_cbs).is::<CallbackScope>(); AssertTypeOf(l2_cbs).is::<CallbackScope>();
@ -1265,6 +1656,7 @@ mod tests {
AssertTypeOf(&HandleScope::new(l3_hs)).is::<HandleScope>(); AssertTypeOf(&HandleScope::new(l3_hs)).is::<HandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_hs)) AssertTypeOf(&EscapableHandleScope::new(l3_hs))
.is::<EscapableHandleScope>(); .is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l3_hs)).is::<TryCatch<HandleScope>>();
} }
{ {
let l3_ehs = &mut EscapableHandleScope::new(l2_cbs); let l3_ehs = &mut EscapableHandleScope::new(l2_cbs);
@ -1274,6 +1666,18 @@ mod tests {
AssertTypeOf(&HandleScope::new(l3_ehs)).is::<EscapableHandleScope>(); AssertTypeOf(&HandleScope::new(l3_ehs)).is::<EscapableHandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_ehs)) AssertTypeOf(&EscapableHandleScope::new(l3_ehs))
.is::<EscapableHandleScope>(); .is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l3_ehs))
.is::<TryCatch<EscapableHandleScope>>();
}
{
let l3_tc = &mut TryCatch::new(l2_cbs);
AssertTypeOf(l3_tc).is::<TryCatch<HandleScope>>();
AssertTypeOf(&ContextScope::new(l3_tc, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l3_tc)).is::<HandleScope>();
AssertTypeOf(&EscapableHandleScope::new(l3_tc))
.is::<EscapableHandleScope>();
AssertTypeOf(&TryCatch::new(l3_tc)).is::<TryCatch<HandleScope>>();
} }
} }
} }

View file

@ -1,247 +0,0 @@
use std::marker::PhantomData;
use std::mem::size_of;
use std::mem::size_of_val;
use std::mem::take;
use std::mem::MaybeUninit;
use crate::Context;
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::Message;
use crate::Value;
extern "C" {
// Note: the C++ CxxTryCatch object *must* live on the stack, and it must
// not move after it is constructed.
fn v8__TryCatch__CONSTRUCT(
buf: *mut MaybeUninit<CxxTryCatch>,
isolate: *mut Isolate,
);
fn v8__TryCatch__DESTRUCT(this: *mut CxxTryCatch);
fn v8__TryCatch__HasCaught(this: *const CxxTryCatch) -> bool;
fn v8__TryCatch__CanContinue(this: *const CxxTryCatch) -> bool;
fn v8__TryCatch__HasTerminated(this: *const CxxTryCatch) -> bool;
fn v8__TryCatch__Exception(this: *const CxxTryCatch) -> *const Value;
fn v8__TryCatch__StackTrace(
this: *const CxxTryCatch,
context: *const Context,
) -> *const Value;
fn v8__TryCatch__Message(this: *const CxxTryCatch) -> *const Message;
fn v8__TryCatch__Reset(this: *mut CxxTryCatch);
fn v8__TryCatch__ReThrow(this: *mut CxxTryCatch) -> *const Value;
fn v8__TryCatch__IsVerbose(this: *const CxxTryCatch) -> bool;
fn v8__TryCatch__SetVerbose(this: *mut CxxTryCatch, value: bool);
fn v8__TryCatch__SetCaptureMessage(this: *mut CxxTryCatch, value: bool);
}
// Note: the 'tc lifetime is there to ensure that after entering a TryCatchScope
// once, the same TryCatch object can't be entered again.
/// An external exception handler.
#[repr(transparent)]
pub struct TryCatch<'tc>(CxxTryCatch, PhantomData<&'tc ()>);
#[repr(C)]
struct CxxTryCatch([usize; 6]);
/// A scope object that will, when entered, active the embedded TryCatch block.
pub struct TryCatchScope<'tc>(TryCatchState<'tc>);
enum TryCatchState<'tc> {
New { isolate: *mut Isolate },
Uninit(MaybeUninit<TryCatch<'tc>>),
Entered(TryCatch<'tc>),
}
impl<'tc> TryCatch<'tc> {
/// Creates a new try/catch block. Note that all TryCatch blocks should be
/// stack allocated because the memory location itself is compared against
/// JavaScript try/catch blocks.
#[allow(clippy::new_ret_no_self)]
pub fn new(scope: &mut Isolate) -> TryCatchScope<'tc> {
TryCatchScope(TryCatchState::New { isolate: scope })
}
/// Returns true if an exception has been caught by this try/catch block.
pub fn has_caught(&self) -> bool {
unsafe { v8__TryCatch__HasCaught(&self.0) }
}
/// For certain types of exceptions, it makes no sense to continue execution.
///
/// If CanContinue returns false, the correct action is to perform any C++
/// cleanup needed and then return. If CanContinue returns false and
/// HasTerminated returns true, it is possible to call
/// CancelTerminateExecution in order to continue calling into the engine.
pub fn can_continue(&self) -> bool {
unsafe { v8__TryCatch__CanContinue(&self.0) }
}
/// Returns true if an exception has been caught due to script execution
/// being terminated.
///
/// There is no JavaScript representation of an execution termination
/// exception. Such exceptions are thrown when the TerminateExecution
/// methods are called to terminate a long-running script.
///
/// If such an exception has been thrown, HasTerminated will return true,
/// indicating that it is possible to call CancelTerminateExecution in order
/// to continue calling into the engine.
pub fn has_terminated(&self) -> bool {
unsafe { v8__TryCatch__HasTerminated(&self.0) }
}
/// Returns the exception caught by this try/catch block. If no exception has
/// been caught an empty handle is returned.
///
/// Note: v8.h states that "the returned handle is valid until this TryCatch
/// block has been destroyed". This is incorrect; the return value lives
/// no longer and no shorter than the active HandleScope at the time this
/// method is called. An issue has been opened about this in the V8 bug
/// tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537.
pub fn exception<'s>(
&self,
scope: &mut HandleScope<'s>,
) -> Option<Local<'s, Value>> {
unsafe { scope.cast_local(|_| v8__TryCatch__Exception(&self.0)) }
}
/// Returns the message associated with this exception. If there is
/// no message associated an empty handle is returned.
///
/// Note: the remark about the lifetime for the `exception()` return value
/// applies here too.
pub fn message<'s>(
&self,
scope: &mut HandleScope<'s>,
) -> Option<Local<'s, Message>> {
unsafe { scope.cast_local(|_| v8__TryCatch__Message(&self.0)) }
}
/// Returns the .stack property of the thrown object. If no .stack
/// property is present an empty handle is returned.
pub fn stack_trace<'s>(
&self,
scope: &mut HandleScope<'s>,
context: Local<Context>,
) -> Option<Local<'s, Value>> {
unsafe {
scope.cast_local(|_| v8__TryCatch__StackTrace(&self.0, &*context))
}
}
/// Clears any exceptions that may have been caught by this try/catch block.
/// After this method has been called, HasCaught() will return false. Cancels
/// the scheduled exception if it is caught and ReThrow() is not called
/// before.
///
/// It is not necessary to clear a try/catch block before using it again; if
/// another exception is thrown the previously caught exception will just be
/// overwritten. However, it is often a good idea since it makes it easier
/// to determine which operation threw a given exception.
pub fn reset(&mut self) {
unsafe { v8__TryCatch__Reset(&mut self.0) };
}
/// Throws the exception caught by this TryCatch in a way that avoids
/// it being caught again by this same TryCatch. As with ThrowException
/// it is illegal to execute any JavaScript operations after calling
/// ReThrow; the caller must return immediately to where the exception
/// is caught.
///
/// This function returns the `undefined` value when successful, or `None` if
/// no exception was caught and therefore there was nothing to rethrow.
pub fn rethrow(&mut self) -> Option<Local<'_, Value>> {
let result = unsafe { Local::from_raw(v8__TryCatch__ReThrow(&mut self.0)) };
if let Some(value) = result {
debug_assert!(value.is_undefined())
}
result
}
/// Returns true if verbosity is enabled.
pub fn is_verbose(&self) -> bool {
unsafe { v8__TryCatch__IsVerbose(&self.0) }
}
/// Set verbosity of the external exception handler.
///
/// By default, exceptions that are caught by an external exception
/// handler are not reported. Call SetVerbose with true on an
/// external exception handler to have exceptions caught by the
/// handler reported as if they were not caught.
pub fn set_verbose(&mut self, value: bool) {
unsafe { v8__TryCatch__SetVerbose(&mut self.0, value) };
}
/// Set whether or not this TryCatch should capture a Message object
/// which holds source information about where the exception
/// occurred. True by default.
pub fn set_capture_message(&mut self, value: bool) {
unsafe { v8__TryCatch__SetCaptureMessage(&mut self.0, value) };
}
fn construct(buf: &mut MaybeUninit<TryCatch>, isolate: *mut Isolate) {
unsafe {
assert_eq!(size_of_val(buf), size_of::<CxxTryCatch>());
let buf = &mut *(buf as *mut _ as *mut MaybeUninit<CxxTryCatch>);
v8__TryCatch__CONSTRUCT(buf, isolate);
}
}
}
impl Drop for CxxTryCatch {
fn drop(&mut self) {
unsafe { v8__TryCatch__DESTRUCT(self) }
}
}
impl<'tc> TryCatchScope<'tc> {
/// Enters the TryCatch block. Exceptions are caught as long as the returned
/// TryCatch object remains in scope.
pub fn enter(&'tc mut self) -> &'tc mut TryCatch {
use TryCatchState::*;
let state = &mut self.0;
let isolate = match take(state) {
New { isolate } => isolate,
_ => unreachable!(),
};
let buf = match state {
Uninit(b) => b,
_ => unreachable!(),
};
TryCatch::construct(buf, isolate);
*state = match take(state) {
Uninit(b) => Entered(unsafe { b.assume_init() }),
_ => unreachable!(),
};
match state {
Entered(v) => v,
_ => unreachable!(),
}
}
}
impl<'tc> Default for TryCatchState<'tc> {
fn default() -> Self {
Self::Uninit(MaybeUninit::uninit())
}
}

View file

@ -7,13 +7,11 @@ pub fn main() {
let context = v8::Context::new(&mut scope1); let context = v8::Context::new(&mut scope1);
let mut scope2 = v8::ContextScope::new(&mut scope1, context); let mut scope2 = v8::ContextScope::new(&mut scope1, context);
let mut try_catch = v8::TryCatch::new(&mut scope2);
let try_catch = try_catch.enter();
let _exception = { let _exception = {
let mut scope3 = v8::HandleScope::new(&mut scope2); let mut scope3 = v8::HandleScope::new(&mut scope2);
let mut scope4 = v8::HandleScope::new(&mut scope3); let mut scope4 = v8::HandleScope::new(&mut scope3);
try_catch.exception(&mut scope4).unwrap() let mut try_catch = v8::TryCatch::new(&mut scope4);
try_catch.exception().unwrap()
}; };
} }

View file

@ -1,11 +1,11 @@
error[E0597]: `scope3` does not live long enough error[E0597]: `scope3` does not live long enough
--> $DIR/try_catch_exception_lifetime.rs:15:43 --> $DIR/try_catch_exception_lifetime.rs:12:43
| |
13 | let _exception = { 10 | let _exception = {
| ---------- borrow later stored here | ---------- borrow later stored here
14 | let mut scope3 = v8::HandleScope::new(&mut scope2); 11 | let mut scope3 = v8::HandleScope::new(&mut scope2);
15 | let mut scope4 = v8::HandleScope::new(&mut scope3); 12 | let mut scope4 = v8::HandleScope::new(&mut scope3);
| ^^^^^^^^^^^ borrowed value does not live long enough | ^^^^^^^^^^^ borrowed value does not live long enough
16 | try_catch.exception(&mut scope4).unwrap() ...
17 | }; 15 | };
| - `scope3` dropped here while still borrowed | - `scope3` dropped here while still borrowed

View file

@ -7,13 +7,11 @@ pub fn main() {
let context = v8::Context::new(&mut scope1); let context = v8::Context::new(&mut scope1);
let mut scope2 = v8::ContextScope::new(&mut scope1, context); let mut scope2 = v8::ContextScope::new(&mut scope1, context);
let mut try_catch = v8::TryCatch::new(&mut scope2);
let try_catch = try_catch.enter();
let _message = { let _message = {
let mut scope3 = v8::HandleScope::new(&mut scope2); let mut scope3 = v8::HandleScope::new(&mut scope2);
let mut scope4 = v8::HandleScope::new(&mut scope3); let mut scope4 = v8::HandleScope::new(&mut scope3);
try_catch.message(&mut scope4).unwrap() let mut try_catch = v8::TryCatch::new(&mut scope4);
try_catch.message().unwrap()
}; };
} }

View file

@ -1,11 +1,11 @@
error[E0597]: `scope3` does not live long enough error[E0597]: `scope3` does not live long enough
--> $DIR/try_catch_message_lifetime.rs:15:43 --> $DIR/try_catch_message_lifetime.rs:12:43
| |
13 | let _message = { 10 | let _message = {
| -------- borrow later stored here | -------- borrow later stored here
14 | let mut scope3 = v8::HandleScope::new(&mut scope2); 11 | let mut scope3 = v8::HandleScope::new(&mut scope2);
15 | let mut scope4 = v8::HandleScope::new(&mut scope3); 12 | let mut scope4 = v8::HandleScope::new(&mut scope3);
| ^^^^^^^^^^^ borrowed value does not live long enough | ^^^^^^^^^^^ borrowed value does not live long enough
16 | try_catch.message(&mut scope4).unwrap() ...
17 | }; 15 | };
| - `scope3` dropped here while still borrowed | - `scope3` dropped here while still borrowed

View file

@ -549,42 +549,35 @@ fn try_catch() {
let scope = &mut v8::ContextScope::new(scope, context); let scope = &mut v8::ContextScope::new(scope, context);
{ {
// Error thrown - should be caught. // Error thrown - should be caught.
let mut try_catch = v8::TryCatch::new(scope); let tc = &mut v8::TryCatch::new(scope);
let tc = try_catch.enter(); let result = eval(tc, context, "throw new Error('foo')");
let result = eval(scope, context, "throw new Error('foo')");
assert!(result.is_none()); assert!(result.is_none());
assert!(tc.has_caught()); assert!(tc.has_caught());
assert!(tc.exception(scope).is_some()); assert!(tc.exception().is_some());
assert!(tc.stack_trace(scope, context).is_some()); assert!(tc.stack_trace().is_some());
assert!(tc.message(scope).is_some()); assert!(tc.message().is_some());
assert_eq!( assert_eq!(
tc.message(scope) tc.message().unwrap().get(tc).to_rust_string_lossy(tc),
.unwrap()
.get(scope)
.to_rust_string_lossy(scope),
"Uncaught Error: foo" "Uncaught Error: foo"
); );
}; };
{ {
// No error thrown. // No error thrown.
let mut try_catch = v8::TryCatch::new(scope); let tc = &mut v8::TryCatch::new(scope);
let tc = try_catch.enter(); let result = eval(tc, context, "1 + 1");
let result = eval(scope, context, "1 + 1");
assert!(result.is_some()); assert!(result.is_some());
assert!(!tc.has_caught()); assert!(!tc.has_caught());
assert!(tc.exception(scope).is_none()); assert!(tc.exception().is_none());
assert!(tc.stack_trace(scope, context).is_none()); assert!(tc.stack_trace().is_none());
assert!(tc.message(scope).is_none()); assert!(tc.message().is_none());
assert!(tc.rethrow().is_none()); assert!(tc.rethrow().is_none());
}; };
{ {
// Rethrow and reset. // Rethrow and reset.
let mut try_catch_1 = v8::TryCatch::new(scope); let tc1 = &mut v8::TryCatch::new(scope);
let tc1 = try_catch_1.enter();
{ {
let mut try_catch_2 = v8::TryCatch::new(scope); let tc2 = &mut v8::TryCatch::new(tc1);
let tc2 = try_catch_2.enter(); eval(tc2, context, "throw 'bar'");
eval(scope, context, "throw 'bar'");
assert!(tc2.has_caught()); assert!(tc2.has_caught());
assert!(tc2.rethrow().is_some()); assert!(tc2.rethrow().is_some());
tc2.reset(); tc2.reset();
@ -603,15 +596,14 @@ fn try_catch_caught_lifetime() {
let context = v8::Context::new(scope); let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context); let scope = &mut v8::ContextScope::new(scope, context);
let (caught_exc, caught_msg) = { let (caught_exc, caught_msg) = {
let mut try_catch = v8::TryCatch::new(scope); let tc = &mut v8::TryCatch::new(scope);
let try_catch = try_catch.enter();
// Throw exception. // Throw exception.
let msg = v8::String::new(scope, "DANG!").unwrap(); let msg = v8::String::new(tc, "DANG!").unwrap();
let exc = v8::Exception::type_error(scope, msg); let exc = v8::Exception::type_error(tc, msg);
scope.throw_exception(exc); tc.throw_exception(exc);
// Catch exception. // Catch exception.
let caught_exc = try_catch.exception(scope).unwrap(); let caught_exc = tc.exception().unwrap();
let caught_msg = try_catch.message(scope).unwrap(); let caught_msg = tc.message().unwrap();
// Move `caught_exc` and `caught_msg` out of the extent of the TryCatch, // Move `caught_exc` and `caught_msg` out of the extent of the TryCatch,
// but still within the extent of the enclosing HandleScope. // but still within the extent of the enclosing HandleScope.
(caught_exc, caught_msg) (caught_exc, caught_msg)
@ -637,15 +629,14 @@ fn throw_exception() {
let context = v8::Context::new(scope); let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context); let scope = &mut v8::ContextScope::new(scope, context);
{ {
let mut try_catch = v8::TryCatch::new(scope); let tc = &mut v8::TryCatch::new(scope);
let tc = try_catch.enter(); let exception = v8::String::new(tc, "boom").unwrap();
let exception = v8::String::new(scope, "boom").unwrap(); tc.throw_exception(exception.into());
scope.throw_exception(exception.into());
assert!(tc.has_caught()); assert!(tc.has_caught());
assert!(tc assert!(tc
.exception(scope) .exception()
.unwrap() .unwrap()
.strict_equals(v8::String::new(scope, "boom").unwrap().into())); .strict_equals(v8::String::new(tc, "boom").unwrap().into()));
}; };
} }
} }
@ -1593,8 +1584,7 @@ fn module_instantiation_failures1() {
// Instantiation should fail. // Instantiation should fail.
{ {
let mut try_catch = v8::TryCatch::new(scope); let tc = &mut v8::TryCatch::new(scope);
let tc = try_catch.enter();
fn resolve_callback<'a>( fn resolve_callback<'a>(
context: v8::Local<'a, v8::Context>, context: v8::Local<'a, v8::Context>,
_specifier: v8::Local<'a, v8::String>, _specifier: v8::Local<'a, v8::String>,
@ -1610,9 +1600,9 @@ fn module_instantiation_failures1() {
assert!(result.is_none()); assert!(result.is_none());
assert!(tc.has_caught()); assert!(tc.has_caught());
assert!(tc assert!(tc
.exception(scope) .exception()
.unwrap() .unwrap()
.strict_equals(v8::String::new(scope, "boom").unwrap().into())); .strict_equals(v8::String::new(tc, "boom").unwrap().into()));
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status()); assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
} }
} }