0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-12-24 08:09:16 -05:00

Get rid of HandleScope closure, add CallbackScope (#119)

This commit is contained in:
Bert Belder 2019-12-25 00:31:36 +01:00 committed by GitHub
parent 57d13f7622
commit ae4b48eb22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 806 additions and 376 deletions

View file

@ -1,9 +1,9 @@
use crate::support::Delete;
use crate::support::Opaque;
use crate::support::UniqueRef;
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::ToLocal;
extern "C" {
fn v8__ArrayBuffer__Allocator__NewDefaultAllocator() -> *mut Allocator;
@ -117,13 +117,12 @@ impl ArrayBuffer {
/// will be deallocated when it is garbage-collected,
/// unless the object is externalized.
pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
byte_length: usize,
) -> Local<'sc, ArrayBuffer> {
unsafe {
let ptr = v8__ArrayBuffer__New(scope.as_mut(), byte_length);
Local::from_raw(ptr).unwrap()
}
let isolate = scope.isolate();
let ptr = unsafe { v8__ArrayBuffer__New(isolate, byte_length) };
unsafe { scope.to_local(ptr) }.unwrap()
}
/// Data length in bytes.
@ -139,12 +138,12 @@ impl ArrayBuffer {
/// given isolate and re-try the allocation. If GCs do not help, then the
/// function will crash with an out-of-memory error.
pub fn new_backing_store<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
byte_length: usize,
) -> UniqueRef<BackingStore> {
unsafe {
UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore(
scope.as_mut(),
scope.isolate(),
byte_length,
))
}

View file

@ -28,7 +28,7 @@ pub struct ArrayBufferView(Opaque);
impl ArrayBufferView {
/// Returns underlying ArrayBuffer.
pub fn buffer<'sc>(&self) -> Option<Local<'sc, ArrayBuffer>> {
unsafe { Local::from_raw(v8__ArrayBufferView__Buffer(self)) }
unsafe { Local::from_raw_(v8__ArrayBufferView__Buffer(self)) }
}
/// Size of a view in bytes.

52
src/callback_scope.rs Normal file
View file

@ -0,0 +1,52 @@
use crate::scope::{Scope, Scoped};
use crate::Context;
use crate::InIsolate;
use crate::Isolate;
use crate::Local;
use crate::Message;
use std::mem::MaybeUninit;
pub trait GetIsolate
where
Self: Sized,
{
fn get_isolate(&mut self) -> &mut Isolate;
}
impl GetIsolate for Message {
fn get_isolate(&mut self) -> &mut Isolate {
self.get_isolate()
}
}
impl GetIsolate for Context {
fn get_isolate(&mut self) -> &mut Isolate {
self.get_isolate()
}
}
pub struct CallbackScope<'s, T> {
local: Local<'s, T>,
}
unsafe impl<'s, T> Scoped<'s> for CallbackScope<'s, T> {
type Args = Local<'s, T>;
fn enter_scope(buf: &mut MaybeUninit<Self>, local: Local<'s, T>) {
*buf = MaybeUninit::new(CallbackScope { local });
}
}
impl<'s, T> CallbackScope<'s, T> {
pub fn new(local: Local<'s, T>) -> Scope<Self> {
Scope::new(local)
}
}
impl<'s, T> InIsolate for crate::scope::Entered<'s, CallbackScope<'s, T>>
where
T: GetIsolate,
{
fn isolate(&mut self) -> &mut Isolate {
self.local.get_isolate()
}
}

View file

@ -1,9 +1,9 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::isolate::Isolate;
use crate::support::Opaque;
use crate::HandleScope;
use crate::Local;
use crate::Object;
use crate::ToLocal;
extern "C" {
fn v8__Context__New(isolate: &Isolate) -> *mut Context;
@ -19,9 +19,10 @@ extern "C" {
pub struct Context(Opaque);
impl Context {
pub fn new<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Context> {
pub fn new<'sc>(scope: &mut impl ToLocal<'sc>) -> Local<'sc, Context> {
// TODO: optional arguments;
unsafe { Local::from_raw(v8__Context__New(scope.as_mut())).unwrap() }
let ptr = unsafe { v8__Context__New(scope.isolate()) };
unsafe { scope.to_local(ptr) }.unwrap()
}
/// Returns the global proxy object.
@ -34,8 +35,11 @@ impl Context {
/// Please note that changes to global proxy object prototype most probably
/// would break VM---v8 expects only global object as a prototype of global
/// proxy object.
pub fn global<'sc>(&mut self) -> Local<'sc, Object> {
unsafe { Local::from_raw(v8__Context__Global(&mut *self)).unwrap() }
pub fn global<'sc>(
&mut self,
scope: &mut impl ToLocal<'sc>,
) -> Local<'sc, Object> {
unsafe { scope.to_local(v8__Context__Global(&mut *self)) }.unwrap()
}
/// Enter this context. After entering a context, all code compiled
@ -53,6 +57,10 @@ impl Context {
// TODO: enter/exit should be controlled by a scope.
unsafe { v8__Context__Exit(self) };
}
pub fn get_isolate(&mut self) -> &mut Isolate {
unsafe { v8__Context__GetIsolate(self) }
}
}
impl AsRef<Isolate> for Context {

View file

@ -3,9 +3,9 @@
use crate::isolate::Isolate;
use crate::support::int;
use crate::support::Opaque;
use crate::HandleScope;
use crate::Local;
use crate::String;
use crate::ToLocal;
use crate::Value;
extern "C" {
@ -46,13 +46,12 @@ impl StackTrace {
pub struct Message(Opaque);
impl Message {
pub fn get<'sc>(&self, _scope: &mut HandleScope<'sc>) -> Local<'sc, String> {
unsafe { Local::from_raw(v8__Message__Get(self)) }.unwrap()
pub fn get<'sc>(&self, scope: &mut impl ToLocal<'sc>) -> Local<'sc, String> {
unsafe { scope.to_local(v8__Message__Get(self)) }.unwrap()
}
#[allow(clippy::mut_from_ref)]
pub unsafe fn get_isolate(&self) -> &mut Isolate {
v8__Message__GetIsolate(self)
pub fn get_isolate(&mut self) -> &mut Isolate {
unsafe { v8__Message__GetIsolate(self) }
}
}
@ -60,59 +59,55 @@ impl Message {
/// Will try to reconstruct the original stack trace from the exception value,
/// or capture the current stack trace if not available.
pub fn create_message<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut exception: Local<'sc, Value>,
) -> Local<'sc, Message> {
unsafe {
Local::from_raw(v8__Exception__CreateMessage(
scope.as_mut(),
&mut *exception,
))
}
.unwrap()
let isolate = scope.isolate();
let ptr = unsafe { v8__Exception__CreateMessage(isolate, &mut *exception) };
unsafe { scope.to_local(ptr) }.unwrap()
}
/// Returns the original stack trace that was captured at the creation time
/// of a given exception, or an empty handle if not available.
pub fn get_stack_trace<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut exception: Local<Value>,
) -> Option<Local<'sc, StackTrace>> {
unsafe { Local::from_raw(v8__Exception__GetStackTrace(&mut *exception)) }
unsafe { scope.to_local(v8__Exception__GetStackTrace(&mut *exception)) }
}
pub fn range_error<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut message: Local<String>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Exception__RangeError(&mut *message)) }.unwrap()
unsafe { scope.to_local(v8__Exception__RangeError(&mut *message)) }.unwrap()
}
pub fn reference_error<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut message: Local<String>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Exception__ReferenceError(&mut *message)) }
unsafe { scope.to_local(v8__Exception__ReferenceError(&mut *message)) }
.unwrap()
}
pub fn syntax_error<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut message: Local<String>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Exception__SyntaxError(&mut *message)) }.unwrap()
unsafe { scope.to_local(v8__Exception__SyntaxError(&mut *message)) }.unwrap()
}
pub fn type_error<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut message: Local<String>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Exception__TypeError(&mut *message)) }.unwrap()
unsafe { scope.to_local(v8__Exception__TypeError(&mut *message)) }.unwrap()
}
pub fn error<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut message: Local<String>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Exception__Error(&mut *message)) }.unwrap()
unsafe { scope.to_local(v8__Exception__Error(&mut *message)) }.unwrap()
}

View file

