1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// Copyright 2019-2020 the Deno authors. All rights reserved. MIT license.

use crate::isolate::Isolate;
use crate::scope::Scope;
use crate::scope::ScopeDefinition;
use crate::scope_traits::ToLocalOrReturnsLocal;
use crate::Data;
use crate::InIsolate;
use crate::Local;

extern "C" {
  fn v8__HandleScope__CONSTRUCT(buf: *mut HandleScope, isolate: *mut Isolate);
  fn v8__HandleScope__DESTRUCT(this: *mut HandleScope);
  fn v8__EscapableHandleScope__CONSTRUCT(
    buf: *mut EscapableHandleScope,
    isolate: *mut Isolate,
  );
  fn v8__EscapableHandleScope__DESTRUCT(this: *mut EscapableHandleScope);
  fn v8__EscapableHandleScope__Escape(
    this: *mut EscapableHandleScope,
    value: *const Data,
  ) -> *const Data;
}

/// A stack-allocated class that governs a number of local handles.
/// After a handle scope has been created, all local handles will be
/// allocated within that handle scope until either the handle scope is
/// deleted or another handle scope is created.  If there is already a
/// handle scope and a new one is created, all allocations will take
/// place in the new handle scope until it is deleted.  After that,
/// new handles will again be allocated in the original handle scope.
///
/// After the handle scope of a local handle has been deleted the
/// garbage collector will no longer track the object stored in the
/// handle and may deallocate it.  The behavior of accessing a handle
/// for which the handle scope has been deleted is undefined.
#[repr(C)]
pub struct HandleScope([usize; 3]);

impl<'s> HandleScope {
  pub fn new<P>(parent: &'s mut P) -> Scope<'s, Self, P>
  where
    P: InIsolate,
  {
    let isolate: *mut Isolate = parent.isolate();
    Scope::new(isolate, parent)
  }
}

unsafe impl<'s> ScopeDefinition<'s> for HandleScope {
  type Args = *mut Isolate;
  unsafe fn enter_scope(buf: *mut Self, isolate: *mut Isolate) {
    v8__HandleScope__CONSTRUCT(buf, isolate);
  }
}

impl Drop for HandleScope {
  fn drop(&mut self) {
    unsafe { v8__HandleScope__DESTRUCT(self) }
  }
}

/// A HandleScope which first allocates a handle in the current scope
/// which will be later filled with the escape value.
#[repr(C)]
pub struct EscapableHandleScope([usize; 4]);

impl<'s> EscapableHandleScope {
  pub fn new<'p: 's, P>(parent: &'s mut P) -> Scope<'s, Self, P>
  where
    P: ToLocalOrReturnsLocal<'p>,
  {
    let isolate: *mut Isolate = parent.isolate();
    Scope::new(isolate, parent)
  }

  /// Pushes the value into the previous scope and returns a handle to it.
  /// Cannot be called twice.
  pub(crate) unsafe fn escape<'p, T>(
    &mut self,
    value: Local<T>,
  ) -> Local<'p, T> {
    Local::from_raw(v8__EscapableHandleScope__Escape(
      self,
      value.as_ptr() as *const Data,
    ) as *const T)
    .unwrap()
  }
}

unsafe impl<'s> ScopeDefinition<'s> for EscapableHandleScope {
  type Args = *mut Isolate;
  unsafe fn enter_scope(buf: *mut Self, isolate: *mut Isolate) {
    v8__EscapableHandleScope__CONSTRUCT(buf, isolate);
  }
}

impl Drop for EscapableHandleScope {
  fn drop(&mut self) {
    unsafe { v8__EscapableHandleScope__DESTRUCT(self) }
  }
}