Skip to content

Commit eef6f2c

Browse files
committed
Cranelift: use a BTreeMap for JITModule code ranges
`JITModule` resolves a PC back to its defining function (for exception unwinding) via a `Vec<(start, end, FuncId)>` that was re-sorted in full on every `finalize_definitions` call. Code that defines and finalizes functions one at a time therefore paid an O(n) sort per finalize, i.e. O(n^2) overall. Replace the vector with a `BTreeMap` keyed on the start address. Inserts stay sorted incrementally (O(log n)) and the lookup becomes an O(log n) range query, so finalizing is linear in the number of functions with no sort.
1 parent fabee3a commit eef6f2c

1 file changed

Lines changed: 8 additions & 24 deletions

File tree

cranelift/jit/src/backend.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use cranelift_module::{
1616
};
1717
use log::info;
1818
use std::cell::RefCell;
19+
use std::collections::BTreeMap;
1920
use std::collections::HashMap;
2021
use std::ffi::CString;
2122
use std::io::Write;
@@ -175,7 +176,7 @@ pub struct JITModule {
175176
declarations: ModuleDeclarations,
176177
compiled_functions: SecondaryMap<FuncId, Option<CompiledBlob>>,
177178
compiled_data_objects: SecondaryMap<DataId, Option<CompiledBlob>>,
178-
code_ranges: Vec<(usize, usize, FuncId)>,
179+
code_ranges: BTreeMap<usize, (usize, FuncId)>,
179180
functions_to_finalize: Vec<FuncId>,
180181
data_objects_to_finalize: Vec<DataId>,
181182
}
@@ -334,9 +335,6 @@ impl JITModule {
334335
data.perform_relocations(|name| self.get_address(name));
335336
}
336337

337-
self.code_ranges
338-
.sort_unstable_by_key(|(start, _end, _)| *start);
339-
340338
// Now that we're done patching, prepare the memory for execution!
341339
let branch_protection = if cfg!(target_arch = "aarch64") && use_bti(&self.isa.isa_flags()) {
342340
BranchProtection::BTI
@@ -367,7 +365,7 @@ impl JITModule {
367365
declarations: ModuleDeclarations::default(),
368366
compiled_functions: SecondaryMap::new(),
369367
compiled_data_objects: SecondaryMap::new(),
370-
code_ranges: Vec::new(),
368+
code_ranges: BTreeMap::new(),
371369
functions_to_finalize: Vec::new(),
372370
data_objects_to_finalize: Vec::new(),
373371
}
@@ -382,23 +380,10 @@ impl JITModule {
382380
pc: usize,
383381
) -> Option<(usize, wasmtime_unwinder::ExceptionTable<'a>)> {
384382
// Search the sorted code-ranges for the PC.
385-
let idx = match self
386-
.code_ranges
387-
.binary_search_by_key(&pc, |(start, _end, _func)| *start)
388-
{
389-
Ok(exact_start_match) => Some(exact_start_match),
390-
Err(least_upper_bound) if least_upper_bound > 0 => {
391-
let last_range_before_pc = &self.code_ranges[least_upper_bound - 1];
392-
if last_range_before_pc.0 <= pc && pc < last_range_before_pc.1 {
393-
Some(least_upper_bound - 1)
394-
} else {
395-
None
396-
}
397-
}
398-
_ => None,
399-
}?;
400-
401-
let (start, _, func) = self.code_ranges[idx];
383+
let (&start, &(end, func)) = self.code_ranges.range(..=pc).next_back()?;
384+
if pc >= end {
385+
return None;
386+
}
402387

403388
// Get the ExceptionTable. The "parse" here simply reads two
404389
// u32s for lengths and constructs borrowed slices, so it's
@@ -521,8 +506,7 @@ impl Module for JITModule {
521506

522507
let range_start = ptr.addr();
523508
let range_end = range_start + size;
524-
// These will be sorted when we finalize.
525-
self.code_ranges.push((range_start, range_end, id));
509+
self.code_ranges.insert(range_start, (range_end, id));
526510

527511
self.functions_to_finalize.push(id);
528512

0 commit comments

Comments
 (0)