0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-03-09 21:47:00 -04:00

Add Local lifetimes back (#95)

This commit is contained in:
Bert Belder 2019-12-20 16:01:45 +01:00
parent bbfaacfe56
commit 331582561b
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
16 changed files with 389 additions and 283 deletions

View file

@ -1,6 +1,7 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::isolate::Isolate; use crate::isolate::Isolate;
use crate::support::Opaque; use crate::support::Opaque;
use crate::HandleScope;
use crate::Local; use crate::Local;
use crate::Object; use crate::Object;
@ -18,9 +19,9 @@ extern "C" {
pub struct Context(Opaque); pub struct Context(Opaque);
impl Context { impl Context {
pub fn new(isolate: &Isolate) -> Local<Context> { pub fn new<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Context> {
// TODO: optional arguments; // TODO: optional arguments;
unsafe { Local::from_raw(v8__Context__New(isolate)).unwrap() } unsafe { Local::from_raw(v8__Context__New(scope.as_mut())).unwrap() }
} }
/// Returns the global proxy object. /// Returns the global proxy object.
@ -33,7 +34,7 @@ impl Context {
/// Please note that changes to global proxy object prototype most probably /// Please note that changes to global proxy object prototype most probably
/// would break VM---v8 expects only global object as a prototype of global /// would break VM---v8 expects only global object as a prototype of global
/// proxy object. /// proxy object.
pub fn global(&mut self) -> Local<Object> { pub fn global<'sc>(&mut self) -> Local<'sc, Object> {
unsafe { Local::from_raw(v8__Context__Global(&mut *self)).unwrap() } unsafe { Local::from_raw(v8__Context__Global(&mut *self)).unwrap() }
} }

View file

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

View file

@ -1,5 +1,6 @@
use crate::support::{int, Opaque}; use crate::support::{int, Opaque};
use crate::Context; use crate::Context;
use crate::HandleScope;
use crate::Isolate; use crate::Isolate;
use crate::Local; use crate::Local;
use crate::Value; use crate::Value;
@ -63,7 +64,10 @@ impl ReturnValue {
/// Getter. Creates a new Local<> so it comes with a certain performance /// Getter. Creates a new Local<> so it comes with a certain performance
/// hit. If the ReturnValue was not yet set, this will return the undefined /// hit. If the ReturnValue was not yet set, this will return the undefined
/// value. /// value.
pub fn get(&mut self) -> Local<Value> { pub fn get<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__ReturnValue__Get(&mut *self)).unwrap() } unsafe { Local::from_raw(v8__ReturnValue__Get(&mut *self)).unwrap() }
} }
} }
@ -122,20 +126,22 @@ pub struct FunctionTemplate(Opaque);
impl FunctionTemplate { impl FunctionTemplate {
/// Creates a function template. /// Creates a function template.
pub fn new( pub fn new<'sc>(
isolate: &Isolate, scope: &mut HandleScope<'sc>,
callback: extern "C" fn(&FunctionCallbackInfo), callback: extern "C" fn(&FunctionCallbackInfo),
) -> Local<FunctionTemplate> { ) -> Local<'sc, FunctionTemplate> {
unsafe { unsafe {
Local::from_raw(v8__FunctionTemplate__New(isolate, callback)).unwrap() Local::from_raw(v8__FunctionTemplate__New(scope.as_mut(), callback))
.unwrap()
} }
} }
/// Returns the unique function instance in the current execution context. /// Returns the unique function instance in the current execution context.
pub fn get_function( pub fn get_function<'sc>(
&mut self, &mut self,
_scope: &mut HandleScope<'sc>,
mut context: Local<Context>, mut context: Local<Context>,
) -> Option<Local<Function>> { ) -> Option<Local<'sc, Function>> {
unsafe { unsafe {
Local::from_raw(v8__FunctionTemplate__GetFunction( Local::from_raw(v8__FunctionTemplate__GetFunction(
&mut *self, &mut *self,
@ -153,20 +159,22 @@ impl Function {
// TODO: add remaining arguments from C++ // TODO: add remaining arguments from C++
/// Create a function in the current execution context /// Create a function in the current execution context
/// for a given FunctionCallback. /// for a given FunctionCallback.
pub fn new( pub fn new<'sc>(
_scope: &mut HandleScope<'sc>,
mut context: Local<Context>, mut context: Local<Context>,
callback: extern "C" fn(&FunctionCallbackInfo), callback: extern "C" fn(&FunctionCallbackInfo),
) -> Option<Local<Function>> { ) -> Option<Local<'sc, Function>> {
unsafe { Local::from_raw(v8__Function__New(&mut *context, callback)) } unsafe { Local::from_raw(v8__Function__New(&mut *context, callback)) }
} }
pub fn call( pub fn call<'sc>(
&mut self, &mut self,
_scope: &mut HandleScope<'sc>,
mut context: Local<Context>, mut context: Local<Context>,
mut recv: Local<Value>, mut recv: Local<Value>,
arc: i32, arc: i32,
argv: Vec<Local<Value>>, argv: Vec<Local<Value>>,
) -> Option<Local<Value>> { ) -> Option<Local<'sc, Value>> {
let mut argv_: Vec<*mut Value> = vec![]; let mut argv_: Vec<*mut Value> = vec![];
for mut arg in argv { for mut arg in argv {
argv_.push(&mut *arg); argv_.push(&mut *arg);

View file

@ -1,3 +1,4 @@
use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use crate::isolate::Isolate; use crate::isolate::Isolate;
@ -8,22 +9,36 @@ extern "C" {
isolate: &Isolate, isolate: &Isolate,
); );
fn v8__HandleScope__DESTRUCT(this: &mut HandleScope); fn v8__HandleScope__DESTRUCT(this: &mut HandleScope);
fn v8__HandleScope__GetIsolate(this: &HandleScope) -> &mut Isolate; fn v8__HandleScope__GetIsolate<'sc>(
this: &'sc HandleScope,
) -> &'sc mut Isolate;
} }
#[repr(C)] #[repr(C)]
pub struct HandleScope([usize; 3]); pub struct HandleScope<'sc>([usize; 3], PhantomData<&'sc mut ()>);
impl HandleScope { impl<'sc> HandleScope<'sc> {
pub fn enter(isolate: &Isolate, mut f: impl FnMut(&mut HandleScope) -> ()) { pub fn enter(
isolate: &Isolate,
mut f: impl FnMut(&mut HandleScope<'_>) -> (),
) {
let mut scope: MaybeUninit<Self> = MaybeUninit::uninit(); let mut scope: MaybeUninit<Self> = MaybeUninit::uninit();
unsafe { v8__HandleScope__CONSTRUCT(&mut scope, isolate) }; unsafe { v8__HandleScope__CONSTRUCT(&mut scope, isolate) };
let scope = unsafe { &mut *(scope.as_mut_ptr()) }; let scope = unsafe { &mut *(scope.as_mut_ptr()) };
f(scope); f(scope);
unsafe { v8__HandleScope__DESTRUCT(scope) }; unsafe { v8__HandleScope__DESTRUCT(scope) };
} }
}
fn get_isolate(&self) -> &Isolate { impl<'sc> AsRef<Isolate> for HandleScope<'sc> {
fn as_ref(&self) -> &Isolate {
unsafe { v8__HandleScope__GetIsolate(self) }
}
}
impl<'sc> AsMut<Isolate> for HandleScope<'sc> {
fn as_mut(&mut self) -> &mut Isolate {
unsafe { v8__HandleScope__GetIsolate(self) } unsafe { v8__HandleScope__GetIsolate(self) }
} }
} }

View file

@ -131,6 +131,18 @@ impl Isolate {
} }
} }
impl AsRef<Isolate> for Isolate {
fn as_ref(&self) -> &Isolate {
self
}
}
impl AsMut<Isolate> for Isolate {
fn as_mut(&mut self) -> &mut Isolate {
self
}
}
/// Same as Isolate but gets disposed when it goes out of scope. /// Same as Isolate but gets disposed when it goes out of scope.
pub struct OwnedIsolate(NonNull<Isolate>); pub struct OwnedIsolate(NonNull<Isolate>);

View file

@ -18,19 +18,19 @@ extern "C" {
/// Tries to parse the string `json_string` and returns it as value if /// Tries to parse the string `json_string` and returns it as value if
/// successful. /// successful.
pub fn parse( pub fn parse<'sc>(
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut json_string: Local<String>, mut json_string: Local<'sc, String>,
) -> Option<Local<Value>> { ) -> 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 /// Tries to stringify the JSON-serializable object `json_object` and returns
/// it as string if successful. /// it as string if successful.
pub fn stringify( pub fn stringify<'sc>(
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut json_object: Local<Value>, mut json_object: Local<'sc, Value>,
) -> Option<Local<String>> { ) -> Option<Local<'sc, String>> {
unsafe { 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

@ -1,4 +1,5 @@
use crate::value::Value; use crate::value::Value;
use std::marker::PhantomData;
use std::ops::Deref; use std::ops::Deref;
use std::ops::DerefMut; use std::ops::DerefMut;
use std::ptr::NonNull; use std::ptr::NonNull;
@ -37,30 +38,30 @@ use std::ptr::NonNull;
/// Note: Local handles in Rusty V8 differ from the V8 C++ API in that they are /// Note: Local handles in Rusty V8 differ from the V8 C++ API in that they are
/// never empty. In situations where empty handles are needed, use /// never empty. In situations where empty handles are needed, use
/// Option<Local>. /// Option<Local>.
pub struct Local<T>(NonNull<T>); pub struct Local<'sc, T>(NonNull<T>, PhantomData<&'sc ()>);
impl<T> Copy for Local<T> {} impl<'sc, T> Copy for Local<'sc, T> {}
impl<T> Clone for Local<T> { impl<'sc, T> Clone for Local<'sc, T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(self.0) Self(self.0, self.1)
} }
} }
impl<T> Local<T> { impl<'sc, T> Local<'sc, T> {
pub unsafe fn from_raw(ptr: *mut T) -> Option<Self> { pub unsafe fn from_raw(ptr: *mut T) -> Option<Self> {
Some(Self(NonNull::new(ptr)?)) Some(Self(NonNull::new(ptr)?, PhantomData))
} }
} }
impl<T> Deref for Local<T> { impl<'sc, T> Deref for Local<'sc, T> {
type Target = T; type Target = T;
fn deref(&self) -> &T { fn deref(&self) -> &T {
unsafe { self.0.as_ref() } unsafe { self.0.as_ref() }
} }
} }
impl<T> DerefMut for Local<T> { impl<'sc, T> DerefMut for Local<'sc, T> {
fn deref_mut(&mut self) -> &mut T { fn deref_mut(&mut self) -> &mut T {
unsafe { self.0.as_mut() } unsafe { self.0.as_mut() }
} }
@ -68,11 +69,11 @@ impl<T> DerefMut for Local<T> {
// TODO make it possible for targets other than Local<Value>. For example // TODO make it possible for targets other than Local<Value>. For example
// Local<String> should be able to be down cast to Local<Name>. // Local<String> should be able to be down cast to Local<Name>.
impl<T> From<Local<T>> for Local<Value> impl<'sc, T> From<Local<'sc, T>> for Local<'sc, Value>
where where
T: Deref<Target = Value>, T: Deref<Target = Value>,
{ {
fn from(v: Local<T>) -> Local<Value> { fn from(v: Local<'sc, T>) -> Local<'sc, Value> {
unsafe { std::mem::transmute(v) } unsafe { std::mem::transmute(v) }
} }
} }

View file

@ -1,5 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
use crate::isolate::Isolate; use crate::isolate::Isolate;
use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
extern "C" { extern "C" {
@ -12,9 +13,9 @@ extern "C" {
/// construction and destruction, the current thread is allowed to use the locked /// 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 /// 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. /// any time. In other words, the scope of a v8::Locker is a critical section.
pub struct Locker([usize; 2]); pub struct Locker<'sc>([usize; 2], PhantomData<&'sc mut ()>);
impl Locker { impl<'a> Locker<'a> {
/// Initialize Locker for a given Isolate. /// Initialize Locker for a given Isolate.
pub fn new(isolate: &Isolate) -> Self { pub fn new(isolate: &Isolate) -> Self {
let mut buf = MaybeUninit::<Self>::uninit(); let mut buf = MaybeUninit::<Self>::uninit();
@ -25,7 +26,7 @@ impl Locker {
} }
} }
impl Drop for Locker { impl<'a> Drop for Locker<'a> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { v8__Locker__DESTRUCT(self) } unsafe { v8__Locker__DESTRUCT(self) }
} }

View file

@ -79,5 +79,8 @@ impl Module {
} }
} }
type ResolveCallback = type ResolveCallback<'sc> = dyn Fn(
dyn Fn(Local<Context>, Local<String>, Local<Module>) -> Option<Local<Module>>; Local<'sc, Context>,
Local<'sc, String>,
Local<'sc, Module>,
) -> Option<Local<'sc, Module>>;

View file

@ -1,19 +1,20 @@
use std::ops::Deref; use std::ops::Deref;
use crate::isolate::Isolate;
use crate::support::Opaque; use crate::support::Opaque;
use crate::Isolate; use crate::value::Value;
use crate::HandleScope;
use crate::Local; use crate::Local;
use crate::Value;
extern "C" { extern "C" {
fn v8__Number__New(isolate: &Isolate, value: f64) -> *mut Number; fn v8__Number__New(isolate: *mut Isolate, value: f64) -> *mut Number;
fn v8__Number__Value(this: &Number) -> f64; fn v8__Number__Value(this: &Number) -> f64;
fn v8__Integer__New(isolate: &Isolate, value: i32) -> *mut Integer; fn v8__Integer__New(isolate: *mut Isolate, value: i32) -> *mut Integer;
fn v8__Integer__NewFromUnsigned( fn v8__Integer__NewFromUnsigned(
isolate: &Isolate, isolate: *mut Isolate,
value: u32, value: u32,
) -> *mut Integer; ) -> *mut Integer;
fn v8__Integer__Value(this: &Integer) -> i64; fn v8__Integer__Value(this: *const Integer) -> i64;
} }
/// A JavaScript number value (ECMA-262, 4.3.20) /// A JavaScript number value (ECMA-262, 4.3.20)
@ -21,9 +22,12 @@ extern "C" {
pub struct Number(Opaque); pub struct Number(Opaque);
impl Number { impl Number {
pub fn new(isolate: &Isolate, value: f64) -> Local<Number> { pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
value: f64,
) -> Local<'sc, Number> {
unsafe { unsafe {
let local = v8__Number__New(isolate, value); let local = v8__Number__New(scope.as_mut(), value);
Local::from_raw(local).unwrap() Local::from_raw(local).unwrap()
} }
} }
@ -45,16 +49,22 @@ impl Deref for Number {
pub struct Integer(Opaque); pub struct Integer(Opaque);
impl Integer { impl Integer {
pub fn new(isolate: &Isolate, value: i32) -> Local<Integer> { pub fn new<'sc>(
scope: &mut HandleScope<'sc>,
value: i32,
) -> Local<'sc, Integer> {
unsafe { unsafe {
let local = v8__Integer__New(isolate, value); let local = v8__Integer__New(scope.as_mut(), value);
Local::from_raw(local).unwrap() Local::from_raw(local).unwrap()
} }
} }
pub fn new_from_unsigned(isolate: &Isolate, value: u32) -> Local<Integer> { pub fn new_from_unsigned<'sc>(
scope: &mut HandleScope<'sc>,
value: u32,
) -> Local<'sc, Integer> {
unsafe { unsafe {
let local = v8__Integer__NewFromUnsigned(isolate, value); let local = v8__Integer__NewFromUnsigned(scope.as_mut(), value);
Local::from_raw(local).unwrap() Local::from_raw(local).unwrap()
} }
} }

View file

@ -2,6 +2,7 @@ use std::ops::Deref;
use crate::isolate::Isolate; use crate::isolate::Isolate;
use crate::support::Opaque; use crate::support::Opaque;
use crate::HandleScope;
use crate::Local; use crate::Local;
use crate::Name; use crate::Name;
use crate::Value; use crate::Value;
@ -12,7 +13,7 @@ pub struct Object(Opaque);
extern "C" { extern "C" {
fn v8__Object__New( fn v8__Object__New(
isolate: &Isolate, isolate: *mut Isolate,
prototype_or_null: *mut Value, prototype_or_null: *mut Value,
names: *mut *mut Name, names: *mut *mut Name,
values: *mut *mut Value, values: *mut *mut Value,
@ -28,13 +29,13 @@ impl Object {
/// a prototype at all). This is similar to Object.create(). /// a prototype at all). This is similar to Object.create().
/// All properties will be created as enumerable, configurable /// All properties will be created as enumerable, configurable
/// and writable properties. /// and writable properties.
pub fn new( pub fn new<'sc>(
isolate: &Isolate, scope: &mut HandleScope<'sc>,
mut prototype_or_null: Local<Value>, mut prototype_or_null: Local<'sc, Value>,
names: Vec<Local<Name>>, names: Vec<Local<'sc, Name>>,
values: Vec<Local<Value>>, values: Vec<Local<'sc, Value>>,
length: usize, length: usize,
) -> Local<Object> { ) -> Local<'sc, Object> {
let mut names_: Vec<*mut Name> = vec![]; let mut names_: Vec<*mut Name> = vec![];
for mut name in names { for mut name in names {
let n = &mut *name; let n = &mut *name;
@ -48,7 +49,7 @@ impl Object {
} }
unsafe { unsafe {
Local::from_raw(v8__Object__New( Local::from_raw(v8__Object__New(
isolate, scope.as_mut(),
&mut *prototype_or_null, &mut *prototype_or_null,
names_.as_mut_ptr(), names_.as_mut_ptr(),
values_.as_mut_ptr(), values_.as_mut_ptr(),

View file

@ -2,6 +2,7 @@ use std::ops::Deref;
use crate::isolate::Isolate; use crate::isolate::Isolate;
use crate::support::Opaque; use crate::support::Opaque;
use crate::HandleScope;
use crate::Local; use crate::Local;
use crate::Value; use crate::Value;
@ -19,29 +20,31 @@ pub struct Boolean(Opaque);
pub struct Name(Opaque); pub struct Name(Opaque);
extern "C" { extern "C" {
fn v8__Null(isolate: &Isolate) -> *mut Primitive; fn v8__Null(isolate: *mut Isolate) -> *mut Primitive;
fn v8__Undefined(isolate: &Isolate) -> *mut Primitive; fn v8__Undefined(isolate: *mut Isolate) -> *mut Primitive;
fn v8__True(isolate: &Isolate) -> *mut Boolean; fn v8__True(isolate: *mut Isolate) -> *mut Boolean;
fn v8__False(isolate: &Isolate) -> *mut Boolean; fn v8__False(isolate: *mut Isolate) -> *mut Boolean;
} }
pub fn new_null(isolate: &Isolate) -> Local<Primitive> { pub fn new_null<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Primitive> {
unsafe { Local::from_raw(v8__Null(isolate)) }.unwrap() unsafe { Local::from_raw(v8__Null(scope.as_mut())) }.unwrap()
} }
pub fn new_undefined(isolate: &Isolate) -> Local<Primitive> { pub fn new_undefined<'sc>(
unsafe { Local::from_raw(v8__Undefined(isolate)) }.unwrap() scope: &mut HandleScope<'sc>,
) -> Local<'sc, Primitive> {
unsafe { Local::from_raw(v8__Undefined(scope.as_mut())) }.unwrap()
} }
pub fn new_true(isolate: &Isolate) -> Local<Boolean> { pub fn new_true<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Boolean> {
unsafe { Local::from_raw(v8__True(isolate)) }.unwrap() unsafe { Local::from_raw(v8__True(scope.as_mut())) }.unwrap()
} }
pub fn new_false(isolate: &Isolate) -> Local<Boolean> { pub fn new_false<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Boolean> {
unsafe { Local::from_raw(v8__False(isolate)) }.unwrap() unsafe { Local::from_raw(v8__False(scope.as_mut())) }.unwrap()
} }
impl Deref for Primitive { impl Deref for Primitive {

View file

@ -1,7 +1,10 @@
use std::marker::PhantomData;
use crate::support::MaybeBool; use crate::support::MaybeBool;
use crate::support::Opaque; use crate::support::Opaque;
use crate::Context; use crate::Context;
use crate::Function; use crate::Function;
use crate::HandleScope;
use crate::Local; use crate::Local;
use crate::Value; use crate::Value;
@ -77,18 +80,21 @@ impl Promise {
/// Returns the content of the [[PromiseResult]] field. The Promise must not /// Returns the content of the [[PromiseResult]] field. The Promise must not
/// be pending. /// be pending.
pub fn result(&mut self) -> Local<Value> { pub fn result<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
) -> Local<'sc, Value> {
unsafe { Local::from_raw(v8__Promise__Result(&mut *self)).unwrap() } unsafe { Local::from_raw(v8__Promise__Result(&mut *self)).unwrap() }
} }
/// Register a rejection handler with a promise. /// Register a rejection handler with a promise.
/// ///
/// See `Self::then2`. /// See `Self::then2`.
pub fn catch( pub fn catch<'sc>(
&mut self, &mut self,
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut handler: Local<Function>, mut handler: Local<'sc, Function>,
) -> Option<Local<Promise>> { ) -> Option<Local<'sc, Promise>> {
unsafe { unsafe {
Local::from_raw(v8__Promise__Catch( Local::from_raw(v8__Promise__Catch(
&mut *self, &mut *self,
@ -101,11 +107,11 @@ impl Promise {
/// Register a resolution handler with a promise. /// Register a resolution handler with a promise.
/// ///
/// See `Self::then2`. /// See `Self::then2`.
pub fn then( pub fn then<'sc>(
&mut self, &mut self,
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut handler: Local<Function>, mut handler: Local<'sc, Function>,
) -> Option<Local<Promise>> { ) -> Option<Local<'sc, Promise>> {
unsafe { unsafe {
Local::from_raw(v8__Promise__Then( Local::from_raw(v8__Promise__Then(
&mut *self, &mut *self,
@ -119,12 +125,12 @@ impl Promise {
/// The handler is given the respective resolution/rejection value as /// The handler is given the respective resolution/rejection value as
/// an argument. If the promise is already resolved/rejected, the handler is /// an argument. If the promise is already resolved/rejected, the handler is
/// invoked at the end of turn. /// invoked at the end of turn.
pub fn then2( pub fn then2<'sc>(
&mut self, &mut self,
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut on_fulfilled: Local<Function>, mut on_fulfilled: Local<'sc, Function>,
mut on_rejected: Local<Function>, mut on_rejected: Local<'sc, Function>,
) -> Option<Local<Promise>> { ) -> Option<Local<'sc, Promise>> {
unsafe { unsafe {
Local::from_raw(v8__Promise__Then2( Local::from_raw(v8__Promise__Then2(
&mut *self, &mut *self,
@ -141,12 +147,18 @@ pub struct PromiseResolver(Opaque);
impl PromiseResolver { impl PromiseResolver {
/// Create a new resolver, along with an associated promise in pending state. /// Create a new resolver, along with an associated promise in pending state.
pub fn new(mut context: Local<Context>) -> Option<Local<PromiseResolver>> { pub fn new<'sc>(
_scope: &mut HandleScope<'sc>,
mut context: Local<'sc, Context>,
) -> Option<Local<'sc, PromiseResolver>> {
unsafe { Local::from_raw(v8__Promise__Resolver__New(&mut *context)) } unsafe { Local::from_raw(v8__Promise__Resolver__New(&mut *context)) }
} }
/// Extract the associated promise. /// Extract the associated promise.
pub fn get_promise(&mut self) -> Local<Promise> { pub fn get_promise<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
) -> Local<'sc, Promise> {
unsafe { unsafe {
Local::from_raw(v8__Promise__Resolver__GetPromise(&mut *self)).unwrap() Local::from_raw(v8__Promise__Resolver__GetPromise(&mut *self)).unwrap()
} }
@ -154,10 +166,10 @@ impl PromiseResolver {
/// Resolve the associated promise with a given value. /// Resolve the associated promise with a given value.
/// Ignored if the promise is no longer pending. /// Ignored if the promise is no longer pending.
pub fn resolve( pub fn resolve<'sc>(
&mut self, &mut self,
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut value: Local<Value>, mut value: Local<'sc, Value>,
) -> Option<bool> { ) -> Option<bool> {
unsafe { unsafe {
v8__Promise__Resolver__Resolve(&mut *self, &mut *context, &mut *value) v8__Promise__Resolver__Resolve(&mut *self, &mut *context, &mut *value)
@ -167,10 +179,10 @@ impl PromiseResolver {
/// Reject the associated promise with a given value. /// Reject the associated promise with a given value.
/// Ignored if the promise is no longer pending. /// Ignored if the promise is no longer pending.
pub fn reject( pub fn reject<'sc>(
&mut self, &mut self,
mut context: Local<Context>, mut context: Local<'sc, Context>,
mut value: Local<Value>, mut value: Local<'sc, Value>,
) -> Option<bool> { ) -> Option<bool> {
unsafe { unsafe {
v8__Promise__Resolver__Reject(&mut *self, &mut *context, &mut *value) v8__Promise__Resolver__Reject(&mut *self, &mut *context, &mut *value)
@ -189,10 +201,10 @@ pub enum PromiseRejectEvent {
} }
#[repr(C)] #[repr(C)]
pub struct PromiseRejectMessage([usize; 3]); pub struct PromiseRejectMessage<'msg>([usize; 3], PhantomData<&'msg ()>);
impl PromiseRejectMessage { impl<'msg> PromiseRejectMessage<'msg> {
pub fn get_promise(&self) -> Local<Promise> { pub fn get_promise(&self) -> Local<'msg, Promise> {
unsafe { unsafe {
Local::from_raw(v8__PromiseRejectMessage__GetPromise(self)).unwrap() Local::from_raw(v8__PromiseRejectMessage__GetPromise(self)).unwrap()
} }
@ -202,7 +214,7 @@ impl PromiseRejectMessage {
unsafe { v8__PromiseRejectMessage__GetEvent(self) } unsafe { v8__PromiseRejectMessage__GetEvent(self) }
} }
pub fn get_value(&self) -> Local<Value> { pub fn get_value(&self) -> Local<'msg, Value> {
unsafe { unsafe {
Local::from_raw(v8__PromiseRejectMessage__GetValue(self)).unwrap() Local::from_raw(v8__PromiseRejectMessage__GetValue(self)).unwrap()
} }

View file

@ -1,9 +1,11 @@
use std::marker::PhantomData;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use std::ptr::null; use std::ptr::null;
use crate::support::Opaque; use crate::support::Opaque;
use crate::Boolean; use crate::Boolean;
use crate::Context; use crate::Context;
use crate::HandleScope;
use crate::Integer; use crate::Integer;
use crate::Local; use crate::Local;
use crate::String; use crate::String;
@ -11,7 +13,7 @@ use crate::Value;
/// The origin, within a file, of a script. /// The origin, within a file, of a script.
#[repr(C)] #[repr(C)]
pub struct ScriptOrigin([usize; 7]); pub struct ScriptOrigin<'sc>([usize; 7], PhantomData<&'sc ()>);
extern "C" { extern "C" {
fn v8__Script__Compile( fn v8__Script__Compile(
@ -42,11 +44,12 @@ pub struct Script(Opaque);
impl Script { impl Script {
/// A shorthand for ScriptCompiler::Compile(). /// A shorthand for ScriptCompiler::Compile().
pub fn compile( pub fn compile<'sc>(
_scope: &mut HandleScope<'sc>,
mut context: Local<Context>, mut context: Local<Context>,
mut source: Local<String>, mut source: Local<String>,
origin: Option<&'_ ScriptOrigin>, origin: Option<&ScriptOrigin>,
) -> Option<Local<Script>> { ) -> Option<Local<'sc, Script>> {
// TODO: use the type system to enforce that a Context has been entered. // TODO: use the type system to enforce that a Context has been entered.
// TODO: `context` and `source` probably shouldn't be mut. // TODO: `context` and `source` probably shouldn't be mut.
unsafe { unsafe {
@ -61,24 +64,28 @@ impl Script {
/// Runs the script returning the resulting value. It will be run in the /// Runs the script returning the resulting value. It will be run in the
/// context in which it was created (ScriptCompiler::CompileBound or /// context in which it was created (ScriptCompiler::CompileBound or
/// UnboundScript::BindToCurrentContext()). /// UnboundScript::BindToCurrentContext()).
pub fn run(&mut self, mut context: Local<Context>) -> Option<Local<Value>> { pub fn run<'sc>(
&mut self,
_scope: &mut HandleScope<'sc>,
mut context: Local<Context>,
) -> Option<Local<'sc, Value>> {
unsafe { Local::from_raw(v8__Script__Run(self, &mut *context)) } unsafe { Local::from_raw(v8__Script__Run(self, &mut *context)) }
} }
} }
/// The origin, within a file, of a script. /// The origin, within a file, of a script.
impl ScriptOrigin { impl<'sc> ScriptOrigin<'sc> {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
mut resource_name: Local<Value>, mut resource_name: Local<'sc, Value>,
mut resource_line_offset: Local<Integer>, mut resource_line_offset: Local<'sc, Integer>,
mut resource_column_offset: Local<Integer>, mut resource_column_offset: Local<'sc, Integer>,
mut resource_is_shared_cross_origin: Local<Boolean>, mut resource_is_shared_cross_origin: Local<'sc, Boolean>,
mut script_id: Local<Integer>, mut script_id: Local<'sc, Integer>,
mut source_map_url: Local<Value>, mut source_map_url: Local<'sc, Value>,
mut resource_is_opaque: Local<Boolean>, mut resource_is_opaque: Local<'sc, Boolean>,
mut is_wasm: Local<Boolean>, mut is_wasm: Local<'sc, Boolean>,
mut is_module: Local<Boolean>, mut is_module: Local<'sc, Boolean>,
) -> Self { ) -> Self {
unsafe { unsafe {
let mut buf = std::mem::MaybeUninit::<ScriptOrigin>::uninit(); let mut buf = std::mem::MaybeUninit::<ScriptOrigin>::uninit();

View file

@ -8,12 +8,13 @@ use crate::isolate::Isolate;
use crate::support::char; use crate::support::char;
use crate::support::int; use crate::support::int;
use crate::support::Opaque; use crate::support::Opaque;
use crate::HandleScope;
use crate::Local; use crate::Local;
use crate::Value; use crate::Value;
extern "C" { extern "C" {
fn v8__String__NewFromUtf8( fn v8__String__NewFromUtf8(
isolate: &Isolate, isolate: *mut Isolate,
data: *const char, data: *const char,
new_type: NewStringType, new_type: NewStringType,
length: int, length: int,
@ -21,11 +22,11 @@ extern "C" {
fn v8__String__Length(this: &String) -> int; fn v8__String__Length(this: &String) -> int;
fn v8__String__Utf8Length(this: &String, isolate: &Isolate) -> int; fn v8__String__Utf8Length(this: &String, isolate: *mut Isolate) -> int;
fn v8__String__WriteUtf8( fn v8__String__WriteUtf8(
this: &String, this: &String,
isolate: &Isolate, isolate: *mut Isolate,
buffer: *mut char, buffer: *mut char,
length: int, length: int,
nchars_ref: *mut int, nchars_ref: *mut int,
@ -65,14 +66,14 @@ bitflags! {
pub struct String(Opaque); pub struct String(Opaque);
impl String { impl String {
pub fn new_from_utf8( pub fn new_from_utf8<'sc>(
isolate: &Isolate, scope: &mut HandleScope<'sc>,
buffer: &[u8], buffer: &[u8],
new_type: NewStringType, new_type: NewStringType,
) -> Option<Local<String>> { ) -> Option<Local<'sc, String>> {
unsafe { unsafe {
let ptr = v8__String__NewFromUtf8( let ptr = v8__String__NewFromUtf8(
isolate, scope.as_mut(),
buffer.as_ptr() as *const char, buffer.as_ptr() as *const char,
new_type, new_type,
buffer.len().try_into().ok()?, buffer.len().try_into().ok()?,
@ -88,13 +89,13 @@ impl String {
/// Returns the number of bytes in the UTF-8 encoded representation of this /// Returns the number of bytes in the UTF-8 encoded representation of this
/// string. /// string.
pub fn utf8_length(&self, isolate: &Isolate) -> usize { pub fn utf8_length(&self, isolate: &mut impl AsMut<Isolate>) -> usize {
unsafe { v8__String__Utf8Length(self, isolate) as usize } unsafe { v8__String__Utf8Length(self, isolate.as_mut()) as usize }
} }
pub fn write_utf8( pub fn write_utf8(
&self, &self,
isolate: &Isolate, isolate: &mut Isolate,
buffer: &mut [u8], buffer: &mut [u8],
nchars_ref: Option<&mut usize>, nchars_ref: Option<&mut usize>,
options: WriteOptions, options: WriteOptions,
@ -117,16 +118,20 @@ impl String {
} }
// Convenience function not present in the original V8 API. // Convenience function not present in the original V8 API.
pub fn new( pub fn new<'sc>(
isolate: &Isolate, scope: &mut HandleScope<'sc>,
value: &str, value: &str,
new_type: NewStringType, new_type: NewStringType,
) -> Option<Local<String>> { ) -> Option<Local<'sc, String>> {
Self::new_from_utf8(isolate, value.as_ref(), new_type) Self::new_from_utf8(scope, value.as_ref(), new_type)
} }
// Convenience function not present in the original V8 API. // Convenience function not present in the original V8 API.
pub fn to_rust_string_lossy(&self, isolate: &Isolate) -> std::string::String { pub fn to_rust_string_lossy(
&self,
isolate: &mut impl AsMut<Isolate>,
) -> std::string::String {
let isolate = isolate.as_mut();
let capacity = self.utf8_length(isolate); let capacity = self.utf8_length(isolate);
let mut string = std::string::String::with_capacity(capacity); let mut string = std::string::String::with_capacity(capacity);
let data = string.as_mut_ptr(); let data = string.as_mut_ptr();

View file

@ -4,7 +4,8 @@
extern crate lazy_static; extern crate lazy_static;
use rusty_v8 as v8; use rusty_v8 as v8;
use rusty_v8::{new_null, FunctionCallbackInfo, Local}; use rusty_v8::{new_null, FunctionCallbackInfo, HandleScope, Local};
use std::default::Default;
use std::sync::Mutex; use std::sync::Mutex;
lazy_static! { lazy_static! {
@ -64,11 +65,11 @@ fn handle_scope_numbers() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let l1 = v8::Integer::new(&isolate, -123); let l1 = v8::Integer::new(scope, -123);
let l2 = v8::Integer::new_from_unsigned(&isolate, 456); let l2 = v8::Integer::new_from_unsigned(scope, 456);
v8::HandleScope::enter(&isolate, |_scope2| { v8::HandleScope::enter(&isolate, |scope2| {
let l3 = v8::Number::new(&isolate, 78.9); let l3 = v8::Number::new(scope2, 78.9);
assert_eq!(l1.value(), -123); assert_eq!(l1.value(), -123);
assert_eq!(l2.value(), 456); assert_eq!(l2.value(), 456);
assert_eq!(l3.value(), 78.9); assert_eq!(l3.value(), 78.9);
@ -89,18 +90,22 @@ fn test_string() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let reference = "Hello 🦕 world!"; let reference = "Hello 🦕 world!";
let local = v8_str(&isolate, reference); let local =
v8::String::new(scope, reference, v8::NewStringType::Normal).unwrap();
assert_eq!(15, local.length()); assert_eq!(15, local.length());
assert_eq!(17, local.utf8_length(&isolate)); assert_eq!(17, local.utf8_length(scope));
assert_eq!(reference, local.to_rust_string_lossy(&isolate)); assert_eq!(reference, local.to_rust_string_lossy(scope));
}); });
drop(locker); drop(locker);
} }
fn v8_str(isolate: &v8::Isolate, s: &str) -> v8::Local<v8::String> { fn v8_str<'sc>(
v8::String::new(&isolate, s, v8::NewStringType::Normal).unwrap() scope: &mut HandleScope<'sc>,
s: &str,
) -> v8::Local<'sc, v8::String> {
v8::String::new(scope, s, v8::NewStringType::Normal).unwrap()
} }
#[test] #[test]
@ -122,18 +127,20 @@ fn isolate_add_message_listener() {
) { ) {
CALL_COUNT.fetch_add(1, Ordering::SeqCst); CALL_COUNT.fetch_add(1, Ordering::SeqCst);
let isolate = message.get_isolate(); let isolate = message.get_isolate();
let message_str = message.get(); v8::HandleScope::enter(&isolate, |scope| {
assert_eq!(message_str.to_rust_string_lossy(&isolate), "Uncaught foo"); let message_str = message.get(scope);
assert_eq!(message_str.to_rust_string_lossy(scope), "Uncaught foo");
});
} }
isolate.add_message_listener(check_message_0); isolate.add_message_listener(check_message_0);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_s| { v8::HandleScope::enter(&isolate, |s| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(s);
context.enter(); context.enter();
let source = v8_str(&isolate, "throw 'foo'"); let source = v8::String::new(s, "throw 'foo'", Default::default()).unwrap();
let mut script = v8::Script::compile(context, source, None).unwrap(); let mut script = v8::Script::compile(s, context, source, None).unwrap();
assert!(script.run(context).is_none()); assert!(script.run(s, context).is_none());
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1); assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
context.exit(); context.exit();
}); });
@ -151,17 +158,19 @@ fn script_compile_and_run() {
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_s| { v8::HandleScope::enter(&isolate, |s| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(s);
context.enter(); context.enter();
let source = v8_str(&isolate, "'Hello ' + 13 + 'th planet'"); let source =
let mut script = v8::Script::compile(context, source, None).unwrap(); v8::String::new(s, "'Hello ' + 13 + 'th planet'", Default::default())
source.to_rust_string_lossy(&isolate); .unwrap();
let result = script.run(context).unwrap(); let mut script = v8::Script::compile(s, context, source, None).unwrap();
source.to_rust_string_lossy(s);
let result = script.run(s, context).unwrap();
// TODO: safer casts. // TODO: safer casts.
let result: v8::Local<v8::String> = let result: v8::Local<v8::String> =
unsafe { std::mem::transmute_copy(&result) }; unsafe { std::mem::transmute_copy(&result) };
assert_eq!(result.to_rust_string_lossy(&isolate), "Hello 13th planet"); assert_eq!(result.to_rust_string_lossy(s), "Hello 13th planet");
context.exit(); context.exit();
}); });
drop(locker); drop(locker);
@ -177,19 +186,21 @@ fn script_origin() {
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_s| { v8::HandleScope::enter(&isolate, |s| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(s);
context.enter(); context.enter();
let resource_name = v8_str(&isolate, "foo.js"); let resource_name =
let resource_line_offset = v8::Integer::new(&isolate, 4); v8::String::new(s, "foo.js", Default::default()).unwrap();
let resource_column_offset = v8::Integer::new(&isolate, 5); let resource_line_offset = v8::Integer::new(s, 4);
let resource_is_shared_cross_origin = v8::new_true(&isolate); let resource_column_offset = v8::Integer::new(s, 5);
let script_id = v8::Integer::new(&isolate, 123); let resource_is_shared_cross_origin = v8::new_true(s);
let source_map_url = v8_str(&isolate, "source_map_url"); let script_id = v8::Integer::new(s, 123);
let resource_is_opaque = v8::new_true(&isolate); let source_map_url =
let is_wasm = v8::new_false(&isolate); v8::String::new(s, "source_map_url", Default::default()).unwrap();
let is_module = v8::new_false(&isolate); let resource_is_opaque = v8::new_true(s);
let is_wasm = v8::new_false(s);
let is_module = v8::new_false(s);
let script_origin = v8::ScriptOrigin::new( let script_origin = v8::ScriptOrigin::new(
resource_name.into(), resource_name.into(),
@ -203,11 +214,11 @@ fn script_origin() {
is_module, is_module,
); );
let source = v8_str(&isolate, "1+2"); let source = v8::String::new(s, "1+2", Default::default()).unwrap();
let mut script = let mut script =
v8::Script::compile(context, source, Some(&script_origin)).unwrap(); v8::Script::compile(s, context, source, Some(&script_origin)).unwrap();
source.to_rust_string_lossy(&isolate); source.to_rust_string_lossy(s);
let _result = script.run(context).unwrap(); let _result = script.run(s, context).unwrap();
context.exit(); context.exit();
}); });
drop(locker); drop(locker);
@ -268,23 +279,23 @@ fn test_primitives() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let null = v8::new_null(&isolate); let null = v8::new_null(scope);
assert!(!null.is_undefined()); assert!(!null.is_undefined());
assert!(null.is_null()); assert!(null.is_null());
assert!(null.is_null_or_undefined()); assert!(null.is_null_or_undefined());
let undefined = v8::new_undefined(&isolate); let undefined = v8::new_undefined(scope);
assert!(undefined.is_undefined()); assert!(undefined.is_undefined());
assert!(!undefined.is_null()); assert!(!undefined.is_null());
assert!(undefined.is_null_or_undefined()); assert!(undefined.is_null_or_undefined());
let true_ = v8::new_true(&isolate); let true_ = v8::new_true(scope);
assert!(!true_.is_undefined()); assert!(!true_.is_undefined());
assert!(!true_.is_null()); assert!(!true_.is_null());
assert!(!true_.is_null_or_undefined()); assert!(!true_.is_null_or_undefined());
let false_ = v8::new_false(&isolate); let false_ = v8::new_false(scope);
assert!(!false_.is_undefined()); assert!(!false_.is_undefined());
assert!(!false_.is_null()); assert!(!false_.is_null());
assert!(!false_.is_null_or_undefined()); assert!(!false_.is_null_or_undefined());
@ -302,24 +313,25 @@ fn exception() {
let mut isolate = v8::Isolate::new(params); let mut isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
isolate.enter(); isolate.enter();
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let reference = "This is a test error"; let reference = "This is a test error";
let local = v8_str(&isolate, reference); let local =
v8::range_error(local); v8::String::new(scope, reference, v8::NewStringType::Normal).unwrap();
v8::reference_error(local); v8::range_error(scope, local);
v8::syntax_error(local); v8::reference_error(scope, local);
v8::type_error(local); v8::syntax_error(scope, local);
let exception = v8::error(local); v8::type_error(scope, local);
let msg = v8::create_message(&isolate, exception); let exception = v8::error(scope, local);
let msg_string = msg.get(); let msg = v8::create_message(scope, exception);
let rust_msg_string = msg_string.to_rust_string_lossy(&isolate); let msg_string = msg.get(scope);
let rust_msg_string = msg_string.to_rust_string_lossy(scope);
assert_eq!( assert_eq!(
"Uncaught Error: This is a test error".to_string(), "Uncaught Error: This is a test error".to_string(),
rust_msg_string rust_msg_string
); );
assert!(v8::get_stack_trace(exception).is_none()); assert!(v8::get_stack_trace(scope, exception).is_none());
context.exit(); context.exit();
}); });
drop(locker); drop(locker);
@ -335,17 +347,17 @@ fn json() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_s| { v8::HandleScope::enter(&isolate, |s| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(s);
context.enter(); context.enter();
let json_string = v8_str(&isolate, "{\"a\": 1, \"b\": 2}"); let json_string = v8_str(s, "{\"a\": 1, \"b\": 2}");
let maybe_value = v8::json::parse(context, json_string); let maybe_value = v8::json::parse(context, json_string);
assert!(maybe_value.is_some()); assert!(maybe_value.is_some());
let value = maybe_value.unwrap(); let value = maybe_value.unwrap();
let maybe_stringified = v8::json::stringify(context, value); let maybe_stringified = v8::json::stringify(context, value);
assert!(maybe_stringified.is_some()); assert!(maybe_stringified.is_some());
let stringified = maybe_stringified.unwrap(); let stringified = maybe_stringified.unwrap();
let rust_str = stringified.to_rust_string_lossy(&isolate); let rust_str = stringified.to_rust_string_lossy(s);
assert_eq!("{\"a\":1,\"b\":2}".to_string(), rust_str); assert_eq!("{\"a\":1,\"b\":2}".to_string(), rust_str);
context.exit(); context.exit();
}); });
@ -367,19 +379,19 @@ fn object() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let null: v8::Local<v8::Value> = new_null(&isolate).into(); let null: v8::Local<v8::Value> = new_null(scope).into();
let s1 = v8_str(&isolate, "a"); let s1 = v8::String::new(scope, "a", v8::NewStringType::Normal).unwrap();
let s2 = v8_str(&isolate, "b"); let s2 = v8::String::new(scope, "b", v8::NewStringType::Normal).unwrap();
let name1: Local<v8::Name> = cast(s1); let name1: Local<v8::Name> = cast(s1);
let name2: Local<v8::Name> = cast(s2); let name2: Local<v8::Name> = cast(s2);
let names = vec![name1, name2]; let names = vec![name1, name2];
let v1: v8::Local<v8::Value> = v8::Number::new(&isolate, 1.0).into(); let v1: v8::Local<v8::Value> = v8::Number::new(scope, 1.0).into();
let v2: v8::Local<v8::Value> = v8::Number::new(&isolate, 2.0).into(); let v2: v8::Local<v8::Value> = v8::Number::new(scope, 2.0).into();
let values = vec![v1, v2]; let values = vec![v1, v2];
let object = v8::Object::new(&isolate, null, names, values, 2); let object = v8::Object::new(scope, null, names, values, 2);
assert!(!object.is_null_or_undefined()); assert!(!object.is_null_or_undefined());
context.exit(); context.exit();
}); });
@ -395,36 +407,32 @@ fn promise_resolved() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let maybe_resolver = v8::PromiseResolver::new(context); let maybe_resolver = v8::PromiseResolver::new(scope, context);
assert!(maybe_resolver.is_some()); assert!(maybe_resolver.is_some());
let mut resolver = maybe_resolver.unwrap(); let mut resolver = maybe_resolver.unwrap();
let mut promise = resolver.get_promise(); let mut promise = resolver.get_promise(scope);
assert!(!promise.has_handler()); assert!(!promise.has_handler());
assert_eq!(promise.state(), v8::PromiseState::Pending); assert_eq!(promise.state(), v8::PromiseState::Pending);
let str = v8_str(&isolate, "test"); let str =
v8::String::new(scope, "test", v8::NewStringType::Normal).unwrap();
let value: Local<v8::Value> = cast(str); let value: Local<v8::Value> = cast(str);
resolver.resolve(context, value); resolver.resolve(context, value);
assert_eq!(promise.state(), v8::PromiseState::Fulfilled); assert_eq!(promise.state(), v8::PromiseState::Fulfilled);
let result = promise.result(); let result = promise.result(scope);
let result_str: v8::Local<v8::String> = cast(result); let result_str: v8::Local<v8::String> = cast(result);
assert_eq!( assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
result_str.to_rust_string_lossy(&isolate),
"test".to_string()
);
// Resolve again with different value, since promise is already in `Fulfilled` state // Resolve again with different value, since promise is already in `Fulfilled` state
// it should be ignored. // it should be ignored.
let str = v8_str(&isolate, "test2"); let str =
v8::String::new(scope, "test2", v8::NewStringType::Normal).unwrap();
let value: Local<v8::Value> = cast(str); let value: Local<v8::Value> = cast(str);
resolver.resolve(context, value); resolver.resolve(context, value);
let result = promise.result(); let result = promise.result(scope);
let result_str: v8::Local<v8::String> = cast(result); let result_str: v8::Local<v8::String> = cast(result);
assert_eq!( assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
result_str.to_rust_string_lossy(&isolate),
"test".to_string()
);
context.exit(); context.exit();
}); });
drop(locker); drop(locker);
@ -439,37 +447,33 @@ fn promise_rejected() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let maybe_resolver = v8::PromiseResolver::new(context); let maybe_resolver = v8::PromiseResolver::new(scope, context);
assert!(maybe_resolver.is_some()); assert!(maybe_resolver.is_some());
let mut resolver = maybe_resolver.unwrap(); let mut resolver = maybe_resolver.unwrap();
let mut promise = resolver.get_promise(); let mut promise = resolver.get_promise(scope);
assert!(!promise.has_handler()); assert!(!promise.has_handler());
assert_eq!(promise.state(), v8::PromiseState::Pending); assert_eq!(promise.state(), v8::PromiseState::Pending);
let str = v8_str(&isolate, "test"); let str =
v8::String::new(scope, "test", v8::NewStringType::Normal).unwrap();
let value: Local<v8::Value> = cast(str); let value: Local<v8::Value> = cast(str);
let rejected = resolver.reject(context, value); let rejected = resolver.reject(context, value);
assert!(rejected.unwrap()); assert!(rejected.unwrap());
assert_eq!(promise.state(), v8::PromiseState::Rejected); assert_eq!(promise.state(), v8::PromiseState::Rejected);
let result = promise.result(); let result = promise.result(scope);
let result_str: v8::Local<v8::String> = cast(result); let result_str: v8::Local<v8::String> = cast(result);
assert_eq!( assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
result_str.to_rust_string_lossy(&isolate),
"test".to_string()
);
// Reject again with different value, since promise is already in `Rejected` state // Reject again with different value, since promise is already in `Rejected` state
// it should be ignored. // it should be ignored.
let str = v8_str(&isolate, "test2"); let str =
v8::String::new(scope, "test2", v8::NewStringType::Normal).unwrap();
let value: Local<v8::Value> = cast(str); let value: Local<v8::Value> = cast(str);
resolver.reject(context, value); resolver.reject(context, value);
let result = promise.result(); let result = promise.result(scope);
let result_str: v8::Local<v8::String> = cast(result); let result_str: v8::Local<v8::String> = cast(result);
assert_eq!( assert_eq!(result_str.to_rust_string_lossy(scope), "test".to_string());
result_str.to_rust_string_lossy(&isolate),
"test".to_string()
);
context.exit(); context.exit();
}); });
drop(locker); drop(locker);
@ -478,16 +482,15 @@ fn promise_rejected() {
extern "C" fn fn_callback(info: &FunctionCallbackInfo) { extern "C" fn fn_callback(info: &FunctionCallbackInfo) {
assert_eq!(info.length(), 0); assert_eq!(info.length(), 0);
let isolate = info.get_isolate(); let isolate = info.get_isolate();
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let s =
context.enter(); v8::String::new(scope, "Hello callback!", v8::NewStringType::Normal)
let s = v8_str(&isolate, "Hello callback!"); .unwrap();
let value: Local<v8::Value> = s.into(); let value: Local<v8::Value> = s.into();
let rv = &mut info.get_return_value(); let rv = &mut info.get_return_value();
let rv_value = rv.get(); let rv_value = rv.get(scope);
assert!(rv_value.is_undefined()); assert!(rv_value.is_undefined());
rv.set(value); rv.set(value);
context.exit();
}); });
} }
@ -500,25 +503,26 @@ fn function() {
); );
let isolate = v8::Isolate::new(params); let isolate = v8::Isolate::new(params);
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let global = context.global(); let global = context.global();
let recv: Local<v8::Value> = global.into(); let recv: Local<v8::Value> = global.into();
// create function using template // create function using template
let mut fn_template = v8::FunctionTemplate::new(&isolate, fn_callback); let mut fn_template = v8::FunctionTemplate::new(scope, fn_callback);
let mut function = fn_template let mut function = fn_template
.get_function(context) .get_function(scope, context)
.expect("Unable to create function"); .expect("Unable to create function");
let _value = v8::Function::call(&mut *function, context, recv, 0, vec![]); let _value =
v8::Function::call(&mut *function, scope, context, recv, 0, vec![]);
// create function without a template // create function without a template
let mut function = v8::Function::new(context, fn_callback) let mut function = v8::Function::new(scope, context, fn_callback)
.expect("Unable to create function"); .expect("Unable to create function");
let maybe_value = let maybe_value =
v8::Function::call(&mut *function, context, recv, 0, vec![]); v8::Function::call(&mut *function, scope, context, recv, 0, vec![]);
let value = maybe_value.unwrap(); let value = maybe_value.unwrap();
let value_str: v8::Local<v8::String> = cast(value); let value_str: v8::Local<v8::String> = cast(value);
let rust_str = value_str.to_rust_string_lossy(&isolate); let rust_str = value_str.to_rust_string_lossy(scope);
assert_eq!(rust_str, "Hello callback!".to_string()); assert_eq!(rust_str, "Hello callback!".to_string());
context.exit(); context.exit();
}); });
@ -534,9 +538,9 @@ extern "C" fn promise_reject_callback(msg: v8::PromiseRejectMessage) {
let isolate = promise_obj.get_isolate(); let isolate = promise_obj.get_isolate();
let value = msg.get_value(); let value = msg.get_value();
let locker = v8::Locker::new(isolate); let locker = v8::Locker::new(isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let value_str: v8::Local<v8::String> = cast(value); let value_str: v8::Local<v8::String> = cast(value);
let rust_str = value_str.to_rust_string_lossy(&isolate); let rust_str = value_str.to_rust_string_lossy(scope);
assert_eq!(rust_str, "promise rejected".to_string()); assert_eq!(rust_str, "promise rejected".to_string());
}); });
drop(locker); drop(locker);
@ -553,11 +557,13 @@ fn set_promise_reject_callback() {
isolate.set_promise_reject_callback(promise_reject_callback); isolate.set_promise_reject_callback(promise_reject_callback);
isolate.enter(); isolate.enter();
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let mut resolver = v8::PromiseResolver::new(context).unwrap(); let mut resolver = v8::PromiseResolver::new(scope, context).unwrap();
let str_ = v8_str(&isolate, "promise rejected"); let str_ =
v8::String::new(scope, "promise rejected", v8::NewStringType::Normal)
.unwrap();
let value: Local<v8::Value> = cast(str_); let value: Local<v8::Value> = cast(str_);
resolver.reject(context, value); resolver.reject(context, value);
context.exit(); context.exit();
@ -566,16 +572,18 @@ fn set_promise_reject_callback() {
isolate.exit(); isolate.exit();
} }
fn mock_script_origin(isolate: &v8::Isolate) -> v8::ScriptOrigin { fn mock_script_origin<'sc>(
let resource_name = v8_str(&isolate, "foo.js"); scope: &mut HandleScope<'sc>,
let resource_line_offset = v8::Integer::new(&isolate, 4); ) -> v8::ScriptOrigin<'sc> {
let resource_column_offset = v8::Integer::new(&isolate, 5); let resource_name = v8_str(scope, "foo.js");
let resource_is_shared_cross_origin = v8::new_true(&isolate); let resource_line_offset = v8::Integer::new(scope, 4);
let script_id = v8::Integer::new(&isolate, 123); let resource_column_offset = v8::Integer::new(scope, 5);
let source_map_url = v8_str(&isolate, "source_map_url"); let resource_is_shared_cross_origin = v8::new_true(scope);
let resource_is_opaque = v8::new_true(&isolate); let script_id = v8::Integer::new(scope, 123);
let is_wasm = v8::new_false(&isolate); let source_map_url = v8_str(scope, "source_map_url");
let is_module = v8::new_true(&isolate); 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( v8::ScriptOrigin::new(
resource_name.into(), resource_name.into(),
resource_line_offset, resource_line_offset,
@ -600,16 +608,14 @@ fn script_compiler_source() {
isolate.set_promise_reject_callback(promise_reject_callback); isolate.set_promise_reject_callback(promise_reject_callback);
isolate.enter(); isolate.enter();
let locker = v8::Locker::new(&isolate); let locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&isolate, |_scope| { v8::HandleScope::enter(&isolate, |scope| {
let mut context = v8::Context::new(&isolate); let mut context = v8::Context::new(scope);
context.enter(); context.enter();
let source = "1+2"; let source = "1+2";
let script_origin = mock_script_origin(&isolate); let script_origin = mock_script_origin(scope);
let source = v8::script_compiler::Source::new( let source =
v8_str(&isolate, source), v8::script_compiler::Source::new(v8_str(scope, source), &script_origin);
&script_origin,
);
let result = v8::script_compiler::compile_module( let result = v8::script_compiler::compile_module(
&isolate, &isolate,