0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-27 16:11:06 -05:00

Rolling to V8 12.9.202.1 (#1579)

* Rolling to V8 12.9.202.1

* initial changes for 12.9

* CallbackScope for fast fns

* disable broken thing by default

* use windows 2022 runner

---------

Co-authored-by: snek <the@snek.dev>
This commit is contained in:
denobot 2024-08-20 10:48:10 -04:00 committed by GitHub
parent 1f5ebd9c4e
commit 3d29396d72
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 98 additions and 151 deletions

View file

@ -62,7 +62,7 @@ jobs:
variant: release variant: release
cargo: cargo cargo: cargo
- os: ${{ github.repository == 'denoland/rusty_v8' && 'windows-2019-xxl' || 'windows-2019' }} - os: ${{ github.repository == 'denoland/rusty_v8' && 'windows-2022-xxl' || 'windows-2022' }}
target: x86_64-pc-windows-msvc target: x86_64-pc-windows-msvc
variant: release # Note: we do not support windows debug builds. variant: release # Note: we do not support windows debug builds.
cargo: cargo cargo: cargo

3
.gitmodules vendored
View file

@ -19,9 +19,6 @@
[submodule "buildtools"] [submodule "buildtools"]
path = buildtools path = buildtools
url = https://chromium.googlesource.com/chromium/src/buildtools.git url = https://chromium.googlesource.com/chromium/src/buildtools.git
[submodule "third_party/zlib"]
path = third_party/zlib
url = https://chromium.googlesource.com/chromium/src/third_party/zlib.git
[submodule "third_party/icu"] [submodule "third_party/icu"]
path = third_party/icu path = third_party/icu
url = https://github.com/denoland/icu.git url = https://github.com/denoland/icu.git

View file

@ -1,6 +1,6 @@
# Rusty V8 Binding # Rusty V8 Binding
V8 Version: 12.8.374.16 V8 Version: 12.9.202.1
[![ci](https://github.com/denoland/rusty_v8/workflows/ci/badge.svg?branch=main)](https://github.com/denoland/rusty_v8/actions) [![ci](https://github.com/denoland/rusty_v8/workflows/ci/badge.svg?branch=main)](https://github.com/denoland/rusty_v8/actions)
[![crates](https://img.shields.io/crates/v/v8.svg)](https://crates.io/crates/v8) [![crates](https://img.shields.io/crates/v/v8.svg)](https://crates.io/crates/v8)

2
build

@ -1 +1 @@
Subproject commit 8cc2df0e909d0365e20cc0869e565149a723d2ca Subproject commit c6d44e625aa64fa89cbdc971dfd301353bee04f3

View file

@ -47,7 +47,7 @@ fn main() {
"PYTHON", "PYTHON",
"DISABLE_CLANG", "DISABLE_CLANG",
"EXTRA_GN_ARGS", "EXTRA_GN_ARGS",
"NO_PRINT_GN_ARGS", "PRINT_GN_ARGS",
"CARGO_ENCODED_RUSTFLAGS", "CARGO_ENCODED_RUSTFLAGS",
]; ];
for env in envs { for env in envs {
@ -313,7 +313,7 @@ fn build_v8(is_asan: bool) {
let gn_out = maybe_gen(gn_args); let gn_out = maybe_gen(gn_args);
assert!(gn_out.exists()); assert!(gn_out.exists());
assert!(gn_out.join("args.gn").exists()); assert!(gn_out.join("args.gn").exists());
if env::var_os("NO_PRINT_GN_ARGS").is_none() { if env_bool("PRINT_GN_ARGS") {
print_gn_args(&gn_out); print_gn_args(&gn_out);
} }
build("rusty_v8", None); build("rusty_v8", None);

@ -1 +1 @@
Subproject commit 3ef44a2b92d5dd1faa5189a06f3a5febe6db2d58 Subproject commit 60a590902cf146c282f15242401bd8543256e2a2

View file

@ -33,6 +33,9 @@ EACH_TYPED_ARRAY(TYPED_ARRAY_MAX_LENGTH)
using v8__CFunction = v8::CFunction; using v8__CFunction = v8::CFunction;
using v8__CFunctionInfo = v8::CFunctionInfo; using v8__CFunctionInfo = v8::CFunctionInfo;
using v8__FastApiArrayBufferView = v8::FastApiArrayBufferView;
using v8__FastOneByteString = v8::FastOneByteString;
using v8__FastApiTypedArray = v8::FastApiTypedArray<void>;
using v8__Isolate__UseCounterFeature = v8::Isolate::UseCounterFeature; using v8__Isolate__UseCounterFeature = v8::Isolate::UseCounterFeature;

View file

@ -1,9 +1,9 @@
use std::ffi::c_void;
use crate::binding::*; use crate::binding::*;
use crate::Isolate; use crate::Isolate;
use crate::Local; use crate::Local;
use crate::Value; use crate::Value;
use std::ffi::c_void;
use std::marker::PhantomData;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
@ -140,42 +140,26 @@ bitflags::bitflags! {
#[repr(C)] #[repr(C)]
pub struct FastApiCallbackOptions<'a> { pub struct FastApiCallbackOptions<'a> {
pub isolate: *mut Isolate, pub isolate: *mut Isolate,
/// If the callback wants to signal an error condition or to perform an
/// allocation, it must set options.fallback to true and do an early return
/// from the fast method. Then V8 checks the value of options.fallback and if
/// it's true, falls back to executing the SlowCallback, which is capable of
/// reporting the error (either by throwing a JS exception or logging to the
/// console) or doing the allocation. It's the embedder's responsibility to
/// ensure that the fast callback is idempotent up to the point where error and
/// fallback conditions are checked, because otherwise executing the slow
/// callback might produce visible side-effects twice.
pub fallback: bool,
/// The `data` passed to the FunctionTemplate constructor, or `undefined`. /// The `data` passed to the FunctionTemplate constructor, or `undefined`.
pub data: Local<'a, Value>, pub data: Local<'a, Value>,
/// When called from WebAssembly, a view of the calling module's memory.
pub wasm_memory: *const FastApiTypedArray<u8>,
} }
// https://source.chromium.org/chromium/chromium/src/+/main:v8/include/v8-fast-api-calls.h;l=336 #[allow(unused)] // only constructed by V8
#[repr(C)] #[repr(transparent)]
pub struct FastApiTypedArray<T: Default> { pub struct FastApiTypedArray<T: Default>(v8__FastApiTypedArray, PhantomData<T>);
/// Returns the length in number of elements.
pub length: usize,
// This pointer should include the typed array offset applied.
// It's not guaranteed that it's aligned to sizeof(T), it's only
// guaranteed that it's 4-byte aligned, so for 8-byte types we need to
// provide a special implementation for reading from it, which hides
// the possibly unaligned read in the `get` method.
data: *mut T,
}
impl<T: Default> FastApiTypedArray<T> { impl<T: Default> FastApiTypedArray<T> {
/// Returns the length in number of elements.
pub const fn length(&self) -> usize {
self.0._base.length_
}
/// Performs an unaligned-safe read of T from the underlying data. /// Performs an unaligned-safe read of T from the underlying data.
#[inline(always)] #[inline(always)]
pub const fn get(&self, index: usize) -> T { pub const fn get(&self, index: usize) -> T {
debug_assert!(index < self.length); debug_assert!(index < self.length());
// SAFETY: src is valid for reads, and is a valid value for T // SAFETY: src is valid for reads, and is a valid value for T
unsafe { std::ptr::read_unaligned(self.data.add(index)) } unsafe { std::ptr::read_unaligned((self.0.data_ as *const T).add(index)) }
} }
/// Returns a slice pointing to the underlying data if safe to do so. /// Returns a slice pointing to the underlying data if safe to do so.
@ -183,14 +167,16 @@ impl<T: Default> FastApiTypedArray<T> {
pub fn get_storage_if_aligned(&self) -> Option<&mut [T]> { pub fn get_storage_if_aligned(&self) -> Option<&mut [T]> {
// V8 may provide an invalid or null pointer when length is zero, so we just // V8 may provide an invalid or null pointer when length is zero, so we just
// ignore that value completely and create an empty slice in this case. // ignore that value completely and create an empty slice in this case.
if self.length == 0 { if self.length() == 0 {
return Some(&mut []); return Some(&mut []);
} }
let data = self.0.data_ as *mut T;
// Ensure that we never return an unaligned or null buffer // Ensure that we never return an unaligned or null buffer
if self.data.is_null() || (self.data as usize) % align_of::<T>() != 0 { if data.is_null() || !data.is_aligned() {
return None; None
} else {
Some(unsafe { std::slice::from_raw_parts_mut(data, self.length()) })
} }
Some(unsafe { std::slice::from_raw_parts_mut(self.data, self.length) })
} }
} }
@ -200,19 +186,9 @@ impl<T: Default> FastApiTypedArray<T> {
/// own instance type. It could be supported if we specify that /// own instance type. It could be supported if we specify that
/// TypedArray<T> always has precedence over the generic ArrayBufferView, /// TypedArray<T> always has precedence over the generic ArrayBufferView,
/// but this complicates overload resolution. /// but this complicates overload resolution.
#[repr(C)] pub type FastApiArrayBufferView = v8__FastApiArrayBufferView;
pub struct FastApiArrayBufferView {
pub data: *mut c_void,
pub byte_length: usize,
}
// FastApiOneByteString is an alias for SeqOneByteString and the type is widely used in deno_core. pub type FastApiOneByteString = v8__FastOneByteString;
#[allow(unused)]
#[repr(C)]
pub struct FastApiOneByteString {
data: *const u8,
pub length: u32,
}
impl FastApiOneByteString { impl FastApiOneByteString {
#[inline(always)] #[inline(always)]
@ -224,6 +200,6 @@ impl FastApiOneByteString {
} }
// SAFETY: The data is guaranteed to be valid for the length of the string. // SAFETY: The data is guaranteed to be valid for the length of the string.
unsafe { std::slice::from_raw_parts(self.data, self.length as usize) } unsafe { std::slice::from_raw_parts(self.data as _, self.length as usize) }
} }
} }

View file

@ -102,6 +102,7 @@ use std::ops::DerefMut;
use std::ptr; use std::ptr;
use std::ptr::NonNull; use std::ptr::NonNull;
use crate::fast_api::FastApiCallbackOptions;
use crate::function::FunctionCallbackInfo; use crate::function::FunctionCallbackInfo;
use crate::function::PropertyCallbackInfo; use crate::function::PropertyCallbackInfo;
use crate::Context; use crate::Context;
@ -628,6 +629,7 @@ where
/// - `&FunctionCallbackInfo` /// - `&FunctionCallbackInfo`
/// - `&PropertyCallbackInfo` /// - `&PropertyCallbackInfo`
/// - `&PromiseRejectMessage` /// - `&PromiseRejectMessage`
/// - `&FastApiCallbackOptions`
#[derive(Debug)] #[derive(Debug)]
pub struct CallbackScope<'s, C = Context> { pub struct CallbackScope<'s, C = Context> {
_data: NonNull<data::ScopeData>, _data: NonNull<data::ScopeData>,
@ -637,10 +639,23 @@ pub struct CallbackScope<'s, C = Context> {
impl<'s> CallbackScope<'s> { impl<'s> CallbackScope<'s> {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub unsafe fn new<P: param::NewCallbackScope<'s>>(param: P) -> P::NewScope { pub unsafe fn new<P: param::NewCallbackScope<'s>>(param: P) -> P::NewScope {
let (isolate, context) = param.get_isolate_mut_and_maybe_current_context(); let context = param.get_context();
data::ScopeData::get_current_mut(isolate) let scope_data = data::ScopeData::get_current_mut(param.get_isolate_mut());
.new_callback_scope_data(context) // A HandleScope is not implicitly created for
.as_scope() // 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()
} }
} }
@ -1160,11 +1175,10 @@ mod param {
pub trait NewCallbackScope<'s>: Sized + getter::GetIsolate<'s> { pub trait NewCallbackScope<'s>: Sized + getter::GetIsolate<'s> {
type NewScope: Scope; type NewScope: Scope;
const NEEDS_SCOPE: bool = false;
unsafe fn get_isolate_mut_and_maybe_current_context( fn get_context(&self) -> Option<Local<'s, Context>> {
self, None
) -> (&'s mut Isolate, Option<Local<'s, Context>>) {
(self.get_isolate_mut(), None)
} }
} }
@ -1184,13 +1198,16 @@ mod param {
type NewScope = CallbackScope<'s>; type NewScope = CallbackScope<'s>;
} }
impl<'s> NewCallbackScope<'s> for &'s FastApiCallbackOptions<'s> {
type NewScope = CallbackScope<'s>;
const NEEDS_SCOPE: bool = true;
}
impl<'s> NewCallbackScope<'s> for Local<'s, Context> { impl<'s> NewCallbackScope<'s> for Local<'s, Context> {
type NewScope = CallbackScope<'s>; type NewScope = CallbackScope<'s>;
unsafe fn get_isolate_mut_and_maybe_current_context( fn get_context(&self) -> Option<Local<'s, Context>> {
self, Some(*self)
) -> (&'s mut Isolate, Option<Local<'s, Context>>) {
(getter::GetIsolate::get_isolate_mut(self), Some(self))
} }
} }
@ -1241,6 +1258,12 @@ mod getter {
} }
} }
impl<'s> GetIsolate<'s> for &'s FastApiCallbackOptions<'s> {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *self.isolate
}
}
impl<'s> GetIsolate<'s> for Local<'s, Context> { impl<'s> GetIsolate<'s> for Local<'s, Context> {
unsafe fn get_isolate_mut(self) -> &'s mut Isolate { unsafe fn get_isolate_mut(self) -> &'s mut Isolate {
&mut *raw::v8__Context__GetIsolate(&*self) &mut *raw::v8__Context__GetIsolate(&*self)
@ -1405,6 +1428,7 @@ pub(crate) mod data {
let isolate = data.isolate; let isolate = data.isolate;
data.scope_type_specific_data.init_with(|| { data.scope_type_specific_data.init_with(|| {
ScopeTypeSpecificData::HandleScope { ScopeTypeSpecificData::HandleScope {
allow_zombie: true,
raw_handle_scope: unsafe { raw::HandleScope::uninit() }, raw_handle_scope: unsafe { raw::HandleScope::uninit() },
raw_context_scope: None, raw_context_scope: None,
} }
@ -1413,6 +1437,7 @@ pub(crate) mod data {
ScopeTypeSpecificData::HandleScope { ScopeTypeSpecificData::HandleScope {
raw_handle_scope, raw_handle_scope,
raw_context_scope, raw_context_scope,
..
} => { } => {
unsafe { raw_handle_scope.init(isolate) }; unsafe { raw_handle_scope.init(isolate) };
init_context_fn(isolate, &mut data.context, raw_context_scope); init_context_fn(isolate, &mut data.context, raw_context_scope);
@ -1422,6 +1447,15 @@ pub(crate) mod data {
}) })
} }
#[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)] #[inline(always)]
pub(super) fn new_handle_scope_data(&mut self) -> &mut Self { pub(super) fn new_handle_scope_data(&mut self) -> &mut Self {
self.new_handle_scope_data_with(|_, _, raw_context_scope| { self.new_handle_scope_data_with(|_, _, raw_context_scope| {
@ -1732,7 +1766,9 @@ pub(crate) mod data {
#[inline(always)] #[inline(always)]
pub(super) fn notify_scope_dropped(&mut self) { pub(super) fn notify_scope_dropped(&mut self) {
match &self.scope_type_specific_data { match &self.scope_type_specific_data {
ScopeTypeSpecificData::HandleScope { .. } ScopeTypeSpecificData::HandleScope {
allow_zombie: true, ..
}
| ScopeTypeSpecificData::EscapableHandleScope { .. } => { | ScopeTypeSpecificData::EscapableHandleScope { .. } => {
// Defer scope exit until the parent scope is touched. // Defer scope exit until the parent scope is touched.
self.status.set(match self.status.get() { self.status.set(match self.status.get() {
@ -1864,6 +1900,7 @@ pub(crate) mod data {
_raw_context_scope: raw::ContextScope, _raw_context_scope: raw::ContextScope,
}, },
HandleScope { HandleScope {
allow_zombie: bool,
raw_handle_scope: raw::HandleScope, raw_handle_scope: raw::HandleScope,
raw_context_scope: Option<raw::ContextScope>, raw_context_scope: Option<raw::ContextScope>,
}, },

View file

@ -10451,7 +10451,13 @@ fn host_create_shadow_realm_context_callback() {
#[test] #[test]
fn test_fast_calls() { fn test_fast_calls() {
static mut WHO: &str = "none"; static mut WHO: &str = "none";
fn fast_fn(_recv: v8::Local<v8::Object>, a: u32, b: u32) -> u32 { fn fast_fn(
_recv: v8::Local<v8::Object>,
a: u32,
b: u32,
options: &v8::fast_api::FastApiCallbackOptions,
) -> u32 {
let _scope = unsafe { v8::CallbackScope::new(options) };
unsafe { WHO = "fast" }; unsafe { WHO = "fast" };
a + b a + b
} }
@ -10464,6 +10470,7 @@ fn test_fast_calls() {
fast_api::Type::V8Value.scalar(), fast_api::Type::V8Value.scalar(),
fast_api::Type::Uint32.scalar(), fast_api::Type::Uint32.scalar(),
fast_api::Type::Uint32.scalar(), fast_api::Type::Uint32.scalar(),
fast_api::Type::CallbackOptions.scalar(),
], ],
fast_api::Int64Representation::Number, fast_api::Int64Representation::Number,
), ),
@ -10887,7 +10894,7 @@ fn test_fast_calls_overload() {
) { ) {
unsafe { WHO = "fast_buf" }; unsafe { WHO = "fast_buf" };
let buf = unsafe { &*data }; let buf = unsafe { &*data };
assert_eq!(buf.length, 2); assert_eq!(buf.length(), 2);
assert_eq!(buf.get(0), 6); assert_eq!(buf.get(0), 6);
assert_eq!(buf.get(1), 9); assert_eq!(buf.get(1), 9);
} }
@ -10977,77 +10984,6 @@ fn test_fast_calls_overload() {
assert_eq!("fast_array", unsafe { WHO }); assert_eq!("fast_array", unsafe { WHO });
} }
#[test]
fn test_fast_calls_callback_options_fallback() {
static mut WHO: &str = "none";
fn fast_fn(
_recv: v8::Local<v8::Object>,
options: *mut fast_api::FastApiCallbackOptions,
) {
if unsafe { WHO == "fast" } {
let options = unsafe { &mut *options };
options.fallback = true; // Go back to slow path.
} else {
unsafe { WHO = "fast" };
}
}
const FAST_TEST: fast_api::CFunction = fast_api::CFunction::new(
fast_fn as _,
&fast_api::CFunctionInfo::new(
fast_api::Type::Void.scalar(),
&[
fast_api::Type::V8Value.scalar(),
fast_api::Type::CallbackOptions.scalar(),
],
fast_api::Int64Representation::Number,
),
);
fn slow_fn(
scope: &mut v8::HandleScope,
_: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue<v8::Value>,
) {
unsafe { WHO = "slow" };
rv.set(v8::Boolean::new(scope, false).into());
}
let _setup_guard = setup::parallel_test();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
let global = context.global(scope);
let template =
v8::FunctionTemplate::builder(slow_fn).build_fast(scope, &[FAST_TEST]);
let name = v8::String::new(scope, "func").unwrap();
let value = template.get_function(scope).unwrap();
global.set(scope, name.into(), value.into()).unwrap();
let source = r#"
function f() { return func(); }
%PrepareFunctionForOptimization(f);
f();
"#;
eval(scope, source).unwrap();
assert_eq!("slow", unsafe { WHO });
let source = r#"
%OptimizeFunctionOnNextCall(f);
f();
"#;
eval(scope, source).unwrap();
assert_eq!("fast", unsafe { WHO });
let source = r#"
f(); // Second call fallbacks back to slow path.
"#;
eval(scope, source).unwrap();
assert_eq!("slow", unsafe { WHO });
}
#[test] #[test]
fn test_fast_calls_callback_options_data() { fn test_fast_calls_callback_options_data() {
static mut DATA: bool = false; static mut DATA: bool = false;
@ -11057,7 +10993,6 @@ fn test_fast_calls_callback_options_data() {
) { ) {
let options = &mut *options; let options = &mut *options;
if !options.data.is_external() { if !options.data.is_external() {
options.fallback = true;
return; return;
} }
@ -11079,11 +11014,10 @@ fn test_fast_calls_callback_options_data() {
); );
fn slow_fn( fn slow_fn(
scope: &mut v8::HandleScope, _: &mut v8::HandleScope,
_: v8::FunctionCallbackArguments, _: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue<v8::Value>, _: v8::ReturnValue<v8::Value>,
) { ) {
rv.set(v8::Boolean::new(scope, false).into());
} }
let _setup_guard = setup::parallel_test(); let _setup_guard = setup::parallel_test();

@ -1 +1 @@
Subproject commit 9d1552f25c3d9e9114b7d7aed55790570a99bc4d Subproject commit ed3733b91e472a1e7a641c1f0c1e6c0ea698e958

@ -1 +1 @@
Subproject commit 6bb75caa139ee1e686d2205910454cf6ea212e58 Subproject commit f801c947082a3e0a4b48780303526b73905f6ecd

@ -1 +1 @@
Subproject commit a3c7d3e2f3e1e724b4651891b1a71257cbd88acc Subproject commit eb6567388e89d9730c76dee71d68ac82e4a1abf6

@ -1 +1 @@
Subproject commit d09db732ff68f40fd3581306c650b17ea1955b4e Subproject commit 116c20dae60d84a77005697cf29f72783f81b0f9

@ -1 +1 @@
Subproject commit 4dc76da47b1145e53e508a23c1bf2204cf5ee7ee Subproject commit 63b7be17f8981d716ea9a0d65bb04654d79548a8

View file

@ -7,7 +7,7 @@ with open('./v8/DEPS') as f:
import subprocess import subprocess
def process(name, dep): def process(name, dep):
if name == 'build': if name == 'build' or name == 'third_party/icu':
# We have our own fork of this # We have our own fork of this
return return

2
v8

@ -1 +1 @@
Subproject commit 8e78e913dfed43460b215473fe39db2fce46984e Subproject commit bc49fb862240af6bfa37dbbae09db7eafd3719e8