mirror of
https://github.com/lexmount/moli.git
synced 2026-11-15 08:08:07 +00:00
refactor(renderer): model pending and ready main worlds explicitly
This commit is contained in:
@@ -91,6 +91,13 @@ async def run_lazy_main_world_group(endpoint: str, _fixture: str,
|
||||
if "Native content" not in outer:
|
||||
raise SmokeError(f"native DOM query returned {outer!r}")
|
||||
if activation == "native-io":
|
||||
await wire.call("Emulation.setTouchEmulationEnabled", {
|
||||
"enabled": True, "maxTouchPoints": 7,
|
||||
}, session)
|
||||
await wire.call("Emulation.setEmulatedMedia", {
|
||||
"media": "print",
|
||||
"features": [{"name": "prefers-color-scheme", "value": "dark"}],
|
||||
}, session)
|
||||
await wire.call("Performance.enable", session=session)
|
||||
metrics = {m["name"]: m["value"] for m in
|
||||
(await wire.call("Performance.getMetrics", session=session))["metrics"]}
|
||||
@@ -120,6 +127,10 @@ async def run_lazy_main_world_group(endpoint: str, _fixture: str,
|
||||
assert_equal(observed, {"title": "Lazy activation", "state": "complete",
|
||||
"text": "Native content", "color": "rgb(0, 0, 255)"},
|
||||
"first main-world evaluation sees completed native Document")
|
||||
if activation == "native-io":
|
||||
assert_equal(await wire.evaluate(session, "({touch:navigator.maxTouchPoints, print:matchMedia('print').matches, dark:matchMedia('(prefers-color-scheme: dark)').matches})"),
|
||||
{"touch": 7, "print": True, "dark": True},
|
||||
"native emulation survives the first main-world activation")
|
||||
if activation in ("preload", "deferred-script", "inline-load"):
|
||||
assert_equal(await wire.evaluate(session, "activationCount"), 1,
|
||||
"initial script runs exactly once")
|
||||
|
||||
@@ -337,11 +337,11 @@ impl PageVm {
|
||||
Ok(RendererPageReply::Unit)
|
||||
}
|
||||
RendererPageCommand::DefaultExecutionContextId => {
|
||||
self.vm_mut().initialize_main_world_if_needed()?;
|
||||
self.vm_mut().ensure_main_world()?;
|
||||
Ok(RendererPageReply::OptionalExecutionContextId(self.default_execution_context_id()))
|
||||
}
|
||||
RendererPageCommand::DefaultOrInitialExecutionContextId => {
|
||||
self.vm_mut().initialize_main_world_if_needed()?;
|
||||
self.vm_mut().ensure_main_world()?;
|
||||
Ok(RendererPageReply::OptionalExecutionContextId(self.default_or_initial_execution_context_id()))
|
||||
}
|
||||
RendererPageCommand::HasIsolatedWorldNamed { name, frame_id } => {
|
||||
@@ -370,7 +370,7 @@ impl PageVm {
|
||||
self.isolated_execution_context_id_for_inspector_context(execution_context_id),
|
||||
)),
|
||||
RendererPageCommand::RuntimeRealmInventory => {
|
||||
self.vm_mut().initialize_main_world_if_needed()?;
|
||||
self.vm_mut().ensure_main_world()?;
|
||||
Ok(RendererPageReply::RuntimeRealmInventory(self.runtime_realm_inventory()))
|
||||
}
|
||||
RendererPageCommand::LiveChildDefaultRuntimeRealmInventory => {
|
||||
|
||||
@@ -115,6 +115,58 @@ async fn evaluate_lazy_test(page: &RendererPageHandle, source: &str) -> serde_js
|
||||
renderer_json_value(reply).expect("evaluation returns a JSON value")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn native_environment_updates_survive_main_world_activation() {
|
||||
let (_runtime, mut page) = lazy_test_page(
|
||||
"<!doctype html><p>Native environment before script</p>",
|
||||
Default::default(),
|
||||
)
|
||||
.await;
|
||||
assert_main_world_count(&page, 0).await;
|
||||
for command in [
|
||||
RendererPageCommand::SetNavigatorOverrides(moli_page_types::NavigatorOverrides {
|
||||
online: Some(false),
|
||||
max_touch_points: 7,
|
||||
..Default::default()
|
||||
}),
|
||||
RendererPageCommand::SetIdleOverride(Some(moli_page_types::EmulatedIdleOverride {
|
||||
is_user_active: false,
|
||||
is_screen_unlocked: false,
|
||||
})),
|
||||
RendererPageCommand::SetEmulatedMedia(moli_page_types::EmulatedMediaOverrides {
|
||||
media: Some("print".to_owned()),
|
||||
color_scheme: Some("dark".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
] {
|
||||
let (reply, _) = page.run_async_command(command).await.unwrap();
|
||||
assert!(matches!(reply, RendererPageReply::Unit));
|
||||
assert_main_world_count(&page, 0).await;
|
||||
}
|
||||
let expression = "JSON.stringify({online:navigator.onLine, touch:navigator.maxTouchPoints, print:matchMedia('print').matches, dark:matchMedia('(prefers-color-scheme: dark)').matches})";
|
||||
assert_eq!(
|
||||
evaluate_lazy_test(&page, expression).await,
|
||||
r#"{"online":false,"touch":7,"print":true,"dark":true}"#
|
||||
);
|
||||
assert_main_world_count(&page, 1).await;
|
||||
|
||||
page.run_async_command(RendererPageCommand::SetNavigatorOverrides(
|
||||
moli_page_types::NavigatorOverrides {
|
||||
online: Some(true),
|
||||
max_touch_points: 2,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
evaluate_lazy_test(&page, expression).await,
|
||||
r#"{"online":true,"touch":2,"print":true,"dark":true}"#
|
||||
);
|
||||
assert_main_world_count(&page, 1).await;
|
||||
page.close_async().await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn cold_runtime_binding_install_initializes_main_world() {
|
||||
for execution_context_id in [None, Some(0)] {
|
||||
|
||||
@@ -751,6 +751,7 @@ mod input_dispatch;
|
||||
mod input_helpers;
|
||||
mod inspector;
|
||||
mod main_world;
|
||||
use main_world::MainWorld;
|
||||
mod native_drag_data;
|
||||
pub(crate) use inspector::{dispatch_inspector_io_owner_wake, dispatch_inspector_main_owner_wake};
|
||||
mod document_context_transition;
|
||||
@@ -1015,15 +1016,12 @@ pub(super) struct ScriptVm {
|
||||
page_inspector: DocumentInspectorBinding,
|
||||
renderer_document_isolate_teardown: RendererDocumentIsolateTeardown,
|
||||
renderer_page_script_environment: Option<RendererPageScriptEnvironment>,
|
||||
page_default_runtime: WindowRealmRuntime,
|
||||
// Release the sizeable History/navigator seeds after the realm is initialized.
|
||||
pending_main_world: Option<Box<main_world::PendingMainWorld>>,
|
||||
main_world: MainWorld,
|
||||
page_isolated_world_contexts: PageIsolatedWorldRegistry,
|
||||
child_frame_realm_store: child_frame_realm::ChildFrameRealmStore,
|
||||
prebootstrapped_child_default_contexts: SharedPrebootstrappedChildDefaultContexts,
|
||||
child_document_modulator_store: ChildDocumentModulatorStore,
|
||||
root_frame_id: Option<String>,
|
||||
baseline_globals: ScriptGlobalsBaseline,
|
||||
// `JsContextHost` stores a non-owning pointer into `document_runtime`, so it
|
||||
// must be dropped before the runtime field during normal Rust field teardown.
|
||||
_context_host: Rc<RefCell<JsContextHost>>,
|
||||
@@ -1236,9 +1234,10 @@ impl ScriptVm {
|
||||
let mut context_ptrs: Vec<*const v8::Global<v8::Context>> = Vec::with_capacity(
|
||||
1 + self.page_isolated_world_contexts.len() + self.child_frame_realm_store.len(),
|
||||
);
|
||||
if self.main_world_is_initialized() {
|
||||
context_ptrs.push(&self.page_default_runtime.context as *const _);
|
||||
}
|
||||
context_ptrs.extend(
|
||||
self.current_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr),
|
||||
);
|
||||
context_ptrs.extend(
|
||||
self.page_isolated_world_contexts
|
||||
.contexts()
|
||||
@@ -1277,9 +1276,10 @@ impl ScriptVm {
|
||||
let mut context_ptrs: Vec<*const v8::Global<v8::Context>> = Vec::with_capacity(
|
||||
1 + self.page_isolated_world_contexts.len() + self.child_frame_realm_store.len(),
|
||||
);
|
||||
if self.main_world_is_initialized() {
|
||||
context_ptrs.push(&self.page_default_runtime.context as *const _);
|
||||
}
|
||||
context_ptrs.extend(
|
||||
self.current_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr),
|
||||
);
|
||||
context_ptrs.extend(
|
||||
self.page_isolated_world_contexts
|
||||
.contexts()
|
||||
@@ -1363,8 +1363,7 @@ impl ScriptVm {
|
||||
inspector_session_id: Option<&str>,
|
||||
object_id: &str,
|
||||
) -> Result<Option<DomHandle>> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let context_host = self._context_host.clone();
|
||||
let page_inspector = &self.page_inspector;
|
||||
let renderer_document_isolate = self.renderer_document_isolate.clone();
|
||||
@@ -1600,8 +1599,7 @@ impl ScriptVm {
|
||||
}))?,
|
||||
));
|
||||
}
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let runtime_binding_replay_context_ptrs = self.runtime_binding_replay_context_ptrs();
|
||||
let renderer_document_isolate = self.renderer_document_isolate.clone();
|
||||
let page_inspector = &mut self.page_inspector;
|
||||
@@ -1745,7 +1743,7 @@ impl ScriptVm {
|
||||
command_output: Option<crate::runtime::RendererRuntimeCommandOutputRecorder>,
|
||||
internal_dispatch_call_id: Option<i32>,
|
||||
) -> Result<Vec<RendererRuntimeInspectorMessage>> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let user_gesture = runtime_protocol_message_user_gesture(raw_json);
|
||||
let file_prompt_handler = runtime_protocol_message_file_prompt_handler(raw_json);
|
||||
if user_gesture {
|
||||
@@ -1770,6 +1768,7 @@ impl ScriptVm {
|
||||
.borrow_mut()
|
||||
.replace_active_inspector_dispatch(true);
|
||||
let result = self.dispatch_inspector_protocol_message_with_current_activation(
|
||||
context_ptr,
|
||||
target,
|
||||
raw_json,
|
||||
deferred_response,
|
||||
@@ -1807,6 +1806,7 @@ impl ScriptVm {
|
||||
|
||||
fn dispatch_inspector_protocol_message_with_current_activation(
|
||||
&mut self,
|
||||
context_ptr: *const v8::Global<v8::Context>,
|
||||
target: PageInspectorSessionTarget<'_>,
|
||||
raw_json: &str,
|
||||
deferred_response: Option<RendererRuntimeInspectorResponseSender>,
|
||||
@@ -1814,7 +1814,6 @@ impl ScriptVm {
|
||||
internal_dispatch_call_id: Option<i32>,
|
||||
) -> Result<Vec<RendererRuntimeInspectorMessage>> {
|
||||
let timing_started = moli_trace::cdp_nav_timing_enabled().then(Instant::now);
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let inspector_window_dispatch_scope =
|
||||
runtime_protocol_message_window_dispatch_target(raw_json)
|
||||
.and_then(|target| self.inspector_window_dispatch_scope_for_target(target));
|
||||
@@ -2270,7 +2269,7 @@ impl ScriptVmPageRealmBootstrap {
|
||||
inherited_security_token,
|
||||
resource_owner_id,
|
||||
promise_reject_dispatch,
|
||||
page_inspector,
|
||||
mut page_inspector,
|
||||
renderer_document_isolate,
|
||||
renderer_document_isolate_teardown,
|
||||
document_runtime,
|
||||
@@ -2284,16 +2283,46 @@ impl ScriptVmPageRealmBootstrap {
|
||||
renderer_page_script_environment,
|
||||
reuse_main_window_proxy,
|
||||
} = self;
|
||||
let mut bootstrap = ScriptVmDefaultWorldBootstrap {
|
||||
page_default_runtime: WindowRealmRuntime::uninitialized(
|
||||
renderer_document_isolate.deferred_context_host_release_queue(),
|
||||
),
|
||||
pending_main_world: Some(Box::new(main_world::PendingMainWorld {
|
||||
inherited_security_token,
|
||||
reuse_main_window_proxy,
|
||||
..Default::default()
|
||||
})),
|
||||
baseline_globals: Default::default(),
|
||||
let pending = Box::new(main_world::PendingMainWorld {
|
||||
inherited_security_token,
|
||||
reuse_main_window_proxy,
|
||||
..Default::default()
|
||||
});
|
||||
let main_world = if initialize_main_world {
|
||||
match main_world::initialize(
|
||||
&renderer_document_isolate,
|
||||
&context_host,
|
||||
resource_owner_id,
|
||||
&promise_reject_dispatch,
|
||||
storage_bucket_store.clone(),
|
||||
None,
|
||||
renderer_page_script_environment.clone(),
|
||||
root_frame_id.as_deref(),
|
||||
&mut page_inspector,
|
||||
&pending,
|
||||
) {
|
||||
Ok((runtime, baseline_globals)) => MainWorld::Ready {
|
||||
runtime,
|
||||
_baseline_globals: baseline_globals,
|
||||
},
|
||||
Err(error) => {
|
||||
drop(page_inspector);
|
||||
return Err(Box::new((
|
||||
error,
|
||||
recover_bootstrap_dom_host_from_holder(
|
||||
renderer_document_isolate,
|
||||
renderer_document_isolate_teardown,
|
||||
context_host,
|
||||
document_runtime,
|
||||
),
|
||||
)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MainWorld::Pending(pending)
|
||||
};
|
||||
Ok(ScriptVmDefaultWorldBootstrap {
|
||||
main_world,
|
||||
resource_owner_id,
|
||||
promise_reject_dispatch,
|
||||
page_inspector,
|
||||
@@ -2308,40 +2337,7 @@ impl ScriptVmPageRealmBootstrap {
|
||||
page_runtime_wake_tx,
|
||||
storage_bucket_store,
|
||||
renderer_page_script_environment,
|
||||
};
|
||||
if initialize_main_world {
|
||||
match main_world::initialize(
|
||||
&bootstrap.renderer_document_isolate,
|
||||
&bootstrap.context_host,
|
||||
bootstrap.resource_owner_id,
|
||||
&bootstrap.promise_reject_dispatch,
|
||||
bootstrap.storage_bucket_store.clone(),
|
||||
None,
|
||||
bootstrap.renderer_page_script_environment.clone(),
|
||||
bootstrap.root_frame_id.as_deref(),
|
||||
&mut bootstrap.page_inspector,
|
||||
bootstrap.pending_main_world.as_ref().unwrap(),
|
||||
) {
|
||||
Ok((runtime, baseline)) => {
|
||||
bootstrap.page_default_runtime = runtime;
|
||||
bootstrap.baseline_globals = baseline;
|
||||
bootstrap.pending_main_world = None;
|
||||
}
|
||||
Err(error) => {
|
||||
drop(bootstrap.page_inspector);
|
||||
return Err(Box::new((
|
||||
error,
|
||||
recover_bootstrap_dom_host_from_holder(
|
||||
bootstrap.renderer_document_isolate,
|
||||
bootstrap.renderer_document_isolate_teardown,
|
||||
bootstrap.context_host,
|
||||
bootstrap.document_runtime,
|
||||
),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(bootstrap)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2489,9 +2485,7 @@ impl ScriptVmDefaultWorldBootstrap {
|
||||
renderer_document_isolate,
|
||||
renderer_document_isolate_teardown,
|
||||
renderer_page_script_environment,
|
||||
page_default_runtime,
|
||||
pending_main_world,
|
||||
baseline_globals,
|
||||
main_world,
|
||||
document_runtime,
|
||||
context_host,
|
||||
prebootstrapped_child_default_contexts,
|
||||
@@ -2510,14 +2504,12 @@ impl ScriptVmDefaultWorldBootstrap {
|
||||
renderer_document_isolate,
|
||||
renderer_document_isolate_teardown,
|
||||
renderer_page_script_environment,
|
||||
page_default_runtime,
|
||||
pending_main_world,
|
||||
main_world,
|
||||
page_isolated_world_contexts: PageIsolatedWorldRegistry::new(),
|
||||
child_frame_realm_store: child_frame_realm::ChildFrameRealmStore::default(),
|
||||
prebootstrapped_child_default_contexts,
|
||||
child_document_modulator_store: ChildDocumentModulatorStore::default(),
|
||||
root_frame_id,
|
||||
baseline_globals,
|
||||
document_runtime: ScriptVmDocumentRuntimeOwner::new(document_runtime),
|
||||
_context_host: context_host,
|
||||
page_context_cancel_tx,
|
||||
@@ -2571,12 +2563,12 @@ impl ScriptVmDefaultWorldBootstrap {
|
||||
|
||||
pub fn finish(self) -> std::result::Result<ScriptVm, ScriptVmBootstrapError> {
|
||||
let vm = self.finish_ownership();
|
||||
if vm.page_default_runtime.is_initialized() {
|
||||
if let Some(runtime) = vm.current_main_world() {
|
||||
vm.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
vm.retain_native_hosts_in_scope(scope);
|
||||
vm.retain_native_hosts_in_scope(scope, runtime);
|
||||
});
|
||||
}
|
||||
Ok(vm)
|
||||
@@ -2584,15 +2576,21 @@ impl ScriptVmDefaultWorldBootstrap {
|
||||
|
||||
fn finish_in_scope(self, scope: &mut v8::PinScope<'_, '_>) -> ScriptVm {
|
||||
let vm = self.finish_ownership();
|
||||
vm.retain_native_hosts_in_scope(scope);
|
||||
if let Some(runtime) = vm.current_main_world() {
|
||||
vm.retain_native_hosts_in_scope(scope, runtime);
|
||||
}
|
||||
vm
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptVm {
|
||||
fn retain_native_hosts_in_scope(&self, scope: &mut v8::PinScope<'_, '_, ()>) {
|
||||
fn retain_native_hosts_in_scope(
|
||||
&self,
|
||||
scope: &mut v8::PinScope<'_, '_, ()>,
|
||||
runtime: &WindowRealmRuntime,
|
||||
) {
|
||||
crate::util::retain_context_host_for_document_realm(
|
||||
v8::Local::new(scope, &self.page_default_runtime.context),
|
||||
v8::Local::new(scope, &runtime.context),
|
||||
self._context_host.clone(),
|
||||
self.renderer_document_isolate
|
||||
.deferred_context_host_release_queue(),
|
||||
@@ -2672,7 +2670,9 @@ impl ScriptVm {
|
||||
self._context_host
|
||||
.borrow_mut()
|
||||
.close_page_context_resources_for_teardown();
|
||||
self.page_default_runtime.mark_closed();
|
||||
if let Some(runtime) = self.main_world.current_mut() {
|
||||
runtime.mark_closed();
|
||||
}
|
||||
for world in self.page_isolated_world_contexts.contexts_mut() {
|
||||
world.runtime.mark_closed();
|
||||
}
|
||||
@@ -2705,9 +2705,10 @@ impl ScriptVm {
|
||||
+ prebootstrapped_contexts.len()
|
||||
+ pending_isolated.len(),
|
||||
);
|
||||
if self.main_world_is_initialized() {
|
||||
context_ptrs.push(&self.page_default_runtime.context as *const _);
|
||||
}
|
||||
context_ptrs.extend(
|
||||
self.current_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr),
|
||||
);
|
||||
context_ptrs.extend(
|
||||
self.page_isolated_world_contexts
|
||||
.contexts()
|
||||
@@ -2783,14 +2784,14 @@ impl ScriptVm {
|
||||
"main navigation crossed page script environment ownership"
|
||||
));
|
||||
}
|
||||
if !self.main_world_is_initialized() {
|
||||
let Some(runtime) = self.current_main_world() else {
|
||||
return Ok(MainWindowProxyNavigationCommit {
|
||||
context: None,
|
||||
renderer_document_isolate: self.renderer_document_isolate.clone(),
|
||||
page_id,
|
||||
});
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
};
|
||||
let context_ptr = runtime.context_ptr();
|
||||
let context = self
|
||||
.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
|
||||
@@ -10,8 +10,7 @@ impl ScriptVm {
|
||||
inspector_session_id: Option<&str>,
|
||||
object_id: &str,
|
||||
) -> Result<String> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let page_inspector = &self.page_inspector;
|
||||
let renderer_document_isolate = self.renderer_document_isolate.clone();
|
||||
renderer_document_isolate.with_entered_renderer_document_isolate_and_inspector_mut(
|
||||
|
||||
@@ -70,10 +70,7 @@ impl ScriptVm {
|
||||
pub(crate) fn upgrade_late_defined_custom_elements_after_parser_checkpoint(
|
||||
&mut self,
|
||||
) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
self.with_default_context_scope(|scope, host_ptr| {
|
||||
self.with_current_main_world_scope(|scope, host_ptr| {
|
||||
let document_handle = unsafe { &*host_ptr }.dom_host().document_handle();
|
||||
let _ = custom_elements::upgrade_late_defined_connected_tree_after_parser_sync(
|
||||
scope,
|
||||
@@ -83,6 +80,7 @@ impl ScriptVm {
|
||||
perform_microtask_checkpoint_and_report_pending_promise_rejections(scope);
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
// Parser operations reach ScriptVm only when they must enter the page default
|
||||
@@ -98,17 +96,17 @@ impl ScriptVm {
|
||||
token_attributes: &[Attribute],
|
||||
intended_parent: Option<DomHandle>,
|
||||
) -> Result<Option<DomHandle>> {
|
||||
if !self.main_world_is_initialized() {
|
||||
let Some(runtime) = self.current_main_world() else {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let context_ptr = runtime.context_ptr();
|
||||
let context_host = self._context_host.clone();
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
// SAFETY: `context_ptr` points to `self.page_default_runtime.context`, which is kept
|
||||
// SAFETY: `context_ptr` points to an owned ready main-world Context, which is kept
|
||||
// alive for the duration of this non-escaping closure while the document
|
||||
// isolate is exclusively borrowed.
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
@@ -209,7 +207,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
navigator_identity: &moli_browser_profile::BrowserIdentityProfile,
|
||||
) {
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
if let Some(pending) = self.main_world.pending_mut() {
|
||||
pending.navigator_identity = Some(navigator_identity.clone());
|
||||
return;
|
||||
}
|
||||
@@ -274,9 +272,10 @@ impl ScriptVm {
|
||||
|
||||
pub(super) fn top_level_context_ptrs(&self) -> Vec<*const v8::Global<v8::Context>> {
|
||||
let mut contexts = Vec::new();
|
||||
if self.main_world_is_initialized() {
|
||||
contexts.push(&self.page_default_runtime.context as *const _);
|
||||
}
|
||||
contexts.extend(
|
||||
self.current_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr),
|
||||
);
|
||||
contexts.extend(
|
||||
self.page_isolated_world_contexts
|
||||
.contexts()
|
||||
@@ -292,9 +291,10 @@ impl ScriptVm {
|
||||
let mut contexts = Vec::with_capacity(
|
||||
1 + self.page_isolated_world_contexts.len() + self.child_frame_realm_store.len(),
|
||||
);
|
||||
if self.main_world_is_initialized() {
|
||||
contexts.push(&self.page_default_runtime.context as *const _);
|
||||
}
|
||||
contexts.extend(
|
||||
self.current_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr),
|
||||
);
|
||||
contexts.extend(
|
||||
self.page_isolated_world_contexts
|
||||
.contexts()
|
||||
|
||||
@@ -618,7 +618,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
effects: DomMutationEffects,
|
||||
) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
if self.current_main_world().is_none() {
|
||||
self.document_runtime
|
||||
.apply_parser_mutation_effects_without_window_realm(
|
||||
(*self._context_host).as_ptr(),
|
||||
@@ -637,7 +637,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
mutation: crate::parser::ParserDomMutation,
|
||||
) -> Result<()> {
|
||||
if !self.main_world_is_initialized()
|
||||
if self.current_main_world().is_none()
|
||||
&& !self
|
||||
.document_runtime
|
||||
.parser_mutation_needs_window_realm(&mutation)
|
||||
@@ -680,20 +680,18 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(crate) fn flush_parser_custom_element_handoff_replacements(&mut self) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
self.with_default_context_scope(|scope, host_ptr| {
|
||||
self.with_current_main_world_scope(|scope, host_ptr| {
|
||||
custom_elements::flush_parser_custom_element_handoff_replacements(scope, host_ptr);
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn install_session_history_position(
|
||||
&mut self,
|
||||
position: moli_session_history::SessionHistoryPosition,
|
||||
) {
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
if let Some(pending) = self.main_world.pending_mut() {
|
||||
pending.history_position = Some(position);
|
||||
return;
|
||||
}
|
||||
@@ -707,7 +705,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
entry_seed: Option<crate::native_bridge::NavigationHistoryEntrySeed>,
|
||||
) {
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
if let Some(pending) = self.main_world.pending_mut() {
|
||||
pending.history_entry = entry_seed;
|
||||
return;
|
||||
}
|
||||
@@ -725,7 +723,7 @@ impl ScriptVm {
|
||||
url: &url::Url,
|
||||
position: moli_session_history::SessionHistoryPosition,
|
||||
) -> Result<Option<crate::native_bridge::NavigationHistoryEntrySeed>> {
|
||||
if let Some(pending) = self.pending_main_world.as_ref() {
|
||||
if let Some(pending) = self.main_world.pending() {
|
||||
// No author realm has mutated History. Preserve the native seed
|
||||
// without materializing the outgoing Window during commit.
|
||||
return Ok(pending.history_entry.as_ref().and_then(|seed| {
|
||||
|
||||
@@ -23,7 +23,7 @@ impl<'vm> ChildHostLoadOwner<'vm> {
|
||||
|
||||
pub(crate) fn resync_child_browsing_contexts(&mut self) {
|
||||
let context_host = self.vm._context_host.clone();
|
||||
if !self.vm.main_world_is_initialized()
|
||||
if self.vm.current_main_world().is_none()
|
||||
&& context_host
|
||||
.borrow()
|
||||
.dom_host()
|
||||
|
||||
@@ -4,14 +4,11 @@
|
||||
//! neither the script element's later load/error terminal nor the enclosing
|
||||
//! selected Page task completion.
|
||||
|
||||
use std::pin::pin;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use super::ScriptVm;
|
||||
use crate::context_bootstrap::dispatch_window_error_event_with_details;
|
||||
use crate::exception_reporting::{V8ExceptionReport, log_uncaught_script_exception};
|
||||
use crate::native_bridge::JsContextHost;
|
||||
|
||||
impl ScriptVm {
|
||||
pub(super) fn report_classic_script_exception_and_finish_evaluation_best_effort(
|
||||
@@ -30,33 +27,24 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
report: &V8ExceptionReport,
|
||||
) -> Result<()> {
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let error_value = report
|
||||
.exception
|
||||
.as_ref()
|
||||
.map(|exception| v8::Local::new(scope, exception));
|
||||
// SAFETY: as_ptr() — V8 callbacks are re-entrant; borrow_mut() panics. See util.rs.
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
let dispatch_result = dispatch_window_error_event_with_details(
|
||||
scope,
|
||||
host_ptr,
|
||||
&report.summary,
|
||||
report.source.as_deref().unwrap_or(""),
|
||||
report.line.unwrap_or(0) as u32,
|
||||
report.column.unwrap_or(0) as u32,
|
||||
error_value,
|
||||
)
|
||||
.map_err(anyhow::Error::msg);
|
||||
let checkpoint_result = Self::perform_microtask_checkpoints(scope, None);
|
||||
dispatch_result?;
|
||||
checkpoint_result
|
||||
})
|
||||
self.with_default_context_scope(|scope, host_ptr| {
|
||||
let error_value = report
|
||||
.exception
|
||||
.as_ref()
|
||||
.map(|exception| v8::Local::new(scope, exception));
|
||||
let dispatch_result = dispatch_window_error_event_with_details(
|
||||
scope,
|
||||
host_ptr,
|
||||
&report.summary,
|
||||
report.source.as_deref().unwrap_or(""),
|
||||
report.line.unwrap_or(0) as u32,
|
||||
report.column.unwrap_or(0) as u32,
|
||||
error_value,
|
||||
)
|
||||
.map_err(anyhow::Error::msg);
|
||||
let checkpoint_result = Self::perform_microtask_checkpoints(scope, None);
|
||||
dispatch_result?;
|
||||
checkpoint_result
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use anyhow::Result;
|
||||
use super::ScriptVm;
|
||||
#[cfg(test)]
|
||||
use super::perform_microtask_checkpoint_and_report_pending_promise_rejections;
|
||||
use crate::document_runtime::DocumentRuntime;
|
||||
use crate::{frame_owner_model::FrameRealmId, native_bridge::JsContextHost};
|
||||
|
||||
impl ScriptVm {
|
||||
@@ -101,11 +102,73 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
op: impl FnOnce(&mut v8::PinScope<'_, '_>, *mut JsContextHost) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
self.with_context_scope_by_ptr(context_ptr, op)
|
||||
}
|
||||
|
||||
/// Update an already-materialized JavaScript surface without creating one.
|
||||
pub(super) fn with_current_main_world_scope<T>(
|
||||
&mut self,
|
||||
op: impl FnOnce(&mut v8::PinScope<'_, '_>, *mut JsContextHost) -> Result<T>,
|
||||
) -> Result<Option<T>> {
|
||||
let Some(runtime) = self.current_main_world() else {
|
||||
return Ok(None);
|
||||
};
|
||||
self.with_context_scope_by_ptr(runtime.context_ptr(), op)
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
/// Script/event entry with the live native Document and an entered realm.
|
||||
pub(super) fn with_main_world_document_scope<T>(
|
||||
&mut self,
|
||||
op: impl FnOnce(
|
||||
&mut v8::PinScope<'_, '_>,
|
||||
*mut JsContextHost,
|
||||
&mut DocumentRuntime,
|
||||
) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
self.with_document_context_scope_by_ptr(context_ptr, op)
|
||||
}
|
||||
|
||||
pub(super) fn with_current_main_world_document_scope<T>(
|
||||
&mut self,
|
||||
op: impl FnOnce(
|
||||
&mut v8::PinScope<'_, '_>,
|
||||
*mut JsContextHost,
|
||||
&mut DocumentRuntime,
|
||||
) -> Result<T>,
|
||||
) -> Result<Option<T>> {
|
||||
let Some(runtime) = self.current_main_world() else {
|
||||
return Ok(None);
|
||||
};
|
||||
self.with_document_context_scope_by_ptr(runtime.context_ptr(), op)
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
fn with_document_context_scope_by_ptr<T>(
|
||||
&mut self,
|
||||
context_ptr: *const v8::Global<v8::Context>,
|
||||
op: impl FnOnce(
|
||||
&mut v8::PinScope<'_, '_>,
|
||||
*mut JsContextHost,
|
||||
&mut DocumentRuntime,
|
||||
) -> Result<T>,
|
||||
) -> Result<T> {
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
// SAFETY: the caller obtains this pointer from an owned live
|
||||
// realm before borrowing the other ScriptVm fields.
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
op(scope, (*context_host).as_ptr(), document_runtime)
|
||||
})
|
||||
}
|
||||
|
||||
/// Inspect the current realm without completing a task or running reactions.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn with_default_context_scope_for_test<T>(
|
||||
|
||||
@@ -142,7 +142,11 @@ impl ScriptVm {
|
||||
let journal = environment.output_journal();
|
||||
let isolate = self.renderer_document_isolate.clone();
|
||||
let inspector_isolate = isolate.clone();
|
||||
let context = &self.page_default_runtime.context;
|
||||
let context = &self
|
||||
.main_world
|
||||
.current()
|
||||
.ok_or_else(|| anyhow!("Window reuse requires its initialized realm"))?
|
||||
.context;
|
||||
let source_document = self
|
||||
._context_host
|
||||
.borrow()
|
||||
|
||||
@@ -127,12 +127,8 @@ impl ScriptVm {
|
||||
.forces_opaque_origin;
|
||||
self.document_runtime
|
||||
.set_main_navigation_policy_container(policy);
|
||||
// A deferred Context reads the committed policy during its first bootstrap.
|
||||
if !self.main_world_is_initialized() {
|
||||
return;
|
||||
}
|
||||
// Refresh an existing token so a CSP sandbox cannot retain the URL's tuple token.
|
||||
let _ = self.with_default_context_scope(|scope, host_ptr| {
|
||||
// A deferred Context reads the policy at bootstrap; update only an existing token.
|
||||
let _ = self.with_current_main_world_scope(|scope, host_ptr| {
|
||||
let key = unsafe { &*host_ptr }.main_default_world_security_token_key();
|
||||
let context = scope.get_current_context();
|
||||
if !crate::native_bridge::set_window_security_token(scope, context, key.as_deref()) {
|
||||
@@ -264,14 +260,11 @@ impl ScriptVm {
|
||||
idle_override: Option<crate::protocol_types::EmulatedIdleOverride>,
|
||||
) -> Result<()> {
|
||||
self.set_idle_override(idle_override);
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
self.with_context_scope_by_ptr(context_ptr, |scope, _| {
|
||||
self.with_current_main_world_scope(|scope, _| {
|
||||
crate::context_bootstrap::apply_idle_override_to_current_context(scope, idle_override);
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub(crate) fn stylesheet_preload_media_matches(&self, media: Option<&str>) -> bool {
|
||||
@@ -356,22 +349,16 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(super) fn sync_document_fonts_for_environment(&mut self) {
|
||||
if !self.main_world_is_initialized() {
|
||||
return;
|
||||
}
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host = self._context_host.borrow();
|
||||
for document in host.documents_with_adopted_style_sheets() {
|
||||
crate::native_bridge::document::sync_document_fonts_for_handle(
|
||||
scope, &host, document,
|
||||
);
|
||||
}
|
||||
});
|
||||
let context_host = self._context_host.clone();
|
||||
let _ = self.with_current_main_world_scope(|scope, _| {
|
||||
let host = context_host.borrow();
|
||||
for document in host.documents_with_adopted_style_sheets() {
|
||||
crate::native_bridge::document::sync_document_fonts_for_handle(
|
||||
scope, &host, document,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn set_network_offline(&mut self, offline: bool) {
|
||||
@@ -396,11 +383,7 @@ impl ScriptVm {
|
||||
.borrow_mut()
|
||||
.set_navigator_overrides(overrides);
|
||||
if changed {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
self.with_context_scope_by_ptr(context_ptr, |scope, _| {
|
||||
self.with_current_main_world_scope(|scope, _| {
|
||||
crate::context_bootstrap::notify_geolocation_override_changed(scope);
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -484,15 +467,13 @@ impl ScriptVm {
|
||||
storage_key: Some(host.top_web_storage_scope().storage_key().clone()),
|
||||
}
|
||||
};
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(capture(&mut self._context_host.borrow_mut(), None));
|
||||
}
|
||||
self.with_default_context_scope(|scope, host_ptr| {
|
||||
let environment = self.with_current_main_world_scope(|scope, host_ptr| {
|
||||
let token = scope.get_current_context().get_security_token(scope);
|
||||
Ok(capture(
|
||||
unsafe { &mut *host_ptr },
|
||||
Some(v8::Global::new(scope, token)),
|
||||
))
|
||||
})
|
||||
})?;
|
||||
Ok(environment.unwrap_or_else(|| capture(&mut self._context_host.borrow_mut(), None)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,14 +607,12 @@ impl RendererPageScriptEnvironment {
|
||||
}
|
||||
|
||||
pub(crate) struct ScriptVmDefaultWorldBootstrap {
|
||||
pub(super) pending_main_world: Option<Box<super::main_world::PendingMainWorld>>,
|
||||
pub(super) main_world: super::main_world::MainWorld,
|
||||
pub(super) resource_owner_id: ResourceOwnerId,
|
||||
pub(super) promise_reject_dispatch: PromiseRejectDispatchSlot,
|
||||
pub(super) page_inspector: DocumentInspectorBinding,
|
||||
pub(super) renderer_document_isolate_teardown: RendererDocumentIsolateTeardown,
|
||||
pub(super) renderer_page_script_environment: Option<RendererPageScriptEnvironment>,
|
||||
pub(super) page_default_runtime: super::WindowRealmRuntime,
|
||||
pub(super) baseline_globals: super::ScriptGlobalsBaseline,
|
||||
pub(super) root_frame_id: Option<String>,
|
||||
pub(super) prebootstrapped_child_default_contexts: SharedPrebootstrappedChildDefaultContexts,
|
||||
pub(super) page_context_cancel_tx: RendererPageContextCancelSender,
|
||||
|
||||
@@ -35,8 +35,7 @@ impl ScriptVm {
|
||||
depth: i32,
|
||||
pierce: bool,
|
||||
) -> Result<RendererDomDebuggerEventListenersResolution> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let context_host = self._context_host.clone();
|
||||
let page_inspector = &self.page_inspector;
|
||||
let renderer_document_isolate = self.renderer_document_isolate.clone();
|
||||
|
||||
@@ -18,7 +18,9 @@ impl Drop for ScriptVm {
|
||||
self.page_inspector
|
||||
.deactivate_page_vm_binding_for_teardown();
|
||||
|
||||
self.page_default_runtime.release_bridge_ref();
|
||||
if let Some(runtime) = self.main_world.current_mut() {
|
||||
runtime.release_bridge_ref();
|
||||
}
|
||||
if let Some(runtime) = self.document_runtime.take_for_retained_document_host() {
|
||||
self._context_host
|
||||
.borrow_mut()
|
||||
|
||||
@@ -404,11 +404,10 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
job: MainFrameScriptJob<'_>,
|
||||
) -> PendingScriptTurn<RawScriptExecutionResult<()>> {
|
||||
if let Err(error) = self.initialize_main_world_if_needed() {
|
||||
return PendingScriptTurn::new(Err(error.into()));
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
let context_ptr = match self.ensure_main_world() {
|
||||
Ok(runtime) => runtime.context_ptr(),
|
||||
Err(error) => return PendingScriptTurn::new(Err(error.into())),
|
||||
};
|
||||
self.exec_in_context_ptr_without_turn_drain(
|
||||
context_ptr,
|
||||
job.source,
|
||||
@@ -690,9 +689,7 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(crate) fn eval(&mut self, source: &str) -> Result<String> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
self.eval_string_in_context_ptr_runtime_turn(context_ptr, source, false)
|
||||
}
|
||||
|
||||
@@ -701,11 +698,9 @@ impl ScriptVm {
|
||||
source: &str,
|
||||
base_url: &Url,
|
||||
) -> Result<Option<String>> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let source = source.to_owned();
|
||||
let base_url = base_url.clone();
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
let provenance = CompiledStringProvenance::at_url(base_url.clone());
|
||||
let pending = PendingScriptTurn::new(
|
||||
self.renderer_document_isolate
|
||||
@@ -763,9 +758,7 @@ impl ScriptVm {
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn eval_with_child_record_sync(&mut self, source: &str) -> Result<String> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
self.eval_string_in_context_ptr_runtime_turn(context_ptr, source, true)
|
||||
}
|
||||
|
||||
@@ -816,9 +809,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
source: &str,
|
||||
) -> Result<String> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
self.eval_string_in_context_ptr_without_turn_drain(
|
||||
context_ptr,
|
||||
source,
|
||||
|
||||
@@ -28,11 +28,8 @@ impl ScriptVm {
|
||||
) -> Option<InspectorWindowDispatchScope> {
|
||||
let execution_context_id = match target {
|
||||
InspectorWindowDispatchTarget::DefaultTop => {
|
||||
if !self.main_world_is_initialized() {
|
||||
return None;
|
||||
}
|
||||
return Some(InspectorWindowDispatchScope {
|
||||
context_ptr: &self.page_default_runtime.context as *const _,
|
||||
context_ptr: self.current_main_world()?.context_ptr(),
|
||||
child_handle: None,
|
||||
});
|
||||
}
|
||||
@@ -42,7 +39,7 @@ impl ScriptVm {
|
||||
};
|
||||
if self.runtime_observable_default_execution_context_id() == Some(execution_context_id) {
|
||||
return Some(InspectorWindowDispatchScope {
|
||||
context_ptr: &self.page_default_runtime.context as *const _,
|
||||
context_ptr: self.current_main_world()?.context_ptr(),
|
||||
child_handle: None,
|
||||
});
|
||||
}
|
||||
@@ -69,11 +66,10 @@ impl ScriptVm {
|
||||
realm_id: FrameRealmId,
|
||||
) -> Result<*const v8::Global<v8::Context>> {
|
||||
if realm_id.0 == 0 {
|
||||
anyhow::ensure!(
|
||||
self.main_world_is_initialized(),
|
||||
"main world is not initialized"
|
||||
);
|
||||
return Ok(&self.page_default_runtime.context as *const _);
|
||||
return self
|
||||
.current_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr)
|
||||
.ok_or_else(|| anyhow!("main world is not initialized"));
|
||||
}
|
||||
self.child_frame_realm_context_ptr(realm_id)
|
||||
}
|
||||
@@ -890,6 +886,7 @@ impl ScriptVm {
|
||||
frame_id: Option<String>,
|
||||
child_handle: Option<DomHandle>,
|
||||
) -> Result<i64> {
|
||||
self.ensure_main_world()?;
|
||||
let document_owner = match child_handle {
|
||||
Some(child_handle) => self
|
||||
._context_host
|
||||
@@ -1216,7 +1213,6 @@ impl ScriptVm {
|
||||
name: &str,
|
||||
grant_universal_access: bool,
|
||||
) -> Result<i64> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
self.publish_prebootstrapped_isolated_window_contexts()?;
|
||||
if let Some(execution_context_id) = self
|
||||
.page_isolated_world_contexts
|
||||
@@ -1260,7 +1256,6 @@ impl ScriptVm {
|
||||
name: &str,
|
||||
grant_universal_access: bool,
|
||||
) -> Result<i64> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
self.publish_prebootstrapped_isolated_window_contexts()?;
|
||||
if let Some(execution_context_id) = self
|
||||
.page_isolated_world_contexts
|
||||
|
||||
@@ -5,7 +5,7 @@ use super::*;
|
||||
|
||||
impl ScriptVm {
|
||||
pub(super) fn reconcile_document_font_resources(&mut self) {
|
||||
if !self.main_world_is_initialized() {
|
||||
if self.current_main_world().is_none() {
|
||||
let host = self._context_host.borrow();
|
||||
let fonts_enabled =
|
||||
host.current_main_document_resource_loader()
|
||||
|
||||
@@ -8,11 +8,11 @@ impl ScriptVm {
|
||||
inherited: Option<&ScriptVmInitialDocumentEnvironment>,
|
||||
) -> Result<crate::frame_owner_model::FrameDocumentLocalWindowTransition> {
|
||||
// No WindowProxy or realm has been exposed, so there is no JS identity to retain.
|
||||
if !self.main_world_is_initialized() {
|
||||
let Some(runtime) = self.current_main_world() else {
|
||||
return Ok(
|
||||
crate::frame_owner_model::FrameDocumentLocalWindowTransition::ReplaceLocalWindow,
|
||||
);
|
||||
}
|
||||
};
|
||||
// Serialized opaque origins are all "null". Compare the inherited
|
||||
// identity instead, so a shared opaque origin can reuse its Window
|
||||
// without treating independently sandboxed documents as same-origin.
|
||||
@@ -24,7 +24,7 @@ impl ScriptVm {
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &runtime.context);
|
||||
let token = v8::Local::new(scope, token);
|
||||
Ok(context.get_security_token(scope).strict_equals(token))
|
||||
})?
|
||||
@@ -160,7 +160,8 @@ impl ScriptVm {
|
||||
host.service_worker_client_id(),
|
||||
);
|
||||
}
|
||||
let context = &vm.page_default_runtime.context;
|
||||
let context = &vm.main_world.current()
|
||||
.ok_or_else(|| anyhow!("initial Window reuse requires an existing realm"))?.context;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) enum MainWorld {
|
||||
// The large startup seeds are released when the realm is materialized.
|
||||
Pending(Box<PendingMainWorld>),
|
||||
Ready {
|
||||
runtime: WindowRealmRuntime,
|
||||
_baseline_globals: ScriptGlobalsBaseline,
|
||||
},
|
||||
}
|
||||
|
||||
impl MainWorld {
|
||||
pub(super) fn record_lifecycle_timing(
|
||||
&mut self,
|
||||
timing: MainWorldLifecycleTiming,
|
||||
) -> Option<&WindowRealmRuntime> {
|
||||
match self {
|
||||
Self::Pending(pending) => {
|
||||
pending.performance.record(timing as usize);
|
||||
None
|
||||
}
|
||||
Self::Ready { runtime, .. } => Some(runtime),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn current(&self) -> Option<&WindowRealmRuntime> {
|
||||
match self {
|
||||
Self::Pending(_) => None,
|
||||
Self::Ready { runtime, .. } => Some(runtime),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn current_mut(&mut self) -> Option<&mut WindowRealmRuntime> {
|
||||
match self {
|
||||
Self::Pending(_) => None,
|
||||
Self::Ready { runtime, .. } => Some(runtime),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn pending(&self) -> Option<&PendingMainWorld> {
|
||||
match self {
|
||||
Self::Pending(pending) => Some(pending),
|
||||
Self::Ready { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn pending_mut(&mut self) -> Option<&mut PendingMainWorld> {
|
||||
match self {
|
||||
Self::Pending(pending) => Some(pending),
|
||||
Self::Ready { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) enum MainWorldLifecycleTiming {
|
||||
DomContentLoadedStart,
|
||||
DomContentLoadedEnd,
|
||||
LoadStart,
|
||||
LoadEnd,
|
||||
}
|
||||
|
||||
/// Native Document state is already live. These are the remaining inputs for
|
||||
/// its first main-world Context, not a second Document or bootstrap DOM.
|
||||
#[derive(Default)]
|
||||
@@ -131,7 +190,7 @@ pub(super) fn initialize(
|
||||
|
||||
impl ScriptVm {
|
||||
pub(super) fn initialize_main_world_for_window_handler(&mut self) -> Result<()> {
|
||||
if self.main_world_is_initialized() {
|
||||
if self.current_main_world().is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
let dom = self.document_runtime.dom_host().dom();
|
||||
@@ -145,39 +204,40 @@ impl ScriptVm {
|
||||
.any(|name| body.attribute(name).is_some())
|
||||
});
|
||||
if has_handler {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
self.ensure_main_world()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn main_world_is_initialized(&self) -> bool {
|
||||
self.page_default_runtime.is_initialized()
|
||||
pub(super) fn current_main_world(&self) -> Option<&WindowRealmRuntime> {
|
||||
self.main_world.current()
|
||||
}
|
||||
|
||||
pub(crate) fn initialize_main_world_if_needed(&mut self) -> Result<()> {
|
||||
let Some(pending) = self.pending_main_world.as_ref() else {
|
||||
return Ok(());
|
||||
};
|
||||
let (runtime, baseline) = initialize(
|
||||
&self.renderer_document_isolate,
|
||||
&self._context_host,
|
||||
self.resource_owner_id,
|
||||
&self.promise_reject_dispatch,
|
||||
self.storage_bucket_store.clone(),
|
||||
self.indexed_db_manager.clone(),
|
||||
self.renderer_page_script_environment.clone(),
|
||||
self.root_frame_id.as_deref(),
|
||||
&mut self.page_inspector,
|
||||
pending,
|
||||
)?;
|
||||
self.page_default_runtime = runtime;
|
||||
self.baseline_globals = baseline;
|
||||
self.pending_main_world = None;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
self.retain_native_hosts_in_scope(&mut scope.init());
|
||||
});
|
||||
Ok(())
|
||||
pub(crate) fn ensure_main_world(&mut self) -> Result<&WindowRealmRuntime> {
|
||||
if let Some(pending) = self.main_world.pending() {
|
||||
let (runtime, baseline_globals) = initialize(
|
||||
&self.renderer_document_isolate,
|
||||
&self._context_host,
|
||||
self.resource_owner_id,
|
||||
&self.promise_reject_dispatch,
|
||||
self.storage_bucket_store.clone(),
|
||||
self.indexed_db_manager.clone(),
|
||||
self.renderer_page_script_environment.clone(),
|
||||
self.root_frame_id.as_deref(),
|
||||
&mut self.page_inspector,
|
||||
pending,
|
||||
)?;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
self.retain_native_hosts_in_scope(&mut scope.init(), &runtime);
|
||||
});
|
||||
self.main_world = MainWorld::Ready {
|
||||
runtime,
|
||||
_baseline_globals: baseline_globals,
|
||||
};
|
||||
}
|
||||
self.current_main_world()
|
||||
.ok_or_else(|| anyhow!("main-world initialization did not produce a Window realm"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use anyhow::Result;
|
||||
use moli_webapi_declare::WebApiObject;
|
||||
use url::Url;
|
||||
|
||||
use super::ScriptVm;
|
||||
use super::{ScriptVm, WindowRealmRuntime};
|
||||
use crate::context_bootstrap::{
|
||||
ORIGINAL_WEBASSEMBLY_COMPILE_ERROR_CONSTRUCTOR_SLOT,
|
||||
ORIGINAL_WEBASSEMBLY_LINK_ERROR_CONSTRUCTOR_SLOT,
|
||||
|
||||
@@ -10,13 +10,7 @@ impl ScriptVm {
|
||||
source_url: &Url,
|
||||
fetch_metadata: &crate::module_runtime::ModuleFetchMetadata,
|
||||
) -> std::result::Result<(ModuleRecordEntry, ModuleIdentityHash), ModuleLoadError> {
|
||||
self.initialize_main_world_if_needed().map_err(|error| {
|
||||
ModuleLoadError::new(
|
||||
ModuleLoadStage::Compile,
|
||||
format!("main world initialization failed: {error}"),
|
||||
)
|
||||
})?;
|
||||
let context_ptr = self.native_module_default_context_ptr();
|
||||
let context_ptr = self.native_module_default_context_ptr(ModuleLoadStage::Compile)?;
|
||||
self.compile_native_module_record_in_context(
|
||||
context_ptr,
|
||||
key,
|
||||
@@ -47,8 +41,15 @@ impl ScriptVm {
|
||||
fetch_metadata,
|
||||
)
|
||||
}
|
||||
pub(super) fn native_module_default_context_ptr(&self) -> *const v8::Global<v8::Context> {
|
||||
&self.page_default_runtime.context as *const _
|
||||
pub(super) fn native_module_default_context_ptr(
|
||||
&mut self,
|
||||
stage: ModuleLoadStage,
|
||||
) -> std::result::Result<*const v8::Global<v8::Context>, ModuleLoadError> {
|
||||
self.ensure_main_world()
|
||||
.map(WindowRealmRuntime::context_ptr)
|
||||
.map_err(|error| {
|
||||
ModuleLoadError::new(stage, format!("main world initialization failed: {error}"))
|
||||
})
|
||||
}
|
||||
pub(super) fn compile_native_module_record_in_context(
|
||||
&mut self,
|
||||
@@ -282,7 +283,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
graph: &crate::module_runtime::ModuleGraphHandle,
|
||||
) -> std::result::Result<(), ModuleLoadError> {
|
||||
let context_ptr = self.native_module_default_context_ptr();
|
||||
let context_ptr = self.native_module_default_context_ptr(ModuleLoadStage::Instantiate)?;
|
||||
self.instantiate_native_module_graph_in_context(context_ptr, graph)
|
||||
}
|
||||
pub(super) fn instantiate_native_module_graph_in_context(
|
||||
@@ -365,7 +366,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
root_entry: crate::module_runtime::ModuleEntryId,
|
||||
) -> std::result::Result<Option<v8::Global<v8::Promise>>, ModuleLoadError> {
|
||||
let context_ptr = self.native_module_default_context_ptr();
|
||||
let context_ptr = self.native_module_default_context_ptr(ModuleLoadStage::Evaluate)?;
|
||||
self.evaluate_native_module_graph_with_owner_in_context(
|
||||
context_ptr,
|
||||
root_entry,
|
||||
@@ -377,7 +378,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
root_entry: crate::module_runtime::ModuleEntryId,
|
||||
) -> std::result::Result<NativeDynamicModuleEvaluation, ModuleLoadError> {
|
||||
let context_ptr = self.native_module_default_context_ptr();
|
||||
let context_ptr = self.native_module_default_context_ptr(ModuleLoadStage::Evaluate)?;
|
||||
self.evaluate_native_module_graph_with_owner_in_context(
|
||||
context_ptr,
|
||||
root_entry,
|
||||
|
||||
@@ -87,63 +87,51 @@ impl ScriptVm {
|
||||
"main module evaluation reaction has no current Document owner",
|
||||
)
|
||||
})?;
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let reaction_id_value = v8::BigInt::new_from_u64(scope, reaction_id);
|
||||
let data = NativeModuleScriptReactionDataDeclaration {
|
||||
module_script_reaction_id: reaction_id_value,
|
||||
scheduler_lane_id: v8::BigInt::new_from_u64(
|
||||
scope,
|
||||
document_owner.scheduler_lane_id.0,
|
||||
),
|
||||
local_window_id: v8::BigInt::new_from_u64(
|
||||
scope,
|
||||
document_owner.local_window_id.0,
|
||||
),
|
||||
document_id: v8::BigInt::new_from_u64(scope, document_owner.document_id.0),
|
||||
}
|
||||
.bind(scope)
|
||||
.map_err(|error| {
|
||||
anyhow::anyhow!("failed to create native module script reaction data: {error}")
|
||||
})?;
|
||||
let on_fulfilled =
|
||||
v8::Function::builder(native_module_script_reaction_fulfilled_callback)
|
||||
.data(data.into())
|
||||
.build(scope)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"failed to create native module script success reaction"
|
||||
)
|
||||
})?;
|
||||
let on_rejected =
|
||||
v8::Function::builder(native_module_script_reaction_rejected_callback)
|
||||
.data(data.into())
|
||||
.build(scope)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"failed to create native module script failure reaction"
|
||||
)
|
||||
})?;
|
||||
let promise = v8::Local::new(scope, &promise);
|
||||
promise
|
||||
.then2(scope, on_fulfilled, on_rejected)
|
||||
.map(|_| ())
|
||||
self.with_default_context_scope(|scope, _| {
|
||||
let reaction_id_value = v8::BigInt::new_from_u64(scope, reaction_id);
|
||||
let data = NativeModuleScriptReactionDataDeclaration {
|
||||
module_script_reaction_id: reaction_id_value,
|
||||
scheduler_lane_id: v8::BigInt::new_from_u64(
|
||||
scope,
|
||||
document_owner.scheduler_lane_id.0,
|
||||
),
|
||||
local_window_id: v8::BigInt::new_from_u64(scope, document_owner.local_window_id.0),
|
||||
document_id: v8::BigInt::new_from_u64(scope, document_owner.document_id.0),
|
||||
}
|
||||
.bind(scope)
|
||||
.map_err(|error| {
|
||||
anyhow::anyhow!("failed to create native module script reaction data: {error}")
|
||||
})?;
|
||||
let on_fulfilled =
|
||||
v8::Function::builder(native_module_script_reaction_fulfilled_callback)
|
||||
.data(data.into())
|
||||
.build(scope)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("failed to attach native module script reactions")
|
||||
anyhow::anyhow!("failed to create native module script success reaction")
|
||||
})?;
|
||||
// `then` schedules the module-script evaluation reaction as a
|
||||
// V8 microtask, even if the evaluation promise is already
|
||||
// settled. Chromium runs module evaluation's error handling
|
||||
// before the script runner advances to later pending scripts;
|
||||
// drain this owner-lane checkpoint now so TLA rejection cannot
|
||||
// be observed after a later dynamic module.
|
||||
Self::perform_microtask_checkpoints(scope, None)
|
||||
})
|
||||
.map_err(|error| ModuleLoadError::new(ModuleLoadStage::Evaluate, error.to_string()))
|
||||
let on_rejected =
|
||||
v8::Function::builder(native_module_script_reaction_rejected_callback)
|
||||
.data(data.into())
|
||||
.build(scope)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("failed to create native module script failure reaction")
|
||||
})?;
|
||||
let promise = v8::Local::new(scope, &promise);
|
||||
promise
|
||||
.then2(scope, on_fulfilled, on_rejected)
|
||||
.map(|_| ())
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("failed to attach native module script reactions")
|
||||
})?;
|
||||
// `then` schedules the module-script evaluation reaction as a
|
||||
// V8 microtask, even if the evaluation promise is already
|
||||
// settled. Chromium runs module evaluation's error handling
|
||||
// before the script runner advances to later pending scripts;
|
||||
// drain this owner-lane checkpoint now so TLA rejection cannot
|
||||
// be observed after a later dynamic module.
|
||||
Self::perform_microtask_checkpoints(scope, None)
|
||||
})
|
||||
.map_err(|error| ModuleLoadError::new(ModuleLoadStage::Evaluate, error.to_string()))
|
||||
}
|
||||
pub(crate) fn attach_child_parser_module_script_evaluation_reactions(
|
||||
&mut self,
|
||||
|
||||
@@ -87,7 +87,7 @@ fn dynamic_import_reaction_parts_in_vm(
|
||||
crate::module_runtime::DynamicModuleEvaluationTarget,
|
||||
) {
|
||||
let context_ptr: *const v8::Global<v8::Context> = match owner.child_parts() {
|
||||
None => &vm.page_default_runtime.context,
|
||||
None => &vm.current_main_world().unwrap().context,
|
||||
Some((_child_handle, _task_owner, realm_id)) => vm
|
||||
.frame_realm_context_ptr(realm_id)
|
||||
.expect("child dynamic-import reaction test realm must be materialized"),
|
||||
@@ -150,7 +150,7 @@ fn dynamic_import_request_in_vm(
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let owner = context_host
|
||||
.borrow()
|
||||
@@ -733,7 +733,7 @@ fn selected_dynamic_import_rejection_body_defers_user_reaction_to_task_end() {
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let owner = context_host
|
||||
.borrow()
|
||||
|
||||
@@ -25,7 +25,7 @@ fn reject_with_error(vm: &mut ScriptVm, error: &ModuleLoadError) -> v8::Global<v
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
v8::Local::new(scope, &resolver)
|
||||
.get_promise(scope)
|
||||
@@ -39,7 +39,7 @@ fn reject_with_error(vm: &mut ScriptVm, error: &ModuleLoadError) -> v8::Global<v
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let promise = v8::Local::new(scope, &resolver).get_promise(scope);
|
||||
assert_eq!(promise.state(), v8::PromiseState::Rejected);
|
||||
|
||||
@@ -31,7 +31,7 @@ impl NavigationHistoryRealm {
|
||||
|
||||
impl ScriptVm {
|
||||
pub(crate) fn reset_navigation_history(&mut self) -> Result<bool> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
self.ensure_main_world()?;
|
||||
let realms = self.live_navigation_history_realms();
|
||||
let mut plans: Vec<(NavigationHistoryRealm, NavigationHistoryPrunePlan)> =
|
||||
Vec::with_capacity(realms.len());
|
||||
@@ -136,9 +136,9 @@ impl ScriptVm {
|
||||
realm: NavigationHistoryRealm,
|
||||
) -> Option<*const v8::Global<v8::Context>> {
|
||||
match realm {
|
||||
NavigationHistoryRealm::TopDefault => {
|
||||
Some(&self.page_default_runtime.context as *const _)
|
||||
}
|
||||
NavigationHistoryRealm::TopDefault => self
|
||||
.current_main_world()
|
||||
.map(|runtime| runtime.context_ptr()),
|
||||
NavigationHistoryRealm::ChildDefault {
|
||||
execution_context_id,
|
||||
child_handle,
|
||||
|
||||
@@ -2,7 +2,7 @@ use anyhow::{Context, Result, anyhow};
|
||||
use std::pin::pin;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use super::ScriptVm;
|
||||
use super::{ScriptVm, main_world::MainWorldLifecycleTiming};
|
||||
use crate::context_bootstrap::{
|
||||
construct_original_event, construct_original_page_transition_event,
|
||||
record_performance_dom_content_loaded_event_end,
|
||||
@@ -27,44 +27,20 @@ const LIFECYCLE_EVENT_WATCHDOG_TIMEOUT: Duration = Duration::from_secs(8);
|
||||
|
||||
impl ScriptVm {
|
||||
fn dispatch_document_event_body(&mut self, event_type: &str) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
// SAFETY: as_ptr() — V8 callbacks are re-entrant; borrow_mut() panics. See util.rs.
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
document_runtime
|
||||
.dispatch_document_event(scope, host_ptr, event_type)
|
||||
.map_err(anyhow::Error::msg)
|
||||
})
|
||||
self.with_current_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime
|
||||
.dispatch_document_event(scope, host_ptr, event_type)
|
||||
.map_err(anyhow::Error::msg)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub(super) fn perform_owner_lane_task_microtask_checkpoints(&mut self) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
// SAFETY: `context_ptr` points at `self.page_default_runtime.context`, and this closure runs with
|
||||
// the document isolate entered. `ScriptVm` owns both values, so the context belongs
|
||||
// to the entered isolate for the full checkpoint scope.
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
Self::perform_microtask_checkpoints(scope, None)?;
|
||||
Ok(())
|
||||
})
|
||||
.context("owner-lane microtask checkpoint failed")
|
||||
self.with_current_main_world_scope(|scope, _| {
|
||||
Self::perform_microtask_checkpoints(scope, None)
|
||||
})
|
||||
.map(|_| ())
|
||||
.context("owner-lane microtask checkpoint failed")
|
||||
}
|
||||
|
||||
/// Execute the body of one V8 foreground continuation.
|
||||
@@ -122,12 +98,15 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
event_type: &str,
|
||||
) -> Result<()> {
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
if event_type == "DOMContentLoaded" {
|
||||
pending.performance.record(0);
|
||||
}
|
||||
let runtime = if event_type == "DOMContentLoaded" {
|
||||
self.main_world
|
||||
.record_lifecycle_timing(MainWorldLifecycleTiming::DomContentLoadedStart)
|
||||
} else {
|
||||
self.current_main_world()
|
||||
};
|
||||
let Some(context_ptr) = runtime.map(super::WindowRealmRuntime::context_ptr) else {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let watchdog = self
|
||||
.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
@@ -141,7 +120,6 @@ impl ScriptVm {
|
||||
});
|
||||
let watchdog_timeout = watchdog.timeout();
|
||||
let result = {
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
@@ -169,22 +147,18 @@ impl ScriptVm {
|
||||
/// Publish the event-end timing that is intentionally observable only
|
||||
/// after the owning lifecycle task's checkpoint.
|
||||
pub(super) fn record_document_lifecycle_event_end(&mut self, event_type: &str) {
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
if event_type == "DOMContentLoaded" {
|
||||
pending.performance.record(1);
|
||||
}
|
||||
if event_type != "DOMContentLoaded" {
|
||||
return;
|
||||
}
|
||||
if event_type == "DOMContentLoaded" {
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
record_performance_dom_content_loaded_event_end(scope);
|
||||
});
|
||||
let context_ptr = self
|
||||
.main_world
|
||||
.record_lifecycle_timing(MainWorldLifecycleTiming::DomContentLoadedEnd)
|
||||
.map(super::WindowRealmRuntime::context_ptr);
|
||||
if let Some(context_ptr) = context_ptr {
|
||||
let _ = self.with_context_scope_by_ptr(context_ptr, |scope, _| {
|
||||
record_performance_dom_content_loaded_event_end(scope);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +189,7 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(super) fn queue_current_main_document_image_load_events(&mut self) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
if self.current_main_world().is_none() {
|
||||
let has_resources = self
|
||||
.document_runtime
|
||||
.dom_host()
|
||||
@@ -231,26 +205,15 @@ impl ScriptVm {
|
||||
if !has_resources {
|
||||
return Ok(());
|
||||
}
|
||||
self.initialize_main_world_if_needed()?;
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
// SAFETY: as_ptr() - V8 callbacks are re-entrant; borrow_mut() panics. See util.rs.
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
document_runtime.queue_current_main_document_image_load_events(scope, host_ptr);
|
||||
Ok(())
|
||||
})
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime.queue_current_main_document_image_load_events(scope, host_ptr);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn queue_current_main_document_media_loads(&mut self) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
if self.current_main_world().is_none() {
|
||||
let has_resources = self
|
||||
.document_runtime
|
||||
.dom_host()
|
||||
@@ -268,36 +231,27 @@ impl ScriptVm {
|
||||
if !has_resources {
|
||||
return Ok(());
|
||||
}
|
||||
self.initialize_main_world_if_needed()?;
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
// SAFETY: as_ptr() - V8 callbacks are re-entrant; borrow_mut() panics. See util.rs.
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
document_runtime.queue_current_main_document_media_loads(scope, host_ptr);
|
||||
Ok(())
|
||||
})
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime.queue_current_main_document_media_loads(scope, host_ptr);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Dispatch the Window `load` body without crossing the load-to-pageshow
|
||||
/// lifecycle checkpoint.
|
||||
pub(super) fn dispatch_window_load_event_body(&mut self) -> Result<()> {
|
||||
self.initialize_main_world_for_window_handler()?;
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
pending.performance.record(2);
|
||||
let Some(context_ptr) = self
|
||||
.main_world
|
||||
.record_lifecycle_timing(MainWorldLifecycleTiming::LoadStart)
|
||||
.map(super::WindowRealmRuntime::context_ptr)
|
||||
else {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let timing_enabled = moli_trace::cdp_nav_timing_enabled();
|
||||
let task_started = timing_enabled.then(Instant::now);
|
||||
self.prune_stale_child_default_execution_contexts();
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
@@ -393,11 +347,13 @@ impl ScriptVm {
|
||||
/// checkpoint. This method deliberately does not perform the final task-end
|
||||
/// checkpoint after pageshow.
|
||||
pub(super) fn dispatch_window_pageshow_event_body(&mut self) -> Result<()> {
|
||||
if let Some(pending) = self.pending_main_world.as_mut() {
|
||||
pending.performance.record(3);
|
||||
let Some(context_ptr) = self
|
||||
.main_world
|
||||
.record_lifecycle_timing(MainWorldLifecycleTiming::LoadEnd)
|
||||
.map(super::WindowRealmRuntime::context_ptr)
|
||||
else {
|
||||
return Ok(());
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
};
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::pin::pin;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use tracing::debug;
|
||||
@@ -30,7 +29,6 @@ use crate::host::{
|
||||
use crate::module_script_continuation::{
|
||||
ModuleScriptContinuation, ModuleScriptEvaluationContinuation, ModuleScriptEvaluationUpdate,
|
||||
};
|
||||
use crate::native_bridge::JsContextHost;
|
||||
use crate::network::ResourceRequestClient;
|
||||
use crate::page_task_queue::PageTaskQueue;
|
||||
use crate::page_task_queue::{
|
||||
@@ -2274,7 +2272,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
ready: crate::document_runtime::ReadyConnectedStyleLoad,
|
||||
) -> bool {
|
||||
if !self.main_world_is_initialized() {
|
||||
if self.current_main_world().is_none() {
|
||||
let host_ptr = (*self._context_host).as_ptr();
|
||||
if ready.load_event_binding().is_some_and(|binding| {
|
||||
!unsafe { &*host_ptr }.main_style_load_event_is_current(binding)
|
||||
@@ -2292,48 +2290,26 @@ impl ScriptVm {
|
||||
.consume_pending_style_load(host_ptr, &ready);
|
||||
return true;
|
||||
}
|
||||
if let Err(error) = self.initialize_main_world_if_needed() {
|
||||
self.record_runtime_warning(format_args!(
|
||||
"style handler initialization failed: {error}"
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
if ready.load_event_binding().is_some_and(|binding| {
|
||||
!unsafe { &*host_ptr }.main_style_load_event_is_current(binding)
|
||||
}) {
|
||||
return false;
|
||||
}
|
||||
document_runtime.dispatch_pending_style_load(scope, host_ptr, ready)
|
||||
})
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
if ready.load_event_binding().is_some_and(|binding| {
|
||||
!unsafe { &*host_ptr }.main_style_load_event_is_current(binding)
|
||||
}) {
|
||||
return Ok(false);
|
||||
}
|
||||
Ok(document_runtime.dispatch_pending_style_load(scope, host_ptr, ready))
|
||||
})
|
||||
.unwrap_or_else(|error| {
|
||||
self.record_runtime_warning(format_args!("style handler dispatch failed: {error}"));
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn apply_pending_stylesheet_source_css_projections(&mut self) {
|
||||
if !self.main_world_is_initialized() {
|
||||
return;
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
document_runtime.apply_pending_stylesheet_source_css_projections(scope, host_ptr);
|
||||
});
|
||||
let _ = self.with_current_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime.apply_pending_stylesheet_source_css_projections(scope, host_ptr);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn settle_stylesheet_link_clients(
|
||||
@@ -2343,47 +2319,29 @@ impl ScriptVm {
|
||||
if clients.is_empty() {
|
||||
return;
|
||||
}
|
||||
if let Err(error) = self.initialize_main_world_if_needed() {
|
||||
self.record_runtime_warning(format_args!(
|
||||
"stylesheet main world initialization failed: {error}"
|
||||
));
|
||||
return;
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
if let Err(error) =
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime
|
||||
.settle_stylesheet_link_clients_in_current_scope(scope, host_ptr, clients);
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
{
|
||||
self.record_runtime_warning(format_args!(
|
||||
"stylesheet client settlement failed: {error}"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_preload_like_link_error_event(&mut self, handle: DomHandle) -> bool {
|
||||
if let Err(error) = self.initialize_main_world_if_needed() {
|
||||
self.record_runtime_warning(format_args!(
|
||||
"stylesheet main world initialization failed: {error}"
|
||||
));
|
||||
return false;
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
document_runtime.dispatch_preload_like_link_error_event(scope, host_ptr, handle);
|
||||
});
|
||||
true
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime.dispatch_preload_like_link_error_event(scope, host_ptr, handle);
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| true)
|
||||
.unwrap_or_else(|error| {
|
||||
self.record_runtime_warning(format_args!("stylesheet error dispatch failed: {error}"));
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn bind_prepared_script_handle_if_needed(
|
||||
@@ -2494,28 +2452,18 @@ impl ScriptVm {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Err(error) = self.initialize_main_world_if_needed() {
|
||||
self.record_runtime_warning(format_args!(
|
||||
"CSP main world initialization failed: {error}"
|
||||
));
|
||||
return;
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
if let Err(error) =
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
for violation in violations {
|
||||
document_runtime.queue_content_security_policy_violation_event_best_effort(
|
||||
scope, host_ptr, &violation,
|
||||
);
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
{
|
||||
self.record_runtime_warning(format_args!("CSP violation dispatch failed: {error}"));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn record_ready_stylesheet_network_results(&mut self) {
|
||||
|
||||
@@ -663,28 +663,18 @@ impl ScriptVm {
|
||||
source: &str,
|
||||
request: ContentSecurityPolicyScriptElementRequest<'_>,
|
||||
) -> Option<String> {
|
||||
if let Err(error) = self.initialize_main_world_if_needed() {
|
||||
self.record_runtime_warning(format_args!("main world initialization failed: {error}"));
|
||||
return None;
|
||||
}
|
||||
let context_host = self._context_host.clone();
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
// SAFETY: context_ptr points to self.page_default_runtime.context, which
|
||||
// remains live for this non-escaping isolate closure.
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
Ok(
|
||||
crate::native_bridge::element::inline_script_source_for_execution(
|
||||
scope, host_ptr, node_id, source, request,
|
||||
),
|
||||
)
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
self.with_default_context_scope(|scope, host_ptr| {
|
||||
Ok(
|
||||
crate::native_bridge::element::inline_script_source_for_execution(
|
||||
scope, host_ptr, node_id, source, request,
|
||||
),
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|error| {
|
||||
self.record_runtime_warning(format_args!(
|
||||
"main world source preparation failed: {error}"
|
||||
));
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,8 @@ impl ScriptVmDefaultWorldBootstrap {
|
||||
.borrow_mut()
|
||||
.mark_main_document_initial_empty();
|
||||
}
|
||||
let bootstrap = bootstrap.default_world_in_entered_scope(scope, global_template)?;
|
||||
let context = v8::Local::new(scope, &bootstrap.page_default_runtime.context);
|
||||
let (bootstrap, context) =
|
||||
bootstrap.default_world_in_entered_scope(scope, global_template)?;
|
||||
// A propagated origin sandbox gives the popup a fresh opaque origin.
|
||||
// Keep its unique token; copying the opener's token would bypass SOP.
|
||||
if !env.document_policy_container.sandbox.forces_opaque_origin {
|
||||
@@ -86,7 +86,7 @@ impl ScriptVmDefaultWorldBootstrap {
|
||||
}
|
||||
let mut vm = bootstrap.finish_in_scope(scope);
|
||||
vm.set_initial_storage_backends_in_scope(
|
||||
scope,
|
||||
context,
|
||||
env.indexed_db_manager.clone(),
|
||||
env.storage_bucket_store.clone(),
|
||||
);
|
||||
@@ -99,7 +99,10 @@ impl ScriptVmPageRealmBootstrap {
|
||||
self,
|
||||
scope: &mut v8::PinScope<'s, '_, ()>,
|
||||
global_template: v8::Local<'s, v8::ObjectTemplate>,
|
||||
) -> std::result::Result<ScriptVmDefaultWorldBootstrap, ScriptVmBootstrapError> {
|
||||
) -> std::result::Result<
|
||||
(ScriptVmDefaultWorldBootstrap, v8::Local<'s, v8::Context>),
|
||||
ScriptVmBootstrapError,
|
||||
> {
|
||||
let Self {
|
||||
inherited_security_token: _,
|
||||
initialize_main_world: _,
|
||||
@@ -186,36 +189,39 @@ impl ScriptVmPageRealmBootstrap {
|
||||
)));
|
||||
}
|
||||
};
|
||||
Ok(ScriptVmDefaultWorldBootstrap {
|
||||
pending_main_world: None,
|
||||
resource_owner_id,
|
||||
promise_reject_dispatch,
|
||||
page_inspector,
|
||||
renderer_document_isolate,
|
||||
renderer_document_isolate_teardown,
|
||||
page_default_runtime: runtime,
|
||||
baseline_globals,
|
||||
document_runtime,
|
||||
root_frame_id,
|
||||
context_host,
|
||||
prebootstrapped_child_default_contexts,
|
||||
page_context_cancel_tx,
|
||||
post_domcontentloaded_page_task_tx,
|
||||
page_runtime_wake_tx,
|
||||
storage_bucket_store,
|
||||
renderer_page_script_environment,
|
||||
})
|
||||
Ok((
|
||||
ScriptVmDefaultWorldBootstrap {
|
||||
main_world: MainWorld::Ready {
|
||||
runtime,
|
||||
_baseline_globals: baseline_globals,
|
||||
},
|
||||
resource_owner_id,
|
||||
promise_reject_dispatch,
|
||||
page_inspector,
|
||||
renderer_document_isolate,
|
||||
renderer_document_isolate_teardown,
|
||||
document_runtime,
|
||||
root_frame_id,
|
||||
context_host,
|
||||
prebootstrapped_child_default_contexts,
|
||||
page_context_cancel_tx,
|
||||
post_domcontentloaded_page_task_tx,
|
||||
page_runtime_wake_tx,
|
||||
storage_bucket_store,
|
||||
renderer_page_script_environment,
|
||||
},
|
||||
local_context,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptVm {
|
||||
fn set_initial_storage_backends_in_scope(
|
||||
&mut self,
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
context: v8::Local<'_, v8::Context>,
|
||||
manager: Option<crate::context_bootstrap::WeakIndexedDbManager>,
|
||||
storage: Option<crate::context_bootstrap::SharedStorageBucketStore>,
|
||||
) {
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
self.indexed_db_manager = manager.clone();
|
||||
self._context_host
|
||||
.borrow_mut()
|
||||
@@ -254,7 +260,11 @@ impl ScriptVm {
|
||||
self.root_frame_id = root_frame_id;
|
||||
let isolate = self.renderer_document_isolate.clone();
|
||||
let inspector_isolate = isolate.clone();
|
||||
let context = &self.page_default_runtime.context;
|
||||
let context = &self
|
||||
.main_world
|
||||
.current()
|
||||
.ok_or_else(|| anyhow!("related Page adoption requires its initialized Window realm"))?
|
||||
.context;
|
||||
let document_url = self.document_runtime.document_url().clone();
|
||||
let root_frame_id = self.root_frame_id.as_deref();
|
||||
let source_document = self
|
||||
|
||||
@@ -88,7 +88,7 @@ impl ScriptVm {
|
||||
result_mode: RuntimeEvaluateResultMode,
|
||||
) -> Result<RuntimeEvaluateOutcome> {
|
||||
if execution_context_id.is_none() {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
self.ensure_main_world()?;
|
||||
}
|
||||
self.validate_runtime_evaluate_context(execution_context_id)?;
|
||||
let call_id = self.next_internal_runtime_evaluate_call_id()?;
|
||||
@@ -348,10 +348,8 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(super) fn install_runtime_binding_in_default_context(&mut self, name: &str) -> Result<()> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr = self.ensure_main_world()?.context_ptr();
|
||||
let owner = self.runtime_binding_document_owner(None)?;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
let execution_context_id = self.default_or_initial_execution_context_id().unwrap_or(0);
|
||||
self.install_runtime_binding_in_context(context_ptr, execution_context_id, owner, name)
|
||||
}
|
||||
@@ -456,18 +454,14 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(super) fn remove_runtime_binding_from_default_context(&mut self, name: &str) -> Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&self.page_default_runtime.context as *const _;
|
||||
self.with_context_scope_by_ptr(context_ptr, |scope, _| {
|
||||
self.with_current_main_world_scope(|scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = v8_string(scope, name)
|
||||
.ok_or_else(|| anyhow!("failed to allocate runtime binding key `{name}`"))?;
|
||||
let _ = global.delete(scope, key.into());
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub(super) fn remove_runtime_binding_from_isolated_context(
|
||||
|
||||
@@ -3,10 +3,15 @@ use super::*;
|
||||
impl ScriptVm {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub(crate) fn snapshot_globals(&mut self) -> Result<Option<BTreeMap<String, JsValueSnapshot>>> {
|
||||
if !self.main_world_is_initialized() {
|
||||
let MainWorld::Ready {
|
||||
runtime,
|
||||
_baseline_globals: baseline_globals,
|
||||
} = &self.main_world
|
||||
else {
|
||||
return Ok(Some(BTreeMap::new()));
|
||||
}
|
||||
let baseline_json = serde_json::to_string(&self.baseline_globals)
|
||||
};
|
||||
let default_context = runtime.context_ptr();
|
||||
let baseline_json = serde_json::to_string(baseline_globals)
|
||||
.context("failed to encode baseline globals for script snapshot")?;
|
||||
let snapshot_source = format!(
|
||||
r#"
|
||||
@@ -97,7 +102,6 @@ impl ScriptVm {
|
||||
}})()
|
||||
"#
|
||||
);
|
||||
let default_context = &self.page_default_runtime.context as *const _;
|
||||
let snapshot_json = self
|
||||
.eval_string_in_context_ptr_internal_snapshot(default_context, &snapshot_source)
|
||||
.context("failed to evaluate script state snapshot")?;
|
||||
@@ -114,7 +118,6 @@ impl ScriptVm {
|
||||
|
||||
#[cfg(not(any(test, feature = "test-support")))]
|
||||
pub(crate) fn snapshot_globals(&mut self) -> Result<Option<BTreeMap<String, JsValueSnapshot>>> {
|
||||
let _ = &self.baseline_globals;
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@@ -126,8 +129,8 @@ impl ScriptVm {
|
||||
.runtime_observable_source_queue
|
||||
.take_report_observable_output(
|
||||
self.runtime_observable_default_execution_context_id(),
|
||||
self.main_world_is_initialized()
|
||||
.then(|| self.page_default_runtime.runtime_observable_context_token),
|
||||
self.current_main_world()
|
||||
.map(|runtime| runtime.runtime_observable_context_token),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -156,14 +159,15 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(super) fn page_runtime_observable_contexts(&self) -> Vec<PageRuntimeObservableContext> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut contexts = vec![PageRuntimeObservableContext {
|
||||
execution_context_id: self.runtime_observable_default_execution_context_id(),
|
||||
context_token: self.page_default_runtime.runtime_observable_context_token,
|
||||
context: &self.page_default_runtime.context as *const _,
|
||||
}];
|
||||
let mut contexts = self
|
||||
.current_main_world()
|
||||
.map(|runtime| PageRuntimeObservableContext {
|
||||
execution_context_id: self.runtime_observable_default_execution_context_id(),
|
||||
context_token: runtime.runtime_observable_context_token,
|
||||
context: runtime.context_ptr(),
|
||||
})
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
let mut isolated_context_ids = self
|
||||
.page_isolated_world_contexts
|
||||
.execution_context_ids()
|
||||
@@ -397,19 +401,16 @@ impl ScriptVm {
|
||||
pub(super) fn moli_memory_counters(&self) -> RendererMoliMemoryDiagnostics {
|
||||
let document = self.document_runtime.snapshot_document();
|
||||
let dom = moli_dom_memory_counters(&document);
|
||||
let main_window_proxy_identity_hash = self
|
||||
.main_world_is_initialized()
|
||||
.then(|| {
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
Ok(context.global(scope).get_identity_hash().get())
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.flatten();
|
||||
let main_window_proxy_identity_hash = self.current_main_world().and_then(|runtime| {
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &runtime.context);
|
||||
Ok(context.global(scope).get_identity_hash().get())
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
let host = self._context_host.borrow();
|
||||
RendererMoliMemoryDiagnostics {
|
||||
scope: RendererMoliMemoryScopeDiagnostics {
|
||||
@@ -507,7 +508,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
context_ptr: *const v8::Global<v8::Context>,
|
||||
) -> Result<Vec<String>> {
|
||||
// SAFETY: callers pass pointers to `self.page_default_runtime.context` or page realm context entries owned by this `ScriptVm`.
|
||||
// SAFETY: callers pass pointers to an owned ready main-world Context or page realm context entries owned by this `ScriptVm`.
|
||||
// The snapshot operation only reads a context slot; it does not mutate or remove any
|
||||
// context while the raw pointer is used.
|
||||
// This is an internal console snapshot, not an owner-visible script turn.
|
||||
@@ -521,7 +522,7 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
context_ptr: *const v8::Global<v8::Context>,
|
||||
) -> Result<Vec<Value>> {
|
||||
// SAFETY: callers pass pointers to `self.page_default_runtime.context` or page realm context entries owned by this `ScriptVm`.
|
||||
// SAFETY: callers pass pointers to an owned ready main-world Context or page realm context entries owned by this `ScriptVm`.
|
||||
// The snapshot operation only reads a context slot; it does not mutate or remove any
|
||||
// context while the raw pointer is used.
|
||||
// This is an internal console snapshot, not an owner-visible script turn.
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
//! synchronous parser/module/runtime algorithms that still need a checkpoint
|
||||
//! consume them through their own named completion boundary.
|
||||
|
||||
use std::pin::pin;
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
|
||||
use super::ScriptVm;
|
||||
@@ -15,7 +13,6 @@ use crate::context_bootstrap::{
|
||||
ORIGINAL_WEBASSEMBLY_LINK_ERROR_CONSTRUCTOR_SLOT, dispatch_window_error_event_with_details,
|
||||
};
|
||||
use crate::host::ScriptEventTask;
|
||||
use crate::native_bridge::JsContextHost;
|
||||
use crate::util::{get_private_value, v8_string, v8str};
|
||||
|
||||
impl ScriptVm {
|
||||
@@ -30,22 +27,11 @@ impl ScriptVm {
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_script_event_body(&mut self, task: &ScriptEventTask) -> Result<()> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
let document_runtime = &mut self.document_runtime;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
// SAFETY: as_ptr() — V8 callbacks are re-entrant; borrow_mut() panics. See util.rs.
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
document_runtime
|
||||
.host_dispatch_script_event(scope, host_ptr, task)
|
||||
.map_err(anyhow::Error::msg)
|
||||
})
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime
|
||||
.host_dispatch_script_event(scope, host_ptr, task)
|
||||
.map_err(anyhow::Error::msg)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn report_window_error_body_best_effort(
|
||||
@@ -68,50 +54,36 @@ impl ScriptVm {
|
||||
filename: Option<&str>,
|
||||
error_constructor: Option<crate::types::ScriptErrorConstructorKind>,
|
||||
) -> Result<()> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &self.page_default_runtime.context;
|
||||
let context_host = self._context_host.clone();
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = unsafe { v8::Local::new(scope, &*context_ptr) };
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let message_value = v8_string(scope, message)
|
||||
.ok_or_else(|| anyhow!("failed to allocate reportError message"))?;
|
||||
let error_value = window_script_failure_error_value(
|
||||
self.with_default_context_scope(|scope, host_ptr| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let message_value = v8_string(scope, message)
|
||||
.ok_or_else(|| anyhow!("failed to allocate reportError message"))?;
|
||||
let error_value =
|
||||
window_script_failure_error_value(scope, global, error_constructor, message_value);
|
||||
if let Some(filename) = filename
|
||||
&& let Some(filename_value) = v8_string(scope, filename)
|
||||
&& let Ok(error_object) = v8::Local::<v8::Object>::try_from(error_value)
|
||||
{
|
||||
let _ = error_object.set(
|
||||
scope,
|
||||
global,
|
||||
error_constructor,
|
||||
message_value,
|
||||
v8str(scope, "fileName").into(),
|
||||
filename_value.into(),
|
||||
);
|
||||
if let Some(filename) = filename
|
||||
&& let Some(filename_value) = v8_string(scope, filename)
|
||||
&& let Ok(error_object) = v8::Local::<v8::Object>::try_from(error_value)
|
||||
{
|
||||
let _ = error_object.set(
|
||||
scope,
|
||||
v8str(scope, "fileName").into(),
|
||||
filename_value.into(),
|
||||
);
|
||||
}
|
||||
// Internal script failure reporting must not call the page-visible
|
||||
// window.reportError function while lifecycle state is unwinding.
|
||||
// Dispatch the equivalent ErrorEvent body directly.
|
||||
// SAFETY: as_ptr() — V8 callbacks are re-entrant; borrow_mut() panics. See util.rs.
|
||||
let host_ptr: *mut JsContextHost = (*context_host).as_ptr();
|
||||
dispatch_window_error_event_with_details(
|
||||
scope,
|
||||
host_ptr,
|
||||
message,
|
||||
filename.unwrap_or(""),
|
||||
0,
|
||||
0,
|
||||
Some(error_value),
|
||||
)
|
||||
.map_err(anyhow::Error::msg)
|
||||
})
|
||||
}
|
||||
// Internal script failure reporting must not call the page-visible
|
||||
// window.reportError function while lifecycle state is unwinding.
|
||||
// Dispatch the equivalent ErrorEvent body directly.
|
||||
dispatch_window_error_event_with_details(
|
||||
scope,
|
||||
host_ptr,
|
||||
message,
|
||||
filename.unwrap_or(""),
|
||||
0,
|
||||
0,
|
||||
Some(error_value),
|
||||
)
|
||||
.map_err(anyhow::Error::msg)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -355,38 +355,31 @@ impl ScriptVm {
|
||||
.deferred_page_tasks_mut()
|
||||
.enter_scope();
|
||||
}
|
||||
self.initialize_main_world_if_needed()
|
||||
.map_err(|error| error.to_string())?;
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| -> std::result::Result<(), String> {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let checkpoint_started = moli_trace::cdp_nav_timing_enabled().then(Instant::now);
|
||||
Self::reset_dom_binding_trace_window();
|
||||
let dom_binding_checkpoint_started =
|
||||
moli_trace::dom_binding_timing_enabled().then(Instant::now);
|
||||
Self::perform_microtask_checkpoints(scope, Some(&script.url))
|
||||
.map_err(|error| error.to_string())?;
|
||||
if let Some(started) = dom_binding_checkpoint_started {
|
||||
Self::emit_dom_binding_trace_window(
|
||||
"renderer_prepared_script_dom_binding_summary",
|
||||
"post_script_checkpoint",
|
||||
Some(&script.url),
|
||||
started.elapsed(),
|
||||
);
|
||||
}
|
||||
if let Some(started) = checkpoint_started {
|
||||
tracing::info!(
|
||||
target: "moli_cdp_nav_timing",
|
||||
url = %script.url,
|
||||
stage = "renderer_prepared_script_checkpoint_done",
|
||||
elapsed_ms = started.elapsed().as_millis(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
self.with_current_main_world_scope(|scope, _| {
|
||||
let checkpoint_started = moli_trace::cdp_nav_timing_enabled().then(Instant::now);
|
||||
Self::reset_dom_binding_trace_window();
|
||||
let dom_binding_checkpoint_started =
|
||||
moli_trace::dom_binding_timing_enabled().then(Instant::now);
|
||||
Self::perform_microtask_checkpoints(scope, Some(&script.url))?;
|
||||
if let Some(started) = dom_binding_checkpoint_started {
|
||||
Self::emit_dom_binding_trace_window(
|
||||
"renderer_prepared_script_dom_binding_summary",
|
||||
"post_script_checkpoint",
|
||||
Some(&script.url),
|
||||
started.elapsed(),
|
||||
);
|
||||
}
|
||||
if let Some(started) = checkpoint_started {
|
||||
tracing::info!(
|
||||
target: "moli_cdp_nav_timing",
|
||||
url = %script.url,
|
||||
stage = "renderer_prepared_script_checkpoint_done",
|
||||
elapsed_ms = started.elapsed().as_millis(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|error| error.to_string())?;
|
||||
let current_script_load_disposition = if skip_current_script_load_enqueue {
|
||||
FollowupPageTaskDisposition::Skipped
|
||||
} else {
|
||||
@@ -600,28 +593,21 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
script_url: Option<&Url>,
|
||||
) -> anyhow::Result<()> {
|
||||
if !self.main_world_is_initialized() {
|
||||
return Ok(());
|
||||
}
|
||||
self.renderer_document_isolate
|
||||
.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
Self::reset_dom_binding_trace_window();
|
||||
let dom_binding_checkpoint_started =
|
||||
moli_trace::dom_binding_timing_enabled().then(Instant::now);
|
||||
Self::perform_microtask_checkpoints(scope, script_url)?;
|
||||
if let Some(started) = dom_binding_checkpoint_started {
|
||||
Self::emit_dom_binding_trace_window(
|
||||
"renderer_script_task_dom_binding_summary",
|
||||
"pre_task_checkpoint",
|
||||
script_url,
|
||||
started.elapsed(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
self.with_current_main_world_scope(|scope, _| {
|
||||
Self::reset_dom_binding_trace_window();
|
||||
let dom_binding_checkpoint_started =
|
||||
moli_trace::dom_binding_timing_enabled().then(Instant::now);
|
||||
Self::perform_microtask_checkpoints(scope, script_url)?;
|
||||
if let Some(started) = dom_binding_checkpoint_started {
|
||||
Self::emit_dom_binding_trace_window(
|
||||
"renderer_script_task_dom_binding_summary",
|
||||
"pre_task_checkpoint",
|
||||
script_url,
|
||||
started.elapsed(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
use std::pin::pin;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use super::ScriptVm;
|
||||
use crate::{
|
||||
context_bootstrap::{TrustedTypesCodeGenerationCheck, trusted_types_code_generation_check},
|
||||
document_runtime::DocumentContentSecurityPolicyViolation,
|
||||
native_bridge::JsContextHost,
|
||||
page_task_queue::ContentSecurityPolicyViolationEventTask,
|
||||
util::context_host_ptr_from_global_bridge,
|
||||
};
|
||||
@@ -38,18 +35,11 @@ impl ScriptVm {
|
||||
&mut self,
|
||||
violation: &DocumentContentSecurityPolicyViolation,
|
||||
) -> Result<()> {
|
||||
self.initialize_main_world_if_needed()?;
|
||||
self.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*self._context_host).as_ptr();
|
||||
self.document_runtime
|
||||
.queue_content_security_policy_violation_event(scope, host_ptr, violation)?;
|
||||
Ok(())
|
||||
})
|
||||
self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime
|
||||
.queue_content_security_policy_violation_event(scope, host_ptr, violation)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -87,20 +77,12 @@ impl ScriptVm {
|
||||
if self.current_main_document_task_owner() != Some(task.owner()) {
|
||||
return ContentSecurityPolicyViolationBodyExecution::DiscardedStaleDocument;
|
||||
}
|
||||
let result = self
|
||||
.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
let scope = pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &self.page_default_runtime.context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let host_ptr: *mut JsContextHost = (*self._context_host).as_ptr();
|
||||
self.document_runtime
|
||||
.dispatch_content_security_policy_violation_event_page_task(
|
||||
scope, host_ptr, task,
|
||||
)?;
|
||||
Ok(())
|
||||
});
|
||||
let result = self.with_main_world_document_scope(|scope, host_ptr, document_runtime| {
|
||||
document_runtime.dispatch_content_security_policy_violation_event_page_task(
|
||||
scope, host_ptr, task,
|
||||
)?;
|
||||
Ok(())
|
||||
});
|
||||
ContentSecurityPolicyViolationBodyExecution::DispatchAttempted(result)
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -221,7 +221,8 @@ fn message_channel_construction_keeps_popup_realm_with_ambient_child_marker() {
|
||||
)
|
||||
};
|
||||
|
||||
let top_context_ptr = &vm.page_default_runtime.context as *const v8::Global<v8::Context>;
|
||||
let top_context_ptr =
|
||||
&vm.current_main_world().unwrap().context as *const v8::Global<v8::Context>;
|
||||
vm.with_context_scope_by_ptr(top_context_ptr, |scope, _host_ptr| {
|
||||
let _previous_child =
|
||||
crate::native_bridge::enter_active_child_window_scope(scope, Some(child_handle));
|
||||
|
||||
+2
-1
@@ -1419,7 +1419,8 @@ fn top_web_storage_receiver_ignores_ambient_opaque_child_owner() {
|
||||
"sandboxed child should have an opaque storage origin"
|
||||
);
|
||||
|
||||
let top_context_ptr = &vm.page_default_runtime.context as *const v8::Global<v8::Context>;
|
||||
let top_context_ptr =
|
||||
&vm.current_main_world().unwrap().context as *const v8::Global<v8::Context>;
|
||||
vm.with_context_scope_by_ptr(top_context_ptr, |scope, _host_ptr| {
|
||||
let _previous =
|
||||
crate::native_bridge::enter_active_child_window_scope(scope, Some(child_handle));
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ fn insert_adjacent_element_preserves_registered_native_alias_identity() {
|
||||
"<!doctype html><body><iframe id=child></iframe></body>",
|
||||
);
|
||||
vm.eval("globalThis.adjacentOwner=document.getElementById('child').contentWindow;globalThis.adjacentRoot=adjacentOwner.document.createElement('div');globalThis.adjacentNode=adjacentOwner.document.createElement('span');adjacentOwner.document.body.appendChild(adjacentRoot)").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, alias) in [
|
||||
|
||||
@@ -160,7 +160,7 @@ fn message_event_sources_preserve_registered_native_proxy_identity() {
|
||||
let mut vm = new_storage_html_test_vm("https://message-event-native-source.test/");
|
||||
vm.eval("document.body.innerHTML = '<iframe id=child></iframe>'; globalThis.sourcePort = new MessageChannel().port1;")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "sourcePort");
|
||||
|
||||
@@ -19,7 +19,7 @@ fn midi_events_preserve_payloads_and_webidl_buffer_policy() {
|
||||
fn midi_event_payloads_accept_native_ports_and_registered_event_proxies() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://midi-event-proxies.test/");
|
||||
vm.eval("document.body.innerHTML = '<iframe></iframe>'; globalThis.childWindow = document.querySelector('iframe').contentWindow;").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "childWindow");
|
||||
|
||||
@@ -320,7 +320,7 @@ fn dom_quad_generated_receivers_keep_registered_proxy_identity_and_error_realms(
|
||||
materialize_single_child_default_realm_for_test(&mut vm, "native Quad child Realm");
|
||||
vm.eval("globalThis.quadRealm = document.getElementById('native-quad-frame').contentWindow;")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "quadTarget");
|
||||
|
||||
@@ -889,7 +889,7 @@ fn dom_exception_factories_capture_v8_stacks_without_author_lookup() {
|
||||
fn dom_exception_getters_read_registered_native_proxy_targets() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://native-error-receiver.test/");
|
||||
vm.eval("globalThis.errors = [new DOMException('message','AbortError'),new QuotaExceededError('full',{quota:12}),new RTCError({errorDetail:'dtls-failure'},'rtc')]").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "errors");
|
||||
|
||||
@@ -22,7 +22,7 @@ fn web_transport_error_getters_accept_native_proxies_and_reject_author_wrappers(
|
||||
vm.eval(r#"document.body.innerHTML='<iframe></iframe>';
|
||||
globalThis.childWindow=document.querySelector('iframe').contentWindow;
|
||||
globalThis.errors=[new childWindow.WebTransportError('m\udfff',{source:'session',streamErrorCode:4294967295})];"#).unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "errors");
|
||||
@@ -77,7 +77,7 @@ fn web_transport_error_getters_accept_native_proxies_and_reject_author_wrappers(
|
||||
fn web_transport_error_deserialization_respects_native_realm_exposure() {
|
||||
let mut source = new_storage_page_task_executor_test_vm("https://transport-error-source.test/");
|
||||
source.eval("globalThis.value=new WebTransportError('message',{source:'session',streamErrorCode:42})").unwrap();
|
||||
let context_ptr = &source.page_default_runtime.context as *const _;
|
||||
let context_ptr = &source.current_main_world().unwrap().context as *const _;
|
||||
let mut payload = None;
|
||||
source
|
||||
.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
@@ -98,7 +98,7 @@ fn web_transport_error_deserialization_respects_native_realm_exposure() {
|
||||
.unwrap(),
|
||||
"false|undefined"
|
||||
);
|
||||
let context_ptr = &target.page_default_runtime.context as *const _;
|
||||
let context_ptr = &target.current_main_world().unwrap().context as *const _;
|
||||
target
|
||||
.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let scope = std::pin::pin!(v8::TryCatch::new(scope));
|
||||
|
||||
@@ -283,7 +283,7 @@ fn webrtc_event_dictionary_snapshots_preserve_registered_native_proxy_payloads()
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for name in ["snapshotCandidate", "snapshotChannel", "snapshotError"] {
|
||||
|
||||
@@ -34,7 +34,7 @@ fn canvas_fill_rect_registered_native_proxy_keeps_context_identity() {
|
||||
ctx.setTransform(1,0,0,1,20,10); ctx.fillStyle='red'; ctx.globalAlpha=.5;",
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "ctx");
|
||||
|
||||
@@ -36,7 +36,7 @@ fn canvas_transform_snapshots_accept_registered_native_proxies_and_share_paint_s
|
||||
for (const ctx of nativeCanvasContexts) ctx.setTransform(1,0,0,1,20,0);"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "nativeCanvasContexts");
|
||||
|
||||
@@ -47,7 +47,7 @@ fn credentials_container_accepts_registered_native_proxies_and_native_credential
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://credentials-container.test/");
|
||||
vm.eval("globalThis.nativeSignal = AbortSignal.abort({})")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let fixtures = v8::Object::new(scope);
|
||||
|
||||
@@ -5,7 +5,7 @@ fn credential_members_preserve_native_receiver_inheritance_and_error_realms() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://credential-interfaces.test/");
|
||||
vm.eval("document.body.innerHTML = '<iframe id=child></iframe>'")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let objects = v8::Object::new(scope);
|
||||
|
||||
@@ -388,7 +388,7 @@ root.appendChild(frame);
|
||||
// Use the production retirement path, pausing before a successor Realm
|
||||
// materializes, so the saved Location really belongs to a facade.
|
||||
vm.destroy_child_default_context(context_id);
|
||||
let context = &vm.page_default_runtime.context as *const v8::Global<v8::Context>;
|
||||
let context = &vm.current_main_world().unwrap().context as *const v8::Global<v8::Context>;
|
||||
vm.with_context_scope_by_ptr(context, |scope, _| {
|
||||
let host_ptr = crate::util::context_host_ptr_from_global_bridge(scope).unwrap();
|
||||
let host = unsafe { &mut *host_ptr };
|
||||
|
||||
@@ -22,7 +22,7 @@ fn css_keyframes_mutations_accept_native_proxies_and_preserve_intrinsic_exceptio
|
||||
const sheet=new other.CSSStyleSheet();sheet.replaceSync('@keyframes native {from {left:0px}}');
|
||||
globalThis.keyframes=sheet.cssRules[0];globalThis.frame=keyframes[0];
|
||||
"#).unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, proxy_name) in [("keyframes", "keyframesProxy"), ("frame", "frameProxy")] {
|
||||
|
||||
@@ -40,7 +40,7 @@ fn css_keyframes_receivers_share_native_proxy_backing_slots_and_owner_realm_cach
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, proxy_name) in [("keyframes", "framesProxy"), ("frame", "frameProxy")] {
|
||||
|
||||
@@ -97,7 +97,7 @@ fn document_create_event_uses_intrinsics_and_registered_native_receivers() {
|
||||
new_storage_page_task_executor_test_vm("https://document-create-event-native.test/");
|
||||
vm.eval("document.body.innerHTML='<iframe></iframe>'; globalThis.child=document.querySelector('iframe').contentWindow;")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "document");
|
||||
|
||||
+1
-1
@@ -3445,7 +3445,7 @@ fn window_named_access_uses_its_realm_during_child_history_callbacks() {
|
||||
._context_host
|
||||
.borrow()
|
||||
.child_browsing_context_handles_in_document_order()[0];
|
||||
let context = &vm.page_default_runtime.context as *const v8::Global<v8::Context>;
|
||||
let context = &vm.current_main_world().unwrap().context as *const v8::Global<v8::Context>;
|
||||
vm.with_context_scope_by_ptr(context, |scope, _| {
|
||||
crate::native_bridge::enter_active_child_window_scope(scope, Some(child));
|
||||
Ok(())
|
||||
|
||||
@@ -4,7 +4,7 @@ use super::*;
|
||||
fn dom_exception_getters_read_registered_native_proxy_targets() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://native-error-receiver.test/");
|
||||
vm.eval("globalThis.errors = [new DOMException('message','AbortError'),new QuotaExceededError('full',{quota:12})]").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "errors");
|
||||
|
||||
+2
-1
@@ -112,7 +112,8 @@ fn inspector_default_runtime_evaluate_masks_ambient_child_owner_scope() {
|
||||
.get(&child_context_id)
|
||||
.expect("Inspector child owner realm record should exist")
|
||||
.child_handle;
|
||||
let top_context_ptr = &vm.page_default_runtime.context as *const v8::Global<v8::Context>;
|
||||
let top_context_ptr =
|
||||
&vm.current_main_world().unwrap().context as *const v8::Global<v8::Context>;
|
||||
vm.with_context_scope_by_ptr(top_context_ptr, |scope, _host_ptr| {
|
||||
let _previous =
|
||||
crate::native_bridge::enter_active_child_window_scope(scope, Some(child_handle));
|
||||
|
||||
@@ -76,7 +76,7 @@ async fn xhr_generated_receivers_preserve_registered_native_proxy_state_and_load
|
||||
vm.eval(
|
||||
"globalThis.xhrOwner = document.querySelector('iframe').contentWindow; globalThis.realXhr = new xhrOwner.XMLHttpRequest(); globalThis.realUpload = realXhr.upload;",
|
||||
).unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, alias) in [("realXhr", "xhrProxy"), ("realUpload", "uploadProxy")] {
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ fn get_html_accepts_registered_native_proxies_and_rejects_author_receivers() {
|
||||
true"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, alias) in [
|
||||
|
||||
@@ -993,7 +993,7 @@ fn xml_http_request_blob_response_uses_final_mime_type() {
|
||||
let headers = moli_fetch::headers_from_byte_strings(&headers).unwrap();
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.page_default_runtime.context as *const _;
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -1094,7 +1094,8 @@ fn xml_http_request_default_response_type_parses_response_xml_for_document_mime(
|
||||
)
|
||||
.expect("xhr responseXML setup should run");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -1183,7 +1184,8 @@ fn xml_http_request_default_response_type_parses_response_xml_for_document_mime(
|
||||
#[test]
|
||||
fn xml_http_request_send_body_applies_webidl_conversion() {
|
||||
let vm = new_storage_test_vm("https://xhr-send-body-webidl.test/");
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
@@ -2011,7 +2013,8 @@ fn pending_network_body_stream_emits_small_chunks_before_close() {
|
||||
let mut vm = new_storage_test_vm("https://pending-stream-small-chunks.test/");
|
||||
let body_source_id = crate::network_host::new_network_body_source_id();
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -2045,7 +2048,8 @@ fn pending_network_body_stream_emits_small_chunks_before_close() {
|
||||
.expect("pending stream read should be registered");
|
||||
assert_eq!(initial, "[]");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -2075,7 +2079,8 @@ fn pending_network_body_stream_buffers_future_chunks_until_next_pull() {
|
||||
let mut vm = new_storage_test_vm("https://pending-stream-backpressure.test/");
|
||||
let body_source_id = crate::network_host::new_network_body_source_id();
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -2106,7 +2111,8 @@ fn pending_network_body_stream_buffers_future_chunks_until_next_pull() {
|
||||
)
|
||||
.expect("first pending stream read should be registered");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let buffered_len = vm
|
||||
.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
@@ -2393,7 +2399,8 @@ async fn streaming_subresource_finish_preserves_response_head_cache_state() {
|
||||
let mut body_writer = crate::types::SubresourceResponseBodyWriter::default();
|
||||
body_writer.append(b"cached-body");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let context_host = vm._context_host.clone();
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate({
|
||||
@@ -2551,7 +2558,8 @@ async fn async_subresource_failure_network_error_override_preserves_fetch_reject
|
||||
Url::parse("https://sw-non-stream-failure.test/data").expect("request URL should parse");
|
||||
let rejection_message = "FetchEvent.respondWith rejected an error Response";
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let context_host = vm._context_host.clone();
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate({
|
||||
@@ -2689,7 +2697,8 @@ async fn streaming_fetch_body_error_records_response_started_then_body_failed()
|
||||
let final_url = Url::parse("https://streaming-fetch-body-error.test/final")
|
||||
.expect("final URL should parse");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let context_host = vm._context_host.clone();
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate({
|
||||
@@ -2836,7 +2845,8 @@ fn install_streaming_fetch_response_fixture(
|
||||
global_name: &'static str,
|
||||
load_client: crate::network::ResourceRequestClient,
|
||||
) {
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let context_host = vm._context_host.clone();
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
@@ -2952,7 +2962,8 @@ async fn streaming_fetch_body_cancel_aborts_streaming_subresource() {
|
||||
let request_url = Url::parse("https://streaming-fetch-body-cancel.test/data")
|
||||
.expect("request URL should parse");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let context_host = vm._context_host.clone();
|
||||
let cancel_handle_for_state = cancel_handle.clone();
|
||||
vm.renderer_document_isolate
|
||||
@@ -3619,7 +3630,8 @@ async fn streaming_xhr_materialization_failure_errors_body_source_before_close()
|
||||
.truncate_file_for_test(0)
|
||||
.expect("test should truncate the pooled body file");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let context_host = vm._context_host.clone();
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
@@ -4263,7 +4275,7 @@ fn xml_http_request_document_response_requires_an_eligible_mime_and_well_formed_
|
||||
.expect("finish document response");
|
||||
} else {
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.page_default_runtime.context;
|
||||
&vm.current_main_world().unwrap().context;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
|
||||
@@ -37,7 +37,7 @@ fn encoded_video_chunk_preserves_bytes_transfer_conversion_and_serialization() {
|
||||
fn encoded_video_chunk_accepts_registered_native_proxy_receivers() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://encoded-video-chunk.test/");
|
||||
vm.eval("globalThis.nativeChunk = new EncodedVideoChunk({type:'delta', timestamp:-5, data:new Uint8Array([4,5])})").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "nativeChunk");
|
||||
|
||||
@@ -177,7 +177,7 @@ fn retained_response_body_keeps_bytes_until_the_last_v8_reference() {
|
||||
let callback = isolate.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let value = context
|
||||
.global(scope)
|
||||
@@ -430,7 +430,7 @@ fn retained_response_body_keeps_error_reason_until_the_last_v8_reference() {
|
||||
let callback = isolate.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let value = context
|
||||
.global(scope)
|
||||
@@ -786,7 +786,7 @@ fn retained_module_function_keeps_native_values_until_the_last_v8_reference() {
|
||||
let callback = isolate.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let value = context
|
||||
.global(scope)
|
||||
@@ -1196,7 +1196,7 @@ fn capture_initial_environment_for_gc_test(
|
||||
let environment = isolate.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
let scope = &mut scope.init();
|
||||
let context = v8::Local::new(scope, &vm.page_default_runtime.context);
|
||||
let context = v8::Local::new(scope, &vm.current_main_world().unwrap().context);
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let opener = context.global(scope);
|
||||
crate::script_vm::ScriptVmInitialDocumentEnvironment::inherited_in_scope(
|
||||
@@ -1316,7 +1316,7 @@ fn retained_document_realm_keeps_native_values_until_the_last_v8_reference() {
|
||||
.unwrap();
|
||||
let weak_host = vm.context_host_weak_for_test();
|
||||
let isolate = vm.renderer_document_isolate.clone();
|
||||
let context = vm.page_default_runtime.context.clone();
|
||||
let context = vm.current_main_world().unwrap().context.clone();
|
||||
drop(vm);
|
||||
assert!(
|
||||
weak_host.upgrade().is_some(),
|
||||
@@ -2959,7 +2959,10 @@ fn resource_owner_id_is_available_from_current_context_slot() {
|
||||
#[test]
|
||||
fn runtime_observable_context_token_is_available_from_current_context_slot() {
|
||||
let mut vm = new_parsed_test_vm("https://example.test/", "<!doctype html><p>runtime</p>");
|
||||
let expected = vm.page_default_runtime.runtime_observable_context_token;
|
||||
let expected = vm
|
||||
.current_main_world()
|
||||
.unwrap()
|
||||
.runtime_observable_context_token;
|
||||
|
||||
vm.with_default_context_scope_and_checkpoint_for_test(|scope, _runtime_ptr| {
|
||||
assert_eq!(
|
||||
|
||||
@@ -170,7 +170,7 @@ fn runtime_await_promise_sync_result_survives_queued_allocation_gc() {
|
||||
// deterministic: the page microtask runs after Inspector has converted the
|
||||
// synchronous string to an awaitable promise, but before Inspector's
|
||||
// reaction publishes the Runtime.evaluate response.
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context;
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.current_main_world().unwrap().context;
|
||||
vm.renderer_document_isolate
|
||||
.clone()
|
||||
.with_entered_renderer_document_isolate(|isolate| {
|
||||
|
||||
@@ -20,7 +20,7 @@ fn gamepad_events_preserve_native_payload_identity_and_registered_proxy_brands()
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://gamepad-payload.test/");
|
||||
vm.eval("document.body.innerHTML = '<iframe id=child></iframe>'")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
// Native identity fixtures only; these are not devices published by
|
||||
|
||||
@@ -197,7 +197,7 @@ impl SqlBackend {
|
||||
panic!("expected connection receipt");
|
||||
};
|
||||
self.connection.borrow_mut().replace(connection.downgrade());
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let database =
|
||||
crate::context_bootstrap::create_sql_database_for_test(scope, connection)
|
||||
|
||||
@@ -13,7 +13,7 @@ fn collect(vm: &mut PageVmTaskExecutorTestHarness) {
|
||||
}
|
||||
|
||||
fn native_entries(vm: &mut PageVmTaskExecutorTestHarness) -> usize {
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
Ok(crate::context_bootstrap::indexed_db_transaction_state_entries_for_test(scope, global))
|
||||
|
||||
@@ -6871,7 +6871,7 @@ fn indexed_db_request_getters_preserve_native_proxy_identity_and_reject_author_w
|
||||
nativeRequest.onupgradeneeded=()=>nativeRequest.result.createObjectStore('s');"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "nativeRequest");
|
||||
|
||||
@@ -27,7 +27,7 @@ fn indexed_db_completed_cursor_graphs_collect_and_retained_cursors_survive_gc()
|
||||
);
|
||||
collect(&mut vm);
|
||||
assert_eq!(vm.eval("checkIndexedDbCursorGc()").unwrap(), "true");
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
assert_eq!(
|
||||
crate::context_bootstrap::indexed_db_native_cursor_count_for_test(scope),
|
||||
@@ -101,7 +101,7 @@ fn indexed_db_schema_getters_accept_registered_native_proxies_in_callee_realms()
|
||||
)
|
||||
.unwrap();
|
||||
vm.eval_after_selected_page_tasks("'prepared'").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "schemaValues");
|
||||
|
||||
@@ -741,7 +741,7 @@ fn native_dom_exception_materializes_in_a_detached_realm() {
|
||||
0
|
||||
);
|
||||
let isolate = vm.renderer_document_isolate.clone();
|
||||
let context = vm.page_default_runtime.context.clone();
|
||||
let context = vm.current_main_world().unwrap().context.clone();
|
||||
drop(vm);
|
||||
isolate.with_renderer_document_isolate_mut(|isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
|
||||
@@ -23,7 +23,8 @@ fn media_device_interfaces_preserve_inheritance_brands_and_secure_exposure() {
|
||||
#[test]
|
||||
fn media_device_serialization_reads_native_fields_and_preserves_utf16() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://media-device-values.test/");
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
|
||||
@@ -47,7 +47,7 @@ fn message_port_transfer_respects_registered_native_proxy_identity() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://port-transfer.test/");
|
||||
vm.eval("globalThis.channel=new MessageChannel();globalThis.original=channel.port1")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "original");
|
||||
|
||||
@@ -265,7 +265,7 @@ fn mutation_observer_observe_accepts_registered_native_proxy_targets_and_receive
|
||||
rv.set(proxy.into());
|
||||
}
|
||||
let mut vm = new_storage_html_test_vm("https://mutation-observer-native-proxy.test/");
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let function = v8::Function::new(scope, register_proxy).unwrap();
|
||||
|
||||
@@ -42,7 +42,7 @@ fn payment_event_payloads_and_update_with_accept_registered_native_proxies() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://payment-native-proxy.test/");
|
||||
vm.eval("globalThis.paymentEvent = new PaymentMethodChangeEvent('x', {methodName:'pay', methodDetails:{token:42}})")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "paymentEvent");
|
||||
|
||||
@@ -14,7 +14,7 @@ fn picture_in_picture_interfaces_validate_descriptors_receivers_and_required_dic
|
||||
}
|
||||
|
||||
fn install_closed_window(vm: &mut ScriptVm) {
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let window = crate::context_bootstrap::closed_picture_in_picture_window_for_test(scope);
|
||||
@@ -107,7 +107,7 @@ fn picture_in_picture_native_event_proxies_read_the_original_private_payload() {
|
||||
new_storage_page_task_executor_test_vm("https://picture-in-picture-event-proxy.test/");
|
||||
install_closed_window(&mut vm);
|
||||
vm.eval("globalThis.nativeEvent = new PictureInPictureEvent('enterpictureinpicture', {pictureInPictureWindow:nativeWindow})").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "nativeEvent");
|
||||
|
||||
@@ -28,7 +28,7 @@ fn rtc_configuration_uses_registered_native_proxy_identity() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://rtc-configuration.test/");
|
||||
vm.eval("globalThis.pc = new RTCPeerConnection({iceTransportPolicy:'relay'})")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let target = global
|
||||
@@ -66,7 +66,7 @@ fn rtc_configuration_uses_registered_native_proxy_identity() {
|
||||
#[test]
|
||||
fn rtc_configuration_snapshots_preserve_certificate_identity_and_immutability() {
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://rtc-configuration.test/");
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let certificate = v8::Object::new(scope);
|
||||
crate::web_api_interfaces::RTCCertificate::DESCRIPTOR
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::*;
|
||||
|
||||
fn install_frames(vm: &mut ScriptVm) {
|
||||
use crate::context_bootstrap::encoded_frames::{FrameKind, native_frame_for_test};
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, kind, metadata) in [
|
||||
@@ -124,7 +124,7 @@ fn rtc_encoded_frame_cross_isolate_clone_respects_worker_exposure_and_private_in
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://rtc-encoded-frames.test/");
|
||||
install_frames(&mut vm);
|
||||
vm.eval("globalThis.__wireSource = [audioFrame, audioFrame.data, audioFrame, videoFrame, videoFrame.data]; true").unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
let payload = vm
|
||||
.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
|
||||
@@ -30,7 +30,7 @@ fn svg_geometry_methods_use_registered_proxy_geometry_without_author_traps() {
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
let key = crate::util::v8str(scope, "rect");
|
||||
|
||||
@@ -19,7 +19,7 @@ fn time_ranges_nonempty_native_snapshots_preserve_endpoints_and_uint32_conversio
|
||||
let mut vm = new_storage_page_task_executor_test_vm("https://time-ranges-native.test/");
|
||||
vm.eval("document.body.innerHTML = '<iframe id=child></iframe>'")
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let intervals = [(-3.5, -1.0), (0.0, 0.0), (0.25, 1.75), (4.0, f64::INFINITY)];
|
||||
let ranges = crate::context_bootstrap::new_time_ranges_value(scope, &intervals);
|
||||
|
||||
+18
-10
@@ -733,7 +733,8 @@ async fn response_clone_tees_pending_network_body_after_parent_consumption() {
|
||||
let response_url = Url::parse("https://response-clone-pending-stream.test/data.json")
|
||||
.expect("response URL should parse");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -799,7 +800,8 @@ async fn response_clone_tees_pending_network_body_after_parent_consumption() {
|
||||
)
|
||||
.expect("pending fetch clone fan-out should evaluate");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -843,7 +845,8 @@ fn pending_fetch_body_pipe_through_text_decoder_stream_pulls_future_chunks() {
|
||||
let response_url = Url::parse("https://pending-fetch-pipe-through.test/stream.txt")
|
||||
.expect("response URL should parse");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -905,7 +908,8 @@ fn pending_fetch_body_pipe_through_text_decoder_stream_pulls_future_chunks() {
|
||||
)
|
||||
.expect("pending fetch pipeThrough setup should evaluate");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -930,7 +934,8 @@ fn pending_fetch_body_pipe_through_text_decoder_stream_pulls_future_chunks() {
|
||||
.expect("first pending pipeThrough result should evaluate");
|
||||
assert_eq!(first, r#"["chunk:O"]"#);
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -965,7 +970,8 @@ fn materialize_response_object_preserves_redirected_slot() {
|
||||
.expect("document URL should parse");
|
||||
let final_url = Url::parse("https://response-materialize-redirected.test/final.txt")
|
||||
.expect("final URL should parse");
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
@@ -1026,7 +1032,7 @@ async fn filtered_response_materialization_preserves_urls_across_clone_and_cache
|
||||
)
|
||||
.expect("final URL should parse");
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.page_default_runtime.context as *const _;
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate({
|
||||
@@ -1134,7 +1140,7 @@ async fn filtered_response_materialization_preserves_urls_across_clone_and_cache
|
||||
);
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.page_default_runtime.context as *const _;
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -1186,7 +1192,8 @@ fn materialize_response_object_rejects_locked_response_body() {
|
||||
.expect("locked response setup should evaluate");
|
||||
assert_eq!(state, "true|false");
|
||||
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
let scope = std::pin::pin!(v8::HandleScope::new(isolate));
|
||||
@@ -1497,7 +1504,8 @@ fn fetched_null_bodies_discard_payloads_without_registering_pending_streams() {
|
||||
use crate::network_host::{FetchResponseRequest, MaterializedResponseBody};
|
||||
|
||||
let vm = new_storage_test_vm("https://null-response.test/");
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
let host = vm._context_host.clone();
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
|
||||
@@ -17,7 +17,8 @@ fn text_codec_runtime_preserves_streaming_bom_and_fatal_errors() {
|
||||
#[test]
|
||||
fn webidl_required_nullable_dictionary_rejects_undefined_member() {
|
||||
let vm = new_storage_test_vm("https://webidl-dictionary-nullable-required.test/");
|
||||
let context_ptr: *const v8::Global<v8::Context> = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr: *const v8::Global<v8::Context> =
|
||||
&vm.current_main_world().unwrap().context as *const _;
|
||||
|
||||
vm.renderer_document_isolate
|
||||
.with_entered_renderer_document_isolate(move |isolate| {
|
||||
|
||||
@@ -12,7 +12,7 @@ globalThis.aborting = new WritableStream();
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let context_ptr = &vm.page_default_runtime.context as *const _;
|
||||
let context_ptr = &vm.current_main_world().unwrap().context as *const _;
|
||||
vm.with_context_scope_by_ptr_and_checkpoint_for_test(context_ptr, |scope, _| {
|
||||
let global = scope.get_current_context().global(scope);
|
||||
for (name, alias) in [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{cell::RefCell, ops::Deref, rc::Weak};
|
||||
use std::{cell::RefCell, mem::ManuallyDrop, ops::Deref, rc::Weak};
|
||||
|
||||
use crate::native_bridge::{JsContextHost, JsContextHostBridgeRef, RuntimeObservableContextToken};
|
||||
|
||||
@@ -8,7 +8,8 @@ use super::RendererDeferredContextHostReleaseQueue;
|
||||
/// with the Context through prebootstrap and publication. Retained JS objects
|
||||
/// own their native backing separately; they never own this runtime record.
|
||||
pub(crate) struct WindowRealmRuntime {
|
||||
state: Option<WindowRealmRuntimeState>,
|
||||
// Always live until Drop moves it into the deferred-close queue.
|
||||
state: ManuallyDrop<WindowRealmRuntimeState>,
|
||||
deferred_releases: RendererDeferredContextHostReleaseQueue,
|
||||
closed: bool,
|
||||
}
|
||||
@@ -31,20 +32,6 @@ impl std::fmt::Debug for WindowRealmRuntimeState {
|
||||
}
|
||||
|
||||
impl WindowRealmRuntime {
|
||||
pub(super) fn uninitialized(
|
||||
deferred_releases: RendererDeferredContextHostReleaseQueue,
|
||||
) -> Self {
|
||||
Self {
|
||||
state: None,
|
||||
deferred_releases,
|
||||
closed: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_initialized(&self) -> bool {
|
||||
self.state.is_some()
|
||||
}
|
||||
|
||||
pub(super) fn new(
|
||||
scope: &mut v8::PinScope<'_, '_, ()>,
|
||||
context: v8::Local<'_, v8::Context>,
|
||||
@@ -54,7 +41,7 @@ impl WindowRealmRuntime {
|
||||
isolated: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
state: Some(WindowRealmRuntimeState {
|
||||
state: ManuallyDrop::new(WindowRealmRuntimeState {
|
||||
context: v8::Global::new(scope, context),
|
||||
runtime_observable_context_token,
|
||||
bridge_ref: None,
|
||||
@@ -67,7 +54,7 @@ impl WindowRealmRuntime {
|
||||
}
|
||||
|
||||
pub(super) fn install_bridge_ref(&mut self, bridge_ref: JsContextHostBridgeRef) {
|
||||
let previous = self.state.as_mut().unwrap().bridge_ref.replace(bridge_ref);
|
||||
let previous = self.state.bridge_ref.replace(bridge_ref);
|
||||
assert!(
|
||||
previous.is_none(),
|
||||
"a Window realm has one native bridge owner"
|
||||
@@ -79,9 +66,11 @@ impl WindowRealmRuntime {
|
||||
}
|
||||
|
||||
pub(super) fn release_bridge_ref(&mut self) {
|
||||
if let Some(state) = self.state.as_mut() {
|
||||
state.bridge_ref.take();
|
||||
}
|
||||
self.state.bridge_ref.take();
|
||||
}
|
||||
|
||||
pub(super) fn context_ptr(&self) -> *const v8::Global<v8::Context> {
|
||||
&self.context
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,19 +78,19 @@ impl Deref for WindowRealmRuntime {
|
||||
type Target = WindowRealmRuntimeState;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.state
|
||||
.as_ref()
|
||||
.expect("a live runtime owns its Context")
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WindowRealmRuntime {
|
||||
fn drop(&mut self) {
|
||||
if !self.closed && self.state.is_some() {
|
||||
// SAFETY: new() initializes state, no method moves it, and Drop takes
|
||||
// it exactly once. The ManuallyDrop field never drops the moved state.
|
||||
let mut state = unsafe { ManuallyDrop::take(&mut self.state) };
|
||||
if !self.closed {
|
||||
// A cache replacement or bootstrap error can occur during a V8
|
||||
// callback with the host already borrowed. Drop only queues the
|
||||
// record; cleanup runs after the outer entered-isolate operation.
|
||||
let mut state = self.state.take().unwrap();
|
||||
// Before publication this bridge token is the only native owner
|
||||
// installed in the Context. Do not defer it past recovery of the
|
||||
// bootstrap's DocumentRuntime, which the host only borrows.
|
||||
|
||||
@@ -323,11 +323,12 @@ impl ScriptVm {
|
||||
stack: message.stack,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
} else if let Some(runtime) = self.current_main_world() {
|
||||
let context_token = runtime.runtime_observable_context_token;
|
||||
self.runtime_observable_source_queue
|
||||
.record_pending_console_event(
|
||||
crate::native_bridge::PendingRuntimeObservableConsoleSourceEvent::new(
|
||||
self.page_default_runtime.runtime_observable_context_token,
|
||||
context_token,
|
||||
message.message,
|
||||
message.args,
|
||||
message.stack,
|
||||
|
||||
Reference in New Issue
Block a user