@ -3,9 +3,10 @@ use std::mem::MaybeUninit;
use crate::support::{int, Opaque};
use crate::Context;
use crate::HandleScope;
use crate::InIsolate;
use crate::Isolate;
use crate::Local;
use crate::ToLocal;
use crate::Value;
extern "C" {
@ -62,8 +63,8 @@ impl<'cb> ReturnValue<'cb> {
}
/// Convenience getter for Isolate
pub fn get_isolate(&self) -> &Isolate {
unsafe { v8__ReturnValue__GetIsolate(self).as_ref().unwrap() }
pub fn get_isolate(&mut self) -> &mut Isolate {
unsafe { &mut *v8__ReturnValue__GetIsolate(self) }
}
/// Getter. Creates a new Local<> so it comes with a certain performance
@ -71,9 +72,9 @@ impl<'cb> ReturnValue<'cb> {
/// value.
pub fn get<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__ReturnValue__Get(self)).unwrap() }
unsafe { scope.to_local(v8__ReturnValue__Get(self)) }.unwrap()
}
}
@ -84,6 +85,15 @@ impl<'cb> ReturnValue<'cb> {
#[repr(C)]
pub struct FunctionCallbackInfo(Opaque);
impl InIsolate for FunctionCallbackInfo {
#[allow(clippy::cast_ref_to_mut)]
fn isolate(&mut self) -> &mut Isolate {
self.get_isolate()
}
}
impl<'s> ToLocal<'s> for FunctionCallbackInfo {}
impl FunctionCallbackInfo {
/// The ReturnValue for the call.
pub fn get_return_value(&self) -> ReturnValue {
@ -96,8 +106,8 @@ impl FunctionCallbackInfo {
/// The current Isolate.
#[allow(clippy::mut_from_ref)]
pub unsafe fn get_isolate(&self) -> &mut Isolate {
v8__FunctionCallbackInfo__GetIsolate(self)
pub fn get_isolate(&mut self) -> &mut Isolate {
unsafe { v8__FunctionCallbackInfo__GetIsolate(self) }
}
/// The number of available arguments.
@ -132,26 +142,22 @@ pub struct FunctionTemplate(Opaque);
impl FunctionTemplate {
/// Creates a function template.
pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
callback: extern "C" fn(&FunctionCallbackInfo),
) -> Local<'sc, FunctionTemplate> {
unsafe {
Local::from_raw(v8__FunctionTemplate__New(scope.as_mut(), callback))
.unwrap()
}
let ptr = unsafe { v8__FunctionTemplate__New(scope.isolate(), callback) };
unsafe { scope.to_local(ptr) }.unwrap()
}
/// Returns the unique function instance in the current execution context.
pub fn get_function<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
) -> Option<Local<'sc, Function>> {
unsafe {
Local::from_raw(v8__FunctionTemplate__GetFunction(
&mut *self,
&mut *context,
))
scope
.to_local(v8__FunctionTemplate__GetFunction(&mut *self, &mut *context))
}
}
}
@ -165,16 +171,16 @@ impl Function {
/// Create a function in the current execution context
/// for a given FunctionCallback.
pub fn new<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
callback: extern "C" fn(&FunctionCallbackInfo),
) -> Option<Local<'sc, Function>> {
unsafe { Local::from_raw(v8__Function__New(&mut *context, callback)) }
unsafe { scope.to_local(v8__Function__New(&mut *context, callback)) }
}
pub fn call<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
mut recv: Local<Value>,
arc: i32,
@ -185,7 +191,7 @@ impl Function {
argv_.push(&mut *arg);
}
unsafe {
Local::from_raw(v8__Function__Call(
scope.to_local(v8__Function__Call(
&mut *self,
&mut *context,
&mut *recv,

View file

@ -1,9 +1,10 @@
use std::mem::transmute;
use std::ptr::NonNull;
use crate::HandleScope;
use crate::InIsolate;
use crate::Isolate;
use crate::Local;
use crate::ToLocal;
use crate::Value;
extern "C" {
@ -51,10 +52,10 @@ impl<T> Global<T> {
/// is non-empty, a new storage cell is created pointing to the same object,
/// and no flags are set.
pub fn new_from(
isolate: &mut impl AsMut<Isolate>,
scope: &mut impl InIsolate,
other: impl AnyHandle<T>,
) -> Self {
let isolate = isolate.as_mut();
let isolate = scope.isolate();
let other_value = other.read(isolate);
Self {
value: other_value
@ -72,23 +73,19 @@ impl<T> Global<T> {
/// Construct a Local<T> from this global handle.
pub fn get<'sc>(
&self,
scope: &'_ mut (impl AsMut<Isolate> + AsMut<HandleScope<'sc>>),
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, T>> {
self.check_isolate(scope.as_mut());
self.check_isolate(scope.isolate());
match &self.value {
None => None,
Some(p) => unsafe { Local::from_raw(p.as_ptr()) },
Some(p) => unsafe { scope.to_local(p.as_ptr()) },
}
}
/// If non-empty, destroy the underlying storage cell
/// and create a new one with the contents of other if other is non empty.
pub fn set(
&mut self,
isolate: &mut impl AsMut<Isolate>,
other: impl AnyHandle<T>,
) {
let isolate = isolate.as_mut();
pub fn set(&mut self, scope: &mut impl InIsolate, other: impl AnyHandle<T>) {
let isolate = scope.isolate();
self.check_isolate(isolate);
let other_value = other.read(isolate);
match (&mut self.value, &other_value) {
@ -111,8 +108,8 @@ impl<T> Global<T> {
/// If non-empty, destroy the underlying storage cell
/// IsEmpty() will return true after this call.
pub fn reset(&mut self, isolate: &mut impl AsMut<Isolate>) {
self.set(isolate, None);
pub fn reset(&mut self, scope: &mut impl InIsolate) {
self.set(scope, None);
}
fn check_isolate(&self, other: &Isolate) {

View file

@ -1,7 +1,9 @@
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use crate::isolate::Isolate;
use crate::scope::Scope;
use crate::scope::Scoped;
use crate::InIsolate;
use crate::Local;
use crate::Value;
@ -30,101 +32,132 @@ extern "C" {
}
#[repr(C)]
pub struct HandleScope<'sc>([usize; 3], PhantomData<&'sc mut ()>);
pub struct HandleScope([usize; 3]);
impl<'sc> HandleScope<'sc> {
pub fn enter(
isolate: &mut impl AsMut<Isolate>,
mut f: impl FnMut(&mut HandleScope<'_>) -> (),
) {
let isolate = isolate.as_mut();
let mut scope: MaybeUninit<Self> = MaybeUninit::uninit();
unsafe { v8__HandleScope__CONSTRUCT(&mut scope, isolate) };
let scope = unsafe { &mut *(scope.as_mut_ptr()) };
f(scope);
unsafe { v8__HandleScope__DESTRUCT(scope) };
impl HandleScope {
pub fn new(scope: &mut impl InIsolate) -> Scope<Self> {
Scope::new(scope.isolate())
}
}
impl<'sc> AsRef<HandleScope<'sc>> for HandleScope<'sc> {
unsafe impl<'s> Scoped<'s> for HandleScope {
type Args = &'s mut Isolate;
fn enter_scope(buf: &mut MaybeUninit<Self>, isolate: &mut Isolate) {
unsafe { v8__HandleScope__CONSTRUCT(buf, isolate) };
}
}
impl Drop for HandleScope {
fn drop(&mut self) {
unsafe { v8__HandleScope__DESTRUCT(self) }
}
}
impl AsRef<HandleScope> for HandleScope {
fn as_ref(&self) -> &Self {
self
}
}
impl<'sc> AsMut<HandleScope<'sc>> for HandleScope<'sc> {
impl AsMut<HandleScope> for HandleScope {
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'sc> AsRef<Isolate> for HandleScope<'sc> {
impl AsRef<Isolate> for HandleScope {
fn as_ref(&self) -> &Isolate {
unsafe { v8__HandleScope__GetIsolate(self) }
}
}
impl<'sc> AsMut<Isolate> for HandleScope<'sc> {
impl AsMut<Isolate> for HandleScope {
fn as_mut(&mut self) -> &mut Isolate {
unsafe { v8__HandleScope__GetIsolate(self) }
}
}
#[repr(C)]
/// A HandleScope which first allocates a handle in the current scope
/// which will be later filled with the escape value.
pub struct EscapableHandleScope<'sc>([usize; 4], PhantomData<&'sc mut ()>);
#[repr(C)]
pub struct EscapableHandleScope([usize; 4]);
impl<'sc> EscapableHandleScope<'sc> {
pub fn new(isolate: &mut impl AsMut<Isolate>) -> Self {
let isolate = isolate.as_mut();
let mut scope: MaybeUninit<Self> = MaybeUninit::uninit();
unsafe {
v8__EscapableHandleScope__CONSTRUCT(&mut scope, isolate);
scope.assume_init()
}
impl EscapableHandleScope {
pub fn new(scope: &mut impl InIsolate) -> Scope<Self> {
Scope::new(scope.isolate())
}
/// Pushes the value into the previous scope and returns a handle to it.
/// Cannot be called twice.
pub fn escape<'parent>(
&mut self,
mut value: Local<'sc, Value>,
) -> Local<'parent, Value> {
pub fn escape<'parent, T>(&mut self, value: Local<T>) -> Local<'parent, T> {
unsafe {
Local::from_raw(v8__EscapableHandleScope__Escape(self, &mut *value))
Local::from_raw_(v8__EscapableHandleScope__Escape(
self,
value.as_ptr() as *mut Value,
) as *mut T)
}
.unwrap()
}
}
unsafe impl<'s> Scoped<'s> for EscapableHandleScope {
type Args = &'s mut Isolate;
fn enter_scope(buf: &mut MaybeUninit<Self>, isolate: &mut Isolate) {
unsafe { v8__EscapableHandleScope__CONSTRUCT(buf, isolate) };
}
}
impl<'sc> Drop for EscapableHandleScope<'sc> {
impl Drop for EscapableHandleScope {
fn drop(&mut self) {
unsafe { v8__EscapableHandleScope__DESTRUCT(self) }
}
}
impl<'sc> AsRef<EscapableHandleScope<'sc>> for EscapableHandleScope<'sc> {
impl AsRef<EscapableHandleScope> for EscapableHandleScope {
fn as_ref(&self) -> &Self {
self
}
}
impl<'sc> AsMut<EscapableHandleScope<'sc>> for EscapableHandleScope<'sc> {
impl AsMut<EscapableHandleScope> for EscapableHandleScope {
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'sc> AsRef<Isolate> for EscapableHandleScope<'sc> {
impl AsRef<Isolate> for EscapableHandleScope {
fn as_ref(&self) -> &Isolate {
unsafe { v8__EscapableHandleScope__GetIsolate(self) }
}
}
impl<'sc> AsMut<Isolate> for EscapableHandleScope<'sc> {
impl AsMut<Isolate> for EscapableHandleScope {
fn as_mut(&mut self) -> &mut Isolate {
unsafe { v8__EscapableHandleScope__GetIsolate(self) }
}
}
use crate::scope::Entered;
impl<'s> InIsolate for Entered<'s, HandleScope> {
fn isolate(&mut self) -> &mut Isolate {
unsafe { v8__HandleScope__GetIsolate(self) }
}
}
impl<'s> InIsolate for Entered<'s, EscapableHandleScope> {
fn isolate(&mut self) -> &mut Isolate {
unsafe { v8__EscapableHandleScope__GetIsolate(self) }
}
}
pub trait ToLocal<'sc>: InIsolate {
unsafe fn to_local<T>(&mut self, ptr: *mut T) -> Option<Local<'sc, T>> {
crate::Local::<'sc, T>::from_raw_(ptr)
}
}
impl<'s> ToLocal<'s> for crate::scope::Entered<'s, HandleScope> {}
impl<'s> ToLocal<'s> for crate::scope::Entered<'s, EscapableHandleScope> {}

View file

@ -162,7 +162,7 @@ impl Isolate {
) -> Local<'sc, Value> {
unsafe {
let ptr = v8__Isolate__ThrowException(self, &exception);
Local::from_raw(ptr).unwrap()
Local::from_raw_(ptr).unwrap()
}
}
@ -207,6 +207,13 @@ impl DerefMut for OwnedIsolate {
}
}
/// Trait for retrieving the current isolate from a scope object.
pub trait InIsolate {
// Do not implement this trait on unscoped Isolate references
// (e.g. OwnedIsolate).
fn isolate(&mut self) -> &mut Isolate;
}
#[repr(C)]
pub struct CreateParams(Opaque);

View file

@ -22,7 +22,7 @@ pub fn parse<'sc>(
mut context: Local<'sc, Context>,
mut json_string: Local<'sc, String>,
) -> Option<Local<'sc, Value>> {
unsafe { Local::from_raw(v8__JSON__Parse(&mut *context, &mut *json_string)) }
unsafe { Local::from_raw_(v8__JSON__Parse(&mut *context, &mut *json_string)) }
}
/// Tries to stringify the JSON-serializable object `json_object` and returns
@ -32,6 +32,6 @@ pub fn stringify<'sc>(
mut json_object: Local<'sc, Value>,
) -> Option<Local<'sc, String>> {
unsafe {
Local::from_raw(v8__JSON__Stringify(&mut *context, &mut *json_object))
Local::from_raw_(v8__JSON__Stringify(&mut *context, &mut *json_object))
}
}

View file

@ -10,6 +10,7 @@ extern crate lazy_static;
extern crate libc;
mod array_buffer;
mod callback_scope;
mod context;
mod exception;
mod function;
@ -37,6 +38,7 @@ pub mod array_buffer_view;
pub mod inspector;
pub mod json;
pub mod platform;
pub mod scope;
pub mod script_compiler;
// This module is intentionally named "V8" rather than "v8" to match the
// C++ namespace "v8::V8".
@ -46,15 +48,15 @@ pub mod V8;
pub use array_buffer::Allocator;
pub use array_buffer::ArrayBuffer;
pub use array_buffer::BackingStore;
pub use callback_scope::CallbackScope;
pub use context::Context;
pub use exception::*;
pub use function::{
Function, FunctionCallbackInfo, FunctionTemplate, ReturnValue,
};
pub use global::Global;
pub use handle_scope::{EscapableHandleScope, HandleScope};
pub use isolate::Isolate;
pub use isolate::OwnedIsolate;
pub use handle_scope::{EscapableHandleScope, HandleScope, ToLocal};
pub use isolate::{InIsolate, Isolate, OwnedIsolate};
pub use local::Local;
pub use locker::Locker;
pub use module::*;

View file

@ -49,13 +49,17 @@ impl<'sc, T> Clone for Local<'sc, T> {
}
impl<'sc, T> Local<'sc, T> {
pub(crate) unsafe fn from_raw(ptr: *mut T) -> Option<Self> {
pub(crate) unsafe fn from_raw_(ptr: *mut T) -> Option<Self> {
Some(Self(NonNull::new(ptr)?, PhantomData))
}
pub(crate) fn as_non_null(self) -> NonNull<T> {
self.0
}
pub(crate) fn as_ptr(self) -> *mut T {
self.0.as_ptr()
}
}
impl<'sc, T> Deref for Local<'sc, T> {

View file

@ -1,5 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::isolate::Isolate;
use crate::InIsolate;
use crate::Isolate;
use std::mem::MaybeUninit;
extern "C" {
@ -29,6 +30,12 @@ impl Locker {
}
}
impl InIsolate for Locker {
fn isolate(&mut self) -> &mut Isolate {
unsafe { &mut *self.isolate }
}
}
impl Drop for Locker {
fn drop(&mut self) {
unsafe { v8__Locker__DESTRUCT(self) }

View file

@ -4,6 +4,7 @@ use crate::support::Opaque;
use crate::Context;
use crate::Local;
use crate::String;
use crate::ToLocal;
use crate::Value;
use std::mem::MaybeUninit;
@ -86,7 +87,7 @@ impl Module {
/// For a module in kErrored status, this returns the corresponding exception.
pub fn get_exception(&self) -> Local<Value> {
unsafe { Local::from_raw(v8__Module__GetException(self)).unwrap() }
unsafe { Local::from_raw_(v8__Module__GetException(self)).unwrap() }
}
/// Returns the number of modules requested by this module.
@ -97,7 +98,7 @@ impl Module {
/// Returns the ith module specifier in this module.
/// i must be < self.get_module_requests_length() and >= 0.
pub fn get_module_request(&self, i: usize) -> Local<String> {
unsafe { Local::from_raw(v8__Module__GetModuleRequest(self, i)).unwrap() }
unsafe { Local::from_raw_(v8__Module__GetModuleRequest(self, i)).unwrap() }
}
/// Returns the source location (line number and column number) of the ith
@ -161,10 +162,11 @@ impl Module {
/// kErrored and propagate the thrown exception (which is then also available
/// via |GetException|).
#[must_use]
pub fn evaluate(
pub fn evaluate<'sc>(
&mut self,
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
) -> Option<Local<Value>> {
unsafe { Local::from_raw(v8__Module__Evaluate(&mut *self, &mut *context)) }
) -> Option<Local<'sc, Value>> {
unsafe { scope.to_local(v8__Module__Evaluate(&mut *self, &mut *context)) }
}
}

View file

@ -4,6 +4,7 @@ use crate::isolate::Isolate;
use crate::support::Opaque;
use crate::value::Value;
use crate::Local;
use crate::ToLocal;
extern "C" {
fn v8__Number__New(isolate: *mut Isolate, value: f64) -> *mut Number;
@ -22,13 +23,11 @@ pub struct Number(Opaque);
impl Number {
pub fn new<'sc>(
scope: &mut impl AsMut<Isolate>,
scope: &mut impl ToLocal<'sc>,
value: f64,
) -> Local<'sc, Number> {
unsafe {
let local = v8__Number__New(scope.as_mut(), value);
Local::from_raw(local).unwrap()
}
let local = unsafe { v8__Number__New(scope.isolate(), value) };
unsafe { scope.to_local(local) }.unwrap()
}
pub fn value(&self) -> f64 {
@ -49,23 +48,19 @@ pub struct Integer(Opaque);
impl Integer {
pub fn new<'sc>(
scope: &mut impl AsMut<Isolate>,
scope: &mut impl ToLocal<'sc>,
value: i32,
) -> Local<'sc, Integer> {
unsafe {
let local = v8__Integer__New(scope.as_mut(), value);
Local::from_raw(local).unwrap()
}
let local = unsafe { v8__Integer__New(scope.isolate(), value) };
unsafe { scope.to_local(local) }.unwrap()
}
pub fn new_from_unsigned<'sc>(
scope: &mut impl AsMut<Isolate>,
scope: &mut impl ToLocal<'sc>,
value: u32,
) -> Local<'sc, Integer> {
unsafe {
let local = v8__Integer__NewFromUnsigned(scope.as_mut(), value);
Local::from_raw(local).unwrap()
}
let local = unsafe { v8__Integer__NewFromUnsigned(scope.isolate(), value) };
unsafe { scope.to_local(local) }.unwrap()
}
pub fn value(&self) -> i64 {

View file

@ -4,9 +4,9 @@ use crate::isolate::Isolate;
use crate::support::MaybeBool;
use crate::support::Opaque;
use crate::Context;
use crate::HandleScope;
use crate::Local;
use crate::Name;
use crate::ToLocal;
use crate::Value;
/// A JavaScript object (ECMA-262, 4.3.3)
@ -45,7 +45,7 @@ impl Object {
/// All properties will be created as enumerable, configurable
/// and writable properties.
pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut prototype_or_null: Local<'sc, Value>,
names: Vec<Local<'sc, Name>>,
values: Vec<Local<'sc, Value>>,
@ -62,16 +62,16 @@ impl Object {
let n = &mut *value;
values_.push(n);
}
unsafe {
Local::from_raw(v8__Object__New(
scope.as_mut(),
let ptr = unsafe {
v8__Object__New(
scope.isolate(),
&mut *prototype_or_null,
names_.as_mut_ptr(),
values_.as_mut_ptr(),
length,
))
.unwrap()
}
)
};
unsafe { scope.to_local(ptr) }.unwrap()
}
/// Implements CreateDataProperty (ECMA-262, 7.3.4).
@ -92,21 +92,18 @@ impl Object {
pub fn get<'a>(
&self,
scope: &mut impl ToLocal<'a>,
context: Local<Context>,
key: Local<Value>,
) -> Option<Local<'a, Value>> {
unsafe {
let ptr = v8__Object__Get(self, &*context, &*key);
if ptr.is_null() {
None
} else {
Some(Local::from_raw(ptr).unwrap())
}
scope.to_local(ptr)
}
}
/// Return the isolate to which the Object belongs to.
pub fn get_isolate(&self) -> &Isolate {
pub fn get_isolate(&mut self) -> &Isolate {
unsafe { v8__Object__GetIsolate(self) }
}
}

View file

@ -1,10 +1,10 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::support::int;
use crate::support::Opaque;
use crate::HandleScope;
use crate::Isolate;
use crate::Local;
use crate::Primitive;
use crate::ToLocal;
extern "C" {
fn v8__PrimitiveArray__New(
@ -38,13 +38,12 @@ pub struct PrimitiveArray(Opaque);
impl PrimitiveArray {
pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
length: usize,
) -> Local<'sc, PrimitiveArray> {
unsafe {
let ptr = v8__PrimitiveArray__New(scope.as_mut(), length as int);
Local::from_raw(ptr).unwrap()
}
let ptr =
unsafe { v8__PrimitiveArray__New(scope.isolate(), length as int) };
unsafe { scope.to_local(ptr) }.unwrap()
}
pub fn length(&self) -> usize {
@ -53,23 +52,22 @@ impl PrimitiveArray {
pub fn set<'sc>(
&self,
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
index: usize,
item: Local<'_, Primitive>,
) {
unsafe {
v8__PrimitiveArray__Set(self, scope.as_mut(), index as int, &item)
v8__PrimitiveArray__Set(self, scope.isolate(), index as int, &item)
}
}
pub fn get<'sc>(
&self,
scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
index: usize,
) -> Local<'sc, Primitive> {
unsafe {
let ptr = v8__PrimitiveArray__Get(self, scope.as_mut(), index as int);
Local::from_raw(ptr).unwrap()
}
let ptr =
unsafe { v8__PrimitiveArray__Get(self, scope.isolate(), index as int) };
unsafe { scope.to_local(ptr) }.unwrap()
}
}

View file

@ -3,6 +3,7 @@ use std::ops::Deref;
use crate::isolate::Isolate;
use crate::support::Opaque;
use crate::Local;
use crate::ToLocal;
use crate::Value;
/// The superclass of primitive values. See ECMA-262 4.3.2.
@ -28,22 +29,26 @@ extern "C" {
fn v8__False(isolate: *mut Isolate) -> *mut Boolean;
}
pub fn new_null<'sc>(scope: &mut impl AsMut<Isolate>) -> Local<'sc, Primitive> {
unsafe { Local::from_raw(v8__Null(scope.as_mut())) }.unwrap()
pub fn new_null<'sc>(scope: &mut impl ToLocal<'sc>) -> Local<'sc, Primitive> {
let ptr = unsafe { v8__Null(scope.isolate()) };
unsafe { scope.to_local(ptr) }.unwrap()
}
pub fn new_undefined<'sc>(
scope: &mut impl AsMut<Isolate>,
scope: &mut impl ToLocal<'sc>,
) -> Local<'sc, Primitive> {
unsafe { Local::from_raw(v8__Undefined(scope.as_mut())) }.unwrap()
let ptr = unsafe { v8__Undefined(scope.isolate()) };
unsafe { scope.to_local(ptr) }.unwrap()
}
pub fn new_true<'sc>(scope: &mut impl AsMut<Isolate>) -> Local<'sc, Boolean> {
unsafe { Local::from_raw(v8__True(scope.as_mut())) }.unwrap()
pub fn new_true<'sc>(scope: &mut impl ToLocal<'sc>) -> Local<'sc, Boolean> {
let ptr = unsafe { v8__True(scope.isolate()) };
unsafe { scope.to_local(ptr) }.unwrap()
}
pub fn new_false<'sc>(scope: &mut impl AsMut<Isolate>) -> Local<'sc, Boolean> {
unsafe { Local::from_raw(v8__False(scope.as_mut())) }.unwrap()
pub fn new_false<'sc>(scope: &mut impl ToLocal<'sc>) -> Local<'sc, Boolean> {
let ptr = unsafe { v8__False(scope.isolate()) };
unsafe { scope.to_local(ptr) }.unwrap()
}
impl Deref for Primitive {

View file

@ -4,8 +4,8 @@ use crate::support::MaybeBool;
use crate::support::Opaque;
use crate::Context;
use crate::Function;
use crate::HandleScope;
use crate::Local;
use crate::ToLocal;
use crate::Value;
extern "C" {
@ -82,9 +82,9 @@ impl Promise {
/// be pending.
pub fn result<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Promise__Result(&mut *self)).unwrap() }
unsafe { scope.to_local(v8__Promise__Result(&mut *self)) }.unwrap()
}
/// Register a rejection handler with a promise.
@ -96,7 +96,7 @@ impl Promise {
mut handler: Local<'sc, Function>,
) -> Option<Local<'sc, Promise>> {
unsafe {
Local::from_raw(v8__Promise__Catch(
Local::from_raw_(v8__Promise__Catch(
&mut *self,
&mut *context,
&mut *handler,
@ -113,7 +113,7 @@ impl Promise {
mut handler: Local<'sc, Function>,
) -> Option<Local<'sc, Promise>> {
unsafe {
Local::from_raw(v8__Promise__Then(
Local::from_raw_(v8__Promise__Then(
&mut *self,
&mut *context,
&mut *handler,
@ -132,7 +132,7 @@ impl Promise {
mut on_rejected: Local<'sc, Function>,
) -> Option<Local<'sc, Promise>> {
unsafe {
Local::from_raw(v8__Promise__Then2(
Local::from_raw_(v8__Promise__Then2(
&mut *self,
&mut *context,
&mut *on_fulfilled,
@ -148,20 +148,19 @@ pub struct PromiseResolver(Opaque);
impl PromiseResolver {
/// Create a new resolver, along with an associated promise in pending state.
pub fn new<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut context: Local<'sc, Context>,
) -> Option<Local<'sc, PromiseResolver>> {
unsafe { Local::from_raw(v8__Promise__Resolver__New(&mut *context)) }
unsafe { scope.to_local(v8__Promise__Resolver__New(&mut *context)) }
}
/// Extract the associated promise.
pub fn get_promise<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
) -> Local<'sc, Promise> {
unsafe {
Local::from_raw(v8__Promise__Resolver__GetPromise(&mut *self)).unwrap()
}
unsafe { scope.to_local(v8__Promise__Resolver__GetPromise(&mut *self)) }
.unwrap()
}
/// Resolve the associated promise with a given value.
@ -206,7 +205,7 @@ pub struct PromiseRejectMessage<'msg>([usize; 3], PhantomData<&'msg ()>);
impl<'msg> PromiseRejectMessage<'msg> {
pub fn get_promise(&self) -> Local<'msg, Promise> {
unsafe {
Local::from_raw(v8__PromiseRejectMessage__GetPromise(self)).unwrap()
Local::from_raw_(v8__PromiseRejectMessage__GetPromise(self)).unwrap()
}
}
@ -216,7 +215,7 @@ impl<'msg> PromiseRejectMessage<'msg> {
pub fn get_value(&self) -> Local<'msg, Value> {
unsafe {
Local::from_raw(v8__PromiseRejectMessage__GetValue(self)).unwrap()
Local::from_raw_(v8__PromiseRejectMessage__GetValue(self)).unwrap()
}
}
}

View file

@ -3,6 +3,7 @@ use crate::support::Opaque;
use crate::Local;
use crate::Object;
use crate::ReturnValue;
use std::mem::MaybeUninit;
extern "C" {
@ -30,11 +31,11 @@ impl PropertyCallbackInfo {
}
#[allow(clippy::mut_from_ref)]
pub unsafe fn get_isolate(&self) -> &mut Isolate {
v8__PropertyCallbackInfo__GetIsolate(self)
pub fn get_isolate(&mut self) -> &mut Isolate {
unsafe { v8__PropertyCallbackInfo__GetIsolate(self) }
}
pub fn this(&self) -> Local<Object> {
unsafe { Local::from_raw(v8__PropertyCallbackInfo__This(self)).unwrap() }
unsafe { Local::from_raw_(v8__PropertyCallbackInfo__This(self)).unwrap() }
}
}

149
src/scope.rs Normal file
View file

@ -0,0 +1,149 @@
use std::marker::PhantomData;
use std::mem::size_of;
use std::mem::take;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::ops::DerefMut;
// 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.
pub unsafe trait Scoped<'s>
where
Self: Sized,
{
type Args;
fn enter_scope(buf: &mut MaybeUninit<Self>, args: Self::Args) -> ();
}
/// A RAII scope wrapper object that will, when the `enter()` method is called,
/// initialize and activate the guarded object.
pub struct Scope<'s, S>(ScopeState<'s, S>)
where
S: Scoped<'s>;
enum ScopeState<'s, S>
where
S: Scoped<'s>,
{
Empty,
New(S::Args),
Uninit(MaybeUninit<S>),
Ready(Entered<'s, S>),
}
/// A wrapper around the an instantiated and entered scope object.
#[repr(transparent)]
pub struct Entered<'s, S>(S, PhantomData<&'s ()>);
impl<'s, S> Scope<'s, S>
where
S: Scoped<'s>,
{
/// Create a new Scope object in unentered state.
pub(crate) fn new(args: S::Args) -> Self {
Self(ScopeState::New(args))
}
/// Initializes the guarded object and returns a mutable reference to it.
/// A scope can only be entered once.
pub fn enter(&'s mut self) -> &'s mut Entered<S> {
assert_eq!(size_of::<S>(), size_of::<MaybeUninit<S>>());
assert_eq!(size_of::<S>(), size_of::<Entered<S>>());
use ScopeState::*;
let state = &mut self.0;
let args = match take(state) {
New(f) => f,
_ => unreachable!(),
};
*state = Uninit(MaybeUninit::uninit());
let buf = match state {
Uninit(b) => b,
_ => unreachable!(),
};
S::enter_scope(buf, args);
*state = match take(state) {
Uninit(b) => Ready(unsafe { b.assume_init() }.into()),
_ => unreachable!(),
};
match state {
Ready(v) => &mut *v,
_ => unreachable!(),
}
}
}
impl<'s, S> Default for ScopeState<'s, S>
where
S: Scoped<'s>,
{
fn default() -> Self {
Self::Empty
}
}
impl<'s, S> From<S> for Entered<'s, S> {
fn from(value: S) -> Self {
Self(value, PhantomData)
}
}
impl<'s, S> Deref for Entered<'s, S> {
type Target = S;
fn deref(&self) -> &S {
unsafe { &*(self as *const _ as *const S) }
}
}
impl<'s, S> DerefMut for Entered<'s, S> {
fn deref_mut(&mut self) -> &mut S {
unsafe { &mut *(self as *mut _ as *mut S) }
}
}
/*
impl<'s, S, T> AsRef<T> for Entered<'s, S>
where
S: AsRef<T>,
{
fn as_ref(&self) -> &T {
self.deref().as_ref()
}
}
impl<'s, S, T> AsMut<T> for Entered<'s, S>
where
S: AsMut<T>,
{
fn as_mut(&mut self) -> &mut T {
self.deref_mut().as_mut()
}
}
*/
impl<'s, S, T> AsRef<Entered<'s, T>> for Entered<'s, S>
where
S: AsRef<T>,
{
fn as_ref(&self) -> &Entered<'s, T> {
let t: &T = self.deref().as_ref();
unsafe { &*(t as *const _ as *const Entered<'s, T>) }
}
}
impl<'s, S, T> AsMut<Entered<'s, T>> for Entered<'s, S>
where
S: AsMut<T>,
{
fn as_mut(&mut self) -> &mut Entered<'s, T> {
let t: &mut T = self.deref_mut().as_mut();
unsafe { &mut *(t as *mut _ as *mut Entered<'s, T>) }
}
}

View file

@ -5,10 +5,10 @@ use std::ptr::null;
use crate::support::Opaque;
use crate::Boolean;
use crate::Context;
use crate::HandleScope;
use crate::Integer;
use crate::Local;
use crate::String;
use crate::ToLocal;
use crate::Value;
/// The origin, within a file, of a script.
@ -45,20 +45,21 @@ pub struct Script(Opaque);
impl Script {
/// A shorthand for ScriptCompiler::Compile().
pub fn compile<'sc>(
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
mut source: Local<String>,
origin: Option<&ScriptOrigin>,
) -> Option<Local<'sc, Script>> {
// TODO: use the type system to enforce that a Context has been entered.
// TODO: `context` and `source` probably shouldn't be mut.
unsafe {
Local::from_raw(v8__Script__Compile(
let ptr = unsafe {
v8__Script__Compile(
&mut *context,
&mut *source,
origin.map(|r| r as *const _).unwrap_or(null()),
))
}
)
};
unsafe { scope.to_local(ptr) }
}
/// Runs the script returning the resulting value. It will be run in the
@ -66,10 +67,10 @@ impl Script {
/// UnboundScript::BindToCurrentContext()).
pub fn run<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
) -> Option<Local<'sc, Value>> {
unsafe { Local::from_raw(v8__Script__Run(self, &mut *context)) }
unsafe { scope.to_local(v8__Script__Run(self, &mut *context)) }
}
}

View file

@ -76,10 +76,10 @@ pub enum NoCacheReason {
///
/// Corresponds to the ParseModule abstract operation in the ECMAScript
/// specification.
pub fn compile_module(
pub fn compile_module<'a>(
isolate: &Isolate,
source: Source,
) -> Option<Local<Module>> {
) -> Option<Local<'a, Module>> {
compile_module2(
isolate,
source,
@ -89,14 +89,14 @@ pub fn compile_module(
}
/// Same as compile_module with more options.
pub fn compile_module2(
pub fn compile_module2<'a>(
isolate: &Isolate,
source: Source,
options: CompileOptions,
no_cache_reason: NoCacheReason,
) -> Option<Local<Module>> {
) -> Option<Local<'a, Module>> {
unsafe {
Local::from_raw(v8__ScriptCompiler__CompileModule(
Local::from_raw_(v8__ScriptCompiler__CompileModule(
isolate,
&source,
options,

View file

@ -25,7 +25,7 @@ impl ScriptOrModule {
pub fn get_resource_name(&self) -> Local<'_, Value> {
unsafe {
let ptr = v8__ScriptOrModule__GetResourceName(self);
Local::from_raw(ptr).unwrap()
Local::from_raw_(ptr).unwrap()
}
}
@ -34,7 +34,7 @@ impl ScriptOrModule {
pub fn get_host_defined_options(&self) -> Local<'_, PrimitiveArray> {
unsafe {
let ptr = v8__ScriptOrModule__GetHostDefinedOptions(self);
Local::from_raw(ptr).unwrap()
Local::from_raw_(ptr).unwrap()
}
}
}

View file

@ -4,11 +4,13 @@ use std::mem::forget;
use std::ops::Deref;
use std::slice;
use crate::isolate::Isolate;
use crate::support::char;
use crate::support::int;
use crate::support::Opaque;
use crate::InIsolate;
use crate::Isolate;
use crate::Local;
use crate::ToLocal;
use crate::Value;
extern "C" {
@ -66,19 +68,19 @@ pub struct String(Opaque);
impl String {
pub fn new_from_utf8<'sc>(
scope: &mut impl AsMut<Isolate>,
scope: &mut impl ToLocal<'sc>,
buffer: &[u8],
new_type: NewStringType,
) -> Option<Local<'sc, String>> {
unsafe {
let ptr = v8__String__NewFromUtf8(
scope.as_mut(),
let ptr = unsafe {
v8__String__NewFromUtf8(
scope.isolate(),
buffer.as_ptr() as *const char,
new_type,
buffer.len().try_into().ok()?,
);
Local::from_raw(ptr)
}
)
};
unsafe { scope.to_local(ptr) }
}
/// Returns the number of characters (UTF-16 code units) in this string.
@ -88,13 +90,13 @@ impl String {
/// Returns the number of bytes in the UTF-8 encoded representation of this
/// string.
pub fn utf8_length(&self, isolate: &mut impl AsMut<Isolate>) -> usize {
unsafe { v8__String__Utf8Length(self, isolate.as_mut()) as usize }
pub fn utf8_length(&self, scope: &mut impl InIsolate) -> usize {
unsafe { v8__String__Utf8Length(self, scope.isolate()) as usize }
}
pub fn write_utf8(
&self,
isolate: &mut Isolate,
scope: &mut impl InIsolate,
buffer: &mut [u8],
nchars_ref: Option<&mut usize>,
options: WriteOptions,
@ -103,7 +105,7 @@ impl String {
let bytes = unsafe {
v8__String__WriteUtf8(
self,
isolate,
scope.isolate(),
buffer.as_mut_ptr() as *mut char,
buffer.len().try_into().unwrap_or(int::max_value()),
&mut nchars_ref_int,
@ -118,7 +120,7 @@ impl String {
// Convenience function not present in the original V8 API.
pub fn new<'sc>(
scope: &mut impl AsMut<Isolate>,
scope: &mut impl ToLocal<'sc>,
value: &str,
) -> Option<Local<'sc, String>> {
Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal)
@ -127,15 +129,14 @@ impl String {
// Convenience function not present in the original V8 API.
pub fn to_rust_string_lossy(
&self,
isolate: &mut impl AsMut<Isolate>,
scope: &mut impl InIsolate,
) -> std::string::String {
let isolate = isolate.as_mut();
let capacity = self.utf8_length(isolate);
let capacity = self.utf8_length(scope);
let mut string = std::string::String::with_capacity(capacity);
let data = string.as_mut_ptr();
forget(string);
let length = self.write_utf8(
isolate,
scope,
unsafe { slice::from_raw_parts_mut(data, capacity) },
None,
WriteOptions::NO_NULL_TERMINATION | WriteOptions::REPLACE_INVALID_UTF8,

View file

@ -5,10 +5,11 @@ use std::mem::take;
use std::mem::MaybeUninit;
use crate::Context;
use crate::HandleScope;
use crate::InIsolate;
use crate::Isolate;
use crate::Local;
use crate::Message;
use crate::ToLocal;
use crate::Value;
extern "C" {
@ -71,9 +72,9 @@ impl<'tc> TryCatch<'tc> {
/// stack allocated because the memory location itself is compared against
/// JavaScript try/catch blocks.
#[allow(clippy::new_ret_no_self)]
pub fn new(scope: &mut impl AsMut<Isolate>) -> TryCatchScope<'tc> {
pub fn new(scope: &mut impl InIsolate) -> TryCatchScope<'tc> {
TryCatchScope(TryCatchState::New {
isolate: scope.as_mut(),
isolate: scope.isolate(),
})
}
@ -111,17 +112,17 @@ impl<'tc> TryCatch<'tc> {
///
/// The returned handle is valid until this TryCatch block has been destroyed.
pub fn exception(&self) -> Option<Local<'tc, Value>> {
unsafe { Local::from_raw(v8__TryCatch__Exception(&self.0)) }
unsafe { Local::from_raw_(v8__TryCatch__Exception(&self.0)) }
}
/// Returns the .stack property of the thrown object. If no .stack
/// property is present an empty handle is returned.
pub fn stack_trace<'sc>(
&self,
_scope: &mut impl AsMut<HandleScope<'sc>>,
scope: &mut impl ToLocal<'sc>,
context: Local<Context>,
) -> Option<Local<'sc, Value>> {
unsafe { Local::from_raw(v8__TryCatch__StackTrace(&self.0, context)) }
unsafe { scope.to_local(v8__TryCatch__StackTrace(&self.0, context)) }
}
/// Returns the message associated with this exception. If there is
@ -130,7 +131,7 @@ impl<'tc> TryCatch<'tc> {
/// The returned handle is valid until this TryCatch block has been
/// destroyed.
pub fn message(&self) -> Option<Local<'tc, Message>> {
unsafe { Local::from_raw(v8__TryCatch__Message(&self.0)) }
unsafe { Local::from_raw_(v8__TryCatch__Message(&self.0)) }
}
/// Clears any exceptions that may have been caught by this try/catch block.
@ -151,7 +152,7 @@ impl<'tc> TryCatch<'tc> {
/// ReThrow; the caller must return immediately to where the exception
/// is caught.
pub fn rethrow<'a>(&'_ mut self) -> Option<Local<'a, Value>> {
unsafe { Local::from_raw(v8__TryCatch__ReThrow(&mut self.0)) }
unsafe { Local::from_raw_(v8__TryCatch__ReThrow(&mut self.0)) }
}
/// Returns true if verbosity is enabled.

View file

@ -0,0 +1,41 @@
extern crate rusty_v8 as v8;
pub fn main() {
let mut isolate: v8::scope::Entered<'_, v8::HandleScope> = mock();
{
let mut hs = v8::EscapableHandleScope::new(&mut isolate);
let hs = hs.enter();
let _fail = v8::EscapableHandleScope::new(&mut isolate);
let _local = v8::Integer::new(hs, 123);
}
{
let mut hs1 = v8::EscapableHandleScope::new(&mut isolate);
let hs1 = hs1.enter();
let _local1 = v8::Integer::new(hs1, 123);
let mut hs2 = v8::EscapableHandleScope::new(hs1);
let hs2 = hs2.enter();
let _fail = v8::Integer::new(hs1, 123);
let _local2 = v8::Integer::new(hs2, 123);
let _local3 = v8::Integer::new(hs2, 123);
}
let _leak1 = {
let mut hs = v8::EscapableHandleScope::new(&mut isolate);
let hs = hs.enter();
v8::Integer::new(hs, 456)
};
let _leak = {
let mut hs = v8::EscapableHandleScope::new(&mut isolate);
hs.enter()
};
}
fn mock<T>() -> T {
unimplemented!()
}
fn access<T>(_value: T) {}

View file

@ -0,0 +1,44 @@
error[E0499]: cannot borrow `isolate` as mutable more than once at a time
--> $DIR/handle_scope_lifetimes.rs:9:47
|
7 | let mut hs = v8::EscapableHandleScope::new(&mut isolate);
| ------------ first mutable borrow occurs here
8 | let hs = hs.enter();
9 | let _fail = v8::EscapableHandleScope::new(&mut isolate);
| ^^^^^^^^^^^^ second mutable borrow occurs here
10 | let _local = v8::Integer::new(hs, 123);
| -- first borrow later used here
error[E0499]: cannot borrow `*hs1` as mutable more than once at a time
--> $DIR/handle_scope_lifetimes.rs:20:34
|
18 | let mut hs2 = v8::EscapableHandleScope::new(hs1);
| --- first mutable borrow occurs here
19 | let hs2 = hs2.enter();
20 | let _fail = v8::Integer::new(hs1, 123);
| ^^^ second mutable borrow occurs here
21 | let _local2 = v8::Integer::new(hs2, 123);
| --- first borrow later used here
error[E0597]: `hs` does not live long enough
--> $DIR/handle_scope_lifetimes.rs:27:14
|
25 | let _leak1 = {
| ------ borrow later stored here
26 | let mut hs = v8::EscapableHandleScope::new(&mut isolate);
27 | let hs = hs.enter();
| ^^ borrowed value does not live long enough
28 | v8::Integer::new(hs, 456)
29 | };
| - `hs` dropped here while still borrowed
error[E0597]: `hs` does not live long enough
--> $DIR/handle_scope_lifetimes.rs:33:5
|
33 | hs.enter()
| ^^--------
| |
| borrowed value does not live long enough
| borrow later used here
34 | };
| - `hs` dropped here while still borrowed

View file

@ -2,7 +2,7 @@ extern crate rusty_v8 as v8;
pub fn main() {
let context: v8::Local<v8::Context> = mock();
let scope: &mut v8::HandleScope<'_> = mock();
let scope: &mut v8::scope::Entered<'_, v8::HandleScope> = mock();
let _leaked = {
let mut try_catch = v8::TryCatch::new(scope);

View file

@ -4,7 +4,7 @@
extern crate lazy_static;
use rusty_v8 as v8;
use rusty_v8::{new_null, FunctionCallbackInfo, HandleScope, Local};
use rusty_v8::{new_null, FunctionCallbackInfo, InIsolate, Local, ToLocal};
use std::sync::Mutex;
lazy_static! {
@ -45,9 +45,14 @@ fn handle_scope_nested() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope1| {
v8::HandleScope::enter(scope1, |_scope2| {});
});
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope1 = hs.enter();
{
let mut hs = v8::HandleScope::new(scope1);
let _scope2 = hs.enter();
}
}
drop(locker);
drop(g);
}
@ -60,18 +65,22 @@ fn handle_scope_numbers() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope1| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope1 = hs.enter();
let l1 = v8::Integer::new(scope1, -123);
let l2 = v8::Integer::new_from_unsigned(scope1, 456);
v8::HandleScope::enter(scope1, |scope2| {
{
let mut hs = v8::HandleScope::new(scope1);
let scope2 = hs.enter();
let l3 = v8::Number::new(scope2, 78.9);
assert_eq!(l1.value(), -123);
assert_eq!(l2.value(), 456);
assert_eq!(l3.value(), 78.9);
assert_eq!(v8::Number::value(&l1), -123f64);
assert_eq!(v8::Number::value(&l2), 456f64);
});
});
}
}
drop(locker);
drop(g);
}
@ -86,35 +95,39 @@ fn global_handles() {
let mut g1 = v8::Global::<v8::String>::new();
let mut g2 = v8::Global::<v8::Integer>::new();
let mut g3 = v8::Global::<v8::Integer>::new();
let mut g4 = v8::Global::<v8::Integer>::new();
let mut _g4 = v8::Global::<v8::Integer>::new();
let g5 = v8::Global::<v8::Script>::new();
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let l1 = v8::String::new(scope, "bla").unwrap();
let l2 = v8::Integer::new(scope, 123);
g1.set(scope, l1);
g2.set(scope, l2);
g3.set(scope, &g2);
g4 = v8::Global::new_from(scope, l2);
});
v8::HandleScope::enter(&mut locker, |scope| {
_g4 = v8::Global::new_from(scope, l2);
}
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
assert!(!g1.is_empty());
assert_eq!(g1.get(scope).unwrap().to_rust_string_lossy(scope), "bla");
assert!(!g2.is_empty());
assert_eq!(g2.get(scope).unwrap().value(), 123);
assert!(!g3.is_empty());
assert_eq!(g3.get(scope).unwrap().value(), 123);
assert!(!g4.is_empty());
assert_eq!(g4.get(scope).unwrap().value(), 123);
assert!(!_g4.is_empty());
assert_eq!(_g4.get(scope).unwrap().value(), 123);
assert!(g5.is_empty());
});
}
g1.reset(&mut locker);
assert!(g1.is_empty());
g2.reset(&mut locker);
assert!(g2.is_empty());
g3.reset(&mut locker);
assert!(g3.is_empty());
g4.reset(&mut locker);
assert!(g4.is_empty());
_g4.reset(&mut locker);
assert!(_g4.is_empty());
assert!(g5.is_empty());
}
@ -125,13 +138,15 @@ fn test_string() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let reference = "Hello 🦕 world!";
let local = v8::String::new(scope, reference).unwrap();
assert_eq!(15, local.length());
assert_eq!(17, local.utf8_length(scope));
assert_eq!(reference, local.to_rust_string_lossy(scope));
});
}
drop(locker);
}
@ -144,42 +159,43 @@ fn escapable_handle_scope() {
let mut isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
isolate.enter();
v8::HandleScope::enter(&mut locker, |scope1| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope1 = hs.enter();
// After dropping EscapableHandleScope, we should be able to
// read escaped values.
let number_val = {
let mut escapable_scope = v8::EscapableHandleScope::new(scope1);
let mut hs = v8::EscapableHandleScope::new(scope1);
let escapable_scope = hs.enter();
let number: Local<v8::Value> =
cast(v8::Number::new(&mut escapable_scope, 78.9));
cast(v8::Number::new(escapable_scope, 78.9));
escapable_scope.escape(number)
};
let number: Local<v8::Number> = cast(number_val);
assert_eq!(number.value(), 78.9);
let str_val = {
let mut escapable_scope = v8::EscapableHandleScope::new(scope1);
let string =
v8::String::new(&mut escapable_scope, "Hello 🦕 world!").unwrap();
escapable_scope.escape(cast(string))
let string = {
let mut hs = v8::EscapableHandleScope::new(scope1);
let escapable_scope = hs.enter();
let string = v8::String::new(escapable_scope, "Hello 🦕 world!").unwrap();
escapable_scope.escape(string)
};
let string: Local<v8::String> = cast(str_val);
assert_eq!("Hello 🦕 world!", string.to_rust_string_lossy(scope1));
let str_val = {
let mut escapable_scope = v8::EscapableHandleScope::new(scope1);
let string = {
let mut hs = v8::EscapableHandleScope::new(scope1);
let escapable_scope = hs.enter();
let nested_str_val = {
let mut nested_escapable_scope =
v8::EscapableHandleScope::new(&mut escapable_scope);
let mut hs = v8::EscapableHandleScope::new(escapable_scope);
let nested_escapable_scope = hs.enter();
let string =
v8::String::new(&mut nested_escapable_scope, "Hello 🦕 world!")
.unwrap();
nested_escapable_scope.escape(cast(string))
v8::String::new(nested_escapable_scope, "Hello 🦕 world!").unwrap();
nested_escapable_scope.escape(string)
};
escapable_scope.escape(nested_str_val)
};
let string: Local<v8::String> = cast(str_val);
assert_eq!("Hello 🦕 world!", string.to_rust_string_lossy(scope1));
});
}
drop(locker);
isolate.exit();
drop(g);
@ -192,7 +208,9 @@ fn array_buffer() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -204,26 +222,29 @@ fn array_buffer() {
assert_eq!(false, bs.is_shared());
context.exit();
});
}
drop(locker);
}
fn v8_str<'sc>(
isolate: &mut impl AsMut<v8::Isolate>,
scope: &mut impl v8::ToLocal<'sc>,
s: &str,
) -> v8::Local<'sc, v8::String> {
v8::String::new(isolate, s).unwrap()
v8::String::new(scope, s).unwrap()
}
fn eval<'sc>(
scope: &mut HandleScope<'sc>,
scope: &mut impl v8::InIsolate,
context: Local<v8::Context>,
code: &'static str,
) -> Option<Local<'sc, v8::Value>> {
let mut hs = v8::EscapableHandleScope::new(scope);
let scope = hs.enter();
let source = v8_str(scope, code);
let mut script =
v8::Script::compile(&mut *scope, context, source, None).unwrap();
script.run(scope, context)
let r = script.run(scope, context);
r.map(|v| scope.escape(v))
}
#[test]
@ -233,7 +254,9 @@ fn try_catch() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
{
@ -279,7 +302,7 @@ fn try_catch() {
assert!(tc1.has_caught());
};
context.exit();
});
}
}
#[test]
@ -289,7 +312,9 @@ fn throw_exception() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
{
@ -303,7 +328,7 @@ fn throw_exception() {
.strict_equals(v8_str(scope, "boom").into()));
};
context.exit();
});
}
}
#[test]
@ -322,16 +347,21 @@ fn add_message_listener() {
_exception: Local<v8::Value>,
) {
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
let isolate = unsafe { message.get_isolate() };
v8::HandleScope::enter(isolate, |scope| {
let mut cbs = v8::CallbackScope::new(message);
let scope = cbs.enter();
{
let mut hs = v8::HandleScope::new(scope);
let scope = hs.enter();
let message_str = message.get(scope);
assert_eq!(message_str.to_rust_string_lossy(scope), "Uncaught foo");
});
}
}
isolate.add_message_listener(check_message_0);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |s| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let s = hs.enter();
let mut context = v8::Context::new(s);
context.enter();
let source = v8::String::new(s, "throw 'foo'").unwrap();
@ -339,7 +369,7 @@ fn add_message_listener() {
assert!(script.run(s, context).is_none());
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
context.exit();
});
}
drop(locker);
drop(g);
}
@ -363,39 +393,43 @@ fn set_host_initialize_import_meta_object_callback() {
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
extern "C" fn callback(
mut context: Local<v8::Context>,
context: Local<v8::Context>,
_module: Local<v8::Module>,
meta: Local<v8::Object>,
) {
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
let key = v8::String::new(&mut *context, "foo").unwrap();
let value = v8::String::new(&mut *context, "bar").unwrap();
let mut cbs = v8::CallbackScope::new(context);
let mut hs = v8::HandleScope::new(cbs.enter());
let scope = hs.enter();
let key = v8::String::new(scope, "foo").unwrap();
let value = v8::String::new(scope, "bar").unwrap();
meta.create_data_property(context, cast(key), value.into());
}
isolate.set_host_initialize_import_meta_object_callback(callback);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |s| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let s = hs.enter();
let mut context = v8::Context::new(s);
context.enter();
let source = mock_source(s, "google.com", "import.meta;");
let mut module =
v8::script_compiler::compile_module(&isolate, source).unwrap();
let result =
module.instantiate_module(context, unexpected_module_resolve_callback);
assert!(result.is_some());
let meta = module.evaluate(context).unwrap();
let meta = module.evaluate(s, context).unwrap();
assert!(meta.is_object());
let meta: Local<v8::Object> = cast(meta);
let key = v8::String::new(&mut *context, "foo").unwrap();
let expected = v8::String::new(&mut *context, "bar").unwrap();
let actual = meta.get(context, key.into()).unwrap();
let key = v8::String::new(s, "foo").unwrap();
let expected = v8::String::new(s, "bar").unwrap();
let actual = meta.get(s, context, key.into()).unwrap();
assert!(expected.strict_equals(actual));
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
context.exit();
});
}
drop(locker);
drop(g);
}
@ -407,8 +441,9 @@ fn script_compile_and_run() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |s| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let s = hs.enter();
let mut context = v8::Context::new(s);
context.enter();
let source = v8::String::new(s, "'Hello ' + 13 + 'th planet'").unwrap();
@ -420,7 +455,7 @@ fn script_compile_and_run() {
unsafe { std::mem::transmute_copy(&result) };
assert_eq!(result.to_rust_string_lossy(s), "Hello 13th planet");
context.exit();
});
}
drop(locker);
}
@ -432,7 +467,9 @@ fn script_origin() {
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |s| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let s = hs.enter();
let mut context = v8::Context::new(s);
context.enter();
@ -464,7 +501,7 @@ fn script_origin() {
source.to_rust_string_lossy(s);
let _result = script.run(s, context).unwrap();
context.exit();
});
}
drop(locker);
}
@ -521,7 +558,9 @@ fn test_primitives() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let null = v8::new_null(scope);
assert!(!null.is_undefined());
assert!(null.is_null());
@ -541,7 +580,7 @@ fn test_primitives() {
assert!(!false_.is_undefined());
assert!(!false_.is_null());
assert!(!false_.is_null_or_undefined());
});
}
drop(locker);
}
@ -553,7 +592,9 @@ fn exception() {
let mut isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
isolate.enter();
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let reference = "This is a test error";
@ -572,7 +613,7 @@ fn exception() {
);
assert!(v8::get_stack_trace(scope, exception).is_none());
context.exit();
});
}
drop(locker);
isolate.exit();
}
@ -584,7 +625,9 @@ fn json() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |s| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let s = hs.enter();
let mut context = v8::Context::new(s);
context.enter();
let json_string = v8_str(s, "{\"a\": 1, \"b\": 2}");
@ -597,7 +640,7 @@ fn json() {
let rust_str = stringified.to_rust_string_lossy(s);
assert_eq!("{\"a\":1,\"b\":2}".to_string(), rust_str);
context.exit();
});
}
drop(locker);
}
@ -614,7 +657,9 @@ fn object() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let null: v8::Local<v8::Value> = new_null(scope).into();
@ -629,7 +674,7 @@ fn object() {
let object = v8::Object::new(scope, null, names, values, 2);
assert!(!object.is_null_or_undefined());
context.exit();
});
}
drop(locker);
}
@ -640,15 +685,18 @@ fn create_data_property() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
eval(scope, context, "var a = {};");
let key = v8_str(scope, "a");
let obj = context
.global()
.get(context, v8_str(scope, "a").into())
.global(scope)
.get(scope, context, key.into())
.unwrap();
assert!(obj.is_object());
let obj: Local<v8::Object> = cast(obj);
@ -658,11 +706,11 @@ fn create_data_property() {
obj.create_data_property(context, cast(key), cast(value)),
v8::MaybeBool::JustTrue
);
let actual = obj.get(context, cast(key)).unwrap();
let actual = obj.get(scope, context, cast(key)).unwrap();
assert!(value.strict_equals(actual));
context.exit();
});
}
drop(locker);
}
@ -673,7 +721,9 @@ fn promise_resolved() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let maybe_resolver = v8::PromiseResolver::new(scope, context);
@ -698,7 +748,7 @@ fn promise_resolved() {
let result_str: v8::Local<v8::String> = cast(result);
assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
context.exit();
});
}
drop(locker);
}
@ -709,7 +759,9 @@ fn promise_rejected() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let maybe_resolver = v8::PromiseResolver::new(scope, context);
@ -735,21 +787,27 @@ fn promise_rejected() {
let result_str: v8::Local<v8::String> = cast(result);
assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
context.exit();
});
}
drop(locker);
}
extern "C" fn fn_callback(info: &FunctionCallbackInfo) {
assert_eq!(info.length(), 0);
let isolate = unsafe { info.get_isolate() };
v8::HandleScope::enter(isolate, |scope| {
{
let rv = &mut info.get_return_value();
#[allow(mutable_transmutes)]
#[allow(clippy::transmute_ptr_to_ptr)]
let info: &mut FunctionCallbackInfo = unsafe { std::mem::transmute(info) };
{
let mut hs = v8::HandleScope::new(info);
let scope = hs.enter();
let s = v8::String::new(scope, "Hello callback!").unwrap();
let value: Local<v8::Value> = s.into();
let rv = &mut info.get_return_value();
let rv_value = rv.get(scope);
assert!(rv_value.is_undefined());
rv.set(value);
});
}
}
}
#[test]
@ -759,10 +817,12 @@ fn function() {
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let global = context.global();
let global = context.global(scope);
let recv: Local<v8::Value> = global.into();
// create function using template
let mut fn_template = v8::FunctionTemplate::new(scope, fn_callback);
@ -781,7 +841,7 @@ fn function() {
let rust_str = value_str.to_rust_string_lossy(scope);
assert_eq!(rust_str, "Hello callback!".to_string());
context.exit();
});
}
drop(locker);
}
@ -790,15 +850,17 @@ extern "C" fn promise_reject_callback(msg: v8::PromiseRejectMessage) {
assert_eq!(event, v8::PromiseRejectEvent::PromiseRejectWithNoHandler);
let mut promise = msg.get_promise();
assert_eq!(promise.state(), v8::PromiseState::Rejected);
let promise_obj: v8::Local<v8::Object> = cast(promise);
let mut promise_obj: v8::Local<v8::Object> = cast(promise);
let isolate = promise_obj.get_isolate();
let value = msg.get_value();
let mut locker = v8::Locker::new(isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let value_str: v8::Local<v8::String> = cast(value);
let rust_str = value_str.to_rust_string_lossy(scope);
assert_eq!(rust_str, "promise rejected".to_string());
});
}
drop(locker);
}
@ -811,7 +873,9 @@ fn set_promise_reject_callback() {
isolate.set_promise_reject_callback(promise_reject_callback);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let mut resolver = v8::PromiseResolver::new(scope, context).unwrap();
@ -819,24 +883,24 @@ fn set_promise_reject_callback() {
let value: Local<v8::Value> = cast(str_);
resolver.reject(context, value);
context.exit();
});
}
drop(locker);
isolate.exit();
}
fn mock_script_origin<'sc>(
isolate: &mut impl AsMut<v8::Isolate>,
scope: &mut impl v8::ToLocal<'sc>,
resource_name_: &str,
) -> v8::ScriptOrigin<'sc> {
let resource_name = v8_str(isolate, resource_name_);
let resource_line_offset = v8::Integer::new(isolate, 0);
let resource_column_offset = v8::Integer::new(isolate, 0);
let resource_is_shared_cross_origin = v8::new_true(isolate);
let script_id = v8::Integer::new(isolate, 123);
let source_map_url = v8_str(isolate, "source_map_url");
let resource_is_opaque = v8::new_true(isolate);
let is_wasm = v8::new_false(isolate);
let is_module = v8::new_true(isolate);
let resource_name = v8_str(scope, resource_name_);
let resource_line_offset = v8::Integer::new(scope, 0);
let resource_column_offset = v8::Integer::new(scope, 0);
let resource_is_shared_cross_origin = v8::new_true(scope);
let script_id = v8::Integer::new(scope, 123);
let source_map_url = v8_str(scope, "source_map_url");
let resource_is_opaque = v8::new_true(scope);
let is_wasm = v8::new_false(scope);
let is_module = v8::new_true(scope);
v8::ScriptOrigin::new(
resource_name.into(),
resource_line_offset,
@ -850,13 +914,14 @@ fn mock_script_origin<'sc>(
)
}
fn mock_source(
isolate: &mut impl AsMut<v8::Isolate>,
fn mock_source<'sc>(
scope: &mut impl ToLocal<'sc>,
resource_name: &str,
source: &str,
) -> v8::script_compiler::Source {
let script_origin = mock_script_origin(isolate, resource_name);
v8::script_compiler::Source::new(v8_str(isolate, source), &script_origin)
let source_str = v8_str(scope, source);
let script_origin = mock_script_origin(scope, resource_name);
v8::script_compiler::Source::new(source_str, &script_origin)
}
#[test]
@ -868,7 +933,9 @@ fn script_compiler_source() {
isolate.set_promise_reject_callback(promise_reject_callback);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -881,7 +948,7 @@ fn script_compiler_source() {
assert!(result.is_some());
context.exit();
});
}
drop(locker);
isolate.exit();
drop(g);
@ -895,7 +962,9 @@ fn module_instantiation_failures1() {
let mut isolate = v8::Isolate::new(params);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -933,13 +1002,15 @@ fn module_instantiation_failures1() {
let mut try_catch = v8::TryCatch::new(scope);
let tc = try_catch.enter();
fn resolve_callback(
mut context: v8::Local<v8::Context>,
context: v8::Local<v8::Context>,
_specifier: v8::Local<v8::String>,
_referrer: v8::Local<v8::Module>,
) -> *mut v8::Module {
let isolate: &mut v8::Isolate = context.as_mut();
let e = v8_str(isolate, "boom");
isolate.throw_exception(e.into());
let mut cbs = v8::CallbackScope::new(context);
let mut hs = v8::HandleScope::new(cbs.enter());
let scope = hs.enter();
let e = v8_str(scope, "boom");
scope.isolate().throw_exception(e.into());
std::ptr::null_mut()
}
let result = module.instantiate_module(context, resolve_callback);
@ -953,22 +1024,25 @@ fn module_instantiation_failures1() {
}
context.exit();
});
}
drop(locker);
isolate.exit();
drop(g);
}
fn compile_specifier_as_module_resolve_callback(
mut context: v8::Local<v8::Context>,
context: v8::Local<v8::Context>,
specifier: v8::Local<v8::String>,
_referrer: v8::Local<v8::Module>,
) -> *mut v8::Module {
let isolate: &mut v8::Isolate = context.as_mut();
let origin = mock_script_origin(isolate, "module.js");
let mut cbs = v8::CallbackScope::new(context);
let mut hs = v8::EscapableHandleScope::new(cbs.enter());
let scope = hs.enter();
let origin = mock_script_origin(scope, "module.js");
let source = v8::script_compiler::Source::new(specifier, &origin);
let module = v8::script_compiler::compile_module(isolate, source).unwrap();
&mut *cast(module)
let module =
v8::script_compiler::compile_module(scope.isolate(), source).unwrap();
&mut *cast(scope.escape(module))
}
#[test]
@ -979,7 +1053,9 @@ fn module_evaluation() {
let mut isolate = v8::Isolate::new(params);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -1002,7 +1078,7 @@ fn module_evaluation() {
assert!(result.unwrap());
assert_eq!(v8::ModuleStatus::Instantiated, module.get_status());
let result = module.evaluate(context);
let result = module.evaluate(scope, context);
assert!(result.is_some());
assert_eq!(v8::ModuleStatus::Evaluated, module.get_status());
@ -1012,7 +1088,7 @@ fn module_evaluation() {
assert!(result.strict_equals(expected.into()));
context.exit();
});
}
drop(locker);
isolate.exit();
drop(g);
@ -1026,7 +1102,9 @@ fn primitive_array() {
let mut isolate = v8::Isolate::new(params);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -1051,7 +1129,7 @@ fn primitive_array() {
assert!(array.get(scope, 2).is_number());
context.exit();
});
}
drop(locker);
isolate.exit();
drop(g);
@ -1075,7 +1153,9 @@ fn equality() {
let mut isolate = v8::Isolate::new(params);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -1086,7 +1166,7 @@ fn equality() {
assert!(!v8_str(scope, "a").same_value(v8_str(scope, "b").into()));
context.exit();
});
}
drop(locker);
isolate.exit();
drop(g);
@ -1100,7 +1180,9 @@ fn array_buffer_view() {
let mut isolate = v8::Isolate::new(params);
isolate.enter();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |s| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let s = hs.enter();
let mut context = v8::Context::new(s);
context.enter();
let source = v8::String::new(s, "new Uint8Array([23,23,23,23])").unwrap();
@ -1121,7 +1203,7 @@ fn array_buffer_view() {
let ab = maybe_ab.unwrap();
assert_eq!(ab.byte_length(), 4);
context.exit();
});
}
drop(locker);
isolate.exit();
drop(g);
@ -1136,7 +1218,9 @@ fn snapshot_creator() {
let mut snapshot_creator = v8::SnapshotCreator::default();
let isolate = snapshot_creator.get_isolate();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
@ -1148,7 +1232,7 @@ fn snapshot_creator() {
snapshot_creator.set_default_context(context);
context.exit();
});
}
snapshot_creator.create_blob(v8::FunctionCodeHandling::Clear)
};
@ -1161,7 +1245,9 @@ fn snapshot_creator() {
params.set_snapshot_blob(&mut startup_data);
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
{
let mut hs = v8::HandleScope::new(&mut locker);
let scope = hs.enter();
let mut context = v8::Context::new(scope);
context.enter();
let source = v8::String::new(scope, "a === 3").unwrap();
@ -1171,7 +1257,7 @@ fn snapshot_creator() {
let true_val: Local<v8::Value> = cast(v8::new_true(scope));
assert!(result.same_value(true_val));
context.exit();
});
}
}
// TODO(ry) startup_data is getting leaked and is not cleaned up properly!