2020-01-17 23:55:09 -05:00
|
|
|
// Copyright 2019-2020 the Deno authors. All rights reserved. MIT license.
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
use std::marker::PhantomData;
|
|
|
|
use std::mem::size_of;
|
|
|
|
use std::mem::take;
|
|
|
|
use std::mem::MaybeUninit;
|
2020-01-19 21:16:37 -05:00
|
|
|
use std::ptr::NonNull;
|
2019-12-24 18:31:36 -05:00
|
|
|
|
2020-01-17 23:55:09 -05:00
|
|
|
use crate::scope_traits::internal::GetRawIsolate;
|
|
|
|
use crate::Context;
|
|
|
|
use crate::FunctionCallbackInfo;
|
2020-01-19 21:16:37 -05:00
|
|
|
use crate::InIsolate;
|
2020-01-17 23:55:09 -05:00
|
|
|
use crate::Isolate;
|
|
|
|
use crate::Local;
|
|
|
|
use crate::PromiseRejectMessage;
|
|
|
|
use crate::PropertyCallbackInfo;
|
|
|
|
|
2019-12-24 18:31:36 -05:00
|
|
|
// Note: the 's lifetime is there to ensure that after entering a scope once,
|
|
|
|
// the same scope object can't ever be entered again.
|
|
|
|
|
|
|
|
/// A trait for defining scoped objects.
|
2020-01-17 23:55:09 -05:00
|
|
|
pub unsafe trait ScopeDefinition<'s>
|
2019-12-24 18:31:36 -05:00
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
{
|
|
|
|
type Args;
|
2020-01-17 23:55:09 -05:00
|
|
|
unsafe fn enter_scope(buf: *mut Self, args: Self::Args) -> ();
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A RAII scope wrapper object that will, when the `enter()` method is called,
|
|
|
|
/// initialize and activate the guarded object.
|
2020-01-19 21:16:37 -05:00
|
|
|
pub struct Scope<'s, S, P = ()>
|
2019-12-24 18:31:36 -05:00
|
|
|
where
|
2020-01-17 23:55:09 -05:00
|
|
|
S: ScopeDefinition<'s>,
|
|
|
|
{
|
2020-01-19 21:16:37 -05:00
|
|
|
state: ScopeState<'s, S, P>,
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
2019-12-24 18:31:36 -05:00
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
enum ScopeState<'s, S, P>
|
2019-12-24 18:31:36 -05:00
|
|
|
where
|
2020-01-17 23:55:09 -05:00
|
|
|
S: ScopeDefinition<'s>,
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
Empty,
|
2020-01-19 21:16:37 -05:00
|
|
|
Allocated {
|
|
|
|
args: S::Args,
|
|
|
|
parent: &'s mut P,
|
|
|
|
},
|
|
|
|
EnteredUninit {
|
2020-01-17 23:55:09 -05:00
|
|
|
data: MaybeUninit<S>,
|
2020-01-19 21:16:37 -05:00
|
|
|
enter: MaybeUninit<Entered<'s, S, P>>,
|
2020-01-17 23:55:09 -05:00
|
|
|
},
|
2020-01-19 21:16:37 -05:00
|
|
|
EnteredReady {
|
2020-01-17 23:55:09 -05:00
|
|
|
data: S,
|
2020-01-19 21:16:37 -05:00
|
|
|
enter: Entered<'s, S, P>,
|
2020-01-17 23:55:09 -05:00
|
|
|
},
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
fn parent_of_root() -> &'static mut () {
|
|
|
|
unsafe { &mut *NonNull::<()>::dangling().as_ptr() }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s, S> Scope<'s, S, ()>
|
|
|
|
where
|
|
|
|
S: ScopeDefinition<'s>,
|
|
|
|
{
|
|
|
|
/// Create a new root Scope object in unentered state.
|
|
|
|
pub(crate) fn new_root(args: S::Args) -> Self {
|
|
|
|
Self::new(args, parent_of_root())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s, S, P> Scope<'s, S, P>
|
2019-12-24 18:31:36 -05:00
|
|
|
where
|
2020-01-17 23:55:09 -05:00
|
|
|
S: ScopeDefinition<'s>,
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
/// Create a new Scope object in unentered state.
|
2020-01-19 21:16:37 -05:00
|
|
|
pub(crate) fn new(args: S::Args, parent: &'s mut P) -> Self {
|
2020-01-17 23:55:09 -05:00
|
|
|
Self {
|
2020-01-19 21:16:37 -05:00
|
|
|
state: ScopeState::Allocated { args, parent },
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Initializes the guarded object and returns a mutable reference to it.
|
|
|
|
/// A scope can only be entered once.
|
2020-01-19 21:16:37 -05:00
|
|
|
pub fn enter(&'s mut self) -> &'s mut Entered<'s, S, P> {
|
2019-12-24 18:31:36 -05:00
|
|
|
assert_eq!(size_of::<S>(), size_of::<MaybeUninit<S>>());
|
|
|
|
|
|
|
|
use ScopeState::*;
|
2020-01-17 23:55:09 -05:00
|
|
|
let Self { state } = self;
|
2019-12-24 18:31:36 -05:00
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
let (parent, args) = match take(state) {
|
|
|
|
Allocated { parent, args } => (parent, args),
|
2019-12-24 18:31:36 -05:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
*state = EnteredUninit {
|
2020-01-17 23:55:09 -05:00
|
|
|
data: MaybeUninit::uninit(),
|
|
|
|
enter: MaybeUninit::uninit(),
|
|
|
|
};
|
|
|
|
let data_ptr = match state {
|
2020-01-19 21:16:37 -05:00
|
|
|
EnteredUninit { data, .. } => data as *mut _ as *mut S,
|
2019-12-24 18:31:36 -05:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
2020-01-17 23:55:09 -05:00
|
|
|
unsafe { S::enter_scope(data_ptr, args) };
|
2019-12-24 18:31:36 -05:00
|
|
|
|
|
|
|
*state = match take(state) {
|
2020-01-19 21:16:37 -05:00
|
|
|
EnteredUninit { data, .. } => EnteredReady {
|
2020-01-17 23:55:09 -05:00
|
|
|
data: unsafe { data.assume_init() },
|
2020-01-19 21:16:37 -05:00
|
|
|
enter: Entered::new(unsafe { &mut *data_ptr }, parent),
|
2020-01-17 23:55:09 -05:00
|
|
|
},
|
2019-12-24 18:31:36 -05:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
match state {
|
2020-01-19 21:16:37 -05:00
|
|
|
EnteredReady { enter, .. } => enter,
|
2019-12-24 18:31:36 -05:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
impl<'s, S, P> Default for ScopeState<'s, S, P>
|
2019-12-24 18:31:36 -05:00
|
|
|
where
|
2020-01-17 23:55:09 -05:00
|
|
|
S: ScopeDefinition<'s>,
|
2019-12-24 18:31:36 -05:00
|
|
|
{
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Empty
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-17 23:55:09 -05:00
|
|
|
/// A wrapper around the an instantiated and entered scope object.
|
2020-01-19 21:16:37 -05:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct Entered<'s, S, P = ()> {
|
|
|
|
data: *mut S,
|
|
|
|
parent: &'s mut P,
|
|
|
|
}
|
2020-01-17 23:55:09 -05:00
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
impl<'s, S> Entered<'s, S, ()> {
|
|
|
|
pub(crate) fn new_root(data: *mut S) -> Self {
|
|
|
|
Self {
|
|
|
|
data,
|
|
|
|
parent: parent_of_root(),
|
|
|
|
}
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
impl<'s, S, P> Entered<'s, S, P> {
|
|
|
|
pub(crate) fn new(data: *mut S, parent: &'s mut P) -> Self {
|
|
|
|
Self { data, parent }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn data(&self) -> &S {
|
|
|
|
unsafe { &*self.data }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn data_mut(&mut self) -> &mut S {
|
|
|
|
unsafe { &mut *self.data }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn parent(&self) -> &P {
|
|
|
|
&self.parent
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
pub(crate) fn parent_mut(&mut self) -> &mut P {
|
|
|
|
&mut self.parent
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A CallbackScope can be used to obtain a mutable Isolate reference within
|
|
|
|
/// a callback that is called by V8 on the thread that already has a Locker
|
|
|
|
/// on the stack.
|
|
|
|
///
|
|
|
|
/// Using a CallbackScope in any other situation is unsafe.
|
|
|
|
/// Also note that CallbackScope should not be used for function and property
|
|
|
|
/// accessor callbacks; use FunctionCallbackScope and PropertyCallbackScope
|
|
|
|
/// instead.
|
|
|
|
///
|
|
|
|
/// A CallbackScope can be created from the following inputs:
|
|
|
|
/// - `&mut Isolate`
|
|
|
|
/// ` - `Local<Context>`
|
|
|
|
/// - `Local<Message>`
|
|
|
|
/// - `Local<Object>`
|
|
|
|
/// - `Local<Promise>`
|
|
|
|
/// - `Local<SharedArrayBuffer>`
|
|
|
|
/// - `&PromiseRejectMessage`
|
|
|
|
pub struct CallbackScope<X = Contained> {
|
|
|
|
isolate: *mut Isolate,
|
|
|
|
phantom: PhantomData<X>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Contained;
|
|
|
|
pub struct Escapable;
|
|
|
|
|
|
|
|
impl<'s> CallbackScope {
|
|
|
|
pub fn new<I>(input: I) -> Scope<'s, Self>
|
|
|
|
where
|
|
|
|
Scope<'s, Self>: From<I>,
|
|
|
|
{
|
|
|
|
Scope::from(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s> CallbackScope<Escapable> {
|
|
|
|
pub fn new_escapable<I>(input: I) -> Scope<'s, Self>
|
|
|
|
where
|
|
|
|
Scope<'s, Self>: From<I>,
|
|
|
|
{
|
|
|
|
Scope::from(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<X> CallbackScope<X> {
|
|
|
|
pub(crate) fn get_raw_isolate_(&self) -> *mut Isolate {
|
|
|
|
self.isolate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<'s, X> ScopeDefinition<'s> for CallbackScope<X> {
|
|
|
|
type Args = *mut Isolate;
|
|
|
|
unsafe fn enter_scope(ptr: *mut Self, isolate: Self::Args) {
|
|
|
|
let data = Self {
|
|
|
|
isolate,
|
|
|
|
phantom: PhantomData,
|
|
|
|
};
|
|
|
|
std::ptr::write(ptr, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s, X> From<&'s mut Isolate> for Scope<'s, CallbackScope<X>> {
|
|
|
|
fn from(isolate: &'s mut Isolate) -> Self {
|
2020-01-19 21:16:37 -05:00
|
|
|
Scope::new_root(isolate as *mut Isolate)
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s, X, T> From<Local<'s, T>> for Scope<'s, CallbackScope<X>>
|
|
|
|
where
|
|
|
|
Local<'s, T>: GetRawIsolate,
|
|
|
|
{
|
|
|
|
fn from(local: Local<'s, T>) -> Self {
|
2020-01-19 21:16:37 -05:00
|
|
|
Scope::new_root(local.get_raw_isolate())
|
2019-12-24 18:31:36 -05:00
|
|
|
}
|
|
|
|
}
|
2020-01-17 23:55:09 -05:00
|
|
|
|
|
|
|
impl<'s, X> From<&'s PromiseRejectMessage<'s>> for Scope<'s, CallbackScope<X>> {
|
|
|
|
fn from(msg: &'s PromiseRejectMessage<'s>) -> Self {
|
|
|
|
Self::from(msg.get_promise())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-20 20:03:45 -05:00
|
|
|
#[repr(C)]
|
|
|
|
/// v8::Locker is a scoped lock object. While it's active, i.e. between its
|
|
|
|
/// construction and destruction, the current thread is allowed to use the locked
|
|
|
|
/// isolate. V8 guarantees that an isolate can be locked by at most one thread at
|
|
|
|
/// any time. In other words, the scope of a v8::Locker is a critical section.
|
|
|
|
pub struct Locker {
|
|
|
|
has_lock: bool,
|
|
|
|
top_level: bool,
|
|
|
|
isolate: *mut Isolate,
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
fn v8__Locker__CONSTRUCT(buf: *mut Locker, isolate: *mut Isolate);
|
|
|
|
fn v8__Locker__DESTRUCT(this: &mut Locker);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s> Locker {
|
|
|
|
// TODO(piscisaureus): We should not be sharing &Isolate references between
|
|
|
|
// threads while at the same time dereferencing to &mut Isolate *within* the
|
|
|
|
// various scopes. Instead, add a separate type (e.g. IsolateHandle).
|
|
|
|
pub fn new(isolate: &Isolate) -> Scope<'s, Self> {
|
|
|
|
Scope::new_root(isolate as *const _ as *mut Isolate)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_raw_isolate_(&self) -> *mut Isolate {
|
|
|
|
self.isolate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<'s> ScopeDefinition<'s> for Locker {
|
|
|
|
type Args = *mut Isolate;
|
|
|
|
|
|
|
|
unsafe fn enter_scope(buf: *mut Self, isolate: *mut Isolate) {
|
|
|
|
v8__Locker__CONSTRUCT(buf, isolate)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Locker {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { v8__Locker__DESTRUCT(self) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-17 23:55:09 -05:00
|
|
|
/// Stack-allocated class which sets the execution context for all operations
|
|
|
|
/// executed within a local scope.
|
2020-01-19 21:16:37 -05:00
|
|
|
pub struct ContextScope {
|
|
|
|
context: *mut Context,
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
impl<'s> ContextScope {
|
|
|
|
pub fn new<P>(
|
|
|
|
parent: &'s mut P,
|
2020-01-17 23:55:09 -05:00
|
|
|
context: Local<'s, Context>,
|
2020-01-19 21:16:37 -05:00
|
|
|
) -> Scope<'s, Self, P>
|
|
|
|
where
|
|
|
|
P: InIsolate,
|
|
|
|
{
|
|
|
|
Scope::new(context, parent)
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
pub(crate) unsafe fn get_captured_context(&self) -> Local<'s, Context> {
|
|
|
|
Local::from_raw(self.context).unwrap()
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
unsafe impl<'s> ScopeDefinition<'s> for ContextScope {
|
2020-01-17 23:55:09 -05:00
|
|
|
type Args = Local<'s, Context>;
|
|
|
|
|
|
|
|
unsafe fn enter_scope(ptr: *mut Self, mut context: Self::Args) {
|
|
|
|
context.enter();
|
2020-01-19 21:16:37 -05:00
|
|
|
std::ptr::write(
|
|
|
|
ptr,
|
|
|
|
Self {
|
|
|
|
context: &mut *context,
|
|
|
|
},
|
|
|
|
);
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 21:16:37 -05:00
|
|
|
impl Drop for ContextScope {
|
2020-01-17 23:55:09 -05:00
|
|
|
fn drop(&mut self) {
|
2020-01-19 21:16:37 -05:00
|
|
|
unsafe { self.get_captured_context() }.exit()
|
2020-01-17 23:55:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type FunctionCallbackScope<'s> = &'s mut Entered<'s, FunctionCallbackInfo>;
|
|
|
|
pub type PropertyCallbackScope<'s> = &'s mut Entered<'s, PropertyCallbackInfo>;
|