rusty_v8/
scope.rs

1// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
2
3//! This module's public API exports a number of 'scope' types.
4//!
5//! These types carry information about the state of the V8 Isolate, as well as
6//! lifetimes for certain (return) values. More specialized scopes typically
7//! deref to more generic scopes, and ultimately they all deref to `Isolate`.
8//!
9//! The scope types in the public API are all pointer wrappers, and they all
10//! point at a heap-allocated struct `data::ScopeData`. `ScopeData` allocations
11//! are never shared between scopes; each Handle/Context/CallbackScope gets
12//! its own instance.
13//!
14//! Notes about the available scope types:
15//! See also the tests at the end of this file.
16//!
17//! - `HandleScope<'s, ()>`
18//!   - 's = lifetime of local handles created in this scope, and of the scope
19//!     itself.
20//!   - This type is returned when a HandleScope is constructed from a direct
21//!     reference to an isolate (`&mut Isolate` or `&mut OwnedIsolate`).
22//!   - A `Context` is _not_ available. Only certain types JavaScript values can
23//!     be created: primitive values, templates, and instances of `Context`.
24//!   - Derefs to `Isolate`.
25//!
26//! - `HandleScope<'s>`
27//!   - 's = lifetime of local handles created in this scope, and of the scope
28//!     itself.
29//!   - A `Context` is available; any type of value can be created.
30//!   - Derefs to `HandleScope<'s, ()>`
31//!
32//! - `ContextScope<'s, P>`
33//!   - 's = lifetime of the scope itself.
34//!   - A `Context` is available; any type of value can be created.
35//!   - Derefs to `P`.
36//!   - When constructed as the child of a `HandleScope<'a, ()>`, the returned
37//!     type is `ContextScope<'s, HandleScope<'p>>`. In other words, the parent
38//!     HandleScope gets an upgrade to indicate the availability of a `Context`.
39//!   - When a new scope is constructed inside this type of scope, the
40//!     `ContextScope` wrapper around `P` is erased first, which means that the
41//!     child scope is set up as if it had been created with `P` as its parent.
42//!
43//! - `EscapableHandleScope<'s, 'e>`
44//!   - 's = lifetime of local handles created in this scope, and of the scope
45//!     itself.
46//!   - 'e = lifetime of the HandleScope that will receive the local handle that
47//!     is created by `EscapableHandleScope::escape()`.
48//!   - A `Context` is available; any type of value can be created.
49//!   - Derefs to `HandleScope<'s>`.
50//!
51//! - `TryCatch<'s, P>`
52//!   - 's = lifetime of the TryCatch scope.
53//!   - `P` is either a `HandleScope` or an `EscapableHandleScope`. This type
54//!     also determines for how long the values returned by `TryCatch` methods
55//!     `exception()`, `message()`, and `stack_trace()` are valid.
56//!   - Derefs to `P`.
57//!   - Creating a new scope inside the `TryCatch` block makes its methods
58//!     inaccessible until the inner scope is dropped. However, the `TryCatch`
59//!     object will nonetheless catch all exception thrown during its lifetime.
60//!
61//! - `CallbackScope<'s, ()>`
62//!   - 's = lifetime of local handles created in this scope, and the value
63//!     returned from the callback, and of the scope itself.
64//!   - A `Context` is _not_ available. Only certain types JavaScript values can
65//!     be created: primitive values, templates, and instances of `Context`.
66//!   - Derefs to `HandleScope<'s, ()>`.
67//!   - This scope type is only to be constructed inside embedder defined
68//!     callbacks when these are called by V8.
69//!   - When a scope is created inside, type is erased to `HandleScope<'s, ()>`.
70//!
71//! - `CallbackScope<'s>`
72//!   - 's = lifetime of local handles created in this scope, and the value
73//!     returned from the callback, and of the scope itself.
74//!   - A `Context` is available; any type of value can be created.
75//!   - Derefs to `HandleScope<'s>`.
76//!   - This scope type is only to be constructed inside embedder defined
77//!     callbacks when these are called by V8.
78//!   - When a scope is created inside, type is erased to `HandleScope<'s>`.
79
80use std::alloc::alloc;
81use std::alloc::Layout;
82use std::any::type_name;
83use std::cell::Cell;
84use std::convert::TryInto;
85
86use std::marker::PhantomData;
87use std::mem::MaybeUninit;
88use std::num::NonZeroUsize;
89use std::ops::Deref;
90use std::ops::DerefMut;
91use std::ptr;
92use std::ptr::NonNull;
93
94use crate::function::FunctionCallbackInfo;
95use crate::function::PropertyCallbackInfo;
96use crate::Context;
97use crate::Data;
98use crate::DataError;
99use crate::Handle;
100use crate::Isolate;
101use crate::Local;
102use crate::Message;
103use crate::Object;
104use crate::OwnedIsolate;
105use crate::Primitive;
106use crate::PromiseRejectMessage;
107use crate::Value;
108
109/// Stack-allocated class which sets the execution context for all operations
110/// executed within a local scope. After entering a context, all code compiled
111/// and run is compiled and run in this context.
112#[derive(Debug)]
113pub struct ContextScope<'s, P> {
114  data: NonNull<data::ScopeData>,
115  _phantom: PhantomData<&'s mut P>,
116}
117
118impl<'s, P: param::NewContextScope<'s>> ContextScope<'s, P> {
119  #[allow(clippy::new_ret_no_self)]
120  pub fn new(param: &'s mut P, context: Local<Context>) -> P::NewScope {
121    let scope_data = param.get_scope_data_mut();
122    if scope_data.get_isolate_ptr()
123      != unsafe { raw::v8__Context__GetIsolate(&*context) }
124    {
125      panic!(
126        "{} and Context do not belong to the same Isolate",
127        type_name::<P>()
128      )
129    }
130    let new_scope_data = scope_data.new_context_scope_data(context);
131    new_scope_data.as_scope()
132  }
133}
134
135/// A stack-allocated class that governs a number of local handles.
136/// After a handle scope has been created, all local handles will be
137/// allocated within that handle scope until either the handle scope is
138/// deleted or another handle scope is created.  If there is already a
139/// handle scope and a new one is created, all allocations will take
140/// place in the new handle scope until it is deleted.  After that,
141/// new handles will again be allocated in the original handle scope.
142///
143/// After the handle scope of a local handle has been deleted the
144/// garbage collector will no longer track the object stored in the
145/// handle and may deallocate it.  The behavior of accessing a handle
146/// for which the handle scope has been deleted is undefined.
147#[derive(Debug)]
148pub struct HandleScope<'s, C = Context> {
149  data: NonNull<data::ScopeData>,
150  _phantom: PhantomData<&'s mut C>,
151}
152
153impl<'s> HandleScope<'s> {
154  #[allow(clippy::new_ret_no_self)]
155  pub fn new<P: param::NewHandleScope<'s>>(param: &'s mut P) -> P::NewScope {
156    param
157      .get_scope_data_mut()
158      .new_handle_scope_data()
159      .as_scope()
160  }
161
162  /// Opens a new `HandleScope` and enters a `Context` in one step.
163  /// The first argument should be an `Isolate` or `OwnedIsolate`.
164  /// The second argument can be any handle that refers to a `Context` object;
165  /// usually this will be a `Global<Context>`.
166  pub fn with_context<
167    P: param::NewHandleScopeWithContext<'s>,
168    H: Handle<Data = Context>,
169  >(
170    param: &'s mut P,
171    context: H,
172  ) -> Self {
173    let context_ref = context.open(param.get_isolate_mut());
174    param
175      .get_scope_data_mut()
176      .new_handle_scope_data_with_context(context_ref)
177      .as_scope()
178  }
179
180  /// Returns the context of the currently running JavaScript, or the context
181  /// on the top of the stack if no JavaScript is running.
182  pub fn get_current_context(&self) -> Local<'s, Context> {
183    let context_ptr = data::ScopeData::get(self).get_current_context();
184    unsafe { Local::from_raw(context_ptr) }.unwrap()
185  }
186
187  /// Returns either the last context entered through V8's C++ API, or the
188  /// context of the currently running microtask while processing microtasks.
189  /// If a context is entered while executing a microtask, that context is
190  /// returned.
191  pub fn get_entered_or_microtask_context(&self) -> Local<'s, Context> {
192    let data = data::ScopeData::get(self);
193    let isolate_ptr = data.get_isolate_ptr();
194    let context_ptr =
195      unsafe { raw::v8__Isolate__GetEnteredOrMicrotaskContext(isolate_ptr) };
196    unsafe { Local::from_raw(context_ptr) }.unwrap()
197  }
198}
199
200impl<'s> HandleScope<'s, ()> {
201  /// Schedules an exception to be thrown when returning to JavaScript. When
202  /// an exception has been scheduled it is illegal to invoke any
203  /// JavaScript operation; the caller must return immediately and only
204  /// after the exception has been handled does it become legal to invoke
205  /// JavaScript operations.
206  ///
207  /// This function always returns the `undefined` value.
208  pub fn throw_exception(
209    &mut self,
210    exception: Local<Value>,
211  ) -> Local<'s, Value> {
212    unsafe {
213      self.cast_local(|sd| {
214        raw::v8__Isolate__ThrowException(sd.get_isolate_ptr(), &*exception)
215      })
216    }
217    .unwrap()
218  }
219
220  pub(crate) unsafe fn cast_local<T>(
221    &mut self,
222    f: impl FnOnce(&mut data::ScopeData) -> *const T,
223  ) -> Option<Local<'s, T>> {
224    Local::from_raw(f(data::ScopeData::get_mut(self)))
225  }
226
227  pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate {
228    data::ScopeData::get(self).get_isolate_ptr()
229  }
230}
231
232impl<'s> HandleScope<'s> {
233  /// Return data that was previously attached to the isolate snapshot via
234  /// SnapshotCreator, and removes the reference to it. If called again with
235  /// same `index` argument, this function returns `DataError::NoData`.
236  ///
237  /// The value that was stored in the snapshot must either match or be
238  /// convertible to type parameter `T`, otherwise `DataError::BadType` is
239  /// returned.
240  pub fn get_isolate_data_from_snapshot_once<T>(
241    &mut self,
242    index: usize,
243  ) -> Result<Local<'s, T>, DataError>
244  where
245    T: 'static,
246    for<'l> Local<'l, Data>: TryInto<Local<'l, T>, Error = DataError>,
247  {
248    unsafe {
249      self
250        .cast_local(|sd| {
251          raw::v8__Isolate__GetDataFromSnapshotOnce(sd.get_isolate_ptr(), index)
252        })
253        .ok_or_else(DataError::no_data::<T>)
254        .and_then(|data| data.try_into())
255    }
256  }
257
258  /// Return data that was previously attached to the context snapshot via
259  /// SnapshotCreator, and removes the reference to it. If called again with
260  /// same `index` argument, this function returns `DataError::NoData`.
261  ///
262  /// The value that was stored in the snapshot must either match or be
263  /// convertible to type parameter `T`, otherwise `DataError::BadType` is
264  /// returned.
265  pub fn get_context_data_from_snapshot_once<T>(
266    &mut self,
267    index: usize,
268  ) -> Result<Local<'s, T>, DataError>
269  where
270    T: 'static,
271    for<'l> Local<'l, Data>: TryInto<Local<'l, T>, Error = DataError>,
272  {
273    unsafe {
274      self
275        .cast_local(|sd| {
276          raw::v8__Context__GetDataFromSnapshotOnce(
277            sd.get_current_context(),
278            index,
279          )
280        })
281        .ok_or_else(DataError::no_data::<T>)
282        .and_then(|data| data.try_into())
283    }
284  }
285}
286
287/// A HandleScope which first allocates a handle in the current scope
288/// which will be later filled with the escape value.
289// TODO(piscisaureus): type parameter `C` is not very useful in practice; being
290// a source of complexity and potential confusion, it is desirable to
291// eventually remove it. Blocker at the time of writing is that there are some
292// tests that enter an `EscapableHandleScope` without creating a `ContextScope`
293// at all. These tests need to updated first.
294#[derive(Debug)]
295pub struct EscapableHandleScope<'s, 'e: 's, C = Context> {
296  data: NonNull<data::ScopeData>,
297  _phantom:
298    PhantomData<(&'s mut raw::HandleScope, &'e mut raw::EscapeSlot, &'s C)>,
299}
300
301impl<'s, 'e: 's> EscapableHandleScope<'s, 'e> {
302  #[allow(clippy::new_ret_no_self)]
303  pub fn new<P: param::NewEscapableHandleScope<'s, 'e>>(
304    param: &'s mut P,
305  ) -> P::NewScope {
306    param
307      .get_scope_data_mut()
308      .new_escapable_handle_scope_data()
309      .as_scope()
310  }
311}
312
313impl<'s, 'e: 's, C> EscapableHandleScope<'s, 'e, C> {
314  /// Pushes the value into the previous scope and returns a handle to it.
315  /// Cannot be called twice.
316  pub fn escape<T>(&mut self, value: Local<T>) -> Local<'e, T>
317  where
318    for<'l> Local<'l, T>: Into<Local<'l, Data>>,
319  {
320    let escape_slot = data::ScopeData::get_mut(self)
321      .get_escape_slot_mut()
322      .expect("internal error: EscapableHandleScope has no escape slot")
323      .take()
324      .expect("EscapableHandleScope::escape() called twice");
325    escape_slot.escape(value)
326  }
327}
328
329/// An external exception handler.
330#[derive(Debug)]
331pub struct TryCatch<'s, P> {
332  data: NonNull<data::ScopeData>,
333  _phantom: PhantomData<&'s mut P>,
334}
335
336impl<'s, P: param::NewTryCatch<'s>> TryCatch<'s, P> {
337  #[allow(clippy::new_ret_no_self)]
338  pub fn new(param: &'s mut P) -> P::NewScope {
339    param.get_scope_data_mut().new_try_catch_data().as_scope()
340  }
341}
342
343impl<'s, P> TryCatch<'s, P> {
344  /// Returns true if an exception has been caught by this try/catch block.
345  pub fn has_caught(&self) -> bool {
346    unsafe { raw::v8__TryCatch__HasCaught(self.get_raw()) }
347  }
348
349  /// For certain types of exceptions, it makes no sense to continue execution.
350  ///
351  /// If CanContinue returns false, the correct action is to perform any C++
352  /// cleanup needed and then return. If CanContinue returns false and
353  /// HasTerminated returns true, it is possible to call
354  /// CancelTerminateExecution in order to continue calling into the engine.
355  pub fn can_continue(&self) -> bool {
356    unsafe { raw::v8__TryCatch__CanContinue(self.get_raw()) }
357  }
358
359  /// Returns true if an exception has been caught due to script execution
360  /// being terminated.
361  ///
362  /// There is no JavaScript representation of an execution termination
363  /// exception. Such exceptions are thrown when the TerminateExecution
364  /// methods are called to terminate a long-running script.
365  ///
366  /// If such an exception has been thrown, HasTerminated will return true,
367  /// indicating that it is possible to call CancelTerminateExecution in order
368  /// to continue calling into the engine.
369  pub fn has_terminated(&self) -> bool {
370    unsafe { raw::v8__TryCatch__HasTerminated(self.get_raw()) }
371  }
372
373  /// Returns true if verbosity is enabled.
374  pub fn is_verbose(&self) -> bool {
375    unsafe { raw::v8__TryCatch__IsVerbose(self.get_raw()) }
376  }
377
378  /// Set verbosity of the external exception handler.
379  ///
380  /// By default, exceptions that are caught by an external exception
381  /// handler are not reported. Call SetVerbose with true on an
382  /// external exception handler to have exceptions caught by the
383  /// handler reported as if they were not caught.
384  pub fn set_verbose(&mut self, value: bool) {
385    unsafe { raw::v8__TryCatch__SetVerbose(self.get_raw_mut(), value) };
386  }
387
388  /// Set whether or not this TryCatch should capture a Message object
389  /// which holds source information about where the exception
390  /// occurred. True by default.
391  pub fn set_capture_message(&mut self, value: bool) {
392    unsafe { raw::v8__TryCatch__SetCaptureMessage(self.get_raw_mut(), value) };
393  }
394
395  /// Clears any exceptions that may have been caught by this try/catch block.
396  /// After this method has been called, HasCaught() will return false. Cancels
397  /// the scheduled exception if it is caught and ReThrow() is not called
398  /// before.
399  ///
400  /// It is not necessary to clear a try/catch block before using it again; if
401  /// another exception is thrown the previously caught exception will just be
402  /// overwritten. However, it is often a good idea since it makes it easier
403  /// to determine which operation threw a given exception.
404  pub fn reset(&mut self) {
405    unsafe { raw::v8__TryCatch__Reset(self.get_raw_mut()) };
406  }
407
408  fn get_raw(&self) -> &raw::TryCatch {
409    data::ScopeData::get(self).get_try_catch()
410  }
411
412  fn get_raw_mut(&mut self) -> &mut raw::TryCatch {
413    data::ScopeData::get_mut(self).get_try_catch_mut()
414  }
415}
416
417impl<'s, 'p: 's, P> TryCatch<'s, P>
418where
419  Self: AsMut<HandleScope<'p, ()>>,
420{
421  /// Returns the exception caught by this try/catch block. If no exception has
422  /// been caught an empty handle is returned.
423  ///
424  /// Note: v8.h states that "the returned handle is valid until this TryCatch
425  /// block has been destroyed". This is incorrect; the return value lives
426  /// no longer and no shorter than the active HandleScope at the time this
427  /// method is called. An issue has been opened about this in the V8 bug
428  /// tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537.
429  pub fn exception(&mut self) -> Option<Local<'p, Value>> {
430    unsafe {
431      self
432        .as_mut()
433        .cast_local(|sd| raw::v8__TryCatch__Exception(sd.get_try_catch()))
434    }
435  }
436
437  /// Returns the message associated with this exception. If there is
438  /// no message associated an empty handle is returned.
439  ///
440  /// Note: the remark about the lifetime for the `exception()` return value
441  /// applies here too.
442  pub fn message(&mut self) -> Option<Local<'p, Message>> {
443    unsafe {
444      self
445        .as_mut()
446        .cast_local(|sd| raw::v8__TryCatch__Message(sd.get_try_catch()))
447    }
448  }
449
450  /// Throws the exception caught by this TryCatch in a way that avoids
451  /// it being caught again by this same TryCatch. As with ThrowException
452  /// it is illegal to execute any JavaScript operations after calling
453  /// ReThrow; the caller must return immediately to where the exception
454  /// is caught.
455  ///
456  /// This function returns the `undefined` value when successful, or `None` if
457  /// no exception was caught and therefore there was nothing to rethrow.
458  pub fn rethrow(&mut self) -> Option<Local<'_, Value>> {
459    unsafe {
460      self
461        .as_mut()
462        .cast_local(|sd| raw::v8__TryCatch__ReThrow(sd.get_try_catch_mut()))
463    }
464  }
465}
466
467impl<'s, 'p: 's, P> TryCatch<'s, P>
468where
469  Self: AsMut<HandleScope<'p>>,
470{
471  /// Returns the .stack property of the thrown object. If no .stack
472  /// property is present an empty handle is returned.
473  pub fn stack_trace(&mut self) -> Option<Local<'p, Value>> {
474    unsafe {
475      self.as_mut().cast_local(|sd| {
476        raw::v8__TryCatch__StackTrace(
477          sd.get_try_catch(),
478          sd.get_current_context(),
479        )
480      })
481    }
482  }
483}
484
485/// A `CallbackScope` can be used to bootstrap a `HandleScope` and
486/// `ContextScope` inside a callback function that gets called by V8.
487/// Bootstrapping a scope inside a callback is the only valid use case of this
488/// type; using it in other places leads to undefined behavior, which is also
489/// the reason `CallbackScope::new()` is marked as being an unsafe function.
490///
491/// For some callback types, rusty_v8 internally creates a scope and passes it
492/// as an argument to to embedder callback. Eventually we intend to wrap all
493/// callbacks in this fashion, so the embedder would never needs to construct
494/// a CallbackScope.
495///
496/// A `CallbackScope<()>`, without context, can be created from:
497///   - `&mut Isolate`
498///   - `&mut OwnedIsolate`
499///
500/// A `CallbackScope`, with context, can be created from:
501///   - `Local<Context>`
502///   - `Local<Message>`
503///   - `Local<Object>`
504///   - `Local<Promise>`
505///   - `Local<SharedArrayBuffer>`
506///   - `&FunctionCallbackInfo`
507///   - `&PropertyCallbackInfo`
508///   - `&PromiseRejectMessage`
509#[derive(Debug)]
510pub struct CallbackScope<'s, C = Context> {
511  data: NonNull<data::ScopeData>,
512  _phantom: PhantomData<&'s mut HandleScope<'s, C>>,
513}
514
515impl<'s> CallbackScope<'s> {
516  #[allow(clippy::new_ret_no_self)]
517  pub unsafe fn new<P: param::NewCallbackScope<'s>>(param: P) -> P::NewScope {
518    let (isolate, context) = param.get_isolate_mut_and_maybe_current_context();
519    data::ScopeData::get_current_mut(isolate)
520      .new_callback_scope_data(context)
521      .as_scope()
522  }
523}
524
525macro_rules! impl_as {
526  // Implements `AsRef<Isolate>` and AsMut<Isolate>` on a scope type.
527  (<$($params:tt),+> $src_type:ty as Isolate) => {
528    impl<$($params),*> AsRef<Isolate> for $src_type {
529      fn as_ref(&self) -> &Isolate {
530        data::ScopeData::get(self).get_isolate()
531      }
532    }
533
534    impl<$($params),*> AsMut<Isolate> for $src_type {
535      fn as_mut(&mut self) -> &mut Isolate {
536        data::ScopeData::get_mut(self).get_isolate_mut()
537      }
538    }
539  };
540
541  // Implements `AsRef` and `AsMut` traits for the purpose of converting a
542  // a scope reference to a scope reference with a different but compatible type.
543  (<$($params:tt),+> $src_type:ty as $tgt_type:ty) => {
544    impl<$($params),*> AsRef<$tgt_type> for $src_type {
545      fn as_ref(&self) -> &$tgt_type {
546        self.cast_ref()
547      }
548    }
549
550    impl<$($params),*> AsMut< $tgt_type> for $src_type {
551      fn as_mut(&mut self) -> &mut $tgt_type {
552        self.cast_mut()
553      }
554    }
555  };
556}
557
558impl_as!(<'s, 'p, P> ContextScope<'s, P> as Isolate);
559impl_as!(<'s, C> HandleScope<'s, C> as Isolate);
560impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as Isolate);
561impl_as!(<'s, P> TryCatch<'s, P> as Isolate);
562impl_as!(<'s, C> CallbackScope<'s, C> as Isolate);
563
564impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p, ()>);
565impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p, ()>);
566impl_as!(<'s, C> HandleScope<'s, C> as HandleScope<'s, ()>);
567impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as HandleScope<'s, ()>);
568impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as HandleScope<'p, ()>);
569impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>);
570impl_as!(<'s, C> CallbackScope<'s, C> as HandleScope<'s, ()>);
571
572impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>);
573impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>);
574impl_as!(<'s> HandleScope<'s> as HandleScope<'s>);
575impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>);
576impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>);
577impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>);
578impl_as!(<'s> CallbackScope<'s> as HandleScope<'s>);
579
580impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e, ()>);
581impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as EscapableHandleScope<'s, 'e, ()>);
582impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>);
583
584impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
585impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as EscapableHandleScope<'s, 'e>);
586impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
587
588impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as TryCatch<'s, HandleScope<'p, ()>>);
589impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, HandleScope<'p, ()>>);
590impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, EscapableHandleScope<'p, 'e, ()>>);
591
592impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as TryCatch<'s, HandleScope<'p>>);
593impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, HandleScope<'p>>);
594impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, EscapableHandleScope<'p, 'e>>);
595
596macro_rules! impl_deref {
597  (<$($params:tt),+> $src_type:ty as $tgt_type:ty) => {
598    impl<$($params),*> Deref for $src_type {
599      type Target = $tgt_type;
600      fn deref(&self) -> &Self::Target {
601        self.as_ref()
602      }
603    }
604
605    impl<$($params),*> DerefMut for $src_type {
606      fn deref_mut(&mut self) -> &mut Self::Target {
607        self.as_mut()
608      }
609    }
610  };
611}
612
613impl_deref!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>);
614impl_deref!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
615
616impl_deref!(<'s> HandleScope<'s, ()> as Isolate);
617impl_deref!(<'s> HandleScope<'s> as HandleScope<'s, ()>);
618
619impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e, ()> as HandleScope<'s, ()>);
620impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>);
621
622impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>);
623impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>);
624impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>);
625impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>);
626
627impl_deref!(<'s> CallbackScope<'s, ()> as HandleScope<'s, ()>);
628impl_deref!(<'s> CallbackScope<'s> as HandleScope<'s>);
629
630macro_rules! impl_scope_drop {
631  (<$($params:tt),+> $type:ty) => {
632    unsafe impl<$($params),*> Scope for $type {}
633
634    impl<$($params),*> Drop for $type {
635      fn drop(&mut self) {
636        data::ScopeData::get_mut(self).notify_scope_dropped();
637      }
638    }
639  };
640}
641
642impl_scope_drop!(<'s, 'p, P> ContextScope<'s, P>);
643impl_scope_drop!(<'s, C> HandleScope<'s, C> );
644impl_scope_drop!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> );
645impl_scope_drop!(<'s, P> TryCatch<'s, P> );
646impl_scope_drop!(<'s, C> CallbackScope<'s, C> );
647
648pub unsafe trait Scope: Sized {}
649
650trait ScopeCast: Sized {
651  fn cast_ref<S: Scope>(&self) -> &S;
652  fn cast_mut<S: Scope>(&mut self) -> &mut S;
653}
654
655impl<T: Scope> ScopeCast for T {
656  fn cast_ref<S: Scope>(&self) -> &S {
657    assert_eq!(Layout::new::<Self>(), Layout::new::<S>());
658    unsafe { &*(self as *const _ as *const S) }
659  }
660
661  fn cast_mut<S: Scope>(&mut self) -> &mut S {
662    assert_eq!(Layout::new::<Self>(), Layout::new::<S>());
663    unsafe { &mut *(self as *mut _ as *mut S) }
664  }
665}
666
667/// Scopes are typically constructed as the child of another scope. The scope
668/// that is returned from `«Child»Scope::new(parent: &mut «Parent»Scope)` does
669/// not necessarily have type `«Child»Scope`, but rather its type is a merger of
670/// both the the parent and child scope types.
671///
672/// For example: a `ContextScope` created inside `HandleScope<'a, ()>` does not
673/// produce a `ContextScope`, but rather a `HandleScope<'a, Context>`, which
674/// describes a scope that is both a `HandleScope` _and_ a `ContextScope`.
675///
676/// The Traits in the (private) `param` module define which types can be passed
677/// as a parameter to the `«Some»Scope::new()` constructor, and what the
678/// actual, merged scope type will be that `new()` returns for a specific
679/// parameter type.
680mod param {
681  use super::*;
682
683  pub trait NewContextScope<'s>: getter::GetScopeData {
684    type NewScope: Scope;
685  }
686
687  impl<'s, 'p: 's, P: Scope> NewContextScope<'s> for ContextScope<'p, P> {
688    type NewScope = ContextScope<'s, P>;
689  }
690
691  impl<'s, 'p: 's, C> NewContextScope<'s> for HandleScope<'p, C> {
692    type NewScope = ContextScope<'s, HandleScope<'p>>;
693  }
694
695  impl<'s, 'p: 's, 'e: 'p, C> NewContextScope<'s>
696    for EscapableHandleScope<'p, 'e, C>
697  {
698    type NewScope = ContextScope<'s, EscapableHandleScope<'p, 'e>>;
699  }
700
701  impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s>
702    for TryCatch<'p, P>
703  {
704    type NewScope = <P as NewContextScope<'s>>::NewScope;
705  }
706
707  impl<'s, 'p: 's, C> NewContextScope<'s> for CallbackScope<'p, C> {
708    type NewScope = ContextScope<'s, HandleScope<'p>>;
709  }
710
711  pub trait NewHandleScope<'s>: getter::GetScopeData {
712    type NewScope: Scope;
713  }
714
715  impl<'s> NewHandleScope<'s> for Isolate {
716    type NewScope = HandleScope<'s, ()>;
717  }
718
719  impl<'s> NewHandleScope<'s> for OwnedIsolate {
720    type NewScope = HandleScope<'s, ()>;
721  }
722
723  impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s>
724    for ContextScope<'p, P>
725  {
726    type NewScope = <P as NewHandleScope<'s>>::NewScope;
727  }
728
729  impl<'s, 'p: 's, C> NewHandleScope<'s> for HandleScope<'p, C> {
730    type NewScope = HandleScope<'s, C>;
731  }
732
733  impl<'s, 'p: 's, 'e: 'p, C> NewHandleScope<'s>
734    for EscapableHandleScope<'p, 'e, C>
735  {
736    type NewScope = EscapableHandleScope<'s, 'e, C>;
737  }
738
739  impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> for TryCatch<'p, P> {
740    type NewScope = <P as NewHandleScope<'s>>::NewScope;
741  }
742
743  impl<'s, 'p: 's, C> NewHandleScope<'s> for CallbackScope<'p, C> {
744    type NewScope = HandleScope<'s, C>;
745  }
746
747  pub trait NewHandleScopeWithContext<'s>: getter::GetScopeData {
748    fn get_isolate_mut(&mut self) -> &mut Isolate;
749  }
750
751  impl<'s> NewHandleScopeWithContext<'s> for Isolate {
752    fn get_isolate_mut(&mut self) -> &mut Isolate {
753      self
754    }
755  }
756
757  impl<'s> NewHandleScopeWithContext<'s> for OwnedIsolate {
758    fn get_isolate_mut(&mut self) -> &mut Isolate {
759      &mut *self
760    }
761  }
762
763  pub trait NewEscapableHandleScope<'s, 'e: 's>: getter::GetScopeData {
764    type NewScope: Scope;
765  }
766
767  impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>>
768    NewEscapableHandleScope<'s, 'e> for ContextScope<'p, P>
769  {
770    type NewScope = <P as NewEscapableHandleScope<'s, 'e>>::NewScope;
771  }
772
773  impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for HandleScope<'p, C> {
774    type NewScope = EscapableHandleScope<'s, 'p, C>;
775  }
776
777  impl<'s, 'p: 's, 'e: 'p, C> NewEscapableHandleScope<'s, 'p>
778    for EscapableHandleScope<'p, 'e, C>
779  {
780    type NewScope = EscapableHandleScope<'s, 'p, C>;
781  }
782
783  impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>>
784    NewEscapableHandleScope<'s, 'e> for TryCatch<'p, P>
785  {
786    type NewScope = <P as NewEscapableHandleScope<'s, 'e>>::NewScope;
787  }
788
789  impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for CallbackScope<'p, C> {
790    type NewScope = EscapableHandleScope<'s, 'p, C>;
791  }
792
793  pub trait NewTryCatch<'s>: getter::GetScopeData {
794    type NewScope: Scope;
795  }
796
797  impl<'s, 'p: 's, P: NewTryCatch<'s>> NewTryCatch<'s> for ContextScope<'p, P> {
798    type NewScope = <P as NewTryCatch<'s>>::NewScope;
799  }
800
801  impl<'s, 'p: 's, C> NewTryCatch<'s> for HandleScope<'p, C> {
802    type NewScope = TryCatch<'s, HandleScope<'p, C>>;
803  }
804
805  impl<'s, 'p: 's, 'e: 'p, C> NewTryCatch<'s>
806    for EscapableHandleScope<'p, 'e, C>
807  {
808    type NewScope = TryCatch<'s, EscapableHandleScope<'p, 'e, C>>;
809  }
810
811  impl<'s, 'p: 's, P> NewTryCatch<'s> for TryCatch<'p, P> {
812    type NewScope = TryCatch<'s, P>;
813  }
814
815  impl<'s, 'p: 's, C> NewTryCatch<'s> for CallbackScope<'p, C> {
816    type NewScope = TryCatch<'s, HandleScope<'p, C>>;
817  }
818
819  pub trait NewCallbackScope<'s>: Sized + getter::GetIsolate<'s> {
820    type NewScope: Scope;
821
822    unsafe fn get_isolate_mut_and_maybe_current_context(
823      self,
824    ) -> (&'s mut Isolate, Option<Local<'s, Context>>) {
825      (self.get_isolate_mut(), None)
826    }
827  }
828
829  impl<'s> NewCallbackScope<'s> for &'s mut Isolate {
830    type NewScope = CallbackScope<'s, ()>;
831  }
832
833  impl<'s> NewCallbackScope<'s> for &'s mut OwnedIsolate {
834    type NewScope = CallbackScope<'s, ()>;
835  }
836
837  impl<'s> NewCallbackScope<'s> for &'s FunctionCallbackInfo {
838    type NewScope = CallbackScope<'s>;
839  }
840
841  impl<'s> NewCallbackScope<'s> for &'s PropertyCallbackInfo {
842    type NewScope = CallbackScope<'s>;
843  }
844
845  impl<'s> NewCallbackScope<'s> for Local<'s, Context> {
846    type NewScope = CallbackScope<'s>;
847
848    unsafe fn get_isolate_mut_and_maybe_current_context(
849      self,
850    ) -> (&'s mut Isolate, Option<Local<'s, Context>>) {
851      (getter::GetIsolate::get_isolate_mut(self), Some(self))
852    }
853  }
854
855  impl<'s> NewCallbackScope<'s> for Local<'s, Message> {
856    type NewScope = CallbackScope<'s>;
857  }
858
859  impl<'s, T: Into<Local<'s, Object>>> NewCallbackScope<'s> for T {
860    type NewScope = CallbackScope<'s>;
861  }
862
863  impl<'s> NewCallbackScope<'s> for &'s PromiseRejectMessage<'s> {
864    type NewScope = CallbackScope<'s>;
865  }
866}
867
868/// The private `getter` module defines traits to look up the related `Isolate`
869/// and `ScopeData` for many different types. The implementation of those traits
870/// on the types that implement them are also all contained in this module.
871mod getter {
872  pub use super::*;
873
874  pub trait GetIsolate<'s> {
875    unsafe fn get_isolate_mut(self) -> &'s mut Isolate;
876  }
877
878  impl<'s> GetIsolate<'s> for &'s mut Isolate {
879    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
880      self
881    }
882  }
883
884  impl<'s> GetIsolate<'s> for &'s mut OwnedIsolate {
885    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
886      &mut *self
887    }
888  }
889
890  impl<'s> GetIsolate<'s> for &'s FunctionCallbackInfo {
891    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
892      &mut *raw::v8__FunctionCallbackInfo__GetIsolate(self)
893    }
894  }
895
896  impl<'s> GetIsolate<'s> for &'s PropertyCallbackInfo {
897    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
898      &mut *raw::v8__PropertyCallbackInfo__GetIsolate(self)
899    }
900  }
901
902  impl<'s> GetIsolate<'s> for Local<'s, Context> {
903    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
904      &mut *raw::v8__Context__GetIsolate(&*self)
905    }
906  }
907
908  impl<'s> GetIsolate<'s> for Local<'s, Message> {
909    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
910      &mut *raw::v8__Message__GetIsolate(&*self)
911    }
912  }
913
914  impl<'s, T: Into<Local<'s, Object>>> GetIsolate<'s> for T {
915    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
916      let object: Local<Object> = self.into();
917      &mut *raw::v8__Object__GetIsolate(&*object)
918    }
919  }
920
921  impl<'s> GetIsolate<'s> for &'s PromiseRejectMessage<'s> {
922    unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
923      let object: Local<Object> = self.get_promise().into();
924      &mut *raw::v8__Object__GetIsolate(&*object)
925    }
926  }
927
928  pub trait GetScopeData {
929    fn get_scope_data_mut(&mut self) -> &mut data::ScopeData;
930  }
931
932  impl<T: Scope> GetScopeData for T {
933    fn get_scope_data_mut(&mut self) -> &mut data::ScopeData {
934      data::ScopeData::get_mut(self)
935    }
936  }
937
938  impl GetScopeData for Isolate {
939    fn get_scope_data_mut(&mut self) -> &mut data::ScopeData {
940      data::ScopeData::get_root_mut(self)
941    }
942  }
943
944  impl GetScopeData for OwnedIsolate {
945    fn get_scope_data_mut(&mut self) -> &mut data::ScopeData {
946      data::ScopeData::get_root_mut(self)
947    }
948  }
949}
950
951/// All publicly exported `«Some»Scope` types are essentially wrapping a pointer
952/// to a heap-allocated struct `ScopeData`. This module contains the definition
953/// for `ScopeData` and its inner types, as well as related helper traits.
954pub(crate) mod data {
955  use super::*;
956
957  #[derive(Debug)]
958  pub struct ScopeData {
959    // The first four fields are always valid - even when the `Box<ScopeData>`
960    // struct is free (does not contain data related to an actual scope).
961    // The `previous` and `isolate` fields never change; the `next` field is
962    // set to `None` initially when the struct is created, but it may later be
963    // assigned a `Some(Box<ScopeData>)` value, after which this field never
964    // changes again.
965    isolate: NonNull<Isolate>,
966    previous: Option<NonNull<ScopeData>>,
967    next: Option<Box<ScopeData>>,
968    // The 'status' field is also always valid (but does change).
969    status: Cell<ScopeStatus>,
970    // The following fields are only valid when this ScopeData object is in use
971    // (eiter current or shadowed -- not free).
972    context: Cell<Option<NonNull<Context>>>,
973    escape_slot: Option<NonNull<Option<raw::EscapeSlot>>>,
974    try_catch: Option<NonNull<raw::TryCatch>>,
975    scope_type_specific_data: ScopeTypeSpecificData,
976  }
977
978  impl ScopeData {
979    /// Returns a mutable reference to the data associated with topmost scope
980    /// on the scope stack. This function does not automatically exit zombie
981    /// scopes, so it might return a zombie ScopeData reference.
982    pub(crate) fn get_current_mut(isolate: &mut Isolate) -> &mut Self {
983      let self_mut = isolate
984        .get_current_scope_data()
985        .map(NonNull::as_ptr)
986        .map(|p| unsafe { &mut *p })
987        .unwrap();
988      match self_mut.status.get() {
989        ScopeStatus::Current { .. } => self_mut,
990        _ => unreachable!(),
991      }
992    }
993
994    /// Initializes the scope stack by creating a 'dummy' `ScopeData` at the
995    /// very bottom. This makes it possible to store the freelist of reusable
996    /// ScopeData objects even when no scope is entered.
997    pub(crate) fn new_root(isolate: &mut Isolate) {
998      let root = Box::leak(Self::boxed(isolate.into()));
999      root.status = ScopeStatus::Current { zombie: false }.into();
1000      debug_assert!(isolate.get_current_scope_data().is_none());
1001      isolate.set_current_scope_data(Some(root.into()));
1002    }
1003
1004    /// Activates and returns the 'root' `ScopeData` object that is created when
1005    /// the isolate is initialized. In order to do so, any zombie scopes that
1006    /// remain on the scope stack are cleaned up.
1007    ///
1008    /// # Panics
1009    ///
1010    /// This function panics if the root can't be activated because there are
1011    /// still other scopes on the stack and they're not zombies.
1012    pub(crate) fn get_root_mut(isolate: &mut Isolate) -> &mut Self {
1013      let mut current_scope_data = Self::get_current_mut(isolate);
1014      loop {
1015        current_scope_data = match current_scope_data {
1016          root if root.previous.is_none() => break root,
1017          data => data.try_exit_scope(),
1018        };
1019      }
1020    }
1021
1022    /// Drops the scope stack and releases all `Box<ScopeData>` allocations.
1023    /// This function should be called only when an Isolate is being disposed.
1024    pub(crate) fn drop_root(isolate: &mut Isolate) {
1025      let root = Self::get_root_mut(isolate);
1026      unsafe { Box::from_raw(root) };
1027      isolate.set_current_scope_data(None);
1028    }
1029
1030    pub(super) fn new_context_scope_data<'s>(
1031      &'s mut self,
1032      context: Local<'s, Context>,
1033    ) -> &'s mut Self {
1034      self.new_scope_data_with(move |data| {
1035        data.scope_type_specific_data.init_with(|| {
1036          ScopeTypeSpecificData::ContextScope {
1037            raw_context_scope: raw::ContextScope::new(context),
1038          }
1039        });
1040        data.context.set(Some(context.as_non_null()));
1041      })
1042    }
1043
1044    /// Implementation helper function, which creates the raw `HandleScope`, but
1045    /// defers (maybe) entering a context to the provided callback argument.
1046    /// This function gets called by `Self::new_handle_scope_data()` and
1047    /// `Self::new_handle_scope_data_with_context()`.
1048    #[inline(always)]
1049    fn new_handle_scope_data_with<F>(&mut self, init_context_fn: F) -> &mut Self
1050    where
1051      F: FnOnce(
1052        NonNull<Isolate>,
1053        &mut Cell<Option<NonNull<Context>>>,
1054        &mut Option<raw::ContextScope>,
1055      ),
1056    {
1057      self.new_scope_data_with(|data| {
1058        let isolate = data.isolate;
1059        data.scope_type_specific_data.init_with(|| {
1060          ScopeTypeSpecificData::HandleScope {
1061            raw_handle_scope: unsafe { raw::HandleScope::uninit() },
1062            raw_context_scope: None,
1063          }
1064        });
1065        match &mut data.scope_type_specific_data {
1066          ScopeTypeSpecificData::HandleScope {
1067            raw_handle_scope,
1068            raw_context_scope,
1069          } => {
1070            unsafe { raw_handle_scope.init(isolate) };
1071            init_context_fn(isolate, &mut data.context, raw_context_scope);
1072          }
1073          _ => unreachable!(),
1074        };
1075      })
1076    }
1077
1078    pub(super) fn new_handle_scope_data(&mut self) -> &mut Self {
1079      self.new_handle_scope_data_with(|_, _, raw_context_scope| {
1080        debug_assert!(raw_context_scope.is_none())
1081      })
1082    }
1083
1084    pub(super) fn new_handle_scope_data_with_context(
1085      &mut self,
1086      context_ref: &Context,
1087    ) -> &mut Self {
1088      self.new_handle_scope_data_with(
1089        move |isolate, context_data, raw_context_scope| unsafe {
1090          let context_nn = NonNull::from(context_ref);
1091          // Copy the `Context` reference to a new local handle to enure that it
1092          // cannot get garbage collected until after this scope is dropped.
1093          let local_context_ptr =
1094            raw::v8__Local__New(isolate.as_ptr(), context_nn.cast().as_ptr())
1095              as *const Context;
1096          let local_context_nn =
1097            NonNull::new_unchecked(local_context_ptr as *mut _);
1098          let local_context = Local::from_non_null(local_context_nn);
1099          // Initialize the `raw::ContextScope`. This enters the context too.
1100          debug_assert!(raw_context_scope.is_none());
1101          ptr::write(
1102            raw_context_scope,
1103            Some(raw::ContextScope::new(local_context)),
1104          );
1105          // Also store the newly created `Local<Context>` in the `Cell` that
1106          // serves as a look-up cache for the current context.
1107          context_data.set(Some(local_context_nn));
1108        },
1109      )
1110    }
1111
1112    pub(super) fn new_escapable_handle_scope_data(&mut self) -> &mut Self {
1113      self.new_scope_data_with(|data| {
1114        // Note: the `raw_escape_slot` field must be initialized _before_ the
1115        // `raw_handle_scope` field, otherwise the escaped local handle ends up
1116        // inside the `EscapableHandleScope` that's being constructed here,
1117        // rather than escaping from it.
1118        let isolate = data.isolate;
1119        data.scope_type_specific_data.init_with(|| {
1120          ScopeTypeSpecificData::EscapableHandleScope {
1121            raw_handle_scope: unsafe { raw::HandleScope::uninit() },
1122            raw_escape_slot: Some(raw::EscapeSlot::new(isolate)),
1123          }
1124        });
1125        match &mut data.scope_type_specific_data {
1126          ScopeTypeSpecificData::EscapableHandleScope {
1127            raw_handle_scope,
1128            raw_escape_slot,
1129          } => {
1130            unsafe { raw_handle_scope.init(isolate) };
1131            data.escape_slot.replace(raw_escape_slot.into());
1132          }
1133          _ => unreachable!(),
1134        }
1135      })
1136    }
1137
1138    pub(super) fn new_try_catch_data(&mut self) -> &mut Self {
1139      self.new_scope_data_with(|data| {
1140        let isolate = data.isolate;
1141        data.scope_type_specific_data.init_with(|| {
1142          ScopeTypeSpecificData::TryCatch {
1143            raw_try_catch: unsafe { raw::TryCatch::uninit() },
1144          }
1145        });
1146        match &mut data.scope_type_specific_data {
1147          ScopeTypeSpecificData::TryCatch { raw_try_catch } => {
1148            unsafe { raw_try_catch.init(isolate) };
1149            data.try_catch.replace(raw_try_catch.into());
1150          }
1151          _ => unreachable!(),
1152        }
1153      })
1154    }
1155
1156    pub(super) fn new_callback_scope_data<'s>(
1157      &'s mut self,
1158      maybe_current_context: Option<Local<'s, Context>>,
1159    ) -> &'s mut Self {
1160      self.new_scope_data_with(|data| {
1161        debug_assert!(data.scope_type_specific_data.is_none());
1162        data
1163          .context
1164          .set(maybe_current_context.map(|cx| cx.as_non_null()));
1165      })
1166    }
1167
1168    fn new_scope_data_with(
1169      &mut self,
1170      init_fn: impl FnOnce(&mut Self),
1171    ) -> &mut Self {
1172      // Mark this scope (the parent of the newly created scope) as 'shadowed';
1173      self.status.set(match self.status.get() {
1174        ScopeStatus::Current { zombie } => ScopeStatus::Shadowed { zombie },
1175        _ => unreachable!(),
1176      });
1177      // Copy fields that that will be inherited by the new scope.
1178      let context = self.context.get().into();
1179      let escape_slot = self.escape_slot;
1180      // Initialize the `struct ScopeData` for the new scope.
1181      let new_scope_data = self.allocate_or_reuse_scope_data();
1182      // In debug builds, `zombie` is initially set to `true`, and the flag is
1183      // later cleared in the `as_scope()` method, to verify that we're
1184      // always creating exactly one scope from any `ScopeData` object.
1185      // For performance reasons this check is not performed in release builds.
1186      new_scope_data.status = Cell::new(ScopeStatus::Current {
1187        zombie: cfg!(debug_assertions),
1188      });
1189      // Store fields inherited from the parent scope.
1190      new_scope_data.context = context;
1191      new_scope_data.escape_slot = escape_slot;
1192      (init_fn)(new_scope_data);
1193      // Make the newly created scope the 'current' scope for this isolate.
1194      let new_scope_nn = unsafe { NonNull::new_unchecked(new_scope_data) };
1195      new_scope_data
1196        .get_isolate_mut()
1197        .set_current_scope_data(Some(new_scope_nn));
1198      new_scope_data
1199    }
1200
1201    /// Either returns an free `Box<ScopeData>` that is available for reuse,
1202    /// or allocates a new one on the heap.
1203    fn allocate_or_reuse_scope_data(&mut self) -> &mut Self {
1204      let self_nn = NonNull::new(self);
1205      match &mut self.next {
1206        Some(next_box) => {
1207          // Reuse a free `Box<ScopeData>` allocation.
1208          debug_assert_eq!(next_box.isolate, self.isolate);
1209          debug_assert_eq!(next_box.previous, self_nn);
1210          debug_assert_eq!(next_box.status.get(), ScopeStatus::Free);
1211          debug_assert!(next_box.scope_type_specific_data.is_none());
1212          next_box.as_mut()
1213        }
1214        next_field @ None => {
1215          // Allocate a new `Box<ScopeData>`.
1216          let mut next_box = Self::boxed(self.isolate);
1217          next_box.previous = self_nn;
1218          next_field.replace(next_box);
1219          next_field.as_mut().unwrap()
1220        }
1221      }
1222    }
1223
1224    pub(super) fn as_scope<S: Scope>(&mut self) -> S {
1225      assert_eq!(Layout::new::<&mut Self>(), Layout::new::<S>());
1226      // In debug builds, a new initialized `ScopeStatus` will have the `zombie`
1227      // flag set, so we have to reset it. In release builds, new `ScopeStatus`
1228      // objects come with the `zombie` flag cleared, so no update is necessary.
1229      if cfg!(debug_assertions) {
1230        assert_eq!(self.status.get(), ScopeStatus::Current { zombie: true });
1231        self.status.set(ScopeStatus::Current { zombie: false });
1232      }
1233      let self_nn = NonNull::from(self);
1234      unsafe { ptr::read(&self_nn as *const _ as *const S) }
1235    }
1236
1237    pub(super) fn get<S: Scope>(scope: &S) -> &Self {
1238      let self_mut = unsafe {
1239        (*(scope as *const S as *mut S as *mut NonNull<Self>)).as_mut()
1240      };
1241      self_mut.try_activate_scope();
1242      self_mut
1243    }
1244
1245    pub(super) fn get_mut<S: Scope>(scope: &mut S) -> &mut Self {
1246      let self_mut =
1247        unsafe { (*(scope as *mut S as *mut NonNull<Self>)).as_mut() };
1248      self_mut.try_activate_scope();
1249      self_mut
1250    }
1251
1252    #[inline(always)]
1253    fn try_activate_scope(mut self: &mut Self) -> &mut Self {
1254      self = match self.status.get() {
1255        ScopeStatus::Current { zombie: false } => self,
1256        ScopeStatus::Shadowed { zombie: false } => {
1257          self.next.as_mut().unwrap().try_exit_scope()
1258        }
1259        _ => unreachable!(),
1260      };
1261      debug_assert_eq!(
1262        self.get_isolate().get_current_scope_data(),
1263        NonNull::new(self as *mut _)
1264      );
1265      self
1266    }
1267
1268    fn try_exit_scope(mut self: &mut Self) -> &mut Self {
1269      loop {
1270        self = match self.status.get() {
1271          ScopeStatus::Shadowed { .. } => {
1272            self.next.as_mut().unwrap().try_exit_scope()
1273          }
1274          ScopeStatus::Current { zombie: true } => break self.exit_scope(),
1275          ScopeStatus::Current { zombie: false } => {
1276            panic!("active scope can't be dropped")
1277          }
1278          _ => unreachable!(),
1279        }
1280      }
1281    }
1282
1283    fn exit_scope(&mut self) -> &mut Self {
1284      // Clear out the scope type specific data field. None of the other fields
1285      // have a destructor, and there's no need to do any cleanup on them.
1286      self.scope_type_specific_data = Default::default();
1287      // Change the ScopeData's status field from 'Current' to 'Free', which
1288      // means that it is not associated with a scope and can be reused.
1289      self.status.set(ScopeStatus::Free);
1290
1291      // Point the Isolate's current scope data slot at our parent scope.
1292      let previous_nn = self.previous.unwrap();
1293      self
1294        .get_isolate_mut()
1295        .set_current_scope_data(Some(previous_nn));
1296      // Update the parent scope's status field to reflect that it is now
1297      // 'Current' again an no longer 'Shadowed'.
1298      let previous_mut = unsafe { &mut *previous_nn.as_ptr() };
1299      previous_mut.status.set(match previous_mut.status.get() {
1300        ScopeStatus::Shadowed { zombie } => ScopeStatus::Current { zombie },
1301        _ => unreachable!(),
1302      });
1303
1304      previous_mut
1305    }
1306
1307    /// This function is called when any of the public scope objects (e.g
1308    /// `HandleScope`, `ContextScope`, etc.) are dropped.
1309    ///
1310    /// The Rust borrow checker allows values of type `HandleScope<'a>` and
1311    /// `EscapableHandleScope<'a, 'e>` to be dropped before their maximum
1312    /// lifetime ('a) is up. This creates a potential problem because any local
1313    /// handles that are created while these scopes are active are bound to
1314    /// that 'a lifetime. This means that we run the risk of creating local
1315    /// handles that outlive their creation scope.
1316    ///
1317    /// Therefore, we don't immediately exit the current scope at the very
1318    /// moment the user drops their Escapable/HandleScope handle.
1319    /// Instead, the current scope is marked as being a 'zombie': the scope
1320    /// itself is gone, but its data still on the stack. The zombie's data will
1321    /// be dropped when the user touches the parent scope; when that happens, it
1322    /// is certain that there are no accessible `Local<'a, T>` handles left,
1323    /// because the 'a lifetime ends there.
1324    ///
1325    /// Scope types that do no store local handles are exited immediately.
1326    pub(super) fn notify_scope_dropped(&mut self) {
1327      match &self.scope_type_specific_data {
1328        ScopeTypeSpecificData::HandleScope { .. }
1329        | ScopeTypeSpecificData::EscapableHandleScope { .. } => {
1330          // Defer scope exit until the parent scope is touched.
1331          self.status.set(match self.status.get() {
1332            ScopeStatus::Current { zombie: false } => {
1333              ScopeStatus::Current { zombie: true }
1334            }
1335            _ => unreachable!(),
1336          })
1337        }
1338        _ => {
1339          // Regular, immediate exit.
1340          self.exit_scope();
1341        }
1342      }
1343    }
1344
1345    pub(crate) fn get_isolate(&self) -> &Isolate {
1346      unsafe { self.isolate.as_ref() }
1347    }
1348
1349    pub(crate) fn get_isolate_mut(&mut self) -> &mut Isolate {
1350      unsafe { self.isolate.as_mut() }
1351    }
1352
1353    pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate {
1354      self.isolate.as_ptr()
1355    }
1356
1357    pub(crate) fn get_current_context(&self) -> *const Context {
1358      // To avoid creating a new Local every time `get_current_context() is
1359      // called, the current context is usually cached in the `context` field.
1360      // If the `context` field contains `None`, this might mean that this cache
1361      // field never got populated, so we'll do that here when necessary.
1362      let get_current_context_from_isolate = || unsafe {
1363        raw::v8__Isolate__GetCurrentContext(self.get_isolate_ptr())
1364      };
1365      match self.context.get().map(|nn| nn.as_ptr() as *const _) {
1366        Some(context) => {
1367          debug_assert!(unsafe {
1368            raw::v8__Context__EQ(context, get_current_context_from_isolate())
1369          });
1370          context
1371        }
1372        None => {
1373          let context = get_current_context_from_isolate();
1374          self.context.set(NonNull::new(context as *mut _));
1375          context
1376        }
1377      }
1378    }
1379
1380    pub(super) fn get_escape_slot_mut(
1381      &mut self,
1382    ) -> Option<&mut Option<raw::EscapeSlot>> {
1383      self
1384        .escape_slot
1385        .as_mut()
1386        .map(|escape_slot_nn| unsafe { escape_slot_nn.as_mut() })
1387    }
1388
1389    pub(super) fn get_try_catch(&self) -> &raw::TryCatch {
1390      self
1391        .try_catch
1392        .as_ref()
1393        .map(|try_catch_nn| unsafe { try_catch_nn.as_ref() })
1394        .unwrap()
1395    }
1396
1397    pub(super) fn get_try_catch_mut(&mut self) -> &mut raw::TryCatch {
1398      self
1399        .try_catch
1400        .as_mut()
1401        .map(|try_catch_nn| unsafe { try_catch_nn.as_mut() })
1402        .unwrap()
1403    }
1404
1405    /// Returns a new `Box<ScopeData>` with the `isolate` field set as specified
1406    /// by the first parameter, and the other fields initialized to their
1407    /// default values. This function exists solely because it turns out that
1408    /// Rust doesn't optimize `Box::new(Self{ .. })` very well (a.k.a. not at
1409    /// all) in this case, which is why `std::alloc::alloc()` is used directly.
1410    fn boxed(isolate: NonNull<Isolate>) -> Box<Self> {
1411      unsafe {
1412        #[allow(clippy::cast_ptr_alignment)]
1413        let self_ptr = alloc(Layout::new::<Self>()) as *mut Self;
1414        ptr::write(
1415          self_ptr,
1416          Self {
1417            isolate,
1418            previous: Default::default(),
1419            next: Default::default(),
1420            status: Default::default(),
1421            context: Default::default(),
1422            escape_slot: Default::default(),
1423            try_catch: Default::default(),
1424            scope_type_specific_data: Default::default(),
1425          },
1426        );
1427        Box::from_raw(self_ptr)
1428      }
1429    }
1430  }
1431
1432  #[derive(Debug, Clone, Copy, Eq, PartialEq)]
1433  enum ScopeStatus {
1434    Free,
1435    Current { zombie: bool },
1436    Shadowed { zombie: bool },
1437  }
1438
1439  impl Default for ScopeStatus {
1440    fn default() -> Self {
1441      Self::Free
1442    }
1443  }
1444
1445  #[derive(Debug)]
1446  enum ScopeTypeSpecificData {
1447    None,
1448    ContextScope {
1449      raw_context_scope: raw::ContextScope,
1450    },
1451    HandleScope {
1452      raw_handle_scope: raw::HandleScope,
1453      raw_context_scope: Option<raw::ContextScope>,
1454    },
1455    EscapableHandleScope {
1456      raw_handle_scope: raw::HandleScope,
1457      raw_escape_slot: Option<raw::EscapeSlot>,
1458    },
1459    TryCatch {
1460      raw_try_catch: raw::TryCatch,
1461    },
1462  }
1463
1464  impl Default for ScopeTypeSpecificData {
1465    fn default() -> Self {
1466      Self::None
1467    }
1468  }
1469
1470  impl Drop for ScopeTypeSpecificData {
1471    fn drop(&mut self) {
1472      // For `HandleScope`s that also enter a `Context`, drop order matters. The
1473      // context is stored in a `Local` handle, which is allocated in this
1474      // scope's own private `raw::HandleScope`. When that `raw::HandleScope`
1475      // is dropped first, we immediately lose the `Local<Context>` handle,
1476      // which we need in order to exit `ContextScope`.
1477      if let Self::HandleScope {
1478        raw_context_scope, ..
1479      } = self
1480      {
1481        *raw_context_scope = None
1482      }
1483    }
1484  }
1485
1486  impl ScopeTypeSpecificData {
1487    pub fn is_none(&self) -> bool {
1488      matches!(self, Self::None)
1489    }
1490
1491    /// Replaces a `ScopeTypeSpecificData::None` value with the value returned
1492    /// from the specified closure. This function exists because initializing
1493    /// scopes is performance critical, and `ptr::write()` produces more
1494    /// efficient code than using a regular assign statement, which will try to
1495    /// drop the old value and move the new value into place, even after
1496    /// asserting `self.is_none()`.
1497    pub fn init_with(&mut self, init_fn: impl FnOnce() -> Self) {
1498      assert!(self.is_none());
1499      unsafe { ptr::write(self, (init_fn)()) }
1500    }
1501  }
1502}
1503
1504/// The `raw` module contains prototypes for all the `extern C` functions that
1505/// are used in this file, as well as definitions for the types they operate on.
1506mod raw {
1507  use super::*;
1508
1509  #[derive(Clone, Copy, Debug)]
1510  #[repr(transparent)]
1511  pub(super) struct Address(NonZeroUsize);
1512
1513  #[derive(Debug)]
1514  pub(super) struct ContextScope {
1515    entered_context: NonNull<Context>,
1516  }
1517
1518  impl ContextScope {
1519    pub fn new(context: Local<Context>) -> Self {
1520      unsafe { v8__Context__Enter(&*context) };
1521      Self {
1522        entered_context: context.as_non_null(),
1523      }
1524    }
1525  }
1526
1527  impl Drop for ContextScope {
1528    fn drop(&mut self) {
1529      unsafe { v8__Context__Exit(self.entered_context.as_ptr()) };
1530    }
1531  }
1532
1533  #[repr(C)]
1534  #[derive(Debug)]
1535  pub(super) struct HandleScope([usize; 3]);
1536
1537  impl HandleScope {
1538    /// This function is marked unsafe because the caller must ensure that the
1539    /// returned value isn't dropped before `init()` has been called.
1540    pub unsafe fn uninit() -> Self {
1541      // This is safe because there is no combination of bits that would produce
1542      // an invalid `[usize; 3]`.
1543      #[allow(clippy::uninit_assumed_init)]
1544      Self(MaybeUninit::uninit().assume_init())
1545    }
1546
1547    /// This function is marked unsafe because `init()` must be called exactly
1548    /// once, no more and no less, after creating a `HandleScope` value with
1549    /// `HandleScope::uninit()`.
1550    pub unsafe fn init(&mut self, isolate: NonNull<Isolate>) {
1551      let buf = NonNull::from(self).cast();
1552      v8__HandleScope__CONSTRUCT(buf.as_ptr(), isolate.as_ptr());
1553    }
1554  }
1555
1556  impl Drop for HandleScope {
1557    fn drop(&mut self) {
1558      unsafe { v8__HandleScope__DESTRUCT(self) };
1559    }
1560  }
1561
1562  #[repr(transparent)]
1563  #[derive(Debug)]
1564  pub(super) struct EscapeSlot(NonNull<raw::Address>);
1565
1566  impl EscapeSlot {
1567    pub fn new(isolate: NonNull<Isolate>) -> Self {
1568      unsafe {
1569        let undefined = raw::v8__Undefined(isolate.as_ptr()) as *const _;
1570        let local = raw::v8__Local__New(isolate.as_ptr(), undefined);
1571        let slot_address_ptr = local as *const Address as *mut _;
1572        let slot_address_nn = NonNull::new_unchecked(slot_address_ptr);
1573        Self(slot_address_nn)
1574      }
1575    }
1576
1577    pub fn escape<'e, T>(self, value: Local<'_, T>) -> Local<'e, T>
1578    where
1579      for<'l> Local<'l, T>: Into<Local<'l, Data>>,
1580    {
1581      assert_eq!(Layout::new::<Self>(), Layout::new::<Local<T>>());
1582      unsafe {
1583        let undefined = Local::<Value>::from_non_null(self.0.cast());
1584        debug_assert!(undefined.is_undefined());
1585        let value_address = *(&*value as *const T as *const Address);
1586        ptr::write(self.0.as_ptr(), value_address);
1587        Local::from_non_null(self.0.cast())
1588      }
1589    }
1590  }
1591
1592  #[repr(C)]
1593  #[derive(Debug)]
1594  pub(super) struct TryCatch([usize; 6]);
1595
1596  impl TryCatch {
1597    /// This function is marked unsafe because the caller must ensure that the
1598    /// returned value isn't dropped before `init()` has been called.
1599    pub unsafe fn uninit() -> Self {
1600      // This is safe because there is no combination of bits that would produce
1601      // an invalid `[usize; 6]`.
1602      #[allow(clippy::uninit_assumed_init)]
1603      Self(MaybeUninit::uninit().assume_init())
1604    }
1605
1606    /// This function is marked unsafe because `init()` must be called exactly
1607    /// once, no more and no less, after creating a `TryCatch` value with
1608    /// `TryCatch::uninit()`.
1609    pub unsafe fn init(&mut self, isolate: NonNull<Isolate>) {
1610      let buf = NonNull::from(self).cast();
1611      v8__TryCatch__CONSTRUCT(buf.as_ptr(), isolate.as_ptr());
1612    }
1613  }
1614
1615  impl Drop for TryCatch {
1616    fn drop(&mut self) {
1617      unsafe { v8__TryCatch__DESTRUCT(self) };
1618    }
1619  }
1620
1621  extern "C" {
1622    pub(super) fn v8__Isolate__GetCurrentContext(
1623      isolate: *mut Isolate,
1624    ) -> *const Context;
1625    pub(super) fn v8__Isolate__GetEnteredOrMicrotaskContext(
1626      isolate: *mut Isolate,
1627    ) -> *const Context;
1628    pub(super) fn v8__Isolate__ThrowException(
1629      isolate: *mut Isolate,
1630      exception: *const Value,
1631    ) -> *const Value;
1632    pub(super) fn v8__Isolate__GetDataFromSnapshotOnce(
1633      this: *mut Isolate,
1634      index: usize,
1635    ) -> *const Data;
1636
1637    pub(super) fn v8__Context__EQ(
1638      this: *const Context,
1639      other: *const Context,
1640    ) -> bool;
1641    pub(super) fn v8__Context__Enter(this: *const Context);
1642    pub(super) fn v8__Context__Exit(this: *const Context);
1643    pub(super) fn v8__Context__GetIsolate(this: *const Context)
1644      -> *mut Isolate;
1645    pub(super) fn v8__Context__GetDataFromSnapshotOnce(
1646      this: *const Context,
1647      index: usize,
1648    ) -> *const Data;
1649
1650    pub(super) fn v8__HandleScope__CONSTRUCT(
1651      buf: *mut MaybeUninit<HandleScope>,
1652      isolate: *mut Isolate,
1653    );
1654    pub(super) fn v8__HandleScope__DESTRUCT(this: *mut HandleScope);
1655
1656    pub(super) fn v8__Local__New(
1657      isolate: *mut Isolate,
1658      other: *const Data,
1659    ) -> *const Data;
1660    pub(super) fn v8__Undefined(isolate: *mut Isolate) -> *const Primitive;
1661
1662    pub(super) fn v8__TryCatch__CONSTRUCT(
1663      buf: *mut MaybeUninit<TryCatch>,
1664      isolate: *mut Isolate,
1665    );
1666    pub(super) fn v8__TryCatch__DESTRUCT(this: *mut TryCatch);
1667    pub(super) fn v8__TryCatch__HasCaught(this: *const TryCatch) -> bool;
1668    pub(super) fn v8__TryCatch__CanContinue(this: *const TryCatch) -> bool;
1669    pub(super) fn v8__TryCatch__HasTerminated(this: *const TryCatch) -> bool;
1670    pub(super) fn v8__TryCatch__IsVerbose(this: *const TryCatch) -> bool;
1671    pub(super) fn v8__TryCatch__SetVerbose(this: *mut TryCatch, value: bool);
1672    pub(super) fn v8__TryCatch__SetCaptureMessage(
1673      this: *mut TryCatch,
1674      value: bool,
1675    );
1676    pub(super) fn v8__TryCatch__Reset(this: *mut TryCatch);
1677    pub(super) fn v8__TryCatch__Exception(
1678      this: *const TryCatch,
1679    ) -> *const Value;
1680    pub(super) fn v8__TryCatch__StackTrace(
1681      this: *const TryCatch,
1682      context: *const Context,
1683    ) -> *const Value;
1684    pub(super) fn v8__TryCatch__Message(
1685      this: *const TryCatch,
1686    ) -> *const Message;
1687    pub(super) fn v8__TryCatch__ReThrow(this: *mut TryCatch) -> *const Value;
1688
1689    pub(super) fn v8__Message__GetIsolate(this: *const Message)
1690      -> *mut Isolate;
1691    pub(super) fn v8__Object__GetIsolate(this: *const Object) -> *mut Isolate;
1692    pub(super) fn v8__FunctionCallbackInfo__GetIsolate(
1693      this: *const FunctionCallbackInfo,
1694    ) -> *mut Isolate;
1695    pub(super) fn v8__PropertyCallbackInfo__GetIsolate(
1696      this: *const PropertyCallbackInfo,
1697    ) -> *mut Isolate;
1698  }
1699}
1700
1701#[cfg(test)]
1702mod tests {
1703  use super::*;
1704  use crate::new_default_platform;
1705  use crate::Global;
1706  use crate::V8;
1707  use std::any::type_name;
1708  use std::sync::Once;
1709
1710  trait SameType {}
1711  impl<A> SameType for (A, A) {}
1712
1713  /// `AssertTypeOf` facilitates comparing types. The important difference with
1714  /// assigning a value to a variable with an explicitly stated type is that the
1715  /// latter allows coercions and dereferencing to change the type, whereas
1716  /// `AssertTypeOf` requires the compared types to match exactly.
1717  struct AssertTypeOf<'a, T>(pub &'a T);
1718  impl<'a, T> AssertTypeOf<'a, T> {
1719    pub fn is<A>(self)
1720    where
1721      (A, T): SameType,
1722    {
1723      assert_eq!(type_name::<A>(), type_name::<T>());
1724    }
1725  }
1726
1727  fn initialize_v8() {
1728    static INIT: Once = Once::new();
1729    INIT.call_once(|| {
1730      V8::initialize_platform(new_default_platform(0, false).make_shared());
1731      V8::initialize();
1732    });
1733  }
1734
1735  #[test]
1736  fn deref_types() {
1737    initialize_v8();
1738    let isolate = &mut Isolate::new(Default::default());
1739    AssertTypeOf(isolate).is::<OwnedIsolate>();
1740    let l1_hs = &mut HandleScope::new(isolate);
1741    AssertTypeOf(l1_hs).is::<HandleScope<()>>();
1742    let context = Context::new(l1_hs);
1743    {
1744      let l2_cxs = &mut ContextScope::new(l1_hs, context);
1745      AssertTypeOf(l2_cxs).is::<ContextScope<HandleScope>>();
1746      {
1747        let d = l2_cxs.deref_mut();
1748        AssertTypeOf(d).is::<HandleScope>();
1749        let d = d.deref_mut();
1750        AssertTypeOf(d).is::<HandleScope<()>>();
1751        let d = d.deref_mut();
1752        AssertTypeOf(d).is::<Isolate>();
1753      }
1754      {
1755        let l3_tc = &mut TryCatch::new(l2_cxs);
1756        AssertTypeOf(l3_tc).is::<TryCatch<HandleScope>>();
1757        let d = l3_tc.deref_mut();
1758        AssertTypeOf(d).is::<HandleScope>();
1759        let d = d.deref_mut();
1760        AssertTypeOf(d).is::<HandleScope<()>>();
1761        let d = d.deref_mut();
1762        AssertTypeOf(d).is::<Isolate>();
1763      }
1764      {
1765        let l3_ehs = &mut EscapableHandleScope::new(l2_cxs);
1766        AssertTypeOf(l3_ehs).is::<EscapableHandleScope>();
1767        {
1768          let l4_cxs = &mut ContextScope::new(l3_ehs, context);
1769          AssertTypeOf(l4_cxs).is::<ContextScope<EscapableHandleScope>>();
1770          let d = l4_cxs.deref_mut();
1771          AssertTypeOf(d).is::<EscapableHandleScope>();
1772          let d = d.deref_mut();
1773          AssertTypeOf(d).is::<HandleScope>();
1774          let d = d.deref_mut();
1775          AssertTypeOf(d).is::<HandleScope<()>>();
1776          let d = d.deref_mut();
1777          AssertTypeOf(d).is::<Isolate>();
1778        }
1779        {
1780          let l4_tc = &mut TryCatch::new(l3_ehs);
1781          AssertTypeOf(l4_tc).is::<TryCatch<EscapableHandleScope>>();
1782          let d = l4_tc.deref_mut();
1783          AssertTypeOf(d).is::<EscapableHandleScope>();
1784          let d = d.deref_mut();
1785          AssertTypeOf(d).is::<HandleScope>();
1786          let d = d.deref_mut();
1787          AssertTypeOf(d).is::<HandleScope<()>>();
1788          let d = d.deref_mut();
1789          AssertTypeOf(d).is::<Isolate>();
1790        }
1791      }
1792    }
1793    {
1794      let l2_tc = &mut TryCatch::new(l1_hs);
1795      AssertTypeOf(l2_tc).is::<TryCatch<HandleScope<()>>>();
1796      let d = l2_tc.deref_mut();
1797      AssertTypeOf(d).is::<HandleScope<()>>();
1798      let d = d.deref_mut();
1799      AssertTypeOf(d).is::<Isolate>();
1800    }
1801    {
1802      let l2_ehs = &mut EscapableHandleScope::new(l1_hs);
1803      AssertTypeOf(l2_ehs).is::<EscapableHandleScope<()>>();
1804      let l3_tc = &mut TryCatch::new(l2_ehs);
1805      AssertTypeOf(l3_tc).is::<TryCatch<EscapableHandleScope<()>>>();
1806      let d = l3_tc.deref_mut();
1807      AssertTypeOf(d).is::<EscapableHandleScope<()>>();
1808      let d = d.deref_mut();
1809      AssertTypeOf(d).is::<HandleScope<()>>();
1810      let d = d.deref_mut();
1811      AssertTypeOf(d).is::<Isolate>();
1812    }
1813    {
1814      // `CallbackScope` is meant to be used inside V8 API callback functions
1815      // only. It assumes that a `HandleScope` already exists on the stack, and
1816      // that a context has been entered. Push a `ContextScope` onto the stack
1817      // to also meet the second expectation.
1818      let _ = ContextScope::new(l1_hs, context);
1819      let l2_cbs = &mut unsafe { CallbackScope::new(context) };
1820      AssertTypeOf(l2_cbs).is::<CallbackScope>();
1821      let d = l2_cbs.deref_mut();
1822      AssertTypeOf(d).is::<HandleScope>();
1823      let d = d.deref_mut();
1824      AssertTypeOf(d).is::<HandleScope<()>>();
1825      let d = d.deref_mut();
1826      AssertTypeOf(d).is::<Isolate>();
1827    }
1828    {
1829      let isolate: &mut Isolate = l1_hs.as_mut();
1830      let l2_cbs = &mut unsafe { CallbackScope::new(isolate) };
1831      AssertTypeOf(l2_cbs).is::<CallbackScope<()>>();
1832      let d = l2_cbs.deref_mut();
1833      AssertTypeOf(d).is::<HandleScope<()>>();
1834      let d = d.deref_mut();
1835      AssertTypeOf(d).is::<Isolate>();
1836    }
1837  }
1838
1839  #[test]
1840  fn new_scope_types() {
1841    initialize_v8();
1842    let isolate = &mut Isolate::new(Default::default());
1843    AssertTypeOf(isolate).is::<OwnedIsolate>();
1844    let global_context: Global<Context>;
1845    {
1846      let l1_hs = &mut HandleScope::new(isolate);
1847      AssertTypeOf(l1_hs).is::<HandleScope<()>>();
1848      let context = Context::new(l1_hs);
1849      global_context = Global::new(l1_hs, context);
1850      AssertTypeOf(&HandleScope::new(l1_hs)).is::<HandleScope<()>>();
1851      {
1852        let l2_cxs = &mut ContextScope::new(l1_hs, context);
1853        AssertTypeOf(l2_cxs).is::<ContextScope<HandleScope>>();
1854        AssertTypeOf(&ContextScope::new(l2_cxs, context))
1855          .is::<ContextScope<HandleScope>>();
1856        AssertTypeOf(&HandleScope::new(l2_cxs)).is::<HandleScope>();
1857        AssertTypeOf(&EscapableHandleScope::new(l2_cxs))
1858          .is::<EscapableHandleScope>();
1859        AssertTypeOf(&TryCatch::new(l2_cxs)).is::<TryCatch<HandleScope>>();
1860      }
1861      {
1862        let l2_ehs = &mut EscapableHandleScope::new(l1_hs);
1863        AssertTypeOf(l2_ehs).is::<EscapableHandleScope<()>>();
1864        AssertTypeOf(&HandleScope::new(l2_ehs))
1865          .is::<EscapableHandleScope<()>>();
1866        AssertTypeOf(&EscapableHandleScope::new(l2_ehs))
1867          .is::<EscapableHandleScope<()>>();
1868        {
1869          let l3_cxs = &mut ContextScope::new(l2_ehs, context);
1870          AssertTypeOf(l3_cxs).is::<ContextScope<EscapableHandleScope>>();
1871          AssertTypeOf(&ContextScope::new(l3_cxs, context))
1872            .is::<ContextScope<EscapableHandleScope>>();
1873          AssertTypeOf(&HandleScope::new(l3_cxs)).is::<EscapableHandleScope>();
1874          AssertTypeOf(&EscapableHandleScope::new(l3_cxs))
1875            .is::<EscapableHandleScope>();
1876          {
1877            let l4_tc = &mut TryCatch::new(l3_cxs);
1878            AssertTypeOf(l4_tc).is::<TryCatch<EscapableHandleScope>>();
1879            AssertTypeOf(&ContextScope::new(l4_tc, context))
1880              .is::<ContextScope<EscapableHandleScope>>();
1881            AssertTypeOf(&HandleScope::new(l4_tc)).is::<EscapableHandleScope>();
1882            AssertTypeOf(&EscapableHandleScope::new(l4_tc))
1883              .is::<EscapableHandleScope>();
1884            AssertTypeOf(&TryCatch::new(l4_tc))
1885              .is::<TryCatch<EscapableHandleScope>>();
1886          }
1887        }
1888        {
1889          let l3_tc = &mut TryCatch::new(l2_ehs);
1890          AssertTypeOf(l3_tc).is::<TryCatch<EscapableHandleScope<()>>>();
1891          AssertTypeOf(&ContextScope::new(l3_tc, context))
1892            .is::<ContextScope<EscapableHandleScope>>();
1893          AssertTypeOf(&HandleScope::new(l3_tc))
1894            .is::<EscapableHandleScope<()>>();
1895          AssertTypeOf(&EscapableHandleScope::new(l3_tc))
1896            .is::<EscapableHandleScope<()>>();
1897          AssertTypeOf(&TryCatch::new(l3_tc))
1898            .is::<TryCatch<EscapableHandleScope<()>>>();
1899        }
1900      }
1901      {
1902        let l2_tc = &mut TryCatch::new(l1_hs);
1903        AssertTypeOf(l2_tc).is::<TryCatch<HandleScope<()>>>();
1904        AssertTypeOf(&ContextScope::new(l2_tc, context))
1905          .is::<ContextScope<HandleScope>>();
1906        AssertTypeOf(&HandleScope::new(l2_tc)).is::<HandleScope<()>>();
1907        AssertTypeOf(&EscapableHandleScope::new(l2_tc))
1908          .is::<EscapableHandleScope<()>>();
1909        AssertTypeOf(&TryCatch::new(l2_tc)).is::<TryCatch<HandleScope<()>>>();
1910      }
1911      {
1912        let l2_cbs = &mut unsafe { CallbackScope::new(context) };
1913        AssertTypeOf(l2_cbs).is::<CallbackScope>();
1914        AssertTypeOf(&ContextScope::new(l2_cbs, context))
1915          .is::<ContextScope<HandleScope>>();
1916        {
1917          let l3_hs = &mut HandleScope::new(l2_cbs);
1918          AssertTypeOf(l3_hs).is::<HandleScope>();
1919          AssertTypeOf(&ContextScope::new(l3_hs, context))
1920            .is::<ContextScope<HandleScope>>();
1921          AssertTypeOf(&HandleScope::new(l3_hs)).is::<HandleScope>();
1922          AssertTypeOf(&EscapableHandleScope::new(l3_hs))
1923            .is::<EscapableHandleScope>();
1924          AssertTypeOf(&TryCatch::new(l3_hs)).is::<TryCatch<HandleScope>>();
1925        }
1926        {
1927          let l3_ehs = &mut EscapableHandleScope::new(l2_cbs);
1928          AssertTypeOf(l3_ehs).is::<EscapableHandleScope>();
1929          AssertTypeOf(&ContextScope::new(l3_ehs, context))
1930            .is::<ContextScope<EscapableHandleScope>>();
1931          AssertTypeOf(&HandleScope::new(l3_ehs)).is::<EscapableHandleScope>();
1932          AssertTypeOf(&EscapableHandleScope::new(l3_ehs))
1933            .is::<EscapableHandleScope>();
1934          AssertTypeOf(&TryCatch::new(l3_ehs))
1935            .is::<TryCatch<EscapableHandleScope>>();
1936        }
1937        {
1938          let l3_tc = &mut TryCatch::new(l2_cbs);
1939          AssertTypeOf(l3_tc).is::<TryCatch<HandleScope>>();
1940          AssertTypeOf(&ContextScope::new(l3_tc, context))
1941            .is::<ContextScope<HandleScope>>();
1942          AssertTypeOf(&HandleScope::new(l3_tc)).is::<HandleScope>();
1943          AssertTypeOf(&EscapableHandleScope::new(l3_tc))
1944            .is::<EscapableHandleScope>();
1945          AssertTypeOf(&TryCatch::new(l3_tc)).is::<TryCatch<HandleScope>>();
1946        }
1947      }
1948    }
1949    {
1950      let l1_cbs = &mut unsafe { CallbackScope::new(&mut *isolate) };
1951      AssertTypeOf(l1_cbs).is::<CallbackScope<()>>();
1952      let context = Context::new(l1_cbs);
1953      AssertTypeOf(&ContextScope::new(l1_cbs, context))
1954        .is::<ContextScope<HandleScope>>();
1955      AssertTypeOf(&HandleScope::new(l1_cbs)).is::<HandleScope<()>>();
1956      AssertTypeOf(&EscapableHandleScope::new(l1_cbs))
1957        .is::<EscapableHandleScope<()>>();
1958      AssertTypeOf(&TryCatch::new(l1_cbs)).is::<TryCatch<HandleScope<()>>>();
1959    }
1960    {
1961      AssertTypeOf(&HandleScope::with_context(isolate, &global_context))
1962        .is::<HandleScope>();
1963      AssertTypeOf(&HandleScope::with_context(isolate, global_context))
1964        .is::<HandleScope>();
1965    }
1966  }
1967}