diff --git a/Cargo.toml b/Cargo.toml index 80eecc39aa..713a05b720 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,11 +101,14 @@ opt-level = 1 default = ["use_custom_libcxx"] use_custom_libcxx = [] v8_enable_pointer_compression = [] +v8_enable_v8_checks = [] [dependencies] bitflags = "2.5" paste = "1.0" -temporal_capi = { package = "ry_temporal_capi", version = "=0.0.11-ry.1", features = [ "compiled_data" ] } +temporal_capi = { package = "ry_temporal_capi", version = "=0.0.11-ry.1", features = [ + "compiled_data", +] } [build-dependencies] miniz_oxide = "0.8.8" diff --git a/benches/function.rs b/benches/function.rs index 8983e8f20e..9fc81214e9 100644 --- a/benches/function.rs +++ b/benches/function.rs @@ -10,14 +10,14 @@ fn main() { v8::V8::initialize_platform(platform); v8::V8::initialize(); let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let handle_scope, isolate); let context = v8::Context::new(handle_scope, Default::default()); let scope = &mut v8::ContextScope::new(handle_scope, context); let global = context.global(scope); { let func = v8::Function::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { rv.set(v8::Integer::new(scope, 42).into()); @@ -30,7 +30,8 @@ fn main() { { extern "C" fn callback(info: *const v8::FunctionCallbackInfo) { let info = unsafe { &*info }; - let scope = unsafe { &mut v8::CallbackScope::new(info) }; + let scope = std::pin::pin!(unsafe { v8::CallbackScope::new(info) }); + let scope = &scope.init(); let mut rv = v8::ReturnValue::from_function_callback_info(info); rv.set(v8::Integer::new(scope, 42).into()); } @@ -51,7 +52,7 @@ fn main() { { let func = v8::Function::new( scope, - |_: &mut v8::HandleScope, + |_: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { rv.set_uint32(42); @@ -74,7 +75,7 @@ fn main() { ), ); let template = v8::FunctionTemplate::builder( - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { rv.set(v8::Integer::new(scope, 42).into()); @@ -90,7 +91,8 @@ fn main() { { extern "C" fn callback(info: *const v8::FunctionCallbackInfo) { let info = unsafe { &*info }; - let scope = unsafe { &mut v8::CallbackScope::new(info) }; + let scope = std::pin::pin!(unsafe { v8::CallbackScope::new(info) }); + let scope = &scope.init(); let mut rv = v8::ReturnValue::from_function_callback_info(info); rv.set(v8::undefined(scope).into()); } @@ -156,10 +158,11 @@ fn main() { } fn eval<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, code: &str, ) -> Option> { - let scope = &mut v8::EscapableHandleScope::new(scope); + v8::escapable_handle_scope!(let scope, scope); + let source = v8::String::new(scope, code).unwrap(); let script = v8::Script::compile(scope, source, None).unwrap(); let r = script.run(scope); diff --git a/build.rs b/build.rs index bb55f8ee58..7e9a65afdc 100644 --- a/build.rs +++ b/build.rs @@ -213,6 +213,10 @@ fn build_v8(is_asan: bool) { "v8_enable_pointer_compression={}", env::var("CARGO_FEATURE_V8_ENABLE_POINTER_COMPRESSION").is_ok() )); + gn_args.push(format!( + "v8_enable_v8_checks={}", + env::var("CARGO_FEATURE_V8_ENABLE_V8_CHECKS").is_ok() + )); // Fix GN's host_cpu detection when using x86_64 bins on Apple Silicon if cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") { gn_args.push("host_cpu=\"arm64\"".to_string()); diff --git a/examples/cppgc-object.rs b/examples/cppgc-object.rs index fc0fdd462c..33b10ebd95 100644 --- a/examples/cppgc-object.rs +++ b/examples/cppgc-object.rs @@ -30,10 +30,10 @@ const TAG: u16 = 1; fn main() { let platform = v8::new_default_platform(0, false).make_shared(); v8::V8::set_flags_from_string("--no_freeze_flags_after_init --expose-gc"); - v8::V8::initialize_platform(platform.clone()); - v8::V8::initialize(); + v8::V8::initialize_platform(platform.clone()); v8::cppgc::initialize_process(platform.clone()); + v8::V8::initialize(); { let heap = @@ -41,20 +41,20 @@ fn main() { let isolate = &mut v8::Isolate::new(v8::CreateParams::default().cpp_heap(heap)); - let handle_scope = &mut v8::HandleScope::new(isolate); + v8::scope!(handle_scope, isolate); let context = v8::Context::new(handle_scope, Default::default()); let scope = &mut v8::ContextScope::new(handle_scope, context); let global = context.global(scope); { let func = v8::Function::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope<'_, '_>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { let id = args.get(0).to_rust_string_lossy(scope); fn empty( - _scope: &mut v8::HandleScope, + _scope: &mut v8::PinScope<'_, '_>, _args: v8::FunctionCallbackArguments, _rv: v8::ReturnValue, ) { @@ -113,8 +113,8 @@ fn execute_script( context_scope: &mut v8::ContextScope, script: v8::Local, ) { - let scope = &mut v8::HandleScope::new(context_scope); - let try_catch = &mut v8::TryCatch::new(scope); + v8::scope!(handle_scope, context_scope); + v8::tc_scope!(let try_catch, handle_scope); let script = v8::Script::compile(try_catch, script, None) .expect("failed to compile script"); diff --git a/examples/cppgc.rs b/examples/cppgc.rs index cd8bb0b1db..7d9415ed71 100644 --- a/examples/cppgc.rs +++ b/examples/cppgc.rs @@ -52,8 +52,8 @@ impl Drop for Rope { fn main() { let platform = v8::new_default_platform(0, false).make_shared(); v8::V8::initialize_platform(platform.clone()); - v8::V8::initialize(); v8::cppgc::initialize_process(platform.clone()); + v8::V8::initialize(); { // Create a managed heap. diff --git a/examples/hello_world.rs b/examples/hello_world.rs index ba37517e85..0fae97c6a7 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -9,14 +9,13 @@ fn main() { let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); // Create a stack-allocated handle scope. - let handle_scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let handle_scope, isolate); // Create a new context. let context = v8::Context::new(handle_scope, Default::default()); // Enter the context for compiling and running the hello world script. - let scope = &mut v8::ContextScope::new(handle_scope, context); - + let scope = &v8::ContextScope::new(handle_scope, context); // Create a string containing the JavaScript source code. let code = v8::String::new(scope, "'Hello' + ' World!'").unwrap(); diff --git a/examples/process.rs b/examples/process.rs index 9fbb655e59..38ab1f4114 100644 --- a/examples/process.rs +++ b/examples/process.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; #[allow(clippy::needless_pass_by_value)] // this function should follow the callback type fn log_callback( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut _retval: v8::ReturnValue, ) { @@ -29,13 +29,13 @@ fn main() { } let mut isolate = v8::Isolate::new(v8::CreateParams::default()); - let mut scope = v8::HandleScope::new(&mut isolate); + v8::scope!(let scope, &mut isolate); let source = std::fs::read_to_string(&file) .unwrap_or_else(|err| panic!("failed to open {file}: {err}")); - let source = v8::String::new(&mut scope, &source).unwrap(); + let source = v8::String::new(scope, &source).unwrap(); - let mut processor = JsHttpRequestProcessor::new(&mut scope, source, options); + let mut processor = JsHttpRequestProcessor::new(scope, source, options); let requests = vec![ StringHttpRequest::new("/process.cc", "localhost", "google.com", "firefox"), @@ -124,22 +124,19 @@ impl HttpRequest for StringHttpRequest { } /// An http request processor that is scriptable using JavaScript. -struct JsHttpRequestProcessor<'s, 'i> { - context: v8::Local<'s, v8::Context>, - context_scope: v8::ContextScope<'i, v8::HandleScope<'s>>, - process_fn: Option>, +struct JsHttpRequestProcessor<'scope, 'obj, 'isolate> { + context: v8::Local<'obj, v8::Context>, + context_scope: v8::ContextScope<'scope, 'obj, v8::HandleScope<'isolate>>, + process_fn: Option>, request_template: v8::Global, _map_template: Option>, } -impl<'s, 'i> JsHttpRequestProcessor<'s, 'i> -where - 's: 'i, -{ +impl<'scope, 'obj, 'isolate> JsHttpRequestProcessor<'scope, 'obj, 'isolate> { /// Creates a scriptable HTTP request processor. pub fn new( - isolate_scope: &'i mut v8::HandleScope<'s, ()>, - source: v8::Local<'s, v8::String>, + isolate_scope: &'scope mut v8::PinScope<'obj, 'isolate, ()>, + source: v8::Local<'obj, v8::String>, options: HashMap, ) -> Self { let global = v8::ObjectTemplate::new(isolate_scope); @@ -155,14 +152,13 @@ where ..Default::default() }, ); - let mut context_scope = v8::ContextScope::new(isolate_scope, context); + let context_scope = v8::ContextScope::new(isolate_scope, context); - let request_template = v8::ObjectTemplate::new(&mut context_scope); + let request_template = v8::ObjectTemplate::new(&context_scope); request_template.set_internal_field_count(1); // make it global - let request_template = - v8::Global::new(&mut context_scope, request_template); + let request_template = v8::Global::new(&context_scope, request_template); let mut self_ = JsHttpRequestProcessor { context, @@ -174,19 +170,17 @@ where // loads options and output let options = self_.wrap_map(options); - let options_str = - v8::String::new(&mut self_.context_scope, "options").unwrap(); - self_.context.global(&mut self_.context_scope).set( - &mut self_.context_scope, + let options_str = v8::String::new(&self_.context_scope, "options").unwrap(); + self_.context.global(&self_.context_scope).set( + &self_.context_scope, options_str.into(), options.into(), ); - let output = v8::Object::new(&mut self_.context_scope); - let output_str = - v8::String::new(&mut self_.context_scope, "output").unwrap(); - self_.context.global(&mut self_.context_scope).set( - &mut self_.context_scope, + let output = v8::Object::new(&self_.context_scope); + let output_str = v8::String::new(&self_.context_scope, "output").unwrap(); + self_.context.global(&self_.context_scope).set( + &self_.context_scope, output_str.into(), output.into(), ); @@ -194,12 +188,11 @@ where // execute script self_.execute_script(source); - let process_str = - v8::String::new(&mut self_.context_scope, "Process").unwrap(); + let process_str = v8::String::new(&self_.context_scope, "Process").unwrap(); let process_fn = self_ .context - .global(&mut self_.context_scope) - .get(&mut self_.context_scope, process_str.into()) + .global(&self_.context_scope) + .get(&self_.context_scope, process_str.into()) .expect("missing function Process"); let process_fn = v8::Local::::try_from(process_fn) @@ -209,9 +202,10 @@ where self_ } - fn execute_script(&mut self, script: v8::Local<'s, v8::String>) { - let scope = &mut v8::HandleScope::new(&mut self.context_scope); - let try_catch = &mut v8::TryCatch::new(scope); + fn execute_script(&mut self, script: v8::Local<'scope, v8::String>) { + v8::scope!(let scope, &mut self.context_scope); + + v8::tc_scope!(let try_catch, scope); let script = v8::Script::compile(try_catch, script, None) .expect("failed to compile script"); @@ -235,8 +229,9 @@ where let request: Box = Box::new(request); let request = self.wrap_request(request); - let scope = &mut v8::HandleScope::new(&mut self.context_scope); - let try_catch = &mut v8::TryCatch::new(scope); + v8::scope!(let scope, &mut self.context_scope); + + v8::tc_scope!(let try_catch, scope); let process_fn = self.process_fn.as_mut().unwrap(); let global = self.context.global(try_catch).into(); @@ -259,7 +254,7 @@ where fn wrap_request( &mut self, request: Box, - ) -> v8::Local<'s, v8::Object> { + ) -> v8::Local<'scope, v8::Object> { // TODO: fix memory leak use std::ffi::c_void; @@ -295,7 +290,7 @@ where /// This handles the properties of `HttpRequest` #[allow(clippy::needless_pass_by_value)] // this function should follow the callback type fn request_prop_handler( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue, @@ -327,7 +322,7 @@ where /// Utility function that extracts the http request object from a wrapper object. fn unwrap_request( - scope: &mut v8::HandleScope, + scope: &v8::PinScope, request: v8::Local, ) -> *mut Box { let external = request @@ -340,9 +335,9 @@ where fn wrap_map( &mut self, options: HashMap, - ) -> v8::Local<'s, v8::Object> { + ) -> v8::Local<'scope, v8::Object> { // TODO: wrap map, not convert into Object - let scope = &mut self.context_scope; + let scope = &self.context_scope; let result = v8::Object::new(scope); for (key, value) in options { @@ -356,7 +351,9 @@ where /// Prints the output. pub fn print_output(&mut self) { - let scope = &mut v8::HandleScope::new(&mut self.context_scope); + let scope: std::pin::Pin<&mut v8::ScopeStorage>> = + std::pin::pin!(v8::HandleScope::new(&mut self.context_scope)); + let scope = &scope.init(); let key = v8::String::new(scope, "output").unwrap(); let output = self .context diff --git a/examples/shell.rs b/examples/shell.rs index 6cda6c574e..9b069ca148 100644 --- a/examples/shell.rs +++ b/examples/shell.rs @@ -10,22 +10,21 @@ fn main() { let mut run_shell_flag = args.len() == 1; let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); - let handle_scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let handle_scope, isolate); let context = v8::Context::new(handle_scope, Default::default()); - let context_scope = &mut v8::ContextScope::new(handle_scope, context); - let scope = &mut v8::HandleScope::new(context_scope); + let mut scope = v8::ContextScope::new(handle_scope, context); - run_main(scope, &args, &mut run_shell_flag); + run_main(&mut scope, &args, &mut run_shell_flag); if run_shell_flag { - run_shell(scope); + run_shell(&mut scope); } } /// Process remaining command line arguments and execute files -fn run_shell(scope: &mut v8::HandleScope) { +fn run_shell(scope: &mut v8::PinScope) { use std::io::{self, Write}; println!("V8 version {} [sample shell]", v8::V8::get_version()); @@ -50,11 +49,7 @@ fn run_shell(scope: &mut v8::HandleScope) { } /// Process remaining command line arguments and execute files -fn run_main( - scope: &mut v8::HandleScope, - args: &[String], - run_shell: &mut bool, -) { +fn run_main(scope: &mut v8::PinScope, args: &[String], run_shell: &mut bool) { let mut skip_next = false; // Parse command-line arguments. @@ -110,18 +105,18 @@ fn run_main( } fn execute_string( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, script: &str, filename: &str, print_result: bool, report_exceptions_flag: bool, ) { - let mut scope = v8::TryCatch::new(scope); + v8::tc_scope!(let tc, scope); - let filename = v8::String::new(&mut scope, filename).unwrap(); - let script = v8::String::new(&mut scope, script).unwrap(); + let filename = v8::String::new(tc, filename).unwrap(); + let script = v8::String::new(tc, script).unwrap(); let origin = v8::ScriptOrigin::new( - &mut scope, + tc, filename.into(), 0, 0, @@ -134,43 +129,38 @@ fn execute_string( None, ); - let script = if let Some(script) = - v8::Script::compile(&mut scope, script, Some(&origin)) - { - script - } else { - assert!(scope.has_caught()); + let script = + if let Some(script) = v8::Script::compile(tc, script, Some(&origin)) { + script + } else { + assert!(tc.has_caught()); - if report_exceptions_flag { - report_exceptions(scope); - } - return; - }; + if report_exceptions_flag { + report_exceptions(tc); + } + return; + }; - if let Some(result) = script.run(&mut scope) { + if let Some(result) = script.run(tc) { if print_result { - println!( - "{}", - result - .to_string(&mut scope) - .unwrap() - .to_rust_string_lossy(&mut scope) - ); + println!("{}", result.to_string(tc).unwrap().to_rust_string_lossy(tc)); } } else { - assert!(scope.has_caught()); + assert!(tc.has_caught()); if report_exceptions_flag { - report_exceptions(scope); + report_exceptions(tc); } } } -fn report_exceptions(mut try_catch: v8::TryCatch) { +fn report_exceptions( + try_catch: &mut v8::PinnedRef<'_, v8::TryCatch>, +) { let exception = try_catch.exception().unwrap(); let exception_string = exception - .to_string(&mut try_catch) + .to_string(try_catch) .unwrap() - .to_rust_string_lossy(&mut try_catch); + .to_rust_string_lossy(try_catch); let message = if let Some(message) = try_catch.message() { message } else { @@ -179,27 +169,25 @@ fn report_exceptions(mut try_catch: v8::TryCatch) { }; // Print (filename):(line number): (message). - let filename = message - .get_script_resource_name(&mut try_catch) - .map_or_else( - || "(unknown)".into(), - |s| { - s.to_string(&mut try_catch) - .unwrap() - .to_rust_string_lossy(&mut try_catch) - }, - ); - let line_number = message.get_line_number(&mut try_catch).unwrap_or_default(); + let filename = message.get_script_resource_name(try_catch).map_or_else( + || "(unknown)".into(), + |s| { + s.to_string(try_catch) + .unwrap() + .to_rust_string_lossy(try_catch) + }, + ); + let line_number = message.get_line_number(try_catch).unwrap_or_default(); eprintln!("{filename}:{line_number}: {exception_string}"); // Print line of source code. let source_line = message - .get_source_line(&mut try_catch) + .get_source_line(try_catch) .map(|s| { - s.to_string(&mut try_catch) + s.to_string(try_catch) .unwrap() - .to_rust_string_lossy(&mut try_catch) + .to_rust_string_lossy(try_catch) }) .unwrap(); eprintln!("{source_line}"); @@ -227,8 +215,8 @@ fn report_exceptions(mut try_catch: v8::TryCatch) { let stack_trace = unsafe { v8::Local::::cast_unchecked(stack_trace) }; let stack_trace = stack_trace - .to_string(&mut try_catch) - .map(|s| s.to_rust_string_lossy(&mut try_catch)); + .to_string(try_catch) + .map(|s| s.to_rust_string_lossy(try_catch)); if let Some(stack_trace) = stack_trace { eprintln!("{stack_trace}"); diff --git a/src/array_buffer.rs b/src/array_buffer.rs index 898f917926..4c9f849b22 100644 --- a/src/array_buffer.rs +++ b/src/array_buffer.rs @@ -9,10 +9,11 @@ use std::slice; use crate::ArrayBuffer; use crate::DataView; -use crate::HandleScope; use crate::Isolate; use crate::Local; use crate::Value; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::MaybeBool; use crate::support::Opaque; use crate::support::Shared; @@ -30,11 +31,11 @@ unsafe extern "C" { ) -> *mut Allocator; fn v8__ArrayBuffer__Allocator__DELETE(this: *mut Allocator); fn v8__ArrayBuffer__New__with_byte_length( - isolate: *mut Isolate, + isolate: *mut RealIsolate, byte_length: usize, ) -> *const ArrayBuffer; fn v8__ArrayBuffer__New__with_backing_store( - isolate: *mut Isolate, + isolate: *mut RealIsolate, backing_store: *const SharedRef, ) -> *const ArrayBuffer; fn v8__ArrayBuffer__Detach( @@ -50,7 +51,7 @@ unsafe extern "C" { this: *const ArrayBuffer, ) -> SharedRef; fn v8__ArrayBuffer__NewBackingStore__with_byte_length( - isolate: *mut Isolate, + isolate: *mut RealIsolate, byte_length: usize, ) -> *mut BackingStore; fn v8__ArrayBuffer__NewBackingStore__with_data( @@ -426,7 +427,7 @@ impl ArrayBuffer { /// unless the object is externalized. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, byte_length: usize, ) -> Local<'s, ArrayBuffer> { unsafe { @@ -442,7 +443,7 @@ impl ArrayBuffer { #[inline(always)] pub fn with_backing_store<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, backing_store: &SharedRef, ) -> Local<'s, ArrayBuffer> { unsafe { @@ -532,7 +533,7 @@ impl ArrayBuffer { ) -> UniqueRef { unsafe { UniqueRef::from_raw(v8__ArrayBuffer__NewBackingStore__with_byte_length( - scope, + (*scope).as_real_ptr(), byte_length, )) } @@ -639,7 +640,7 @@ impl DataView { /// Returns a new DataView. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, arraybuffer: Local<'s, ArrayBuffer>, byte_offset: usize, length: usize, diff --git a/src/array_buffer_view.rs b/src/array_buffer_view.rs index a21745194c..9d4e928c98 100644 --- a/src/array_buffer_view.rs +++ b/src/array_buffer_view.rs @@ -1,10 +1,10 @@ use crate::ArrayBuffer; use crate::ArrayBufferView; use crate::BackingStore; -use crate::HandleScope; use crate::Local; use crate::SharedRef; use crate::binding::memory_span_t; +use crate::scope::PinScope; use crate::support::int; use std::convert::TryInto; use std::ffi::c_void; @@ -35,7 +35,7 @@ impl ArrayBufferView { #[inline(always)] pub fn buffer<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, ) -> Option> { unsafe { scope.cast_local(|_| v8__ArrayBufferView__Buffer(self)) } } diff --git a/src/bigint.rs b/src/bigint.rs index 9cc959c9ba..306383d7cb 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -1,16 +1,16 @@ use crate::BigInt; use crate::Context; -use crate::HandleScope; -use crate::Isolate; use crate::Local; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::int; use std::mem::MaybeUninit; unsafe extern "C" { - fn v8__BigInt__New(isolate: *mut Isolate, value: i64) -> *const BigInt; + fn v8__BigInt__New(isolate: *mut RealIsolate, value: i64) -> *const BigInt; fn v8__BigInt__NewFromUnsigned( - isolate: *mut Isolate, + isolate: *mut RealIsolate, value: u64, ) -> *const BigInt; fn v8__BigInt__NewFromWords( @@ -33,7 +33,7 @@ unsafe extern "C" { impl BigInt { #[inline(always)] pub fn new_from_i64<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, value: i64, ) -> Local<'s, BigInt> { unsafe { @@ -44,7 +44,7 @@ impl BigInt { #[inline(always)] pub fn new_from_u64<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, value: u64, ) -> Local<'s, BigInt> { unsafe { @@ -62,7 +62,7 @@ impl BigInt { /// (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...) #[inline(always)] pub fn new_from_words<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_, ()>, sign_bit: bool, words: &[u64], ) -> Option> { diff --git a/src/binding.cc b/src/binding.cc index 6b708f38fe..eb6e8aaddc 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -33,14 +33,21 @@ constexpr size_t align_to(size_t size) { return (size + sizeof(T) - 1) & ~(sizeof(T) - 1); } +#ifdef V8_ENABLE_CHECKS +constexpr size_t handle_scope_size = 4; +#else +constexpr size_t handle_scope_size = 3; +#endif + static_assert(sizeof(two_pointers_t) == sizeof(std::shared_ptr), "std::shared_ptr size mismatch"); -static_assert(sizeof(v8::HandleScope) == sizeof(size_t) * 3, +static_assert(sizeof(v8::HandleScope) == sizeof(size_t) * handle_scope_size, "HandleScope size mismatch"); -static_assert(sizeof(v8::EscapableHandleScope) == sizeof(size_t) * 4, +static_assert(sizeof(v8::EscapableHandleScope) == + sizeof(size_t) * (handle_scope_size + 1), "EscapableHandleScope size mismatch"); static_assert(sizeof(v8::PromiseRejectMessage) == sizeof(size_t) * 3, diff --git a/src/context.rs b/src/context.rs index 17cd4b3595..482ef35527 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,7 @@ +use crate::isolate::RealIsolate; +use crate::scope::PinScope; // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. use crate::Context; -use crate::HandleScope; use crate::Local; use crate::MicrotaskQueue; use crate::Object; @@ -9,7 +10,6 @@ use crate::Value; use crate::Weak; use crate::handle::UnsafeRefHandle; use crate::isolate::BuildTypeIdHasher; -use crate::isolate::Isolate; use crate::isolate::RawSlot; use crate::support::int; use std::any::TypeId; @@ -20,12 +20,12 @@ use std::rc::Rc; unsafe extern "C" { fn v8__Context__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, templ: *const ObjectTemplate, global_object: *const Value, microtask_queue: *mut MicrotaskQueue, ) -> *const Context; - fn v8__Context__GetIsolate(this: *const Context) -> *mut Isolate; + fn v8__Context__GetIsolate(this: *const Context) -> *mut RealIsolate; fn v8__Context__Global(this: *const Context) -> *const Object; fn v8__Context__GetExtrasBindingObject(this: *const Context) -> *const Object; @@ -49,7 +49,7 @@ unsafe extern "C" { value: *const Value, ); fn v8__Context__FromSnapshot( - isolate: *mut Isolate, + isolate: *mut RealIsolate, context_snapshot_index: usize, global_object: *const Value, microtask_queue: *mut MicrotaskQueue, @@ -100,7 +100,7 @@ impl Context { /// Creates a new context. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, options: ContextOptions, ) -> Local<'s, Context> { unsafe { @@ -121,7 +121,7 @@ impl Context { #[inline(always)] pub fn get_extras_binding_object<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, ) -> Local<'s, Object> { unsafe { scope.cast_local(|_| v8__Context__GetExtrasBindingObject(self)) } .unwrap() @@ -138,10 +138,7 @@ impl Context { /// would break VM---v8 expects only global object as a prototype of global /// proxy object. #[inline(always)] - pub fn global<'s>( - &self, - scope: &mut HandleScope<'s, ()>, - ) -> Local<'s, Object> { + pub fn global<'s>(&self, scope: &PinScope<'s, '_, ()>) -> Local<'s, Object> { unsafe { scope.cast_local(|_| v8__Context__Global(self)) }.unwrap() } @@ -162,7 +159,8 @@ impl Context { &self, create_if_not_present: bool, ) -> Option<&mut ContextAnnex> { - let isolate = unsafe { &mut *v8__Context__GetIsolate(self) }; + let isolate = unsafe { v8__Context__GetIsolate(self) }; + let mut isolate = unsafe { crate::isolate::Isolate::from_raw_ptr(isolate) }; let num_data_fields = unsafe { v8__Context__GetNumberOfEmbedderDataFields(self) } as int; @@ -187,7 +185,7 @@ impl Context { let annex = Box::new(ContextAnnex { slots: Default::default(), // Gets replaced later in the method. - self_weak: Weak::empty(isolate), + self_weak: Weak::empty(&mut isolate), }); let annex_ptr = Box::into_raw(annex); unsafe { @@ -210,10 +208,10 @@ impl Context { // and assuming the caller is only using safe code, the `Local` or // `Global` must still be alive, so `self_ref_handle` won't outlive it. // We also check above that `isolate` is the context's isolate. - let self_ref_handle = unsafe { UnsafeRefHandle::new(self, isolate) }; + let self_ref_handle = unsafe { UnsafeRefHandle::new(self, &mut isolate) }; Weak::with_guaranteed_finalizer( - isolate, + &mut isolate, self_ref_handle, Box::new(move || { // SAFETY: The lifetimes of references to the annex returned by this @@ -327,7 +325,7 @@ impl Context { #[inline(always)] pub fn get_embedder_data<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, slot: i32, ) -> Option> { unsafe { scope.cast_local(|_| v8__Context__GetEmbedderData(self, slot)) } @@ -368,14 +366,14 @@ impl Context { /// is no way to provide a global object template since we do not create /// a new global object from template, but we can reuse a global object. pub fn from_snapshot<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, context_snapshot_index: usize, options: ContextOptions, ) -> Option> { unsafe { scope.cast_local(|sd| { v8__Context__FromSnapshot( - sd.get_isolate_mut(), + sd.get_isolate_ptr(), context_snapshot_index, options.global_object.map_or_else(null, |o| &*o as *const _), options.microtask_queue.unwrap_or_else(null_mut), @@ -387,7 +385,7 @@ impl Context { #[inline(always)] pub fn get_security_token<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, ) -> Local<'s, Value> { unsafe { scope.cast_local(|_| v8__Context__GetSecurityToken(self)) } .unwrap() diff --git a/src/cppgc.rs b/src/cppgc.rs index 28525a0aea..411cf1ac36 100644 --- a/src/cppgc.rs +++ b/src/cppgc.rs @@ -174,6 +174,7 @@ pub unsafe fn shutdown_process() { /// /// ``` /// use v8::cppgc::{Member, Visitor, GarbageCollected}; +/// use std::ffi::CStr; /// /// struct Foo { foo: Member } /// diff --git a/src/data.rs b/src/data.rs index 7f9aa6a66b..04385d9463 100644 --- a/src/data.rs +++ b/src/data.rs @@ -249,6 +249,7 @@ impl DataError { } } + #[allow(dead_code)] pub(crate) fn no_data() -> Self { Self::NoData { expected: type_name::(), @@ -288,6 +289,7 @@ impl_from! { Template for Data } impl_from! { FunctionTemplate for Data } impl_from! { ObjectTemplate for Data } impl_from! { UnboundModuleScript for Data } +impl_from! { UnboundScript for Data } impl_from! { Value for Data } impl_from! { External for Data } impl_from! { Object for Data } diff --git a/src/date.rs b/src/date.rs index 88c412bb5f..e0270e5730 100644 --- a/src/date.rs +++ b/src/date.rs @@ -2,8 +2,8 @@ use crate::Context; use crate::Date; -use crate::HandleScope; use crate::Local; +use crate::scope::PinScope; unsafe extern "C" { fn v8__Date__New(context: *const Context, value: f64) -> *const Date; @@ -14,7 +14,7 @@ unsafe extern "C" { impl Date { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, value: f64, ) -> Option> { unsafe { diff --git a/src/exception.rs b/src/exception.rs index b2614a5779..8efec027b0 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -3,7 +3,6 @@ use std::convert::TryInto; use crate::Context; -use crate::HandleScope; use crate::Local; use crate::Message; use crate::Object; @@ -11,7 +10,8 @@ use crate::StackFrame; use crate::StackTrace; use crate::String; use crate::Value; -use crate::isolate::Isolate; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::MaybeBool; use crate::support::int; @@ -37,16 +37,16 @@ unsafe extern "C" { fn v8__Message__GetStackTrace(this: *const Message) -> *const StackTrace; fn v8__StackTrace__CurrentStackTrace( - isolate: *mut Isolate, + isolate: *mut RealIsolate, frame_limit: int, ) -> *const StackTrace; fn v8__StackTrace__CurrentScriptNameOrSourceURL( - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const String; fn v8__StackTrace__GetFrameCount(this: *const StackTrace) -> int; fn v8__StackTrace__GetFrame( this: *const StackTrace, - isolate: *mut Isolate, + isolate: *mut RealIsolate, index: u32, ) -> *const StackFrame; @@ -70,7 +70,7 @@ unsafe extern "C" { fn v8__Exception__TypeError(message: *const String) -> *const Value; fn v8__Exception__CreateMessage( - isolate: *mut Isolate, + isolate: *mut RealIsolate, exception: *const Value, ) -> *const Message; fn v8__Exception__GetStackTrace(exception: *const Value) @@ -85,7 +85,7 @@ impl StackTrace { /// Grab a snapshot of the current JavaScript execution stack. #[inline(always)] pub fn current_stack_trace<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, frame_limit: usize, ) -> Option> { let frame_limit = frame_limit.try_into().ok()?; @@ -107,7 +107,7 @@ impl StackTrace { /// #[inline(always)] pub fn current_script_name_or_source_url<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|sd| { @@ -126,7 +126,7 @@ impl StackTrace { #[inline(always)] pub fn get_frame<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, index: usize, ) -> Option> { unsafe { @@ -171,7 +171,7 @@ impl StackFrame { #[inline(always)] pub fn get_script_name<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__StackFrame__GetScriptName(self)) } } @@ -183,7 +183,7 @@ impl StackFrame { #[inline(always)] pub fn get_script_name_or_source_url<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__StackFrame__GetScriptNameOrSourceURL(self)) @@ -194,7 +194,7 @@ impl StackFrame { #[inline(always)] pub fn get_function_name<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__StackFrame__GetFunctionName(self)) } } @@ -228,7 +228,7 @@ impl StackFrame { impl Message { #[inline(always)] - pub fn get<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, String> { + pub fn get<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, String> { unsafe { scope.cast_local(|_| v8__Message__Get(self)) }.unwrap() } @@ -238,7 +238,7 @@ impl Message { #[inline(always)] pub fn get_stack_trace<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__Message__GetStackTrace(self)) } } @@ -246,7 +246,7 @@ impl Message { #[inline(always)] pub fn get_source_line<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|sd| { @@ -260,14 +260,14 @@ impl Message { #[inline(always)] pub fn get_script_resource_name<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__Message__GetScriptResourceName(self)) } } /// Returns the number, 1-based, of the line where the error occurred. #[inline(always)] - pub fn get_line_number(&self, scope: &mut HandleScope) -> Option { + pub fn get_line_number(&self, scope: &PinScope<'_, '_>) -> Option { let i = unsafe { v8__Message__GetLineNumber(self, &*scope.get_current_context()) }; @@ -336,7 +336,7 @@ pub struct Exception; impl Exception { #[inline(always)] pub fn error<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, message: Local, ) -> Local<'s, Value> { Self::new_error_with(scope, message, v8__Exception__Error) @@ -344,7 +344,7 @@ impl Exception { #[inline(always)] pub fn range_error<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, message: Local, ) -> Local<'s, Value> { Self::new_error_with(scope, message, v8__Exception__RangeError) @@ -352,7 +352,7 @@ impl Exception { #[inline(always)] pub fn reference_error<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, message: Local, ) -> Local<'s, Value> { Self::new_error_with(scope, message, v8__Exception__ReferenceError) @@ -360,7 +360,7 @@ impl Exception { #[inline(always)] pub fn syntax_error<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, message: Local, ) -> Local<'s, Value> { Self::new_error_with(scope, message, v8__Exception__SyntaxError) @@ -368,7 +368,7 @@ impl Exception { #[inline(always)] pub fn type_error<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, message: Local, ) -> Local<'s, Value> { Self::new_error_with(scope, message, v8__Exception__TypeError) @@ -377,7 +377,7 @@ impl Exception { /// Internal helper to make the above error constructors less repetitive. #[inline(always)] fn new_error_with<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, message: Local, contructor: unsafe extern "C" fn(*const String) -> *const Value, ) -> Local<'s, Value> { @@ -394,7 +394,7 @@ impl Exception { /// or capture the current stack trace if not available. #[inline(always)] pub fn create_message<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, exception: Local, ) -> Local<'s, Message> { unsafe { @@ -409,7 +409,7 @@ impl Exception { /// of a given exception, or an empty handle if not available. #[inline(always)] pub fn get_stack_trace<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, exception: Local, ) -> Option> { unsafe { scope.cast_local(|_| v8__Exception__GetStackTrace(&*exception)) } diff --git a/src/external.rs b/src/external.rs index 9292a8b9a8..6bcee30a1a 100644 --- a/src/external.rs +++ b/src/external.rs @@ -3,13 +3,13 @@ use std::ffi::c_void; use crate::External; -use crate::HandleScope; -use crate::Isolate; use crate::Local; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; unsafe extern "C" { fn v8__External__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, value: *mut c_void, ) -> *const External; fn v8__External__Value(this: *const External) -> *mut c_void; @@ -19,7 +19,7 @@ impl External { #[inline(always)] #[allow(clippy::not_unsafe_ptr_arg_deref)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, value: *mut c_void, ) -> Local<'s, Self> { unsafe { diff --git a/src/fast_api.rs b/src/fast_api.rs index 1f41c908c2..eb31123d29 100644 --- a/src/fast_api.rs +++ b/src/fast_api.rs @@ -2,7 +2,9 @@ use crate::Isolate; use crate::Local; use crate::Value; use crate::binding::*; +use crate::isolate::RealIsolate; use std::ffi::c_void; +use std::ptr::NonNull; #[derive(Clone, Copy)] #[repr(transparent)] @@ -125,11 +127,31 @@ bitflags::bitflags! { /// ``` #[repr(C)] pub struct FastApiCallbackOptions<'a> { - pub isolate: *mut Isolate, + pub(crate) isolate: *mut RealIsolate, /// The `data` passed to the FunctionTemplate constructor, or `undefined`. pub data: Local<'a, Value>, } +impl<'a> FastApiCallbackOptions<'a> { + pub unsafe fn isolate_unchecked(&self) -> &'a Isolate { + unsafe { + Isolate::from_raw_ref(std::mem::transmute::< + &*mut RealIsolate, + &NonNull, + >(&self.isolate)) + } + } + + pub unsafe fn isolate_unchecked_mut(&mut self) -> &mut Isolate { + unsafe { + Isolate::from_raw_ref_mut(std::mem::transmute::< + &mut *mut RealIsolate, + &mut NonNull, + >(&mut self.isolate)) + } + } +} + pub type FastApiOneByteString = v8__FastOneByteString; impl FastApiOneByteString { diff --git a/src/fixed_array.rs b/src/fixed_array.rs index 38e84841cf..b4cb8df69c 100644 --- a/src/fixed_array.rs +++ b/src/fixed_array.rs @@ -1,8 +1,8 @@ +use crate::scope::PinScope; // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. use crate::Context; use crate::Data; use crate::FixedArray; -use crate::HandleScope; use crate::Local; use crate::support::int; @@ -25,7 +25,7 @@ impl FixedArray { #[inline(always)] pub fn get<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, index: usize, ) -> Option> { if index >= self.length() { diff --git a/src/function.rs b/src/function.rs index 78a59e6f90..910caf4221 100644 --- a/src/function.rs +++ b/src/function.rs @@ -5,9 +5,9 @@ use std::ptr::null; use crate::Array; use crate::Boolean; +use crate::CallbackScope; use crate::Context; use crate::Function; -use crate::HandleScope; use crate::Integer; use crate::Isolate; use crate::Local; @@ -19,7 +19,9 @@ use crate::Signature; use crate::String; use crate::UniqueRef; use crate::Value; -use crate::scope::CallbackScope; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; +use crate::scope::callback_scope; use crate::script_compiler::CachedData; use crate::support::MapFnFrom; use crate::support::MapFnTo; @@ -72,7 +74,7 @@ unsafe extern "C" { fn v8__PropertyCallbackInfo__GetIsolate( this: *const RawPropertyCallbackInfo, - ) -> *mut Isolate; + ) -> *mut RealIsolate; fn v8__PropertyCallbackInfo__Data( this: *const RawPropertyCallbackInfo, ) -> *const Value; @@ -218,7 +220,7 @@ where /// hit. If the ReturnValue was not yet set, this will return the undefined /// value. #[inline(always)] - pub fn get<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Value> { + pub fn get<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Value> { unsafe { scope.cast_local(|_| v8__ReturnValue__Value__Get(&self.0)) } .unwrap() } @@ -253,9 +255,9 @@ impl FunctionCallbackInfo { impl FunctionCallbackInfo { #[inline(always)] - pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate { + pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate { let arg_nn = - self.get_implicit_arg_non_null::<*mut Isolate>(Self::kIsolateIndex); + self.get_implicit_arg_non_null::<*mut RealIsolate>(Self::kIsolateIndex); *unsafe { arg_nn.as_ref() } } @@ -265,12 +267,12 @@ impl FunctionCallbackInfo { } #[inline(always)] - pub(crate) fn new_target(&self) -> Local { + pub(crate) fn new_target(&self) -> Local<'_, Value> { unsafe { self.get_implicit_arg_local(Self::kNewTargetIndex) } } #[inline(always)] - pub(crate) fn this(&self) -> Local { + pub(crate) fn this(&self) -> Local<'_, Object> { unsafe { self.get_arg_local(-1) } } @@ -281,7 +283,7 @@ impl FunctionCallbackInfo { } #[inline(always)] - pub(crate) fn data(&self) -> Local { + pub(crate) fn data(&self) -> Local<'_, Value> { unsafe { let ptr = v8__FunctionCallbackInfo__Data(self); let nn = NonNull::new_unchecked(ptr as *mut Value); @@ -295,12 +297,14 @@ impl FunctionCallbackInfo { } #[inline(always)] - pub(crate) fn get(&self, index: int) -> Local { + pub(crate) fn get(&self, index: int) -> Local<'_, Value> { if index >= 0 && index < self.length { unsafe { self.get_arg_local(index) } } else { - let isolate = unsafe { &mut *self.get_isolate_ptr() }; - undefined(isolate).into() + let isolate = unsafe { + crate::isolate::Isolate::from_raw_ptr(self.get_isolate_ptr()) + }; + undefined(&isolate).into() } } @@ -325,7 +329,7 @@ impl FunctionCallbackInfo { // SAFETY: caller must guarantee that the implicit argument at `index` // contains a valid V8 handle. #[inline(always)] - unsafe fn get_implicit_arg_local(&self, index: i32) -> Local { + unsafe fn get_implicit_arg_local(&self, index: i32) -> Local<'_, T> { let nn = self.get_implicit_arg_non_null::(index); unsafe { Local::from_non_null(nn) } } @@ -333,7 +337,7 @@ impl FunctionCallbackInfo { // SAFETY: caller must guarantee that the `index` value lies between -1 and // self.length. #[inline(always)] - unsafe fn get_arg_local(&self, index: i32) -> Local { + unsafe fn get_arg_local(&self, index: i32) -> Local<'_, T> { let ptr = unsafe { self.values.offset(index as _) } as *mut T; debug_assert!(!ptr.is_null()); let nn = unsafe { NonNull::new_unchecked(ptr) }; @@ -353,7 +357,7 @@ pub struct PropertyCallbackInfo(RawPropertyCallbackInfo, PhantomData); impl PropertyCallbackInfo { #[inline(always)] - pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate { + pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate { unsafe { v8__PropertyCallbackInfo__GetIsolate(&self.0) } } } @@ -373,7 +377,7 @@ impl<'s> FunctionCallbackArguments<'s> { /// not be called. #[inline(always)] pub unsafe fn get_isolate(&mut self) -> &mut Isolate { - unsafe { &mut *self.0.get_isolate_ptr() } + unsafe { &mut *(self.0.get_isolate_ptr() as *mut crate::isolate::Isolate) } } /// For construct calls, this returns the "new.target" value. @@ -511,19 +515,20 @@ pub type FunctionCallback = unsafe extern "C" fn(*const FunctionCallbackInfo); impl MapFnFrom for FunctionCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, FunctionCallbackArguments<'s>, - ReturnValue, + ReturnValue<'s, Value>, ), { fn mapping() -> Self { let f = |info: *const FunctionCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + let scope = std::pin::pin!(unsafe { CallbackScope::new(info) }); + let mut scope = scope.init(); let args = FunctionCallbackArguments::from_function_callback_info(info); let rv = ReturnValue::from_function_callback_info(info); - (F::get())(scope, args, rv); + (F::get())(&mut scope, args, rv); }; f.to_c_fn() } @@ -535,8 +540,8 @@ pub(crate) type NamedGetterCallbackForAccessor = impl MapFnFrom for NamedGetterCallbackForAccessor where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, PropertyCallbackArguments<'s>, ReturnValue, @@ -546,7 +551,7 @@ where let f = |key: SealedLocal, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); @@ -564,8 +569,8 @@ pub(crate) type NamedGetterCallback = unsafe extern "C" fn( impl MapFnFrom for NamedGetterCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, PropertyCallbackArguments<'s>, ReturnValue, @@ -575,7 +580,7 @@ where let f = |key: SealedLocal, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); @@ -593,8 +598,8 @@ pub(crate) type NamedQueryCallback = unsafe extern "C" fn( impl MapFnFrom for NamedQueryCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, PropertyCallbackArguments<'s>, ReturnValue, @@ -604,7 +609,7 @@ where let f = |key: SealedLocal, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); @@ -623,8 +628,8 @@ pub(crate) type NamedSetterCallbackForAccessor = unsafe extern "C" fn( impl MapFnFrom for NamedSetterCallbackForAccessor where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, Local<'s, Value>, PropertyCallbackArguments<'s>, @@ -636,7 +641,7 @@ where value: SealedLocal, info: *const PropertyCallbackInfo<()>| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let value = unsafe { scope.unseal(value) }; let args = PropertyCallbackArguments::from_property_callback_info(info); @@ -656,8 +661,8 @@ pub(crate) type NamedSetterCallback = unsafe extern "C" fn( impl MapFnFrom for NamedSetterCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, Local<'s, Value>, PropertyCallbackArguments<'s>, @@ -669,7 +674,7 @@ where value: SealedLocal, info: *const PropertyCallbackInfo<()>| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let value = unsafe { scope.unseal(value) }; let args = PropertyCallbackArguments::from_property_callback_info(info); @@ -687,8 +692,8 @@ pub(crate) type PropertyEnumeratorCallback = impl MapFnFrom for PropertyEnumeratorCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, PropertyCallbackArguments<'s>, ReturnValue, ), @@ -696,7 +701,7 @@ where fn mapping() -> Self { let f = |info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); (F::get())(scope, args, rv); @@ -714,8 +719,8 @@ pub(crate) type NamedDefinerCallback = unsafe extern "C" fn( impl MapFnFrom for NamedDefinerCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, &PropertyDescriptor, PropertyCallbackArguments<'s>, @@ -727,7 +732,7 @@ where desc: *const PropertyDescriptor, info: *const PropertyCallbackInfo<()>| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let args = PropertyCallbackArguments::from_property_callback_info(info); let desc = unsafe { &*desc }; @@ -746,8 +751,8 @@ pub(crate) type NamedDeleterCallback = unsafe extern "C" fn( impl MapFnFrom for NamedDeleterCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, Local<'s, Name>, PropertyCallbackArguments<'s>, ReturnValue, @@ -757,7 +762,7 @@ where let f = |key: SealedLocal, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let key = unsafe { scope.unseal(key) }; let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); @@ -773,8 +778,8 @@ pub(crate) type IndexedGetterCallback = impl MapFnFrom for IndexedGetterCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, u32, PropertyCallbackArguments<'s>, ReturnValue, @@ -783,7 +788,7 @@ where fn mapping() -> Self { let f = |index: u32, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); (F::get())(scope, index, args, rv) @@ -800,8 +805,8 @@ pub(crate) type IndexedQueryCallback = unsafe extern "C" fn( impl MapFnFrom for IndexedQueryCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, u32, PropertyCallbackArguments<'s>, ReturnValue, @@ -810,7 +815,7 @@ where fn mapping() -> Self { let f = |key: u32, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); (F::get())(scope, key, args, rv) @@ -828,8 +833,8 @@ pub(crate) type IndexedSetterCallback = unsafe extern "C" fn( impl MapFnFrom for IndexedSetterCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, u32, Local<'s, Value>, PropertyCallbackArguments<'s>, @@ -841,7 +846,7 @@ where value: SealedLocal, info: *const PropertyCallbackInfo<()>| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let value = unsafe { scope.unseal(value) }; let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); @@ -860,8 +865,8 @@ pub(crate) type IndexedDefinerCallback = unsafe extern "C" fn( impl MapFnFrom for IndexedDefinerCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, u32, &PropertyDescriptor, PropertyCallbackArguments<'s>, @@ -873,7 +878,7 @@ where desc: *const PropertyDescriptor, info: *const PropertyCallbackInfo<()>| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); let desc = unsafe { &*desc }; @@ -891,8 +896,8 @@ pub(crate) type IndexedDeleterCallback = unsafe extern "C" fn( impl MapFnFrom for IndexedDeleterCallback where F: UnitType - + for<'s> Fn( - &mut HandleScope<'s>, + + for<'s, 'i> Fn( + &mut PinScope<'s, 'i>, u32, PropertyCallbackArguments<'s>, ReturnValue, @@ -901,7 +906,7 @@ where fn mapping() -> Self { let f = |index: u32, info: *const PropertyCallbackInfo| { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let args = PropertyCallbackArguments::from_property_callback_info(info); let rv = ReturnValue::from_property_callback_info(info); (F::get())(scope, index, args, rv) @@ -976,9 +981,9 @@ impl<'s, T> FunctionBuilder<'s, T> { impl<'s> FunctionBuilder<'s, Function> { /// Create the function in the current execution context. #[inline(always)] - pub fn build( + pub fn build<'i>( self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, 'i>, ) -> Option> { unsafe { scope.cast_local(|sd| { @@ -1016,7 +1021,7 @@ impl Function { /// for a given FunctionCallback. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, callback: impl MapFnTo, ) -> Option> { Self::builder(callback).build(scope) @@ -1024,7 +1029,7 @@ impl Function { #[inline(always)] pub fn new_raw<'s>( - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, callback: FunctionCallback, ) -> Option> { Self::builder_raw(callback).build(scope) @@ -1034,7 +1039,7 @@ impl Function { #[inline] pub fn call<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, recv: Local, args: &[Local], ) -> Option> { @@ -1052,7 +1057,7 @@ impl Function { #[inline] pub fn call_with_context<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, context: Local, recv: Local, args: &[Local], @@ -1079,7 +1084,7 @@ impl Function { #[inline(always)] pub fn new_instance<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, args: &[Local], ) -> Option> { let args = Local::slice_into_raw(args); @@ -1093,7 +1098,7 @@ impl Function { } #[inline(always)] - pub fn get_name<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, String> { + pub fn get_name<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, String> { unsafe { scope.cast_local(|_| v8__Function__GetName(self)).unwrap() } } @@ -1117,7 +1122,7 @@ impl Function { } #[inline(always)] - pub fn get_script_origin(&self) -> &ScriptOrigin { + pub fn get_script_origin(&self) -> &ScriptOrigin<'_> { unsafe { let ptr = v8__Function__GetScriptOrigin(self); &*ptr diff --git a/src/handle.rs b/src/handle.rs index dad3fabca2..6d1faa7731 100644 --- a/src/handle.rs +++ b/src/handle.rs @@ -10,16 +10,24 @@ use std::ops::Deref; use std::ptr::NonNull; use crate::Data; -use crate::HandleScope; use crate::Isolate; use crate::IsolateHandle; +use crate::isolate::RealIsolate; +use crate::scope::GetIsolate; +use crate::scope::PinScope; use crate::support::Opaque; unsafe extern "C" { - fn v8__Local__New(isolate: *mut Isolate, other: *const Data) -> *const Data; - fn v8__Global__New(isolate: *mut Isolate, data: *const Data) -> *const Data; + fn v8__Local__New( + isolate: *mut RealIsolate, + other: *const Data, + ) -> *const Data; + fn v8__Global__New( + isolate: *mut RealIsolate, + data: *const Data, + ) -> *const Data; fn v8__Global__NewWeak( - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *const Data, parameter: *const c_void, callback: unsafe extern "C" fn(*const WeakCallbackInfo), @@ -27,7 +35,7 @@ unsafe extern "C" { fn v8__Global__Reset(data: *const Data); fn v8__WeakCallbackInfo__GetIsolate( this: *const WeakCallbackInfo, - ) -> *mut Isolate; + ) -> *mut RealIsolate; fn v8__WeakCallbackInfo__GetParameter( this: *const WeakCallbackInfo, ) -> *mut c_void; @@ -40,12 +48,12 @@ unsafe extern "C" { fn v8__TracedReference__DESTRUCT(this: *mut TracedReference); fn v8__TracedReference__Reset( this: *mut TracedReference, - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *mut Data, ); fn v8__TracedReference__Get( this: *const TracedReference, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const Data; fn v8__Eternal__CONSTRUCT(this: *mut Eternal); @@ -53,11 +61,11 @@ unsafe extern "C" { fn v8__Eternal__Clear(this: *mut Eternal); fn v8__Eternal__Get( this: *const Eternal, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const Data; fn v8__Eternal__Set( this: *mut Eternal, - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *mut Data, ); fn v8__Eternal__IsEmpty(this: *const Eternal) -> bool; @@ -100,13 +108,34 @@ unsafe extern "C" { #[derive(Debug)] pub struct Local<'s, T>(NonNull, PhantomData<&'s ()>); +mod sealed { + pub trait Sealed {} +} + +// this trait exists to allow you to specify the output lifetime for `Local::extend_lifetime_unchecked`. +// so you can do something like `unsafe { Local::extend_lifetime_unchecked::>(local) }`. +// if it were just a lifetime parameter, it would be "late bound" and you could not explicitly specify the output lifetime. +pub trait ExtendLifetime<'s, T>: sealed::Sealed { + type Input; + unsafe fn extend_lifetime_unchecked_from(value: Self::Input) -> Self; +} + +impl sealed::Sealed for Local<'_, T> {} + +impl<'s, T> ExtendLifetime<'s, T> for Local<'_, T> { + type Input = Local<'s, T>; + unsafe fn extend_lifetime_unchecked_from(value: Self::Input) -> Self { + unsafe { Local::from_non_null(value.as_non_null()) } + } +} + impl<'s, T> Local<'s, T> { /// Construct a new Local from an existing Handle. #[inline(always)] - pub fn new( - scope: &mut HandleScope<'s, ()>, + pub fn new<'i>( + scope: &PinScope<'s, 'i, ()>, handle: impl Handle, - ) -> Self { + ) -> Local<'s, T> { let HandleInfo { data, host } = handle.get_handle_info(); host.assert_match_isolate(scope); unsafe { @@ -126,6 +155,35 @@ impl<'s, T> Local<'s, T> { { unsafe { transmute(other) } } + /// Extend the lifetime of a `Local` handle to a longer lifetime. + /// + /// # Safety + /// + /// The caller is responsible for ensuring that the `Local` handle is valid + /// for the longer lifetime. Incorrect usage can lead to the usage of invalid + /// handles + /// + /// # Example + /// + /// ```ignore + /// let isolate = unsafe { Isolate::from_raw_isolate_ptr(isolate_ptr) }; + /// callback_scope!(unsafe scope, &mut isolate); + /// // the lifetime of the local handle will be tied to the lifetime of `&mut isolate`, + /// // which, because we've created it from a raw pointer, is only as long as the current function. + /// // the real lifetime at runtime is + /// // actually the lifetime of the parent scope. if we can guarantee that the parent scope lives at least as long as + /// // `'o`, it is valid to extend the lifetime of the local handle to `'o` by using `extend_lifetime_unchecked`. + /// let context = Local::new(scope, context_global_handle); + /// + /// let local_longer_lifetime = unsafe { local.extend_lifetime_unchecked::>() }; + /// ``` + #[inline(always)] + pub unsafe fn extend_lifetime_unchecked<'o, O>(self) -> O + where + O: ExtendLifetime<'s, T, Input = Self>, + { + unsafe { O::extend_lifetime_unchecked_from(self) } + } #[inline(always)] pub(crate) unsafe fn from_raw(ptr: *const T) -> Option { @@ -232,10 +290,10 @@ pub struct Global { impl Global { /// Construct a new Global from an existing Handle. #[inline(always)] - pub fn new(isolate: &mut Isolate, handle: impl Handle) -> Self { + pub fn new(isolate: &Isolate, handle: impl Handle) -> Self { let HandleInfo { data, host } = handle.get_handle_info(); host.assert_match_isolate(isolate); - unsafe { Self::new_raw(isolate, data) } + unsafe { Self::new_raw(isolate as *const Isolate as *mut Isolate, data) } } /// Implementation helper function that contains the code that can be shared @@ -244,7 +302,7 @@ impl Global { unsafe fn new_raw(isolate: *mut Isolate, data: NonNull) -> Self { let data = data.cast().as_ptr(); unsafe { - let data = v8__Global__New(isolate, data) as *const T; + let data = v8__Global__New((*isolate).as_real_ptr(), data) as *const T; let data = NonNull::new_unchecked(data as *mut _); let isolate_handle = (*isolate).thread_safe_handle(); Self { @@ -287,7 +345,8 @@ impl Global { impl Clone for Global { fn clone(&self) -> Self { let HandleInfo { data, host } = self.get_handle_info(); - unsafe { Self::new_raw(host.get_isolate().as_mut(), data) } + let mut isolate = unsafe { Isolate::from_non_null(host.get_isolate()) }; + unsafe { Self::new_raw(isolate.as_mut(), data) } } } @@ -500,13 +559,13 @@ enum HandleHost { // the `Isolate` that hosts it (the handle) and the currently entered // scope. Scope, - Isolate(NonNull), + Isolate(NonNull), DisposedIsolate, } -impl From<&'_ mut Isolate> for HandleHost { - fn from(isolate: &'_ mut Isolate) -> Self { - Self::Isolate(NonNull::from(isolate)) +impl From<&'_ Isolate> for HandleHost { + fn from(isolate: &'_ Isolate) -> Self { + Self::Isolate(unsafe { NonNull::new_unchecked(isolate.as_real_ptr()) }) } } @@ -539,9 +598,10 @@ impl HandleHost { fn match_host( self, other: Self, - scope_isolate_opt: Option<&mut Isolate>, + scope_isolate_opt: Option<&Isolate>, ) -> bool { - let scope_isolate_opt_nn = scope_isolate_opt.map(NonNull::from); + let scope_isolate_opt_nn = scope_isolate_opt + .map(|isolate| unsafe { NonNull::new_unchecked(isolate.as_real_ptr()) }); match (self, other, scope_isolate_opt_nn) { (Self::Scope, Self::Scope, _) => true, (Self::Isolate(ile1), Self::Isolate(ile2), _) => ile1 == ile2, @@ -562,7 +622,7 @@ impl HandleHost { } } - fn assert_match_host(self, other: Self, scope_opt: Option<&mut Isolate>) { + fn assert_match_host(self, other: Self, scope_opt: Option<&Isolate>) { assert!( self.match_host(other, scope_opt), "attempt to use Handle in an Isolate that is not its host" @@ -570,15 +630,15 @@ impl HandleHost { } #[allow(dead_code)] - fn match_isolate(self, isolate: &mut Isolate) -> bool { + fn match_isolate(self, isolate: &Isolate) -> bool { self.match_host(isolate.into(), Some(isolate)) } - fn assert_match_isolate(self, isolate: &mut Isolate) { + fn assert_match_isolate(self, isolate: &Isolate) { self.assert_match_host(isolate.into(), Some(isolate)); } - fn get_isolate(self) -> NonNull { + fn get_isolate(self) -> NonNull { match self { Self::Scope => panic!("host Isolate for Handle not available"), Self::Isolate(ile) => ile, @@ -588,7 +648,8 @@ impl HandleHost { #[allow(dead_code)] fn get_isolate_handle(self) -> IsolateHandle { - unsafe { self.get_isolate().as_ref() }.thread_safe_handle() + let isolate = unsafe { Isolate::from_non_null(self.get_isolate()) }; + isolate.thread_safe_handle() } } @@ -681,7 +742,7 @@ impl Weak { let data = data.cast().as_ptr(); let data = unsafe { v8__Global__NewWeak( - isolate, + (*isolate).as_real_ptr(), data, weak_data.deref() as *const _ as *const c_void, Self::first_pass_callback, @@ -737,14 +798,10 @@ impl Weak { if isolate_ptr.is_null() { unreachable!("Isolate was dropped but weak handle wasn't reset."); } - - let finalizer_id = if let Some(finalizer) = finalizer { - let isolate = unsafe { &mut *isolate_ptr }; - Some(isolate.get_finalizer_map_mut().add(finalizer)) - } else { - None - }; - Self::new_raw(isolate_ptr, data, finalizer_id) + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate_ptr) }; + let finalizer_id = finalizer + .map(|finalizer| isolate.get_finalizer_map_mut().add(finalizer)); + Self::new_raw(&mut isolate, data, finalizer_id) } else { Weak { data: None, @@ -789,7 +846,7 @@ impl Weak { // Disposed isolates have no finalizers. false } else { - let isolate = unsafe { &mut *isolate_ptr }; + let isolate = unsafe { Isolate::from_raw_ptr(isolate_ptr) }; isolate.get_finalizer_map().map.contains_key(&finalizer_id) } } else { @@ -839,7 +896,7 @@ impl Weak { pub fn to_local<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, ) -> Option> { if let Some(data) = self.get_pointer() { let handle_host: HandleHost = (&self.isolate_handle).into(); @@ -885,7 +942,7 @@ impl Weak { unsafe extern "C" fn second_pass_callback(wci: *const WeakCallbackInfo) { // SAFETY: This callback is guaranteed by V8 to be called in the isolate's // thread before the isolate is disposed. - let isolate = unsafe { &mut *v8__WeakCallbackInfo__GetIsolate(wci) }; + let isolate = unsafe { v8__WeakCallbackInfo__GetIsolate(wci) }; // SAFETY: This callback might be called well after the first pass callback, // which means the corresponding Weak might have been dropped. In Weak's @@ -896,6 +953,8 @@ impl Weak { let ptr = v8__WeakCallbackInfo__GetParameter(wci); &*(ptr as *mut WeakData) }; + + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; let finalizer: Option = { let finalizer_id = weak_data.finalizer_id.unwrap(); isolate.get_finalizer_map_mut().map.remove(&finalizer_id) @@ -910,7 +969,7 @@ impl Weak { } match finalizer { - Some(FinalizerCallback::Regular(finalizer)) => finalizer(isolate), + Some(FinalizerCallback::Regular(finalizer)) => finalizer(&mut isolate), Some(FinalizerCallback::Guaranteed(finalizer)) => finalizer(), None => {} } @@ -931,7 +990,7 @@ impl Drop for Weak { // SAFETY: We're in the isolate's thread because `Weak` isn't Send or Sync. let isolate_ptr = unsafe { self.isolate_handle.get_isolate_ptr() }; if !isolate_ptr.is_null() { - let isolate = unsafe { &mut *isolate_ptr }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate_ptr) }; let finalizer = isolate.get_finalizer_map_mut().map.remove(&finalizer_id); return finalizer.is_some(); @@ -1073,16 +1132,13 @@ impl TracedReference { /// Construct a TracedReference from a Local. /// /// A new storage cell is created pointing to the same object. - pub fn new(scope: &mut HandleScope<()>, data: Local) -> Self { + pub fn new<'s>(scope: &PinScope<'s, '_, ()>, data: Local<'s, T>) -> Self { let mut this = Self::empty(); this.reset(scope, Some(data)); this } - pub fn get<'s>( - &self, - scope: &mut HandleScope<'s, ()>, - ) -> Option> { + pub fn get<'s>(&self, scope: &PinScope<'s, '_, ()>) -> Option> { unsafe { scope.cast_local(|sd| { v8__TracedReference__Get( @@ -1095,7 +1151,11 @@ impl TracedReference { /// Always resets the reference. Creates a new reference from `other` if it is /// non-empty. - pub fn reset(&mut self, scope: &mut HandleScope<()>, data: Option>) { + pub fn reset<'s>( + &mut self, + scope: &PinScope<'s, '_, ()>, + data: Option>, + ) { unsafe { v8__TracedReference__Reset( self as *mut Self as *mut TracedReference, @@ -1140,7 +1200,7 @@ impl Eternal { } } - pub fn set(&self, scope: &mut HandleScope<()>, data: Local) { + pub fn set<'s>(&self, scope: &PinScope<'s, '_, ()>, data: Local<'s, T>) { unsafe { v8__Eternal__Set( self as *const Self as *mut Eternal, @@ -1150,10 +1210,7 @@ impl Eternal { } } - pub fn get<'s>( - &self, - scope: &mut HandleScope<'s, ()>, - ) -> Option> { + pub fn get<'s>(&self, scope: &PinScope<'s, '_, ()>) -> Option> { unsafe { scope.cast_local(|sd| { v8__Eternal__Get( diff --git a/src/inspector.rs b/src/inspector.rs index b96204a22a..cce1bc8bc7 100644 --- a/src/inspector.rs +++ b/src/inspector.rs @@ -18,6 +18,7 @@ use crate::Isolate; use crate::Local; use crate::StackTrace; use crate::Value; +use crate::isolate::RealIsolate; use crate::support::CxxVTable; use crate::support::Opaque; use crate::support::UniquePtr; @@ -88,14 +89,14 @@ unsafe extern "C" { ) -> bool; fn v8_inspector__StringBuffer__DELETE(this: *mut StringBuffer); - fn v8_inspector__StringBuffer__string(this: &StringBuffer) -> StringView; + fn v8_inspector__StringBuffer__string(this: &StringBuffer) -> StringView<'_>; fn v8_inspector__StringBuffer__create( source: StringView, ) -> UniquePtr; fn v8_inspector__V8Inspector__DELETE(this: *mut RawV8Inspector); fn v8_inspector__V8Inspector__create( - isolate: *mut Isolate, + isolate: *mut RealIsolate, client: *mut RawV8InspectorClient, ) -> *mut RawV8Inspector; fn v8_inspector__V8Inspector__connect( @@ -504,7 +505,7 @@ pub trait V8InspectorClientImpl { fn ensure_default_context_in_group( &self, context_group_id: i32, - ) -> Option> { + ) -> Option> { None } @@ -630,7 +631,7 @@ impl StringBuffer { // therefore we declare self as mutable here. // TODO: figure out whether it'd be safe to assume a const receiver here. // That would make it possible to implement `Deref`. - pub fn string(&self) -> StringView { + pub fn string(&self) -> StringView<'_> { unsafe { v8_inspector__StringBuffer__string(self) } } @@ -885,7 +886,7 @@ impl V8Inspector { ) -> V8Inspector { let raw = unsafe { UniqueRef::from_raw(v8_inspector__V8Inspector__create( - isolate, + isolate.as_real_ptr(), client.raw(), )) }; diff --git a/src/isolate.rs b/src/isolate.rs index a101a17a25..23311f0efc 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -6,11 +6,11 @@ use crate::Data; use crate::FixedArray; use crate::Function; use crate::FunctionCodeHandling; -use crate::HandleScope; use crate::Local; use crate::Message; use crate::Module; use crate::Object; +use crate::PinScope; use crate::Platform; use crate::Promise; use crate::PromiseResolver; @@ -32,7 +32,6 @@ use crate::handle::FinalizerMap; use crate::isolate_create_params::CreateParams; use crate::isolate_create_params::raw; use crate::promise::PromiseRejectMessage; -use crate::scope::data::ScopeData; use crate::snapshot::SnapshotCreator; use crate::support::MapFnFrom; use crate::support::MapFnTo; @@ -61,6 +60,7 @@ use std::mem::needs_drop; use std::mem::size_of; use std::ops::Deref; use std::ops::DerefMut; +use std::pin::pin; use std::ptr; use std::ptr::NonNull; use std::ptr::addr_of_mut; @@ -173,7 +173,7 @@ pub enum WasmAsyncSuccess { Fail, } pub type WasmAsyncResolvePromiseCallback = unsafe extern "C" fn( - *mut Isolate, + UnsafeRawIsolatePtr, Local, Local, Local, @@ -235,8 +235,8 @@ pub type HostInitializeImportMetaObjectCallback = /// ``` pub trait HostImportModuleDynamicallyCallback: UnitType - + for<'s> FnOnce( - &mut HandleScope<'s>, + + for<'s, 'i> FnOnce( + &mut PinScope<'s, 'i>, Local<'s, Data>, Local<'s, Value>, Local<'s, String>, @@ -270,8 +270,8 @@ pub type RawHostImportModuleDynamicallyCallback = impl HostImportModuleDynamicallyCallback for F where F: UnitType - + for<'s> FnOnce( - &mut HandleScope<'s>, + + for<'s, 'i> FnOnce( + &mut PinScope<'s, 'i>, Local<'s, Data>, Local<'s, Value>, Local<'s, String>, @@ -280,17 +280,19 @@ where { #[inline(always)] fn to_c_fn(self) -> RawHostImportModuleDynamicallyCallback { + #[allow(unused_variables)] #[inline(always)] - fn scope_adapter<'s, F: HostImportModuleDynamicallyCallback>( + fn scope_adapter<'s, 'i: 's, F: HostImportModuleDynamicallyCallback>( context: Local<'s, Context>, host_defined_options: Local<'s, Data>, resource_name: Local<'s, Value>, specifier: Local<'s, String>, import_attributes: Local<'s, FixedArray>, ) -> Option> { - let scope = &mut unsafe { CallbackScope::new(context) }; + let scope = pin!(unsafe { CallbackScope::new(context) }); + let mut scope = scope.init(); (F::get())( - scope, + &mut scope, host_defined_options, resource_name, specifier, @@ -390,8 +392,8 @@ where /// imports. pub trait HostImportModuleWithPhaseDynamicallyCallback: UnitType - + for<'s> FnOnce( - &mut HandleScope<'s>, + + for<'s, 'i> FnOnce( + &mut PinScope<'s, 'i>, Local<'s, Data>, Local<'s, Value>, Local<'s, String>, @@ -428,8 +430,8 @@ pub type RawHostImportModuleWithPhaseDynamicallyCallback = impl HostImportModuleWithPhaseDynamicallyCallback for F where F: UnitType - + for<'s> FnOnce( - &mut HandleScope<'s>, + + for<'s, 'i> FnOnce( + &mut PinScope<'s, 'i>, Local<'s, Data>, Local<'s, Value>, Local<'s, String>, @@ -439,6 +441,7 @@ where { #[inline(always)] fn to_c_fn(self) -> RawHostImportModuleWithPhaseDynamicallyCallback { + #[allow(unused_variables)] #[inline(always)] fn scope_adapter<'s, F: HostImportModuleWithPhaseDynamicallyCallback>( context: Local<'s, Context>, @@ -448,9 +451,10 @@ where import_phase: ModuleImportPhase, import_attributes: Local<'s, FixedArray>, ) -> Option> { - let scope = &mut unsafe { CallbackScope::new(context) }; + let scope = pin!(unsafe { CallbackScope::new(context) }); + let mut scope = scope.init(); (F::get())( - scope, + &mut scope, host_defined_options, resource_name, specifier, @@ -530,10 +534,10 @@ where /// creation fails, the embedder must propagate that exception by returning /// [`None`]. pub type HostCreateShadowRealmContextCallback = - for<'s> fn(scope: &mut HandleScope<'s>) -> Option>; + for<'s, 'i> fn(scope: &mut PinScope<'s, 'i>) -> Option>; pub type GcCallbackWithData = unsafe extern "C" fn( - isolate: *mut Isolate, + isolate: UnsafeRawIsolatePtr, r#type: GCType, flags: GCCallbackFlags, data: *mut c_void, @@ -586,171 +590,176 @@ pub type UseCounterCallback = unsafe extern "C" fn(&mut Isolate, UseCounterFeature); unsafe extern "C" { - fn v8__Isolate__New(params: *const raw::CreateParams) -> *mut Isolate; - fn v8__Isolate__Dispose(this: *mut Isolate); - fn v8__Isolate__GetNumberOfDataSlots(this: *const Isolate) -> u32; - fn v8__Isolate__GetData(isolate: *const Isolate, slot: u32) -> *mut c_void; + fn v8__Isolate__New(params: *const raw::CreateParams) -> *mut RealIsolate; + fn v8__Isolate__Dispose(this: *mut RealIsolate); + fn v8__Isolate__GetNumberOfDataSlots(this: *const RealIsolate) -> u32; + fn v8__Isolate__GetData( + isolate: *const RealIsolate, + slot: u32, + ) -> *mut c_void; fn v8__Isolate__SetData( - isolate: *const Isolate, + isolate: *const RealIsolate, slot: u32, data: *mut c_void, ); - fn v8__Isolate__Enter(this: *mut Isolate); - fn v8__Isolate__Exit(this: *mut Isolate); - fn v8__Isolate__GetCurrent() -> *mut Isolate; - fn v8__Isolate__MemoryPressureNotification(this: *mut Isolate, level: u8); - fn v8__Isolate__ClearKeptObjects(isolate: *mut Isolate); - fn v8__Isolate__LowMemoryNotification(isolate: *mut Isolate); + fn v8__Isolate__Enter(this: *mut RealIsolate); + fn v8__Isolate__Exit(this: *mut RealIsolate); + fn v8__Isolate__GetCurrent() -> *mut RealIsolate; + fn v8__Isolate__MemoryPressureNotification(this: *mut RealIsolate, level: u8); + fn v8__Isolate__ClearKeptObjects(isolate: *mut RealIsolate); + fn v8__Isolate__LowMemoryNotification(isolate: *mut RealIsolate); fn v8__Isolate__GetHeapStatistics( - this: *mut Isolate, + this: *mut RealIsolate, s: *mut v8__HeapStatistics, ); fn v8__Isolate__SetCaptureStackTraceForUncaughtExceptions( - this: *mut Isolate, + this: *mut RealIsolate, capture: bool, frame_limit: i32, ); fn v8__Isolate__AddMessageListener( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: MessageCallback, ) -> bool; fn v8__Isolate__AddMessageListenerWithErrorLevel( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: MessageCallback, message_levels: MessageErrorLevel, ) -> bool; fn v8__Isolate__AddGCPrologueCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: GcCallbackWithData, data: *mut c_void, gc_type_filter: GCType, ); fn v8__Isolate__RemoveGCPrologueCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: GcCallbackWithData, data: *mut c_void, ); fn v8__Isolate__AddGCEpilogueCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: GcCallbackWithData, data: *mut c_void, gc_type_filter: GCType, ); fn v8__Isolate__RemoveGCEpilogueCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: GcCallbackWithData, data: *mut c_void, ); - fn v8__Isolate__NumberOfHeapSpaces(isolate: *mut Isolate) -> size_t; + fn v8__Isolate__NumberOfHeapSpaces(isolate: *mut RealIsolate) -> size_t; fn v8__Isolate__GetHeapSpaceStatistics( - isolate: *mut Isolate, + isolate: *mut RealIsolate, space_statistics: *mut v8__HeapSpaceStatistics, index: size_t, ) -> bool; fn v8__Isolate__AddNearHeapLimitCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: NearHeapLimitCallback, data: *mut c_void, ); fn v8__Isolate__RemoveNearHeapLimitCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: NearHeapLimitCallback, heap_limit: usize, ); fn v8__Isolate__SetOOMErrorHandler( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: OomErrorCallback, ); fn v8__Isolate__AdjustAmountOfExternalAllocatedMemory( - isolate: *mut Isolate, + isolate: *mut RealIsolate, change_in_bytes: i64, ) -> i64; - fn v8__Isolate__GetCppHeap(isolate: *mut Isolate) -> *mut Heap; + fn v8__Isolate__GetCppHeap(isolate: *mut RealIsolate) -> *mut Heap; fn v8__Isolate__SetPrepareStackTraceCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: PrepareStackTraceCallback, ); - fn v8__Isolate__SetPromiseHook(isolate: *mut Isolate, hook: PromiseHook); + fn v8__Isolate__SetPromiseHook(isolate: *mut RealIsolate, hook: PromiseHook); fn v8__Isolate__SetPromiseRejectCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: PromiseRejectCallback, ); fn v8__Isolate__SetWasmAsyncResolvePromiseCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: WasmAsyncResolvePromiseCallback, ); fn v8__Isolate__SetAllowWasmCodeGenerationCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: AllowWasmCodeGenerationCallback, ); fn v8__Isolate__SetHostInitializeImportMetaObjectCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: HostInitializeImportMetaObjectCallback, ); fn v8__Isolate__SetHostImportModuleDynamicallyCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: RawHostImportModuleDynamicallyCallback, ); fn v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: RawHostImportModuleWithPhaseDynamicallyCallback, ); #[cfg(not(target_os = "windows"))] fn v8__Isolate__SetHostCreateShadowRealmContextCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: unsafe extern "C" fn( initiator_context: Local, ) -> *mut Context, ); #[cfg(target_os = "windows")] fn v8__Isolate__SetHostCreateShadowRealmContextCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: unsafe extern "C" fn( rv: *mut *mut Context, initiator_context: Local, ) -> *mut *mut Context, ); fn v8__Isolate__SetUseCounterCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: UseCounterCallback, ); fn v8__Isolate__RequestInterrupt( - isolate: *const Isolate, + isolate: *const RealIsolate, callback: InterruptCallback, data: *mut c_void, ); - fn v8__Isolate__TerminateExecution(isolate: *const Isolate); - fn v8__Isolate__IsExecutionTerminating(isolate: *const Isolate) -> bool; - fn v8__Isolate__CancelTerminateExecution(isolate: *const Isolate); + fn v8__Isolate__TerminateExecution(isolate: *const RealIsolate); + fn v8__Isolate__IsExecutionTerminating(isolate: *const RealIsolate) -> bool; + fn v8__Isolate__CancelTerminateExecution(isolate: *const RealIsolate); fn v8__Isolate__GetMicrotasksPolicy( - isolate: *const Isolate, + isolate: *const RealIsolate, ) -> MicrotasksPolicy; fn v8__Isolate__SetMicrotasksPolicy( - isolate: *mut Isolate, + isolate: *mut RealIsolate, policy: MicrotasksPolicy, ); - fn v8__Isolate__PerformMicrotaskCheckpoint(isolate: *mut Isolate); + fn v8__Isolate__PerformMicrotaskCheckpoint(isolate: *mut RealIsolate); fn v8__Isolate__EnqueueMicrotask( - isolate: *mut Isolate, + isolate: *mut RealIsolate, function: *const Function, ); - fn v8__Isolate__SetAllowAtomicsWait(isolate: *mut Isolate, allow: bool); + fn v8__Isolate__SetAllowAtomicsWait(isolate: *mut RealIsolate, allow: bool); fn v8__Isolate__SetWasmStreamingCallback( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: unsafe extern "C" fn(*const FunctionCallbackInfo), ); fn v8__Isolate__DateTimeConfigurationChangeNotification( - isolate: *mut Isolate, + isolate: *mut RealIsolate, time_zone_detection: TimeZoneDetection, ); - fn v8__Isolate__HasPendingBackgroundTasks(isolate: *const Isolate) -> bool; + fn v8__Isolate__HasPendingBackgroundTasks( + isolate: *const RealIsolate, + ) -> bool; fn v8__Isolate__RequestGarbageCollectionForTesting( - isolate: *mut Isolate, + isolate: *mut RealIsolate, r#type: usize, ); fn v8__HeapProfiler__TakeHeapSnapshot( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: unsafe extern "C" fn(*mut c_void, *const u8, usize) -> bool, arg: *mut c_void, ); @@ -766,29 +775,124 @@ unsafe extern "C" { /// rusty_v8 note: Unlike in the C++ API, the Isolate is entered when it is /// constructed and exited when dropped. Because of that v8::OwnedIsolate /// instances must be dropped in the reverse order of creation -#[repr(C)] +#[repr(transparent)] #[derive(Debug)] -pub struct Isolate(Opaque); +pub struct Isolate(NonNull); + +#[repr(transparent)] +#[derive(Debug, Clone, Copy)] +pub struct UnsafeRawIsolatePtr(*mut RealIsolate); + +impl UnsafeRawIsolatePtr { + pub fn null() -> Self { + Self(std::ptr::null_mut()) + } + + pub fn is_null(&self) -> bool { + self.0.is_null() + } +} + +#[repr(C)] +pub struct RealIsolate(Opaque); impl Isolate { + pub(crate) fn as_real_ptr(&self) -> *mut RealIsolate { + self.0.as_ptr() + } + + pub unsafe fn as_raw_isolate_ptr(&self) -> UnsafeRawIsolatePtr { + UnsafeRawIsolatePtr(self.0.as_ptr()) + } + + #[inline] + pub unsafe fn from_raw_isolate_ptr(ptr: UnsafeRawIsolatePtr) -> Self { + Self(NonNull::new(ptr.0).unwrap()) + } + + #[inline] + pub unsafe fn from_raw_isolate_ptr_unchecked( + ptr: UnsafeRawIsolatePtr, + ) -> Self { + Self(unsafe { NonNull::new_unchecked(ptr.0) }) + } + + pub unsafe fn from_raw_ptr_unchecked(ptr: *mut RealIsolate) -> Self { + Self(unsafe { NonNull::new_unchecked(ptr) }) + } + + pub unsafe fn from_raw_ptr(ptr: *mut RealIsolate) -> Self { + Self(NonNull::new(ptr).unwrap()) + } + + #[inline] + pub unsafe fn ref_from_raw_isolate_ptr(ptr: &UnsafeRawIsolatePtr) -> &Self { + if ptr.is_null() { + panic!("UnsafeRawIsolatePtr is null"); + } + unsafe { &*(ptr as *const UnsafeRawIsolatePtr as *const Isolate) } + } + + #[inline] + pub unsafe fn ref_from_raw_isolate_ptr_unchecked( + ptr: &UnsafeRawIsolatePtr, + ) -> &Self { + unsafe { &*(ptr as *const UnsafeRawIsolatePtr as *const Isolate) } + } + + #[inline] + pub unsafe fn ref_from_raw_isolate_ptr_mut( + ptr: &mut UnsafeRawIsolatePtr, + ) -> &mut Self { + if ptr.is_null() { + panic!("UnsafeRawIsolatePtr is null"); + } + unsafe { &mut *(ptr as *mut UnsafeRawIsolatePtr as *mut Isolate) } + } + + #[inline] + pub unsafe fn ref_from_raw_isolate_ptr_mut_unchecked( + ptr: &mut UnsafeRawIsolatePtr, + ) -> &mut Self { + unsafe { &mut *(ptr as *mut UnsafeRawIsolatePtr as *mut Isolate) } + } + + #[inline] + pub(crate) unsafe fn from_non_null(ptr: NonNull) -> Self { + Self(ptr) + } + + #[inline] + pub(crate) unsafe fn from_raw_ref(ptr: &NonNull) -> &Self { + // SAFETY: Isolate is a repr(transparent) wrapper around NonNull + unsafe { &*(ptr as *const NonNull as *const Isolate) } + } + + #[inline] + pub(crate) unsafe fn from_raw_ref_mut( + ptr: &mut NonNull, + ) -> &mut Self { + // SAFETY: Isolate is a repr(transparent) wrapper around NonNull + unsafe { &mut *(ptr as *mut NonNull as *mut Isolate) } + } + // Isolate data slots used internally by rusty_v8. const ANNEX_SLOT: u32 = 0; - const CURRENT_SCOPE_DATA_SLOT: u32 = 1; const INTERNAL_DATA_SLOT_COUNT: u32 = 2; #[inline(always)] fn assert_embedder_data_slot_count_and_offset_correct(&self) { assert!( - unsafe { v8__Isolate__GetNumberOfDataSlots(self) } + unsafe { v8__Isolate__GetNumberOfDataSlots(self.as_real_ptr()) } >= Self::INTERNAL_DATA_SLOT_COUNT ) } - fn new_impl(params: CreateParams) -> *mut Isolate { + fn new_impl(params: CreateParams) -> *mut RealIsolate { crate::V8::assert_initialized(); let (raw_create_params, create_param_allocations) = params.finalize(); let cxx_isolate = unsafe { v8__Isolate__New(&raw_create_params) }; - let isolate = unsafe { &mut *cxx_isolate }; + let mut isolate = unsafe { Isolate::from_raw_ptr(cxx_isolate) }; isolate.initialize(create_param_allocations); cxx_isolate } @@ -957,46 +1061,46 @@ impl Isolate { /// Returns the maximum number of available embedder data slots. Valid slots /// are in the range of `0 <= n < Isolate::get_number_of_data_slots()`. pub fn get_number_of_data_slots(&self) -> u32 { - let n = unsafe { v8__Isolate__GetNumberOfDataSlots(self) }; + let n = unsafe { v8__Isolate__GetNumberOfDataSlots(self.as_real_ptr()) }; n - Self::INTERNAL_DATA_SLOT_COUNT } #[inline(always)] pub(crate) fn get_data_internal(&self, slot: u32) -> *mut c_void { - unsafe { v8__Isolate__GetData(self, slot) } + unsafe { v8__Isolate__GetData(self.as_real_ptr(), slot) } } #[inline(always)] pub(crate) fn set_data_internal(&mut self, slot: u32, data: *mut c_void) { - unsafe { v8__Isolate__SetData(self, slot, data) } - } - - pub(crate) fn init_scope_root(&mut self) { - ScopeData::new_root(self); - } - - pub(crate) fn dispose_scope_root(&mut self) { - ScopeData::drop_root(self); - } - - /// Returns a pointer to the `ScopeData` struct for the current scope. - #[inline(always)] - pub(crate) fn get_current_scope_data(&self) -> Option> { - let scope_data_ptr = self.get_data_internal(Self::CURRENT_SCOPE_DATA_SLOT); - NonNull::new(scope_data_ptr).map(NonNull::cast) - } - - /// Updates the slot that stores a `ScopeData` pointer for the current scope. - #[inline(always)] - pub(crate) fn set_current_scope_data( - &mut self, - scope_data: Option>, - ) { - let scope_data_ptr = scope_data - .map(NonNull::cast) - .map_or_else(null_mut, NonNull::as_ptr); - self.set_data_internal(Self::CURRENT_SCOPE_DATA_SLOT, scope_data_ptr); - } + unsafe { v8__Isolate__SetData(self.as_real_ptr(), slot, data) } + } + + // pub(crate) fn init_scope_root(&mut self) { + // ScopeData::new_root(self); + // } + + // pub(crate) fn dispose_scope_root(&mut self) { + // ScopeData::drop_root(self); + // } + + // /// Returns a pointer to the `ScopeData` struct for the current scope. + // #[inline(always)] + // pub(crate) fn get_current_scope_data(&self) -> Option> { + // let scope_data_ptr = self.get_data_internal(Self::CURRENT_SCOPE_DATA_SLOT); + // NonNull::new(scope_data_ptr).map(NonNull::cast) + // } + + // /// Updates the slot that stores a `ScopeData` pointer for the current scope. + // #[inline(always)] + // pub(crate) fn set_current_scope_data( + // &mut self, + // scope_data: Option>, + // ) { + // let scope_data_ptr = scope_data + // .map(NonNull::cast) + // .map_or_else(null_mut, NonNull::as_ptr); + // self.set_data_internal(Self::CURRENT_SCOPE_DATA_SLOT, scope_data_ptr); + // } /// Get a reference to embedder data added with `set_slot()`. #[inline(always)] @@ -1055,9 +1159,9 @@ impl Isolate { /// rusty_v8 note: Unlike in the C++ API, the isolate is entered when it is /// constructed and exited when dropped. #[inline(always)] - pub unsafe fn enter(&mut self) { + pub unsafe fn enter(&self) { unsafe { - v8__Isolate__Enter(self); + v8__Isolate__Enter(self.as_real_ptr()); } } @@ -1070,9 +1174,9 @@ impl Isolate { /// rusty_v8 note: Unlike in the C++ API, the isolate is entered when it is /// constructed and exited when dropped. #[inline(always)] - pub unsafe fn exit(&mut self) { + pub unsafe fn exit(&self) { unsafe { - v8__Isolate__Exit(self); + v8__Isolate__Exit(self.as_real_ptr()); } } @@ -1082,7 +1186,9 @@ impl Isolate { /// the isolate is executing long running JavaScript code. #[inline(always)] pub fn memory_pressure_notification(&mut self, level: MemoryPressureLevel) { - unsafe { v8__Isolate__MemoryPressureNotification(self, level as u8) } + unsafe { + v8__Isolate__MemoryPressureNotification(self.as_real_ptr(), level as u8) + } } /// Clears the set of objects held strongly by the heap. This set of @@ -1098,14 +1204,14 @@ impl Isolate { /// time which does not interrupt synchronous ECMAScript code execution. #[inline(always)] pub fn clear_kept_objects(&mut self) { - unsafe { v8__Isolate__ClearKeptObjects(self) } + unsafe { v8__Isolate__ClearKeptObjects(self.as_real_ptr()) } } /// Optional notification that the system is running low on memory. /// V8 uses these notifications to attempt to free memory. #[inline(always)] pub fn low_memory_notification(&mut self) { - unsafe { v8__Isolate__LowMemoryNotification(self) } + unsafe { v8__Isolate__LowMemoryNotification(self.as_real_ptr()) } } /// Get statistics about the heap memory usage. @@ -1113,7 +1219,7 @@ impl Isolate { pub fn get_heap_statistics(&mut self) -> HeapStatistics { let inner = unsafe { let mut s = MaybeUninit::zeroed(); - v8__Isolate__GetHeapStatistics(self, s.as_mut_ptr()); + v8__Isolate__GetHeapStatistics(self.as_real_ptr(), s.as_mut_ptr()); s.assume_init() }; HeapStatistics(inner) @@ -1122,7 +1228,7 @@ impl Isolate { /// Returns the number of spaces in the heap. #[inline(always)] pub fn number_of_heap_spaces(&mut self) -> usize { - unsafe { v8__Isolate__NumberOfHeapSpaces(self) } + unsafe { v8__Isolate__NumberOfHeapSpaces(self.as_real_ptr()) } } /// Get the memory usage of a space in the heap. @@ -1139,7 +1245,11 @@ impl Isolate { ) -> Option { let inner = unsafe { let mut s = MaybeUninit::zeroed(); - if !v8__Isolate__GetHeapSpaceStatistics(self, s.as_mut_ptr(), index) { + if !v8__Isolate__GetHeapSpaceStatistics( + self.as_real_ptr(), + s.as_mut_ptr(), + index, + ) { return None; } s.assume_init() @@ -1157,7 +1267,7 @@ impl Isolate { ) { unsafe { v8__Isolate__SetCaptureStackTraceForUncaughtExceptions( - self, + self.as_real_ptr(), capture, frame_limit, ); @@ -1172,7 +1282,7 @@ impl Isolate { /// The exception object will be passed to the callback. #[inline(always)] pub fn add_message_listener(&mut self, callback: MessageCallback) -> bool { - unsafe { v8__Isolate__AddMessageListener(self, callback) } + unsafe { v8__Isolate__AddMessageListener(self.as_real_ptr(), callback) } } /// Adds a message listener for the specified message levels. @@ -1184,7 +1294,7 @@ impl Isolate { ) -> bool { unsafe { v8__Isolate__AddMessageListenerWithErrorLevel( - self, + self.as_real_ptr(), callback, message_levels, ) @@ -1208,7 +1318,10 @@ impl Isolate { // it's empty. That is, you can't return None and that's why the Rust API // expects Local instead of Option>. unsafe { - v8__Isolate__SetPrepareStackTraceCallback(self, callback.map_fn_to()); + v8__Isolate__SetPrepareStackTraceCallback( + self.as_real_ptr(), + callback.map_fn_to(), + ); }; } @@ -1216,7 +1329,7 @@ impl Isolate { /// events. #[inline(always)] pub fn set_promise_hook(&mut self, hook: PromiseHook) { - unsafe { v8__Isolate__SetPromiseHook(self, hook) } + unsafe { v8__Isolate__SetPromiseHook(self.as_real_ptr(), hook) } } /// Set callback to notify about promise reject with no handler, or @@ -1226,7 +1339,9 @@ impl Isolate { &mut self, callback: PromiseRejectCallback, ) { - unsafe { v8__Isolate__SetPromiseRejectCallback(self, callback) } + unsafe { + v8__Isolate__SetPromiseRejectCallback(self.as_real_ptr(), callback) + } } #[inline(always)] @@ -1234,7 +1349,12 @@ impl Isolate { &mut self, callback: WasmAsyncResolvePromiseCallback, ) { - unsafe { v8__Isolate__SetWasmAsyncResolvePromiseCallback(self, callback) } + unsafe { + v8__Isolate__SetWasmAsyncResolvePromiseCallback( + self.as_real_ptr(), + callback, + ) + } } #[inline(always)] @@ -1243,7 +1363,10 @@ impl Isolate { callback: AllowWasmCodeGenerationCallback, ) { unsafe { - v8__Isolate__SetAllowWasmCodeGenerationCallback(self, callback); + v8__Isolate__SetAllowWasmCodeGenerationCallback( + self.as_real_ptr(), + callback, + ); } } @@ -1255,7 +1378,10 @@ impl Isolate { callback: HostInitializeImportMetaObjectCallback, ) { unsafe { - v8__Isolate__SetHostInitializeImportMetaObjectCallback(self, callback); + v8__Isolate__SetHostInitializeImportMetaObjectCallback( + self.as_real_ptr(), + callback, + ); } } @@ -1268,7 +1394,7 @@ impl Isolate { ) { unsafe { v8__Isolate__SetHostImportModuleDynamicallyCallback( - self, + self.as_real_ptr(), callback.to_c_fn(), ); } @@ -1288,7 +1414,7 @@ impl Isolate { ) { unsafe { v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback( - self, + self.as_real_ptr(), callback.to_c_fn(), ); } @@ -1304,8 +1430,10 @@ impl Isolate { unsafe extern "C" fn rust_shadow_realm_callback( initiator_context: Local, ) -> *mut Context { - let mut scope = unsafe { CallbackScope::new(initiator_context) }; - let callback = scope + let scope = pin!(unsafe { CallbackScope::new(initiator_context) }); + let mut scope = scope.init(); + let isolate = scope.as_ref(); + let callback = isolate .get_slot::() .unwrap(); let context = callback(&mut scope); @@ -1330,12 +1458,12 @@ impl Isolate { unsafe { #[cfg(target_os = "windows")] v8__Isolate__SetHostCreateShadowRealmContextCallback( - self, + self.as_real_ptr(), rust_shadow_realm_callback_windows, ); #[cfg(not(target_os = "windows"))] v8__Isolate__SetHostCreateShadowRealmContextCallback( - self, + self.as_real_ptr(), rust_shadow_realm_callback, ); } @@ -1346,7 +1474,7 @@ impl Isolate { #[inline(always)] pub fn set_use_counter_callback(&mut self, callback: UseCounterCallback) { unsafe { - v8__Isolate__SetUseCounterCallback(self, callback); + v8__Isolate__SetUseCounterCallback(self.as_real_ptr(), callback); } } @@ -1366,7 +1494,12 @@ impl Isolate { gc_type_filter: GCType, ) { unsafe { - v8__Isolate__AddGCPrologueCallback(self, callback, data, gc_type_filter); + v8__Isolate__AddGCPrologueCallback( + self.as_real_ptr(), + callback, + data, + gc_type_filter, + ); } } @@ -1379,7 +1512,9 @@ impl Isolate { callback: GcCallbackWithData, data: *mut c_void, ) { - unsafe { v8__Isolate__RemoveGCPrologueCallback(self, callback, data) } + unsafe { + v8__Isolate__RemoveGCPrologueCallback(self.as_real_ptr(), callback, data) + } } /// Enables the host application to receive a notification after a @@ -1393,7 +1528,12 @@ impl Isolate { gc_type_filter: GCType, ) { unsafe { - v8__Isolate__AddGCEpilogueCallback(self, callback, data, gc_type_filter); + v8__Isolate__AddGCEpilogueCallback( + self.as_real_ptr(), + callback, + data, + gc_type_filter, + ); } } @@ -1406,7 +1546,9 @@ impl Isolate { callback: GcCallbackWithData, data: *mut c_void, ) { - unsafe { v8__Isolate__RemoveGCEpilogueCallback(self, callback, data) } + unsafe { + v8__Isolate__RemoveGCEpilogueCallback(self.as_real_ptr(), callback, data) + } } /// Add a callback to invoke in case the heap size is close to the heap limit. @@ -1419,7 +1561,9 @@ impl Isolate { callback: NearHeapLimitCallback, data: *mut c_void, ) { - unsafe { v8__Isolate__AddNearHeapLimitCallback(self, callback, data) }; + unsafe { + v8__Isolate__AddNearHeapLimitCallback(self.as_real_ptr(), callback, data) + }; } /// Remove the given callback and restore the heap limit to the given limit. @@ -1433,7 +1577,11 @@ impl Isolate { heap_limit: usize, ) { unsafe { - v8__Isolate__RemoveNearHeapLimitCallback(self, callback, heap_limit); + v8__Isolate__RemoveNearHeapLimitCallback( + self.as_real_ptr(), + callback, + heap_limit, + ); }; } @@ -1450,30 +1598,33 @@ impl Isolate { change_in_bytes: i64, ) -> i64 { unsafe { - v8__Isolate__AdjustAmountOfExternalAllocatedMemory(self, change_in_bytes) + v8__Isolate__AdjustAmountOfExternalAllocatedMemory( + self.as_real_ptr(), + change_in_bytes, + ) } } #[inline(always)] pub fn get_cpp_heap(&mut self) -> Option<&Heap> { - unsafe { v8__Isolate__GetCppHeap(self).as_ref() } + unsafe { v8__Isolate__GetCppHeap(self.as_real_ptr()).as_ref() } } #[inline(always)] pub fn set_oom_error_handler(&mut self, callback: OomErrorCallback) { - unsafe { v8__Isolate__SetOOMErrorHandler(self, callback) }; + unsafe { v8__Isolate__SetOOMErrorHandler(self.as_real_ptr(), callback) }; } /// Returns the policy controlling how Microtasks are invoked. #[inline(always)] pub fn get_microtasks_policy(&self) -> MicrotasksPolicy { - unsafe { v8__Isolate__GetMicrotasksPolicy(self) } + unsafe { v8__Isolate__GetMicrotasksPolicy(self.as_real_ptr()) } } /// Returns the policy controlling how Microtasks are invoked. #[inline(always)] pub fn set_microtasks_policy(&mut self, policy: MicrotasksPolicy) { - unsafe { v8__Isolate__SetMicrotasksPolicy(self, policy) } + unsafe { v8__Isolate__SetMicrotasksPolicy(self.as_real_ptr(), policy) } } /// Runs the default MicrotaskQueue until it gets empty and perform other @@ -1482,13 +1633,13 @@ impl Isolate { /// callbacks are swallowed. #[inline(always)] pub fn perform_microtask_checkpoint(&mut self) { - unsafe { v8__Isolate__PerformMicrotaskCheckpoint(self) } + unsafe { v8__Isolate__PerformMicrotaskCheckpoint(self.as_real_ptr()) } } /// Enqueues the callback to the default MicrotaskQueue #[inline(always)] pub fn enqueue_microtask(&mut self, microtask: Local) { - unsafe { v8__Isolate__EnqueueMicrotask(self, &*microtask) } + unsafe { v8__Isolate__EnqueueMicrotask(self.as_real_ptr(), &*microtask) } } /// Set whether calling Atomics.wait (a function that may block) is allowed in @@ -1496,7 +1647,7 @@ impl Isolate { /// CreateParams::allow_atomics_wait. #[inline(always)] pub fn set_allow_atomics_wait(&mut self, allow: bool) { - unsafe { v8__Isolate__SetAllowAtomicsWait(self, allow) } + unsafe { v8__Isolate__SetAllowAtomicsWait(self.as_real_ptr(), allow) } } /// Embedder injection point for `WebAssembly.compileStreaming(source)`. @@ -1509,9 +1660,14 @@ impl Isolate { #[inline(always)] pub fn set_wasm_streaming_callback(&mut self, _: F) where - F: UnitType + Fn(&mut HandleScope, Local, WasmStreaming), + F: UnitType + Fn(&mut PinScope, Local, WasmStreaming), { - unsafe { v8__Isolate__SetWasmStreamingCallback(self, trampoline::()) } + unsafe { + v8__Isolate__SetWasmStreamingCallback( + self.as_real_ptr(), + trampoline::(), + ) + } } /// Notification that the embedder has changed the time zone, daylight savings @@ -1529,7 +1685,7 @@ impl Isolate { ) { unsafe { v8__Isolate__DateTimeConfigurationChangeNotification( - self, + self.as_real_ptr(), time_zone_detection, ); } @@ -1540,7 +1696,7 @@ impl Isolate { /// compilation. #[inline(always)] pub fn has_pending_background_tasks(&self) -> bool { - unsafe { v8__Isolate__HasPendingBackgroundTasks(self) } + unsafe { v8__Isolate__HasPendingBackgroundTasks(self.as_real_ptr()) } } /// Request garbage collection with a specific embedderstack state in this @@ -1559,7 +1715,7 @@ impl Isolate { ) { unsafe { v8__Isolate__RequestGarbageCollectionForTesting( - self, + self.as_real_ptr(), match r#type { GarbageCollectionType::Full => 0, GarbageCollectionType::Minor => 1, @@ -1574,7 +1730,7 @@ impl Isolate { // No test case in rusty_v8 show this, but there have been situations in // deno where dropping Annex before the states causes a segfault. unsafe { - v8__Isolate__Dispose(self); + v8__Isolate__Dispose(self.as_real_ptr()); } } @@ -1608,7 +1764,11 @@ impl Isolate { let arg = addr_of_mut!(callback); unsafe { - v8__HeapProfiler__TakeHeapSnapshot(self, trampoline::, arg as _); + v8__HeapProfiler__TakeHeapSnapshot( + self.as_real_ptr(), + trampoline::, + arg as _, + ); } } @@ -1706,7 +1866,7 @@ pub(crate) struct IsolateAnnex { // before the isolate is disposed. // - Any other thread must lock the mutex while it's reading/using the // `isolate` pointer. - isolate: *mut Isolate, + isolate: *mut RealIsolate, isolate_mutex: Mutex<()>, } @@ -1723,7 +1883,7 @@ impl IsolateAnnex { slots: HashMap::default(), finalizer_map: FinalizerMap::default(), maybe_snapshot_creator: None, - isolate, + isolate: isolate.as_real_ptr(), isolate_mutex: Mutex::new(()), } } @@ -1751,7 +1911,7 @@ impl IsolateHandle { // This function is marked unsafe because it must be called only with either // IsolateAnnex::mutex locked, or from the main thread associated with the V8 // isolate. - pub(crate) unsafe fn get_isolate_ptr(&self) -> *mut Isolate { + pub(crate) unsafe fn get_isolate_ptr(&self) -> *mut RealIsolate { self.0.isolate } @@ -1851,22 +2011,22 @@ impl IsolateHandle { /// Same as Isolate but gets disposed when it goes out of scope. #[derive(Debug)] pub struct OwnedIsolate { - cxx_isolate: NonNull, + cxx_isolate: NonNull, } impl OwnedIsolate { - pub(crate) fn new(cxx_isolate: *mut Isolate) -> Self { - let mut isolate = Self::new_already_entered(cxx_isolate); + pub(crate) fn new(cxx_isolate: *mut RealIsolate) -> Self { + let isolate = Self::new_already_entered(cxx_isolate); unsafe { isolate.enter(); } isolate } - pub(crate) fn new_already_entered(cxx_isolate: *mut Isolate) -> Self { + pub(crate) fn new_already_entered(cxx_isolate: *mut RealIsolate) -> Self { let cxx_isolate = NonNull::new(cxx_isolate).unwrap(); - let mut owned_isolate = Self { cxx_isolate }; - owned_isolate.init_scope_root(); + let owned_isolate: OwnedIsolate = Self { cxx_isolate }; + // owned_isolate.init_scope_root(); owned_isolate } } @@ -1881,10 +2041,11 @@ impl Drop for OwnedIsolate { ); // Safety: We need to check `this == Isolate::GetCurrent()` before calling exit() assert!( - self.cxx_isolate.as_mut() as *mut Isolate == v8__Isolate__GetCurrent(), + self.cxx_isolate.as_mut() as *mut RealIsolate + == v8__Isolate__GetCurrent(), "v8::OwnedIsolate instances must be dropped in the reverse order of creation. They are entered upon creation and exited upon being dropped." ); - self.dispose_scope_root(); + // self.dispose_scope_root(); self.exit(); self.dispose_annex(); Platform::notify_isolate_shutdown(&get_current_platform(), self); @@ -1911,7 +2072,7 @@ impl OwnedIsolate { // create_param_allocations is needed during CreateBlob // so v8 can read external references let _create_param_allocations = unsafe { - self.dispose_scope_root(); + // self.dispose_scope_root(); self.dispose_annex() }; @@ -1925,13 +2086,19 @@ impl OwnedIsolate { impl Deref for OwnedIsolate { type Target = Isolate; fn deref(&self) -> &Self::Target { - unsafe { self.cxx_isolate.as_ref() } + unsafe { + std::mem::transmute::<&NonNull, &Isolate>(&self.cxx_isolate) + } } } impl DerefMut for OwnedIsolate { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { self.cxx_isolate.as_mut() } + unsafe { + std::mem::transmute::<&mut NonNull, &mut Isolate>( + &mut self.cxx_isolate, + ) + } } } @@ -2054,8 +2221,8 @@ impl HeapSpaceStatistics { impl<'s, F> MapFnFrom for PrepareStackTraceCallback<'s> where F: UnitType - + Fn( - &mut HandleScope<'s>, + + for<'a> Fn( + &mut PinScope<'s, 'a>, Local<'s, Value>, Local<'s, Array>, ) -> Local<'s, Value>, @@ -2064,7 +2231,8 @@ where #[cfg(target_os = "windows")] fn mapping() -> Self { let f = |ret_ptr, context, error, sites| { - let mut scope: CallbackScope = unsafe { CallbackScope::new(context) }; + let scope = pin!(unsafe { CallbackScope::new(context) }); + let mut scope: crate::PinnedRef = scope.init(); let r = (F::get())(&mut scope, error, sites); unsafe { std::ptr::write(ret_ptr, &*r as *const _) }; ret_ptr @@ -2076,7 +2244,9 @@ where #[cfg(not(target_os = "windows"))] fn mapping() -> Self { let f = |context, error, sites| { - let mut scope: CallbackScope = unsafe { CallbackScope::new(context) }; + let scope = pin!(unsafe { CallbackScope::new(context) }); + let mut scope: crate::PinnedRef = scope.init(); + let r = (F::get())(&mut scope, error, sites); PrepareStackTraceCallbackRet(&*r as *const _) }; @@ -2232,3 +2402,14 @@ impl Drop for RawSlot { } } } + +impl AsRef for OwnedIsolate { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.cxx_isolate) } + } +} +impl AsRef for Isolate { + fn as_ref(&self) -> &Isolate { + self + } +} diff --git a/src/json.rs b/src/json.rs index 72492c6f15..cc3870433d 100644 --- a/src/json.rs +++ b/src/json.rs @@ -1,10 +1,11 @@ // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. //! A JSON Parser and Stringifier. + use crate::Context; -use crate::HandleScope; use crate::Local; use crate::String; use crate::Value; +use crate::scope::PinScope; unsafe extern "C" { fn v8__JSON__Parse( @@ -21,7 +22,7 @@ unsafe extern "C" { /// successful. #[inline(always)] pub fn parse<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, json_string: Local<'_, String>, ) -> Option> { unsafe { @@ -34,7 +35,7 @@ pub fn parse<'s>( /// it as string if successful. #[inline(always)] pub fn stringify<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, json_object: Local<'_, Value>, ) -> Option> { unsafe { diff --git a/src/lib.rs b/src/lib.rs index da3d3209c8..8e8ee93068 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,8 @@ //! //! let isolate = &mut v8::Isolate::new(Default::default()); //! -//! let scope = &mut v8::HandleScope::new(isolate); +//! let scope = std::pin::pin!(v8::HandleScope::new(isolate)); +//! let scope = &mut scope.init(); //! let context = v8::Context::new(scope, Default::default()); //! let scope = &mut v8::ContextScope::new(scope, context); //! @@ -125,6 +126,7 @@ pub use isolate::OwnedIsolate; pub use isolate::PromiseHook; pub use isolate::PromiseHookType; pub use isolate::PromiseRejectCallback; +pub use isolate::RealIsolate; pub use isolate::TimeZoneDetection; pub use isolate::UseCounterCallback; pub use isolate::UseCounterFeature; @@ -145,10 +147,17 @@ pub use property_filter::*; pub use property_handler_flags::*; pub use regexp::RegExpCreationFlags; pub use scope::AllowJavascriptExecutionScope; +// pub use scope::CallbackScope; pub use scope::CallbackScope; pub use scope::ContextScope; pub use scope::DisallowJavascriptExecutionScope; pub use scope::EscapableHandleScope; +pub use scope::PinCallbackScope; +pub use scope::PinScope; +pub use scope::PinnedRef; +pub use scope::ScopeStorage; +// pub use scope::HandleScope; +pub use isolate::UnsafeRawIsolatePtr; pub use scope::HandleScope; pub use scope::OnFailure; pub use scope::TryCatch; @@ -200,6 +209,7 @@ pub const TYPED_ARRAY_MAX_SIZE_IN_HEAP: usize = binding::v8__TYPED_ARRAY_MAX_SIZE_IN_HEAP as _; #[cfg(test)] +#[allow(unused)] pub(crate) fn initialize_v8() { use std::sync::Once; diff --git a/src/microtask.rs b/src/microtask.rs index e1eb052e88..6a69b75f8d 100644 --- a/src/microtask.rs +++ b/src/microtask.rs @@ -5,17 +5,18 @@ use crate::Isolate; use crate::Local; use crate::MicrotasksPolicy; use crate::UniqueRef; +use crate::isolate::RealIsolate; use crate::support::Opaque; use crate::support::int; unsafe extern "C" { fn v8__MicrotaskQueue__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, policy: MicrotasksPolicy, ) -> *mut MicrotaskQueue; fn v8__MicrotaskQueue__DESTRUCT(queue: *mut MicrotaskQueue); fn v8__MicrotaskQueue__PerformCheckpoint( - isolate: *mut Isolate, + isolate: *mut RealIsolate, queue: *const MicrotaskQueue, ); fn v8__MicrotaskQueue__IsRunningMicrotasks( @@ -25,7 +26,7 @@ unsafe extern "C" { queue: *const MicrotaskQueue, ) -> int; fn v8__MicrotaskQueue__EnqueueMicrotask( - isolate: *mut Isolate, + isolate: *mut RealIsolate, queue: *const MicrotaskQueue, microtask: *const Function, ); @@ -53,7 +54,12 @@ impl MicrotaskQueue { isolate: &mut Isolate, policy: MicrotasksPolicy, ) -> UniqueRef { - unsafe { UniqueRef::from_raw(v8__MicrotaskQueue__New(isolate, policy)) } + unsafe { + UniqueRef::from_raw(v8__MicrotaskQueue__New( + isolate.as_real_ptr(), + policy, + )) + } } pub fn enqueue_microtask( @@ -61,7 +67,13 @@ impl MicrotaskQueue { isolate: &mut Isolate, microtask: Local, ) { - unsafe { v8__MicrotaskQueue__EnqueueMicrotask(isolate, self, &*microtask) } + unsafe { + v8__MicrotaskQueue__EnqueueMicrotask( + isolate.as_real_ptr(), + self, + &*microtask, + ) + } } /// Adds a callback to notify the embedder after microtasks were run. The @@ -76,7 +88,7 @@ impl MicrotaskQueue { /// the callback. pub fn perform_checkpoint(&self, isolate: &mut Isolate) { unsafe { - v8__MicrotaskQueue__PerformCheckpoint(isolate, self); + v8__MicrotaskQueue__PerformCheckpoint(isolate.as_real_ptr(), self); } } diff --git a/src/module.rs b/src/module.rs index c8c97103ca..300e9906c0 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,8 +4,6 @@ use std::ptr::null; use crate::Context; use crate::FixedArray; -use crate::HandleScope; -use crate::Isolate; use crate::Local; use crate::Message; use crate::Module; @@ -14,6 +12,9 @@ use crate::Object; use crate::String; use crate::UnboundModuleScript; use crate::Value; +use crate::isolate::RealIsolate; +use crate::scope::GetIsolate; +use crate::scope::PinScope; use crate::support::MapFnFrom; use crate::support::MapFnTo; use crate::support::MaybeBool; @@ -30,11 +31,11 @@ use crate::support::int; /// /// ```rust,ignore /// fn my_resolve_callback<'a>( -/// context: v8::Local<'a, v8::Context>, -/// specifier: v8::Local<'a, v8::String>, -/// import_attributes: v8::Local<'a, v8::FixedArray>, -/// referrer: v8::Local<'a, v8::Module>, -/// ) -> Option> { +/// context: v8::Local<'s, v8::Context>, +/// specifier: v8::Local<'s, v8::String>, +/// import_attributes: v8::Local<'s, v8::FixedArray>, +/// referrer: v8::Local<'s, v8::Module>, +/// ) -> Option> { /// // ... /// Some(resolved_module) /// } @@ -45,34 +46,34 @@ use crate::support::int; pub struct ResolveModuleCallbackRet(*const Module); #[cfg(not(target_os = "windows"))] -pub type ResolveModuleCallback<'a> = +pub type ResolveModuleCallback<'s> = unsafe extern "C" fn( - Local<'a, Context>, - Local<'a, String>, - Local<'a, FixedArray>, - Local<'a, Module>, + Local<'s, Context>, + Local<'s, String>, + Local<'s, FixedArray>, + Local<'s, Module>, ) -> ResolveModuleCallbackRet; // Windows x64 ABI: Local returned on the stack. #[cfg(target_os = "windows")] -pub type ResolveModuleCallback<'a> = unsafe extern "C" fn( +pub type ResolveModuleCallback<'s> = unsafe extern "C" fn( *mut *const Module, - Local<'a, Context>, - Local<'a, String>, - Local<'a, FixedArray>, - Local<'a, Module>, + Local<'s, Context>, + Local<'s, String>, + Local<'s, FixedArray>, + Local<'s, Module>, ) -> *mut *const Module; -impl<'a, F> MapFnFrom for ResolveModuleCallback<'a> +impl<'s, F> MapFnFrom for ResolveModuleCallback<'s> where F: UnitType + Fn( - Local<'a, Context>, - Local<'a, String>, - Local<'a, FixedArray>, - Local<'a, Module>, - ) -> Option>, + Local<'s, Context>, + Local<'s, String>, + Local<'s, FixedArray>, + Local<'s, Module>, + ) -> Option>, { #[cfg(not(target_os = "windows"))] fn mapping() -> Self { @@ -105,25 +106,25 @@ where pub struct SyntheticModuleEvaluationStepsRet(*const Value); #[cfg(not(target_os = "windows"))] -pub type SyntheticModuleEvaluationSteps<'a> = +pub type SyntheticModuleEvaluationSteps<'s> = unsafe extern "C" fn( - Local<'a, Context>, - Local<'a, Module>, + Local<'s, Context>, + Local<'s, Module>, ) -> SyntheticModuleEvaluationStepsRet; // Windows x64 ABI: Local returned on the stack. #[cfg(target_os = "windows")] -pub type SyntheticModuleEvaluationSteps<'a> = +pub type SyntheticModuleEvaluationSteps<'s> = unsafe extern "C" fn( *mut *const Value, - Local<'a, Context>, - Local<'a, Module>, + Local<'s, Context>, + Local<'s, Module>, ) -> *mut *const Value; -impl<'a, F> MapFnFrom for SyntheticModuleEvaluationSteps<'a> +impl<'s, F> MapFnFrom for SyntheticModuleEvaluationSteps<'s> where F: UnitType - + Fn(Local<'a, Context>, Local<'a, Module>) -> Option>, + + Fn(Local<'s, Context>, Local<'s, Module>) -> Option>, { #[cfg(not(target_os = "windows"))] fn mapping() -> Self { @@ -154,34 +155,34 @@ where pub struct ResolveSourceCallbackRet(*const Object); #[cfg(not(target_os = "windows"))] -pub type ResolveSourceCallback<'a> = +pub type ResolveSourceCallback<'s> = unsafe extern "C" fn( - Local<'a, Context>, - Local<'a, String>, - Local<'a, FixedArray>, - Local<'a, Module>, + Local<'s, Context>, + Local<'s, String>, + Local<'s, FixedArray>, + Local<'s, Module>, ) -> ResolveSourceCallbackRet; // Windows x64 ABI: Local returned on the stack. #[cfg(target_os = "windows")] -pub type ResolveSourceCallback<'a> = unsafe extern "C" fn( +pub type ResolveSourceCallback<'s> = unsafe extern "C" fn( *mut *const Object, - Local<'a, Context>, - Local<'a, String>, - Local<'a, FixedArray>, - Local<'a, Module>, + Local<'s, Context>, + Local<'s, String>, + Local<'s, FixedArray>, + Local<'s, Module>, ) -> *mut *const Object; -impl<'a, F> MapFnFrom for ResolveSourceCallback<'a> +impl<'s, F> MapFnFrom for ResolveSourceCallback<'s> where F: UnitType + Fn( - Local<'a, Context>, - Local<'a, String>, - Local<'a, FixedArray>, - Local<'a, Module>, - ) -> Option>, + Local<'s, Context>, + Local<'s, String>, + Local<'s, FixedArray>, + Local<'s, Module>, + ) -> Option>, { #[cfg(not(target_os = "windows"))] fn mapping() -> Self { @@ -234,7 +235,7 @@ unsafe extern "C" { fn v8__Module__IsSourceTextModule(this: *const Module) -> bool; fn v8__Module__IsSyntheticModule(this: *const Module) -> bool; fn v8__Module__CreateSyntheticModule( - isolate: *const Isolate, + isolate: *const RealIsolate, module_name: *const String, export_names_len: usize, export_names_raw: *const *const String, @@ -242,7 +243,7 @@ unsafe extern "C" { ) -> *const Module; fn v8__Module__SetSyntheticModuleExport( this: *const Module, - isolate: *const Isolate, + isolate: *const RealIsolate, export_name: *const String, export_value: *const Value, ) -> MaybeBool; @@ -260,7 +261,7 @@ unsafe extern "C" { ) -> *const FixedArray; fn v8__Module__GetStalledTopLevelAwaitMessage( this: *const Module, - isolate: *const Isolate, + isolate: *const RealIsolate, out_vec: *mut StalledTopLevelAwaitMessage, vec_len: usize, ) -> usize; @@ -312,7 +313,7 @@ impl Module { /// For a module in kErrored status, this returns the corresponding exception. #[inline(always)] - pub fn get_exception(&self) -> Local { + pub fn get_exception<'o>(&self) -> Local<'o, Value> { // Note: the returned value is not actually stored in a HandleScope, // therefore we don't need a scope object here. unsafe { Local::from_raw(v8__Module__GetException(self)) }.unwrap() @@ -320,7 +321,7 @@ impl Module { /// Returns the ModuleRequests for this module. #[inline(always)] - pub fn get_module_requests(&self) -> Local { + pub fn get_module_requests<'o>(&self) -> Local<'o, FixedArray> { unsafe { Local::from_raw(v8__Module__GetModuleRequests(self)) }.unwrap() } @@ -363,7 +364,7 @@ impl Module { /// /// The module's status must be at least kInstantiated. #[inline(always)] - pub fn get_module_namespace(&self) -> Local { + pub fn get_module_namespace<'o>(&self) -> Local<'o, Value> { // Note: the returned value is not actually stored in a HandleScope, // therefore we don't need a scope object here. unsafe { Local::from_raw(v8__Module__GetModuleNamespace(self)).unwrap() } @@ -376,10 +377,10 @@ impl Module { /// exception is propagated.) #[must_use] #[inline(always)] - pub fn instantiate_module<'a>( + pub fn instantiate_module<'s, 'i>( &self, - scope: &mut HandleScope, - callback: impl MapFnTo>, + scope: &PinScope<'s, 'i>, + callback: impl MapFnTo>, ) -> Option { unsafe { v8__Module__InstantiateModule( @@ -399,11 +400,11 @@ impl Module { /// exception is propagated.) #[must_use] #[inline(always)] - pub fn instantiate_module2<'a>( + pub fn instantiate_module2<'s, 'i>( &self, - scope: &mut HandleScope, - callback: impl MapFnTo>, - source_callback: impl MapFnTo>, + scope: &PinScope<'s, 'i>, + callback: impl MapFnTo>, + source_callback: impl MapFnTo>, ) -> Option { unsafe { v8__Module__InstantiateModule( @@ -426,7 +427,7 @@ impl Module { #[inline(always)] pub fn evaluate<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -461,11 +462,11 @@ impl Module { /// module_name is used solely for logging/debugging and doesn't affect module /// behavior. #[inline(always)] - pub fn create_synthetic_module<'s, 'a>( - scope: &mut HandleScope<'s>, + pub fn create_synthetic_module<'s, 'i>( + scope: &PinScope<'s, 'i>, module_name: Local, export_names: &[Local], - evaluation_steps: impl MapFnTo>, + evaluation_steps: impl MapFnTo>, ) -> Local<'s, Module> { let export_names = Local::slice_into_raw(export_names); let export_names_len = export_names.len(); @@ -492,11 +493,11 @@ impl Module { /// Returns Some(true) on success, None if an error was thrown. #[must_use] #[inline(always)] - pub fn set_synthetic_module_export( + pub fn set_synthetic_module_export<'s>( &self, - scope: &mut HandleScope, - export_name: Local, - export_value: Local, + scope: &mut PinScope<'s, '_>, + export_name: Local<'s, String>, + export_value: Local<'s, Value>, ) -> Option { unsafe { v8__Module__SetSyntheticModuleExport( @@ -512,7 +513,7 @@ impl Module { #[inline(always)] pub fn get_unbound_module_script<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, UnboundModuleScript> { unsafe { scope @@ -526,10 +527,10 @@ impl Module { /// returned vector contains a tuple of the unresolved module and a message /// with the pending top-level await. /// An embedder may call this before exiting to improve error messages. - pub fn get_stalled_top_level_await_message( + pub fn get_stalled_top_level_await_message<'s>( &self, - scope: &mut HandleScope, - ) -> Vec<(Local, Local)> { + scope: &PinScope<'s, '_, ()>, + ) -> Vec<(Local<'s, Module>, Local<'s, Message>)> { let mut out_vec: Vec = Vec::with_capacity(16); for _i in 0..16 { out_vec.push(StalledTopLevelAwaitMessage { @@ -563,7 +564,7 @@ impl Module { impl ModuleRequest { /// Returns the module specifier for this ModuleRequest. #[inline(always)] - pub fn get_specifier(&self) -> Local { + pub fn get_specifier<'o>(&self) -> Local<'o, String> { unsafe { Local::from_raw(v8__ModuleRequest__GetSpecifier(self)) }.unwrap() } @@ -587,7 +588,7 @@ impl ModuleRequest { /// opposed to, for example, triggering an error if an unsupported assertion is /// present). #[inline(always)] - pub fn get_import_attributes(&self) -> Local { + pub fn get_import_attributes<'o>(&self) -> Local<'o, FixedArray> { unsafe { Local::from_raw(v8__ModuleRequest__GetImportAttributes(self)) } .unwrap() } diff --git a/src/number.rs b/src/number.rs index 2402817138..1211a3b7e5 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,20 +1,20 @@ use std::alloc::Layout; use std::ptr::NonNull; -use crate::HandleScope; use crate::Int32; use crate::Integer; -use crate::Isolate; use crate::Local; use crate::Number; use crate::Uint32; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; unsafe extern "C" { - fn v8__Number__New(isolate: *mut Isolate, value: f64) -> *const Number; + fn v8__Number__New(isolate: *mut RealIsolate, value: f64) -> *const Number; fn v8__Number__Value(this: *const Number) -> f64; - fn v8__Integer__New(isolate: *mut Isolate, value: i32) -> *const Integer; + fn v8__Integer__New(isolate: *mut RealIsolate, value: i32) -> *const Integer; fn v8__Integer__NewFromUnsigned( - isolate: *mut Isolate, + isolate: *mut RealIsolate, value: u32, ) -> *const Integer; fn v8__Integer__Value(this: *const Integer) -> i64; @@ -25,7 +25,7 @@ unsafe extern "C" { impl Number { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, value: f64, ) -> Local<'s, Number> { unsafe { @@ -43,7 +43,7 @@ impl Number { impl Integer { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, value: i32, ) -> Local<'s, Integer> { unsafe { @@ -54,7 +54,7 @@ impl Integer { #[inline(always)] pub fn new_from_unsigned<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, value: u32, ) -> Local<'s, Integer> { unsafe { diff --git a/src/object.rs b/src/object.rs index 674a422551..bca5089dd8 100644 --- a/src/object.rs +++ b/src/object.rs @@ -5,7 +5,6 @@ use crate::Array; use crate::Context; use crate::Data; use crate::GetPropertyNamesArgs; -use crate::HandleScope; use crate::IndexFilter; use crate::KeyCollectionMode; use crate::KeyConversionMode; @@ -25,6 +24,8 @@ use crate::cppgc::GarbageCollected; use crate::cppgc::GetRustObj; use crate::cppgc::UnsafePtr; use crate::isolate::Isolate; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::MapFnTo; use crate::support::Maybe; use crate::support::MaybeBool; @@ -36,9 +37,9 @@ use std::num::NonZeroI32; use std::ptr::null; unsafe extern "C" { - fn v8__Object__New(isolate: *mut Isolate) -> *const Object; + fn v8__Object__New(isolate: *mut RealIsolate) -> *const Object; fn v8__Object__New__with_prototype_and_properties( - isolate: *mut Isolate, + isolate: *mut RealIsolate, prototype_or_null: *const Value, names: *const *const Name, values: *const *const Value, @@ -232,26 +233,26 @@ unsafe extern "C" { out: *mut Maybe, ); fn v8__Object__Wrap( - isolate: *const Isolate, + isolate: *const RealIsolate, wrapper: *const Object, value: *const RustObj, tag: u16, ); fn v8__Object__Unwrap( - isolate: *const Isolate, + isolate: *const RealIsolate, wrapper: *const Object, tag: u16, ) -> *mut RustObj; fn v8__Object__IsApiWrapper(this: *const Object) -> bool; - fn v8__Array__New(isolate: *mut Isolate, length: int) -> *const Array; + fn v8__Array__New(isolate: *mut RealIsolate, length: int) -> *const Array; fn v8__Array__New_with_elements( - isolate: *mut Isolate, + isolate: *mut RealIsolate, elements: *const *const Value, length: usize, ) -> *const Array; fn v8__Array__Length(array: *const Array) -> u32; - fn v8__Map__New(isolate: *mut Isolate) -> *const Map; + fn v8__Map__New(isolate: *mut RealIsolate) -> *const Map; fn v8__Map__Clear(this: *const Map); fn v8__Map__Get( this: *const Map, @@ -276,7 +277,7 @@ unsafe extern "C" { ) -> MaybeBool; fn v8__Map__Size(map: *const Map) -> usize; fn v8__Map__As__Array(this: *const Map) -> *const Array; - fn v8__Set__New(isolate: *mut Isolate) -> *const Set; + fn v8__Set__New(isolate: *mut RealIsolate) -> *const Set; fn v8__Set__Clear(this: *const Set); fn v8__Set__Add( this: *const Set, @@ -302,7 +303,7 @@ const LAST_TAG: u16 = 0x7fff; impl Object { /// Creates an empty object. #[inline(always)] - pub fn new<'s>(scope: &mut HandleScope<'s>) -> Local<'s, Object> { + pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Object> { unsafe { scope.cast_local(|sd| v8__Object__New(sd.get_isolate_ptr())) } .unwrap() } @@ -314,7 +315,7 @@ impl Object { /// configurable and writable properties. #[inline(always)] pub fn with_prototype_and_properties<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, prototype_or_null: Local<'s, Value>, names: &[Local], values: &[Local], @@ -341,7 +342,7 @@ impl Object { #[inline(always)] pub fn set( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, value: Local, ) -> Option { @@ -356,7 +357,7 @@ impl Object { #[inline(always)] pub fn set_with_receiver( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, value: Local, receiver: Local, @@ -378,7 +379,7 @@ impl Object { #[inline(always)] pub fn set_index( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, index: u32, value: Local, ) -> Option { @@ -393,7 +394,7 @@ impl Object { #[inline(always)] pub fn set_prototype( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, prototype: Local, ) -> Option { unsafe { @@ -404,7 +405,7 @@ impl Object { /// Returns the name of the function invoked as a constructor for this object. #[inline(always)] - pub fn get_constructor_name(&self) -> Local { + pub fn get_constructor_name(&self) -> Local<'_, String> { unsafe { Local::from_raw(v8__Object__GetConstructorName(self)) }.unwrap() } @@ -418,7 +419,7 @@ impl Object { #[inline(always)] pub fn create_data_property( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, value: Local, ) -> Option { @@ -442,7 +443,7 @@ impl Object { #[inline(always)] pub fn define_own_property( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, value: Local, attr: PropertyAttribute, @@ -462,7 +463,7 @@ impl Object { #[inline(always)] pub fn define_property( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, descriptor: &PropertyDescriptor, ) -> Option { @@ -480,7 +481,7 @@ impl Object { #[inline(always)] pub fn get<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, ) -> Option> { unsafe { @@ -492,7 +493,7 @@ impl Object { #[inline(always)] pub fn get_with_receiver<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, receiver: Local, ) -> Option> { @@ -511,7 +512,7 @@ impl Object { #[inline(always)] pub fn get_index<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, index: u32, ) -> Option> { unsafe { @@ -526,7 +527,7 @@ impl Object { #[inline(always)] pub fn get_prototype<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__Object__GetPrototype(self)) } } @@ -535,7 +536,7 @@ impl Object { #[inline(always)] pub fn set_accessor( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, name: Local, getter: impl MapFnTo, ) -> Option { @@ -549,7 +550,7 @@ impl Object { #[inline(always)] pub fn set_accessor_with_setter( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, name: Local, getter: impl MapFnTo, setter: impl MapFnTo, @@ -563,7 +564,7 @@ impl Object { #[inline(always)] pub fn set_accessor_with_configuration( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, name: Local, configuration: AccessorConfiguration, ) -> Option { @@ -595,7 +596,7 @@ impl Object { #[inline(always)] pub fn get_creation_context<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|_| v8__Object__GetCreationContext(self)) } } @@ -606,7 +607,7 @@ impl Object { #[inline(always)] pub fn get_own_property_names<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, args: GetPropertyNamesArgs, ) -> Option> { unsafe { @@ -628,7 +629,7 @@ impl Object { #[inline(always)] pub fn get_property_names<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, args: GetPropertyNamesArgs, ) -> Option> { unsafe { @@ -658,7 +659,7 @@ impl Object { #[inline(always)] pub fn has( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { v8__Object__Has(self, &*scope.get_current_context(), &*key) } @@ -666,7 +667,11 @@ impl Object { } #[inline(always)] - pub fn has_index(&self, scope: &mut HandleScope, index: u32) -> Option { + pub fn has_index( + &self, + scope: &PinScope<'_, '_>, + index: u32, + ) -> Option { unsafe { v8__Object__HasIndex(self, &*scope.get_current_context(), index) } .into() } @@ -675,7 +680,7 @@ impl Object { #[inline(always)] pub fn has_own_property( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { @@ -687,7 +692,7 @@ impl Object { #[inline(always)] pub fn delete( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { v8__Object__Delete(self, &*scope.get_current_context(), &*key) } @@ -697,7 +702,7 @@ impl Object { #[inline] pub fn delete_index( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, index: u32, ) -> Option { unsafe { @@ -717,7 +722,7 @@ impl Object { #[inline(always)] pub fn get_internal_field<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, index: usize, ) -> Option> { // Trying to access out-of-bounds internal fields makes V8 abort @@ -774,7 +779,7 @@ impl Object { assert!(TAG < LAST_TAG); } let ptr = value.get_rust_obj(); - unsafe { v8__Object__Wrap(isolate as *mut _, &*wrapper, ptr, TAG) } + unsafe { v8__Object__Wrap(isolate.as_real_ptr(), &*wrapper, ptr, TAG) } } /// Unwraps a JS wrapper object. @@ -791,7 +796,8 @@ impl Object { const { assert!(TAG < LAST_TAG); } - let ptr = unsafe { v8__Object__Unwrap(isolate as *mut _, &*wrapper, TAG) }; + let ptr = + unsafe { v8__Object__Unwrap(isolate.as_real_ptr(), &*wrapper, TAG) }; unsafe { UnsafePtr::new(&ptr) } } @@ -813,7 +819,7 @@ impl Object { #[inline(always)] pub fn set_integrity_level( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, level: IntegrityLevel, ) -> Option { unsafe { @@ -846,7 +852,7 @@ impl Object { #[inline(always)] pub fn get_private<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, ) -> Option> { unsafe { @@ -863,7 +869,7 @@ impl Object { #[inline(always)] pub fn set_private( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, value: Local, ) -> Option { @@ -885,7 +891,7 @@ impl Object { #[inline(always)] pub fn delete_private( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { @@ -901,7 +907,7 @@ impl Object { #[inline(always)] pub fn has_private( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { @@ -917,7 +923,7 @@ impl Object { /// Returns [PropertyAttribute::NONE] when the property doesn't exist. pub fn get_property_attributes( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { let mut out = Maybe::::default(); @@ -937,7 +943,7 @@ impl Object { #[inline] pub fn get_own_property_descriptor<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, ) -> Option> { unsafe { @@ -961,7 +967,7 @@ impl Object { #[inline] pub fn preview_entries<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> (Option>, bool) { let mut is_key_value = MaybeUninit::uninit(); unsafe { @@ -980,7 +986,7 @@ impl Object { #[inline(always)] pub fn get_real_named_property<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, ) -> Option> { unsafe { @@ -993,7 +999,7 @@ impl Object { #[inline(always)] pub fn has_real_named_property( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { @@ -1012,7 +1018,7 @@ impl Object { #[inline(always)] pub fn get_real_named_property_attributes( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { let mut out = Maybe::::default(); @@ -1046,7 +1052,7 @@ impl Array { /// Creates a JavaScript array with the given length. If the length /// is negative the returned array will have length 0. #[inline(always)] - pub fn new<'s>(scope: &mut HandleScope<'s>, length: i32) -> Local<'s, Array> { + pub fn new<'s>(scope: &PinScope<'s, '_>, length: i32) -> Local<'s, Array> { unsafe { scope.cast_local(|sd| v8__Array__New(sd.get_isolate_ptr(), length)) } @@ -1057,7 +1063,7 @@ impl Array { /// length. #[inline(always)] pub fn new_with_elements<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, elements: &[Local], ) -> Local<'s, Array> { if elements.is_empty() { @@ -1084,7 +1090,7 @@ impl Array { impl Map { #[inline(always)] - pub fn new<'s>(scope: &mut HandleScope<'s>) -> Local<'s, Map> { + pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Map> { unsafe { scope.cast_local(|sd| v8__Map__New(sd.get_isolate_ptr())) } .unwrap() } @@ -1102,7 +1108,7 @@ impl Map { #[inline(always)] pub fn get<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, ) -> Option> { unsafe { @@ -1113,7 +1119,7 @@ impl Map { #[inline(always)] pub fn set<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, value: Local, ) -> Option> { @@ -1127,7 +1133,7 @@ impl Map { #[inline(always)] pub fn has( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { v8__Map__Has(self, &*scope.get_current_context(), &*key) }.into() @@ -1136,7 +1142,7 @@ impl Map { #[inline(always)] pub fn delete( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { v8__Map__Delete(self, &*scope.get_current_context(), &*key) } @@ -1146,14 +1152,14 @@ impl Map { /// Returns an array of length size() * 2, where index N is the Nth key and /// index N + 1 is the Nth value. #[inline(always)] - pub fn as_array<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Array> { + pub fn as_array<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Array> { unsafe { scope.cast_local(|_| v8__Map__As__Array(self)) }.unwrap() } } impl Set { #[inline(always)] - pub fn new<'s>(scope: &mut HandleScope<'s>) -> Local<'s, Set> { + pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Set> { unsafe { scope.cast_local(|sd| v8__Set__New(sd.get_isolate_ptr())) } .unwrap() } @@ -1171,7 +1177,7 @@ impl Set { #[inline(always)] pub fn add<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, key: Local, ) -> Option> { unsafe { @@ -1182,7 +1188,7 @@ impl Set { #[inline(always)] pub fn has( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { v8__Set__Has(self, &*scope.get_current_context(), &*key) }.into() @@ -1191,7 +1197,7 @@ impl Set { #[inline(always)] pub fn delete( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, key: Local, ) -> Option { unsafe { v8__Set__Delete(self, &*scope.get_current_context(), &*key) } @@ -1201,7 +1207,7 @@ impl Set { /// Returns an array of length size() * 2, where index N is the Nth key and /// index N + 1 is the Nth value. #[inline(always)] - pub fn as_array<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Array> { + pub fn as_array<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Array> { unsafe { scope.cast_local(|_| v8__Set__As__Array(self)) }.unwrap() } } diff --git a/src/platform.rs b/src/platform.rs index 265eb9372b..712a414447 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -1,4 +1,5 @@ use crate::Isolate; +use crate::isolate::RealIsolate; use crate::support::int; use crate::support::Opaque; @@ -25,19 +26,19 @@ unsafe extern "C" { fn v8__Platform__PumpMessageLoop( platform: *mut Platform, - isolate: *mut Isolate, + isolate: *mut RealIsolate, wait_for_work: bool, ) -> bool; fn v8__Platform__RunIdleTasks( platform: *mut Platform, - isolate: *mut Isolate, + isolate: *mut RealIsolate, idle_time_in_seconds: f64, ); fn v8__Platform__NotifyIsolateShutdown( platform: *mut Platform, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ); fn std__shared_ptr__v8__Platform__CONVERT__std__unique_ptr( @@ -187,13 +188,13 @@ impl Platform { #[inline(always)] pub fn pump_message_loop( platform: &SharedRef, - isolate: &mut Isolate, + isolate: &Isolate, wait_for_work: bool, ) -> bool { unsafe { v8__Platform__PumpMessageLoop( &**platform as *const Self as *mut _, - isolate, + isolate.as_real_ptr(), wait_for_work, ) } @@ -206,13 +207,13 @@ impl Platform { #[inline(always)] pub fn run_idle_tasks( platform: &SharedRef, - isolate: &mut Isolate, + isolate: &Isolate, idle_time_in_seconds: f64, ) { unsafe { v8__Platform__RunIdleTasks( &**platform as *const Self as *mut _, - isolate, + isolate.as_real_ptr(), idle_time_in_seconds, ); } @@ -226,12 +227,12 @@ impl Platform { #[inline(always)] pub(crate) unsafe fn notify_isolate_shutdown( platform: &SharedRef, - isolate: &mut Isolate, + isolate: &Isolate, ) { unsafe { v8__Platform__NotifyIsolateShutdown( &**platform as *const Self as *mut _, - isolate, + isolate.as_real_ptr(), ); } } diff --git a/src/primitive_array.rs b/src/primitive_array.rs index 02cf67caaa..121e1d8905 100644 --- a/src/primitive_array.rs +++ b/src/primitive_array.rs @@ -1,14 +1,16 @@ // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. -use crate::HandleScope; -use crate::Isolate; + use crate::Local; use crate::Primitive; use crate::PrimitiveArray; +use crate::isolate::RealIsolate; +use crate::scope::GetIsolate; +use crate::scope::PinScope; use crate::support::int; unsafe extern "C" { fn v8__PrimitiveArray__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, length: int, ) -> *const PrimitiveArray; @@ -16,14 +18,14 @@ unsafe extern "C" { fn v8__PrimitiveArray__Set( this: *const PrimitiveArray, - isolate: *mut Isolate, + isolate: *mut RealIsolate, index: int, item: *const Primitive, ); fn v8__PrimitiveArray__Get( this: *const PrimitiveArray, - isolate: *mut Isolate, + isolate: *mut RealIsolate, index: int, ) -> *const Primitive; } @@ -31,7 +33,7 @@ unsafe extern "C" { impl PrimitiveArray { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, length: usize, ) -> Local<'s, PrimitiveArray> { unsafe { @@ -50,7 +52,7 @@ impl PrimitiveArray { #[inline(always)] pub fn set( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, index: usize, item: Local<'_, Primitive>, ) { @@ -67,7 +69,7 @@ impl PrimitiveArray { #[inline(always)] pub fn get<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, index: usize, ) -> Local<'s, Primitive> { unsafe { diff --git a/src/primitives.rs b/src/primitives.rs index a554745236..6351f8bcae 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -2,38 +2,45 @@ use crate::Boolean; use crate::Local; use crate::Primitive; use crate::isolate::Isolate; +use crate::isolate::RealIsolate; unsafe extern "C" { - fn v8__Null(isolate: *mut Isolate) -> *const Primitive; - fn v8__Undefined(isolate: *mut Isolate) -> *const Primitive; + fn v8__Null(isolate: *mut RealIsolate) -> *const Primitive; + fn v8__Undefined(isolate: *mut RealIsolate) -> *const Primitive; - fn v8__Boolean__New(isolate: *mut Isolate, value: bool) -> *const Boolean; + fn v8__Boolean__New(isolate: *mut RealIsolate, value: bool) + -> *const Boolean; } #[inline(always)] -pub fn null<'a, R>(scope: &mut R) -> Local<'a, Primitive> +pub fn null<'s, R>(scope: &R) -> Local<'s, Primitive> where - R: AsMut, + R: AsRef, { - unsafe { Local::from_raw_unchecked(v8__Null(scope.as_mut())) } + unsafe { Local::from_raw_unchecked(v8__Null(scope.as_ref().as_real_ptr())) } } #[inline(always)] -pub fn undefined<'a, R>(scope: &mut R) -> Local<'a, Primitive> +pub fn undefined<'s, R>(scope: &R) -> Local<'s, Primitive> where - R: AsMut, + R: AsRef, { - unsafe { Local::from_raw_unchecked(v8__Undefined(scope.as_mut())) } + unsafe { + Local::from_raw_unchecked(v8__Undefined(scope.as_ref().as_real_ptr())) + } } impl Boolean { #[inline(always)] - pub fn new<'a, R>(scope: &mut R, value: bool) -> Local<'a, Boolean> + pub fn new<'s, R>(scope: &R, value: bool) -> Local<'s, Boolean> where - R: AsMut, + R: AsRef, { unsafe { - Local::from_raw_unchecked(v8__Boolean__New(scope.as_mut(), value)) + Local::from_raw_unchecked(v8__Boolean__New( + scope.as_ref().as_real_ptr(), + value, + )) } } } diff --git a/src/private.rs b/src/private.rs index f04c63f738..0293fa3396 100644 --- a/src/private.rs +++ b/src/private.rs @@ -1,17 +1,17 @@ -use crate::HandleScope; -use crate::Isolate; use crate::Local; use crate::Private; use crate::String; use crate::Value; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; unsafe extern "C" { fn v8__Private__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, name: *const String, ) -> *const Private; fn v8__Private__ForApi( - isolate: *mut Isolate, + isolate: *mut RealIsolate, name: *const String, ) -> *const Private; fn v8__Private__Name(this: *const Private) -> *const Value; @@ -21,7 +21,7 @@ impl Private { /// Create a private symbol. If name is not empty, it will be the description. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, name: Option>, ) -> Local<'s, Private> { unsafe { @@ -44,7 +44,7 @@ impl Private { /// e.g., "Class#property". #[inline(always)] pub fn for_api<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, name: Option>, ) -> Local<'s, Private> { unsafe { @@ -60,7 +60,7 @@ impl Private { /// Returns the print name string of the private symbol, or undefined if none. #[inline(always)] - pub fn name<'s>(&self, scope: &mut HandleScope<'s, ()>) -> Local<'s, Value> { + pub fn name<'s>(&self, scope: &PinScope<'s, '_, ()>) -> Local<'s, Value> { unsafe { scope.cast_local(|_| v8__Private__Name(self)) }.unwrap() } } diff --git a/src/promise.rs b/src/promise.rs index ed662eada6..0c45e76254 100644 --- a/src/promise.rs +++ b/src/promise.rs @@ -2,11 +2,11 @@ use std::marker::PhantomData; use crate::Context; use crate::Function; -use crate::HandleScope; use crate::Local; use crate::Promise; use crate::PromiseResolver; use crate::Value; +use crate::scope::PinScope; use crate::support::MaybeBool; unsafe extern "C" { @@ -82,7 +82,7 @@ impl Promise { /// Returns the content of the [[PromiseResult]] field. The Promise must not /// be pending. #[inline(always)] - pub fn result<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Value> { + pub fn result<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Value> { unsafe { scope.cast_local(|_| v8__Promise__Result(self)) }.unwrap() } @@ -92,7 +92,7 @@ impl Promise { #[inline(always)] pub fn catch<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, handler: Local, ) -> Option> { unsafe { @@ -108,7 +108,7 @@ impl Promise { #[inline(always)] pub fn then<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, handler: Local, ) -> Option> { unsafe { @@ -125,7 +125,7 @@ impl Promise { #[inline(always)] pub fn then2<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, on_fulfilled: Local, on_rejected: Local, ) -> Option> { @@ -146,7 +146,7 @@ impl PromiseResolver { /// Create a new resolver, along with an associated promise in pending state. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -158,7 +158,7 @@ impl PromiseResolver { #[inline(always)] pub fn get_promise<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, Promise> { unsafe { scope.cast_local(|_| v8__Promise__Resolver__GetPromise(self)) } .unwrap() @@ -169,7 +169,7 @@ impl PromiseResolver { #[inline(always)] pub fn resolve( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, value: Local<'_, Value>, ) -> Option { unsafe { @@ -187,7 +187,7 @@ impl PromiseResolver { #[inline(always)] pub fn reject( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, value: Local<'_, Value>, ) -> Option { unsafe { diff --git a/src/property_descriptor.rs b/src/property_descriptor.rs index 0345f1ba0f..0b0ef93725 100644 --- a/src/property_descriptor.rs +++ b/src/property_descriptor.rs @@ -129,15 +129,15 @@ impl PropertyDescriptor { unsafe { v8__PropertyDescriptor__writable(self) } } - pub fn value(&self) -> Local { + pub fn value(&self) -> Local<'_, Value> { unsafe { Local::from_raw(v8__PropertyDescriptor__value(self)) }.unwrap() } - pub fn get(&self) -> Local { + pub fn get(&self) -> Local<'_, Value> { unsafe { Local::from_raw(v8__PropertyDescriptor__get(self)) }.unwrap() } - pub fn set(&self) -> Local { + pub fn set(&self) -> Local<'_, Value> { unsafe { Local::from_raw(v8__PropertyDescriptor__set(self)) }.unwrap() } diff --git a/src/proxy.rs b/src/proxy.rs index 3b0875c9ea..2de7889ef3 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -1,9 +1,9 @@ use crate::Context; -use crate::HandleScope; use crate::Local; use crate::Object; use crate::Proxy; use crate::Value; +use crate::scope::PinScope; unsafe extern "C" { fn v8__Proxy__New( @@ -20,7 +20,7 @@ unsafe extern "C" { impl Proxy { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, target: Local, handler: Local, ) -> Option> { @@ -32,18 +32,12 @@ impl Proxy { } #[inline(always)] - pub fn get_handler<'s>( - &self, - scope: &mut HandleScope<'s>, - ) -> Local<'s, Value> { + pub fn get_handler<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Value> { unsafe { scope.cast_local(|_| v8__Proxy__GetHandler(self)) }.unwrap() } #[inline(always)] - pub fn get_target<'s>( - &self, - scope: &mut HandleScope<'s>, - ) -> Local<'s, Value> { + pub fn get_target<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Value> { unsafe { scope.cast_local(|_| v8__Proxy__GetTarget(self)) }.unwrap() } diff --git a/src/regexp.rs b/src/regexp.rs index 5e03864396..f0f29ee103 100644 --- a/src/regexp.rs +++ b/src/regexp.rs @@ -1,9 +1,9 @@ use crate::Context; -use crate::HandleScope; use crate::Local; use crate::Object; use crate::RegExp; use crate::String; +use crate::scope::PinScope; use crate::support::int; bitflags! { @@ -39,7 +39,7 @@ unsafe extern "C" { impl RegExp { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, pattern: Local, flags: RegExpCreationFlags, ) -> Option> { @@ -53,7 +53,7 @@ impl RegExp { #[inline(always)] pub fn exec<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, subject: Local, ) -> Option> { unsafe { @@ -64,10 +64,7 @@ impl RegExp { } #[inline(always)] - pub fn get_source<'s>( - &self, - scope: &mut HandleScope<'s>, - ) -> Local<'s, String> { + pub fn get_source<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, String> { unsafe { scope.cast_local(|_| v8__RegExp__GetSource(self)) }.unwrap() } } diff --git a/src/scope.rs b/src/scope.rs index ad88ecd0c5..1873ae7ca0 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -1,148 +1,247 @@ -// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. - -//! This module's public API exports a number of 'scope' types. +//! This module contains the rust wrappers for V8's scope types. +//! +//! There are two main types of scopes, with the other types being derived from them: +//! - `HandleScope` - a scope to create and access `Local` handles +//! - `TryCatch` - a scope to catch exceptions thrown from javascript +//! +//! There are a few important properties that make v8 scopes challenging to model in rust. +//! - `HandleScope`s can (and almost certainly will be) nested, but handles are only +//! bound to the innermost `HandleScope` +//! - Importantly, this means that the Handle lifetimes are determined by the innermost `HandleScope` +//! - Both `HandleScope` and `TryCatch` cannot be moved, because V8 holds direct pointers to them +//! - The C++ API relies heavily on inheritance, which is a bit awkward to model in rust +//! +//! # Example +//! +//! ```rust +//! use v8::{HandleScope, Local, Object, Isolate, Context, ContextScope, Object}; +//! v8::V8::initialize(); +//! +//! let scope = HandleScope::new(&mut isolate); +//! let scope = std::pin::pin!(scope); +//! let mut scope = scope.init(); +//! let context = Context::new(&scope, Default::default()); +//! +//! let context_scope = ContextScope::new(&mut scope, context); +//! let object = Object::new(&context_scope); +//! +//! ``` +//! +//! ## Explanation +//! The first thing you'll notice is that creating a `HandleScope` requires a few different steps. You'll see this pattern +//! across all scope types that are address-sensitive (all except for `ContextScope`): +//! +//! 1. Allocate the storage for the scope. At this point, the scope is not yet address-sensitive, and so it can be safely moved. +//! 2. Pin the storage to the stack. This is necessary because once we initialize the scope, it must not be moved. +//! 3. Initialize the scope. This is where the scope is actually initialized, and our `Pin` ensures that the scope cannot be moved. +//! +//! This is a bit verbose, so you can collapse it into two lines, +//! ```rust +//! let scope = std::pin::pin!(HandleScope::new(&mut isolate)); +//! let mut scope = scope.init(); +//! ``` +//! +//! or use the provided macros: +//! ```rust +//! // note that this expands into statements, introducing a new variable `scope` into the current +//! // block. Using it as an expression (`let scope = v8::scope!(let scope, &mut isolate);`) will not work +//! v8::scope!(let scope, &mut isolate); +//! ``` +//! +//! # Scopes as function args +//! In a function that takes a scope, you'll typically want to take a `PinScope`, like +//! ```rust +//! fn foo<'s, 'i>(scope: &mut v8::PinScope<'s, 'i>) { +//! let local = v8::Number::new(scope, 42); +//! } +//! ``` +//! +//! `PinScope` is just a shorthand for `PinnedRef<'s, HandleScope<'i>>`, which you can use if you really prefer. +//! +//! The lifetimes can sometimes be elided, but if you are taking or returning a `Local`, you'll need to specify at least the first one. +//! ``` +//! fn foo<'s>(scope: &mut v8::PinScope<'s, '_>, arg: v8::Local<'s, v8::Number>) -> v8::Local<'s, v8::Number> { +//! v8::Number::new(scope, arg.value() + 42.0); +//! } +//! ``` +//! +//! # Deref/DerefMut //! -//! These types carry information about the state of the V8 Isolate, as well as -//! lifetimes for certain (return) values. More specialized scopes typically -//! deref to more generic scopes, and ultimately they all deref to `Isolate`. +//! Scopes implement `Deref` and `DerefMut` to allow for sort of "inheritance" of behavior. This is useful because +//! it allows most methods (as mentioned above) to just take a `PinScope`, and other scopes will deref to `PinScope`. //! -//! The scope types in the public API are all pointer wrappers, and they all -//! point at a heap-allocated struct `data::ScopeData`. `ScopeData` allocations -//! are never shared between scopes; each Handle/Context/CallbackScope gets -//! its own instance. +//! That lets you seamlessly pass, for instance, a `ContextScope` to a function that takes a `PinScope`. +//! Note that pinned scopes do not implement `Deref` or `DerefMut`, themselves, rather `PinnedRef` does. //! -//! Notes about the available scope types: -//! See also the tests at the end of this file. +//! The deref implementations are: //! -//! - `HandleScope<'s, ()>` -//! - 's = lifetime of local handles created in this scope, and of the scope -//! itself. -//! - This type is returned when a HandleScope is constructed from a direct -//! reference to an isolate (`&mut Isolate` or `&mut OwnedIsolate`). -//! - A `Context` is _not_ available. Only certain types JavaScript values can -//! be created: primitive values, templates, and instances of `Context`. -//! - Derefs to `Isolate`. +//! PinnedRef<'_, HandleScope<'_, ()>> -> Isolate +//! PinnedRef<'_, HandleScope<'_>> -> PinnedRef<'_, HandleScope<'_, ()>> +//! PinnedRef<'_, ContextScope<'_, '_>> -> PinnedRef<'_, HandleScope<'_>> +//! PinnedRef<'_, CallbackScope<'_, '_>> -> PinnedRef<'_, HandleScope<'_, ()>> //! -//! - `HandleScope<'s>` -//! - 's = lifetime of local handles created in this scope, and of the scope -//! itself. -//! - A `Context` is available; any type of value can be created. -//! - Derefs to `HandleScope<'s, ()>` //! -//! - `ContextScope<'s, P>` -//! - 's = lifetime of the scope itself. -//! - A `Context` is available; any type of value can be created. -//! - Derefs to `P`. -//! - When constructed as the child of a `HandleScope<'a, ()>`, the returned -//! type is `ContextScope<'s, HandleScope<'p>>`. In other words, the parent -//! HandleScope gets an upgrade to indicate the availability of a `Context`. -//! - When a new scope is constructed inside this type of scope, the -//! `ContextScope` wrapper around `P` is erased first, which means that the -//! child scope is set up as if it had been created with `P` as its parent. //! -//! - `EscapableHandleScope<'s, 'e>` -//! - 's = lifetime of local handles created in this scope, and of the scope -//! itself. -//! - 'e = lifetime of the HandleScope that will receive the local handle that -//! is created by `EscapableHandleScope::escape()`. -//! - A `Context` is available; any type of value can be created. -//! - Derefs to `HandleScope<'s>`. +//! # Internals //! -//! - `TryCatch<'s, P>` -//! - 's = lifetime of the TryCatch scope. -//! - `P` is either a `HandleScope` or an `EscapableHandleScope`. This type -//! also determines for how long the values returned by `TryCatch` methods -//! `exception()`, `message()`, and `stack_trace()` are valid. -//! - Derefs to `P`. -//! - Creating a new scope inside the `TryCatch` block makes its methods -//! inaccessible until the inner scope is dropped. However, the `TryCatch` -//! object will nonetheless catch all exception thrown during its lifetime. +//! The initialization process uses the typestate pattern. The storage for the scope is a `ScopeStorage` struct, which is +//! then transititions to a `Pin<&mut ScopeStorage>`, and then `init` transitions to a `PinnedRef<'s, T>`. //! -//! - `CallbackScope<'s, ()>` -//! - 's = lifetime of local handles created in this scope, and the value -//! returned from the callback, and of the scope itself. -//! - A `Context` is _not_ available. Only certain types JavaScript values can -//! be created: primitive values, templates, and instances of `Context`. -//! - Derefs to `HandleScope<'s, ()>`. -//! - This scope type is only to be constructed inside embedder defined -//! callbacks when these are called by V8. -//! - When a scope is created inside, type is erased to `HandleScope<'s, ()>`. +//! The `ScopeStorage` struct tracks initialization state, and is responsible for calling the destructor when the storage is dropped +//! (iff the scope was initialized). //! -//! - `CallbackScope<'s>` -//! - 's = lifetime of local handles created in this scope, and the value -//! returned from the callback, and of the scope itself. -//! - A `Context` is available; any type of value can be created. -//! - Derefs to `HandleScope<'s>`. -//! - This scope type is only to be constructed inside embedder defined -//! callbacks when these are called by V8. -//! - When a scope is created inside, type is erased to `HandleScope<'s>`. +//! The `PinnedRef` type, returned from `init`, is a transparent wrapper around a `Pin<&mut T>`. The reason it is a newtype is so +//! that it can have specialized Deref/DerefMut implementations for the different scope types. `Pin` has a blanket implementation +//! that doesn't have the behavior we want. //! -//! - `DisallowJavascriptExecutionScope<'s, P>` -//! - 's = lifetime of the `DisallowJavascriptExecutionScope` scope. -//! - `P` is either a `HandleScope`, `ContextScope`, `EscapableHandleScope` -//! or a `TryCatch`. -//! - Derefs to `P`. +//! ## Lifetimes //! -//! - `AllowJavascriptExecutionScope<'s, P>` -//! - 's = lifetime of the `AllowJavascriptExecutionScope` scope. -//! - `P` is `DisallowJavascriptExecutionScope`. -//! - Derefs to `HandleScope<'s, ()>`. - -use std::alloc::Layout; -use std::alloc::alloc; -use std::any::type_name; -use std::cell::Cell; -use std::convert::TryInto; - -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::num::NonZeroUsize; -use std::ops::Deref; -use std::ops::DerefMut; -use std::ptr; -use std::ptr::NonNull; - -use crate::Context; -use crate::Data; -use crate::DataError; -use crate::Function; -use crate::Handle; -use crate::Isolate; -use crate::Local; -use crate::Message; -use crate::Object; -use crate::OwnedIsolate; -use crate::Primitive; -use crate::PromiseRejectMessage; -use crate::SealedLocal; -use crate::Value; -use crate::fast_api::FastApiCallbackOptions; -use crate::function::FunctionCallbackInfo; -use crate::function::PropertyCallbackInfo; +//! The trickiest part of the scopes here are the lifetimes. In general, the lifetimes exist for a few reasons: +//! - ensure that a scope can't outlive the thing it's made from (e.g. an isolate, or another scope) +//! - ensure that a scope higher up the stack can't be used until the scope below it has dropped +//! - ensure that the `Handle`s bound to the scope do not outlive the scope +//! +//! These lifetimes do not need to be exact, and in some cases I'm sure they are shorter than they could be, +//! as long as everything lives long enough. In other words, the lifetimes just need to be a safe approximation. +//! +//! +//! ### HandleScope +//! `HandleScope` itself has only one lifetime, `'i` which is the lifetime of the thing that the scope was created from +//! (e.g. an isolate). +//! +//! The lifetime for handles bound to the scope is really the lifetime of the `HandleScope` itself. In our case, +//! since we've pinned it to the stack, that is the lifetime of the pinned reference. So in +//! `PinnedRef<'s, HandleScope<'i>>`, `'s` is the lifetime of the pinned reference, and therefore +//! the handles, and 'i is the lifetime of the isolate. +//! +//! ### ContextScope +//! ContextScope is really just a wrapper around another scope, with a `Context` added to it. +//! It wraps a scope, and so it is not actually address-sensitive, and can be moved around freely. +//! +//! ContextScope has two lifetimes, `'b` and `'s`. `'b` is the lifetime of the borrow of the scope +//! it's wrapping, and `'s` is the lifetime of the scope. +//! +//! Effectively you have `&'b PinnedRef<'s, T>`. +//! +//! The lifetime for handles bound to the scope is the lifetime of the scope that it was created from. +//! So in `ContextScope<'b, 's>`, `'b` is the lifetime of the borrow of the inner scope, and `'s` is the lifetime of the inner scope (and therefore the handles). +use crate::{ + Context, Data, DataError, Function, FunctionCallbackInfo, Isolate, Local, + Message, Object, OwnedIsolate, PromiseRejectMessage, PropertyCallbackInfo, + SealedLocal, Value, fast_api::FastApiCallbackOptions, isolate::RealIsolate, + support::assert_layout_subset, +}; +use std::{ + any::type_name, + cell::Cell, + marker::{PhantomData, PhantomPinned}, + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + pin::Pin, + ptr::NonNull, +}; +pub(crate) mod raw; + +pub type PinScope<'s, 'i, C = Context> = PinnedRef<'s, HandleScope<'i, C>>; +pub type PinCallbackScope<'s, 'i, C = Context> = + PinnedRef<'s, CallbackScope<'i, C>>; + +/// Storage for a scope. +/// +/// Tracks the initialization state of the scope, and holds the scope itself. +#[repr(C)] +pub struct ScopeStorage { + inited: bool, + scope: ManuallyDrop, + _pinned: PhantomPinned, +} -/// Stack-allocated class which sets the execution context for all operations -/// executed within a local scope. After entering a context, all code compiled -/// and run is compiled and run in this context. -#[derive(Debug)] -pub struct ContextScope<'s, P> { - _data: NonNull, - _phantom: PhantomData<&'s mut P>, +impl ScopeStorage { + pub(crate) fn projected(self: Pin<&mut Self>) -> Pin<&mut T> { + // SAFETY: we are just projecting to a field, so the scope remains pinned + unsafe { + let self_mut = self.get_unchecked_mut(); + Pin::new_unchecked(&mut self_mut.scope) + } + } + + pub fn new(scope: T) -> Self { + Self { + inited: false, + scope: ManuallyDrop::new(scope), + _pinned: PhantomPinned, + } + } + + pub fn init(mut self: Pin<&mut Self>) -> PinnedRef<'_, T> { + if self.inited { + // free old, going to reuse this storage + unsafe { + let self_mut = self.as_mut().get_unchecked_mut(); + self_mut.drop_inner(); + self_mut.inited = false; + } + } + + // hold onto a pointer so we can set this after initialization. we can't use a normal + // mutable reference because the borrow checker will see overlapping borrows. this is + // safe, however, because we lose our mutable reference to the storage in `init_stack` + // as it gets projected to the inner type + let inited_ptr = + unsafe { &raw mut self.as_mut().get_unchecked_mut().inited }; + let ret = T::init_stack(self); + unsafe { inited_ptr.write(true) }; + PinnedRef(ret) + } + + /// SAFEFTY: `self.inited` must be true, and therefore must be pinned + unsafe fn drop_inner(&mut self) { + unsafe { + T::deinit(&mut self.scope); + } + self.inited = false; + } } -impl<'s, P: param::NewContextScope<'s>> ContextScope<'s, P> { - #[allow(clippy::new_ret_no_self)] - pub fn new(param: &'s mut P, context: Local) -> P::NewScope { - let scope_data = param.get_scope_data_mut(); - if scope_data.get_isolate_ptr() - != unsafe { raw::v8__Context__GetIsolate(&*context) } - { - panic!( - "{} and Context do not belong to the same Isolate", - type_name::

() - ) +impl Drop for ScopeStorage { + fn drop(&mut self) { + if self.inited { + unsafe { + self.drop_inner(); + } } - let new_scope_data = scope_data.new_context_scope_data(context); - new_scope_data.as_scope() + } +} + +pub trait Scope: Sized + sealed::Sealed + ScopeInit {} + +mod sealed { + pub trait Sealed {} +} + +pub trait ScopeInit: Sized { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self>; + + unsafe fn deinit(me: &mut Self); +} + +impl ScopeInit for HandleScope<'_, C> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + // SAFETY: no moving the scope from this point on + let storage_mut = unsafe { storage.get_unchecked_mut() }; + unsafe { + let isolate = storage_mut.scope.isolate; + raw::HandleScope::init(&mut storage_mut.scope.raw_handle_scope, isolate) + }; + + let projected = &mut storage_mut.scope; + + // SAFETY: scope is still pinned + unsafe { Pin::new_unchecked(projected) } + } + + unsafe fn deinit(me: &mut Self) { + unsafe { raw::v8__HandleScope__DESTRUCT(&mut me.raw_handle_scope) }; } } @@ -158,142 +257,286 @@ impl<'s, P: param::NewContextScope<'s>> ContextScope<'s, P> { /// garbage collector will no longer track the object stored in the /// handle and may deallocate it. The behavior of accessing a handle /// for which the handle scope has been deleted is undefined. +#[repr(C)] #[derive(Debug)] pub struct HandleScope<'s, C = Context> { - _data: NonNull, + raw_handle_scope: raw::HandleScope, + isolate: NonNull, + context: Cell>>, _phantom: PhantomData<&'s mut C>, + _pinned: PhantomPinned, } -impl<'s> HandleScope<'s> { - #[allow(clippy::new_ret_no_self)] - pub fn new>(param: &'s mut P) -> P::NewScope { - param - .get_scope_data_mut() - .new_handle_scope_data() - .as_scope() - } - - /// Opens a new `HandleScope` and enters a `Context` in one step. - /// The first argument should be an `Isolate` or `OwnedIsolate`. - /// The second argument can be any handle that refers to a `Context` object; - /// usually this will be a `Global`. - pub fn with_context< - P: param::NewHandleScopeWithContext<'s>, - H: Handle, - >( - param: &'s mut P, - context: H, - ) -> Self { - let context_ref = context.open(param.get_isolate_mut()); - param - .get_scope_data_mut() - .new_handle_scope_data_with_context(context_ref) - .as_scope() +impl sealed::Sealed for HandleScope<'_, C> {} +impl Scope for HandleScope<'_, C> {} + +mod get_isolate { + use crate::RealIsolate; + pub trait GetIsolate { + fn get_isolate_ptr(&self) -> *mut RealIsolate; } +} +pub(crate) use get_isolate::GetIsolate; - /// Returns the context of the currently running JavaScript, or the context - /// on the top of the stack if no JavaScript is running. - #[inline(always)] - pub fn get_current_context(&self) -> Local<'s, Context> { - let context_ptr = data::ScopeData::get(self).get_current_context(); - unsafe { Local::from_raw(context_ptr) }.unwrap() +mod get_isolate_impls { + use crate::{Promise, PromiseRejectMessage}; + + use super::*; + impl GetIsolate for Isolate { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.as_real_ptr() + } } - /// Returns either the last context entered through V8's C++ API, or the - /// context of the currently running microtask while processing microtasks. - /// If a context is entered while executing a microtask, that context is - /// returned. - pub fn get_entered_or_microtask_context(&self) -> Local<'s, Context> { - let data = data::ScopeData::get(self); - let isolate_ptr = data.get_isolate_ptr(); - let context_ptr = - unsafe { raw::v8__Isolate__GetEnteredOrMicrotaskContext(isolate_ptr) }; - unsafe { Local::from_raw(context_ptr) }.unwrap() + impl GetIsolate for OwnedIsolate { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.as_real_ptr() + } } - /// Returns the host defined options set for currently running script or - /// module, if available. - #[inline(always)] - pub fn get_current_host_defined_options(&self) -> Option> { - let data = data::ScopeData::get(self); - let isolate_ptr = data.get_isolate_ptr(); - unsafe { - Local::from_raw(raw::v8__Isolate__GetCurrentHostDefinedOptions( - isolate_ptr, - )) + impl GetIsolate for FunctionCallbackInfo { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.get_isolate_ptr() } } -} -impl<'s> HandleScope<'s, ()> { - /// Schedules an exception to be thrown when returning to JavaScript. When - /// an exception has been scheduled it is illegal to invoke any - /// JavaScript operation; the caller must return immediately and only - /// after the exception has been handled does it become legal to invoke - /// JavaScript operations. - /// - /// This function always returns the `undefined` value. - #[inline(always)] - pub fn throw_exception( - &mut self, - exception: Local, - ) -> Local<'s, Value> { - unsafe { - self.cast_local(|sd| { - raw::v8__Isolate__ThrowException(sd.get_isolate_ptr(), &*exception) - }) + impl GetIsolate for PropertyCallbackInfo { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.get_isolate_ptr() } - .unwrap() } - #[inline(always)] - pub(crate) unsafe fn cast_local( - &mut self, - f: impl FnOnce(&mut data::ScopeData) -> *const T, - ) -> Option> { - unsafe { Local::from_raw(f(data::ScopeData::get_mut(self))) } + impl GetIsolate for FastApiCallbackOptions<'_> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.isolate + } } - #[inline(always)] - pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate { - data::ScopeData::get(self).get_isolate_ptr() + impl GetIsolate for Local<'_, Context> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + unsafe { raw::v8__Context__GetIsolate(&**self) } + } } - /// Open a handle passed from V8 in the current scope. - /// - /// # Safety - /// - /// The handle must be rooted in this scope. + impl GetIsolate for Local<'_, Message> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + unsafe { raw::v8__Message__GetIsolate(&**self) } + } + } + + impl GetIsolate for Local<'_, Promise> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + let object: Local = (*self).into(); + unsafe { raw::v8__Object__GetIsolate(&*object) } + } + } + + impl GetIsolate for PromiseRejectMessage<'_> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + let object: Local = self.get_promise().into(); + unsafe { raw::v8__Object__GetIsolate(&*object) } + } + } + + impl GetIsolate for HandleScope<'_, C> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.isolate.as_ptr() + } + } + + impl GetIsolate + for ContextScope<'_, '_, P> + { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.scope.get_isolate_ptr() + } + } + + impl GetIsolate for &mut P { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + P::get_isolate_ptr(self) + } + } + + impl GetIsolate for &P { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + P::get_isolate_ptr(self) + } + } + + impl GetIsolate for TryCatch<'_, '_, P> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.scope.get_isolate_ptr() + } + } + + impl GetIsolate for CallbackScope<'_, C> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.isolate.as_ptr() + } + } + + impl GetIsolate for EscapableHandleScope<'_, '_, C> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.isolate.as_ptr() + } + } + + impl GetIsolate for AllowJavascriptExecutionScope<'_, '_, P> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.scope.get_isolate_ptr() + } + } + + impl GetIsolate for DisallowJavascriptExecutionScope<'_, '_, P> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.scope.get_isolate_ptr() + } + } +} + +pub trait NewHandleScope<'s> { + type NewScope: Scope; + + fn make_new_scope(me: &'s mut Self) -> Self::NewScope; +} + +impl<'s, 'p: 's, C> NewHandleScope<'s> for PinnedRef<'_, HandleScope<'p, C>> { + type NewScope = HandleScope<'s, C>; + + fn make_new_scope(me: &'s mut Self) -> Self::NewScope { + HandleScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: me.0.isolate, + context: Cell::new(me.0.context.get()), + _phantom: PhantomData, + _pinned: PhantomPinned, + } + } +} + +impl<'s> NewHandleScope<'s> for Isolate { + type NewScope = HandleScope<'s, ()>; + #[inline(always)] - pub unsafe fn unseal(&self, v: SealedLocal) -> Local<'s, T> { - unsafe { Local::from_non_null(v.0) } + fn make_new_scope(me: &'s mut Self) -> Self::NewScope { + HandleScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: unsafe { NonNull::new_unchecked(me.as_real_ptr()) }, + context: Cell::new(None), + _phantom: PhantomData, + _pinned: PhantomPinned, + } } } -// TODO(mmastrac): When the never type is stabilized, we can replace this trait -// with type bounds (https://github.com/rust-lang/rust/issues/35121): +impl<'s> NewHandleScope<'s> for OwnedIsolate { + type NewScope = HandleScope<'s, ()>; -// for<'l> DataError: From< as TryInto>>::Error>, -mod get_data_sealed { - use crate::DataError; - use std::convert::Infallible; + fn make_new_scope(me: &'s mut Self) -> Self::NewScope { + HandleScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: unsafe { NonNull::new_unchecked(me.get_isolate_ptr()) }, + context: Cell::new(None), + _phantom: PhantomData, + _pinned: PhantomPinned, + } + } +} - pub trait ToDataError { - fn to_data_error(self) -> DataError; +impl<'s, 'p: 's, 'i, C> NewHandleScope<'s> + for PinnedRef<'p, CallbackScope<'i, C>> +{ + type NewScope = HandleScope<'i, C>; + + fn make_new_scope(me: &'s mut Self) -> Self::NewScope { + HandleScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: me.0.isolate, + context: Cell::new(me.0.context.get()), + _phantom: PhantomData, + _pinned: PhantomPinned, + } } - impl ToDataError for DataError { - fn to_data_error(self) -> DataError { - self +} + +impl<'a, 'i> NewHandleScope<'a> for ContextScope<'_, '_, HandleScope<'i>> { + type NewScope = HandleScope<'i>; + fn make_new_scope(me: &'a mut Self) -> Self::NewScope { + HandleScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: unsafe { NonNull::new_unchecked(me.scope.get_isolate_ptr()) }, + context: Cell::new(Some(me.raw_handle_scope.entered_context)), + _phantom: PhantomData, + _pinned: PhantomPinned, } } - impl ToDataError for Infallible { - fn to_data_error(self) -> DataError { - unreachable!() +} + +pub(crate) struct ScopeData { + isolate: NonNull, + context: Cell>>, +} + +impl ScopeData { + #[inline(always)] + pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.isolate.as_ptr() + } + + pub(crate) fn get_current_context(&self) -> *mut Context { + if let Some(context) = self.context.get() { + context.as_ptr() + } else { + let isolate = self.get_isolate_ptr(); + let context = + unsafe { raw::v8__Isolate__GetCurrentContext(isolate) }.cast_mut(); + self + .context + .set(Some(unsafe { NonNull::new_unchecked(context) })); + context } } } impl<'s> HandleScope<'s> { + #[allow(clippy::new_ret_no_self)] + pub fn new>( + scope: &'s mut P, + ) -> ScopeStorage { + ScopeStorage::new(P::make_new_scope(scope)) + } +} + +impl<'s> PinnedRef<'s, HandleScope<'_>> { + /// Returns the context of the currently running JavaScript, or the context + /// on the top of the stack if no JavaScript is running + pub fn get_current_context(&self) -> Local<'s, Context> { + if let Some(context) = self.0.context.get() { + unsafe { Local::from_non_null(context) } + } else { + let isolate = self.0.isolate; + let context = + unsafe { raw::v8__Isolate__GetCurrentContext(isolate.as_ptr()) } + .cast_mut(); + unsafe { + self.0.context.set(Some(NonNull::new_unchecked(context))); + Local::from_raw_unchecked(context) + } + } + } + + /// Returns either the last context entered through V8's C++ API, or the + /// context of the currently running microtask while processing microtasks. + /// If a context is entered while executing a microtask, that context is + /// returned. + pub fn get_entered_or_microtask_context(&self) -> Local<'_, Context> { + let context_ptr = unsafe { + raw::v8__Isolate__GetEnteredOrMicrotaskContext(self.0.isolate.as_ptr()) + }; + unsafe { Local::from_raw_unchecked(context_ptr) } + } + /// Return data that was previously attached to the isolate snapshot via /// SnapshotCreator, and removes the reference to it. If called again with /// same `index` argument, this function returns `DataError::NoData`. @@ -302,7 +545,7 @@ impl<'s> HandleScope<'s> { /// convertible to type parameter `T`, otherwise `DataError::BadType` is /// returned. pub fn get_isolate_data_from_snapshot_once( - &mut self, + &self, index: usize, ) -> Result, DataError> where @@ -333,7 +576,7 @@ impl<'s> HandleScope<'s> { /// convertible to type parameter `T`, otherwise `DataError::BadType` is /// returned. pub fn get_context_data_from_snapshot_once( - &mut self, + &self, index: usize, ) -> Result, DataError> where @@ -361,16 +604,16 @@ impl<'s> HandleScope<'s> { #[inline(always)] pub fn set_promise_hooks( - &mut self, + &self, init_hook: Option>, before_hook: Option>, after_hook: Option>, resolve_hook: Option>, ) { unsafe { - let sd = data::ScopeData::get_mut(self); + let context = self.get_current_context(); raw::v8__Context__SetPromiseHooks( - sd.get_current_context(), + context.as_non_null().as_ptr(), init_hook.map_or_else(std::ptr::null, |v| &*v), before_hook.map_or_else(std::ptr::null, |v| &*v), after_hook.map_or_else(std::ptr::null, |v| &*v), @@ -380,23 +623,18 @@ impl<'s> HandleScope<'s> { } #[inline(always)] - pub fn set_continuation_preserved_embedder_data( - &mut self, - data: Local, - ) { + pub fn set_continuation_preserved_embedder_data(&self, data: Local) { unsafe { - let sd = data::ScopeData::get_mut(self); + let isolate = self.0.isolate; raw::v8__Context__SetContinuationPreservedEmbedderData( - sd.get_isolate_ptr(), + isolate.as_ptr(), &*data, ); } } #[inline(always)] - pub fn get_continuation_preserved_embedder_data( - &mut self, - ) -> Local<'s, Value> { + pub fn get_continuation_preserved_embedder_data(&self) -> Local<'s, Value> { unsafe { self .cast_local(|sd| { @@ -407,212 +645,303 @@ impl<'s> HandleScope<'s> { .unwrap() } } -} - -/// A HandleScope which first allocates a handle in the current scope -/// which will be later filled with the escape value. -// TODO(piscisaureus): type parameter `C` is not very useful in practice; being -// a source of complexity and potential confusion, it is desirable to -// eventually remove it. Blocker at the time of writing is that there are some -// tests that enter an `EscapableHandleScope` without creating a `ContextScope` -// at all. These tests need to updated first. -#[derive(Debug)] -pub struct EscapableHandleScope<'s, 'e: 's, C = Context> { - _data: NonNull, - _phantom: - PhantomData<(&'s mut raw::HandleScope, &'e mut raw::EscapeSlot, &'s C)>, -} - -impl<'s, 'e: 's> EscapableHandleScope<'s, 'e> { - #[allow(clippy::new_ret_no_self)] - pub fn new>( - param: &'s mut P, - ) -> P::NewScope { - param - .get_scope_data_mut() - .new_escapable_handle_scope_data() - .as_scope() - } -} -impl<'s, 'e: 's, C> EscapableHandleScope<'s, 'e, C> { - /// Pushes the value into the previous scope and returns a handle to it. - /// Cannot be called twice. - pub fn escape(&mut self, value: Local) -> Local<'e, T> - where - for<'l> Local<'l, T>: Into>, - { - let escape_slot = data::ScopeData::get_mut(self) - .get_escape_slot_mut() - .expect("internal error: EscapableHandleScope has no escape slot") - .take() - .expect("EscapableHandleScope::escape() called twice"); - escape_slot.escape(value) + /// Returns the host defined options set for currently running script or + /// module, if available. + #[inline(always)] + pub fn get_current_host_defined_options(&self) -> Option> { + let isolate_ptr = self.0.isolate.as_ptr(); + unsafe { + Local::from_raw(raw::v8__Isolate__GetCurrentHostDefinedOptions( + isolate_ptr, + )) + } } } -/// An external exception handler. -#[derive(Debug)] -pub struct TryCatch<'s, P> { - _data: NonNull, - _phantom: PhantomData<&'s mut P>, -} +// for<'l> DataError: From< as TryInto>>::Error>, +mod get_data_sealed { + use crate::DataError; + use std::convert::Infallible; -impl<'s, P: param::NewTryCatch<'s>> TryCatch<'s, P> { - #[allow(clippy::new_ret_no_self)] - pub fn new(param: &'s mut P) -> P::NewScope { - param.get_scope_data_mut().new_try_catch_data().as_scope() + pub trait ToDataError { + fn to_data_error(self) -> DataError; + } + impl ToDataError for DataError { + fn to_data_error(self) -> DataError { + self + } + } + impl ToDataError for Infallible { + fn to_data_error(self) -> DataError { + unreachable!() + } } } -impl

TryCatch<'_, P> { - /// Returns true if an exception has been caught by this try/catch block. +impl<'p> PinnedRef<'p, HandleScope<'_, ()>> { #[inline(always)] - pub fn has_caught(&self) -> bool { - unsafe { raw::v8__TryCatch__HasCaught(self.get_raw()) } + pub(crate) unsafe fn cast_local( + &self, + _f: impl FnOnce(&mut ScopeData) -> *const T, + ) -> Option> { + let mut data: ScopeData = ScopeData { + context: Cell::new(self.0.context.get()), + isolate: self.0.isolate, + }; + let ptr = _f(&mut data); + unsafe { Local::from_raw(ptr) } } - /// For certain types of exceptions, it makes no sense to continue execution. + /// Schedules an exception to be thrown when returning to JavaScript. When + /// an exception has been scheduled it is illegal to invoke any + /// JavaScript operation; the caller must return immediately and only + /// after the exception has been handled does it become legal to invoke + /// JavaScript operations. /// - /// If CanContinue returns false, the correct action is to perform any C++ - /// cleanup needed and then return. If CanContinue returns false and - /// HasTerminated returns true, it is possible to call - /// CancelTerminateExecution in order to continue calling into the engine. - #[inline(always)] - pub fn can_continue(&self) -> bool { - unsafe { raw::v8__TryCatch__CanContinue(self.get_raw()) } + /// This function always returns the `undefined` value. + pub fn throw_exception( + &self, + exception: Local<'p, Value>, + ) -> Local<'p, Value> { + unsafe { + self.cast_local(|sd| { + raw::v8__Isolate__ThrowException(sd.get_isolate_ptr(), &*exception) + }) + } + .unwrap() } - /// Returns true if an exception has been caught due to script execution - /// being terminated. + /// Open a handle passed from V8 in the current scope. /// - /// There is no JavaScript representation of an execution termination - /// exception. Such exceptions are thrown when the TerminateExecution - /// methods are called to terminate a long-running script. + /// # Safety /// - /// If such an exception has been thrown, HasTerminated will return true, - /// indicating that it is possible to call CancelTerminateExecution in order - /// to continue calling into the engine. + /// The handle must be rooted in this scope. #[inline(always)] - pub fn has_terminated(&self) -> bool { - unsafe { raw::v8__TryCatch__HasTerminated(self.get_raw()) } + pub unsafe fn unseal<'a, T>(&self, v: SealedLocal) -> Local<'a, T> { + unsafe { Local::from_non_null(v.0) } } +} - /// Returns true if verbosity is enabled. - #[inline(always)] - pub fn is_verbose(&self) -> bool { - unsafe { raw::v8__TryCatch__IsVerbose(self.get_raw()) } +impl HandleScope<'_, C> {} + +impl GetIsolate for Pin<&mut HandleScope<'_, C>> { + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.isolate.as_ptr() } +} - /// Set verbosity of the external exception handler. - /// - /// By default, exceptions that are caught by an external exception - /// handler are not reported. Call SetVerbose with true on an - /// external exception handler to have exceptions caught by the - /// handler reported as if they were not caught. - #[inline(always)] - pub fn set_verbose(&mut self, value: bool) { - unsafe { raw::v8__TryCatch__SetVerbose(self.get_raw_mut(), value) }; +/// Stack-allocated class which sets the execution context for all operations +/// executed within a local scope. After entering a context, all code compiled +/// and run is compiled and run in this context. +#[repr(C)] +pub struct ContextScope<'borrow, 'scope, P: ClearCachedContext> { + raw_handle_scope: raw::ContextScope, + scope: &'borrow mut PinnedRef<'scope, P>, +} + +impl ScopeInit for ContextScope<'_, '_, P> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + storage.projected() } + unsafe fn deinit(_me: &mut Self) {} +} - /// Set whether or not this TryCatch should capture a Message object - /// which holds source information about where the exception - /// occurred. True by default. - #[inline(always)] - pub fn set_capture_message(&mut self, value: bool) { - unsafe { raw::v8__TryCatch__SetCaptureMessage(self.get_raw_mut(), value) }; +impl<'p, P: ClearCachedContext> Deref for ContextScope<'_, 'p, P> { + type Target = PinnedRef<'p, P>; + fn deref(&self) -> &Self::Target { + self.scope } +} - /// Clears any exceptions that may have been caught by this try/catch block. - /// After this method has been called, HasCaught() will return false. Cancels - /// the scheduled exception if it is caught and ReThrow() is not called - /// before. - /// - /// It is not necessary to clear a try/catch block before using it again; if - /// another exception is thrown the previously caught exception will just be - /// overwritten. However, it is often a good idea since it makes it easier - /// to determine which operation threw a given exception. - #[inline(always)] - pub fn reset(&mut self) { - unsafe { raw::v8__TryCatch__Reset(self.get_raw_mut()) }; +impl DerefMut for ContextScope<'_, '_, P> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.scope } +} - #[inline(always)] - fn get_raw(&self) -> &raw::TryCatch { - data::ScopeData::get(self).get_try_catch() +impl sealed::Sealed for ContextScope<'_, '_, P> {} +impl Scope for ContextScope<'_, '_, P> {} + +mod new_context_scope { + + use super::{GetIsolate, Scope}; + use crate::{Context, Local}; + + pub trait NewContextScope<'s, 'c>: GetIsolate { + type NewScope: Scope; + + fn make_new_scope( + me: &'s mut Self, + context: Local<'c, Context>, + ) -> Self::NewScope; } +} +use new_context_scope::NewContextScope; - #[inline(always)] - fn get_raw_mut(&mut self) -> &mut raw::TryCatch { - data::ScopeData::get_mut(self).get_try_catch_mut() +mod clear_cached_context { + pub trait ClearCachedContext { + fn clear_cached_context(&self); + } +} +use clear_cached_context::ClearCachedContext; + +impl ClearCachedContext for HandleScope<'_, C> { + fn clear_cached_context(&self) { + self.context.set(None); + } +} + +impl ClearCachedContext for CallbackScope<'_, C> { + fn clear_cached_context(&self) {} +} + +impl ClearCachedContext for PinnedRef<'_, P> { + fn clear_cached_context(&self) { + self.0.clear_cached_context(); + } +} + +impl ClearCachedContext for EscapableHandleScope<'_, '_, C> { + fn clear_cached_context(&self) { + self.context.set(None); } } -impl<'s, 'p: 's, P> TryCatch<'s, P> +impl

Drop for ContextScope<'_, '_, P> where - Self: AsMut>, + P: ClearCachedContext, { - /// Returns the exception caught by this try/catch block. If no exception has - /// been caught an empty handle is returned. - /// - /// Note: v8.h states that "the returned handle is valid until this TryCatch - /// block has been destroyed". This is incorrect; the return value lives - /// no longer and no shorter than the active HandleScope at the time this - /// method is called. An issue has been opened about this in the V8 bug - /// tracker: https://bugs.chromium.org/p/v8/issues/detail?id=10537. - pub fn exception(&mut self) -> Option> { - unsafe { - self - .as_mut() - .cast_local(|sd| raw::v8__TryCatch__Exception(sd.get_try_catch())) - } + fn drop(&mut self) { + self.scope.0.clear_cached_context(); } +} - /// Returns the message associated with this exception. If there is - /// no message associated an empty handle is returned. - /// - /// Note: the remark about the lifetime for the `exception()` return value - /// applies here too. - pub fn message(&mut self) -> Option> { - unsafe { - self - .as_mut() - .cast_local(|sd| raw::v8__TryCatch__Message(sd.get_try_catch())) +impl<'scope, 'obj: 'scope, 'ct, P: Scope + GetIsolate> + NewContextScope<'scope, 'ct> for ContextScope<'_, 'obj, P> +where + P: ClearCachedContext, +{ + type NewScope = ContextScope<'scope, 'obj, P>; + + fn make_new_scope( + me: &'scope mut Self, + context: Local<'ct, Context>, + ) -> Self::NewScope { + ContextScope { + raw_handle_scope: raw::ContextScope::new(context), + scope: me.scope, } } +} - /// Throws the exception caught by this TryCatch in a way that avoids - /// it being caught again by this same TryCatch. As with ThrowException - /// it is illegal to execute any JavaScript operations after calling - /// ReThrow; the caller must return immediately to where the exception - /// is caught. - /// - /// This function returns the `undefined` value when successful, or `None` if - /// no exception was caught and therefore there was nothing to rethrow. - pub fn rethrow(&mut self) -> Option> { - unsafe { - self - .as_mut() - .cast_local(|sd| raw::v8__TryCatch__ReThrow(sd.get_try_catch_mut())) +impl<'scope, 'obj: 'scope, 'ct, 'i, C> NewContextScope<'scope, 'ct> + for PinnedRef<'obj, HandleScope<'i, C>> +where + 'ct: 'scope, +{ + type NewScope = ContextScope<'scope, 'obj, HandleScope<'i>>; + + fn make_new_scope( + me: &'scope mut Self, + context: Local<'ct, Context>, + ) -> Self::NewScope { + me.0.context.set(None); + ContextScope { + raw_handle_scope: raw::ContextScope::new(context), + scope: unsafe { + // SAFETY: we are adding the context, so we can mark that it now has a context. + // the types are the same aside from the type parameter, which is only used in a ZST + cast_pinned_ref_mut::, HandleScope<'i, Context>>(me) + }, } } } -impl<'s, 'p: 's, P> TryCatch<'s, P> -where - Self: AsMut>, +impl<'scope, 'obj: 'scope, 'i, 'ct, C> NewContextScope<'scope, 'ct> + for PinnedRef<'obj, CallbackScope<'i, C>> { - /// Returns the .stack property of the thrown object. If no .stack - /// property is present an empty handle is returned. - pub fn stack_trace(&mut self) -> Option> { - unsafe { - self.as_mut().cast_local(|sd| { - raw::v8__TryCatch__StackTrace( - sd.get_try_catch(), - sd.get_current_context(), + type NewScope = ContextScope<'scope, 'obj, HandleScope<'i>>; + + fn make_new_scope( + me: &'scope mut Self, + context: Local<'ct, Context>, + ) -> Self::NewScope { + ContextScope { + raw_handle_scope: raw::ContextScope::new(context), + scope: unsafe { + // we are adding the context, so we can mark that it now has a context. + // SAFETY: CallbackScope is a superset of HandleScope, so giving a "view" of + // the CallbackScope as a HandleScope is valid, and we won't ever move out of the transmuted + // value + cast_pinned_ref_mut::, HandleScope<'i, Context>>( + me, ) - }) + }, + } + } +} + +// these lifetimes are crazy. basically we have +// - 'borrow: the borrow of the scope +// - 'scope: the lifetime of the scope. this must be longer than 'borrow. this is the lifetime of the handles created from the scope. +// - 'i: the lifetime of the inner the `EscapableHandleScope` is made from +// - 'esc: the lifetime of the slot that the `EscapableHandleScope` will eventually escape to. this must be longer than 'i +// - 'ct: the lifetime of the context (this is _not_ the same as 'scope, it can be longer or shorter) +impl<'borrow, 'scope: 'borrow, 'i, 'esc: 'i, 'ct, C> + NewContextScope<'borrow, 'ct> + for PinnedRef<'scope, EscapableHandleScope<'i, 'esc, C>> +{ + type NewScope = ContextScope<'borrow, 'scope, EscapableHandleScope<'i, 'esc>>; + + fn make_new_scope( + me: &'borrow mut Self, + context: Local<'ct, Context>, + ) -> Self::NewScope { + ContextScope { + raw_handle_scope: raw::ContextScope::new(context), + scope: unsafe { + // SAFETY: layouts are the same aside from the type parameter, which is only used in a ZST + std::mem::transmute::< + &'borrow mut PinnedRef<'scope, EscapableHandleScope<'i, 'esc, C>>, + &'borrow mut PinnedRef< + 'scope, + EscapableHandleScope<'i, 'esc, Context>, + >, + >(me) + }, + } + } +} + +impl ClearCachedContext for ContextScope<'_, '_, P> { + fn clear_cached_context(&self) { + self.scope.0.clear_cached_context(); + } +} + +impl< + 'scope, + 'obj: 'scope, + 'ct, + P: NewContextScope<'scope, 'ct> + ClearCachedContext, +> ContextScope<'scope, 'obj, P> +{ + #[allow(clippy::new_ret_no_self)] + pub fn new( + param: &'scope mut P, + context: Local<'ct, Context>, + ) -> P::NewScope { + if param.get_isolate_ptr() + != unsafe { raw::v8__Context__GetIsolate(&*context) } + { + panic!( + "{} and Context do not belong to the same Isolate", + type_name::

() + ) } + param.clear_cached_context(); + P::make_new_scope(param, context) } } @@ -641,1660 +970,1172 @@ where /// - `&PropertyCallbackInfo` /// - `&PromiseRejectMessage` /// - `&FastApiCallbackOptions` +#[repr(C)] #[derive(Debug)] pub struct CallbackScope<'s, C = Context> { - _data: NonNull, - _phantom: PhantomData<&'s mut HandleScope<'s, C>>, + raw_handle_scope: raw::HandleScope, + isolate: NonNull, + context: Cell>>, + _phantom: PhantomData<&'s C>, + _pinned: PhantomPinned, + needs_scope: bool, } +assert_layout_subset!(HandleScope<'static, ()>, CallbackScope<'static, ()> { raw_handle_scope, isolate, context, _phantom, _pinned }); + impl<'s> CallbackScope<'s> { #[allow(clippy::new_ret_no_self)] - pub unsafe fn new>(param: P) -> P::NewScope { - let context = param.get_context(); - let scope_data = - data::ScopeData::get_current_mut(unsafe { param.get_isolate_mut() }); - // A HandleScope is not implicitly created for - // fast functions, so one must be opened here. - let scope_data = if P::NEEDS_SCOPE { - if let Some(context) = context { - scope_data.new_handle_scope_data_with_context(&context) - } else { - scope_data.new_handle_scope_data() - } - } else { - scope_data.new_callback_scope_data(context) - }; - // This scope needs to exit when dropped, as it - // must not live beyond the callback activation. - scope_data.disable_zombie(); - scope_data.as_scope() + pub unsafe fn new>( + param: P, + ) -> ScopeStorage { + ScopeStorage::new(P::make_new_scope(param)) } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(C)] -pub enum OnFailure { - CrashOnFailure, - ThrowOnFailure, - DumpOnFailure, +impl AsRef for CallbackScope<'_, C> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.isolate) } + } } -#[derive(Debug)] -pub struct DisallowJavascriptExecutionScope<'s, P> { - _data: NonNull, - _phantom: PhantomData<&'s mut P>, -} +impl ScopeInit for CallbackScope<'_, C> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + let storage_mut = unsafe { storage.get_unchecked_mut() }; + let isolate = storage_mut.scope.isolate; + if storage_mut.scope.needs_scope { + unsafe { + raw::HandleScope::init( + &mut storage_mut.scope.raw_handle_scope, + isolate, + ); + } + } -impl<'s, P: param::NewDisallowJavascriptExecutionScope<'s>> - DisallowJavascriptExecutionScope<'s, P> -{ - #[allow(clippy::new_ret_no_self)] - pub fn new(param: &'s mut P, on_failure: OnFailure) -> P::NewScope { - param - .get_scope_data_mut() - .new_disallow_javascript_execution_scope_data(on_failure) - .as_scope() + let projected = &mut storage_mut.scope; + unsafe { Pin::new_unchecked(projected) } } -} - -#[derive(Debug)] -pub struct AllowJavascriptExecutionScope<'s, P> { - _data: NonNull, - _phantom: PhantomData<&'s mut P>, -} -impl<'s, P: param::NewAllowJavascriptExecutionScope<'s>> - AllowJavascriptExecutionScope<'s, P> -{ - #[allow(clippy::new_ret_no_self)] - pub fn new(param: &'s mut P) -> P::NewScope { - param - .get_scope_data_mut() - .new_allow_javascript_execution_scope_data() - .as_scope() + unsafe fn deinit(me: &mut Self) { + if me.needs_scope { + unsafe { raw::v8__HandleScope__DESTRUCT(&mut me.raw_handle_scope) }; + } } } -macro_rules! impl_as { - // Implements `AsRef` and AsMut` on a scope type. - (<$($params:tt),+> $src_type:ty as Isolate) => { - impl<$($params),*> AsRef for $src_type { - fn as_ref(&self) -> &Isolate { - data::ScopeData::get(self).get_isolate() - } - } +impl sealed::Sealed for CallbackScope<'_, C> {} +impl Scope for CallbackScope<'_, C> {} - impl<$($params),*> AsMut for $src_type { - fn as_mut(&mut self) -> &mut Isolate { - data::ScopeData::get_mut(self).get_isolate_mut() - } - } - }; +pub trait NewCallbackScope<'s>: Sized + GetIsolate { + type NewScope: Scope; + const NEEDS_SCOPE: bool = false; - // Implements `AsRef` and `AsMut` traits for the purpose of converting a - // a scope reference to a scope reference with a different but compatible type. - (<$($params:tt),+> $src_type:ty as $tgt_type:ty) => { - impl<$($params),*> AsRef<$tgt_type> for $src_type { - fn as_ref(&self) -> &$tgt_type { - self.cast_ref() - } - } + #[inline] + fn get_context(&self) -> Option> { + None + } - impl<$($params),*> AsMut< $tgt_type> for $src_type { - fn as_mut(&mut self) -> &mut $tgt_type { - self.cast_mut() - } - } - }; + fn make_new_scope(me: Self) -> Self::NewScope; } -impl_as!(<'s, 'p, P> ContextScope<'s, P> as Isolate); -impl_as!(<'s, C> HandleScope<'s, C> as Isolate); -impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as Isolate); -impl_as!(<'s, P> TryCatch<'s, P> as Isolate); -impl_as!(<'s, P> DisallowJavascriptExecutionScope<'s, P> as Isolate); -impl_as!(<'s, P> AllowJavascriptExecutionScope<'s, P> as Isolate); -impl_as!(<'s, C> CallbackScope<'s, C> as Isolate); - -impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p, ()>); -impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p, ()>); -impl_as!(<'s, C> HandleScope<'s, C> as HandleScope<'s, ()>); -impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as HandleScope<'s, ()>); -impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as HandleScope<'p, ()>); -impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>); -impl_as!(<'s, 'p, C> DisallowJavascriptExecutionScope<'s, HandleScope<'p, C>> as HandleScope<'p, ()>); -impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>); -impl_as!(<'s, 'p, C> AllowJavascriptExecutionScope<'s, HandleScope<'p, C>> as HandleScope<'p, ()>); -impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as HandleScope<'p, ()>); -impl_as!(<'s, C> CallbackScope<'s, C> as HandleScope<'s, ()>); - -impl_as!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>); -impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); -impl_as!(<'s> HandleScope<'s> as HandleScope<'s>); -impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>); -impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>); -impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); -impl_as!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); -impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); -impl_as!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); -impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as HandleScope<'p>); -impl_as!(<'s> CallbackScope<'s> as HandleScope<'s>); - -impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e, ()>); -impl_as!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> as EscapableHandleScope<'s, 'e, ()>); -impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>); -impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>); -impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as EscapableHandleScope<'p, 'e, ()>); - -impl_as!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); -impl_as!(<'s, 'e> EscapableHandleScope<'s, 'e> as EscapableHandleScope<'s, 'e>); -impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); -impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); -impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); - -impl_as!(<'s, 'p, C> TryCatch<'s, HandleScope<'p, C>> as TryCatch<'s, HandleScope<'p, ()>>); -impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, HandleScope<'p, ()>>); -impl_as!(<'s, 'p, 'e, C> TryCatch<'s, EscapableHandleScope<'p, 'e, C>> as TryCatch<'s, EscapableHandleScope<'p, 'e, ()>>); - -impl_as!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as TryCatch<'s, HandleScope<'p>>); -impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, HandleScope<'p>>); -impl_as!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as TryCatch<'s, EscapableHandleScope<'p, 'e>>); - -impl_as!(<'s, 'p, C> DisallowJavascriptExecutionScope<'s, HandleScope<'p, C>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); -impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); -impl_as!(<'s, 'p, 'e, C> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>>); - -impl_as!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p>>); -impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as DisallowJavascriptExecutionScope<'s, HandleScope<'p>>); -impl_as!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>>); - -impl_as!(<'s, 'p, C> AllowJavascriptExecutionScope<'s, HandleScope<'p, C>> as AllowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); -impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as AllowJavascriptExecutionScope<'s, HandleScope<'p, ()>>); -impl_as!(<'s, 'p, 'e, C> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>> as AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>>); - -impl_as!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p>> as AllowJavascriptExecutionScope<'s, HandleScope<'p>>); -impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as AllowJavascriptExecutionScope<'s, HandleScope<'p>>); -impl_as!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>>); - -impl_as!(<'s, 'p, P> DisallowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); -impl_as!(<'s, 'p, P> AllowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); - -macro_rules! impl_deref { - (<$($params:tt),+> $src_type:ty as $tgt_type:ty) => { - impl<$($params),*> Deref for $src_type { - type Target = $tgt_type; - #[inline] - fn deref(&self) -> &Self::Target { - self.as_ref() - } - } - - impl<$($params),*> DerefMut for $src_type { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_mut() - } - } - }; +fn make_new_callback_scope<'a, C>( + isolate: impl GetIsolate, + context: Option>, +) -> CallbackScope<'a, C> { + CallbackScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: unsafe { NonNull::new_unchecked(isolate.get_isolate_ptr()) }, + context: Cell::new(context), + _phantom: PhantomData, + _pinned: PhantomPinned, + needs_scope: false, + } } -impl_deref!(<'s, 'p> ContextScope<'s, HandleScope<'p>> as HandleScope<'p>); -impl_deref!(<'s, 'p, 'e> ContextScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); - -impl_deref!(<'s> HandleScope<'s, ()> as Isolate); -impl_deref!(<'s> HandleScope<'s> as HandleScope<'s, ()>); +impl<'s> NewCallbackScope<'s> for &'s mut Isolate { + type NewScope = CallbackScope<'s, ()>; -impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e, ()> as HandleScope<'s, ()>); -impl_deref!(<'s, 'e> EscapableHandleScope<'s, 'e> as HandleScope<'s>); + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(&*me, None) + } +} -impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>); -impl_deref!(<'s, 'p> TryCatch<'s, HandleScope<'p>> as HandleScope<'p>); -impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>); -impl_deref!(<'s, 'p, 'e> TryCatch<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); +impl<'s> NewCallbackScope<'s> for &'s mut OwnedIsolate { + type NewScope = CallbackScope<'s, ()>; -impl_deref!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>); -impl_deref!(<'s, 'p> DisallowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); -impl_deref!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>); -impl_deref!(<'s, 'p, 'e> DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); -impl_deref!(<'s, 'p, P> DisallowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(&*me, None) + } +} -impl_deref!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p, ()>> as HandleScope<'p, ()>); -impl_deref!(<'s, 'p> AllowJavascriptExecutionScope<'s, HandleScope<'p>> as HandleScope<'p>); -impl_deref!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, ()>> as EscapableHandleScope<'p, 'e, ()>); -impl_deref!(<'s, 'p, 'e> AllowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e>> as EscapableHandleScope<'p, 'e>); -impl_deref!(<'s, 'p, P> AllowJavascriptExecutionScope<'s, TryCatch<'p, P>> as TryCatch<'p, P>); +impl<'s> NewCallbackScope<'s> for &'s FunctionCallbackInfo { + type NewScope = CallbackScope<'s>; -impl_deref!(<'s> CallbackScope<'s, ()> as HandleScope<'s, ()>); -impl_deref!(<'s> CallbackScope<'s> as HandleScope<'s>); + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(me, None) + } +} -macro_rules! impl_scope_drop { - (<$($params:tt),+> $type:ty) => { - unsafe impl<$($params),*> Scope for $type {} +impl<'s, T> NewCallbackScope<'s> for &'s PropertyCallbackInfo { + type NewScope = CallbackScope<'s>; - impl<$($params),*> Drop for $type { - #[inline(always)] - fn drop(&mut self) { - data::ScopeData::get_mut(self).notify_scope_dropped(); - } - } - }; + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(me, None) + } } -impl_scope_drop!(<'s, 'p, P> ContextScope<'s, P>); -impl_scope_drop!(<'s, C> HandleScope<'s, C> ); -impl_scope_drop!(<'s, 'e, C> EscapableHandleScope<'s, 'e, C> ); -impl_scope_drop!(<'s, P> TryCatch<'s, P> ); -impl_scope_drop!(<'s, P> DisallowJavascriptExecutionScope<'s, P>); -impl_scope_drop!(<'s, P> AllowJavascriptExecutionScope<'s, P>); -impl_scope_drop!(<'s, C> CallbackScope<'s, C> ); +impl<'s> NewCallbackScope<'s> for &'s FastApiCallbackOptions<'s> { + type NewScope = CallbackScope<'s>; + const NEEDS_SCOPE: bool = true; -pub unsafe trait Scope: Sized {} - -trait ScopeCast: Sized { - fn cast_ref(&self) -> &S; - fn cast_mut(&mut self) -> &mut S; + fn make_new_scope(me: Self) -> Self::NewScope { + let isolate = (*me).get_isolate_ptr(); + CallbackScope { + raw_handle_scope: unsafe { raw::HandleScope::uninit() }, + isolate: unsafe { NonNull::new_unchecked(isolate) }, + context: Cell::new(me.get_context().map(|c| c.as_non_null())), + _phantom: PhantomData, + _pinned: PhantomPinned, + needs_scope: Self::NEEDS_SCOPE, + } + } } -impl ScopeCast for T { - fn cast_ref(&self) -> &S { - assert_eq!(Layout::new::(), Layout::new::()); - unsafe { &*(self as *const _ as *const S) } +impl<'s> NewCallbackScope<'s> for Local<'s, Context> { + type NewScope = CallbackScope<'s>; + + #[inline] + fn get_context(&self) -> Option> { + Some(*self) } - fn cast_mut(&mut self) -> &mut S { - assert_eq!(Layout::new::(), Layout::new::()); - unsafe { &mut *(self as *mut _ as *mut S) } + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(me, Some(me.as_non_null())) } } -/// Scopes are typically constructed as the child of another scope. The scope -/// that is returned from `«Child»Scope::new(parent: &mut «Parent»Scope)` does -/// not necessarily have type `«Child»Scope`, but rather its type is a merger of -/// both the the parent and child scope types. -/// -/// For example: a `ContextScope` created inside `HandleScope<'a, ()>` does not -/// produce a `ContextScope`, but rather a `HandleScope<'a, Context>`, which -/// describes a scope that is both a `HandleScope` _and_ a `ContextScope`. -/// -/// The Traits in the (private) `param` module define which types can be passed -/// as a parameter to the `«Some»Scope::new()` constructor, and what the -/// actual, merged scope type will be that `new()` returns for a specific -/// parameter type. -mod param { - use super::*; +impl<'s> NewCallbackScope<'s> for Local<'s, Message> { + type NewScope = CallbackScope<'s>; - pub trait NewContextScope<'s>: getter::GetScopeData { - type NewScope: Scope; + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(me, None) } +} - impl<'s, 'p: 's, P: Scope> NewContextScope<'s> for ContextScope<'p, P> { - type NewScope = ContextScope<'s, P>; - } +impl<'s, T: Into> + GetIsolate> NewCallbackScope<'s> for T { + type NewScope = CallbackScope<'s>; - impl<'s, 'p: 's, C> NewContextScope<'s> for HandleScope<'p, C> { - type NewScope = ContextScope<'s, HandleScope<'p>>; + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(me, None) } +} - impl<'s, 'p: 's, 'e: 'p, C> NewContextScope<'s> - for EscapableHandleScope<'p, 'e, C> - { - type NewScope = ContextScope<'s, EscapableHandleScope<'p, 'e>>; - } +impl<'s> NewCallbackScope<'s> for &'s PromiseRejectMessage<'s> { + type NewScope = CallbackScope<'s>; - impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s> - for TryCatch<'p, P> - { - type NewScope =

>::NewScope; + fn make_new_scope(me: Self) -> Self::NewScope { + make_new_callback_scope(me, None) } +} - impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s> - for DisallowJavascriptExecutionScope<'p, P> - { - type NewScope =

>::NewScope; +impl<'s> AsRef>> for CallbackScope<'s, ()> { + fn as_ref(&self) -> &Pin<&'s mut HandleScope<'s, ()>> { + unsafe { std::mem::transmute(self) } } +} - impl<'s, 'p: 's, P: NewContextScope<'s>> NewContextScope<'s> - for AllowJavascriptExecutionScope<'p, P> - { - type NewScope =

>::NewScope; - } +/// An external exception handler. +#[repr(C)] +pub struct TryCatch<'scope, 'obj, P> { + raw_try_catch: raw::TryCatch, + scope: &'scope mut PinnedRef<'obj, P>, + _pinned: PhantomPinned, +} - impl<'s, 'p: 's, C> NewContextScope<'s> for CallbackScope<'p, C> { - type NewScope = ContextScope<'s, HandleScope<'p>>; +impl<'scope, P: NewTryCatch<'scope>> TryCatch<'scope, '_, P> { + #[allow(clippy::new_ret_no_self)] + pub fn new(param: &'scope mut P) -> ScopeStorage { + ScopeStorage::new(P::make_new_scope(param)) } +} - pub trait NewHandleScope<'s>: getter::GetScopeData { - type NewScope: Scope; +impl ScopeInit for TryCatch<'_, '_, P> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + let storage_mut = unsafe { storage.get_unchecked_mut() }; + let isolate = unsafe { + NonNull::new_unchecked(storage_mut.scope.scope.get_isolate_ptr()) + }; + unsafe { + raw::TryCatch::init(&mut storage_mut.scope.raw_try_catch, isolate); + } + let projected = &mut storage_mut.scope; + unsafe { Pin::new_unchecked(projected) } } - impl<'s> NewHandleScope<'s> for Isolate { - type NewScope = HandleScope<'s, ()>; + unsafe fn deinit(me: &mut Self) { + unsafe { raw::v8__TryCatch__DESTRUCT(&mut me.raw_try_catch) }; } +} - impl<'s> NewHandleScope<'s> for OwnedIsolate { - type NewScope = HandleScope<'s, ()>; +impl<'scope, 'obj: 'scope, 'iso: 'obj, P: GetIsolate> + PinnedRef<'_, TryCatch<'scope, 'obj, P>> +where + PinnedRef<'obj, P>: AsRef>>, +{ + /// Returns true if an exception has been caught by this try/catch block. + #[inline(always)] + pub fn has_caught(&self) -> bool { + unsafe { raw::v8__TryCatch__HasCaught(self.get_raw()) } } - impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> - for ContextScope<'p, P> - { - type NewScope =

>::NewScope; + /// For certain types of exceptions, it makes no sense to continue execution. + /// + /// If CanContinue returns false, the correct action is to perform any C++ + /// cleanup needed and then return. If CanContinue returns false and + /// HasTerminated returns true, it is possible to call + /// CancelTerminateExecution in order to continue calling into the engine. + #[inline(always)] + pub fn can_continue(&self) -> bool { + unsafe { raw::v8__TryCatch__CanContinue(self.get_raw()) } } - impl<'s, 'p: 's, C> NewHandleScope<'s> for HandleScope<'p, C> { - type NewScope = HandleScope<'s, C>; + /// Returns true if an exception has been caught due to script execution + /// being terminated. + /// + /// There is no JavaScript representation of an execution termination + /// exception. Such exceptions are thrown when the TerminateExecution + /// methods are called to terminate a long-running script. + /// + /// If such an exception has been thrown, HasTerminated will return true, + /// indicating that it is possible to call CancelTerminateExecution in order + /// to continue calling into the engine. + #[inline(always)] + pub fn has_terminated(&self) -> bool { + unsafe { raw::v8__TryCatch__HasTerminated(self.get_raw()) } } - impl<'s, 'p: 's, 'e: 'p, C> NewHandleScope<'s> - for EscapableHandleScope<'p, 'e, C> - { - type NewScope = EscapableHandleScope<'s, 'e, C>; + /// Returns true if verbosity is enabled. + #[inline(always)] + pub fn is_verbose(&self) -> bool { + unsafe { raw::v8__TryCatch__IsVerbose(self.get_raw()) } } - impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> for TryCatch<'p, P> { - type NewScope =

>::NewScope; + /// Set verbosity of the external exception handler. + /// + /// By default, exceptions that are caught by an external exception + /// handler are not reported. Call SetVerbose with true on an + /// external exception handler to have exceptions caught by the + /// handler reported as if they were not caught. + #[inline(always)] + pub fn set_verbose(&mut self, value: bool) { + unsafe { raw::v8__TryCatch__SetVerbose(self.get_raw_mut(), value) }; } - impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> - for DisallowJavascriptExecutionScope<'p, P> - { - type NewScope =

>::NewScope; + /// Set whether or not this TryCatch should capture a Message object + /// which holds source information about where the exception + /// occurred. True by default. + #[inline(always)] + pub fn set_capture_message(&mut self, value: bool) { + unsafe { raw::v8__TryCatch__SetCaptureMessage(self.get_raw_mut(), value) }; } - impl<'s, 'p: 's, P: NewHandleScope<'s>> NewHandleScope<'s> - for AllowJavascriptExecutionScope<'p, P> - { - type NewScope =

>::NewScope; + /// Clears any exceptions that may have been caught by this try/catch block. + /// After this method has been called, HasCaught() will return false. Cancels + /// the scheduled exception if it is caught and ReThrow() is not called + /// before. + /// + /// It is not necessary to clear a try/catch block before using it again; if + /// another exception is thrown the previously caught exception will just be + /// overwritten. However, it is often a good idea since it makes it easier + /// to determine which operation threw a given exception. + #[inline(always)] + pub fn reset(&mut self) { + unsafe { raw::v8__TryCatch__Reset(self.get_raw_mut()) }; } - impl<'s, 'p: 's, C> NewHandleScope<'s> for CallbackScope<'p, C> { - type NewScope = HandleScope<'s, C>; + #[inline(always)] + fn get_raw(&self) -> &raw::TryCatch { + &self.0.raw_try_catch } - pub trait NewHandleScopeWithContext<'s>: getter::GetScopeData { - fn get_isolate_mut(&mut self) -> &mut Isolate; + #[inline(always)] + unsafe fn get_raw_mut(&mut self) -> &mut raw::TryCatch { + unsafe { &mut self.0.as_mut().get_unchecked_mut().raw_try_catch } } - impl NewHandleScopeWithContext<'_> for Isolate { - #[inline] - fn get_isolate_mut(&mut self) -> &mut Isolate { + pub fn exception(&self) -> Option> { + unsafe { self + .0 + .scope + .as_ref() + .cast_local(|_data| raw::v8__TryCatch__Exception(self.get_raw())) } } - impl NewHandleScopeWithContext<'_> for OwnedIsolate { - #[inline] - fn get_isolate_mut(&mut self) -> &mut Isolate { - &mut *self + pub fn message(&self) -> Option> { + unsafe { + self + .0 + .scope + .as_ref() + .cast_local(|_data| raw::v8__TryCatch__Message(self.get_raw())) } } - pub trait NewEscapableHandleScope<'s, 'e: 's>: getter::GetScopeData { - type NewScope: Scope; - } - - impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>> - NewEscapableHandleScope<'s, 'e> for ContextScope<'p, P> - { - type NewScope =

>::NewScope; - } - - impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for HandleScope<'p, C> { - type NewScope = EscapableHandleScope<'s, 'p, C>; - } - - impl<'s, 'p: 's, 'e: 'p, C> NewEscapableHandleScope<'s, 'p> - for EscapableHandleScope<'p, 'e, C> - { - type NewScope = EscapableHandleScope<'s, 'p, C>; - } - - impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>> - NewEscapableHandleScope<'s, 'e> for TryCatch<'p, P> - { - type NewScope =

>::NewScope; - } - - impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>> - NewEscapableHandleScope<'s, 'e> - for DisallowJavascriptExecutionScope<'p, P> - { - type NewScope =

>::NewScope; - } - - impl<'s, 'p: 's, 'e: 'p, P: NewEscapableHandleScope<'s, 'e>> - NewEscapableHandleScope<'s, 'e> for AllowJavascriptExecutionScope<'p, P> - { - type NewScope =

>::NewScope; - } - - impl<'s, 'p: 's, C> NewEscapableHandleScope<'s, 'p> for CallbackScope<'p, C> { - type NewScope = EscapableHandleScope<'s, 'p, C>; - } - - pub trait NewTryCatch<'s>: getter::GetScopeData { - type NewScope: Scope; - } - - impl<'s, 'p: 's, P: NewTryCatch<'s>> NewTryCatch<'s> for ContextScope<'p, P> { - type NewScope =

>::NewScope; - } - - impl<'s, 'p: 's, C> NewTryCatch<'s> for HandleScope<'p, C> { - type NewScope = TryCatch<'s, HandleScope<'p, C>>; - } - - impl<'s, 'p: 's, 'e: 'p, C> NewTryCatch<'s> - for EscapableHandleScope<'p, 'e, C> - { - type NewScope = TryCatch<'s, EscapableHandleScope<'p, 'e, C>>; - } - - impl<'s, 'p: 's, P> NewTryCatch<'s> for TryCatch<'p, P> { - type NewScope = TryCatch<'s, P>; - } - - impl<'s, 'p: 's, P> NewTryCatch<'s> - for DisallowJavascriptExecutionScope<'p, P> - { - type NewScope = TryCatch<'s, P>; - } - - impl<'s, 'p: 's, P> NewTryCatch<'s> for AllowJavascriptExecutionScope<'p, P> { - type NewScope = TryCatch<'s, P>; + pub fn rethrow(&mut self) -> Option> { + let raw_mut = unsafe { self.get_raw_mut() as *mut raw::TryCatch }; + unsafe { + self + .0 + .scope + .as_ref() + .cast_local(|_data| raw::v8__TryCatch__ReThrow(raw_mut)) + } } - impl<'s, 'p: 's, C> NewTryCatch<'s> for CallbackScope<'p, C> { - type NewScope = TryCatch<'s, HandleScope<'p, C>>; + pub fn stack_trace(&self) -> Option> { + unsafe { + self.0.scope.as_ref().cast_local(|_data| { + raw::v8__TryCatch__StackTrace( + self.get_raw(), + _data.get_current_context(), + ) + }) + } } +} - pub trait NewDisallowJavascriptExecutionScope<'s>: - getter::GetScopeData - { - type NewScope: Scope; - } +impl

sealed::Sealed for TryCatch<'_, '_, P> {} +impl Scope for TryCatch<'_, '_, P> {} - impl<'s, 'p: 's, P: NewDisallowJavascriptExecutionScope<'s>> - NewDisallowJavascriptExecutionScope<'s> for ContextScope<'p, P> - { - type NewScope =

>::NewScope; - } +pub trait NewTryCatch<'scope>: GetIsolate { + type NewScope: Scope; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope; +} - impl<'s, 'p: 's, C> NewDisallowJavascriptExecutionScope<'s> - for HandleScope<'p, C> - { - type NewScope = DisallowJavascriptExecutionScope<'s, HandleScope<'p, C>>; +impl<'scope, 'obj: 'scope, 'i, C> NewTryCatch<'scope> + for PinnedRef<'obj, HandleScope<'i, C>> +{ + type NewScope = TryCatch<'scope, 'obj, HandleScope<'i, C>>; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope { + TryCatch { + scope: me, + raw_try_catch: unsafe { raw::TryCatch::uninit() }, + _pinned: PhantomPinned, + } } +} - impl<'s, 'p: 's, 'e: 'p, C> NewDisallowJavascriptExecutionScope<'s> - for EscapableHandleScope<'p, 'e, C> - { - type NewScope = - DisallowJavascriptExecutionScope<'s, EscapableHandleScope<'p, 'e, C>>; - } +// the lifetimes here are: +// - 'borrow: the lifetime of the borrow of the scope +// - 'scope: the lifetime of the escapable handle scope +// - 'obj: the lifetime of the handles created from the escapable handle scope +// - 'esc: the lifetime of the slot that the escapable handle scope will eventually escape to. this must be longer than 'obj +impl<'borrow, 'scope: 'borrow, 'obj: 'borrow, 'esc: 'obj, C> + NewTryCatch<'borrow> + for PinnedRef<'scope, EscapableHandleScope<'obj, 'esc, C>> +{ + type NewScope = + TryCatch<'borrow, 'scope, EscapableHandleScope<'obj, 'esc, C>>; - impl<'s, 'p: 's, P> NewDisallowJavascriptExecutionScope<'s> - for TryCatch<'p, P> - { - type NewScope = DisallowJavascriptExecutionScope<'s, TryCatch<'p, P>>; + fn make_new_scope(me: &'borrow mut Self) -> Self::NewScope { + TryCatch { + scope: me, + raw_try_catch: unsafe { raw::TryCatch::uninit() }, + _pinned: PhantomPinned, + } } +} - impl<'s, 'p: 's, P> NewDisallowJavascriptExecutionScope<'s> - for DisallowJavascriptExecutionScope<'p, P> - { - type NewScope = DisallowJavascriptExecutionScope<'s, P>; +impl<'scope, 'obj: 'scope, T: GetIsolate + Scope + ClearCachedContext> + NewTryCatch<'scope> for ContextScope<'_, 'obj, T> +{ + type NewScope = TryCatch<'scope, 'obj, T>; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope { + TryCatch { + scope: me, + raw_try_catch: unsafe { raw::TryCatch::uninit() }, + _pinned: PhantomPinned, + } } +} - impl<'s, 'p: 's, P> NewDisallowJavascriptExecutionScope<'s> - for AllowJavascriptExecutionScope<'p, P> - { - type NewScope = DisallowJavascriptExecutionScope<'s, P>; +impl<'scope, 'obj: 'scope, 'i, C> NewTryCatch<'scope> + for PinnedRef<'obj, CallbackScope<'i, C>> +{ + type NewScope = TryCatch<'scope, 'i, HandleScope<'i, C>>; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope { + TryCatch { + scope: unsafe { + std::mem::transmute::< + &mut PinnedRef<'_, CallbackScope<'_, C>>, + &mut PinnedRef<'_, HandleScope<'_, C>>, + >(me) + }, + raw_try_catch: unsafe { raw::TryCatch::uninit() }, + _pinned: PhantomPinned, + } } +} - pub trait NewAllowJavascriptExecutionScope<'s>: getter::GetScopeData { - type NewScope: Scope; +impl<'scope, 'obj: 'scope, 'obj_outer: 'obj, 'iso, C> NewTryCatch<'scope> + for PinnedRef<'obj, TryCatch<'_, 'obj_outer, HandleScope<'iso, C>>> +{ + type NewScope = TryCatch<'scope, 'obj_outer, HandleScope<'iso, C>>; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope { + TryCatch { + scope: unsafe { me.as_mut_ref().0.get_unchecked_mut().scope }, + raw_try_catch: unsafe { raw::TryCatch::uninit() }, + _pinned: PhantomPinned, + } } +} - impl<'s, 'p: 's, P: NewAllowJavascriptExecutionScope<'s>> - NewAllowJavascriptExecutionScope<'s> for ContextScope<'p, P> - { - type NewScope =

>::NewScope; - } +/// A HandleScope which first allocates a handle in the current scope +/// which will be later filled with the escape value. +#[repr(C)] +pub struct EscapableHandleScope<'s, 'esc: 's, C = Context> { + raw_handle_scope: raw::HandleScope, + isolate: NonNull, + context: Cell>>, + _phantom: + PhantomData<(&'s mut raw::HandleScope, &'esc mut raw::EscapeSlot, &'s C)>, + _pinned: PhantomPinned, + raw_escape_slot: Option, +} - impl<'s, 'p: 's, C> NewAllowJavascriptExecutionScope<'s> - for HandleScope<'p, C> - { - type NewScope = HandleScope<'p, C>; - } +assert_layout_subset!(HandleScope<'static, ()>, EscapableHandleScope<'static, 'static, ()> { + raw_handle_scope, + isolate, + context, + _phantom, + _pinned, +}); + +impl<'s, 'esc: 's, C> ScopeInit for EscapableHandleScope<'s, 'esc, C> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + let storage_mut = unsafe { storage.get_unchecked_mut() }; + unsafe { + let isolate = storage_mut.scope.isolate; + raw::HandleScope::init(&mut storage_mut.scope.raw_handle_scope, isolate); + } + let projected = &mut storage_mut.scope; - impl<'s, 'p: 's, 'e: 'p, C> NewAllowJavascriptExecutionScope<'s> - for EscapableHandleScope<'p, 'e, C> - { - type NewScope = EscapableHandleScope<'p, 'e, C>; + unsafe { Pin::new_unchecked(projected) } } - impl<'s, 'p: 's, P> NewAllowJavascriptExecutionScope<'s> for TryCatch<'p, P> { - type NewScope = TryCatch<'s, P>; + unsafe fn deinit(me: &mut Self) { + unsafe { raw::v8__HandleScope__DESTRUCT(&raw mut me.raw_handle_scope) }; } +} - impl<'s, 'p: 's, P: Scope> NewAllowJavascriptExecutionScope<'s> - for DisallowJavascriptExecutionScope<'p, P> - { - type NewScope = P; +impl<'s, 'esc: 's> EscapableHandleScope<'s, 'esc> { + #[allow(clippy::new_ret_no_self)] + pub fn new>( + scope: &'s mut P, + ) -> ScopeStorage { + ScopeStorage::new(P::make_new_scope(scope)) } +} - impl<'s, 'p: 's, P> NewAllowJavascriptExecutionScope<'s> - for AllowJavascriptExecutionScope<'p, P> +impl<'s, 'esc: 's, C> PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>> { + /// Pushes the value into the previous scope and returns a handle to it. + /// Cannot be called twice. + pub fn escape<'a, T>(&mut self, value: Local<'a, T>) -> Local<'esc, T> + where + for<'l> Local<'l, T>: Into>, { - type NewScope = AllowJavascriptExecutionScope<'s, P>; - } - - pub trait NewCallbackScope<'s>: Sized + getter::GetIsolate<'s> { - type NewScope: Scope; - const NEEDS_SCOPE: bool = false; - - #[inline] - fn get_context(&self) -> Option> { - None - } - } - - impl<'s> NewCallbackScope<'s> for &'s mut Isolate { - type NewScope = CallbackScope<'s, ()>; - } - - impl<'s> NewCallbackScope<'s> for &'s mut OwnedIsolate { - type NewScope = CallbackScope<'s, ()>; + let escape_slot = unsafe { self.0.as_mut().get_unchecked_mut() } + .raw_escape_slot + .take() + .expect("EscapableHandleScope::escape() called twice"); + escape_slot.escape(value) } +} - impl<'s> NewCallbackScope<'s> for &'s FunctionCallbackInfo { - type NewScope = CallbackScope<'s>; +impl<'p, 's, 'esc: 's, C> Deref + for PinnedRef<'p, EscapableHandleScope<'s, 'esc, C>> +{ + type Target = PinnedRef<'p, HandleScope<'s, C>>; + fn deref(&self) -> &Self::Target { + unsafe { std::mem::transmute(self) } } +} - impl<'s, T> NewCallbackScope<'s> for &'s PropertyCallbackInfo { - type NewScope = CallbackScope<'s>; +impl<'s, 'esc: 's, C> DerefMut + for PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>> +{ + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { std::mem::transmute(self) } } +} - impl<'s> NewCallbackScope<'s> for &'s FastApiCallbackOptions<'s> { - type NewScope = CallbackScope<'s>; - const NEEDS_SCOPE: bool = true; - } +pub trait NewEscapableHandleScope<'s> { + type NewScope: Scope; + fn make_new_scope(me: &'s mut Self) -> Self::NewScope; +} - impl<'s> NewCallbackScope<'s> for Local<'s, Context> { - type NewScope = CallbackScope<'s>; +impl<'s, 'obj: 's, C> NewEscapableHandleScope<'s> + for PinnedRef<'obj, HandleScope<'_, C>> +{ + type NewScope = EscapableHandleScope<'s, 'obj, C>; + fn make_new_scope(me: &'s mut Self) -> Self::NewScope { + // Note: the `raw_escape_slot` field must be initialized _before_ the + // `raw_handle_scope` field, otherwise the escaped local handle ends up + // inside the `EscapableHandleScope` that's being constructed here, + // rather than escaping from it. + let isolate = me.0.isolate; + let raw_escape_slot = raw::EscapeSlot::new(isolate); + let raw_handle_scope = unsafe { raw::HandleScope::uninit() }; - #[inline] - fn get_context(&self) -> Option> { - Some(*self) + EscapableHandleScope { + isolate, + context: Cell::new(me.0.context.get()), + raw_escape_slot: Some(raw_escape_slot), + raw_handle_scope, + _phantom: PhantomData, + _pinned: PhantomPinned, } } - - impl<'s> NewCallbackScope<'s> for Local<'s, Message> { - type NewScope = CallbackScope<'s>; - } - - impl<'s, T: Into>> NewCallbackScope<'s> for T { - type NewScope = CallbackScope<'s>; - } - - impl<'s> NewCallbackScope<'s> for &'s PromiseRejectMessage<'s> { - type NewScope = CallbackScope<'s>; - } } -/// The private `getter` module defines traits to look up the related `Isolate` -/// and `ScopeData` for many different types. The implementation of those traits -/// on the types that implement them are also all contained in this module. -mod getter { - pub use super::*; - - pub trait GetIsolate<'s> { - unsafe fn get_isolate_mut(self) -> &'s mut Isolate; - } - - impl<'s> GetIsolate<'s> for &'s mut Isolate { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - self - } +impl<'borrow, 'obj: 'borrow, C> NewEscapableHandleScope<'borrow> + for ContextScope<'_, 'obj, HandleScope<'_, C>> +{ + type NewScope = EscapableHandleScope<'borrow, 'obj, C>; + fn make_new_scope(me: &'borrow mut Self) -> Self::NewScope { + NewEscapableHandleScope::make_new_scope(me.scope) } +} - impl<'s> GetIsolate<'s> for &'s mut OwnedIsolate { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - &mut *self +impl<'borrow, 's: 'borrow, 'esc: 'borrow, C> NewEscapableHandleScope<'borrow> + for PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>> +{ + type NewScope = EscapableHandleScope<'borrow, 's, C>; + fn make_new_scope(me: &'borrow mut Self) -> Self::NewScope { + // Note: the `raw_escape_slot` field must be initialized _before_ the + // `raw_handle_scope` field, otherwise the escaped local handle ends up + // inside the `EscapableHandleScope` that's being constructed here, + // rather than escaping from it. + let isolate = me.0.isolate; + let raw_escape_slot = raw::EscapeSlot::new(isolate); + let raw_handle_scope = unsafe { raw::HandleScope::uninit() }; + EscapableHandleScope { + isolate, + context: Cell::new(me.0.context.get()), + raw_escape_slot: Some(raw_escape_slot), + raw_handle_scope, + _phantom: PhantomData, + _pinned: PhantomPinned, } } +} - impl<'s> GetIsolate<'s> for &'s FunctionCallbackInfo { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - unsafe { &mut *self.get_isolate_ptr() } - } - } +impl<'s, 'esc: 's, C> sealed::Sealed for EscapableHandleScope<'s, 'esc, C> {} +impl<'s, 'esc: 's, C> Scope for EscapableHandleScope<'s, 'esc, C> {} - impl<'s, T> GetIsolate<'s> for &'s PropertyCallbackInfo { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - unsafe { &mut *self.get_isolate_ptr() } - } - } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub enum OnFailure { + CrashOnFailure, + ThrowOnFailure, + DumpOnFailure, +} - impl<'s> GetIsolate<'s> for &'s FastApiCallbackOptions<'s> { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - unsafe { &mut *self.isolate } - } - } +#[repr(C)] +pub struct DisallowJavascriptExecutionScope<'scope, 'obj, P> { + raw: raw::DisallowJavascriptExecutionScope, + scope: &'scope mut PinnedRef<'obj, P>, + on_failure: OnFailure, + _pinned: PhantomPinned, +} - impl<'s> GetIsolate<'s> for Local<'s, Context> { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - unsafe { &mut *raw::v8__Context__GetIsolate(&*self) } +impl ScopeInit for DisallowJavascriptExecutionScope<'_, '_, P> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + // SAFETY: we aren't going to move the raw scope out + let storage_mut = unsafe { storage.get_unchecked_mut() }; + let isolate = storage_mut.scope.scope.get_isolate_ptr(); + let on_failure = storage_mut.scope.on_failure; + // SAFETY: calling the raw function, isolate is valid, and the raw scope won't be moved + unsafe { + raw::DisallowJavascriptExecutionScope::init( + &mut storage_mut.scope.raw, + NonNull::new_unchecked(isolate), + on_failure, + ); + Pin::new_unchecked(&mut storage_mut.scope) } } - impl<'s> GetIsolate<'s> for Local<'s, Message> { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - unsafe { &mut *raw::v8__Message__GetIsolate(&*self) } - } + unsafe fn deinit(me: &mut Self) { + unsafe { raw::v8__DisallowJavascriptExecutionScope__DESTRUCT(&mut me.raw) }; } +} - impl<'s, T: Into>> GetIsolate<'s> for T { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - let object: Local = self.into(); - unsafe { &mut *raw::v8__Object__GetIsolate(&*object) } - } - } +impl sealed::Sealed + for DisallowJavascriptExecutionScope<'_, '_, P> +{ +} +impl Scope + for DisallowJavascriptExecutionScope<'_, '_, P> +{ +} - impl<'s> GetIsolate<'s> for &'s PromiseRejectMessage<'s> { - #[inline] - unsafe fn get_isolate_mut(self) -> &'s mut Isolate { - let object: Local = self.get_promise().into(); - unsafe { &mut *raw::v8__Object__GetIsolate(&*object) } - } +impl<'scope, P: NewDisallowJavascriptExecutionScope<'scope>> + DisallowJavascriptExecutionScope<'scope, '_, P> +{ + #[allow(clippy::new_ret_no_self)] + pub fn new( + param: &'scope mut P, + on_failure: OnFailure, + ) -> ScopeStorage { + ScopeStorage::new(P::make_new_scope(param, on_failure)) } +} - pub trait GetScopeData { - fn get_scope_data_mut(&mut self) -> &mut data::ScopeData; - } +pub trait NewDisallowJavascriptExecutionScope<'scope> { + type NewScope: Scope; + fn make_new_scope( + me: &'scope mut Self, + on_failure: OnFailure, + ) -> Self::NewScope; +} - impl GetScopeData for T { - fn get_scope_data_mut(&mut self) -> &mut data::ScopeData { - data::ScopeData::get_mut(self) - } +impl<'scope, 'obj, P> NewDisallowJavascriptExecutionScope<'scope> + for ContextScope<'_, 'obj, P> +where + P: ClearCachedContext, + PinnedRef<'obj, P>: NewDisallowJavascriptExecutionScope<'scope>, +{ + type NewScope = as NewDisallowJavascriptExecutionScope< + 'scope, + >>::NewScope; + fn make_new_scope( + me: &'scope mut Self, + on_failure: OnFailure, + ) -> Self::NewScope { + PinnedRef::<'obj, P>::make_new_scope(me.scope, on_failure) } +} - impl GetScopeData for Isolate { - #[inline] - fn get_scope_data_mut(&mut self) -> &mut data::ScopeData { - data::ScopeData::get_root_mut(self) - } - } +impl<'scope, 'obj: 'scope, P: Scope + GetIsolate> + NewDisallowJavascriptExecutionScope<'scope> for PinnedRef<'obj, P> +{ + type NewScope = DisallowJavascriptExecutionScope<'scope, 'obj, P>; - impl GetScopeData for OwnedIsolate { - #[inline] - fn get_scope_data_mut(&mut self) -> &mut data::ScopeData { - data::ScopeData::get_root_mut(self) + fn make_new_scope( + me: &'scope mut Self, + on_failure: OnFailure, + ) -> Self::NewScope { + DisallowJavascriptExecutionScope { + raw: unsafe { raw::DisallowJavascriptExecutionScope::uninit() }, + scope: me, + on_failure, + _pinned: PhantomPinned, } } } -/// All publicly exported `«Some»Scope` types are essentially wrapping a pointer -/// to a heap-allocated struct `ScopeData`. This module contains the definition -/// for `ScopeData` and its inner types, as well as related helper traits. -pub(crate) mod data { - use super::*; - - #[derive(Debug)] - pub struct ScopeData { - // The first four fields are always valid - even when the `Box` - // struct is free (does not contain data related to an actual scope). - // The `previous` and `isolate` fields never change; the `next` field is - // set to `None` initially when the struct is created, but it may later be - // assigned a `Some(Box)` value, after which this field never - // changes again. - isolate: NonNull, - previous: Option>, - next: Option>, - // The 'status' field is also always valid (but does change). - status: Cell, - // The following fields are only valid when this ScopeData object is in use - // (eiter current or shadowed -- not free). - context: Cell>>, - escape_slot: Option>>, - try_catch: Option>, - scope_type_specific_data: ScopeTypeSpecificData, - } - - impl ScopeData { - /// Returns a mutable reference to the data associated with topmost scope - /// on the scope stack. This function does not automatically exit zombie - /// scopes, so it might return a zombie ScopeData reference. - #[inline(always)] - pub(crate) fn get_current_mut(isolate: &mut Isolate) -> &mut Self { - let self_mut = isolate - .get_current_scope_data() - .map(NonNull::as_ptr) - .map(|p| unsafe { &mut *p }) - .unwrap(); - match self_mut.status.get() { - ScopeStatus::Current { .. } => self_mut, - _ => unreachable!(), - } - } - - /// Initializes the scope stack by creating a 'dummy' `ScopeData` at the - /// very bottom. This makes it possible to store the freelist of reusable - /// ScopeData objects even when no scope is entered. - pub(crate) fn new_root(isolate: &mut Isolate) { - let root = Box::leak(Self::boxed(isolate.into())); - root.status = ScopeStatus::Current { zombie: false }.into(); - debug_assert!(isolate.get_current_scope_data().is_none()); - isolate.set_current_scope_data(Some(root.into())); - } - - /// Activates and returns the 'root' `ScopeData` object that is created when - /// the isolate is initialized. In order to do so, any zombie scopes that - /// remain on the scope stack are cleaned up. - /// - /// # Panics - /// - /// This function panics if the root can't be activated because there are - /// still other scopes on the stack and they're not zombies. - #[inline(always)] - pub(crate) fn get_root_mut(isolate: &mut Isolate) -> &mut Self { - let mut current_scope_data = Self::get_current_mut(isolate); - loop { - current_scope_data = match current_scope_data { - root if root.previous.is_none() => break root, - data => data.try_exit_scope(), - }; - } - } - - /// Drops the scope stack and releases all `Box` allocations. - /// This function should be called only when an Isolate is being disposed. - pub(crate) fn drop_root(isolate: &mut Isolate) { - let root = Self::get_root_mut(isolate); - unsafe { - let _ = Box::from_raw(root); - }; - isolate.set_current_scope_data(None); - } - - #[inline(always)] - pub(super) fn new_context_scope_data<'s>( - &'s mut self, - context: Local<'s, Context>, - ) -> &'s mut Self { - self.new_scope_data_with(move |data| { - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::ContextScope { - _raw_context_scope: raw::ContextScope::new(context), - } - }); - data.context.set(Some(context.as_non_null())); - }) - } - - /// Implementation helper function, which creates the raw `HandleScope`, but - /// defers (maybe) entering a context to the provided callback argument. - /// This function gets called by `Self::new_handle_scope_data()` and - /// `Self::new_handle_scope_data_with_context()`. - #[inline(always)] - fn new_handle_scope_data_with(&mut self, init_context_fn: F) -> &mut Self - where - F: FnOnce( - NonNull, - &mut Cell>>, - &mut Option, - ), - { - self.new_scope_data_with(|data| { - let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::HandleScope { - allow_zombie: true, - raw_handle_scope: unsafe { raw::HandleScope::uninit() }, - raw_context_scope: None, - } - }); - match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::HandleScope { - raw_handle_scope, - raw_context_scope, - .. - } => { - unsafe { raw_handle_scope.init(isolate) }; - init_context_fn(isolate, &mut data.context, raw_context_scope); - } - _ => unreachable!(), - }; - }) - } - - #[inline(always)] - pub(super) fn disable_zombie(&mut self) { - if let ScopeTypeSpecificData::HandleScope { allow_zombie, .. } = - &mut self.scope_type_specific_data - { - *allow_zombie = false; - } - } - - #[inline(always)] - pub(super) fn new_handle_scope_data(&mut self) -> &mut Self { - self.new_handle_scope_data_with(|_, _, raw_context_scope| { - debug_assert!(raw_context_scope.is_none()); - }) - } - - #[inline(always)] - pub(super) fn new_handle_scope_data_with_context( - &mut self, - context_ref: &Context, - ) -> &mut Self { - self.new_handle_scope_data_with( - move |isolate, context_data, raw_context_scope| unsafe { - let context_nn = NonNull::from(context_ref); - // Copy the `Context` reference to a new local handle to enure that it - // cannot get garbage collected until after this scope is dropped. - let local_context_ptr = - raw::v8__Local__New(isolate.as_ptr(), context_nn.cast().as_ptr()) - as *const Context; - let local_context_nn = - NonNull::new_unchecked(local_context_ptr as *mut _); - let local_context = Local::from_non_null(local_context_nn); - // Initialize the `raw::ContextScope`. This enters the context too. - debug_assert!(raw_context_scope.is_none()); - ptr::write( - raw_context_scope, - Some(raw::ContextScope::new(local_context)), - ); - // Also store the newly created `Local` in the `Cell` that - // serves as a look-up cache for the current context. - context_data.set(Some(local_context_nn)); - }, - ) - } - - #[inline(always)] - pub(super) fn new_escapable_handle_scope_data(&mut self) -> &mut Self { - self.new_scope_data_with(|data| { - // Note: the `raw_escape_slot` field must be initialized _before_ the - // `raw_handle_scope` field, otherwise the escaped local handle ends up - // inside the `EscapableHandleScope` that's being constructed here, - // rather than escaping from it. - let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::EscapableHandleScope { - raw_handle_scope: unsafe { raw::HandleScope::uninit() }, - raw_escape_slot: Some(raw::EscapeSlot::new(isolate)), - } - }); - match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::EscapableHandleScope { - raw_handle_scope, - raw_escape_slot, - } => { - unsafe { raw_handle_scope.init(isolate) }; - data.escape_slot.replace(raw_escape_slot.into()); - } - _ => unreachable!(), - } - }) - } - - #[inline(always)] - pub(super) fn new_try_catch_data(&mut self) -> &mut Self { - self.new_scope_data_with(|data| { - let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::TryCatch { - raw_try_catch: unsafe { raw::TryCatch::uninit() }, - } - }); - match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::TryCatch { raw_try_catch } => { - unsafe { raw_try_catch.init(isolate) }; - data.try_catch.replace(raw_try_catch.into()); - } - _ => unreachable!(), - } - }) - } - - #[inline(always)] - pub(super) fn new_disallow_javascript_execution_scope_data( - &mut self, - on_failure: OnFailure, - ) -> &mut Self { - self.new_scope_data_with(|data| { - let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::DisallowJavascriptExecutionScope { - raw_scope: unsafe { - raw::DisallowJavascriptExecutionScope::uninit() - }, - } - }); - match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::DisallowJavascriptExecutionScope { - raw_scope, - } => unsafe { raw_scope.init(isolate, on_failure) }, - _ => unreachable!(), - } - }) - } +#[repr(C)] +pub struct AllowJavascriptExecutionScope<'scope, 'obj, P> { + raw: raw::AllowJavascriptExecutionScope, + scope: &'scope mut PinnedRef<'obj, P>, + _pinned: PhantomPinned, +} - #[inline(always)] - pub(super) fn new_allow_javascript_execution_scope_data( - &mut self, - ) -> &mut Self { - self.new_scope_data_with(|data| { - let isolate = data.isolate; - data.scope_type_specific_data.init_with(|| { - ScopeTypeSpecificData::AllowJavascriptExecutionScope { - raw_scope: unsafe { raw::AllowJavascriptExecutionScope::uninit() }, - } - }); - match &mut data.scope_type_specific_data { - ScopeTypeSpecificData::AllowJavascriptExecutionScope { - raw_scope, - } => unsafe { raw_scope.init(isolate) }, - _ => unreachable!(), - } - }) +impl ScopeInit for AllowJavascriptExecutionScope<'_, '_, P> { + fn init_stack(storage: Pin<&mut ScopeStorage>) -> Pin<&mut Self> { + let storage_mut = unsafe { storage.get_unchecked_mut() }; + let isolate = unsafe { + NonNull::new_unchecked(storage_mut.scope.scope.get_isolate_ptr()) + }; + unsafe { + raw::AllowJavascriptExecutionScope::init( + &mut storage_mut.scope.raw, + isolate, + ); } + let projected = &mut storage_mut.scope; + unsafe { Pin::new_unchecked(projected) } + } - #[inline(always)] - pub(super) fn new_callback_scope_data<'s>( - &'s mut self, - maybe_current_context: Option>, - ) -> &'s mut Self { - self.new_scope_data_with(|data| { - debug_assert!(data.scope_type_specific_data.is_none()); - data - .context - .set(maybe_current_context.map(|cx| cx.as_non_null())); - }) - } + unsafe fn deinit(me: &mut Self) { + unsafe { raw::v8__AllowJavascriptExecutionScope__DESTRUCT(&mut me.raw) }; + } +} - #[inline(always)] - fn new_scope_data_with( - &mut self, - init_fn: impl FnOnce(&mut Self), - ) -> &mut Self { - // Mark this scope (the parent of the newly created scope) as 'shadowed'; - self.status.set(match self.status.get() { - ScopeStatus::Current { zombie } => ScopeStatus::Shadowed { zombie }, - _ => unreachable!(), - }); - // Copy fields that that will be inherited by the new scope. - let context = self.context.get().into(); - let escape_slot = self.escape_slot; - // Initialize the `struct ScopeData` for the new scope. - let new_scope_data = self.allocate_or_reuse_scope_data(); - // In debug builds, `zombie` is initially set to `true`, and the flag is - // later cleared in the `as_scope()` method, to verify that we're - // always creating exactly one scope from any `ScopeData` object. - // For performance reasons this check is not performed in release builds. - new_scope_data.status = Cell::new(ScopeStatus::Current { - zombie: cfg!(debug_assertions), - }); - // Store fields inherited from the parent scope. - new_scope_data.context = context; - new_scope_data.escape_slot = escape_slot; - (init_fn)(new_scope_data); - // Make the newly created scope the 'current' scope for this isolate. - let new_scope_nn = unsafe { NonNull::new_unchecked(new_scope_data) }; - new_scope_data - .get_isolate_mut() - .set_current_scope_data(Some(new_scope_nn)); - new_scope_data - } - - /// Either returns an free `Box` that is available for reuse, - /// or allocates a new one on the heap. - #[inline(always)] - fn allocate_or_reuse_scope_data(&mut self) -> &mut Self { - let self_nn = NonNull::new(self); - match &mut self.next { - Some(next_box) => { - // Reuse a free `Box` allocation. - debug_assert_eq!(next_box.isolate, self.isolate); - debug_assert_eq!(next_box.previous, self_nn); - debug_assert_eq!(next_box.status.get(), ScopeStatus::Free); - debug_assert!(next_box.scope_type_specific_data.is_none()); - next_box.as_mut() - } - next_field @ None => { - // Allocate a new `Box`. - let mut next_box = Self::boxed(self.isolate); - next_box.previous = self_nn; - next_field.replace(next_box); - next_field.as_mut().unwrap() - } - } - } +impl sealed::Sealed + for AllowJavascriptExecutionScope<'_, '_, P> +{ +} +impl Scope for AllowJavascriptExecutionScope<'_, '_, P> {} - #[inline(always)] - pub(super) fn as_scope(&mut self) -> S { - assert_eq!(Layout::new::<&mut Self>(), Layout::new::()); - // In debug builds, a new initialized `ScopeStatus` will have the `zombie` - // flag set, so we have to reset it. In release builds, new `ScopeStatus` - // objects come with the `zombie` flag cleared, so no update is necessary. - if cfg!(debug_assertions) { - assert_eq!(self.status.get(), ScopeStatus::Current { zombie: true }); - self.status.set(ScopeStatus::Current { zombie: false }); - } - let self_nn = NonNull::from(self); - unsafe { ptr::read(&self_nn as *const _ as *const S) } - } +impl<'scope, P: NewAllowJavascriptExecutionScope<'scope>> + AllowJavascriptExecutionScope<'scope, '_, P> +{ + #[allow(clippy::new_ret_no_self)] + pub fn new(param: &'scope mut P) -> ScopeStorage { + ScopeStorage::new(P::make_new_scope(param)) + } +} - #[inline(always)] - pub(super) fn get(scope: &S) -> &Self { - let self_mut = unsafe { - (*(scope as *const S as *mut S as *mut NonNull)).as_mut() - }; - self_mut.try_activate_scope(); - self_mut - } +pub trait NewAllowJavascriptExecutionScope<'scope> { + type NewScope: Scope; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope; +} - #[inline(always)] - pub(super) fn get_mut(scope: &mut S) -> &mut Self { - let self_mut = - unsafe { (*(scope as *mut S as *mut NonNull)).as_mut() }; - self_mut.try_activate_scope(); - self_mut +impl<'scope, 'obj: 'scope, P: Scope + GetIsolate> + NewAllowJavascriptExecutionScope<'scope> for PinnedRef<'obj, P> +{ + type NewScope = AllowJavascriptExecutionScope<'scope, 'obj, P>; + fn make_new_scope(me: &'scope mut Self) -> Self::NewScope { + AllowJavascriptExecutionScope { + raw: unsafe { raw::AllowJavascriptExecutionScope::uninit() }, + scope: me, + _pinned: PhantomPinned, } + } +} - #[inline(always)] - fn try_activate_scope(mut self: &mut Self) -> &mut Self { - self = match self.status.get() { - ScopeStatus::Current { zombie: false } => self, - ScopeStatus::Shadowed { zombie: false } => { - self.next.as_mut().unwrap().try_exit_scope() - } - _ => unreachable!(), - }; - debug_assert_eq!( - self.get_isolate().get_current_scope_data(), - NonNull::new(self as *mut _) - ); - self - } +// Note: the macros below _do not_ use std::pin::pin! because +// it leads to worse compiler errors when the scope doesn't live long enough. +// Instead, we do the same thing as std::pin::pin! but without the additional temporary scope. + +#[allow(unused_macros, clippy::macro_metavars_in_unsafe)] +#[macro_export] +macro_rules! callback_scope { + (unsafe $scope: ident, $param: expr $(,)?) => { + #[allow(clippy::macro_metavars_in_unsafe)] + let mut $scope = { + // force the caller to put a separate unsafe block around the param expr + let param = $param; + unsafe { $crate::CallbackScope::new(param) } + }; + // SAFETY: we are shadowing the original binding, so it can't be accessed + // ever again + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + }; + (unsafe let $scope: ident, $param: expr $(,)?) => { + $crate::callback_scope!(unsafe $scope, $param); + } +} - #[inline(always)] - fn try_exit_scope(mut self: &mut Self) -> &mut Self { - loop { - self = match self.status.get() { - ScopeStatus::Shadowed { .. } => { - self.next.as_mut().unwrap().try_exit_scope() - } - ScopeStatus::Current { zombie: true } => break self.exit_scope(), - ScopeStatus::Current { zombie: false } => { - panic!("active scope can't be dropped") - } - _ => unreachable!(), - } - } - } +#[allow(unused_imports)] +pub(crate) use callback_scope; - #[inline(always)] - fn exit_scope(&mut self) -> &mut Self { - // Clear out the scope type specific data field. None of the other fields - // have a destructor, and there's no need to do any cleanup on them. - if !matches!(self.scope_type_specific_data, ScopeTypeSpecificData::None) { - self.scope_type_specific_data = Default::default(); - } +/// Creates a pinned `HandleScope` and binds `&mut PinScope` to `$scope`. +/// +/// ```rust +/// v8::scope!(let scope, isolate); +/// ``` +#[allow(unused_macros)] +#[macro_export] +macro_rules! scope { + ($scope: ident, $param: expr $(,)?) => { + let mut $scope = $crate::HandleScope::new($param); + // SAFETY: we are shadowing the original binding, so it can't be accessed + // ever again + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + }; + (let $scope: ident, $param: expr $(,)?) => { + $crate::scope!($scope, $param); + }; +} - // Change the ScopeData's status field from 'Current' to 'Free', which - // means that it is not associated with a scope and can be reused. - self.status.set(ScopeStatus::Free); +#[allow(unused_imports)] +pub(crate) use scope; + +#[allow(unused_macros)] +#[macro_export] +macro_rules! scope_with_context { + ($scope: ident, $param: expr, $context: expr $(,)?) => { + let mut $scope = $crate::HandleScope::new($param); + // SAFETY: we are shadowing the original binding, so it can't be accessed + // ever again + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + let context = v8::Local::new($scope, $context); + let $scope = &mut $crate::ContextScope::new($scope, context); + }; + (let $scope: ident, $param: expr, $context: expr $(,)?) => { + $crate::scope_with_context!($scope, $param, $context); + }; +} - // Point the Isolate's current scope data slot at our parent scope. - let previous_nn = self.previous.unwrap(); - self - .get_isolate_mut() - .set_current_scope_data(Some(previous_nn)); - - // Update the parent scope's status field to reflect that it is now - // 'Current' again an no longer 'Shadowed'. - let previous_mut = unsafe { &mut *previous_nn.as_ptr() }; - previous_mut.status.set(match previous_mut.status.get() { - ScopeStatus::Shadowed { zombie } => ScopeStatus::Current { zombie }, - _ => unreachable!(), - }); - - previous_mut - } - - /// This function is called when any of the public scope objects (e.g - /// `HandleScope`, `ContextScope`, etc.) are dropped. - /// - /// The Rust borrow checker allows values of type `HandleScope<'a>` and - /// `EscapableHandleScope<'a, 'e>` to be dropped before their maximum - /// lifetime ('a) is up. This creates a potential problem because any local - /// handles that are created while these scopes are active are bound to - /// that 'a lifetime. This means that we run the risk of creating local - /// handles that outlive their creation scope. - /// - /// Therefore, we don't immediately exit the current scope at the very - /// moment the user drops their Escapable/HandleScope handle. - /// Instead, the current scope is marked as being a 'zombie': the scope - /// itself is gone, but its data still on the stack. The zombie's data will - /// be dropped when the user touches the parent scope; when that happens, it - /// is certain that there are no accessible `Local<'a, T>` handles left, - /// because the 'a lifetime ends there. - /// - /// Scope types that do no store local handles are exited immediately. - #[inline(always)] - pub(super) fn notify_scope_dropped(&mut self) { - match &self.scope_type_specific_data { - ScopeTypeSpecificData::HandleScope { - allow_zombie: true, .. - } - | ScopeTypeSpecificData::EscapableHandleScope { .. } => { - // Defer scope exit until the parent scope is touched. - self.status.set(match self.status.get() { - ScopeStatus::Current { zombie: false } => { - ScopeStatus::Current { zombie: true } - } - _ => unreachable!(), - }); - } - _ => { - // Regular, immediate exit. - self.exit_scope(); - } - } - } +#[allow(unused_imports)] +pub(crate) use scope_with_context; + +#[allow(unused_macros)] +#[macro_export] +macro_rules! tc_scope { + ($scope: ident, $param: expr $(,)?) => { + let mut $scope = $crate::TryCatch::new($param); + // SAFETY: we are shadowing the original binding, so it can't be accessed + // ever again + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + }; + (let $scope: ident, $param: expr $(,)?) => { + $crate::tc_scope!($scope, $param); + }; +} - #[inline(always)] - pub(crate) fn get_isolate(&self) -> &Isolate { - unsafe { self.isolate.as_ref() } - } +#[macro_export] +macro_rules! disallow_javascript_execution_scope { + ($scope: ident, $param: expr, $on_failure: expr $(,)?) => { + let mut $scope = + $crate::DisallowJavascriptExecutionScope::new($param, $on_failure); + // SAFETY: we are shadowing the original binding, so it can't be accessed + // ever again + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + }; + (let $scope: ident, $param: expr, $on_failure: expr $(,)?) => { + $crate::disallow_javascript_execution_scope!($scope, $param, $on_failure); + }; +} - #[inline(always)] - pub(crate) fn get_isolate_mut(&mut self) -> &mut Isolate { - unsafe { self.isolate.as_mut() } - } +#[allow(unused_imports)] +pub(crate) use disallow_javascript_execution_scope; - #[inline(always)] - pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate { - self.isolate.as_ptr() - } +#[macro_export] +macro_rules! allow_javascript_execution_scope { + ($scope: ident, $param: expr $(,)?) => { + let mut $scope = $crate::AllowJavascriptExecutionScope::new($param); + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + }; + (let $scope: ident, $param: expr $(,)?) => { + $crate::allow_javascript_execution_scope!($scope, $param); + }; +} - #[inline(always)] - pub(crate) fn get_current_context(&self) -> *const Context { - // To avoid creating a new Local every time `get_current_context() is - // called, the current context is usually cached in the `context` field. - // If the `context` field contains `None`, this might mean that this cache - // field never got populated, so we'll do that here when necessary. - let get_current_context_from_isolate = || unsafe { - raw::v8__Isolate__GetCurrentContext(self.get_isolate_ptr()) - }; - match self.context.get().map(|nn| nn.as_ptr() as *const _) { - Some(context) => { - debug_assert!(unsafe { - raw::v8__Context__EQ(context, get_current_context_from_isolate()) - }); - context - } - None => { - let context = get_current_context_from_isolate(); - self.context.set(NonNull::new(context as *mut _)); - context - } - } - } +#[allow(unused_imports)] +pub(crate) use allow_javascript_execution_scope; - #[inline(always)] - pub(super) fn get_escape_slot_mut( - &mut self, - ) -> Option<&mut Option> { - self - .escape_slot - .as_mut() - .map(|escape_slot_nn| unsafe { escape_slot_nn.as_mut() }) - } +#[macro_export] +macro_rules! escapable_handle_scope { + ($scope: ident, $param: expr $(,)?) => { + let mut $scope = $crate::EscapableHandleScope::new($param); + let mut $scope = { + let scope_pinned = unsafe { std::pin::Pin::new_unchecked(&mut $scope) }; + scope_pinned.init() + }; + let $scope = &mut $scope; + }; + (let $scope: ident, $param: expr $(,)?) => { + $crate::escapable_handle_scope!($scope, $param); + }; +} - #[inline(always)] - pub(super) fn get_try_catch(&self) -> &raw::TryCatch { - self - .try_catch - .as_ref() - .map(|try_catch_nn| unsafe { try_catch_nn.as_ref() }) - .unwrap() - } +#[allow(unused_imports)] +pub(crate) use escapable_handle_scope; - #[inline(always)] - pub(super) fn get_try_catch_mut(&mut self) -> &mut raw::TryCatch { - self - .try_catch - .as_mut() - .map(|try_catch_nn| unsafe { try_catch_nn.as_mut() }) - .unwrap() - } +#[repr(transparent)] +pub struct PinnedRef<'p, T>(Pin<&'p mut T>); - /// Returns a new `Box` with the `isolate` field set as specified - /// by the first parameter, and the other fields initialized to their - /// default values. This function exists solely because it turns out that - /// Rust doesn't optimize `Box::new(Self{ .. })` very well (a.k.a. not at - /// all) in this case, which is why `std::alloc::alloc()` is used directly. - #[cold] - fn boxed(isolate: NonNull) -> Box { - unsafe { - #[allow(clippy::cast_ptr_alignment)] - let self_ptr = alloc(Layout::new::()) as *mut Self; - ptr::write( - self_ptr, - Self { - isolate, - previous: Default::default(), - next: Default::default(), - status: Default::default(), - context: Default::default(), - escape_slot: Default::default(), - try_catch: Default::default(), - scope_type_specific_data: Default::default(), - }, - ); - Box::from_raw(self_ptr) - } - } +impl<'p, T> From> for PinnedRef<'p, T> { + fn from(value: Pin<&'p mut T>) -> Self { + PinnedRef(value) } +} - #[derive(Debug, Clone, Copy, Eq, PartialEq)] - enum ScopeStatus { - Free, - Current { zombie: bool }, - Shadowed { zombie: bool }, +impl PinnedRef<'_, T> { + pub fn as_mut_ref(&mut self) -> PinnedRef<'_, T> { + PinnedRef(self.0.as_mut()) } +} - impl Default for ScopeStatus { - fn default() -> Self { - Self::Free - } - } +unsafe fn cast_pinned_ref<'b, 'o, I, O>( + pinned: &PinnedRef<'_, I>, +) -> &'b PinnedRef<'o, O> { + unsafe { std::mem::transmute(pinned) } +} - #[derive(Debug)] - enum ScopeTypeSpecificData { - None, - ContextScope { - _raw_context_scope: raw::ContextScope, - }, - HandleScope { - allow_zombie: bool, - raw_handle_scope: raw::HandleScope, - raw_context_scope: Option, - }, - EscapableHandleScope { - raw_handle_scope: raw::HandleScope, - raw_escape_slot: Option, - }, - TryCatch { - raw_try_catch: raw::TryCatch, - }, - DisallowJavascriptExecutionScope { - raw_scope: raw::DisallowJavascriptExecutionScope, - }, - AllowJavascriptExecutionScope { - raw_scope: raw::AllowJavascriptExecutionScope, - }, - } +unsafe fn cast_pinned_ref_mut<'b, 'o, I, O>( + pinned: &mut PinnedRef<'_, I>, +) -> &'b mut PinnedRef<'o, O> { + unsafe { std::mem::transmute(pinned) } +} - impl Default for ScopeTypeSpecificData { - fn default() -> Self { - Self::None - } +impl<'p, 'i> Deref for PinnedRef<'p, HandleScope<'i>> { + type Target = PinnedRef<'p, HandleScope<'i, ()>>; + fn deref(&self) -> &Self::Target { + unsafe { cast_pinned_ref::, HandleScope<'i, ()>>(self) } } +} - impl Drop for ScopeTypeSpecificData { - #[inline(always)] - fn drop(&mut self) { - // For `HandleScope`s that also enter a `Context`, drop order matters. The - // context is stored in a `Local` handle, which is allocated in this - // scope's own private `raw::HandleScope`. When that `raw::HandleScope` - // is dropped first, we immediately lose the `Local` handle, - // which we need in order to exit `ContextScope`. - if let Self::HandleScope { - raw_context_scope, .. - } = self - { - *raw_context_scope = None; - } - } +impl DerefMut for PinnedRef<'_, HandleScope<'_>> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { cast_pinned_ref_mut::, HandleScope<'_, ()>>(self) } } +} - impl ScopeTypeSpecificData { - pub fn is_none(&self) -> bool { - matches!(self, Self::None) - } +impl Deref for PinnedRef<'_, HandleScope<'_, ()>> { + type Target = Isolate; + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { Isolate::from_raw_ref(&self.0.isolate) } + } +} - /// Replaces a `ScopeTypeSpecificData::None` value with the value returned - /// from the specified closure. This function exists because initializing - /// scopes is performance critical, and `ptr::write()` produces more - /// efficient code than using a regular assign statement, which will try to - /// drop the old value and move the new value into place, even after - /// asserting `self.is_none()`. - pub fn init_with(&mut self, init_fn: impl FnOnce() -> Self) { - assert!(self.is_none()); - unsafe { ptr::write(self, (init_fn)()) } +impl DerefMut for PinnedRef<'_, HandleScope<'_, ()>> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + Isolate::from_raw_ref_mut( + &mut self.0.as_mut().get_unchecked_mut().isolate, + ) } } } -/// The `raw` module contains prototypes for all the `extern C` functions that -/// are used in this file, as well as definitions for the types they operate on. -mod raw { - use super::*; - - #[derive(Clone, Copy, Debug)] - #[repr(transparent)] - pub(super) struct Address(NonZeroUsize); +impl<'i> Deref for PinnedRef<'_, CallbackScope<'i>> { + // You may notice the output lifetime is a little bit weird here. + // Basically, we're saying that any Handles created from this `CallbackScope` + // will live as long as the thing that we made the `CallbackScope` from. + // In practice, this means that the caller of `CallbackScope::new` needs to + // be careful to ensure that the input lifetime is a safe approximation. + type Target = PinnedRef<'i, HandleScope<'i>>; + fn deref(&self) -> &Self::Target { + unsafe { cast_pinned_ref::, HandleScope<'i>>(self) } + } +} - #[derive(Debug)] - pub(super) struct ContextScope { - entered_context: NonNull, +impl DerefMut for PinnedRef<'_, CallbackScope<'_>> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { cast_pinned_ref_mut::, HandleScope<'_>>(self) } } +} - impl ContextScope { - pub fn new(context: Local) -> Self { - unsafe { v8__Context__Enter(&*context) }; - Self { - entered_context: context.as_non_null(), - } +impl<'i> Deref for PinnedRef<'_, CallbackScope<'i, ()>> { + type Target = PinnedRef<'i, HandleScope<'i, ()>>; + fn deref(&self) -> &Self::Target { + unsafe { + cast_pinned_ref::, HandleScope<'i, ()>>(self) } } +} - impl Drop for ContextScope { - #[inline(always)] - fn drop(&mut self) { - unsafe { v8__Context__Exit(self.entered_context.as_ptr()) }; +impl DerefMut for PinnedRef<'_, CallbackScope<'_, ()>> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + cast_pinned_ref_mut::, HandleScope<'_, ()>>(self) } } +} - #[repr(C)] - #[derive(Debug)] - pub(super) struct HandleScope([MaybeUninit; 3]); +impl<'obj, 'iso, C> Deref + for PinnedRef<'_, TryCatch<'_, 'obj, HandleScope<'iso, C>>> +{ + type Target = PinnedRef<'obj, HandleScope<'iso, C>>; + fn deref(&self) -> &Self::Target { + self.0.scope + } +} - impl HandleScope { - /// Creates an uninitialized `HandleScope`. - /// - /// This function is marked unsafe because the caller must ensure that the - /// returned value isn't dropped before `init()` has been called. - pub unsafe fn uninit() -> Self { - Self(unsafe { MaybeUninit::uninit().assume_init() }) - } +impl DerefMut for PinnedRef<'_, TryCatch<'_, '_, HandleScope<'_, C>>> { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: we're just projecting the pinned reference, it still can't be moved + unsafe { self.as_mut_ref().0.get_unchecked_mut().scope } + } +} - /// This function is marked unsafe because `init()` must be called exactly - /// once, no more and no less, after creating a `HandleScope` value with - /// `HandleScope::uninit()`. - pub unsafe fn init(&mut self, isolate: NonNull) { - let buf = NonNull::from(self).cast(); - unsafe { - v8__HandleScope__CONSTRUCT(buf.as_ptr(), isolate.as_ptr()); - } - } +impl<'borrow, 'scope: 'borrow, 'obj: 'borrow, 'esc: 'obj, C> Deref + for PinnedRef< + '_, + TryCatch<'borrow, 'scope, EscapableHandleScope<'obj, 'esc, C>>, + > +{ + type Target = PinnedRef<'scope, EscapableHandleScope<'obj, 'esc, C>>; + + fn deref(&self) -> &Self::Target { + self.0.scope } +} - impl Drop for HandleScope { - #[inline(always)] - fn drop(&mut self) { - unsafe { v8__HandleScope__DESTRUCT(self) }; - } +impl<'borrow, 'scope: 'borrow, 'obj: 'borrow, 'esc: 'obj, C> DerefMut + for PinnedRef< + '_, + TryCatch<'borrow, 'scope, EscapableHandleScope<'obj, 'esc, C>>, + > +{ + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: we're just projecting the pinned reference, it still can't be moved + unsafe { self.0.as_mut().get_unchecked_mut().scope } } +} - #[repr(transparent)] - #[derive(Debug)] - pub(super) struct EscapeSlot(NonNull); +impl<'obj, P> Deref + for PinnedRef<'_, DisallowJavascriptExecutionScope<'_, 'obj, P>> +{ + type Target = PinnedRef<'obj, P>; + fn deref(&self) -> &Self::Target { + self.0.scope + } +} - impl EscapeSlot { - pub fn new(isolate: NonNull) -> Self { - unsafe { - let undefined = raw::v8__Undefined(isolate.as_ptr()) as *const _; - let local = raw::v8__Local__New(isolate.as_ptr(), undefined); - let slot_address_ptr = local as *const Address as *mut _; - let slot_address_nn = NonNull::new_unchecked(slot_address_ptr); - Self(slot_address_nn) - } - } +impl

DerefMut + for PinnedRef<'_, DisallowJavascriptExecutionScope<'_, '_, P>> +{ + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: we're just projecting the pinned reference, it still can't be moved + unsafe { self.0.as_mut().get_unchecked_mut().scope } + } +} - pub fn escape<'e, T>(self, value: Local<'_, T>) -> Local<'e, T> - where - for<'l> Local<'l, T>: Into>, - { - assert_eq!(Layout::new::(), Layout::new::>()); - unsafe { - let undefined = Local::::from_non_null(self.0.cast()); - debug_assert!(undefined.is_undefined()); - let value_address = *(&*value as *const T as *const Address); - ptr::write(self.0.as_ptr(), value_address); - Local::from_non_null(self.0.cast()) - } - } +impl<'obj, P> Deref + for PinnedRef<'_, AllowJavascriptExecutionScope<'_, 'obj, P>> +{ + type Target = PinnedRef<'obj, P>; + fn deref(&self) -> &Self::Target { + self.0.scope } +} +impl

DerefMut for PinnedRef<'_, AllowJavascriptExecutionScope<'_, '_, P>> { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: we're just projecting the pinned reference, it still can't be moved + unsafe { self.0.as_mut().get_unchecked_mut().scope } + } +} - #[repr(C)] - #[derive(Debug)] - pub(super) struct TryCatch([MaybeUninit; 6]); +impl

GetIsolate for PinnedRef<'_, P> +where + P: GetIsolate, +{ + fn get_isolate_ptr(&self) -> *mut RealIsolate { + self.0.get_isolate_ptr() + } +} - impl TryCatch { - /// Creates an uninitialized `TryCatch`. - /// - /// This function is marked unsafe because the caller must ensure that the - /// returned value isn't dropped before `init()` has been called. - pub unsafe fn uninit() -> Self { - Self(unsafe { MaybeUninit::uninit().assume_init() }) - } +impl AsRef for PinnedRef<'_, HandleScope<'_, C>> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.0.isolate) } + } +} - /// This function is marked unsafe because `init()` must be called exactly - /// once, no more and no less, after creating a `TryCatch` value with - /// `TryCatch::uninit()`. - pub unsafe fn init(&mut self, isolate: NonNull) { - let buf = NonNull::from(self).cast(); - unsafe { - v8__TryCatch__CONSTRUCT(buf.as_ptr(), isolate.as_ptr()); - } +impl AsMut for PinnedRef<'_, HandleScope<'_, C>> { + fn as_mut(&mut self) -> &mut Isolate { + unsafe { + Isolate::from_raw_ref_mut( + &mut self.0.as_mut().get_unchecked_mut().isolate, + ) } } +} + +impl AsRef for PinnedRef<'_, CallbackScope<'_, C>> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.0.isolate) } + } +} - impl Drop for TryCatch { - #[inline(always)] - fn drop(&mut self) { - unsafe { v8__TryCatch__DESTRUCT(self) }; +impl AsMut for PinnedRef<'_, CallbackScope<'_, C>> { + fn as_mut(&mut self) -> &mut Isolate { + unsafe { + Isolate::from_raw_ref_mut( + &mut self.0.as_mut().get_unchecked_mut().isolate, + ) } } +} - #[repr(C)] - #[derive(Debug)] - pub(super) struct DisallowJavascriptExecutionScope([MaybeUninit; 2]); +impl AsRef for PinnedRef<'_, TryCatch<'_, '_, HandleScope<'_, C>>> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.0.scope.0.isolate) } + } +} - impl DisallowJavascriptExecutionScope { - /// Creates an uninitialized `DisallowJavascriptExecutionScope`. - /// - /// This function is marked unsafe because the caller must ensure that the - /// returned value isn't dropped before `init()` has been called. - #[inline] - pub unsafe fn uninit() -> Self { - Self(unsafe { MaybeUninit::uninit().assume_init() }) +impl AsMut for PinnedRef<'_, TryCatch<'_, '_, HandleScope<'_, C>>> { + fn as_mut(&mut self) -> &mut Isolate { + unsafe { + Isolate::from_raw_ref_mut( + &mut self + .0 + .as_mut() + .get_unchecked_mut() + .scope + .0 + .as_mut() + .get_unchecked_mut() + .isolate, + ) } + } +} - /// This function is marked unsafe because `init()` must be called exactly - /// once, no more and no less, after creating a - /// `DisallowJavascriptExecutionScope` value with - /// `DisallowJavascriptExecutionScope::uninit()`. - #[inline] - pub unsafe fn init( - &mut self, - isolate: NonNull, - on_failure: OnFailure, - ) { - let buf = NonNull::from(self).cast(); - unsafe { - v8__DisallowJavascriptExecutionScope__CONSTRUCT( - buf.as_ptr(), - isolate.as_ptr(), - on_failure, - ); - } - } +impl AsRef + for PinnedRef< + '_, + DisallowJavascriptExecutionScope<'_, '_, HandleScope<'_, C>>, + > +{ + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.0.scope.0.isolate) } } +} - impl Drop for DisallowJavascriptExecutionScope { - #[inline(always)] - fn drop(&mut self) { - unsafe { v8__DisallowJavascriptExecutionScope__DESTRUCT(self) }; - } +impl AsRef + for PinnedRef<'_, AllowJavascriptExecutionScope<'_, '_, HandleScope<'_, C>>> +{ + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.0.scope.0.isolate) } } +} - #[repr(C)] - #[derive(Debug)] - pub(super) struct AllowJavascriptExecutionScope([MaybeUninit; 2]); +impl AsRef for PinnedRef<'_, EscapableHandleScope<'_, '_>> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.0.isolate) } + } +} - impl AllowJavascriptExecutionScope { - /// Creates an uninitialized `AllowJavascriptExecutionScope`. - /// - /// This function is marked unsafe because the caller must ensure that the - /// returned value isn't dropped before `init()` has been called. - #[inline] - pub unsafe fn uninit() -> Self { - Self(unsafe { MaybeUninit::uninit().assume_init() }) - } +impl AsRef for ContextScope<'_, '_, HandleScope<'_, C>> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.scope.0.isolate) } + } +} +impl AsRef for ContextScope<'_, '_, CallbackScope<'_, C>> { + fn as_ref(&self) -> &Isolate { + unsafe { Isolate::from_raw_ref(&self.scope.0.isolate) } + } +} - /// This function is marked unsafe because `init()` must be called exactly - /// once, no more and no less, after creating an - /// `AllowJavascriptExecutionScope` value with - /// `AllowJavascriptExecutionScope::uninit()`. - #[inline] - pub unsafe fn init(&mut self, isolate: NonNull) { - unsafe { - let buf = NonNull::from(self).cast(); - v8__AllowJavascriptExecutionScope__CONSTRUCT( - buf.as_ptr(), - isolate.as_ptr(), - ); - } +impl<'pin, 's, 'esc: 's, C> AsRef>> + for PinnedRef<'pin, EscapableHandleScope<'s, 'esc, C>> +{ + fn as_ref(&self) -> &PinnedRef<'pin, HandleScope<'s, C>> { + unsafe { + cast_pinned_ref::, HandleScope<'s, C>>( + self, + ) } } +} - impl Drop for AllowJavascriptExecutionScope { - #[inline(always)] - fn drop(&mut self) { - unsafe { v8__AllowJavascriptExecutionScope__DESTRUCT(self) }; - } - } - - unsafe extern "C" { - pub(super) fn v8__Isolate__GetCurrentContext( - isolate: *mut Isolate, - ) -> *const Context; - pub(super) fn v8__Isolate__GetEnteredOrMicrotaskContext( - isolate: *mut Isolate, - ) -> *const Context; - pub(super) fn v8__Isolate__ThrowException( - isolate: *mut Isolate, - exception: *const Value, - ) -> *const Value; - pub(super) fn v8__Isolate__GetDataFromSnapshotOnce( - this: *mut Isolate, - index: usize, - ) -> *const Data; - pub(super) fn v8__Isolate__GetCurrentHostDefinedOptions( - this: *mut Isolate, - ) -> *const Data; - - pub(super) fn v8__Context__EQ( - this: *const Context, - other: *const Context, - ) -> bool; - pub(super) fn v8__Context__Enter(this: *const Context); - pub(super) fn v8__Context__Exit(this: *const Context); - pub(super) fn v8__Context__GetIsolate(this: *const Context) - -> *mut Isolate; - pub(super) fn v8__Context__GetDataFromSnapshotOnce( - this: *const Context, - index: usize, - ) -> *const Data; - pub(super) fn v8__Context__SetPromiseHooks( - this: *const Context, - init_hook: *const Function, - before_hook: *const Function, - after_hook: *const Function, - resolve_hook: *const Function, - ); - pub(super) fn v8__Context__SetContinuationPreservedEmbedderData( - this: *mut Isolate, - value: *const Value, - ); - pub(super) fn v8__Context__GetContinuationPreservedEmbedderData( - this: *mut Isolate, - ) -> *const Value; - - pub(super) fn v8__HandleScope__CONSTRUCT( - buf: *mut MaybeUninit, - isolate: *mut Isolate, - ); - pub(super) fn v8__HandleScope__DESTRUCT(this: *mut HandleScope); - - pub(super) fn v8__Local__New( - isolate: *mut Isolate, - other: *const Data, - ) -> *const Data; - pub(super) fn v8__Undefined(isolate: *mut Isolate) -> *const Primitive; - - pub(super) fn v8__TryCatch__CONSTRUCT( - buf: *mut MaybeUninit, - isolate: *mut Isolate, - ); - pub(super) fn v8__TryCatch__DESTRUCT(this: *mut TryCatch); - pub(super) fn v8__TryCatch__HasCaught(this: *const TryCatch) -> bool; - pub(super) fn v8__TryCatch__CanContinue(this: *const TryCatch) -> bool; - pub(super) fn v8__TryCatch__HasTerminated(this: *const TryCatch) -> bool; - pub(super) fn v8__TryCatch__IsVerbose(this: *const TryCatch) -> bool; - pub(super) fn v8__TryCatch__SetVerbose(this: *mut TryCatch, value: bool); - pub(super) fn v8__TryCatch__SetCaptureMessage( - this: *mut TryCatch, - value: bool, - ); - pub(super) fn v8__TryCatch__Reset(this: *mut TryCatch); - pub(super) fn v8__TryCatch__Exception( - this: *const TryCatch, - ) -> *const Value; - pub(super) fn v8__TryCatch__StackTrace( - this: *const TryCatch, - context: *const Context, - ) -> *const Value; - pub(super) fn v8__TryCatch__Message( - this: *const TryCatch, - ) -> *const Message; - pub(super) fn v8__TryCatch__ReThrow(this: *mut TryCatch) -> *const Value; - - pub(super) fn v8__DisallowJavascriptExecutionScope__CONSTRUCT( - buf: *mut MaybeUninit, - isolate: *mut Isolate, - on_failure: OnFailure, - ); - pub(super) fn v8__DisallowJavascriptExecutionScope__DESTRUCT( - this: *mut DisallowJavascriptExecutionScope, - ); - - pub(super) fn v8__AllowJavascriptExecutionScope__CONSTRUCT( - buf: *mut MaybeUninit, - isolate: *mut Isolate, - ); - pub(super) fn v8__AllowJavascriptExecutionScope__DESTRUCT( - this: *mut AllowJavascriptExecutionScope, - ); - - pub(super) fn v8__Message__GetIsolate(this: *const Message) - -> *mut Isolate; - pub(super) fn v8__Object__GetIsolate(this: *const Object) -> *mut Isolate; +impl<'obj, 'inner, C> AsRef>> + for PinnedRef<'obj, HandleScope<'inner, C>> +{ + fn as_ref(&self) -> &PinnedRef<'obj, HandleScope<'inner, C>> { + self } } @@ -2302,8 +2143,8 @@ mod raw { mod tests { use super::*; use crate::ContextOptions; - use crate::Global; use std::any::type_name; + use std::pin::pin; trait SameType {} impl SameType for (A, A) {} @@ -2327,101 +2168,113 @@ mod tests { crate::initialize_v8(); let isolate = &mut Isolate::new(Default::default()); AssertTypeOf(isolate).is::(); - let l1_hs = &mut HandleScope::new(isolate); - AssertTypeOf(l1_hs).is::>(); + let l1_hs = pin!(HandleScope::new(isolate)); + let l1_hs = &mut l1_hs.init(); + AssertTypeOf(l1_hs).is::>>(); let context = Context::new(l1_hs, ContextOptions::default()); { let l2_cxs = &mut ContextScope::new(l1_hs, context); AssertTypeOf(l2_cxs).is::>(); { let d = l2_cxs.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } { - let l3_tc = &mut TryCatch::new(l2_cxs); - AssertTypeOf(l3_tc).is::>(); + tc_scope!(let l3_tc, &mut **l2_cxs); + AssertTypeOf(l3_tc).is::>>(); let d = l3_tc.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } { - let l3_djses = &mut DisallowJavascriptExecutionScope::new( - l2_cxs, - OnFailure::CrashOnFailure, - ); + disallow_javascript_execution_scope!(let l3_djses, l2_cxs, OnFailure::CrashOnFailure); AssertTypeOf(l3_djses) - .is::>(); + .is::>>(); let d = l3_djses.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); { - let l4_ajses = &mut AllowJavascriptExecutionScope::new(l3_djses); - AssertTypeOf(l4_ajses).is::(); + allow_javascript_execution_scope!(let l4_ajses, l3_djses); + AssertTypeOf(l4_ajses).is::, + >, + >>(); let d = l4_ajses.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d) + .is::>>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } } { - let l3_ehs = &mut EscapableHandleScope::new(l2_cxs); - AssertTypeOf(l3_ehs).is::(); + escapable_handle_scope!(let l3_ehs, l2_cxs); + AssertTypeOf(l3_ehs).is::>(); { let l4_cxs = &mut ContextScope::new(l3_ehs, context); AssertTypeOf(l4_cxs).is::>(); let d = l4_cxs.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } { - let l4_tc = &mut TryCatch::new(l3_ehs); - AssertTypeOf(l4_tc).is::>(); + tc_scope!(let l4_tc, l3_ehs); + AssertTypeOf(l4_tc).is::>>(); let d = l4_tc.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } { - let l4_djses = &mut DisallowJavascriptExecutionScope::new( - l3_ehs, - OnFailure::CrashOnFailure, - ); + disallow_javascript_execution_scope!(let l4_djses, l3_ehs, OnFailure::CrashOnFailure); AssertTypeOf(l4_djses) - .is::>(); + .is::>>(); let d = l4_djses.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); { - let l5_ajses = &mut AllowJavascriptExecutionScope::new(l4_djses); - AssertTypeOf(l5_ajses).is::(); + allow_javascript_execution_scope!(let l5_ajses, l4_djses); + AssertTypeOf(l5_ajses).is::, + >, + >>(); let d = l5_ajses.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } @@ -2429,44 +2282,52 @@ mod tests { } } { - let l2_tc = &mut TryCatch::new(l1_hs); - AssertTypeOf(l2_tc).is::>>(); + tc_scope!(let l2_tc, l1_hs); + AssertTypeOf(l2_tc).is::>>>(); let d = l2_tc.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); { - let l3_djses = &mut DisallowJavascriptExecutionScope::new( - l2_tc, - OnFailure::CrashOnFailure, - ); - AssertTypeOf(l3_djses) - .is::>>>(); + disallow_javascript_execution_scope!(let l3_djses, l2_tc, OnFailure::CrashOnFailure); + AssertTypeOf(l3_djses).is::>>, + >>(); let d = l3_djses.deref_mut(); - AssertTypeOf(d).is::>>(); + AssertTypeOf(d).is::>>>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); { - let l4_ajses = &mut AllowJavascriptExecutionScope::new(l3_djses); - AssertTypeOf(l4_ajses).is::>>(); + allow_javascript_execution_scope!(let l4_ajses, l3_djses); + AssertTypeOf(l4_ajses).is::>>, + >, + >>(); let d = l4_ajses.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>, + >>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>>>(); + let d = d.deref_mut(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } } } { - let l2_ehs = &mut EscapableHandleScope::new(l1_hs); - AssertTypeOf(l2_ehs).is::>(); - let l3_tc = &mut TryCatch::new(l2_ehs); - AssertTypeOf(l3_tc).is::>>(); + escapable_handle_scope!(let l2_ehs, l1_hs); + AssertTypeOf(l2_ehs).is::>>(); + tc_scope!(let l3_tc, l2_ehs); + AssertTypeOf(l3_tc).is::>>>(); let d = l3_tc.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } @@ -2476,152 +2337,23 @@ mod tests { // that a context has been entered. Push a `ContextScope` onto the stack // to also meet the second expectation. let _ = ContextScope::new(l1_hs, context); - let l2_cbs = &mut unsafe { CallbackScope::new(context) }; - AssertTypeOf(l2_cbs).is::(); + callback_scope!(unsafe l2_cbs, context); + AssertTypeOf(l2_cbs).is::>(); let d = l2_cbs.deref_mut(); - AssertTypeOf(d).is::(); + AssertTypeOf(d).is::>(); let d = d.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } { let isolate: &mut Isolate = l1_hs.as_mut(); - let l2_cbs = &mut unsafe { CallbackScope::new(isolate) }; - AssertTypeOf(l2_cbs).is::>(); + callback_scope!(unsafe l2_cbs, isolate); + AssertTypeOf(l2_cbs).is::>>(); let d = l2_cbs.deref_mut(); - AssertTypeOf(d).is::>(); + AssertTypeOf(d).is::>>(); let d = d.deref_mut(); AssertTypeOf(d).is::(); } } - - #[test] - fn new_scope_types() { - crate::initialize_v8(); - let isolate = &mut Isolate::new(Default::default()); - AssertTypeOf(isolate).is::(); - let global_context: Global; - { - let l1_hs = &mut HandleScope::new(isolate); - AssertTypeOf(l1_hs).is::>(); - let context = Context::new(l1_hs, Default::default()); - global_context = Global::new(l1_hs, context); - AssertTypeOf(&HandleScope::new(l1_hs)).is::>(); - { - let l2_cxs = &mut ContextScope::new(l1_hs, context); - AssertTypeOf(l2_cxs).is::>(); - AssertTypeOf(&ContextScope::new(l2_cxs, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l2_cxs)).is::(); - AssertTypeOf(&EscapableHandleScope::new(l2_cxs)) - .is::(); - AssertTypeOf(&TryCatch::new(l2_cxs)).is::>(); - } - { - let l2_ehs = &mut EscapableHandleScope::new(l1_hs); - AssertTypeOf(l2_ehs).is::>(); - AssertTypeOf(&HandleScope::new(l2_ehs)) - .is::>(); - AssertTypeOf(&EscapableHandleScope::new(l2_ehs)) - .is::>(); - { - let l3_cxs = &mut ContextScope::new(l2_ehs, context); - AssertTypeOf(l3_cxs).is::>(); - AssertTypeOf(&ContextScope::new(l3_cxs, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l3_cxs)).is::(); - AssertTypeOf(&EscapableHandleScope::new(l3_cxs)) - .is::(); - { - let l4_tc = &mut TryCatch::new(l3_cxs); - AssertTypeOf(l4_tc).is::>(); - AssertTypeOf(&ContextScope::new(l4_tc, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l4_tc)).is::(); - AssertTypeOf(&EscapableHandleScope::new(l4_tc)) - .is::(); - AssertTypeOf(&TryCatch::new(l4_tc)) - .is::>(); - } - } - { - let l3_tc = &mut TryCatch::new(l2_ehs); - AssertTypeOf(l3_tc).is::>>(); - AssertTypeOf(&ContextScope::new(l3_tc, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l3_tc)) - .is::>(); - AssertTypeOf(&EscapableHandleScope::new(l3_tc)) - .is::>(); - AssertTypeOf(&TryCatch::new(l3_tc)) - .is::>>(); - } - } - { - let l2_tc = &mut TryCatch::new(l1_hs); - AssertTypeOf(l2_tc).is::>>(); - AssertTypeOf(&ContextScope::new(l2_tc, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l2_tc)).is::>(); - AssertTypeOf(&EscapableHandleScope::new(l2_tc)) - .is::>(); - AssertTypeOf(&TryCatch::new(l2_tc)).is::>>(); - } - { - let l2_cbs = &mut unsafe { CallbackScope::new(context) }; - AssertTypeOf(l2_cbs).is::(); - AssertTypeOf(&ContextScope::new(l2_cbs, context)) - .is::>(); - { - let l3_hs = &mut HandleScope::new(l2_cbs); - AssertTypeOf(l3_hs).is::(); - AssertTypeOf(&ContextScope::new(l3_hs, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l3_hs)).is::(); - AssertTypeOf(&EscapableHandleScope::new(l3_hs)) - .is::(); - AssertTypeOf(&TryCatch::new(l3_hs)).is::>(); - } - { - let l3_ehs = &mut EscapableHandleScope::new(l2_cbs); - AssertTypeOf(l3_ehs).is::(); - AssertTypeOf(&ContextScope::new(l3_ehs, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l3_ehs)).is::(); - AssertTypeOf(&EscapableHandleScope::new(l3_ehs)) - .is::(); - AssertTypeOf(&TryCatch::new(l3_ehs)) - .is::>(); - } - { - let l3_tc = &mut TryCatch::new(l2_cbs); - AssertTypeOf(l3_tc).is::>(); - AssertTypeOf(&ContextScope::new(l3_tc, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l3_tc)).is::(); - AssertTypeOf(&EscapableHandleScope::new(l3_tc)) - .is::(); - AssertTypeOf(&TryCatch::new(l3_tc)).is::>(); - } - } - } - { - let l1_cbs = &mut unsafe { CallbackScope::new(&mut *isolate) }; - AssertTypeOf(l1_cbs).is::>(); - let context = Context::new(l1_cbs, Default::default()); - AssertTypeOf(&ContextScope::new(l1_cbs, context)) - .is::>(); - AssertTypeOf(&HandleScope::new(l1_cbs)).is::>(); - AssertTypeOf(&EscapableHandleScope::new(l1_cbs)) - .is::>(); - AssertTypeOf(&TryCatch::new(l1_cbs)).is::>>(); - } - { - AssertTypeOf(&HandleScope::with_context(isolate, &global_context)) - .is::(); - AssertTypeOf(&HandleScope::with_context(isolate, global_context)) - .is::(); - } - } } diff --git a/src/scope/raw.rs b/src/scope/raw.rs new file mode 100644 index 0000000000..72f2002a9f --- /dev/null +++ b/src/scope/raw.rs @@ -0,0 +1,322 @@ +/// The `raw` module contains prototypes for all the `extern C` functions that +/// are used in the scope module, as well as definitions for the types they operate on. +use crate::{ + Context, Data, Function, Local, Message, Object, OnFailure, Primitive, Value, + isolate::RealIsolate, +}; +use std::num::NonZeroUsize; +use std::{ + mem::MaybeUninit, + ptr::{self, NonNull}, +}; + +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub(super) struct Address(NonZeroUsize); + +#[derive(Debug)] +#[repr(transparent)] +pub(super) struct ContextScope { + pub(super) entered_context: NonNull, +} + +impl ContextScope { + pub fn new(context: Local) -> Self { + unsafe { v8__Context__Enter(&*context) }; + Self { + entered_context: context.as_non_null(), + } + } +} + +impl Drop for ContextScope { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__Context__Exit(self.entered_context.as_ptr()) }; + } +} + +#[cfg(feature = "v8_enable_v8_checks")] +pub const HANDLE_SCOPE_SIZE: usize = 4; +#[cfg(not(feature = "v8_enable_v8_checks"))] +pub const HANDLE_SCOPE_SIZE: usize = 3; + +#[repr(C)] +#[derive(Debug)] +pub(super) struct HandleScope([MaybeUninit; HANDLE_SCOPE_SIZE]); + +impl HandleScope { + /// Creates an uninitialized `HandleScope`. + /// + /// This function is marked unsafe because the caller must ensure that the + /// returned value isn't dropped before `init()` has been called. + #[inline(always)] + pub unsafe fn uninit() -> Self { + unsafe { MaybeUninit::uninit().assume_init() } + } + + /// This function is marked unsafe because `init()` must be called exactly + /// once, no more and no less, after creating a `HandleScope` value with + /// `HandleScope::uninit()`. + #[inline(always)] + pub unsafe fn init(&mut self, isolate: NonNull) { + let buf = NonNull::from(self).as_ptr().cast(); + unsafe { + v8__HandleScope__CONSTRUCT(buf, isolate.as_ptr()); + } + } +} + +impl Drop for HandleScope { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__HandleScope__DESTRUCT(self) }; + } +} + +#[repr(transparent)] +#[derive(Debug)] +pub(super) struct EscapeSlot(NonNull

); + +impl EscapeSlot { + pub fn new(isolate: NonNull) -> Self { + unsafe { + let undefined = v8__Undefined(isolate.as_ptr()) as *const _; + let local = v8__Local__New(isolate.as_ptr(), undefined); + let slot_address_ptr = local as *const Address as *mut _; + let slot_address_nn = NonNull::new_unchecked(slot_address_ptr); + Self(slot_address_nn) + } + } + + pub fn escape<'e, T>(self, value: Local<'_, T>) -> Local<'e, T> + where + for<'l> Local<'l, T>: Into>, + { + const { + assert!(size_of::() == size_of::>()); + assert!(align_of::() == align_of::>()); + } + unsafe { + let undefined = Local::::from_non_null(self.0.cast()); + debug_assert!(undefined.is_undefined()); + let value_address = *(&*value as *const T as *const Address); + ptr::write(self.0.as_ptr(), value_address); + Local::from_non_null(self.0.cast()) + } + } +} + +#[repr(C)] +#[derive(Debug)] +pub(super) struct TryCatch([MaybeUninit; 6]); + +impl TryCatch { + /// Creates an uninitialized `TryCatch`. + /// + /// This function is marked unsafe because the caller must ensure that the + /// returned value isn't dropped before `init()` has been called. + pub unsafe fn uninit() -> Self { + // SAFETY: All bit patterns are valid, since the struct is made up of MaybeUninit. + Self(unsafe { MaybeUninit::uninit().assume_init() }) + } + + /// This function is marked unsafe because `init()` must be called exactly + /// once, no more and no less, after creating a `TryCatch` value with + /// `TryCatch::uninit()`. + pub unsafe fn init(&mut self, isolate: NonNull) { + let buf = NonNull::from(self).cast(); + unsafe { + v8__TryCatch__CONSTRUCT(buf.as_ptr(), isolate.as_ptr()); + } + } +} + +impl Drop for TryCatch { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__TryCatch__DESTRUCT(self) }; + } +} + +#[repr(C)] +#[derive(Debug)] +pub(super) struct DisallowJavascriptExecutionScope([MaybeUninit; 2]); + +impl DisallowJavascriptExecutionScope { + /// Creates an uninitialized `DisallowJavascriptExecutionScope`. + /// + /// This function is marked unsafe because the caller must ensure that the + /// returned value isn't dropped before `init()` has been called. + #[inline] + pub unsafe fn uninit() -> Self { + // SAFETY: All bit patterns are valid, since the struct is made up of MaybeUninit. + Self(unsafe { MaybeUninit::uninit().assume_init() }) + } + + /// This function is marked unsafe because `init()` must be called exactly + /// once, no more and no less, after creating a + /// `DisallowJavascriptExecutionScope` value with + /// `DisallowJavascriptExecutionScope::uninit()`. + #[inline] + pub unsafe fn init( + &mut self, + isolate: NonNull, + on_failure: OnFailure, + ) { + let buf = NonNull::from(self).cast(); + unsafe { + v8__DisallowJavascriptExecutionScope__CONSTRUCT( + buf.as_ptr(), + isolate.as_ptr(), + on_failure, + ); + } + } +} + +impl Drop for DisallowJavascriptExecutionScope { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__DisallowJavascriptExecutionScope__DESTRUCT(self) }; + } +} + +#[repr(C)] +#[derive(Debug)] +pub(super) struct AllowJavascriptExecutionScope([MaybeUninit; 2]); + +impl AllowJavascriptExecutionScope { + /// Creates an uninitialized `AllowJavascriptExecutionScope`. + /// + /// This function is marked unsafe because the caller must ensure that the + /// returned value isn't dropped before `init()` has been called. + #[inline] + pub unsafe fn uninit() -> Self { + Self(unsafe { MaybeUninit::uninit().assume_init() }) + } + + /// This function is marked unsafe because `init()` must be called exactly + /// once, no more and no less, after creating an + /// `AllowJavascriptExecutionScope` value with + /// `AllowJavascriptExecutionScope::uninit()`. + #[inline] + pub unsafe fn init(&mut self, isolate: NonNull) { + unsafe { + let buf = NonNull::from(self).cast(); + v8__AllowJavascriptExecutionScope__CONSTRUCT( + buf.as_ptr(), + isolate.as_ptr(), + ); + } + } +} + +impl Drop for AllowJavascriptExecutionScope { + #[inline(always)] + fn drop(&mut self) { + unsafe { v8__AllowJavascriptExecutionScope__DESTRUCT(self) }; + } +} + +unsafe extern "C" { + pub(super) fn v8__Isolate__GetCurrentContext( + isolate: *mut RealIsolate, + ) -> *const Context; + pub(super) fn v8__Isolate__GetEnteredOrMicrotaskContext( + isolate: *mut RealIsolate, + ) -> *const Context; + pub(super) fn v8__Isolate__ThrowException( + isolate: *mut RealIsolate, + exception: *const Value, + ) -> *const Value; + pub(super) fn v8__Isolate__GetDataFromSnapshotOnce( + this: *mut RealIsolate, + index: usize, + ) -> *const Data; + pub(super) fn v8__Isolate__GetCurrentHostDefinedOptions( + this: *mut RealIsolate, + ) -> *const Data; + + pub(super) fn v8__Context__Enter(this: *const Context); + pub(super) fn v8__Context__Exit(this: *const Context); + pub(super) fn v8__Context__GetIsolate( + this: *const Context, + ) -> *mut RealIsolate; + pub(super) fn v8__Context__GetDataFromSnapshotOnce( + this: *const Context, + index: usize, + ) -> *const Data; + pub(super) fn v8__Context__SetPromiseHooks( + this: *const Context, + init_hook: *const Function, + before_hook: *const Function, + after_hook: *const Function, + resolve_hook: *const Function, + ); + pub(super) fn v8__Context__SetContinuationPreservedEmbedderData( + this: *mut RealIsolate, + value: *const Value, + ); + pub(super) fn v8__Context__GetContinuationPreservedEmbedderData( + this: *mut RealIsolate, + ) -> *const Value; + + pub(super) fn v8__HandleScope__CONSTRUCT( + buf: *mut MaybeUninit, + isolate: *mut RealIsolate, + ); + pub(super) fn v8__HandleScope__DESTRUCT(this: *mut HandleScope); + + pub(super) fn v8__Local__New( + isolate: *mut RealIsolate, + other: *const Data, + ) -> *const Data; + pub(super) fn v8__Undefined(isolate: *mut RealIsolate) -> *const Primitive; + + pub(super) fn v8__TryCatch__CONSTRUCT( + buf: *mut MaybeUninit, + isolate: *mut RealIsolate, + ); + pub(super) fn v8__TryCatch__DESTRUCT(this: *mut TryCatch); + pub(super) fn v8__TryCatch__HasCaught(this: *const TryCatch) -> bool; + pub(super) fn v8__TryCatch__CanContinue(this: *const TryCatch) -> bool; + pub(super) fn v8__TryCatch__HasTerminated(this: *const TryCatch) -> bool; + pub(super) fn v8__TryCatch__IsVerbose(this: *const TryCatch) -> bool; + pub(super) fn v8__TryCatch__SetVerbose(this: *mut TryCatch, value: bool); + pub(super) fn v8__TryCatch__SetCaptureMessage( + this: *mut TryCatch, + value: bool, + ); + pub(super) fn v8__TryCatch__Reset(this: *mut TryCatch); + pub(super) fn v8__TryCatch__Exception(this: *const TryCatch) -> *const Value; + pub(super) fn v8__TryCatch__StackTrace( + this: *const TryCatch, + context: *const Context, + ) -> *const Value; + pub(super) fn v8__TryCatch__Message(this: *const TryCatch) -> *const Message; + pub(super) fn v8__TryCatch__ReThrow(this: *mut TryCatch) -> *const Value; + + pub(super) fn v8__DisallowJavascriptExecutionScope__CONSTRUCT( + buf: *mut MaybeUninit, + isolate: *mut RealIsolate, + on_failure: OnFailure, + ); + pub(super) fn v8__DisallowJavascriptExecutionScope__DESTRUCT( + this: *mut DisallowJavascriptExecutionScope, + ); + + pub(super) fn v8__AllowJavascriptExecutionScope__CONSTRUCT( + buf: *mut MaybeUninit, + isolate: *mut RealIsolate, + ); + pub(super) fn v8__AllowJavascriptExecutionScope__DESTRUCT( + this: *mut AllowJavascriptExecutionScope, + ); + + pub(super) fn v8__Message__GetIsolate( + this: *const Message, + ) -> *mut RealIsolate; + pub(super) fn v8__Object__GetIsolate(this: *const Object) + -> *mut RealIsolate; +} diff --git a/src/script.rs b/src/script.rs index a3b94ff60d..b127253a01 100644 --- a/src/script.rs +++ b/src/script.rs @@ -4,12 +4,12 @@ use std::ptr::null; use crate::Context; use crate::Data; -use crate::HandleScope; use crate::Local; use crate::Script; use crate::String; use crate::UnboundScript; use crate::Value; +use crate::scope::PinScope; /// The origin, within a file, of a script. #[repr(C)] @@ -59,7 +59,7 @@ impl Script { /// A shorthand for ScriptCompiler::Compile(). #[inline(always)] pub fn compile<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, source: Local, origin: Option<&ScriptOrigin>, ) -> Option> { @@ -78,7 +78,7 @@ impl Script { #[inline(always)] pub fn get_unbound_script<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, UnboundScript> { unsafe { scope @@ -91,10 +91,7 @@ impl Script { /// context in which it was created (ScriptCompiler::CompileBound or /// UnboundScript::BindToCurrentContext()). #[inline] - pub fn run<'s>( - &self, - scope: &mut HandleScope<'s>, - ) -> Option> { + pub fn run<'s>(&self, scope: &PinScope<'s, '_>) -> Option> { unsafe { scope.cast_local(|sd| v8__Script__Run(self, sd.get_current_context())) } @@ -105,9 +102,9 @@ impl Script { impl<'s> ScriptOrigin<'s> { #[allow(clippy::too_many_arguments)] #[inline(always)] - pub fn new( + pub fn new<'i>( // TODO(littledivy): remove - _scope: &mut HandleScope<'s, ()>, + _scope: &PinScope<'s, 'i>, resource_name: Local<'s, Value>, resource_line_offset: i32, resource_column_offset: i32, diff --git a/src/script_compiler.rs b/src/script_compiler.rs index 58f20f3b7f..6d49a4fe0a 100644 --- a/src/script_compiler.rs +++ b/src/script_compiler.rs @@ -7,9 +7,11 @@ use crate::Module; use crate::Object; use crate::ScriptOrigin; use crate::String; +use crate::UniqueRef; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::int; -use crate::{Context, Isolate, Script, UnboundScript}; -use crate::{HandleScope, UniqueRef}; +use crate::{Context, Script, UnboundScript}; unsafe extern "C" { fn v8__ScriptCompiler__Source__CONSTRUCT( @@ -28,7 +30,7 @@ unsafe extern "C" { ) -> *mut CachedData<'a>; fn v8__ScriptCompiler__CachedData__DELETE<'a>(this: *mut CachedData<'a>); fn v8__ScriptCompiler__CompileModule( - isolate: *mut Isolate, + isolate: *mut RealIsolate, source: *mut Source, options: CompileOptions, no_cache_reason: NoCacheReason, @@ -50,7 +52,7 @@ unsafe extern "C" { no_cache_reason: NoCacheReason, ) -> *const Function; fn v8__ScriptCompiler__CompileUnboundScript( - isolate: *mut Isolate, + isolate: *mut RealIsolate, source: *mut Source, options: CompileOptions, no_cache_reason: NoCacheReason, @@ -177,7 +179,7 @@ impl Source { } #[inline(always)] - pub fn get_cached_data(&self) -> Option<&CachedData> { + pub fn get_cached_data(&self) -> Option<&CachedData<'_>> { unsafe { let cached_data = v8__ScriptCompiler__Source__GetCachedData(self); if cached_data.is_null() { @@ -237,7 +239,7 @@ pub enum NoCacheReason { /// specification. #[inline(always)] pub fn compile_module<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, source: &mut Source, ) -> Option> { compile_module2( @@ -251,7 +253,7 @@ pub fn compile_module<'s>( /// Same as compile_module with more options. #[inline(always)] pub fn compile_module2<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, source: &mut Source, options: CompileOptions, no_cache_reason: NoCacheReason, @@ -270,7 +272,7 @@ pub fn compile_module2<'s>( #[inline(always)] pub fn compile<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, source: &mut Source, options: CompileOptions, no_cache_reason: NoCacheReason, @@ -289,7 +291,7 @@ pub fn compile<'s>( #[inline(always)] pub fn compile_function<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, source: &mut Source, arguments: &[Local], context_extensions: &[Local], @@ -316,7 +318,7 @@ pub fn compile_function<'s>( #[inline(always)] pub fn compile_unbound_script<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, source: &mut Source, options: CompileOptions, no_cache_reason: NoCacheReason, diff --git a/src/script_or_module.rs b/src/script_or_module.rs index 62c483a228..48be50e09e 100644 --- a/src/script_or_module.rs +++ b/src/script_or_module.rs @@ -18,7 +18,7 @@ impl ScriptOrModule { /// The name that was passed by the embedder as ResourceName to the /// ScriptOrigin. This can be either a v8::String or v8::Undefined. #[inline(always)] - pub fn get_resource_name(&self) -> Local { + pub fn get_resource_name(&self) -> Local<'_, Value> { // Note: the C++ `v8::ScriptOrModule::GetResourceName()` does not actually // return a local handle, but rather a handle whose lifetime is bound to // the related `ScriptOrModule` object. @@ -31,7 +31,7 @@ impl ScriptOrModule { /// The options that were passed by the embedder as HostDefinedOptions to the /// ScriptOrigin. #[inline(always)] - pub fn host_defined_options(&self) -> Local { + pub fn host_defined_options(&self) -> Local<'_, Data> { // Note: the C++ `v8::ScriptOrModule::HostDefinedOptions()` does not // actually return a local handle, but rather a handle whose lifetime is // bound to the related `ScriptOrModule` object. diff --git a/src/shared_array_buffer.rs b/src/shared_array_buffer.rs index 97045b581a..20768c6bb1 100644 --- a/src/shared_array_buffer.rs +++ b/src/shared_array_buffer.rs @@ -4,20 +4,21 @@ use std::ffi::c_void; use crate::BackingStore; use crate::BackingStoreDeleterCallback; -use crate::HandleScope; -use crate::Isolate; use crate::Local; use crate::SharedArrayBuffer; +use crate::isolate::RealIsolate; +use crate::scope::GetIsolate; +use crate::scope::PinScope; use crate::support::SharedRef; use crate::support::UniqueRef; unsafe extern "C" { fn v8__SharedArrayBuffer__New__with_byte_length( - isolate: *mut Isolate, + isolate: *mut RealIsolate, byte_length: usize, ) -> *const SharedArrayBuffer; fn v8__SharedArrayBuffer__New__with_backing_store( - isolate: *mut Isolate, + isolate: *mut RealIsolate, backing_store: *const SharedRef, ) -> *const SharedArrayBuffer; fn v8__SharedArrayBuffer__ByteLength(this: *const SharedArrayBuffer) @@ -26,7 +27,7 @@ unsafe extern "C" { this: *const SharedArrayBuffer, ) -> SharedRef; fn v8__SharedArrayBuffer__NewBackingStore__with_byte_length( - isolate: *mut Isolate, + isolate: *mut RealIsolate, byte_length: usize, ) -> *mut BackingStore; fn v8__SharedArrayBuffer__NewBackingStore__with_data( @@ -44,7 +45,7 @@ impl SharedArrayBuffer { /// unless the object is externalized. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, byte_length: usize, ) -> Option> { unsafe { @@ -59,7 +60,7 @@ impl SharedArrayBuffer { #[inline(always)] pub fn with_backing_store<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, backing_store: &SharedRef, ) -> Local<'s, SharedArrayBuffer> { unsafe { @@ -97,13 +98,13 @@ impl SharedArrayBuffer { /// function will crash with an out-of-memory error. #[inline(always)] pub fn new_backing_store( - scope: &mut Isolate, + scope: &PinScope<'_, '_>, byte_length: usize, ) -> UniqueRef { unsafe { UniqueRef::from_raw( v8__SharedArrayBuffer__NewBackingStore__with_byte_length( - scope, + scope.get_isolate_ptr(), byte_length, ), ) diff --git a/src/snapshot.rs b/src/snapshot.rs index 2615250caf..c493c65f18 100644 --- a/src/snapshot.rs +++ b/src/snapshot.rs @@ -1,9 +1,9 @@ use crate::Context; use crate::Data; -use crate::Isolate; use crate::Local; use crate::OwnedIsolate; use crate::external_references::ExternalReference; +use crate::isolate::RealIsolate; use crate::isolate_create_params::raw; use crate::support::char; use crate::support::int; @@ -19,7 +19,7 @@ unsafe extern "C" { fn v8__SnapshotCreator__DESTRUCT(this: *mut SnapshotCreator); fn v8__SnapshotCreator__GetIsolate( this: *const SnapshotCreator, - ) -> *mut Isolate; + ) -> *mut RealIsolate; fn v8__SnapshotCreator__CreateBlob( this: *mut SnapshotCreator, function_code_handling: FunctionCodeHandling, diff --git a/src/string.rs b/src/string.rs index 38b9eb278c..feaa2ecbf1 100644 --- a/src/string.rs +++ b/src/string.rs @@ -1,8 +1,9 @@ -use crate::HandleScope; use crate::Isolate; use crate::Local; use crate::String; use crate::binding::v8__String__kMaxLength; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::Opaque; use crate::support::char; use crate::support::int; @@ -17,24 +18,24 @@ use std::ptr::NonNull; use std::slice; unsafe extern "C" { - fn v8__String__Empty(isolate: *mut Isolate) -> *const String; + fn v8__String__Empty(isolate: *mut RealIsolate) -> *const String; fn v8__String__NewFromUtf8( - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *const char, new_type: NewStringType, length: int, ) -> *const String; fn v8__String__NewFromOneByte( - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *const u8, new_type: NewStringType, length: int, ) -> *const String; fn v8__String__NewFromTwoByte( - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *const u16, new_type: NewStringType, length: int, @@ -42,11 +43,14 @@ unsafe extern "C" { fn v8__String__Length(this: *const String) -> int; - fn v8__String__Utf8Length(this: *const String, isolate: *mut Isolate) -> int; + fn v8__String__Utf8Length( + this: *const String, + isolate: *mut RealIsolate, + ) -> int; fn v8__String__Write( this: *const String, - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *mut u16, start: int, length: int, @@ -55,7 +59,7 @@ unsafe extern "C" { fn v8__String__Write_v2( this: *const String, - isolate: *mut Isolate, + isolate: *mut RealIsolate, offset: u32, length: u32, buffer: *mut u16, @@ -64,7 +68,7 @@ unsafe extern "C" { fn v8__String__WriteOneByte( this: *const String, - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *mut u8, start: int, length: int, @@ -73,7 +77,7 @@ unsafe extern "C" { fn v8__String__WriteOneByte_v2( this: *const String, - isolate: *mut Isolate, + isolate: *mut RealIsolate, offset: u32, length: u32, buffer: *mut u8, @@ -82,7 +86,7 @@ unsafe extern "C" { fn v8__String__WriteUtf8( this: *const String, - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *mut char, length: int, nchars_ref: *mut int, @@ -91,7 +95,7 @@ unsafe extern "C" { fn v8__String__WriteUtf8_v2( this: *const String, - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *mut char, capacity: size_t, flags: int, @@ -107,25 +111,25 @@ unsafe extern "C" { ) -> *mut ExternalStringResourceBase; fn v8__String__NewExternalOneByteConst( - isolate: *mut Isolate, + isolate: *mut RealIsolate, onebyte_const: *const OneByteConst, ) -> *const String; fn v8__String__NewExternalOneByteStatic( - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *const char, length: int, ) -> *const String; fn v8__String__NewExternalOneByte( - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *mut char, length: size_t, free: unsafe extern "C" fn(*mut char, size_t), ) -> *const String; fn v8__String__NewExternalTwoByteStatic( - isolate: *mut Isolate, + isolate: *mut RealIsolate, buffer: *const u16, length: int, ) -> *const String; @@ -146,7 +150,7 @@ unsafe extern "C" { fn v8__String__ValueView__CONSTRUCT( buf: *mut ValueView, - isolate: *mut Isolate, + isolate: *mut RealIsolate, string: *const String, ); fn v8__String__ValueView__DESTRUCT(this: *mut ValueView); @@ -282,7 +286,7 @@ unsafe extern "C" fn one_byte_const_length(this: *const OneByteConst) -> usize { } unsafe extern "C" fn one_byte_const_unaccount( _this: *const OneByteConst, - _isolate: *mut Isolate, + _isolate: *mut RealIsolate, ) { } unsafe extern "C" fn one_byte_const_estimate_memory_usage( @@ -303,7 +307,7 @@ type OneByteConstData = unsafe extern "C" fn(*const OneByteConst) -> *const char; type OneByteConstLength = unsafe extern "C" fn(*const OneByteConst) -> usize; type OneByteConstUnaccount = - unsafe extern "C" fn(*const OneByteConst, *mut Isolate); + unsafe extern "C" fn(*const OneByteConst, *mut RealIsolate); type OneByteConstEstimateMemoryUsage = unsafe extern "C" fn(*const OneByteConst) -> size_t; type OneByteConstEstimateSharedMemoryUsage = @@ -403,7 +407,7 @@ impl String { pub const MAX_LENGTH: usize = v8__String__kMaxLength as _; #[inline(always)] - pub fn empty<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, String> { + pub fn empty<'s>(scope: &PinScope<'s, '_, ()>) -> Local<'s, String> { // FIXME(bnoordhuis) v8__String__Empty() is infallible so there // is no need to box up the result, only to unwrap it again. unsafe { scope.cast_local(|sd| v8__String__Empty(sd.get_isolate_ptr())) } @@ -414,7 +418,7 @@ impl String { /// length > kMaxLength #[inline(always)] pub fn new_from_utf8<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: &[u8], new_type: NewStringType, ) -> Option> { @@ -438,7 +442,7 @@ impl String { /// length > kMaxLength. #[inline(always)] pub fn new_from_one_byte<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: &[u8], new_type: NewStringType, ) -> Option> { @@ -459,7 +463,7 @@ impl String { /// length > kMaxLength. #[inline(always)] pub fn new_from_two_byte<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: &[u16], new_type: NewStringType, ) -> Option> { @@ -485,8 +489,8 @@ impl String { /// Returns the number of bytes in the UTF-8 encoded representation of this /// string. #[inline(always)] - pub fn utf8_length(&self, scope: &mut Isolate) -> usize { - unsafe { v8__String__Utf8Length(self, scope) as usize } + pub fn utf8_length(&self, scope: &Isolate) -> usize { + unsafe { v8__String__Utf8Length(self, scope.as_real_ptr()) as usize } } /// Writes the contents of the string to an external buffer, as 16-bit @@ -495,7 +499,7 @@ impl String { #[deprecated = "Use `v8::String::write_v2` instead"] pub fn write( &self, - scope: &mut Isolate, + scope: &Isolate, buffer: &mut [u16], start: usize, options: WriteOptions, @@ -503,7 +507,7 @@ impl String { unsafe { v8__String__Write( self, - scope, + scope.as_real_ptr(), buffer.as_mut_ptr(), start.try_into().unwrap_or(int::MAX), buffer.len().try_into().unwrap_or(int::MAX), @@ -517,7 +521,7 @@ impl String { #[inline(always)] pub fn write_v2( &self, - scope: &mut Isolate, + scope: &Isolate, offset: u32, buffer: &mut [u16], flags: WriteFlags, @@ -525,7 +529,7 @@ impl String { unsafe { v8__String__Write_v2( self, - scope, + scope.as_real_ptr(), offset, self.length().min(buffer.len()) as _, buffer.as_mut_ptr(), @@ -540,7 +544,7 @@ impl String { #[deprecated = "Use `v8::String::write_one_byte_v2` instead."] pub fn write_one_byte( &self, - scope: &mut Isolate, + scope: &Isolate, buffer: &mut [u8], start: usize, options: WriteOptions, @@ -548,7 +552,7 @@ impl String { unsafe { v8__String__WriteOneByte( self, - scope, + scope.as_real_ptr(), buffer.as_mut_ptr(), start.try_into().unwrap_or(int::MAX), buffer.len().try_into().unwrap_or(int::MAX), @@ -562,7 +566,7 @@ impl String { #[inline(always)] pub fn write_one_byte_v2( &self, - scope: &mut Isolate, + scope: &Isolate, offset: u32, buffer: &mut [u8], flags: WriteFlags, @@ -570,7 +574,7 @@ impl String { unsafe { v8__String__WriteOneByte_v2( self, - scope, + scope.as_real_ptr(), offset, self.length().min(buffer.len()) as _, buffer.as_mut_ptr(), @@ -585,7 +589,7 @@ impl String { #[deprecated = "Use `v8::String::write_one_byte_uninit_v2` instead."] pub fn write_one_byte_uninit( &self, - scope: &mut Isolate, + scope: &Isolate, buffer: &mut [MaybeUninit], start: usize, options: WriteOptions, @@ -593,7 +597,7 @@ impl String { unsafe { v8__String__WriteOneByte( self, - scope, + scope.as_real_ptr(), buffer.as_mut_ptr() as *mut u8, start.try_into().unwrap_or(int::MAX), buffer.len().try_into().unwrap_or(int::MAX), @@ -607,7 +611,7 @@ impl String { #[inline(always)] pub fn write_one_byte_uninit_v2( &self, - scope: &mut Isolate, + scope: &Isolate, offset: u32, buffer: &mut [MaybeUninit], flags: WriteFlags, @@ -615,7 +619,7 @@ impl String { unsafe { v8__String__WriteOneByte_v2( self, - scope, + scope.as_real_ptr(), offset, self.length().min(buffer.len()) as _, buffer.as_mut_ptr() as _, @@ -652,7 +656,7 @@ impl String { #[inline(always)] pub fn write_utf8_v2( &self, - scope: &mut Isolate, + scope: &Isolate, buffer: &mut [u8], flags: WriteFlags, processed_characters_return: Option<&mut usize>, @@ -680,7 +684,7 @@ impl String { #[deprecated = "Use `v8::String::write_utf8_uninit_v2` instead."] pub fn write_utf8_uninit( &self, - scope: &mut Isolate, + scope: &Isolate, buffer: &mut [MaybeUninit], nchars_ref: Option<&mut usize>, options: WriteOptions, @@ -689,7 +693,7 @@ impl String { let bytes = unsafe { v8__String__WriteUtf8( self, - scope, + scope.as_real_ptr(), buffer.as_mut_ptr() as *mut char, buffer.len().try_into().unwrap_or(int::MAX), &mut nchars_ref_int, @@ -705,7 +709,7 @@ impl String { /// Writes the contents of the string to an external [`MaybeUninit`] buffer, as UTF-8. pub fn write_utf8_uninit_v2( &self, - scope: &mut Isolate, + scope: &Isolate, buffer: &mut [MaybeUninit], flags: WriteFlags, processed_characters_return: Option<&mut usize>, @@ -713,7 +717,7 @@ impl String { let bytes = unsafe { v8__String__WriteUtf8_v2( self, - scope, + scope.as_real_ptr(), buffer.as_mut_ptr() as _, buffer.len(), flags.bits(), @@ -728,7 +732,7 @@ impl String { // Convenience function not present in the original V8 API. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, value: &str, ) -> Option> { Self::new_from_utf8(scope, value.as_ref(), NewStringType::Normal) @@ -776,7 +780,7 @@ impl String { /// OneByte string resources to contain Latin-1. #[inline(always)] pub fn new_from_onebyte_const<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, onebyte_const: &'static OneByteConst, ) -> Option> { unsafe { @@ -790,7 +794,7 @@ impl String { /// must be Latin-1 or ASCII, not UTF-8! #[inline(always)] pub fn new_external_onebyte_static<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: &'static [u8], ) -> Option> { let buffer_len = buffer.len().try_into().ok()?; @@ -810,7 +814,7 @@ impl String { /// V8 will take ownership of the buffer and free it when the string is garbage collected. #[inline(always)] pub fn new_external_onebyte<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: Box<[u8]>, ) -> Option> { let buffer_len = buffer.len(); @@ -835,7 +839,7 @@ impl String { /// The destructor will be called with the buffer and length when the string is garbage collected. #[inline(always)] pub unsafe fn new_external_onebyte_raw<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: *mut char, buffer_len: usize, destructor: unsafe extern "C" fn(*mut char, usize), @@ -855,7 +859,7 @@ impl String { /// Creates a v8::String from a `&'static [u16]`. #[inline(always)] pub fn new_external_twobyte_static<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, buffer: &'static [u16], ) -> Option> { let buffer_len = buffer.len().try_into().ok()?; @@ -960,10 +964,7 @@ impl String { /// Creates a copy of a [`crate::String`] in a [`std::string::String`]. /// Convenience function not present in the original V8 API. - pub fn to_rust_string_lossy( - &self, - scope: &mut Isolate, - ) -> std::string::String { + pub fn to_rust_string_lossy(&self, scope: &Isolate) -> std::string::String { let len_utf16 = self.length(); // No need to allocate or do any work for zero-length strings @@ -1161,7 +1162,11 @@ impl<'s> ValueView<'s> { pub fn new(isolate: &mut Isolate, string: Local<'s, String>) -> Self { let mut v = std::mem::MaybeUninit::uninit(); unsafe { - v8__String__ValueView__CONSTRUCT(v.as_mut_ptr(), isolate, &*string); + v8__String__ValueView__CONSTRUCT( + v.as_mut_ptr(), + isolate.as_real_ptr(), + &*string, + ); v.assume_init() } } diff --git a/src/support.rs b/src/support.rs index d0ba45cc0d..a28572695e 100644 --- a/src/support.rs +++ b/src/support.rs @@ -611,6 +611,47 @@ where } } +macro_rules! assert_layout_subset { + ($subset: ty, $superset: ty { $($field: ident),* $(,)? }) => { + const _: () = { + if !(std::mem::size_of::<$subset>() < std::mem::size_of::<$superset>()) { + panic!(concat!( + "assertion failed: ", + "size of `", + stringify!($subset), + "` is greater than `", + stringify!($superset), + "`" + )); + } + if !(std::mem::align_of::<$subset>() == std::mem::align_of::<$superset>()) { + panic!(concat!( + "assertion failed: `", + stringify!($subset), + "` and `", + stringify!($superset), + "` have different alignments" + )); + } + $( + if std::mem::offset_of!($subset, $field) != std::mem::offset_of!($superset, $field) { + panic!(concat!( + "assertion failed: `", + stringify!($subset), + "` and `", + stringify!($superset), + "` have different offsets for field `", + stringify!($field), + "`" + )); + } + )* + }; + }; +} + +pub(crate) use assert_layout_subset; + #[cfg(test)] mod tests { use super::*; diff --git a/src/symbol.rs b/src/symbol.rs index 1ba17830b6..a6958e9c44 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -1,34 +1,34 @@ -use crate::HandleScope; -use crate::Isolate; use crate::Local; use crate::String; use crate::Symbol; use crate::Value; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; unsafe extern "C" { fn v8__Symbol__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, description: *const String, ) -> *const Symbol; fn v8__Symbol__For( - isolate: *mut Isolate, + isolate: *mut RealIsolate, description: *const String, ) -> *const Symbol; fn v8__Symbol__ForApi( - isolate: *mut Isolate, + isolate: *mut RealIsolate, description: *const String, ) -> *const Symbol; fn v8__Symbol__Description( this: *const Symbol, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const Value; } macro_rules! well_known { ($name:ident, $binding:ident) => { - pub fn $name<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, Symbol> { + pub fn $name<'s>(scope: &PinScope<'s, '_, ()>) -> Local<'s, Symbol> { unsafe extern "C" { - fn $binding(isolate: *mut Isolate) -> *const Symbol; + fn $binding(isolate: *mut RealIsolate) -> *const Symbol; } unsafe { scope.cast_local(|sd| $binding(sd.get_isolate_ptr())) }.unwrap() } @@ -40,7 +40,7 @@ impl Symbol { /// description. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, description: Option>, ) -> Local<'s, Symbol> { unsafe { @@ -63,7 +63,7 @@ impl Symbol { /// Corresponds to v8::Symbol::For() in C++. #[inline(always)] pub fn for_key<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, description: Local, ) -> Local<'s, Symbol> { unsafe { @@ -78,7 +78,7 @@ impl Symbol { /// Corresponds to v8::Symbol::ForApi() in C++. #[inline(always)] pub fn for_api<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, description: Local, ) -> Local<'s, Symbol> { unsafe { @@ -93,7 +93,7 @@ impl Symbol { #[inline(always)] pub fn description<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, ) -> Local<'s, Value> { unsafe { scope.cast_local(|sd| v8__Symbol__Description(self, sd.get_isolate_ptr())) diff --git a/src/template.rs b/src/template.rs index 722c4d98dc..c9248f9103 100644 --- a/src/template.rs +++ b/src/template.rs @@ -3,7 +3,6 @@ use crate::Context; use crate::Function; use crate::FunctionBuilder; use crate::FunctionCallback; -use crate::HandleScope; use crate::IndexedDefinerCallback; use crate::IndexedDeleterCallback; use crate::IndexedGetterCallback; @@ -31,7 +30,8 @@ use crate::data::Name; use crate::data::ObjectTemplate; use crate::data::Template; use crate::fast_api::CFunction; -use crate::isolate::Isolate; +use crate::isolate::RealIsolate; +use crate::scope::PinScope; use crate::support::MapFnTo; use crate::support::int; use std::convert::TryFrom; @@ -52,11 +52,11 @@ unsafe extern "C" { ); fn v8__Signature__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, templ: *const FunctionTemplate, ) -> *const Signature; fn v8__FunctionTemplate__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, callback: FunctionCallback, data_or_null: *const Value, signature_or_null: *const Signature, @@ -88,7 +88,7 @@ unsafe extern "C" { fn v8__FunctionTemplate__RemovePrototype(this: *const FunctionTemplate); fn v8__ObjectTemplate__New( - isolate: *mut Isolate, + isolate: *mut RealIsolate, templ: *const FunctionTemplate, ) -> *const ObjectTemplate; fn v8__ObjectTemplate__NewInstance( @@ -668,9 +668,9 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> { /// Creates the function template. #[inline(always)] - pub fn build( + pub fn build<'i>( self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, 'i, ()>, ) -> Local<'s, FunctionTemplate> { unsafe { scope.cast_local(|sd| { @@ -695,9 +695,9 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> { /// useful to pass them explicitly - eg. when you are snapshotting you'd provide /// the overloads and `CFunctionInfo` that would be placed in the external /// references array. - pub fn build_fast( + pub fn build_fast<'i>( self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, 'i>, overloads: &[CFunction], ) -> Local<'s, FunctionTemplate> { unsafe { @@ -728,7 +728,7 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> { impl Signature { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, templ: Local, ) -> Local<'s, Self> { unsafe { @@ -758,7 +758,7 @@ impl FunctionTemplate { /// Creates a function template. #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, callback: impl MapFnTo, ) -> Local<'s, FunctionTemplate> { Self::builder(callback).build(scope) @@ -766,7 +766,7 @@ impl FunctionTemplate { #[inline(always)] pub fn new_raw<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, callback: FunctionCallback, ) -> Local<'s, FunctionTemplate> { Self::builder_raw(callback).build(scope) @@ -776,7 +776,7 @@ impl FunctionTemplate { #[inline(always)] pub fn get_function<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|sd| { @@ -798,7 +798,7 @@ impl FunctionTemplate { #[inline(always)] pub fn prototype_template<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, ) -> Local<'s, ObjectTemplate> { unsafe { scope.cast_local(|_sd| v8__FunctionTemplate__PrototypeTemplate(self)) @@ -811,7 +811,7 @@ impl FunctionTemplate { #[inline(always)] pub fn instance_template<'s>( &self, - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, ) -> Local<'s, ObjectTemplate> { unsafe { scope.cast_local(|_sd| v8__FunctionTemplate__InstanceTemplate(self)) @@ -843,7 +843,7 @@ impl FunctionTemplate { impl ObjectTemplate { /// Creates an object template. #[inline(always)] - pub fn new<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, ObjectTemplate> { + pub fn new<'s>(scope: &PinScope<'s, '_, ()>) -> Local<'s, ObjectTemplate> { unsafe { scope.cast_local(|sd| { v8__ObjectTemplate__New(sd.get_isolate_ptr(), std::ptr::null()) @@ -855,7 +855,7 @@ impl ObjectTemplate { /// Creates an object template from a function template. #[inline(always)] pub fn new_from_template<'s>( - scope: &mut HandleScope<'s, ()>, + scope: &PinScope<'s, '_, ()>, templ: Local, ) -> Local<'s, ObjectTemplate> { unsafe { @@ -869,7 +869,7 @@ impl ObjectTemplate { #[inline(always)] pub fn new_instance<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|sd| { diff --git a/src/typed_array.rs b/src/typed_array.rs index 521bf58f2a..1ef8413282 100644 --- a/src/typed_array.rs +++ b/src/typed_array.rs @@ -1,7 +1,7 @@ // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. use crate::ArrayBuffer; -use crate::HandleScope; use crate::Local; +use crate::PinScope; use crate::TypedArray; use crate::binding::v8__TypedArray__kMaxByteLength; use crate::support::size_t; @@ -40,7 +40,7 @@ macro_rules! typed_array { impl $name { #[inline(always)] pub fn new<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, buf: Local, byte_offset: usize, length: usize, diff --git a/src/unbound_module_script.rs b/src/unbound_module_script.rs index ddca1fdd7e..a9da4bdef4 100644 --- a/src/unbound_module_script.rs +++ b/src/unbound_module_script.rs @@ -1,6 +1,6 @@ use crate::CachedData; -use crate::HandleScope; use crate::Local; +use crate::PinScope; use crate::UnboundModuleScript; use crate::UniqueRef; use crate::Value; @@ -39,7 +39,7 @@ impl UnboundModuleScript { pub fn get_source_mapping_url<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, Value> { unsafe { scope @@ -50,7 +50,7 @@ impl UnboundModuleScript { pub fn get_source_url<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, Value> { unsafe { scope diff --git a/src/unbound_script.rs b/src/unbound_script.rs index ef36beba66..e58ed397c6 100644 --- a/src/unbound_script.rs +++ b/src/unbound_script.rs @@ -1,6 +1,6 @@ use crate::CachedData; -use crate::HandleScope; use crate::Local; +use crate::PinScope; use crate::Script; use crate::UnboundScript; use crate::UniqueRef; @@ -28,7 +28,7 @@ impl UnboundScript { #[inline(always)] pub fn bind_to_current_context<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, Script> { unsafe { scope.cast_local(|_| v8__UnboundScript__BindToCurrentContext(self)) @@ -56,7 +56,7 @@ impl UnboundScript { #[inline(always)] pub fn get_source_mapping_url<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, Value> { unsafe { scope @@ -68,7 +68,7 @@ impl UnboundScript { #[inline(always)] pub fn get_source_url<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Local<'s, Value> { unsafe { scope diff --git a/src/value.rs b/src/value.rs index 23ed604f2c..41b0654b83 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,16 +1,17 @@ use crate::BigInt; use crate::Boolean; use crate::Context; -use crate::HandleScope; use crate::Int32; use crate::Integer; -use crate::Isolate; use crate::Local; use crate::Number; use crate::Object; +use crate::PinScope; use crate::String; use crate::Uint32; use crate::Value; +use crate::isolate::RealIsolate; +use crate::scope::GetIsolate; use crate::support::Maybe; unsafe extern "C" { @@ -114,7 +115,7 @@ unsafe extern "C" { ) -> *const Int32; fn v8__Value__ToBoolean( this: *const Value, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const Boolean; fn v8__Value__NumberValue( @@ -137,12 +138,14 @@ unsafe extern "C" { context: *const Context, out: *mut Maybe, ); - fn v8__Value__BooleanValue(this: *const Value, isolate: *mut Isolate) - -> bool; + fn v8__Value__BooleanValue( + this: *const Value, + isolate: *mut RealIsolate, + ) -> bool; fn v8__Value__GetHash(this: *const Value) -> u32; fn v8__Value__TypeOf( this: *const Value, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const String; } @@ -533,7 +536,7 @@ impl Value { #[inline(always)] pub fn to_big_int<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -544,7 +547,7 @@ impl Value { #[inline(always)] pub fn to_number<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -555,7 +558,7 @@ impl Value { #[inline(always)] pub fn to_string<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -567,7 +570,7 @@ impl Value { #[inline(always)] pub fn to_rust_string_lossy( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, ) -> std::string::String { self .to_string(scope) @@ -577,7 +580,7 @@ impl Value { #[inline(always)] pub fn to_detail_string<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope.cast_local(|sd| { @@ -589,7 +592,7 @@ impl Value { #[inline(always)] pub fn to_object<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -600,7 +603,7 @@ impl Value { #[inline(always)] pub fn to_integer<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -611,7 +614,7 @@ impl Value { #[inline(always)] pub fn to_uint32<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -622,7 +625,7 @@ impl Value { #[inline(always)] pub fn to_int32<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, ) -> Option> { unsafe { scope @@ -632,10 +635,7 @@ impl Value { /// Perform the equivalent of Boolean(value) in JS. This can never fail. #[inline(always)] - pub fn to_boolean<'s>( - &self, - scope: &mut HandleScope<'s, ()>, - ) -> Local<'s, Boolean> { + pub fn to_boolean<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Boolean> { unsafe { scope.cast_local(|sd| v8__Value__ToBoolean(self, sd.get_isolate_ptr())) } @@ -645,7 +645,7 @@ impl Value { #[inline(always)] pub fn instance_of( &self, - scope: &mut HandleScope, + scope: &PinScope<'_, '_>, object: Local, ) -> Option { let mut out = Maybe::::default(); @@ -661,7 +661,7 @@ impl Value { } #[inline(always)] - pub fn number_value(&self, scope: &mut HandleScope) -> Option { + pub fn number_value(&self, scope: &PinScope<'_, '_>) -> Option { let mut out = Maybe::::default(); unsafe { v8__Value__NumberValue(self, &*scope.get_current_context(), &mut out); @@ -670,7 +670,7 @@ impl Value { } #[inline(always)] - pub fn integer_value(&self, scope: &mut HandleScope) -> Option { + pub fn integer_value(&self, scope: &PinScope<'_, '_>) -> Option { let mut out = Maybe::::default(); unsafe { v8__Value__IntegerValue(self, &*scope.get_current_context(), &mut out); @@ -679,7 +679,7 @@ impl Value { } #[inline(always)] - pub fn uint32_value(&self, scope: &mut HandleScope) -> Option { + pub fn uint32_value(&self, scope: &PinScope<'_, '_>) -> Option { let mut out = Maybe::::default(); unsafe { v8__Value__Uint32Value(self, &*scope.get_current_context(), &mut out); @@ -688,7 +688,7 @@ impl Value { } #[inline(always)] - pub fn int32_value(&self, scope: &mut HandleScope) -> Option { + pub fn int32_value(&self, scope: &PinScope<'_, '_>) -> Option { let mut out = Maybe::::default(); unsafe { v8__Value__Int32Value(self, &*scope.get_current_context(), &mut out); @@ -697,7 +697,7 @@ impl Value { } #[inline(always)] - pub fn boolean_value(&self, scope: &mut HandleScope<'_, ()>) -> bool { + pub fn boolean_value(&self, scope: &PinScope<'_, '_>) -> bool { unsafe { v8__Value__BooleanValue(self, scope.get_isolate_ptr()) } } @@ -711,10 +711,7 @@ impl Value { } #[inline(always)] - pub fn type_of<'s>( - &self, - scope: &mut HandleScope<'s, ()>, - ) -> Local<'s, String> { + pub fn type_of<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, String> { unsafe { scope.cast_local(|sd| v8__Value__TypeOf(self, sd.get_isolate_ptr())) } diff --git a/src/value_deserializer.rs b/src/value_deserializer.rs index 82cd5f8d21..4c646270ab 100644 --- a/src/value_deserializer.rs +++ b/src/value_deserializer.rs @@ -1,17 +1,19 @@ use crate::ArrayBuffer; -use crate::CallbackScope; use crate::Context; -use crate::ContextScope; use crate::Exception; use crate::Global; -use crate::HandleScope; use crate::Isolate; use crate::Local; use crate::Object; +use crate::PinScope; use crate::SharedArrayBuffer; use crate::String; use crate::Value; use crate::WasmModuleObject; +use crate::isolate::RealIsolate; +use crate::scope::CallbackScope; +use crate::scope::ContextScope; +use crate::scope::GetIsolate; use crate::support::CxxVTable; use crate::support::FieldOffset; @@ -20,6 +22,7 @@ use crate::support::MaybeBool; use std::ffi::c_void; use std::mem::MaybeUninit; use std::pin::Pin; +use std::pin::pin; use std::ptr::addr_of; // Must be == sizeof(v8::ValueDeserializer::Delegate), @@ -32,18 +35,23 @@ pub struct CxxValueDeserializerDelegate { #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueDeserializer__Delegate__ReadHostObject( this: &CxxValueDeserializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> *const Object { let value_deserializer_heap = unsafe { ValueDeserializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); let context = Local::new(scope, &value_deserializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = { ContextScope::new(scope, context) }; match value_deserializer_heap .value_deserializer_impl - .read_host_object(scope, &value_deserializer_heap.cxx_value_deserializer) - { + .read_host_object( + &mut scope, + &value_deserializer_heap.cxx_value_deserializer, + ) { None => std::ptr::null(), Some(x) => x.as_non_null().as_ptr(), } @@ -52,18 +60,22 @@ unsafe extern "C" fn v8__ValueDeserializer__Delegate__ReadHostObject( #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetSharedArrayBufferFromId( this: &CxxValueDeserializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, transfer_id: u32, ) -> *const SharedArrayBuffer { let value_deserializer_heap = unsafe { ValueDeserializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); + // let hs = scope; let context = Local::new(scope, &value_deserializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = { ContextScope::new(scope, context) }; match value_deserializer_heap .value_deserializer_impl - .get_shared_array_buffer_from_id(scope, transfer_id) + .get_shared_array_buffer_from_id(&mut scope, transfer_id) { None => std::ptr::null(), Some(x) => x.as_non_null().as_ptr(), @@ -73,18 +85,21 @@ unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetSharedArrayBufferFromId #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetWasmModuleFromId( this: &mut CxxValueDeserializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, clone_id: u32, ) -> *const WasmModuleObject { let value_deserializer_heap = unsafe { ValueDeserializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); let context = Local::new(scope, &value_deserializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = { ContextScope::new(scope, context) }; match value_deserializer_heap .value_deserializer_impl - .get_wasm_module_from_id(scope, clone_id) + .get_wasm_module_from_id(&mut scope, clone_id) { None => std::ptr::null(), Some(x) => x.as_non_null().as_ptr(), @@ -107,7 +122,7 @@ pub struct CxxValueDeserializer { unsafe extern "C" { fn v8__ValueDeserializer__CONSTRUCT( buf: *mut MaybeUninit, - isolate: *mut Isolate, + isolate: *mut RealIsolate, data: *const u8, size: usize, delegate: *mut CxxValueDeserializerDelegate, @@ -173,7 +188,7 @@ unsafe extern "C" { pub trait ValueDeserializerImpl { fn read_host_object<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, _value_deserializer: &dyn ValueDeserializerHelper, ) -> Option> { let msg = @@ -186,7 +201,7 @@ pub trait ValueDeserializerImpl { fn get_shared_array_buffer_from_id<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, _transfer_id: u32, ) -> Option> { let msg = String::new( @@ -201,7 +216,7 @@ pub trait ValueDeserializerImpl { fn get_wasm_module_from_id<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, _clone_id: u32, ) -> Option> { let msg = String::new( @@ -401,8 +416,8 @@ pub struct ValueDeserializer<'a> { } impl<'a> ValueDeserializer<'a> { - pub fn new( - scope: &mut HandleScope, + pub fn new<'s, 'i, D: ValueDeserializerImpl + 'a>( + scope: &PinScope<'s, 'i>, value_deserializer_impl: Box, data: &[u8], ) -> Self { diff --git a/src/value_serializer.rs b/src/value_serializer.rs index 79f1b5ee84..88a13ae4ce 100644 --- a/src/value_serializer.rs +++ b/src/value_serializer.rs @@ -1,23 +1,26 @@ use crate::ArrayBuffer; -use crate::CallbackScope; use crate::Context; -use crate::ContextScope; use crate::Exception; use crate::Global; -use crate::HandleScope; use crate::Isolate; use crate::Local; use crate::Object; +use crate::PinScope; use crate::SharedArrayBuffer; use crate::String; use crate::Value; use crate::WasmModuleObject; +use crate::isolate::RealIsolate; +use crate::scope::CallbackScope; +use crate::scope::ContextScope; +use crate::scope::GetIsolate; use std::alloc::Layout; use std::alloc::alloc; use std::alloc::dealloc; use std::alloc::realloc; use std::mem::MaybeUninit; +use std::pin::pin; use std::ptr::addr_of; use std::sync::atomic::AtomicUsize; @@ -41,59 +44,68 @@ unsafe extern "C" fn v8__ValueSerializer__Delegate__ThrowDataCloneError( message: Local, ) { let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) }; - let scope = unsafe { - &mut CallbackScope::new(value_serializer_heap.isolate_ptr.as_mut().unwrap()) - }; + let mut isolate = + unsafe { Isolate::from_raw_ptr(value_serializer_heap.isolate_ptr) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); let context = Local::new(scope, &value_serializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = ContextScope::new(scope, context); value_serializer_heap .value_serializer_impl - .throw_data_clone_error(scope, message); + .throw_data_clone_error(&mut scope, message); } #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueSerializer__Delegate__HasCustomHostObject( this: &CxxValueSerializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, ) -> bool { let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) }; + let isolate = unsafe { Isolate::from_raw_ptr(isolate) }; value_serializer_heap .value_serializer_impl - .has_custom_host_object(unsafe { &mut *isolate }) + .has_custom_host_object(&isolate) } #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueSerializer__Delegate__IsHostObject( this: &CxxValueSerializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, object: Local, ) -> MaybeBool { let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); let context = Local::new(scope, &value_serializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = ContextScope::new(scope, context); MaybeBool::from( value_serializer_heap .value_serializer_impl - .is_host_object(scope, object), + .is_host_object(&mut scope, object), ) } #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueSerializer__Delegate__WriteHostObject( this: &CxxValueSerializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, object: Local, ) -> MaybeBool { let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); let context = Local::new(scope, &value_serializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = ContextScope::new(scope, context); let value_serializer_impl = value_serializer_heap.value_serializer_impl.as_ref(); MaybeBool::from(value_serializer_impl.write_host_object( - scope, + &mut scope, object, &value_serializer_heap.cxx_value_serializer, )) @@ -102,17 +114,20 @@ unsafe extern "C" fn v8__ValueSerializer__Delegate__WriteHostObject( #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueSerializer__Delegate__GetSharedArrayBufferId( this: &CxxValueSerializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, shared_array_buffer: Local, clone_id: *mut u32, ) -> bool { let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); let context = Local::new(scope, &value_serializer_heap.context); - let scope = &mut ContextScope::new(scope, context); + let mut scope = ContextScope::new(scope, context); match value_serializer_heap .value_serializer_impl - .get_shared_array_buffer_id(scope, shared_array_buffer) + .get_shared_array_buffer_id(&mut scope, shared_array_buffer) { Some(x) => { unsafe { @@ -127,13 +142,16 @@ unsafe extern "C" fn v8__ValueSerializer__Delegate__GetSharedArrayBufferId( #[unsafe(no_mangle)] unsafe extern "C" fn v8__ValueSerializer__Delegate__GetWasmModuleTransferId( this: &CxxValueSerializerDelegate, - isolate: *mut Isolate, + isolate: *mut RealIsolate, module: Local, transfer_id: *mut u32, ) -> bool { let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) }; - let scope = unsafe { &mut CallbackScope::new(isolate.as_mut().unwrap()) }; - let context = Local::new(scope, value_serializer_heap.context.clone()); + let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) }; + let scope = unsafe { CallbackScope::new(&mut isolate) }; + let scope = pin!(scope); + let scope = &mut scope.init(); + let context = Local::new(scope, &value_serializer_heap.context); let scope = &mut ContextScope::new(scope, context); match value_serializer_heap .value_serializer_impl @@ -206,7 +224,7 @@ pub struct CxxValueSerializer { unsafe extern "C" { fn v8__ValueSerializer__CONSTRUCT( buf: *mut MaybeUninit, - isolate: *mut Isolate, + isolate: *mut RealIsolate, delegate: *mut CxxValueSerializerDelegate, ); @@ -258,17 +276,17 @@ unsafe extern "C" { pub trait ValueSerializerImpl { fn throw_data_clone_error<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, message: Local<'s, String>, ); - fn has_custom_host_object(&self, _isolate: &mut Isolate) -> bool { + fn has_custom_host_object(&self, _isolate: &Isolate) -> bool { false } fn is_host_object<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, _object: Local<'s, Object>, ) -> Option { let msg = @@ -281,7 +299,7 @@ pub trait ValueSerializerImpl { fn write_host_object<'s>( &self, - scope: &mut HandleScope<'s>, + scope: &mut PinScope<'s, '_>, _object: Local<'s, Object>, _value_serializer: &dyn ValueSerializerHelper, ) -> Option { @@ -295,7 +313,7 @@ pub trait ValueSerializerImpl { fn get_shared_array_buffer_id<'s>( &self, - _scope: &mut HandleScope<'s>, + _scope: &mut PinScope<'s, '_>, _shared_array_buffer: Local<'s, SharedArrayBuffer>, ) -> Option { None @@ -303,7 +321,7 @@ pub trait ValueSerializerImpl { fn get_wasm_module_transfer_id( &self, - scope: &mut HandleScope<'_>, + scope: &mut PinScope<'_, '_>, _module: Local, ) -> Option { let msg = String::new( @@ -330,7 +348,7 @@ pub struct ValueSerializerHeap<'a> { cxx_value_serializer: CxxValueSerializer, buffer_size: AtomicUsize, context: Global, - isolate_ptr: *mut Isolate, + isolate_ptr: *mut RealIsolate, } impl ValueSerializerHeap<'_> { @@ -484,8 +502,8 @@ pub struct ValueSerializer<'a> { /// The 's lifetime is the lifetime of the HandleScope which is used to retrieve /// a Local<'s, Context> for the CallbackScopes impl<'a> ValueSerializer<'a> { - pub fn new( - scope: &mut HandleScope, + pub fn new<'s, 'i, D: ValueSerializerImpl + 'a>( + scope: &PinScope<'s, 'i>, value_serializer_impl: Box, ) -> Self { let context = scope.get_current_context(); diff --git a/src/wasm.rs b/src/wasm.rs index e86e7961f1..89036d403d 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -1,15 +1,16 @@ // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license. use crate::ArrayBuffer; -use crate::Isolate; use crate::Local; +use crate::PinScope; use crate::Value; use crate::WasmMemoryObject; use crate::WasmModuleObject; use crate::function::FunctionCallbackArguments; use crate::function::FunctionCallbackInfo; -use crate::scope::CallbackScope; -use crate::scope::HandleScope; +use crate::isolate::RealIsolate; +use crate::scope::GetIsolate; +use crate::scope::callback_scope; use crate::support::Opaque; use crate::support::UnitType; use crate::support::char; @@ -95,7 +96,7 @@ impl WasmModuleObject { /// a CompiledWasmModule. #[inline(always)] pub fn from_compiled_module<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, compiled_module: &CompiledWasmModule, ) -> Option> { unsafe { @@ -119,7 +120,7 @@ impl WasmModuleObject { /// Compile a Wasm module from the provided uncompiled bytes. #[inline(always)] pub fn compile<'s>( - scope: &mut HandleScope<'s>, + scope: &PinScope<'s, '_>, wire_bytes: &[u8], ) -> Option> { unsafe { @@ -182,7 +183,7 @@ impl Drop for CompiledWasmModule { impl WasmMemoryObject { /// Returns underlying ArrayBuffer. #[inline(always)] - pub fn buffer(&self) -> Local { + pub fn buffer(&self) -> Local<'_, ArrayBuffer> { unsafe { Local::from_raw(v8__WasmMemoryObject__Buffer(self)) }.unwrap() } } @@ -190,14 +191,14 @@ impl WasmMemoryObject { pub(crate) fn trampoline() -> unsafe extern "C" fn(*const FunctionCallbackInfo) where - F: UnitType + Fn(&mut HandleScope, Local, WasmStreaming), + F: UnitType + Fn(&mut PinScope, Local, WasmStreaming), { unsafe extern "C" fn c_fn(info: *const FunctionCallbackInfo) where - F: UnitType + Fn(&mut HandleScope, Local, WasmStreaming), + F: UnitType + Fn(&mut PinScope, Local, WasmStreaming), { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; + callback_scope!(unsafe scope, info); let args = FunctionCallbackArguments::from_function_callback_info(info); let data = args.data(); let zero = null_mut(); @@ -213,7 +214,7 @@ where unsafe extern "C" { fn v8__WasmStreaming__Unpack( - isolate: *mut Isolate, + isolate: *mut RealIsolate, value: *const Value, that: *mut WasmStreamingSharedPtr, // Out parameter. ); @@ -235,14 +236,14 @@ unsafe extern "C" { ); fn v8__WasmModuleObject__FromCompiledModule( - isolate: *mut Isolate, + isolate: *mut RealIsolate, compiled_module: *const InternalCompiledWasmModule, ) -> *const WasmModuleObject; fn v8__WasmModuleObject__GetCompiledModule( this: *const WasmModuleObject, ) -> *mut InternalCompiledWasmModule; fn v8__WasmModuleObject__Compile( - isolate: *mut Isolate, + isolate: *mut RealIsolate, wire_bytes_data: *const u8, length: usize, ) -> *mut WasmModuleObject; diff --git a/tests/compile_fail/boxed_local.rs b/tests/compile_fail/boxed_local.rs index 765b5d8e4a..a8a06266bd 100644 --- a/tests/compile_fail/boxed_local.rs +++ b/tests/compile_fail/boxed_local.rs @@ -1,12 +1,16 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); + let scope1 = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope1 = scope1.init(); let _boxed_local = { - let mut scope2 = v8::HandleScope::new(&mut scope1); - let mut scope3 = v8::HandleScope::new(&mut scope2); + let scope = pin!(v8::HandleScope::new(&mut scope1)); + let mut scope = scope.init(); + let scope3 = pin!(v8::HandleScope::new(&mut scope)); + let mut scope3 = scope3.init(); Box::new(v8::Integer::new(&mut scope3, 123)) }; } diff --git a/tests/compile_fail/boxed_local.stderr b/tests/compile_fail/boxed_local.stderr index 6eeef3de9f..a4ce372e15 100644 --- a/tests/compile_fail/boxed_local.stderr +++ b/tests/compile_fail/boxed_local.stderr @@ -1,12 +1,42 @@ -error[E0597]: `scope2` does not live long enough - --> tests/compile_fail/boxed_local.rs:9:43 +error[E0597]: `scope` does not live long enough + --> tests/compile_fail/boxed_local.rs:12:44 | -7 | let _boxed_local = { +9 | let _boxed_local = { | ------------ borrow later stored here -8 | let mut scope2 = v8::HandleScope::new(&mut scope1); - | ---------- binding `scope2` declared here -9 | let mut scope3 = v8::HandleScope::new(&mut scope2); - | ^^^^^^^^^^^ borrowed value does not live long enough -10 | Box::new(v8::Integer::new(&mut scope3, 123)) -11 | }; - | - `scope2` dropped here while still borrowed +10 | let scope = pin!(v8::HandleScope::new(&mut scope1)); +11 | let mut scope = scope.init(); + | --------- binding `scope` declared here +12 | let scope3 = pin!(v8::HandleScope::new(&mut scope)); + | ^^^^^^^^^^ borrowed value does not live long enough +... +15 | }; + | - `scope` dropped here while still borrowed + +error[E0716]: temporary value dropped while borrowed + --> tests/compile_fail/boxed_local.rs:12:18 + | +9 | let _boxed_local = { + | ------------ borrow later stored here +... +12 | let scope3 = pin!(v8::HandleScope::new(&mut scope)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +... +15 | }; + | - temporary value is freed at the end of this statement + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/compile_fail/boxed_local.rs:10:17 + | +9 | let _boxed_local = { + | ------------ borrow later stored here +10 | let scope = pin!(v8::HandleScope::new(&mut scope1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +... +15 | }; + | - temporary value is freed at the end of this statement + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile_fail/drop_scope_before_local.rs b/tests/compile_fail/drop_scope_before_local.rs new file mode 100644 index 0000000000..df5077a038 --- /dev/null +++ b/tests/compile_fail/drop_scope_before_local.rs @@ -0,0 +1,17 @@ +// Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; + +pub fn main() { + let mut isolate = v8::Isolate::new(mock()); + let mut scope_pinned = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope_pinned.as_mut().init(); + + let local = v8::Integer::new(&mut scope, 123); + drop(scope_pinned); + + local.is_int32(); +} + +fn mock() -> T { + unimplemented!() +} diff --git a/tests/compile_fail/drop_scope_before_local.stderr b/tests/compile_fail/drop_scope_before_local.stderr new file mode 100644 index 0000000000..df7d317a76 --- /dev/null +++ b/tests/compile_fail/drop_scope_before_local.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `scope_pinned` because it is borrowed + --> tests/compile_fail/drop_scope_before_local.rs:10:8 + | +6 | let mut scope_pinned = pin!(v8::HandleScope::new(&mut isolate)); + | ---------------- binding `scope_pinned` declared here +7 | let mut scope = scope_pinned.as_mut().init(); + | ------------ borrow of `scope_pinned` occurs here +... +10 | drop(scope_pinned); + | ^^^^^^^^^^^^ move out of `scope_pinned` occurs here +11 | +12 | local.is_int32(); + | ----- borrow later used here diff --git a/tests/compile_fail/handle_scope_escape_lifetime.rs b/tests/compile_fail/handle_scope_escape_lifetime.rs index 6dfb2fa91f..f53eeb2693 100644 --- a/tests/compile_fail/handle_scope_escape_lifetime.rs +++ b/tests/compile_fail/handle_scope_escape_lifetime.rs @@ -1,13 +1,20 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); + let scope1 = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope1 = scope1.init(); let _local = { - let mut scope2 = v8::HandleScope::new(&mut scope1); - let mut scope3 = v8::HandleScope::new(&mut scope2); - let mut scope4 = v8::EscapableHandleScope::new(&mut scope3); + let scope = pin!(v8::HandleScope::new(&mut scope1)); + let mut scope = scope.init(); + let scope3 = pin!(v8::HandleScope::new(&mut scope)); + let mut scope3 = scope3.init(); + let context = v8::Context::new(&mut scope3, v8::ContextOptions::default()); + let mut scope3 = v8::ContextScope::new(&mut scope3, context); + let scope4 = pin!(v8::EscapableHandleScope::new(&mut scope3)); + let mut scope4 = scope4.init(); let value = v8::Integer::new(&mut scope4, 42); scope4.escape(value) }; diff --git a/tests/compile_fail/handle_scope_escape_lifetime.stderr b/tests/compile_fail/handle_scope_escape_lifetime.stderr index fccbc2076a..dfbc8a644c 100644 --- a/tests/compile_fail/handle_scope_escape_lifetime.stderr +++ b/tests/compile_fail/handle_scope_escape_lifetime.stderr @@ -1,12 +1,42 @@ -error[E0597]: `scope2` does not live long enough - --> tests/compile_fail/handle_scope_escape_lifetime.rs:9:43 +error[E0597]: `scope` does not live long enough + --> tests/compile_fail/handle_scope_escape_lifetime.rs:12:44 | -7 | let _local = { +9 | let _local = { | ------ borrow later stored here -8 | let mut scope2 = v8::HandleScope::new(&mut scope1); - | ---------- binding `scope2` declared here -9 | let mut scope3 = v8::HandleScope::new(&mut scope2); - | ^^^^^^^^^^^ borrowed value does not live long enough +10 | let scope = pin!(v8::HandleScope::new(&mut scope1)); +11 | let mut scope = scope.init(); + | --------- binding `scope` declared here +12 | let scope3 = pin!(v8::HandleScope::new(&mut scope)); + | ^^^^^^^^^^ borrowed value does not live long enough ... -13 | }; - | - `scope2` dropped here while still borrowed +20 | }; + | - `scope` dropped here while still borrowed + +error[E0716]: temporary value dropped while borrowed + --> tests/compile_fail/handle_scope_escape_lifetime.rs:12:18 + | +9 | let _local = { + | ------ borrow later stored here +... +12 | let scope3 = pin!(v8::HandleScope::new(&mut scope)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +... +20 | }; + | - temporary value is freed at the end of this statement + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> tests/compile_fail/handle_scope_escape_lifetime.rs:10:17 + | +9 | let _local = { + | ------ borrow later stored here +10 | let scope = pin!(v8::HandleScope::new(&mut scope1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use +... +20 | }; + | - temporary value is freed at the end of this statement + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile_fail/handle_scope_escape_to_nowhere.stderr b/tests/compile_fail/handle_scope_escape_to_nowhere.stderr index 3800513e21..b0b7f33651 100644 --- a/tests/compile_fail/handle_scope_escape_to_nowhere.stderr +++ b/tests/compile_fail/handle_scope_escape_to_nowhere.stderr @@ -1,36 +1,28 @@ -error[E0277]: the trait bound `OwnedIsolate: v8::scope::param::NewEscapableHandleScope<'_, '_>` is not satisfied +error[E0277]: the trait bound `OwnedIsolate: v8::scope::NewEscapableHandleScope<'_>` is not satisfied --> tests/compile_fail/handle_scope_escape_to_nowhere.rs:5:50 | 5 | let mut _scope = v8::EscapableHandleScope::new(&mut isolate); - | ----------------------------- ^^^^^^^^^^^^ the trait `v8::scope::param::NewEscapableHandleScope<'_, '_>` is not implemented for `OwnedIsolate` + | ----------------------------- ^^^^^^^^^^^^ the trait `v8::scope::NewEscapableHandleScope<'_>` is not implemented for `OwnedIsolate` | | | required by a bound introduced by this call | - = help: the following other types implement trait `v8::scope::param::NewEscapableHandleScope<'s, 'e>`: - `AllowJavascriptExecutionScope<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` - `CallbackScope<'p, C>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'p>` - `ContextScope<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` - `DisallowJavascriptExecutionScope<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` - `EscapableHandleScope<'p, 'e, C>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'p>` - `HandleScope<'p, C>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'p>` - `TryCatch<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` -note: required by a bound in `EscapableHandleScope::<'s, 'e>::new` + = help: the following other types implement trait `v8::scope::NewEscapableHandleScope<'s>`: + `ContextScope<'_, 'obj, HandleScope<'_, C>>` implements `v8::scope::NewEscapableHandleScope<'borrow>` + `PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>>` implements `v8::scope::NewEscapableHandleScope<'borrow>` + `PinnedRef<'obj, HandleScope<'_, C>>` implements `v8::scope::NewEscapableHandleScope<'s>` +note: required by a bound in `EscapableHandleScope::<'s, 'esc>::new` --> src/scope.rs | - | pub fn new>( - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EscapableHandleScope::<'s, 'e>::new` + | pub fn new>( + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EscapableHandleScope::<'s, 'esc>::new` -error[E0277]: the trait bound `OwnedIsolate: v8::scope::param::NewEscapableHandleScope<'_, '_>` is not satisfied +error[E0277]: the trait bound `OwnedIsolate: v8::scope::NewEscapableHandleScope<'_>` is not satisfied --> tests/compile_fail/handle_scope_escape_to_nowhere.rs:5:20 | 5 | let mut _scope = v8::EscapableHandleScope::new(&mut isolate); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `v8::scope::param::NewEscapableHandleScope<'_, '_>` is not implemented for `OwnedIsolate` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `v8::scope::NewEscapableHandleScope<'_>` is not implemented for `OwnedIsolate` | - = help: the following other types implement trait `v8::scope::param::NewEscapableHandleScope<'s, 'e>`: - `AllowJavascriptExecutionScope<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` - `CallbackScope<'p, C>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'p>` - `ContextScope<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` - `DisallowJavascriptExecutionScope<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` - `EscapableHandleScope<'p, 'e, C>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'p>` - `HandleScope<'p, C>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'p>` - `TryCatch<'p, P>` implements `v8::scope::param::NewEscapableHandleScope<'s, 'e>` + = help: the following other types implement trait `v8::scope::NewEscapableHandleScope<'s>`: + `ContextScope<'_, 'obj, HandleScope<'_, C>>` implements `v8::scope::NewEscapableHandleScope<'borrow>` + `PinnedRef<'_, EscapableHandleScope<'s, 'esc, C>>` implements `v8::scope::NewEscapableHandleScope<'borrow>` + `PinnedRef<'obj, HandleScope<'_, C>>` implements `v8::scope::NewEscapableHandleScope<'s>` diff --git a/tests/compile_fail/handle_scope_lifetime_1.rs b/tests/compile_fail/handle_scope_lifetime_1.rs index 3b428f6195..27f6c188e3 100644 --- a/tests/compile_fail/handle_scope_lifetime_1.rs +++ b/tests/compile_fail/handle_scope_lifetime_1.rs @@ -1,9 +1,13 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); - let mut _scope2 = v8::EscapableHandleScope::new(&mut scope1); + let scope1 = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope1 = scope1.init(); + let context = v8::Context::new(&mut scope1, v8::ContextOptions::default()); + let mut context_scope = v8::ContextScope::new(&mut scope1, context); + let mut _scope2 = v8::EscapableHandleScope::new(&mut context_scope); let _local = v8::Integer::new(&mut scope1, 123); } diff --git a/tests/compile_fail/handle_scope_lifetime_1.stderr b/tests/compile_fail/handle_scope_lifetime_1.stderr index a226a9fd83..e1c582da80 100644 --- a/tests/compile_fail/handle_scope_lifetime_1.stderr +++ b/tests/compile_fail/handle_scope_lifetime_1.stderr @@ -1,9 +1,10 @@ error[E0499]: cannot borrow `scope1` as mutable more than once at a time - --> $DIR/handle_scope_lifetime_1.rs:7:33 - | -6 | let mut _scope2 = v8::EscapableHandleScope::new(&mut scope1); - | ----------- first mutable borrow occurs here -7 | let _local = v8::Integer::new(&mut scope1, 123); - | ^^^^^^^^^^^ second mutable borrow occurs here -8 | } - | - first borrow might be used here, when `_scope2` is dropped and runs the `Drop` code for type `EscapableHandleScope` + --> tests/compile_fail/handle_scope_lifetime_1.rs:11:33 + | +9 | let mut context_scope = v8::ContextScope::new(&mut scope1, context); + | ----------- first mutable borrow occurs here +10 | let mut _scope2 = v8::EscapableHandleScope::new(&mut context_scope); +11 | let _local = v8::Integer::new(&mut scope1, 123); + | ^^^^^^^^^^^ second mutable borrow occurs here +12 | } + | - first borrow might be used here, when `context_scope` is dropped and runs the `Drop` code for type `ContextScope` diff --git a/tests/compile_fail/handle_scope_lifetime_2.rs b/tests/compile_fail/handle_scope_lifetime_2.rs index f77d59406a..4029eb1144 100644 --- a/tests/compile_fail/handle_scope_lifetime_2.rs +++ b/tests/compile_fail/handle_scope_lifetime_2.rs @@ -1,11 +1,16 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); - let mut scope2 = v8::EscapableHandleScope::new(&mut scope1); + let scope1 = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope1 = scope1.init(); + let context = v8::Context::new(&mut scope1, v8::ContextOptions::default()); + let mut context_scope = v8::ContextScope::new(&mut scope1, context); + let scope = pin!(v8::EscapableHandleScope::new(&mut context_scope)); + let mut scope = scope.init(); let _local1 = v8::Integer::new(&mut scope1, 123); - let _local2 = v8::Integer::new(&mut scope2, 123); + let _local2 = v8::Integer::new(&mut scope, 123); } fn mock() -> T { diff --git a/tests/compile_fail/handle_scope_lifetime_2.stderr b/tests/compile_fail/handle_scope_lifetime_2.stderr index f5af542ec2..54cd63a286 100644 --- a/tests/compile_fail/handle_scope_lifetime_2.stderr +++ b/tests/compile_fail/handle_scope_lifetime_2.stderr @@ -1,9 +1,11 @@ error[E0499]: cannot borrow `scope1` as mutable more than once at a time - --> $DIR/handle_scope_lifetime_2.rs:7:34 - | -6 | let mut scope2 = v8::EscapableHandleScope::new(&mut scope1); - | ----------- first mutable borrow occurs here -7 | let _local1 = v8::Integer::new(&mut scope1, 123); - | ^^^^^^^^^^^ second mutable borrow occurs here -8 | let _local2 = v8::Integer::new(&mut scope2, 123); - | ----------- first borrow later used here + --> tests/compile_fail/handle_scope_lifetime_2.rs:12:34 + | +9 | let mut context_scope = v8::ContextScope::new(&mut scope1, context); + | ----------- first mutable borrow occurs here +... +12 | let _local1 = v8::Integer::new(&mut scope1, 123); + | ^^^^^^^^^^^ second mutable borrow occurs here +13 | let _local2 = v8::Integer::new(&mut scope, 123); +14 | } + | - first borrow might be used here, when `context_scope` is dropped and runs the `Drop` code for type `ContextScope` diff --git a/tests/compile_fail/handle_scope_lifetime_3.rs b/tests/compile_fail/handle_scope_lifetime_3.rs index b0345e6581..bc165848fe 100644 --- a/tests/compile_fail/handle_scope_lifetime_3.rs +++ b/tests/compile_fail/handle_scope_lifetime_3.rs @@ -1,10 +1,15 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; + pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); + let scope1 = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope1 = scope1.init(); + let context = v8::Context::new(&mut scope1, v8::ContextOptions::default()); + let mut context_scope = v8::ContextScope::new(&mut scope1, context); let _local = { - let mut _scope2 = v8::EscapableHandleScope::new(&mut scope1); + let mut _scope2 = v8::EscapableHandleScope::new(&mut context_scope); v8::Integer::new(&mut scope1, 123) }; } diff --git a/tests/compile_fail/handle_scope_lifetime_3.stderr b/tests/compile_fail/handle_scope_lifetime_3.stderr index 4ef3cc36df..e60994c5e9 100644 --- a/tests/compile_fail/handle_scope_lifetime_3.stderr +++ b/tests/compile_fail/handle_scope_lifetime_3.stderr @@ -1,9 +1,11 @@ error[E0499]: cannot borrow `scope1` as mutable more than once at a time - --> $DIR/handle_scope_lifetime_3.rs:8:22 - | -7 | let mut _scope2 = v8::EscapableHandleScope::new(&mut scope1); - | ----------- first mutable borrow occurs here -8 | v8::Integer::new(&mut scope1, 123) - | ^^^^^^^^^^^ second mutable borrow occurs here -9 | }; - | - first borrow might be used here, when `_scope2` is dropped and runs the `Drop` code for type `EscapableHandleScope` + --> tests/compile_fail/handle_scope_lifetime_3.rs:13:22 + | +9 | let mut context_scope = v8::ContextScope::new(&mut scope1, context); + | ----------- first mutable borrow occurs here +... +13 | v8::Integer::new(&mut scope1, 123) + | ^^^^^^^^^^^ second mutable borrow occurs here +14 | }; +15 | } + | - first borrow might be used here, when `context_scope` is dropped and runs the `Drop` code for type `ContextScope` diff --git a/tests/compile_fail/handle_scope_lifetime_4.rs b/tests/compile_fail/handle_scope_lifetime_4.rs index 83c8d17337..f535373c9f 100644 --- a/tests/compile_fail/handle_scope_lifetime_4.rs +++ b/tests/compile_fail/handle_scope_lifetime_4.rs @@ -1,12 +1,17 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. +use std::pin::pin; pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); + let scope1 = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope1 = scope1.init(); + + let context = v8::Context::new(&mut scope1, v8::ContextOptions::default()); + let mut context_scope = v8::ContextScope::new(&mut scope1, context); let mut _scope3 = { - let mut scope2 = v8::HandleScope::new(&mut scope1); - v8::EscapableHandleScope::new(&mut scope2) + v8::scope!(scope, &mut context_scope); + v8::EscapableHandleScope::new(scope) }; } diff --git a/tests/compile_fail/handle_scope_lifetime_4.stderr b/tests/compile_fail/handle_scope_lifetime_4.stderr index 6728153a27..080f8a3df2 100644 --- a/tests/compile_fail/handle_scope_lifetime_4.stderr +++ b/tests/compile_fail/handle_scope_lifetime_4.stderr @@ -1,11 +1,31 @@ -error[E0597]: `scope2` does not live long enough - --> tests/compile_fail/handle_scope_lifetime_4.rs:9:35 +error[E0597]: `scope` does not live long enough + --> tests/compile_fail/handle_scope_lifetime_4.rs:13:5 | -7 | let mut _scope3 = { +12 | let mut _scope3 = { | ----------- borrow later stored here -8 | let mut scope2 = v8::HandleScope::new(&mut scope1); - | ---------- binding `scope2` declared here -9 | v8::EscapableHandleScope::new(&mut scope2) - | ^^^^^^^^^^^ borrowed value does not live long enough -10 | }; - | - `scope2` dropped here while still borrowed +13 | v8::scope!(scope, &mut context_scope); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope` declared here +14 | v8::EscapableHandleScope::new(scope) +15 | }; + | - `scope` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0597]: `scope` does not live long enough + --> tests/compile_fail/handle_scope_lifetime_4.rs:13:5 + | +12 | let mut _scope3 = { + | ----------- borrow later stored here +13 | v8::scope!(scope, &mut context_scope); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope` declared here +14 | v8::EscapableHandleScope::new(scope) +15 | }; + | - `scope` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile_fail/local_outlive_handle_scope.rs b/tests/compile_fail/local_outlive_handle_scope.rs new file mode 100644 index 0000000000..9a6e2eceb4 --- /dev/null +++ b/tests/compile_fail/local_outlive_handle_scope.rs @@ -0,0 +1,10 @@ +fn main() { + let isolate = &mut v8::Isolate::new(Default::default()); + v8::scope!(let scope1, isolate); + + let _local = { + v8::scope!(let scope, scope1); + + v8::Integer::new(scope, 123) + }; +} diff --git a/tests/compile_fail/local_outlive_handle_scope.stderr b/tests/compile_fail/local_outlive_handle_scope.stderr new file mode 100644 index 0000000000..fbcc99cd72 --- /dev/null +++ b/tests/compile_fail/local_outlive_handle_scope.stderr @@ -0,0 +1,15 @@ +error[E0597]: `scope` does not live long enough + --> tests/compile_fail/local_outlive_handle_scope.rs:6:5 + | +5 | let _local = { + | ------ borrow later stored here +6 | v8::scope!(let scope, scope1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope` declared here +... +9 | }; + | - `scope` dropped here while still borrowed + | + = note: this error originates in the macro `$crate::scope` which comes from the expansion of the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile_fail/object_without_context_scope.rs b/tests/compile_fail/object_without_context_scope.rs index 1cbc43494e..2c20f164c5 100644 --- a/tests/compile_fail/object_without_context_scope.rs +++ b/tests/compile_fail/object_without_context_scope.rs @@ -2,8 +2,8 @@ pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope = v8::HandleScope::new(&mut isolate); - let _object = v8::Object::new(&mut scope); + v8::scope!(scope, &mut isolate); + let _object = v8::Object::new(&*scope); } fn mock() -> T { diff --git a/tests/compile_fail/object_without_context_scope.stderr b/tests/compile_fail/object_without_context_scope.stderr index f4a4f0ff6e..c8093300ac 100644 --- a/tests/compile_fail/object_without_context_scope.stderr +++ b/tests/compile_fail/object_without_context_scope.stderr @@ -1,15 +1,15 @@ error[E0308]: mismatched types --> tests/compile_fail/object_without_context_scope.rs:6:33 | -6 | let _object = v8::Object::new(&mut scope); - | --------------- ^^^^^^^^^^ expected `&mut HandleScope<'_>`, found `&mut HandleScope<'_, ()>` +6 | let _object = v8::Object::new(&*scope); + | --------------- ^^^^^^^ expected `&PinnedRef<'_, HandleScope<'_>>`, found `&PinnedRef<'_, HandleScope<'_, ()>>` | | | arguments to this function are incorrect | - = note: expected mutable reference `&mut HandleScope<'_, v8::Context>` - found mutable reference `&mut HandleScope<'_, ()>` + = note: expected reference `&PinnedRef<'_, HandleScope<'_, v8::Context>>` + found reference `&PinnedRef<'_, HandleScope<'_, ()>>` note: associated function defined here --> src/object.rs | - | pub fn new<'s>(scope: &mut HandleScope<'s>) -> Local<'s, Object> { + | pub fn new<'s>(scope: &PinScope<'s, '_>) -> Local<'s, Object> { | ^^^ diff --git a/tests/compile_fail/try_catch_exception_lifetime.rs b/tests/compile_fail/try_catch_exception_lifetime.rs index eec182a3c2..6e575bc3a7 100644 --- a/tests/compile_fail/try_catch_exception_lifetime.rs +++ b/tests/compile_fail/try_catch_exception_lifetime.rs @@ -2,14 +2,15 @@ pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope1, Default::default()); - let mut scope2 = v8::ContextScope::new(&mut scope1, context); + v8::scope!(scope1, &mut isolate); + let context = v8::Context::new(scope1, Default::default()); + let mut scope = v8::ContextScope::new(scope1, context); let _exception = { - let mut scope3 = v8::HandleScope::new(&mut scope2); - let mut scope4 = v8::HandleScope::new(&mut scope3); - let mut try_catch = v8::TryCatch::new(&mut scope4); + v8::scope!(scope3, &mut scope); + v8::scope!(scope4, scope3); + let try_catch = std::pin::pin!(v8::TryCatch::new(scope4)); + let try_catch = try_catch.init(); try_catch.exception().unwrap() }; } diff --git a/tests/compile_fail/try_catch_exception_lifetime.stderr b/tests/compile_fail/try_catch_exception_lifetime.stderr index 6e81835a34..3abae0a40d 100644 --- a/tests/compile_fail/try_catch_exception_lifetime.stderr +++ b/tests/compile_fail/try_catch_exception_lifetime.stderr @@ -1,12 +1,48 @@ +error[E0597]: `scope4` does not live long enough + --> tests/compile_fail/try_catch_exception_lifetime.rs:11:5 + | +9 | let _exception = { + | ---------- borrow later stored here +10 | v8::scope!(scope3, &mut scope); +11 | v8::scope!(scope4, scope3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope4` declared here +... +15 | }; + | - `scope4` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0597]: `scope3` does not live long enough - --> tests/compile_fail/try_catch_exception_lifetime.rs:11:43 + --> tests/compile_fail/try_catch_exception_lifetime.rs:10:5 | 9 | let _exception = { | ---------- borrow later stored here -10 | let mut scope3 = v8::HandleScope::new(&mut scope2); - | ---------- binding `scope3` declared here -11 | let mut scope4 = v8::HandleScope::new(&mut scope3); - | ^^^^^^^^^^^ borrowed value does not live long enough +10 | v8::scope!(scope3, &mut scope); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope3` declared here ... -14 | }; +15 | }; | - `scope3` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0597]: `scope3` does not live long enough + --> tests/compile_fail/try_catch_exception_lifetime.rs:10:5 + | +9 | let _exception = { + | ---------- borrow later stored here +10 | v8::scope!(scope3, &mut scope); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope3` declared here +... +15 | }; + | - `scope3` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/compile_fail/try_catch_message_lifetime.rs b/tests/compile_fail/try_catch_message_lifetime.rs index cca0229fb8..8ee204d76b 100644 --- a/tests/compile_fail/try_catch_message_lifetime.rs +++ b/tests/compile_fail/try_catch_message_lifetime.rs @@ -2,14 +2,15 @@ pub fn main() { let mut isolate = v8::Isolate::new(mock()); - let mut scope1 = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope1, Default::default()); - let mut scope2 = v8::ContextScope::new(&mut scope1, context); + v8::scope!(scope1, &mut isolate); + let context = v8::Context::new(scope1, Default::default()); + let mut scope = v8::ContextScope::new(scope1, context); let _message = { - let mut scope3 = v8::HandleScope::new(&mut scope2); - let mut scope4 = v8::HandleScope::new(&mut scope3); - let mut try_catch = v8::TryCatch::new(&mut scope4); + v8::scope!(scope3, &mut scope); + v8::scope!(scope4, scope3); + let try_catch = std::pin::pin!(v8::TryCatch::new(scope4)); + let try_catch = try_catch.init(); try_catch.message().unwrap() }; } diff --git a/tests/compile_fail/try_catch_message_lifetime.stderr b/tests/compile_fail/try_catch_message_lifetime.stderr index 34964012d8..6a9cb41271 100644 --- a/tests/compile_fail/try_catch_message_lifetime.stderr +++ b/tests/compile_fail/try_catch_message_lifetime.stderr @@ -1,12 +1,48 @@ +error[E0597]: `scope4` does not live long enough + --> tests/compile_fail/try_catch_message_lifetime.rs:11:5 + | +9 | let _message = { + | -------- borrow later stored here +10 | v8::scope!(scope3, &mut scope); +11 | v8::scope!(scope4, scope3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope4` declared here +... +15 | }; + | - `scope4` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0597]: `scope3` does not live long enough - --> tests/compile_fail/try_catch_message_lifetime.rs:11:43 + --> tests/compile_fail/try_catch_message_lifetime.rs:10:5 | 9 | let _message = { | -------- borrow later stored here -10 | let mut scope3 = v8::HandleScope::new(&mut scope2); - | ---------- binding `scope3` declared here -11 | let mut scope4 = v8::HandleScope::new(&mut scope3); - | ^^^^^^^^^^^ borrowed value does not live long enough +10 | v8::scope!(scope3, &mut scope); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope3` declared here ... -14 | }; +15 | }; | - `scope3` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0597]: `scope3` does not live long enough + --> tests/compile_fail/try_catch_message_lifetime.rs:10:5 + | +9 | let _message = { + | -------- borrow later stored here +10 | v8::scope!(scope3, &mut scope); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | borrowed value does not live long enough + | binding `scope3` declared here +... +15 | }; + | - `scope3` dropped here while still borrowed + | + = note: this error originates in the macro `v8::scope` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/slots.rs b/tests/slots.rs index a84848d7e9..9b7e5ea3d0 100644 --- a/tests/slots.rs +++ b/tests/slots.rs @@ -5,6 +5,7 @@ use std::ops::Deref; use std::ops::DerefMut; +use std::pin::pin; use std::rc::Rc; use std::sync::Once; use std::sync::atomic::AtomicUsize; @@ -45,7 +46,8 @@ impl CoreIsolate { // Returns false if there was an error. fn execute(&mut self, code: &str) -> bool { - let scope = &mut v8::HandleScope::new(&mut self.0); + let scope = pin!(v8::HandleScope::new(&mut self.0)); + let scope = &mut scope.init(); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new(scope, code).unwrap(); @@ -254,7 +256,7 @@ fn slots_auto_boxing() { fn context_slots() { setup(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); assert!(context.set_slot(Rc::new(TestState(0))).is_none()); @@ -281,7 +283,8 @@ fn dropped_context_slots() { let mut isolate = CoreIsolate::new(Default::default()); let dropped = Rc::new(Cell::new(false)); { - let scope = &mut v8::HandleScope::new(isolate.deref_mut()); + let scope = pin!(v8::HandleScope::new(isolate.deref_mut())); + let scope = &mut scope.init(); let context = v8::Context::new(scope, Default::default()); context.set_slot(Rc::new(DropMarker(dropped.clone()))); @@ -307,7 +310,8 @@ fn dropped_context_slots_on_kept_context() { let dropped = Rc::new(Cell::new(false)); let _global_context; { - let scope = &mut v8::HandleScope::new(isolate.deref_mut()); + let scope = pin!(v8::HandleScope::new(isolate.deref_mut())); + let scope = &mut scope.init(); let context = v8::Context::new(scope, Default::default()); context.set_slot(Rc::new(DropMarker(dropped.clone()))); @@ -326,7 +330,8 @@ fn clear_all_context_slots() { let mut snapshot_creator = v8::Isolate::snapshot_creator(None, None); { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + let scope = pin!(v8::HandleScope::new(&mut snapshot_creator)); + let scope = &mut scope.init(); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); diff --git a/tests/test_api.rs b/tests/test_api.rs index 7302f47347..959bdbbc27 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -10,6 +10,7 @@ use std::ffi::c_void; use std::hash::Hash; use std::mem::MaybeUninit; use std::os::raw::c_char; +use std::pin::pin; use std::ptr::addr_of_mut; use std::rc::Rc; use std::sync::Arc; @@ -81,9 +82,10 @@ fn handle_scope_nested() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope1 = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope1, isolate); + { - let _scope2 = &mut v8::HandleScope::new(scope1); + v8::scope!(let _scope2, scope1); } } } @@ -94,12 +96,14 @@ fn handle_scope_numbers() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope1 = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope1, isolate); + let l1 = v8::Integer::new(scope1, -123); let l2 = v8::Integer::new_from_unsigned(scope1, 456); { - let scope2 = &mut v8::HandleScope::new(scope1); - let l3 = v8::Number::new(scope2, 78.9); + v8::scope!(let scope, scope1); + + let l3 = v8::Number::new(scope, 78.9); let l4 = l1.cast::(); let l5 = l2.cast::(); assert_eq!(l1.value(), -123); @@ -113,21 +117,6 @@ fn handle_scope_numbers() { } } -#[test] -fn handle_scope_non_lexical_lifetime() { - let _setup_guard = setup::parallel_test(); - let isolate = &mut v8::Isolate::new(Default::default()); - let scope1 = &mut v8::HandleScope::new(isolate); - - // Despite `local` living slightly longer than `scope2`, this test should - // not crash. - let local = { - let scope2 = &mut v8::HandleScope::new(scope1); - v8::Integer::new(scope2, 123) - }; - assert_eq!(local.value(), 123); -} - #[test] fn global_handles() { let _setup_guard = setup::parallel_test(); @@ -139,7 +128,8 @@ fn global_handles() { let mut g5: Option> = None; let g6; { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let l1 = v8::String::new(scope, "bla").unwrap(); let l2 = v8::Integer::new(scope, 123); g1 = v8::Global::new(scope, l1); @@ -151,7 +141,8 @@ fn global_handles() { g6 = g1.clone(); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + assert_eq!(g1.open(scope).to_rust_string_lossy(scope), "bla"); assert_eq!(g2.as_ref().unwrap().open(scope).value(), 123); assert_eq!(g3.open(scope).value(), 123); @@ -176,12 +167,14 @@ fn global_from_into_raw() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let (raw, weak) = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let global = v8::Global::new(scope, local); @@ -208,7 +201,8 @@ fn global_from_into_raw() { fn local_handle_deref() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let key = v8::String::new(scope, "key").unwrap(); @@ -230,7 +224,7 @@ fn global_handle_drop() { let _g1: v8::Global; let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let l1 = v8::String::new(scope, "foo").unwrap(); _g1 = v8::Global::new(scope, l1); @@ -246,7 +240,8 @@ fn test_string() { let isolate = &mut v8::Isolate::new(Default::default()); { // Ensure that a Latin-1 string correctly round-trips - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let reference = "\u{00a0}"; assert_eq!(2, reference.len()); let local = v8::String::new(scope, reference).unwrap(); @@ -260,7 +255,8 @@ fn test_string() { assert_eq!(2, local.to_rust_cow_lossy(scope, &mut buf).len()); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let reference = "Hello 🦕 world!"; let local = v8::String::new(scope, reference).unwrap(); assert_eq!(15, local.length()); @@ -286,14 +282,16 @@ fn test_string() { ); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let local = v8::String::empty(scope); assert_eq!(0, local.length()); assert_eq!(0, local.utf8_length(scope)); assert_eq!("", local.to_rust_string_lossy(scope)); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let local = v8::String::new_from_utf8(scope, b"", v8::NewStringType::Normal).unwrap(); assert_eq!(0, local.length()); @@ -301,7 +299,8 @@ fn test_string() { assert_eq!("", local.to_rust_string_lossy(scope)); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let local = v8::String::new_from_one_byte(scope, b"foo", v8::NewStringType::Normal) .unwrap(); @@ -313,7 +312,8 @@ fn test_string() { assert_eq!("foo", local.to_rust_string_lossy(scope)); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let local = v8::String::new_from_two_byte( scope, &[0xD83E, 0xDD95], @@ -325,7 +325,8 @@ fn test_string() { assert_eq!("🦕", local.to_rust_string_lossy(scope)); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let mut buffer = Vec::with_capacity(v8::String::MAX_LENGTH); for _ in 0..buffer.capacity() / 4 { // U+10348 in UTF-8 @@ -358,7 +359,8 @@ fn test_string() { assert!(none.is_none()); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let invalid_sequence_identifier = v8::String::new_from_utf8( scope, &[0xa0, 0xa1], @@ -432,7 +434,8 @@ fn test_string() { assert_eq!(invalid_4_octet_sequence.length(), 6); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let s = "Lorem ipsum dolor sit amet. Qui inventore debitis et voluptas cupiditate qui recusandae molestias et ullam possimus"; let one_byte = v8::String::new_from_one_byte( scope, @@ -478,36 +481,49 @@ fn escapable_handle_scope() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let handle_scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let handle_scope, isolate); + + let context = v8::Context::new(handle_scope, Default::default()); + let context_scope = &mut v8::ContextScope::new(handle_scope, context); // After dropping EscapableHandleScope, we should be able to // read escaped values. let number = { - let escapable_scope = &mut v8::EscapableHandleScope::new(handle_scope); + let escapable_scope = pin!(v8::EscapableHandleScope::new(context_scope)); + let escapable_scope = &mut escapable_scope.init(); let number = v8::Number::new(escapable_scope, 78.9); escapable_scope.escape(number) }; assert_eq!(number.value(), 78.9); let string = { - let escapable_scope = &mut v8::EscapableHandleScope::new(handle_scope); + let escapable_scope = pin!(v8::EscapableHandleScope::new(context_scope)); + let escapable_scope = &mut escapable_scope.init(); let string = v8::String::new(escapable_scope, "Hello 🦕 world!").unwrap(); escapable_scope.escape(string) }; - assert_eq!("Hello 🦕 world!", string.to_rust_string_lossy(handle_scope)); + assert_eq!( + "Hello 🦕 world!", + string.to_rust_string_lossy(context_scope) + ); let string = { - let escapable_scope = &mut v8::EscapableHandleScope::new(handle_scope); + let escapable_scope = pin!(v8::EscapableHandleScope::new(context_scope)); + let escapable_scope = &mut escapable_scope.init(); let nested_str_val = { let nested_escapable_scope = - &mut v8::EscapableHandleScope::new(escapable_scope); + pin!(v8::EscapableHandleScope::new(escapable_scope)); + let nested_escapable_scope = &mut nested_escapable_scope.init(); let string = v8::String::new(nested_escapable_scope, "Hello 🦕 world!").unwrap(); nested_escapable_scope.escape(string) }; escapable_scope.escape(nested_str_val) }; - assert_eq!("Hello 🦕 world!", string.to_rust_string_lossy(handle_scope)); + assert_eq!( + "Hello 🦕 world!", + string.to_rust_string_lossy(context_scope) + ); } } @@ -517,15 +533,20 @@ fn escapable_handle_scope_can_escape_only_once() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope1 = &mut v8::HandleScope::new(isolate); - let scope2 = &mut v8::EscapableHandleScope::new(scope1); + v8::scope!(let scope1, isolate); + + let context = v8::Context::new(scope1, Default::default()); + let scope1 = &mut v8::ContextScope::new(scope1, context); - let local1 = v8::Integer::new(scope2, -123); - let escaped1 = scope2.escape(local1); + let scope = pin!(v8::EscapableHandleScope::new(scope1)); + let scope = &mut scope.init(); + + let local1 = v8::Integer::new(scope, -123); + let escaped1 = scope.escape(local1); assert!(escaped1 == local1); - let local2 = v8::Integer::new(scope2, 456); - let escaped2 = scope2.escape(local2); + let local2 = v8::Integer::new(scope, 456); + let escaped2 = scope.escape(local2); assert!(escaped2 == local2); } @@ -534,7 +555,8 @@ fn context_scope() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context1 = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context1); @@ -568,14 +590,15 @@ fn microtasks() { isolate.perform_microtask_checkpoint(); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); let function = v8::Function::new( scope, - |_: &mut v8::HandleScope, + |_: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue| { CALL_COUNT.fetch_add(1, Ordering::SeqCst); @@ -628,7 +651,8 @@ fn data_view() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -644,7 +668,8 @@ fn array_buffer() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -805,7 +830,8 @@ fn backing_store_segfault() { array_buffer_allocator.assert_use_count_eq(2); let isolate = &mut v8::Isolate::new(params); array_buffer_allocator.assert_use_count_eq(2); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let ab = v8::ArrayBuffer::new(scope, 10); @@ -844,7 +870,7 @@ fn array_buffer_with_shared_backing_store() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -911,10 +937,11 @@ fn deref_empty_backing_store() { } fn eval<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, code: &str, ) -> Option> { - let scope = &mut v8::EscapableHandleScope::new(scope); + let scope = pin!(v8::EscapableHandleScope::new(scope)); + let scope = &mut scope.init(); let source = v8::String::new(scope, code).unwrap(); let script = v8::Script::compile(scope, source, None).unwrap(); let r = script.run(scope); @@ -925,7 +952,7 @@ fn eval<'s>( fn external() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let ex1_value = 1usize as *mut std::ffi::c_void; let ex1_handle_a = v8::External::new(scope, ex1_value); @@ -986,12 +1013,14 @@ fn try_catch() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); + let mut scope = v8::ContextScope::new(scope, context); { // Error thrown - should be caught. - let tc = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc, &mut scope); + let result = eval(tc, "throw new Error('foo')"); assert!(result.is_none()); assert!(tc.has_caught()); @@ -1005,7 +1034,8 @@ fn try_catch() { }; { // No error thrown. - let tc = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc, &mut scope); + let result = eval(tc, "1 + 1"); assert!(result.is_some()); assert!(!tc.has_caught()); @@ -1016,9 +1046,11 @@ fn try_catch() { }; { // Rethrow and reset. - let tc1 = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc1, &mut scope); + { - let tc2 = &mut v8::TryCatch::new(tc1); + v8::tc_scope!(let tc2, tc1); + eval(tc2, "throw 'bar'"); assert!(tc2.has_caught()); assert!(tc2.rethrow().is_some()); @@ -1036,11 +1068,13 @@ fn try_catch() { fn try_catch_caught_lifetime() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let (caught_exc, caught_msg) = { - let tc = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc, scope); + // Throw exception. let msg = v8::String::new(tc, "DANG!").unwrap(); let exc = v8::Exception::type_error(tc, msg); @@ -1067,11 +1101,13 @@ fn throw_exception() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { - let tc = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc, scope); + let exception = v8::String::new(tc, "boom").unwrap(); tc.throw_exception(exception.into()); assert!(tc.has_caught()); @@ -1143,7 +1179,8 @@ fn terminate_execution() { let (tx, rx) = std::sync::mpsc::channel::(); let handle = isolate.thread_safe_handle(); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -1178,7 +1215,8 @@ fn request_interrupt_small_scripts() { let isolate = &mut v8::Isolate::new(Default::default()); let handle = isolate.thread_safe_handle(); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -1204,12 +1242,14 @@ fn add_message_listener() { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); - extern "C" fn check_message_0( - message: v8::Local, - _exception: v8::Local, + extern "C" fn check_message_0<'s>( + message: v8::Local<'s, v8::Message>, + _exception: v8::Local<'s, v8::Value>, ) { - let scope = &mut unsafe { v8::CallbackScope::new(message) }; - let scope = &mut v8::HandleScope::new(scope); + let scope = pin!(unsafe { v8::CallbackScope::new(message) }); + let scope = &mut scope.init(); + v8::scope!(let scope, scope); + let message_str = message.get(scope); assert_eq!(message_str.to_rust_string_lossy(scope), "Uncaught foo"); assert_eq!(Some(1), message.get_line_number(scope)); @@ -1243,7 +1283,8 @@ fn add_message_listener() { isolate.add_message_listener(check_message_0); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new(scope, "throw 'foo'").unwrap(); @@ -1253,12 +1294,12 @@ fn add_message_listener() { } } -fn unexpected_module_resolve_callback<'a>( - _context: v8::Local<'a, v8::Context>, - _specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, - _referrer: v8::Local<'a, v8::Module>, -) -> Option> { +fn unexpected_module_resolve_callback<'s>( + _context: v8::Local<'s, v8::Context>, + _specifier: v8::Local<'s, v8::String>, + _import_attributes: v8::Local<'s, v8::FixedArray>, + _referrer: v8::Local<'s, v8::Module>, +) -> Option> { unreachable!() } @@ -1275,8 +1316,9 @@ fn set_host_initialize_import_meta_object_callback() { meta: v8::Local, ) { CALL_COUNT.fetch_add(1, Ordering::SeqCst); - let scope = &mut unsafe { v8::CallbackScope::new(context) }; - let scope = &mut v8::HandleScope::new(scope); + v8::callback_scope!(unsafe scope, context); + v8::scope!(let scope, scope); + let key = v8::String::new(scope, "foo").unwrap(); let value = v8::String::new(scope, "bar").unwrap(); meta.create_data_property(scope, key.into(), value.into()); @@ -1284,7 +1326,8 @@ fn set_host_initialize_import_meta_object_callback() { isolate.set_host_initialize_import_meta_object_callback(callback); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let mut source = mock_source( @@ -1308,7 +1351,8 @@ fn script_compile_and_run() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new(scope, "'Hello ' + 13 + 'th planet'").unwrap(); @@ -1325,7 +1369,8 @@ fn script_origin() { let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -1413,7 +1458,8 @@ fn test_primitives() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let null = v8::null(scope); assert!(!null.is_undefined()); assert!(null.is_null()); @@ -1442,7 +1488,8 @@ fn test_primitives() { fn exception() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -1472,14 +1519,15 @@ fn exception() { fn create_message_argument_lifetimes() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { let create_message = v8::Function::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { let message = v8::Exception::create_message(scope, args.get(0)); @@ -1505,7 +1553,8 @@ fn json() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let json_string = v8::String::new(scope, "{\"a\": 1, \"b\": 2}").unwrap(); @@ -1525,7 +1574,8 @@ fn no_internal_field() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let object = v8::Object::new(scope); @@ -1544,7 +1594,8 @@ fn object_template() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let object_templ = v8::ObjectTemplate::new(scope); let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback); let name = v8::String::new(scope, "f").unwrap(); @@ -1608,7 +1659,8 @@ fn object_template_from_function_template() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback); let expected_class_name = v8::String::new(scope, "fortytwo").unwrap(); function_templ.set_class_name(expected_class_name); @@ -1631,7 +1683,8 @@ fn object_template_immutable_proto() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let object_templ = v8::ObjectTemplate::new(scope); object_templ.set_immutable_proto(); let context = v8::Context::new( @@ -1667,7 +1720,7 @@ fn function_template_signature() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let templ0 = v8::FunctionTemplate::new(scope, fortytwo_callback); let signature = v8::Signature::new(scope, templ0); @@ -1677,7 +1730,8 @@ fn function_template_signature() { let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + let global = context.global(scope); let name = v8::String::new(scope, "C").unwrap(); @@ -1706,11 +1760,12 @@ fn function_template_prototype() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback); let prototype_templ = function_templ.prototype_template(scope); @@ -1779,7 +1834,7 @@ fn function_template_intrinsic_data_property() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback); @@ -1826,12 +1881,13 @@ fn function_template_intrinsic_data_property() { fn instance_template_with_internal_field() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); pub fn constructor_callback( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue, ) { @@ -1866,12 +1922,13 @@ fn instance_template_with_internal_field() { fn object_template_set_accessor() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -1892,7 +1949,7 @@ fn object_template_set_accessor() { rv.set(internal_field); }; - let setter = |scope: &mut v8::HandleScope, + let setter = |scope: &mut v8::PinScope, key: v8::Local, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -1911,7 +1968,7 @@ fn object_template_set_accessor() { }; let getter_with_data = - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -1934,7 +1991,7 @@ fn object_template_set_accessor() { }; let setter_with_data = - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, key: v8::Local, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -2027,7 +2084,7 @@ fn object_template_set_accessor() { // Accessor property let getter = v8::FunctionTemplate::new(scope, fortytwo_callback); fn property_setter( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, _: v8::ReturnValue, ) { @@ -2083,12 +2140,13 @@ fn object_template_set_accessor() { fn object_template_set_named_property_handler() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2115,7 +2173,7 @@ fn object_template_set_named_property_handler() { v8::Intercepted::Yes }; - let setter = |scope: &mut v8::HandleScope, + let setter = |scope: &mut v8::PinScope, key: v8::Local, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -2146,7 +2204,7 @@ fn object_template_set_named_property_handler() { v8::Intercepted::Yes }; - let query = |scope: &mut v8::HandleScope, + let query = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2180,7 +2238,7 @@ fn object_template_set_named_property_handler() { v8::Intercepted::Yes }; - let deleter = |scope: &mut v8::HandleScope, + let deleter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2200,7 +2258,7 @@ fn object_template_set_named_property_handler() { v8::Intercepted::Yes }; - let enumerator = |scope: &mut v8::HandleScope, + let enumerator = |scope: &mut v8::PinScope, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { let this = args.this(); @@ -2224,7 +2282,7 @@ fn object_template_set_named_property_handler() { rv.set(result); }; - let definer = |scope: &mut v8::HandleScope, + let definer = |scope: &mut v8::PinScope, key: v8::Local, desc: &v8::PropertyDescriptor, args: v8::PropertyCallbackArguments, @@ -2259,7 +2317,7 @@ fn object_template_set_named_property_handler() { v8::Intercepted::Yes }; - let descriptor = |scope: &mut v8::HandleScope, + let descriptor = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2578,11 +2636,12 @@ fn object_template_set_named_property_handler() { fn object_template_set_indexed_property_handler() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, index: u32, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2603,7 +2662,7 @@ fn object_template_set_indexed_property_handler() { v8::Intercepted::Yes }; - let setter = |_scope: &mut v8::HandleScope, + let setter = |_scope: &mut v8::PinScope, index: u32, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -2623,7 +2682,7 @@ fn object_template_set_indexed_property_handler() { v8::Intercepted::Yes }; - let query = |_scope: &mut v8::HandleScope, + let query = |_scope: &mut v8::PinScope, index: u32, _args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2638,7 +2697,7 @@ fn object_template_set_indexed_property_handler() { v8::Intercepted::Yes }; - let deleter = |_scope: &mut v8::HandleScope, + let deleter = |_scope: &mut v8::PinScope, index: u32, _args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2648,7 +2707,7 @@ fn object_template_set_indexed_property_handler() { v8::Intercepted::Yes }; - let enumerator = |scope: &mut v8::HandleScope, + let enumerator = |scope: &mut v8::PinScope, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { let this = args.this(); @@ -2671,7 +2730,7 @@ fn object_template_set_indexed_property_handler() { rv.set(result); }; - let definer = |_scope: &mut v8::HandleScope, + let definer = |_scope: &mut v8::PinScope, index: u32, desc: &v8::PropertyDescriptor, args: v8::PropertyCallbackArguments, @@ -2694,7 +2753,7 @@ fn object_template_set_indexed_property_handler() { v8::Intercepted::Yes }; - let descriptor = |scope: &mut v8::HandleScope, + let descriptor = |scope: &mut v8::PinScope, index: u32, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -2878,7 +2937,8 @@ fn object() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let null: v8::Local = v8::null(scope).into(); @@ -2964,7 +3024,8 @@ fn map() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -3008,7 +3069,8 @@ fn set() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -3046,7 +3108,8 @@ fn array() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let s1 = v8::String::new(scope, "a").unwrap(); @@ -3090,7 +3153,8 @@ fn create_data_property() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -3121,14 +3185,15 @@ fn create_data_property() { fn object_set_accessor() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -3179,14 +3244,15 @@ fn object_set_accessor() { fn object_set_accessor_with_setter() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -3211,7 +3277,7 @@ fn object_set_accessor_with_setter() { CALL_COUNT.fetch_add(1, Ordering::SeqCst); }; - let setter = |scope: &mut v8::HandleScope, + let setter = |scope: &mut v8::PinScope, key: v8::Local, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -3281,14 +3347,15 @@ fn object_set_accessor_with_setter() { fn object_set_accessor_with_setter_with_property() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -3313,7 +3380,7 @@ fn object_set_accessor_with_setter_with_property() { CALL_COUNT.fetch_add(1, Ordering::SeqCst); }; - let setter = |scope: &mut v8::HandleScope, + let setter = |scope: &mut v8::PinScope, key: v8::Local, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -3384,14 +3451,15 @@ fn object_set_accessor_with_setter_with_property() { fn object_set_accessor_with_data() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); - let getter = |scope: &mut v8::HandleScope, + let getter = |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -3419,7 +3487,7 @@ fn object_set_accessor_with_data() { CALL_COUNT.fetch_add(1, Ordering::SeqCst); }; - let setter = |scope: &mut v8::HandleScope, + let setter = |scope: &mut v8::PinScope, key: v8::Local, value: v8::Local, args: v8::PropertyCallbackArguments, @@ -3496,7 +3564,8 @@ fn promise_resolved() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let maybe_resolver = v8::PromiseResolver::new(scope); @@ -3524,7 +3593,8 @@ fn promise_rejected() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let maybe_resolver = v8::PromiseResolver::new(scope); @@ -3552,7 +3622,8 @@ fn proxy() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let target = v8::Object::new(scope); @@ -3569,7 +3640,7 @@ fn proxy() { } fn fn_callback_external( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -3585,7 +3656,7 @@ fn fn_callback_external( } fn fn_callback( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -3596,7 +3667,7 @@ fn fn_callback( } fn fn_callback_new( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -3612,7 +3683,7 @@ fn fn_callback_new( } fn fn_callback2( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -3633,7 +3704,7 @@ fn fn_callback2( } fn fortytwo_callback( - _: &mut v8::HandleScope, + _: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -3641,7 +3712,7 @@ fn fortytwo_callback( } fn data_is_true_callback( - _scope: &mut v8::HandleScope, + _scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, _rv: v8::ReturnValue, ) { @@ -3650,13 +3721,13 @@ fn data_is_true_callback( } fn nested_builder<'a>( - scope: &mut v8::HandleScope<'a>, + scope: &mut v8::PinScope<'a, '_>, args: v8::FunctionCallbackArguments<'a>, _: v8::ReturnValue, ) { let arg0 = args.get(0); v8::Function::builder( - |_: &mut v8::HandleScope, + |_: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue| {}, ) @@ -3669,7 +3740,8 @@ fn function_builder_raw() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let global = context.global(scope); @@ -3677,7 +3749,7 @@ fn function_builder_raw() { extern "C" fn callback(info: *const v8::FunctionCallbackInfo) { let info = unsafe { &*info }; - let scope = unsafe { &mut v8::CallbackScope::new(info) }; + v8::callback_scope!(unsafe scope, info); let args = v8::FunctionCallbackArguments::from_function_callback_info(info); assert!(args.length() == 1); @@ -3704,7 +3776,8 @@ fn return_value() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let global = context.global(scope); @@ -3714,7 +3787,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3737,7 +3810,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3760,7 +3833,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3783,7 +3856,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3805,7 +3878,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3827,7 +3900,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3850,7 +3923,7 @@ fn return_value() { { let template = v8::FunctionTemplate::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue| { assert_eq!(args.length(), 0); @@ -3877,7 +3950,8 @@ fn function() { let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let global = context.global(scope); @@ -3989,8 +4063,9 @@ fn function() { } { - let mut root_scope = v8::HandleScope::new(isolate); - let context = v8::Context::new(&mut root_scope, Default::default()); + let root_scope = pin!(v8::HandleScope::new(isolate)); + let mut root_scope = root_scope.init(); + let context = v8::Context::new(&root_scope, Default::default()); let mut scope = v8::ContextScope::new(&mut root_scope, context); let function: v8::Local = @@ -3998,15 +4073,14 @@ fn function() { .unwrap() .try_into() .unwrap(); - drop(scope); - let recv = v8::undefined(&mut root_scope).into(); + let recv = v8::undefined(&scope).into(); let ret = function - .call_with_context(&mut root_scope, context, recv, &[]) + .call_with_context(&scope, context, recv, &[]) .unwrap(); let integer: v8::Local = ret.try_into().unwrap(); - let mut scope = v8::ContextScope::new(&mut root_scope, context); - assert_eq!(integer.int32_value(&mut scope).unwrap(), 1); + let scope = v8::ContextScope::new(&mut scope, context); + assert_eq!(integer.int32_value(&scope).unwrap(), 1); } } @@ -4015,7 +4089,8 @@ fn function_column_and_line_numbers() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let mut source = mock_source( @@ -4075,7 +4150,8 @@ fn function_script_origin_and_id() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -4154,7 +4230,8 @@ fn constructor() { let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let global = context.global(scope); @@ -4168,14 +4245,15 @@ fn constructor() { } extern "C" fn promise_reject_callback(msg: v8::PromiseRejectMessage) { - let scope = &mut unsafe { v8::CallbackScope::new(&msg) }; + v8::callback_scope!(unsafe scope, &msg); let event = msg.get_event(); assert_eq!(event, v8::PromiseRejectEvent::PromiseRejectWithNoHandler); let promise = msg.get_promise(); assert_eq!(promise.state(), v8::PromiseState::Rejected); let value = msg.get_value().unwrap(); { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let value_str = value.to_rust_string_lossy(scope); assert_eq!(value_str, "promise rejected".to_string()); } @@ -4187,7 +4265,8 @@ fn set_promise_reject_callback() { let isolate = &mut v8::Isolate::new(Default::default()); isolate.set_promise_reject_callback(promise_reject_callback); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let resolver = v8::PromiseResolver::new(scope).unwrap(); @@ -4211,7 +4290,8 @@ fn promise_reject_callback_no_value() { let isolate = &mut v8::Isolate::new(Default::default()); isolate.set_promise_reject_callback(promise_reject_callback); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" @@ -4235,7 +4315,7 @@ fn promise_hook() { // Check that PromiseHookType implements Clone and PartialEq. _ = type_.clone() == v8::PromiseHookType::Init; - let scope = &mut unsafe { v8::CallbackScope::new(promise) }; + v8::callback_scope!(unsafe scope, promise); let context = promise.get_creation_context(scope).unwrap(); let scope = &mut v8::ContextScope::new(scope, context); let global = context.global(scope); @@ -4249,7 +4329,8 @@ fn promise_hook() { let isolate = &mut v8::Isolate::new(Default::default()); isolate.set_promise_hook(hook); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" @@ -4284,7 +4365,8 @@ fn context_get_extras_binding_object() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let extras_binding = context.get_extras_binding_object(scope); @@ -4305,7 +4387,8 @@ fn context_promise_hooks() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let init_hook = v8::Local::::try_from( @@ -4411,7 +4494,8 @@ fn context_promise_hooks_partial() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let init_hook = v8::Local::::try_from( @@ -4485,7 +4569,8 @@ fn security_token() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -4509,7 +4594,7 @@ fn security_token() { templ.set_named_property_handler( v8::NamedPropertyHandlerConfiguration::new() .getter( - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { @@ -4538,7 +4623,8 @@ fn security_token() { // Without the security context, the variable can not be shared child_context.set_security_token(security_token); let child_scope = &mut v8::ContextScope::new(scope, child_context); - let try_catch = &mut v8::TryCatch::new(child_scope); + v8::tc_scope!(let try_catch, child_scope); + let result = eval(try_catch, source); assert!(!try_catch.has_caught()); assert!(result.unwrap().is_undefined()); @@ -4554,7 +4640,8 @@ fn security_token() { }, ); let child_scope = &mut v8::ContextScope::new(scope, child_context); - let try_catch = &mut v8::TryCatch::new(child_scope); + v8::tc_scope!(let try_catch, child_scope); + let result = eval(try_catch, source); assert!(try_catch.has_caught()); let exc = try_catch.exception().unwrap(); @@ -4574,7 +4661,7 @@ fn context_with_object_template() { static CALLS: Mutex> = Mutex::new(Vec::new()); fn definer<'s>( - _scope: &mut v8::HandleScope<'s>, + _scope: &mut v8::PinScope<'s, '_>, _key: v8::Local<'s, v8::Name>, _descriptor: &v8::PropertyDescriptor, _args: v8::PropertyCallbackArguments<'s>, @@ -4585,7 +4672,7 @@ fn context_with_object_template() { } pub fn setter<'s>( - _scope: &mut v8::HandleScope<'s>, + _scope: &mut v8::PinScope<'s, '_>, _key: v8::Local<'s, v8::Name>, _value: v8::Local<'s, v8::Value>, _args: v8::PropertyCallbackArguments<'s>, @@ -4596,7 +4683,8 @@ fn context_with_object_template() { } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let object_template = v8::ObjectTemplate::new(scope); let mut config = v8::NamedPropertyHandlerConfiguration::new().flags( v8::PropertyHandlerFlags::NON_MASKING @@ -4630,7 +4718,8 @@ fn allow_code_generation_from_strings() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); // The code generation is allowed by default assert!(context.is_code_generation_from_strings_allowed()); @@ -4641,7 +4730,8 @@ fn allow_code_generation_from_strings() { { let scope = &mut v8::ContextScope::new(scope, context); - let try_catch = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let try_catch, scope); + let result = eval(try_catch, source).unwrap(); let expected = v8::Integer::new(try_catch, 1); assert!(expected.strict_equals(result)); @@ -4652,7 +4742,8 @@ fn allow_code_generation_from_strings() { { let scope = &mut v8::ContextScope::new(scope, context); - let try_catch = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let try_catch, scope); + let result = eval(try_catch, source); assert!(try_catch.has_caught()); let exc = try_catch.exception().unwrap(); @@ -4675,7 +4766,8 @@ fn allow_atomics_wait() { let allow = *allow; isolate.set_allow_atomics_wait(allow); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" @@ -4683,7 +4775,8 @@ fn allow_atomics_wait() { const a = new Int32Array(b); "timed-out" === Atomics.wait(a, 0, 0, 1); "#; - let try_catch = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let try_catch, scope); + let result = eval(try_catch, source); if allow { assert!(!try_catch.has_caught()); @@ -4711,7 +4804,7 @@ fn date_time_configuration_change_notification() { } fn mock_script_origin<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, resource_name_: &str, ) -> v8::ScriptOrigin<'s> { let resource_name = v8::String::new(scope, resource_name_).unwrap(); @@ -4739,7 +4832,7 @@ fn mock_script_origin<'s>( } fn mock_source( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, resource_name: &str, source: &str, ) -> v8::script_compiler::Source { @@ -4754,7 +4847,8 @@ fn script_compiler_source() { let isolate = &mut v8::Isolate::new(Default::default()); isolate.set_promise_reject_callback(promise_reject_callback); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -4777,7 +4871,8 @@ fn module_instantiation_failures1() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -4820,15 +4915,17 @@ fn module_instantiation_failures1() { // Instantiation should fail. { - let tc = &mut v8::TryCatch::new(scope); - fn resolve_callback<'a>( - context: v8::Local<'a, v8::Context>, - _specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, - _referrer: v8::Local<'a, v8::Module>, - ) -> Option> { - let scope = &mut unsafe { v8::CallbackScope::new(context) }; - let scope = &mut v8::HandleScope::new(scope); + v8::tc_scope!(let tc, scope); + + fn resolve_callback<'s>( + context: v8::Local<'s, v8::Context>, + _specifier: v8::Local<'s, v8::String>, + _import_attributes: v8::Local<'s, v8::FixedArray>, + _referrer: v8::Local<'s, v8::Module>, + ) -> Option> { + v8::callback_scope!(unsafe scope, context); + v8::scope!(let scope, scope); + let e = v8::String::new(scope, "boom").unwrap(); scope.throw_exception(e.into()); None @@ -4849,13 +4946,13 @@ fn module_instantiation_failures1() { // Clippy thinks the return value doesn't need to be an Option, it's unaware // of the mapping that MapFnFrom does for ResolveModuleCallback. #[allow(clippy::unnecessary_wraps)] -fn compile_specifier_as_module_resolve_callback<'a>( - context: v8::Local<'a, v8::Context>, - specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, - _referrer: v8::Local<'a, v8::Module>, -) -> Option> { - let scope = &mut unsafe { v8::CallbackScope::new(context) }; +fn compile_specifier_as_module_resolve_callback<'s>( + context: v8::Local<'s, v8::Context>, + specifier: v8::Local<'s, v8::String>, + _import_attributes: v8::Local<'s, v8::FixedArray>, + _referrer: v8::Local<'s, v8::Module>, +) -> Option> { + v8::callback_scope!(unsafe scope, context); let origin = mock_script_origin(scope, "module.js"); let mut source = v8::script_compiler::Source::new(specifier, Some(&origin)); let module = v8::script_compiler::compile_module(scope, &mut source).unwrap(); @@ -4867,7 +4964,8 @@ fn module_evaluation() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -4910,7 +5008,8 @@ fn module_stalled_top_level_await() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -4976,13 +5075,13 @@ fn import_attributes() { // Clippy thinks the return value doesn't need to be an Option, it's unaware // of the mapping that MapFnFrom does for ResolveModuleCallback. #[allow(clippy::unnecessary_wraps)] - fn module_resolve_callback<'a>( - context: v8::Local<'a, v8::Context>, - _specifier: v8::Local<'a, v8::String>, - import_attributes: v8::Local<'a, v8::FixedArray>, - _referrer: v8::Local<'a, v8::Module>, - ) -> Option> { - let scope = &mut unsafe { v8::CallbackScope::new(context) }; + fn module_resolve_callback<'s>( + context: v8::Local<'s, v8::Context>, + _specifier: v8::Local<'s, v8::String>, + import_attributes: v8::Local<'s, v8::FixedArray>, + _referrer: v8::Local<'s, v8::Module>, + ) -> Option> { + v8::callback_scope!(unsafe scope, context); // "type" keyword, value and source offset of assertion assert_eq!(import_attributes.length(), 3); @@ -5005,7 +5104,7 @@ fn import_attributes() { } fn dynamic_import_cb<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, _host_defined_options: v8::Local<'s, v8::Data>, _resource_name: v8::Local<'s, v8::Value>, _specifier: v8::Local<'s, v8::String>, @@ -5024,7 +5123,8 @@ fn import_attributes() { isolate.set_host_import_module_dynamically_callback(dynamic_import_cb); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5057,7 +5157,8 @@ fn primitive_array() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5088,7 +5189,8 @@ fn equality() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5122,7 +5224,8 @@ fn equality_edge_cases() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5181,7 +5284,8 @@ fn get_hash() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5295,7 +5399,8 @@ fn array_buffer_view() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new( @@ -5336,7 +5441,8 @@ fn continuation_preserved_embedder_data() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let data = scope.get_continuation_preserved_embedder_data(); @@ -5366,7 +5472,8 @@ fn snapshot_creator() { let startup_data = { let mut snapshot_creator = v8::Isolate::snapshot_creator(None, None); { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); eval(scope, "b = 2 + 3").unwrap(); @@ -5389,7 +5496,8 @@ fn snapshot_creator() { // Check that the SnapshotCreator isolate has been set up correctly. let _ = snapshot_creator.thread_safe_handle(); - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); eval(scope, "a = 1 + 2").unwrap(); @@ -5414,7 +5522,8 @@ fn snapshot_creator() { let params = v8::Isolate::create_params().snapshot_blob(startup_data); let isolate = &mut v8::Isolate::new(params); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let result = eval(scope, "a === 3").unwrap(); @@ -5457,8 +5566,9 @@ fn snapshot_creator_multiple_contexts() { let startup_data = { let mut snapshot_creator = v8::Isolate::snapshot_creator(None, None); { - let mut scope = v8::HandleScope::new(&mut snapshot_creator); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut snapshot_creator)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let scope = &mut v8::ContextScope::new(&mut scope, context); eval(scope, "globalThis.__bootstrap = { defaultContextProp: 1};") .unwrap(); @@ -5471,7 +5581,8 @@ fn snapshot_creator_multiple_contexts() { scope.set_default_context(context); } { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); eval(scope, "globalThis.__bootstrap = { context0Prop: 2 };").unwrap(); @@ -5496,7 +5607,8 @@ fn snapshot_creator_multiple_contexts() { None, ); { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { @@ -5519,7 +5631,8 @@ fn snapshot_creator_multiple_contexts() { scope.set_default_context(context); } { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::from_snapshot(scope, 0, Default::default()).unwrap(); let scope = &mut v8::ContextScope::new(scope, context); @@ -5550,7 +5663,8 @@ fn snapshot_creator_multiple_contexts() { let params = v8::Isolate::create_params().snapshot_blob(startup_data); let isolate = &mut v8::Isolate::new(params); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { @@ -5576,7 +5690,8 @@ fn snapshot_creator_multiple_contexts() { } } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::from_snapshot(scope, 0, Default::default()).unwrap(); let scope = &mut v8::ContextScope::new(scope, context); @@ -5611,8 +5726,9 @@ fn snapshot_creator_context_embedder_data() { let startup_data = { let mut snapshot_creator = v8::Isolate::snapshot_creator(None, None); { - let mut scope = v8::HandleScope::new(&mut snapshot_creator); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut snapshot_creator)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let scope = &mut v8::ContextScope::new(&mut scope, context); let x = eval(scope, "({ prop: 1 })").unwrap(); context.set_embedder_data(1, x); @@ -5639,7 +5755,8 @@ fn snapshot_creator_context_embedder_data() { None, ); { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { @@ -5665,7 +5782,8 @@ fn snapshot_creator_context_embedder_data() { let params = v8::Isolate::create_params().snapshot_blob(startup_data); let isolate = &mut v8::Isolate::new(params); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { @@ -5713,7 +5831,8 @@ fn external_references() { let mut snapshot_creator = v8::Isolate::snapshot_creator(Some(refs.to_vec().into()), None); { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5745,7 +5864,8 @@ fn external_references() { .external_references(refs.to_vec().into()); let isolate = &mut v8::Isolate::new(params); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5763,7 +5883,8 @@ fn uint8_array() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = @@ -5790,7 +5911,8 @@ fn uint8_array() { fn typed_array_constructors() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5907,7 +6029,8 @@ fn typed_array_constructors() { // v8::ArrayBuffer::new raises a fatal if the length is > kMaxLength, so we test this behavior // through the JS side of things, where a non-fatal RangeError is thrown in such cases. { - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + eval( scope, &format!("new Uint8Array({})", v8::Uint8Array::MAX_LENGTH + 1), @@ -5925,7 +6048,7 @@ fn dynamic_import() { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); fn dynamic_import_cb<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, _host_defined_options: v8::Local<'s, v8::Data>, _resource_name: v8::Local<'s, v8::Value>, specifier: v8::Local<'s, v8::String>, @@ -5942,7 +6065,8 @@ fn dynamic_import() { isolate.set_host_import_module_dynamically_callback(dynamic_import_cb); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -5962,7 +6086,8 @@ fn shared_array_buffer() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -6020,7 +6145,8 @@ fn typeof_checker() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -6041,7 +6167,8 @@ fn value_checker() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -6411,13 +6538,14 @@ fn try_from_data() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let mut module_source = mock_source(scope, "answer.js", "fail()"); let function_callback = - |_: &mut v8::HandleScope, + |_: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue| { unreachable!() }; @@ -6488,7 +6616,8 @@ fn try_from_value() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -6757,7 +6886,8 @@ fn inspector_dispatch_protocol_message() { V8InspectorClient::new(Box::new(default_client.clone())); let inspector = V8Inspector::create(isolate, inspector_client); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let mut _scope = v8::ContextScope::new(scope, context); @@ -6799,9 +6929,10 @@ fn inspector_exception_thrown() { V8InspectorClient::new(Box::new(default_client.clone())); let inspector = V8Inspector::create(isolate, inspector_client); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); - let mut context_scope = v8::ContextScope::new(scope, context); + let context_scope = v8::ContextScope::new(scope, context); let name = b""; let name_view = StringView::from(&name[..]); @@ -6838,10 +6969,9 @@ fn inspector_exception_thrown() { let url = &url.into_bytes()[..]; let url_string_view = StringView::from(url); let exception_msg = - v8::String::new(&mut context_scope, "This is a test error").unwrap(); - let exception = v8::Exception::error(&mut context_scope, exception_msg); - let stack_trace = - v8::Exception::get_stack_trace(&mut context_scope, exception); + v8::String::new(&context_scope, "This is a test error").unwrap(); + let exception = v8::Exception::error(&context_scope, exception_msg); + let stack_trace = v8::Exception::get_stack_trace(&context_scope, exception); let stack_trace_ptr = inspector.create_stack_trace(stack_trace); let _id = inspector.exception_thrown( context, @@ -6872,7 +7002,8 @@ fn inspector_schedule_pause_on_next_statement() { let inspector_client = V8InspectorClient::new(Box::new(client.clone())); let inspector = V8Inspector::create(isolate, inspector_client); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -6977,7 +7108,8 @@ fn inspector_console_api_message() { let inspector_client = V8InspectorClient::new(Box::new(client.clone())); let inspector = V8Inspector::create(isolate, inspector_client); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7004,7 +7136,8 @@ fn context_from_object_template() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let object_templ = v8::ObjectTemplate::new(scope); let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback); let name = v8::String::new(scope, "f").unwrap(); @@ -7028,7 +7161,8 @@ fn take_heap_snapshot() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" @@ -7053,12 +7187,13 @@ fn take_heap_snapshot() { fn get_constructor_name() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); fn check_ctor_name( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, script: &str, expected_name: &str, ) { @@ -7092,7 +7227,8 @@ fn get_constructor_name() { fn get_property_attributes() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7121,7 +7257,8 @@ fn get_property_attributes() { // exception let key = eval(scope, "({ toString() { throw 'foo' } })").unwrap(); - let tc = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc, scope); + assert!(obj.get_property_attributes(tc, key).is_none()); assert!(tc.has_caught()); } @@ -7130,7 +7267,8 @@ fn get_property_attributes() { fn get_own_property_descriptor() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7178,7 +7316,8 @@ fn get_own_property_descriptor() { fn preview_entries() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7258,7 +7397,8 @@ fn test_prototype_api() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7283,7 +7423,8 @@ fn test_prototype_api() { assert_eq!(sub_gotten.to_rust_string_lossy(scope), "test_proto_value"); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7294,7 +7435,8 @@ fn test_prototype_api() { assert!(obj.get_prototype(scope).unwrap().is_null()); } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7310,7 +7452,8 @@ fn test_map_api() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7346,7 +7489,7 @@ fn test_object_get_property_names() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7527,7 +7670,8 @@ fn module_snapshot() { let startup_data = { let mut snapshot_creator = v8::Isolate::snapshot_creator(None, None); { - let scope = &mut v8::HandleScope::new(&mut snapshot_creator); + v8::scope!(let scope, &mut snapshot_creator); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7572,7 +7716,8 @@ fn module_snapshot() { let params = v8::Isolate::create_params().snapshot_blob(startup_data); let isolate = &mut v8::Isolate::new(params); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7618,7 +7763,8 @@ fn heap_limits() { let state_ptr = &mut test_state as *mut _ as *mut c_void; isolate.add_near_heap_limit_callback(heap_limit_callback, state_ptr); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7670,7 +7816,8 @@ fn heap_statistics() { assert_eq!(s.total_global_handles_size(), 0); assert_eq!(s.number_of_native_contexts(), 0); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7695,11 +7842,11 @@ fn low_memory_notification() { // Clippy thinks the return value doesn't need to be an Option, it's unaware // of the mapping that MapFnFrom does for ResolveModuleCallback. #[allow(clippy::unnecessary_wraps)] -fn synthetic_evaluation_steps<'a>( - context: v8::Local<'a, v8::Context>, +fn synthetic_evaluation_steps<'s>( + context: v8::Local<'s, v8::Context>, module: v8::Local, -) -> Option> { - let scope = &mut unsafe { v8::CallbackScope::new(context) }; +) -> Option> { + v8::callback_scope!(unsafe scope, context); let mut set = |name, value| { let name = v8::String::new(scope, name).unwrap(); let value = v8::Number::new(scope, value).into(); @@ -7711,12 +7858,14 @@ fn synthetic_evaluation_steps<'a>( set("b", 2.0); { - let scope = &mut v8::TryCatch::new(scope); - let name = v8::String::new(scope, "does not exist").unwrap(); - let value = v8::undefined(scope).into(); + let scope = std::pin::pin!(v8::TryCatch::new(scope)); + let mut scope = scope.init(); + + let name = v8::String::new(&scope, "does not exist").unwrap(); + let value = v8::undefined(&scope).into(); assert!( module - .set_synthetic_module_export(scope, name, value) + .set_synthetic_module_export(&mut scope, name, value) .is_none() ); assert!(scope.has_caught()); @@ -7731,7 +7880,7 @@ fn synthetic_module() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7764,7 +7913,7 @@ fn synthetic_module() { let ns = v8::Local::::try_from(module.get_module_namespace()).unwrap(); - let mut check = |name, value| { + let check = |name, value| { let name = v8::String::new(scope, name).unwrap().into(); let value = v8::Number::new(scope, value).into(); assert!(ns.get(scope, name).unwrap().strict_equals(value)); @@ -7778,7 +7927,7 @@ fn static_source_phase_import() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7794,13 +7943,13 @@ fn static_source_phase_import() { context.set_slot(Rc::new(v8::Global::new(scope, obj))); - fn resolve_source<'a>( - context: v8::Local<'a, v8::Context>, - _specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, - _referrer: v8::Local<'a, v8::Module>, - ) -> Option> { - let scope = unsafe { &mut v8::CallbackScope::new(context) }; + fn resolve_source<'s>( + context: v8::Local<'s, v8::Context>, + _specifier: v8::Local<'s, v8::String>, + _import_attributes: v8::Local<'s, v8::FixedArray>, + _referrer: v8::Local<'s, v8::Module>, + ) -> Option> { + v8::callback_scope!(unsafe scope, context); let global = Rc::into_inner(context.remove_slot::>().unwrap()) .unwrap(); @@ -7826,7 +7975,7 @@ fn dynamic_source_phase_import() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7836,7 +7985,7 @@ fn dynamic_source_phase_import() { context.set_slot(Rc::new(v8::Global::new(scope, obj))); fn dynamic_import_cb<'s>( - _scope: &mut v8::HandleScope<'s>, + _scope: &mut v8::PinScope<'s, '_>, _host_defined_options: v8::Local<'s, v8::Data>, _resource_name: v8::Local<'s, v8::Value>, _specifier: v8::Local<'s, v8::String>, @@ -7846,7 +7995,7 @@ fn dynamic_source_phase_import() { } fn dynamic_import_phase_cb<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, _host_defined_options: v8::Local<'s, v8::Data>, _resource_name: v8::Local<'s, v8::Value>, _specifier: v8::Local<'s, v8::String>, @@ -7887,7 +8036,7 @@ fn date() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -7913,7 +8062,7 @@ fn date() { fn symbol() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let desc = v8::String::new(scope, "a description").unwrap(); @@ -7952,7 +8101,7 @@ fn symbol() { fn private() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let p = v8::Private::new(scope, None); assert!(p.name(scope) == v8::undefined(scope)); @@ -7996,7 +8145,7 @@ fn private() { fn external_onebyte_string() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); // "hello©" // Note that we're specifically testing a byte array that is not ASCII nor @@ -8022,7 +8171,8 @@ fn bigint() { let _setup_guard: setup::SetupGuard> = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8065,16 +8215,16 @@ struct Custom1Value<'a> { } impl<'a> Custom1Value<'a> { - fn serializer<'s>( - scope: &mut v8::HandleScope<'s>, + fn serializer<'s, 'i>( + scope: &mut v8::PinScope<'s, 'i>, array_buffers: &'a mut ArrayBuffers, - ) -> v8::ValueSerializer<'a> { + ) -> v8::ValueSerializer<'a> where { let array_buffers = RefCell::new(array_buffers); v8::ValueSerializer::new(scope, Box::new(Self { array_buffers })) } - fn deserializer<'s>( - scope: &mut v8::HandleScope<'s>, + fn deserializer<'s, 'i>( + scope: &mut v8::PinScope<'s, 'i>, data: &[u8], array_buffers: &'a mut ArrayBuffers, ) -> v8::ValueDeserializer<'a> { @@ -8087,7 +8237,7 @@ impl v8::ValueSerializerImpl for Custom1Value<'_> { #[allow(unused_variables)] fn throw_data_clone_error<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, message: v8::Local<'s, v8::String>, ) { let error = v8::Exception::error(scope, message); @@ -8097,7 +8247,7 @@ impl v8::ValueSerializerImpl for Custom1Value<'_> { #[allow(unused_variables)] fn get_shared_array_buffer_id<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, shared_array_buffer: v8::Local<'s, v8::SharedArrayBuffer>, ) -> Option { self.array_buffers.borrow_mut().push( @@ -8108,7 +8258,7 @@ impl v8::ValueSerializerImpl for Custom1Value<'_> { fn write_host_object<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, object: v8::Local<'s, v8::Object>, value_serializer: &dyn v8::ValueSerializerHelper, ) -> Option { @@ -8127,7 +8277,7 @@ impl v8::ValueDeserializerImpl for Custom1Value<'_> { #[allow(unused_variables)] fn get_shared_array_buffer_from_id<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, transfer_id: u32, ) -> Option> { let backing_store = self @@ -8144,7 +8294,7 @@ impl v8::ValueDeserializerImpl for Custom1Value<'_> { fn read_host_object<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, value_deserializer: &dyn v8::ValueDeserializerHelper, ) -> Option> { let mut value = 0; @@ -8168,7 +8318,7 @@ fn value_serializer_and_deserializer() { let mut array_buffers = ArrayBuffers::new(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8209,7 +8359,7 @@ fn value_serializer_and_deserializer_js_objects() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8242,7 +8392,7 @@ fn value_serializer_and_deserializer_js_objects() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8322,7 +8472,7 @@ fn value_serializer_and_deserializer_array_buffers() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8347,7 +8497,7 @@ fn value_serializer_and_deserializer_array_buffers() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8386,7 +8536,7 @@ fn value_serializer_and_deserializer_embedder_host_object() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8411,7 +8561,7 @@ fn value_serializer_and_deserializer_embedder_host_object() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8437,9 +8587,9 @@ fn value_serializer_and_deserializer_embedder_host_object() { struct Custom2Value {} impl Custom2Value { - fn serializer<'s>( - scope: &mut v8::HandleScope<'s>, - ) -> v8::ValueSerializer<'s> { + fn serializer<'i>( + scope: &mut v8::PinScope<'_, 'i>, + ) -> v8::ValueSerializer<'i> { v8::ValueSerializer::new(scope, Box::new(Self {})) } } @@ -8448,10 +8598,11 @@ impl v8::ValueSerializerImpl for Custom2Value { #[allow(unused_variables)] fn throw_data_clone_error<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, message: v8::Local<'s, v8::String>, ) { - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + let error = v8::Exception::error(scope, message); scope.throw_exception(error); } @@ -8462,11 +8613,11 @@ fn value_serializer_not_implemented() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); let objects: v8::Local = eval( scope, @@ -8496,17 +8647,17 @@ fn value_serializer_not_implemented() { struct Custom3Value {} -impl<'a> Custom3Value { - fn serializer<'s>( - scope: &mut v8::HandleScope<'s>, - ) -> v8::ValueSerializer<'a> { +impl Custom3Value { + fn serializer<'i>( + scope: &mut v8::PinScope<'_, 'i>, + ) -> v8::ValueSerializer<'i> { v8::ValueSerializer::new(scope, Box::new(Self {})) } - fn deserializer<'s>( - scope: &mut v8::HandleScope<'s>, + fn deserializer<'i>( + scope: &mut v8::PinScope<'_, 'i>, data: &[u8], - ) -> v8::ValueDeserializer<'a> { + ) -> v8::ValueDeserializer<'i> { v8::ValueDeserializer::new(scope, Box::new(Self {}), data) } } @@ -8515,20 +8666,20 @@ impl v8::ValueSerializerImpl for Custom3Value { #[allow(unused_variables)] fn throw_data_clone_error<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, message: v8::Local<'s, v8::String>, ) { let error = v8::Exception::error(scope, message); scope.throw_exception(error); } - fn has_custom_host_object(&self, _isolate: &mut v8::Isolate) -> bool { + fn has_custom_host_object(&self, _isolate: &v8::Isolate) -> bool { true } fn is_host_object<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, object: v8::Local<'s, v8::Object>, ) -> Option { let key = v8::String::new(scope, "hostObject").unwrap(); @@ -8537,7 +8688,7 @@ impl v8::ValueSerializerImpl for Custom3Value { fn write_host_object<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, object: v8::Local<'s, v8::Object>, value_serializer: &dyn v8::ValueSerializerHelper, ) -> Option { @@ -8555,7 +8706,7 @@ impl v8::ValueSerializerImpl for Custom3Value { impl v8::ValueDeserializerImpl for Custom3Value { fn read_host_object<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, value_deserializer: &dyn v8::ValueDeserializerHelper, ) -> Option> { let mut value = 0; @@ -8576,7 +8727,7 @@ fn value_serializer_and_deserializer_custom_host_object() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8599,7 +8750,7 @@ fn value_serializer_and_deserializer_custom_host_object() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8641,7 +8792,8 @@ fn clear_kept_objects() { let isolate = &mut v8::Isolate::new(Default::default()); isolate.set_microtasks_policy(v8::MicrotasksPolicy::Explicit); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8671,7 +8823,7 @@ fn wasm_streaming_callback() { static WS: RefCell> = const { RefCell::new(None) }; } - let callback = |scope: &mut v8::HandleScope, + let callback = |scope: &mut v8::PinScope, url: v8::Local, ws: v8::WasmStreaming| { assert_eq!("https://example.com", url.to_rust_string_lossy(scope)); @@ -8683,7 +8835,8 @@ fn wasm_streaming_callback() { let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); isolate.set_wasm_streaming_callback(callback); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8748,17 +8901,21 @@ fn wasm_streaming_callback() { fn unbound_script_conversion() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + + let context = v8::Context::new(scope, Default::default()); + let scope = &mut v8::ContextScope::new(scope, context); + let unbound_script = { - let context = v8::Context::new(scope, Default::default()); - let scope = &mut v8::ContextScope::new(scope, context); + let esc = pin!(v8::EscapableHandleScope::new(scope)); + let mut esc = esc.init(); let source = v8::String::new( - scope, + &esc, "'Hello ' + value\n//# sourceMappingURL=foo.js.map", ) .unwrap(); - let script = v8::Script::compile(scope, source, None).unwrap(); - script.get_unbound_script(scope) + let script = v8::Script::compile(&esc, source, None).unwrap(); + esc.escape(script.get_unbound_script(&esc)) }; { @@ -8780,7 +8937,8 @@ fn unbound_script_conversion() { fn get_source_mapping_from_comment() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8830,7 +8988,8 @@ fn get_source_mapping_from_comment() { fn origin_source_map_overrides_source_mapping_url_comment() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8882,7 +9041,8 @@ fn origin_source_map_overrides_source_mapping_url_comment() { fn ignore_origin_source_map_empty_string() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8933,7 +9093,8 @@ fn ignore_origin_source_map_empty_string() { fn no_source_map_comment() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -8985,7 +9146,8 @@ fn ept_torture_test() { // This should not OOM or crash when we run in a tight loop as the EPT should be subject // to GC. { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new( @@ -9048,7 +9210,8 @@ fn run_with_rust_allocator() { let isolate = &mut v8::Isolate::new(create_params); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new( @@ -9076,7 +9239,8 @@ fn run_with_rust_allocator() { // This should not OOM or crash when we run in a tight loop as the EPT should be subject // to GC. { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new( @@ -9133,10 +9297,11 @@ fn prepare_stack_trace_callback() { let isolate = &mut v8::Isolate::new(Default::default()); isolate.set_prepare_stack_trace_callback(callback); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); let result = eval(scope, script).unwrap(); assert_eq!(Some(42), result.uint32_value(scope)); @@ -9172,7 +9337,7 @@ fn prepare_stack_trace_callback() { } fn callback<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, error: v8::Local, sites: v8::Local, ) -> v8::Local<'s, v8::Value> { @@ -9195,7 +9360,8 @@ fn icu_date() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" @@ -9225,7 +9391,8 @@ fn icu_format() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" @@ -9244,7 +9411,8 @@ fn icu_format() { fn icu_collator() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new(scope, "new Intl.Collator('en-US')").unwrap(); @@ -9253,7 +9421,7 @@ fn icu_collator() { } fn create_module<'s>( - scope: &mut v8::HandleScope<'s, v8::Context>, + scope: &mut v8::PinScope<'s, '_, v8::Context>, source: &str, code_cache: Option>, options: v8::script_compiler::CompileOptions, @@ -9298,7 +9466,7 @@ fn create_module<'s>( } fn create_unbound_module_script<'s>( - scope: &mut v8::HandleScope<'s, v8::Context>, + scope: &mut v8::PinScope<'s, '_, v8::Context>, source: &str, code_cache: Option>, ) -> v8::Local<'s, v8::UnboundModuleScript> { @@ -9315,7 +9483,8 @@ fn create_unbound_module_script<'s>( fn unbound_module_script_conversion() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let mut scope = v8::ContextScope::new(scope, context); create_unbound_module_script(&mut scope, "'Hello ' + value", None); @@ -9337,12 +9506,12 @@ fn cached_data_version_tag() { #[test] fn code_cache() { - fn resolve_callback<'a>( - _context: v8::Local<'a, v8::Context>, - _specifier: v8::Local<'a, v8::String>, - _import_attributes: v8::Local<'a, v8::FixedArray>, - _referrer: v8::Local<'a, v8::Module>, - ) -> Option> { + fn resolve_callback<'s>( + _context: v8::Local<'s, v8::Context>, + _specifier: v8::Local<'s, v8::String>, + _import_attributes: v8::Local<'s, v8::FixedArray>, + _referrer: v8::Local<'s, v8::Module>, + ) -> Option> { None } @@ -9351,7 +9520,8 @@ fn code_cache() { let code_cache = { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let mut scope = v8::ContextScope::new(scope, context); let unbound_module_script = @@ -9360,7 +9530,8 @@ fn code_cache() { }; let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let mut scope = v8::ContextScope::new(scope, context); let module = create_module( @@ -9369,19 +9540,18 @@ fn code_cache() { Some(v8::CachedData::new(&code_cache)), v8::script_compiler::CompileOptions::ConsumeCodeCache, ); - let mut scope = v8::HandleScope::new(&mut scope); - module - .instantiate_module(&mut scope, resolve_callback) - .unwrap(); - module.evaluate(&mut scope).unwrap(); + let scope = pin!(v8::HandleScope::new(&mut scope)); + let scope = scope.init(); + module.instantiate_module(&scope, resolve_callback).unwrap(); + module.evaluate(&scope).unwrap(); let top = v8::Local::::try_from(module.get_module_namespace()).unwrap(); - let key = v8::String::new(&mut scope, "hello").unwrap(); + let key = v8::String::new(&scope, "hello").unwrap(); let value = - v8::Local::::try_from(top.get(&mut scope, key.into()).unwrap()) + v8::Local::::try_from(top.get(&scope, key.into()).unwrap()) .unwrap(); - assert_eq!(&value.to_rust_string_lossy(&mut scope), "world"); + assert_eq!(&value.to_rust_string_lossy(&scope), "world"); } #[test] @@ -9391,7 +9561,8 @@ fn function_code_cache() { let code_cache = { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let mut source = v8::script_compiler::Source::new( @@ -9412,7 +9583,8 @@ fn function_code_cache() { }; let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9442,7 +9614,8 @@ fn function_code_cache() { fn eager_compile_script() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9465,7 +9638,8 @@ fn code_cache_script() { let _setup_guard = setup::parallel_test(); let code_cache = { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9482,7 +9656,8 @@ fn code_cache_script() { }; let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9510,7 +9685,8 @@ fn code_cache_script() { fn compile_function() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9547,7 +9723,8 @@ static EXAMPLE_STRING: v8::OneByteConst = fn external_strings() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9652,7 +9829,8 @@ fn counter_lookup_callback() { let _setup_guard = setup::parallel_test(); let params = v8::CreateParams::default().counter_lookup_callback(callback); let isolate = &mut v8::Isolate::new(params); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let _ = eval(scope, "console.log(42);").unwrap(); @@ -9682,7 +9860,8 @@ fn compiled_wasm_module() { let compiled_module = { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9706,7 +9885,8 @@ fn compiled_wasm_module() { { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -9741,13 +9921,14 @@ fn function_names() { // Setup isolate let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); // Rust function fn callback( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -9809,13 +9990,14 @@ fn backing_store_from_empty_boxed_slice() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); - let mut scope = v8::ContextScope::new(&mut scope, context); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); + let scope = v8::ContextScope::new(&mut scope, context); let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(Box::new([])) .make_shared(); - let _ = v8::ArrayBuffer::with_backing_store(&mut scope, &store); + let _ = v8::ArrayBuffer::with_backing_store(&scope, &store); } #[test] @@ -9823,13 +10005,14 @@ fn backing_store_from_empty_vec() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); - let mut scope = v8::ContextScope::new(&mut scope, context); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); + let scope = v8::ContextScope::new(&mut scope, context); let store = v8::ArrayBuffer::new_backing_store_from_vec(Vec::new()).make_shared(); - let _ = v8::ArrayBuffer::with_backing_store(&mut scope, &store); + let _ = v8::ArrayBuffer::with_backing_store(&scope, &store); } #[test] @@ -9837,14 +10020,15 @@ fn backing_store_data() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); - let mut scope = v8::ContextScope::new(&mut scope, context); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); + let scope = v8::ContextScope::new(&mut scope, context); let v = vec![1, 2, 3, 4, 5]; let len = v.len(); let store = v8::ArrayBuffer::new_backing_store_from_vec(v).make_shared(); - let buf = v8::ArrayBuffer::with_backing_store(&mut scope, &store); + let buf = v8::ArrayBuffer::with_backing_store(&scope, &store); assert_eq!(buf.byte_length(), len); assert!(buf.data().is_some()); assert_eq!( @@ -9868,8 +10052,9 @@ fn backing_store_resizable() { assert!(!store_fixed.is_resizable_by_user_javascript()); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let mut scope = v8::ContextScope::new(&mut scope, context); let ab_val = @@ -9886,13 +10071,14 @@ fn current_stack_trace() { // Setup isolate let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); // A simple JS-facing function that returns its call depth, max of 5 fn call_depth( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -9936,7 +10122,7 @@ fn current_script_name_or_source_url() { static USED: AtomicBool = AtomicBool::new(false); fn analyze_script_url_in_stack( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, _rv: v8::ReturnValue, ) { @@ -9948,7 +10134,8 @@ fn current_script_name_or_source_url() { // Setup isolate let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let key = v8::String::new(scope, "analyzeScriptURLInStack").unwrap(); let tmpl = v8::FunctionTemplate::new(scope, analyze_script_url_in_stack); let obj_template = v8::ObjectTemplate::new(scope); @@ -10001,18 +10188,19 @@ fn instance_of() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); - let mut scope = v8::ContextScope::new(&mut scope, context); - let global = context.global(&mut scope); - let array_name = v8::String::new(&mut scope, "Array").unwrap(); - let array_constructor = global.get(&mut scope, array_name.into()).unwrap(); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); + let scope = v8::ContextScope::new(&mut scope, context); + let global = context.global(&scope); + let array_name = v8::String::new(&scope, "Array").unwrap(); + let array_constructor = global.get(&scope, array_name.into()).unwrap(); let array_constructor = v8::Local::::try_from(array_constructor).unwrap(); let array: v8::Local = - v8::Array::new_with_elements(&mut scope, &[]).into(); + v8::Array::new_with_elements(&scope, &[]).into(); - assert!(array.instance_of(&mut scope, array_constructor).unwrap()); + assert!(array.instance_of(&scope, array_constructor).unwrap()); } #[test] @@ -10027,12 +10215,14 @@ fn weak_handle() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let weak = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let weak = v8::Weak::new(scope, local); @@ -10043,7 +10233,7 @@ fn weak_handle() { weak }; - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full); @@ -10060,27 +10250,31 @@ fn finalizers() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); // The finalizer for a dropped Weak is never called. { { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let _ = v8::Weak::with_finalizer(scope, local, Box::new(|_| unreachable!())); } - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + scope .request_garbage_collection_for_testing(v8::GarbageCollectionType::Full); } let finalizer_called = Rc::new(Cell::new(false)); let weak = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); // We use a channel to send data into the finalizer without having to worry @@ -10109,7 +10303,8 @@ fn finalizers() { weak }; - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full); assert!(weak.is_empty()); assert!(finalizer_called.get()); @@ -10127,14 +10322,16 @@ fn guaranteed_finalizers() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); // The finalizer for a dropped Weak is never called. { { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let _ = v8::Weak::with_guaranteed_finalizer( scope, @@ -10143,14 +10340,16 @@ fn guaranteed_finalizers() { ); } - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + scope .request_garbage_collection_for_testing(v8::GarbageCollectionType::Full); } let finalizer_called = Rc::new(Cell::new(false)); let weak = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); // We use a channel to send data into the finalizer without having to worry @@ -10179,7 +10378,8 @@ fn guaranteed_finalizers() { weak }; - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + scope.request_garbage_collection_for_testing(v8::GarbageCollectionType::Full); assert!(weak.is_empty()); assert!(finalizer_called.get()); @@ -10190,12 +10390,14 @@ fn weak_from_global() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let global = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let object = v8::Object::new(scope); v8::Global::new(scope, object) }; @@ -10217,7 +10419,8 @@ fn weak_from_into_raw() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10230,7 +10433,8 @@ fn weak_from_into_raw() { { finalizer_called.take(); let (weak1, weak2) = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let weak = v8::Weak::new(scope, local); let weak_with_finalizer = v8::Weak::with_finalizer( @@ -10264,7 +10468,8 @@ fn weak_from_into_raw() { // into_raw from a GC'd pointer { let weak = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); v8::Weak::new(scope, local) }; @@ -10279,7 +10484,8 @@ fn weak_from_into_raw() { { finalizer_called.take(); let (weak, weak_with_finalizer) = { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let weak = v8::Weak::new(scope, local); let weak_with_finalizer = v8::Weak::with_finalizer( @@ -10312,7 +10518,8 @@ fn weak_from_into_raw() { // Leaking a Weak will not crash the isolate. { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); v8::Weak::new(scope, local).into_raw(); v8::Weak::with_finalizer(scope, local, Box::new(|_| {})).into_raw(); @@ -10330,7 +10537,8 @@ fn drop_weak_from_raw_in_finalizer() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10338,7 +10546,8 @@ fn drop_weak_from_raw_in_finalizer() { let finalized = Rc::new(Cell::new(false)); { - let scope = &mut v8::HandleScope::new(scope); + v8::scope!(let scope, scope); + let local = v8::Object::new(scope); let weak = v8::Weak::with_finalizer( scope, @@ -10381,7 +10590,8 @@ fn finalizer_on_kept_global() { { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10445,7 +10655,8 @@ fn context_embedder_data() { let expected0 = "Bla"; let expected1 = 123.456f64; { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); unsafe { @@ -10463,7 +10674,8 @@ fn context_embedder_data() { } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = global_context.open(scope); let actual0 = context.get_aligned_pointer_from_embedder_data(0) as *mut &str; @@ -10481,12 +10693,14 @@ fn host_create_shadow_realm_context_callback() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); { - let tc_scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc_scope, scope); + assert!(eval(tc_scope, "new ShadowRealm()").is_none()); assert!(tc_scope.has_caught()); } @@ -10518,7 +10732,8 @@ fn host_create_shadow_realm_context_callback() { }); { - let tc_scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let tc_scope, scope); + assert!(eval(tc_scope, "new ShadowRealm()").is_none()); assert!(tc_scope.has_caught()); assert!(tc_scope.get_slot::().unwrap().callback_called); @@ -10578,7 +10793,7 @@ fn test_fast_calls() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -10590,7 +10805,8 @@ fn test_fast_calls() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10639,7 +10855,7 @@ fn test_fast_calls_empty_buffer() { } fn slow_fn( - _scope: &mut v8::HandleScope, + _scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, _rv: v8::ReturnValue, ) { @@ -10662,7 +10878,8 @@ fn test_fast_calls_empty_buffer() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10714,7 +10931,7 @@ fn test_fast_calls_sequence() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -10724,7 +10941,8 @@ fn test_fast_calls_sequence() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10787,7 +11005,7 @@ fn test_fast_calls_arraybuffer() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -10797,7 +11015,8 @@ fn test_fast_calls_arraybuffer() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10857,7 +11076,7 @@ fn test_fast_calls_typedarray() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -10867,7 +11086,8 @@ fn test_fast_calls_typedarray() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -10927,7 +11147,7 @@ fn test_fast_calls_reciever() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -10942,7 +11162,8 @@ fn test_fast_calls_reciever() { V8_WRAPPER_OBJECT_INDEX, ), ); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11026,7 +11247,7 @@ fn test_fast_calls_overload() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -11036,7 +11257,8 @@ fn test_fast_calls_overload() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11104,7 +11326,7 @@ fn test_fast_calls_callback_options_data() { ); fn slow_fn( - _: &mut v8::HandleScope, + _: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue, ) { @@ -11112,7 +11334,8 @@ fn test_fast_calls_callback_options_data() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11146,7 +11369,8 @@ fn test_fast_calls_callback_options_data() { fn test_detach_key() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11215,7 +11439,7 @@ fn test_fast_calls_onebytestring() { ); fn slow_fn( - _: &mut v8::HandleScope, + _: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue, ) { @@ -11224,7 +11448,8 @@ fn test_fast_calls_onebytestring() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11294,7 +11519,7 @@ fn test_fast_calls_i64representation() { ); fn slow_fn( - _: &mut v8::HandleScope, + _: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue, ) { @@ -11303,7 +11528,8 @@ fn test_fast_calls_i64representation() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11377,7 +11603,7 @@ fn gc_callbacks() { } extern "C" fn prologue( - _isolate: *mut v8::Isolate, + _isolate: v8::UnsafeRawIsolatePtr, _type: v8::GCType, _flags: v8::GCCallbackFlags, data: *mut c_void, @@ -11387,7 +11613,7 @@ fn gc_callbacks() { } extern "C" fn epilogue( - _isolate: *mut v8::Isolate, + _isolate: v8::UnsafeRawIsolatePtr, _type: v8::GCType, _flags: v8::GCCallbackFlags, data: *mut c_void, @@ -11403,7 +11629,8 @@ fn gc_callbacks() { isolate.add_gc_epilogue_callback(epilogue, state_ptr, v8::GCType::kGCTypeAll); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11416,7 +11643,8 @@ fn gc_callbacks() { isolate.remove_gc_prologue_callback(prologue, state_ptr); isolate.remove_gc_epilogue_callback(epilogue, state_ptr); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11451,7 +11679,7 @@ fn test_fast_calls_pointer() { ); fn slow_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -11461,7 +11689,8 @@ fn test_fast_calls_pointer() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11507,7 +11736,8 @@ fn object_define_property() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11531,7 +11761,8 @@ fn object_define_property() { } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11558,7 +11789,8 @@ fn object_define_property() { } { - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); @@ -11589,12 +11821,13 @@ fn object_define_property() { fn bubbling_up_exception() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); fn boom_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, _retval: v8::ReturnValue, ) { @@ -11621,7 +11854,8 @@ try { let source = v8::String::new(scope, code).unwrap(); let script = v8::Script::compile(scope, source, None).unwrap(); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + let _result = script.run(scope); // This fails in debug build, but passes in release build. assert!(!scope.has_caught()); @@ -11633,12 +11867,13 @@ try { fn bubbling_up_exception_in_function_call() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); fn boom_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, _retval: v8::ReturnValue, ) { @@ -11669,14 +11904,17 @@ fn bubbling_up_exception_in_function_call() { let source = v8::String::new(scope, code).unwrap(); let script = v8::Script::compile(scope, source, None).unwrap(); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + let call_boom_fn_val = script.run(scope).unwrap(); let call_boom_fn = v8::Local::::try_from(call_boom_fn_val).unwrap(); - let scope = &mut v8::TryCatch::new(scope); - let this = v8::undefined(scope); - let result = call_boom_fn.call(scope, this.into(), &[]).unwrap(); + let scope = std::pin::pin!(v8::TryCatch::new(scope)); + let scope = scope.init(); + + let this = v8::undefined(&*scope); + let result = call_boom_fn.call(&scope, this.into(), &[]).unwrap(); assert!(result.is_undefined()); // This fails in debug build, but passes in release build. assert!(!scope.has_caught()); @@ -11688,14 +11926,15 @@ fn bubbling_up_exception_in_function_call() { fn exception_thrown_but_continues_execution() { let _setup_guard = setup::parallel_test(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); fn call_object_property<'s>( - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, value: v8::Local, property: &str, ) -> Option> { @@ -11710,7 +11949,7 @@ fn exception_thrown_but_continues_execution() { } fn print_fn( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, _retval: v8::ReturnValue, ) { @@ -11752,7 +11991,8 @@ fn exception_thrown_but_continues_execution() { let source = v8::String::new(scope, code).unwrap(); let script = v8::Script::compile(scope, source, None).unwrap(); - let scope = &mut v8::TryCatch::new(scope); + v8::tc_scope!(let scope, scope); + let _result = script.run(scope); assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 2); } @@ -11762,23 +12002,26 @@ fn disallow_javascript_execution_scope() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let mut scope = v8::ContextScope::new(&mut scope, context); // We can run JS before the scope begins. assert_eq!( - eval(&mut scope, "42").unwrap().uint32_value(&mut scope), + eval(&mut scope, "42").unwrap().uint32_value(&scope), Some(42) ); { - let try_catch = &mut v8::TryCatch::new(&mut scope); + v8::tc_scope!(let try_catch, &mut scope); + { - let scope = &mut v8::DisallowJavascriptExecutionScope::new( + let scope = pin!(v8::DisallowJavascriptExecutionScope::new( try_catch, v8::OnFailure::ThrowOnFailure, - ); + )); + let scope = &mut scope.init(); assert!(eval(scope, "42").is_none()); } assert!(try_catch.has_caught()); @@ -11787,7 +12030,7 @@ fn disallow_javascript_execution_scope() { // And we can run JS after the scope ends. assert_eq!( - eval(&mut scope, "42").unwrap().uint32_value(&mut scope), + eval(&mut scope, "42").unwrap().uint32_value(&scope), Some(42) ); } @@ -11801,17 +12044,23 @@ fn allow_javascript_execution_scope() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let mut scope = v8::ContextScope::new(&mut scope, context); - let disallow_scope = &mut v8::DisallowJavascriptExecutionScope::new( + let disallow_scope = pin!(v8::DisallowJavascriptExecutionScope::new( &mut scope, v8::OnFailure::CrashOnFailure, - ); - let allow_scope = &mut v8::AllowJavascriptExecutionScope::new(disallow_scope); + )); + let mut disallow_scope = disallow_scope.init(); + let allow_scope = + pin!(v8::AllowJavascriptExecutionScope::new(&mut disallow_scope)); + let mut allow_scope = allow_scope.init(); assert_eq!( - eval(allow_scope, "42").unwrap().uint32_value(allow_scope), + eval(&mut allow_scope, "42") + .unwrap() + .uint32_value(&allow_scope), Some(42) ); } @@ -11825,7 +12074,7 @@ fn allow_scope_in_read_host_object() { impl v8::ValueSerializerImpl for Serializer { fn write_host_object<'s>( &self, - _scope: &mut v8::HandleScope<'s>, + _scope: &mut v8::PinScope<'s, '_>, _object: v8::Local<'s, v8::Object>, _value_serializer: &dyn v8::ValueSerializerHelper, ) -> Option { @@ -11835,7 +12084,7 @@ fn allow_scope_in_read_host_object() { fn throw_data_clone_error<'s>( &self, - _scope: &mut v8::HandleScope<'s>, + _scope: &mut v8::PinScope<'s, '_>, _message: v8::Local<'s, v8::String>, ) { todo!() @@ -11846,11 +12095,12 @@ fn allow_scope_in_read_host_object() { impl v8::ValueDeserializerImpl for Deserializer { fn read_host_object<'s>( &self, - scope: &mut v8::HandleScope<'s>, + scope: &mut v8::PinScope<'s, '_>, _value_deserializer: &dyn v8::ValueDeserializerHelper, ) -> Option> { - let scope2 = &mut v8::AllowJavascriptExecutionScope::new(scope); - let value = eval(scope2, "{}").unwrap(); + let scope = pin!(v8::AllowJavascriptExecutionScope::new(scope)); + let scope = &mut scope.init(); + let value = eval(scope, "{}").unwrap(); let object = v8::Local::::try_from(value).unwrap(); Some(object) } @@ -11859,20 +12109,21 @@ fn allow_scope_in_read_host_object() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); - let mut scope = v8::ContextScope::new(&mut scope, context); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); + let scope = v8::ContextScope::new(&mut scope, context); let serialized = { - let serializer = v8::ValueSerializer::new(&mut scope, Box::new(Serializer)); + let serializer = v8::ValueSerializer::new(&scope, Box::new(Serializer)); serializer - .write_value(context, v8::Object::new(&mut scope).into()) + .write_value(context, v8::Object::new(&scope).into()) .unwrap(); serializer.release() }; let deserializer = - v8::ValueDeserializer::new(&mut scope, Box::new(Deserializer), &serialized); + v8::ValueDeserializer::new(&scope, Box::new(Deserializer), &serialized); let value = deserializer.read_value(context).unwrap(); assert!(value.is_object()); } @@ -11882,8 +12133,9 @@ fn microtask_queue() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let queue = context.get_microtask_queue(); let mut scope = v8::ContextScope::new(&mut scope, context); @@ -11891,7 +12143,7 @@ fn microtask_queue() { static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); let function = v8::Function::new( &mut scope, - |_: &mut v8::HandleScope, + |_: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue| { CALL_COUNT.fetch_add(1, Ordering::SeqCst); @@ -11911,10 +12163,11 @@ fn microtask_queue_new() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); let queue = v8::MicrotaskQueue::new(&mut scope, v8::MicrotasksPolicy::Auto); - let context = v8::Context::new(&mut scope, Default::default()); + let context = v8::Context::new(&scope, Default::default()); context.set_microtask_queue(queue.as_ref()); assert!(std::ptr::eq(context.get_microtask_queue(), queue.as_ref())); @@ -11927,9 +12180,10 @@ fn clear_slots_annex_uninitialized() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let scope = scope.init(); - let context = v8::Context::new(&mut scope, Default::default()); + let context = v8::Context::new(&scope, Default::default()); let r = 0; // This would increase slot count without initializing the annex. @@ -11946,8 +12200,9 @@ fn clear_slots_annex_uninitialized() { fn string_valueview() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let scope = &mut v8::ContextScope::new(&mut scope, context); { @@ -11977,13 +12232,14 @@ fn string_valueview() { fn host_defined_options() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let scope = &mut v8::ContextScope::new(&mut scope, context); let test = v8::Function::new( scope, - |scope: &mut v8::HandleScope, + |scope: &mut v8::PinScope, _: v8::FunctionCallbackArguments, _: v8::ReturnValue| { let host_defined_options = unsafe { @@ -12047,8 +12303,9 @@ fn use_counter_callback() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); isolate.set_use_counter_callback(callback); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let scope = &mut v8::ContextScope::new(&mut scope, context); eval(scope, "'use strict'; 1 + 1"); @@ -12063,21 +12320,22 @@ fn test_eternals() { { let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let scope = scope.init(); - let str1 = v8::String::new(&mut scope, "hello").unwrap(); + let str1 = v8::String::new(&scope, "hello").unwrap(); assert!(eternal1.is_empty()); - assert!(eternal1.get(&mut scope).is_none()); - eternal1.set(&mut scope, str1); + assert!(eternal1.get(&scope).is_none()); + eternal1.set(&scope, str1); assert!(!eternal1.is_empty()); - let str1_get = eternal1.get(&mut scope).unwrap(); + let str1_get = eternal1.get(&scope).unwrap(); assert_eq!(str1, str1_get); eternal1.clear(); assert!(eternal1.is_empty()); - assert!(eternal1.get(&mut scope).is_none()); + assert!(eternal1.get(&scope).is_none()); } // Try all 'standalone' methods after isolate has dropped. @@ -12090,8 +12348,9 @@ fn test_regexp() { let _setup_guard = setup::parallel_test(); let mut isolate = v8::Isolate::new(Default::default()); - let mut scope = v8::HandleScope::new(&mut isolate); - let context = v8::Context::new(&mut scope, Default::default()); + let scope = pin!(v8::HandleScope::new(&mut isolate)); + let mut scope = scope.init(); + let context = v8::Context::new(&scope, Default::default()); let scope = &mut v8::ContextScope::new(&mut scope, context); let pattern = v8::String::new(scope, "ab+c").unwrap(); diff --git a/tests/test_api_entropy_source.rs b/tests/test_api_entropy_source.rs index 4982aa31b8..2b4a9aa615 100644 --- a/tests/test_api_entropy_source.rs +++ b/tests/test_api_entropy_source.rs @@ -27,7 +27,8 @@ fn set_entropy_source() { let mut results = vec![]; for _ in 0..N { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new(scope, "Math.random()").unwrap(); diff --git a/tests/test_api_flags.rs b/tests/test_api_flags.rs index 413bb6c3b9..ae13f7cad8 100644 --- a/tests/test_api_flags.rs +++ b/tests/test_api_flags.rs @@ -9,7 +9,8 @@ fn set_flags_from_string() { ); v8::V8::initialize(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = "(function() { return this })()"; diff --git a/tests/test_cppgc.rs b/tests/test_cppgc.rs index b441145ea8..d471f4bc89 100644 --- a/tests/test_cppgc.rs +++ b/tests/test_cppgc.rs @@ -87,12 +87,12 @@ macro_rules! test { } fn op_wrap( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope<'_, '_>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { fn empty( - _scope: &mut v8::HandleScope, + _scope: &mut v8::PinScope<'_, '_>, _args: v8::FunctionCallbackArguments, _rv: v8::ReturnValue, ) { @@ -118,7 +118,7 @@ macro_rules! test { } fn op_unwrap( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope<'_, '_>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -131,7 +131,8 @@ macro_rules! test { let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); { - let handle_scope = &mut v8::HandleScope::new(isolate); + let handle_scope = std::pin::pin!(v8::HandleScope::new(isolate)); + let handle_scope = &mut handle_scope.init(); let context = v8::Context::new(handle_scope, Default::default()); let scope = &mut v8::ContextScope::new(handle_scope, context); let global = context.global(scope); @@ -211,8 +212,9 @@ fn execute_script( context_scope: &mut v8::ContextScope, source: &str, ) { - let scope = &mut v8::HandleScope::new(context_scope); - let scope = &mut v8::TryCatch::new(scope); + v8::scope!(let scope, context_scope); + + v8::tc_scope!(let scope, scope); let source = v8::String::new(scope, source).unwrap(); @@ -260,12 +262,12 @@ fn cppgc_cell() { } fn op_wrap( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope<'_, '_>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { fn empty( - _scope: &mut v8::HandleScope, + _scope: &mut v8::PinScope<'_, '_>, _args: v8::FunctionCallbackArguments, _rv: v8::ReturnValue, ) { @@ -311,7 +313,7 @@ fn cppgc_cell() { } fn op_unwrap( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope<'_, '_>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -335,7 +337,7 @@ fn cppgc_cell() { let isolate = &mut v8::Isolate::new(v8::CreateParams::default()); { - let handle_scope = &mut v8::HandleScope::new(isolate); + v8::scope!(handle_scope, isolate); let context = v8::Context::new(handle_scope, Default::default()); let scope = &mut v8::ContextScope::new(handle_scope, context); let global = context.global(scope); diff --git a/tests/test_external_deserialize.rs b/tests/test_external_deserialize.rs index 69d798d397..4911d925a2 100644 --- a/tests/test_external_deserialize.rs +++ b/tests/test_external_deserialize.rs @@ -1,7 +1,7 @@ use v8::MapFnTo; fn callback( - scope: &mut v8::HandleScope, + scope: &mut v8::PinScope<'_, '_>, args: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { @@ -33,7 +33,8 @@ fn external_deserialize() { ); { - let scope = &mut v8::HandleScope::new(&mut isolate); + v8::scope!(let scope, &mut isolate); + let context = v8::Context::new(scope, Default::default()); scope.set_default_context(context); @@ -86,7 +87,8 @@ fn external_deserialize() { ); { - let scope = &mut v8::HandleScope::new(&mut isolate_b); + v8::scope!(let scope, &mut isolate_b); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); diff --git a/tests/test_platform_atomics_pump_message_loop.rs b/tests/test_platform_atomics_pump_message_loop.rs index 190791acd3..e645c21cce 100644 --- a/tests/test_platform_atomics_pump_message_loop.rs +++ b/tests/test_platform_atomics_pump_message_loop.rs @@ -6,7 +6,8 @@ fn atomics_pump_message_loop() { ); v8::V8::initialize(); let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); + let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = r#" diff --git a/tests/test_single_threaded_default_platform.rs b/tests/test_single_threaded_default_platform.rs index a1e43a012e..8717ae53b7 100644 --- a/tests/test_single_threaded_default_platform.rs +++ b/tests/test_single_threaded_default_platform.rs @@ -8,7 +8,7 @@ fn single_threaded_default_platform() { { let isolate = &mut v8::Isolate::new(Default::default()); - let scope = &mut v8::HandleScope::new(isolate); + v8::scope!(let scope, isolate); let context = v8::Context::new(scope, Default::default()); let scope = &mut v8::ContextScope::new(scope, context); let source = v8::String::new(scope, "Math.random()").unwrap();