fix: reconcile shared module sources and main regressions

This commit is contained in:
ldm0
2026-10-11 18:06:45 +08:00
parent ea1354d461
commit 8eddfcff7b
8 changed files with 11 additions and 142 deletions
-1
View File
@@ -6798,7 +6798,6 @@ async fn parse_time_lifecycle_queue_can_stop_cleanly_at_load_stage_after_load_mi
Ok(())
}
#[path = "scripts/child_markup_insertion.rs"]
mod child_markup_insertion;
#[path = "scripts/preload_consumption.rs"]
-27
View File
@@ -335,33 +335,6 @@ impl NativeDom {
.map(|document| document.scripting_enabled())
}
pub(crate) fn light_subtree_handles(
&self,
root: NativeNodeId,
include_root: bool,
) -> impl Iterator<Item = NativeNodeId> + '_ {
let first = self.node(root).and_then(|node| {
if include_root {
Some(root)
} else {
node.first_child()
}
});
std::iter::successors(first, move |&handle| {
if let Some(child) = self.first_child(handle) {
return Some(child);
}
let mut current = handle;
while current != root {
if let Some(sibling) = self.next_sibling(current) {
return Some(sibling);
}
current = self.parent_node(current)?;
}
None
})
}
fn collect_matching_elements(
&self,
root: NativeNodeId,
@@ -80,10 +80,11 @@ impl ModuleKind {
/// Whether the module map still needs the fetched source after compilation.
pub(crate) fn retains_source_after_compilation(self) -> bool {
match self {
// V8 owns JavaScript source; synthetic text records own JSON/CSS source.
Self::JavaScript | Self::Json | Self::Css => false,
// Preserve the separate source semantics of Wasm and text preloads.
Self::WebAssembly | Self::ModulePreloadText => true,
// V8 owns JavaScript source and parsed JSON/text exports; compiled
// CSS records retain their shared source allocation.
Self::JavaScript | Self::Json | Self::Css | Self::Text => false,
// Wasm source-phase imports still need the original bytes.
Self::WebAssembly => true,
}
}
}
+3 -2
View File
@@ -2750,6 +2750,7 @@ mod tests {
for (module_type, text) in [
("json", r#"{"answer":42}"#),
("css", "body { color: red; }"),
("text", "plain text export"),
] {
let mut vm = new_test_vm("https://app.example.test/page");
let source_url = url(&format!("https://app.example.test/source.{module_type}"));
@@ -2785,10 +2786,10 @@ mod tests {
);
drop(fetched);
drop(source);
if module_type == "json" {
if module_type != "css" {
assert!(
weak_source.upgrade().is_none(),
"parsed JSON modules must release the original source text",
"{module_type}: V8 exports must release the original source text",
);
} else {
assert_eq!(
@@ -71,7 +71,9 @@ impl ScriptVm {
)
}
ModuleKind::Json | ModuleKind::Css | ModuleKind::Text => {
let ModuleSource::Text(source) = source else {
let (ModuleSource::Text(source) | ModuleSource::TextWithOrigin { source, .. }) =
source
else {
return Err(ModuleLoadError::new(
ModuleLoadStage::Compile,
format!("synthetic text module `{source_url}` did not retain text source"),
@@ -394,57 +394,6 @@ fn document_open_resets_compat_mode_and_parser_updates_it_incrementally() {
);
}
#[test]
fn child_document_open_resets_compat_mode_before_doctype_or_eof() {
let mut vm = new_parsed_test_vm(
"https://child-document-open-quirks.test/",
"<!doctype html><body>parent",
);
let result = vm
.eval(
r#"
(() => {
const f = document.body.appendChild(document.createElement('iframe'));
const d = f.contentDocument;
const rows = [];
for (const chunks of [
[],
['<!doctype html public', ' "-//IETF//DTD HTML 3//"', '>'],
['<!doctype html', '>'],
['<!--comment-->', '<body>quirks'],
['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">']
]) {
const modes = [d.compatMode];
d.open();
modes.push(d.compatMode);
for (const chunk of chunks) {
d.write(chunk);
modes.push(d.compatMode);
}
d.close();
modes.push(d.compatMode);
rows.push(modes.join('|'));
}
f.remove();
return rows.join('\n');
})()
"#,
)
.unwrap();
assert_eq!(
result,
[
"BackCompat|CSS1Compat|BackCompat",
"BackCompat|CSS1Compat|CSS1Compat|CSS1Compat|BackCompat|BackCompat",
"BackCompat|CSS1Compat|CSS1Compat|CSS1Compat|CSS1Compat",
"CSS1Compat|CSS1Compat|CSS1Compat|BackCompat|BackCompat",
"BackCompat|CSS1Compat|CSS1Compat|CSS1Compat",
]
.join("\n")
);
assert_eq!(vm.eval("document.compatMode").unwrap(), "CSS1Compat");
}
#[test]
fn child_document_open_initializes_native_no_quirks_mode() {
for open in ["d.open()", "d.write('<!doctype html')"] {
@@ -791,44 +740,3 @@ fn child_document_open_resets_compat_mode_before_doctype_or_eof() {
);
assert_eq!(vm.eval("document.compatMode").unwrap(), "CSS1Compat");
}
#[test]
fn child_document_open_initializes_native_no_quirks_mode() {
for open in ["d.open()", "d.write('<!doctype html')"] {
let mut vm = new_parsed_test_vm(
"https://child-document-open-native-mode.test/",
"<body>quirks parent",
);
vm.eval(&format!(
r#"
const f = document.body.appendChild(document.createElement('iframe'));
f.id = 'mode-frame';
const d = f.contentDocument;
{open};
const html = d.appendChild(d.createElement('html'));
html.appendChild(d.createElement('body'));
d.body.innerHTML = '<p class="UPPER">child</p>';
"#
))
.unwrap();
assert_eq!(
vm.eval("JSON.stringify([d.compatMode, d.querySelectorAll('.upper').length, document.compatMode])")
.unwrap(),
r#"["CSS1Compat",0,"BackCompat"]"#,
"{open}"
);
let host = vm._context_host.borrow();
let frame = host.dom_host().element_handle_by_id("mode-frame").unwrap();
let document = host.child_browsing_context_document_handle(frame).unwrap();
assert_eq!(
host.dom_host()
.node(document)
.unwrap()
.as_document()
.unwrap()
.quirks_mode(),
selectors::matching::QuirksMode::NoQuirks,
"{open}: native mode must not be limited-quirks"
);
}
}
@@ -2331,7 +2331,6 @@ mod window_cross_origin_getters;
mod window_event_receivers;
mod window_execution_context;
mod window_getter_consolidation;
mod worklet_interfaces;
mod payment_response_interfaces;
mod body_mime_consolidation;
@@ -3604,20 +3604,6 @@ async fn worker_does_not_expose_window_worklet_interfaces() {
);
}
#[tokio::test]
async fn worker_does_not_expose_window_media_device_interfaces() {
ensure_v8();
let mut handle = spawn_worker("postMessage({MediaDeviceInfo:'MediaDeviceInfo' in self,InputDeviceInfo:'InputDeviceInfo' in self});close();".to_owned(), "https://media-device-worker.test/worker.js".into());
let message = timeout(TIMEOUT, handle.recv())
.await
.expect("timed out")
.expect("channel closed");
assert_eq!(
expect_post_json(message),
r#"{"MediaDeviceInfo":false,"InputDeviceInfo":false}"#
);
}
#[tokio::test]
async fn worker_does_not_expose_window_audio_node_interface() {
ensure_v8();