vendor(v8): add browsing context lifecycle bridges

This commit is contained in:
ldm0
2026-09-03 04:15:22 +08:00
parent 2a56edc48d
commit 073bbb9899
6 changed files with 175 additions and 1 deletions
+8
View File
@@ -28,6 +28,7 @@ unsafe extern "C" {
) -> *const Context;
fn v8__Isolate__GetCurrent() -> *mut RealIsolate;
fn v8__Context__Global(this: *const Context) -> *const Object;
fn v8__Context__DetachGlobal(this: *const Context);
fn v8__Context__GetExtrasBindingObject(this: *const Context)
-> *const Object;
fn v8__Context__GetNumberOfEmbedderDataFields(this: *const Context) -> u32;
@@ -143,6 +144,13 @@ impl Context {
unsafe { scope.cast_local(|_| v8__Context__Global(self)) }.unwrap()
}
/// Detaches this context's global proxy so its identity can be reused by a
/// subsequently created context.
#[inline(always)]
pub fn detach_global(&self) {
unsafe { v8__Context__DetachGlobal(self) }
}
/// Returns the microtask queue associated with this context.
///
/// Returns `None` if the context has no microtask queue, which is the case
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2026 the Moli authors. MIT license.
#include "support.h"
#include "v8-context.h"
#include "v8-isolate.h"
using namespace support;
static_assert(sizeof(v8::Context::BackupIncumbentScope) ==
sizeof(size_t) * 3,
"BackupIncumbentScope size mismatch");
extern "C" {
void v8__Context__BackupIncumbentScope__CONSTRUCT(
uninit_t<v8::Context::BackupIncumbentScope>* buf,
const v8::Context& context) {
construct_in_place<v8::Context::BackupIncumbentScope>(buf,
ptr_to_local(&context));
}
void v8__Context__BackupIncumbentScope__DESTRUCT(
v8::Context::BackupIncumbentScope* self) {
self->~BackupIncumbentScope();
}
void v8__Context__DetachGlobal(const v8::Context& self) {
ptr_to_local(&self)->DetachGlobal();
}
const v8::Context* v8__Isolate__GetIncumbentContext(v8::Isolate* isolate) {
return local_to_ptr(isolate->GetIncumbentContext());
}
void v8__Isolate__SetFailedAccessCheckCallbackFunction(
v8::Isolate* isolate, v8::FailedAccessCheckCallback callback) {
isolate->SetFailedAccessCheckCallbackFunction(callback);
}
} // extern "C"
+33 -1
View File
@@ -82,10 +82,23 @@ use std::sync::atomic::AtomicUsize;
#[repr(C)]
pub enum MicrotasksPolicy {
Explicit = 0,
// Scoped = 1 (RAII) is omitted for now, doesn't quite map to idiomatic Rust.
Scoped = 1,
Auto = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum AccessType {
Get,
Set,
Has,
Delete,
Keys,
}
pub type FailedAccessCheckCallback =
unsafe extern "C" fn(Local<Object>, AccessType, Local<Value>);
/// Memory pressure level for the MemoryPressureNotification.
/// None hints V8 that there is no memory pressure.
/// Moderate hints V8 to speed up incremental garbage collection at the cost
@@ -819,6 +832,10 @@ unsafe extern "C" {
isolate: *mut RealIsolate,
callback: RawModifyCodeGenerationFromStringsCallback,
);
fn v8__Isolate__SetFailedAccessCheckCallbackFunction(
isolate: *mut RealIsolate,
callback: FailedAccessCheckCallback,
);
fn v8__Isolate__RequestInterrupt(
isolate: *const RealIsolate,
callback: InterruptCallback,
@@ -905,6 +922,21 @@ impl UnsafeRawIsolatePtr {
pub struct RealIsolate(Opaque);
impl Isolate {
/// Installs the callback invoked when an object access check fails and no
/// failed-access interceptor handles the operation.
#[inline(always)]
pub fn set_failed_access_check_callback_function(
&mut self,
callback: FailedAccessCheckCallback,
) {
unsafe {
v8__Isolate__SetFailedAccessCheckCallbackFunction(
self.as_real_ptr(),
callback,
)
}
}
pub(crate) fn as_real_ptr(&self) -> *mut RealIsolate {
self.0.as_ptr()
}
+3
View File
@@ -109,6 +109,8 @@ pub use handle::SealedLocal;
pub use handle::TracedReference;
pub use handle::Weak;
pub use isolate::GarbageCollectionType;
pub use isolate::AccessType;
pub use isolate::FailedAccessCheckCallback;
pub use isolate::HeapCodeStatistics;
pub use isolate::HeapSpaceStatistics;
pub use isolate::HeapStatistics;
@@ -162,6 +164,7 @@ pub use property_filter::*;
pub use property_handler_flags::*;
pub use regexp::RegExpCreationFlags;
pub use scope::AllowJavascriptExecutionScope;
pub use scope::BackupIncumbentScope;
// pub use scope::CallbackScope;
pub use scope::CallbackScope;
pub use scope::ContextScope;
+51
View File
@@ -340,6 +340,12 @@ mod get_isolate_impls {
}
}
impl GetIsolate for Local<'_, Object> {
fn get_isolate_ptr(&self) -> *mut RealIsolate {
unsafe { raw::v8__Isolate__GetCurrent() }
}
}
impl GetIsolate for Local<'_, Message> {
fn get_isolate_ptr(&self) -> *mut RealIsolate {
unsafe { raw::v8__Isolate__GetCurrent() }
@@ -563,6 +569,15 @@ impl<'s> PinnedRef<'s, HandleScope<'_>> {
unsafe { Local::from_raw_unchecked(context_ptr) }
}
/// Returns the context corresponding to the incumbent Realm in the HTML
/// specification.
pub fn get_incumbent_context(&self) -> Option<Local<'s, Context>> {
let context_ptr = unsafe {
raw::v8__Isolate__GetIncumbentContext(self.0.isolate.as_ptr())
};
unsafe { Local::from_raw(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`.
@@ -789,6 +804,42 @@ impl<P: ClearCachedContext> DerefMut for ContextScope<'_, '_, P> {
impl<P: ClearCachedContext> sealed::Sealed for ContextScope<'_, '_, P> {}
impl<P: ClearCachedContext> Scope for ContextScope<'_, '_, P> {}
/// Pushes a context onto V8's backup incumbent settings object stack.
///
/// V8 links this object into an isolate-owned stack by its address. Pin the
/// returned `ScopeStorage` before calling `init()` and keep it alive until the
/// callback invocation completes.
pub struct BackupIncumbentScope<'s> {
raw: raw::BackupIncumbentScope,
context: Local<'s, Context>,
_pinned: PhantomPinned,
}
impl<'s> BackupIncumbentScope<'s> {
pub fn new(context: Local<'s, Context>) -> ScopeStorage<Self> {
ScopeStorage::new(Self {
raw: unsafe { raw::BackupIncumbentScope::uninit() },
context,
_pinned: PhantomPinned,
})
}
}
impl ScopeInit for BackupIncumbentScope<'_> {
fn init_stack(storage: Pin<&mut ScopeStorage<Self>>) -> Pin<&mut Self> {
let storage_mut = unsafe { storage.get_unchecked_mut() };
let context = storage_mut.scope.context;
unsafe {
storage_mut.scope.raw.init(context);
Pin::new_unchecked(&mut storage_mut.scope)
}
}
unsafe fn deinit(me: &mut Self) {
unsafe { me.raw.deinit() };
}
}
mod new_context_scope {
use super::{GetIsolate, Scope};
+40
View File
@@ -36,6 +36,36 @@ impl Drop for ContextScope {
}
}
#[repr(C)]
#[derive(Debug)]
pub(super) struct BackupIncumbentScope([MaybeUninit<usize>; 3]);
impl BackupIncumbentScope {
/// Creates uninitialized storage for V8's stack-address-sensitive scope.
///
/// The returned value must be pinned before `init()` constructs the C++
/// object in place.
pub unsafe fn uninit() -> Self {
Self(unsafe { MaybeUninit::uninit().assume_init() })
}
/// # Safety
///
/// `self` must be pinned at its final address and initialized exactly once.
pub unsafe fn init(&mut self, context: Local<Context>) {
unsafe {
v8__Context__BackupIncumbentScope__CONSTRUCT(self, &*context);
}
}
/// # Safety
///
/// `self` must have been initialized by `init()` and must not have moved.
pub unsafe fn deinit(&mut self) {
unsafe { v8__Context__BackupIncumbentScope__DESTRUCT(self) };
}
}
#[cfg(feature = "v8_enable_v8_checks")]
pub const HANDLE_SCOPE_SIZE: usize = 4;
#[cfg(not(feature = "v8_enable_v8_checks"))]
@@ -227,6 +257,9 @@ unsafe extern "C" {
pub(super) fn v8__Isolate__GetEnteredOrMicrotaskContext(
isolate: *mut RealIsolate,
) -> *const Context;
pub(super) fn v8__Isolate__GetIncumbentContext(
isolate: *mut RealIsolate,
) -> *const Context;
pub(super) fn v8__Isolate__ThrowException(
isolate: *mut RealIsolate,
exception: *const Value,
@@ -241,6 +274,13 @@ unsafe extern "C" {
pub(super) fn v8__Context__Enter(this: *const Context);
pub(super) fn v8__Context__Exit(this: *const Context);
pub(super) fn v8__Context__BackupIncumbentScope__CONSTRUCT(
buf: *mut BackupIncumbentScope,
context: *const Context,
);
pub(super) fn v8__Context__BackupIncumbentScope__DESTRUCT(
this: *mut BackupIncumbentScope,
);
pub(super) fn v8__Context__GetDataFromSnapshotOnce(
this: *const Context,
index: usize,