Skip to content

Commit a24d90c

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 a24d90c

1 file changed

Lines changed: 10 additions & 24 deletions

File tree

cranelift/jit/src/backend.rs

Lines changed: 10 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,9 @@ 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+
/// Map from a function's start address to its (end address, FuncId), used
180+
/// to resolve a PC back to its function for exception unwinding.
181+
code_ranges: BTreeMap<usize, (usize, FuncId)>,
179182
functions_to_finalize: Vec<FuncId>,
180183
data_objects_to_finalize: Vec<DataId>,
181184
}
@@ -334,9 +337,6 @@ impl JITModule {
334337
data.perform_relocations(|name| self.get_address(name));
335338
}
336339

337-
self.code_ranges
338-
.sort_unstable_by_key(|(start, _end, _)| *start);
339-
340340
// Now that we're done patching, prepare the memory for execution!
341341
let branch_protection = if cfg!(target_arch = "aarch64") && use_bti(&self.isa.isa_flags()) {
342342
BranchProtection::BTI
@@ -367,7 +367,7 @@ impl JITModule {
367367
declarations: ModuleDeclarations::default(),
368368
compiled_functions: SecondaryMap::new(),
369369
compiled_data_objects: SecondaryMap::new(),
370-
code_ranges: Vec::new(),
370+
code_ranges: BTreeMap::new(),
371371
functions_to_finalize: Vec::new(),
372372
data_objects_to_finalize: Vec::new(),
373373
}
@@ -382,23 +382,10 @@ impl JITModule {
382382
pc: usize,
383383
) -> Option<(usize, wasmtime_unwinder::ExceptionTable<'a>)> {
384384
// 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];
385+
let (&start, &(end, func)) = self.code_ranges.range(..=pc).next_back()?;
386+
if pc >= end {
387+
return None;
388+
}
402389

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

522509
let range_start = ptr.addr();
523510
let range_end = range_start + size;
524-
// These will be sorted when we finalize.
525-
self.code_ranges.push((range_start, range_end, id));
511+
self.code_ranges.insert(range_start, (range_end, id));
526512

527513
self.functions_to_finalize.push(id);
528514

0 commit comments

Comments
 (0)