mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 18:20:51 +00:00
Merge pull request #987 from alexcrichton/gc-locals
Add gc support for locals in functions
This commit is contained in:
commit
ec6e13a0f8
@ -8,8 +8,9 @@ extern crate parity_wasm;
|
||||
extern crate log;
|
||||
extern crate rustc_demangle;
|
||||
|
||||
use std::mem;
|
||||
use std::collections::HashSet;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
|
||||
use parity_wasm::elements::*;
|
||||
|
||||
@ -132,6 +133,8 @@ fn run(config: &mut Config, module: &mut Module) {
|
||||
module.sections_mut().remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
gc_locals(module);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@ -839,3 +842,124 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gc_locals(module: &mut Module) {
|
||||
let mut code = None;
|
||||
let mut types = None;
|
||||
let mut functions = None;
|
||||
let mut locals = None;
|
||||
let mut imported_functions = 0;
|
||||
for section in module.sections_mut() {
|
||||
match section {
|
||||
Section::Import(s) => imported_functions = s.functions(),
|
||||
Section::Code(s) => code = Some(s),
|
||||
Section::Function(s) => functions = Some(s),
|
||||
Section::Type(s) => types = Some(s),
|
||||
Section::Name(NameSection::Local(s)) => locals = Some(s),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let code = match code {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
let types = types.unwrap();
|
||||
let functions = functions.unwrap();
|
||||
|
||||
for (i, body) in code.bodies_mut().iter_mut().enumerate() {
|
||||
let ty_idx = functions.entries()[i].type_ref();
|
||||
let ty = match &types.types()[ty_idx as usize] {
|
||||
Type::Function(f) => f,
|
||||
};
|
||||
gc_body((i + imported_functions) as u32, body, ty, &mut locals);
|
||||
}
|
||||
}
|
||||
|
||||
/// Each body of a function has a list of locals, and each local has a type and
|
||||
/// a number of how many locals of this type there are. The purpose of this is
|
||||
/// to collapse something like:
|
||||
///
|
||||
/// Local::new(1, ValueType::I32);
|
||||
/// Local::new(1, ValueType::I32);
|
||||
///
|
||||
/// to ...
|
||||
///
|
||||
/// Local::new(2, ValueType::I32);
|
||||
///
|
||||
/// to encode this a bit more compactly
|
||||
fn gc_body(
|
||||
idx: u32,
|
||||
body: &mut FuncBody,
|
||||
ty: &FunctionType,
|
||||
names: &mut Option<&mut LocalNameSection>,
|
||||
) {
|
||||
let mut local_tys = ty.params().to_vec();
|
||||
for local in body.locals_mut().drain(..) {
|
||||
local_tys.extend(iter::repeat(local.value_type()).take(local.count() as usize));
|
||||
}
|
||||
let mut used = vec![false; local_tys.len()];
|
||||
|
||||
for instr in body.code().elements() {
|
||||
match instr {
|
||||
Instruction::GetLocal(i) => used[*i as usize] = true,
|
||||
Instruction::SetLocal(i) => used[*i as usize] = true,
|
||||
Instruction::TeeLocal(i) => used[*i as usize] = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut map = vec![None; local_tys.len()];
|
||||
for i in 0..ty.params().len() {
|
||||
map[i] = Some(i as u32);
|
||||
}
|
||||
let mut next = ty.params().len() as u32;
|
||||
for i in ty.params().len()..used.len() {
|
||||
if !used[i] {
|
||||
continue
|
||||
}
|
||||
// We're using this local, so map it to the next index (the lowest).
|
||||
// Find all other locals with the same type and lump then into our
|
||||
// `Local` declaration.
|
||||
let before = next;
|
||||
map[i] = Some(next);
|
||||
next += 1;
|
||||
for j in i + 1..used.len() {
|
||||
if used[j] && local_tys[i] == local_tys[j] {
|
||||
used[j] = false; // make sure we don't visit this later
|
||||
map[j] = Some(next);
|
||||
next += 1;
|
||||
}
|
||||
}
|
||||
body.locals_mut().push(Local::new((next - before) as u32, local_tys[i]));
|
||||
}
|
||||
|
||||
for instr in body.code_mut().elements_mut() {
|
||||
let get = |i: &u32| {
|
||||
map[*i as usize].unwrap()
|
||||
};
|
||||
match instr {
|
||||
Instruction::GetLocal(i) => *i = get(i),
|
||||
Instruction::SetLocal(i) => *i = get(i),
|
||||
Instruction::TeeLocal(i) => *i = get(i),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(names) = names {
|
||||
remap_local_names(idx, &map, names);
|
||||
}
|
||||
}
|
||||
|
||||
fn remap_local_names(idx: u32, map: &[Option<u32>], names: &mut LocalNameSection) {
|
||||
let prev = match names.local_names_mut().remove(idx) {
|
||||
Some(map) => map,
|
||||
None => return,
|
||||
};
|
||||
let mut new = IndexMap::with_capacity(map.len());
|
||||
for (idx, name) in prev {
|
||||
if let Some(new_idx) = map[idx as usize] {
|
||||
new.insert(new_idx, name);
|
||||
}
|
||||
}
|
||||
names.local_names_mut().insert(idx, new);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user