Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 42 additions & 9 deletions crates/wasm_split_cli/src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ impl<'a> EmitState<'a> {
let mut shared_names = HashMap::new();
// We potentially overwrite the mapping later on again, but that's okay.
// We could also check the reloc section for better names.
let shared_by_import = program_info
let mut shared_by_import = program_info
.shared_deps
.iter()
.filter(|dep| !matches!(dep, DepNode::Function(_) | DepNode::DataSymbol(_)));
for (unique_id, dep) in shared_by_import.enumerate() {
.filter(|dep| !matches!(dep, DepNode::Function(_) | DepNode::DataSymbol(_)))
.collect::<Vec<_>>();
shared_by_import.sort();
for (unique_id, dep) in shared_by_import.into_iter().enumerate() {
let chosen_name = Cow::Owned(format!("__wasm_split_shared{unique_id}"));
shared_names.insert(*dep, chosen_name);
}
Expand Down Expand Up @@ -177,13 +179,28 @@ impl<'a> EmitState<'a> {
}
}

#[derive(Debug, Default)]
#[derive(Default)]
struct IndirectFunctionEmitInfo {
table_entries: Vec<InputFuncId>,
function_table_index: HashMap<InputFuncId, usize>,
table_range_for_output_module: Vec<Range<usize>>,
}

impl std::fmt::Debug for IndirectFunctionEmitInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let _ = self.function_table_index;
f.debug_struct("IndirectFunctionEmitInfo")
.field("table_entries", &self.table_entries)
// Omit this field since it's derived from table_entries
// .field("function_table_index", &self.function_table_index)
.field(
"table_range_for_output_module",
&self.table_range_for_output_module,
)
.finish()
}
}

impl IndirectFunctionEmitInfo {
fn new(module: &InputModule, program_info: &SplitProgramInfo) -> Result<Self> {
let mut indirect_functions = module
Expand Down Expand Up @@ -217,7 +234,8 @@ impl IndirectFunctionEmitInfo {
};

let mut table_entries: Vec<_> = indirect_functions.into_iter().collect();
table_entries.sort_unstable_by_key(|&func_id| module_for_func(func_id));
// all keys are unique, hence this sort is actually stable
table_entries.sort_unstable_by_key(|&func_id| (module_for_func(func_id), func_id));
let function_table_index: HashMap<_, _> = table_entries
.iter()
.enumerate()
Expand Down Expand Up @@ -282,6 +300,7 @@ enum DataSegmentEmitInfo {
},
}

#[derive(Debug)]
struct DataEmitInfo {
per_segment: Vec<DataSegmentEmitInfo>,
}
Expand Down Expand Up @@ -364,7 +383,10 @@ impl DataEmitInfo {
Some(Ok((symbol_index, def_data)))
})
.collect::<Result<Vec<_>>>()?;
included_symbols.sort_by_key(|(_, def_data)| (def_data.index, def_data.offset));
// all keys are unique by the inclusion of the symbol index
included_symbols.sort_unstable_by_key(|&(sym_index, ref def_data)| {
(def_data.index, def_data.offset, sym_index)
});
for (symbol_index, def_data) in included_symbols {
let segment_index = def_data.index as usize;
let DataSegmentAnalysis::Ranges {
Expand Down Expand Up @@ -701,7 +723,13 @@ impl<'a> ModuleEmitState<'a> {
});
}

for dep in &output_module_info.included_symbols {
let mut included_symbols = output_module_info
.included_symbols
.iter()
.cloned()
.collect::<Vec<_>>();
included_symbols.sort();
for dep in &included_symbols {
if let &dep @ DepNode::Function(input_func) = dep {
let is_import = input_func < emit_state.input_module.imported_funcs.len();
if !is_import {
Expand Down Expand Up @@ -730,7 +758,12 @@ impl<'a> ModuleEmitState<'a> {
let mut also_needs_indirect_table =
!emit_state.indirect_functions.table_range_for_output_module[output_module_index]
.is_empty();
for used_shared in &output_module_info.used_shared_deps {
let mut used_shared_deps = output_module_info
.used_shared_deps
.iter()
.collect::<Vec<_>>();
used_shared_deps.sort();
for used_shared in used_shared_deps {
if output_module_info.included_symbols.contains(used_shared) {
continue;
}
Expand Down Expand Up @@ -809,7 +842,7 @@ impl<'a> ModuleEmitState<'a> {
});
exported_dont_share.insert(dep);
}
for dep in &output_module_info.included_symbols {
for dep in &included_symbols {
if !program_info.shared_deps.contains(dep) || exported_dont_share.contains(dep) {
continue;
}
Expand Down
8 changes: 6 additions & 2 deletions crates/wasm_split_cli/src/reloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ impl<'a> RelocInfoParser<'a> {
.entries()
.into_iter()
.collect::<Result<Vec<_>, _>>()?;
reloc_entries.sort_by_key(|entry| entry.offset);
// We need to slices of entries when we search for a specific offset
// We *might* be fine with assuming that the entries are already sorted, but a single pass to correct this
// doesn't cost a lot of performance.
reloc_entries.sort_unstable_by_key(|entry| entry.offset);
self.info
.relocs
.insert(reader.section_index() as SectionIndex, reloc_entries);
Expand Down Expand Up @@ -211,7 +214,8 @@ fn get_data_symbols(data_segments: &[Data], symbols: &[SymbolInfo]) -> Result<Ve
range: shift_range(symbol_range, data_offset),
});
}
data_symbols.sort_by_key(|symbol| symbol.range.start);
// We assume that these are sorted by range start later on
data_symbols.sort_unstable_by_key(|symbol| symbol.range.start);
Ok(data_symbols)
}

Expand Down
8 changes: 7 additions & 1 deletion crates/wasm_split_cli/src/split_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ pub fn get_split_points(module: &InputModule) -> Result<Vec<SplitPoint>> {
);
}

// This sort here should not influence downstream results,
// but we do it anyway for good measure since its cheap
let mut split_points = split_points;
split_points.sort_unstable_by_key(|split| split.export);
Ok(split_points)
}

Expand Down Expand Up @@ -572,9 +576,11 @@ pub fn compute_split_modules(
program_info.split_points = split_points;

program_info.output_modules = split_module_contents.into_iter().collect();
// We sort by split module here to get a stable assignment from split->output index
// An unstable sort is sufficient, no two keys compare equal.
program_info
.output_modules
.sort_by_key(|(identifier, _)| (*identifier).clone());
.sort_unstable_by_key(|(identifier, _)| (*identifier).clone());

for (output_index, (_, info)) in program_info.output_modules.iter().enumerate() {
for &symbol in info.included_symbols.iter() {
Expand Down
71 changes: 71 additions & 0 deletions test-runner/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ tracing-subscriber = { version = "0.3.23", features = ["fmt"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.150"
serde_with = "3.21.0"
sha2 = "0.11.0"
Loading