Compress in-memory representation of FunctionAddressMap (#2321)

This commit compresses `FunctionAddressMap` by performing a simple
coalescing of adjacent `InstructionAddressMap` descriptors if they
describe the same source location. This is intended to handle the common
case where a sequene of machine instructions describes a high-level wasm
instruction.

For the module on #2318 this reduces the cache entry size from 306MB to
161MB.
This commit is contained in:
Alex Crichton
2020-10-26 13:22:25 -05:00
committed by GitHub
parent 27233857c5
commit f6d5b8772c

View File

@@ -233,18 +233,16 @@ fn get_function_address_map<'data>(
body_len: usize, body_len: usize,
isa: &dyn isa::TargetIsa, isa: &dyn isa::TargetIsa,
) -> FunctionAddressMap { ) -> FunctionAddressMap {
let mut instructions = Vec::new(); let instructions = if let Some(ref mcr) = &context.mach_compile_result {
if let Some(ref mcr) = &context.mach_compile_result {
// New-style backend: we have a `MachCompileResult` that will give us `MachSrcLoc` mapping // New-style backend: we have a `MachCompileResult` that will give us `MachSrcLoc` mapping
// tuples. // tuples.
for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() { collect_address_maps(mcr.buffer.get_srclocs_sorted().into_iter().map(
instructions.push(InstructionAddressMap { |&MachSrcLoc { start, end, loc }| InstructionAddressMap {
srcloc: loc, srcloc: loc,
code_offset: start as usize, code_offset: start as usize,
code_len: (end - start) as usize, code_len: (end - start) as usize,
}); },
} ))
} else { } else {
// Old-style backend: we need to traverse the instruction/encoding info in the function. // Old-style backend: we need to traverse the instruction/encoding info in the function.
let func = &context.func; let func = &context.func;
@@ -252,17 +250,17 @@ fn get_function_address_map<'data>(
blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase
let encinfo = isa.encoding_info(); let encinfo = isa.encoding_info();
for block in blocks { collect_address_maps(
for (offset, inst, size) in func.inst_offsets(block, &encinfo) { blocks
let srcloc = func.srclocs[inst]; .into_iter()
instructions.push(InstructionAddressMap { .flat_map(|block| func.inst_offsets(block, &encinfo))
srcloc, .map(|(offset, inst, size)| InstructionAddressMap {
srcloc: func.srclocs[inst],
code_offset: offset as usize, code_offset: offset as usize,
code_len: size as usize, code_len: size as usize,
}); }),
} )
} };
}
// Generate artificial srcloc for function start/end to identify boundary // Generate artificial srcloc for function start/end to identify boundary
// within module. Similar to FuncTranslator::cur_srcloc(): it will wrap around // within module. Similar to FuncTranslator::cur_srcloc(): it will wrap around
@@ -282,6 +280,30 @@ fn get_function_address_map<'data>(
} }
} }
// Collects an iterator of `InstructionAddressMap` into a `Vec` for insertion
// into a `FunctionAddressMap`. This will automatically coalesce adjacent
// instructions which map to the same original source position.
fn collect_address_maps(
iter: impl IntoIterator<Item = InstructionAddressMap>,
) -> Vec<InstructionAddressMap> {
let mut iter = iter.into_iter();
let mut cur = match iter.next() {
Some(i) => i,
None => return Vec::new(),
};
let mut ret = Vec::new();
for item in iter {
if cur.code_offset + cur.code_len == item.code_offset && item.srcloc == cur.srcloc {
cur.code_len += item.code_len;
} else {
ret.push(cur);
cur = item;
}
}
ret.push(cur);
return ret;
}
/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR,
/// optimizing it and then translating to assembly. /// optimizing it and then translating to assembly.
#[derive(Default)] #[derive(Default)]