mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-16 18:20:51 +00:00
Merge pull request #985 from alexcrichton/differeng-gc
Restructure internals of `wasm-gc`
This commit is contained in:
commit
1ec68009e8
@ -57,37 +57,41 @@ fn run(config: &mut Config, module: &mut Module) {
|
||||
cx.blacklist.insert("__heap_base");
|
||||
cx.blacklist.insert("__data_end");
|
||||
|
||||
// always treat memory as a root
|
||||
cx.add_memory(0);
|
||||
|
||||
// All exports are a root
|
||||
if let Some(section) = module.export_section() {
|
||||
for (i, entry) in section.entries().iter().enumerate() {
|
||||
if cx.blacklist.contains(entry.field()) {
|
||||
continue
|
||||
}
|
||||
cx.add_export_entry(entry, i as u32);
|
||||
}
|
||||
}
|
||||
if let Some(section) = module.import_section() {
|
||||
for (i, entry) in section.entries().iter().enumerate() {
|
||||
debug!("import {:?}", entry);
|
||||
if let External::Memory(_) = *entry.external() {
|
||||
cx.add_import_entry(entry, i as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pessimistically assume all passive data and table segments are
|
||||
// required
|
||||
if let Some(section) = module.data_section() {
|
||||
for entry in section.entries() {
|
||||
cx.add_data_segment(entry);
|
||||
}
|
||||
}
|
||||
if let Some(tables) = module.table_section() {
|
||||
for i in 0..tables.entries().len() as u32 {
|
||||
cx.add_table(i);
|
||||
if entry.passive() {
|
||||
cx.add_data_segment(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(elements) = module.elements_section() {
|
||||
for seg in elements.entries() {
|
||||
cx.add_element_segment(seg);
|
||||
if seg.passive() {
|
||||
cx.add_element_segment(seg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The start function is also a root
|
||||
if let Some(i) = module.start_section() {
|
||||
cx.add_function(i);
|
||||
}
|
||||
|
||||
cx.analysis
|
||||
};
|
||||
|
||||
@ -132,7 +136,6 @@ fn run(config: &mut Config, module: &mut Module) {
|
||||
|
||||
#[derive(Default)]
|
||||
struct Analysis {
|
||||
codes: BitSet,
|
||||
tables: BitSet,
|
||||
memories: BitSet,
|
||||
globals: BitSet,
|
||||
@ -140,67 +143,56 @@ struct Analysis {
|
||||
imports: BitSet,
|
||||
exports: BitSet,
|
||||
functions: BitSet,
|
||||
all_globals: BitSet,
|
||||
}
|
||||
|
||||
enum Memories<'a> {
|
||||
Exported(&'a MemorySection),
|
||||
Imported(&'a MemoryType),
|
||||
}
|
||||
|
||||
impl<'a> Memories<'a> {
|
||||
fn has_entry(&self, idx: usize) -> bool {
|
||||
match *self {
|
||||
Memories::Exported(memory_section) => idx < memory_section.entries().len(),
|
||||
Memories::Imported(_) => idx == 0,
|
||||
}
|
||||
}
|
||||
imported_functions: u32,
|
||||
imported_globals: u32,
|
||||
imported_memories: u32,
|
||||
imported_tables: u32,
|
||||
}
|
||||
|
||||
struct LiveContext<'a> {
|
||||
blacklist: HashSet<&'static str>,
|
||||
function_section: Option<&'a FunctionSection>,
|
||||
type_section: Option<&'a TypeSection>,
|
||||
data_section: Option<&'a DataSection>,
|
||||
element_section: Option<&'a ElementSection>,
|
||||
code_section: Option<&'a CodeSection>,
|
||||
table_section: Option<&'a TableSection>,
|
||||
memories: Option<Memories<'a>>,
|
||||
global_section: Option<&'a GlobalSection>,
|
||||
import_section: Option<&'a ImportSection>,
|
||||
imported_functions: u32,
|
||||
imported_globals: u32,
|
||||
analysis: Analysis,
|
||||
}
|
||||
|
||||
impl<'a> LiveContext<'a> {
|
||||
fn new(module: &'a Module) -> LiveContext<'a> {
|
||||
let memories = module.memory_section().map(Memories::Exported).or_else(|| {
|
||||
if let Some(import_section) = module.import_section() {
|
||||
for entry in import_section.entries() {
|
||||
if let External::Memory(ref memory_type) = *entry.external() {
|
||||
return Some(Memories::Imported(memory_type));
|
||||
}
|
||||
let (mut tables, mut memories, mut globals, mut functions) = (0, 0, 0, 0);
|
||||
if let Some(imports) = module.import_section() {
|
||||
for entry in imports.entries() {
|
||||
match entry.external() {
|
||||
External::Memory(_) => memories += 1,
|
||||
External::Table(_) => tables += 1,
|
||||
External::Function(_) => functions += 1,
|
||||
External::Global(_) => globals += 1,
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
});
|
||||
}
|
||||
|
||||
LiveContext {
|
||||
blacklist: HashSet::new(),
|
||||
function_section: module.function_section(),
|
||||
type_section: module.type_section(),
|
||||
data_section: module.data_section(),
|
||||
element_section: module.elements_section(),
|
||||
code_section: module.code_section(),
|
||||
table_section: module.table_section(),
|
||||
memories: memories,
|
||||
global_section: module.global_section(),
|
||||
import_section: module.import_section(),
|
||||
imported_functions: module.import_section()
|
||||
.map(|s| s.functions())
|
||||
.unwrap_or(0) as u32,
|
||||
imported_globals: module.import_section()
|
||||
.map(|s| s.globals())
|
||||
.unwrap_or(0) as u32,
|
||||
analysis: Analysis::default(),
|
||||
analysis: Analysis {
|
||||
imported_functions: functions,
|
||||
imported_globals: globals,
|
||||
imported_tables: tables,
|
||||
imported_memories: memories,
|
||||
..Analysis::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,10 +200,10 @@ impl<'a> LiveContext<'a> {
|
||||
if !self.analysis.functions.insert(idx) {
|
||||
return
|
||||
}
|
||||
debug!("adding function: {}", idx);
|
||||
|
||||
if idx < self.imported_functions {
|
||||
if idx < self.analysis.imported_functions {
|
||||
let imports = self.import_section.unwrap();
|
||||
debug!("adding import: {}", idx);
|
||||
let (i, import) = imports.entries()
|
||||
.iter()
|
||||
.enumerate()
|
||||
@ -225,57 +217,48 @@ impl<'a> LiveContext<'a> {
|
||||
.next()
|
||||
.expect("expected an imported function with this index");
|
||||
let i = i as u32;
|
||||
self.analysis.imports.insert(i);
|
||||
return self.add_import_entry(import, i);
|
||||
}
|
||||
let idx = idx - self.imported_functions;
|
||||
|
||||
if !self.analysis.codes.insert(idx) {
|
||||
return
|
||||
}
|
||||
|
||||
debug!("adding function: {}", idx);
|
||||
let idx = idx - self.analysis.imported_functions;
|
||||
let functions = self.function_section.expect("no functions section");
|
||||
self.add_type(functions.entries()[idx as usize].type_ref());
|
||||
let codes = self.code_section.expect("no codes section");
|
||||
self.add_func_body(&codes.bodies()[idx as usize]);
|
||||
}
|
||||
|
||||
fn add_table(&mut self, mut idx: u32) {
|
||||
if let Some(imports) = self.import_section {
|
||||
let imported_tables = imports.entries()
|
||||
fn add_table(&mut self, idx: u32) {
|
||||
if !self.analysis.tables.insert(idx) {
|
||||
return
|
||||
}
|
||||
debug!("adding table: {}", idx);
|
||||
|
||||
// Add all element segments that initialize this table
|
||||
if let Some(elements) = self.element_section {
|
||||
for entry in elements.entries().iter().filter(|d| !d.passive()) {
|
||||
if entry.index() == idx {
|
||||
self.add_element_segment(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if idx < self.analysis.imported_tables {
|
||||
let imports = self.import_section.unwrap();
|
||||
let (i, import) = imports.entries()
|
||||
.iter()
|
||||
.filter(|i| {
|
||||
.enumerate()
|
||||
.filter(|&(_, i)| {
|
||||
match *i.external() {
|
||||
External::Table(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.count();
|
||||
let imported_tables = imported_tables as u32;
|
||||
if idx < imported_tables {
|
||||
debug!("adding table import: {}", idx);
|
||||
let (i, import) = imports.entries()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, i)| {
|
||||
match *i.external() {
|
||||
External::Table(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.skip(idx as usize)
|
||||
.next()
|
||||
.expect("expected an imported table with this index");
|
||||
let i = i as u32;
|
||||
self.analysis.imports.insert(i);
|
||||
return self.add_import_entry(import, i);
|
||||
}
|
||||
idx -= imported_tables;
|
||||
}
|
||||
if !self.analysis.tables.insert(idx) {
|
||||
return
|
||||
.skip(idx as usize)
|
||||
.next()
|
||||
.expect("expected an imported table with this index");
|
||||
let i = i as u32;
|
||||
return self.add_import_entry(import, i);
|
||||
}
|
||||
let idx = idx - self.analysis.imported_tables;
|
||||
let tables = self.table_section.expect("no table section");
|
||||
let table = &tables.entries()[idx as usize];
|
||||
drop(table);
|
||||
@ -285,18 +268,47 @@ impl<'a> LiveContext<'a> {
|
||||
if !self.analysis.memories.insert(idx) {
|
||||
return
|
||||
}
|
||||
let memories = self.memories.as_ref().expect("no memory section or imported memory");
|
||||
assert!(memories.has_entry(idx as usize));
|
||||
debug!("adding memory: {}", idx);
|
||||
|
||||
// Add all data segments that initialize this memory
|
||||
if let Some(data) = self.data_section {
|
||||
for entry in data.entries().iter().filter(|d| !d.passive()) {
|
||||
if entry.index() == idx {
|
||||
self.add_data_segment(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ... and add the import if it's an imported memory ..
|
||||
if idx < self.analysis.imported_memories {
|
||||
let imports = self.import_section.unwrap();
|
||||
let (i, import) = imports.entries()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, i)| {
|
||||
match *i.external() {
|
||||
External::Memory(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.skip(idx as usize)
|
||||
.next()
|
||||
.expect("expected an imported memory with this index");
|
||||
let i = i as u32;
|
||||
return self.add_import_entry(import, i);
|
||||
}
|
||||
|
||||
// ... and if it's not imported that's it!
|
||||
}
|
||||
|
||||
fn add_global(&mut self, idx: u32) {
|
||||
if !self.analysis.all_globals.insert(idx) {
|
||||
if !self.analysis.globals.insert(idx) {
|
||||
return
|
||||
}
|
||||
debug!("adding global: {}", idx);
|
||||
|
||||
if idx < self.imported_globals {
|
||||
if idx < self.analysis.imported_globals {
|
||||
let imports = self.import_section.unwrap();
|
||||
debug!("adding global import: {}", idx);
|
||||
let (i, import) = imports.entries()
|
||||
.iter()
|
||||
.enumerate()
|
||||
@ -310,14 +322,10 @@ impl<'a> LiveContext<'a> {
|
||||
.next()
|
||||
.expect("expected an imported global with this index");
|
||||
let i = i as u32;
|
||||
self.analysis.imports.insert(i);
|
||||
return self.add_import_entry(import, i);
|
||||
}
|
||||
let idx = idx - self.imported_globals;
|
||||
|
||||
if !self.analysis.globals.insert(idx) {
|
||||
return
|
||||
}
|
||||
let idx = idx - self.analysis.imported_globals;
|
||||
let globals = self.global_section.expect("no global section");
|
||||
let global = &globals.entries()[idx as usize];
|
||||
self.add_global_type(global.global_type());
|
||||
@ -380,7 +388,10 @@ impl<'a> LiveContext<'a> {
|
||||
Instruction::Loop(ref b) |
|
||||
Instruction::If(ref b) => self.add_block_type(b),
|
||||
Instruction::Call(f) => self.add_function(f),
|
||||
Instruction::CallIndirect(t, _) => self.add_type(t),
|
||||
Instruction::CallIndirect(t, _) => {
|
||||
self.add_type(t);
|
||||
self.add_table(0);
|
||||
}
|
||||
Instruction::GetGlobal(i) |
|
||||
Instruction::SetGlobal(i) => self.add_global(i),
|
||||
_ => {}
|
||||
@ -395,10 +406,9 @@ impl<'a> LiveContext<'a> {
|
||||
}
|
||||
|
||||
fn add_export_entry(&mut self, entry: &ExportEntry, idx: u32) {
|
||||
if self.blacklist.contains(entry.field()) {
|
||||
if !self.analysis.exports.insert(idx) {
|
||||
return
|
||||
}
|
||||
self.analysis.exports.insert(idx);
|
||||
match *entry.internal() {
|
||||
Internal::Function(i) => self.add_function(i),
|
||||
Internal::Table(i) => self.add_table(i),
|
||||
@ -408,14 +418,15 @@ impl<'a> LiveContext<'a> {
|
||||
}
|
||||
|
||||
fn add_import_entry(&mut self, entry: &ImportEntry, idx: u32) {
|
||||
if !self.analysis.imports.insert(idx) {
|
||||
return
|
||||
}
|
||||
debug!("adding import: {}", idx);
|
||||
match *entry.external() {
|
||||
External::Function(i) => self.add_type(i),
|
||||
External::Table(_) => {},
|
||||
External::Memory(_) => {
|
||||
self.add_memory(0);
|
||||
self.analysis.imports.insert(idx);
|
||||
},
|
||||
External::Global(_) => {},
|
||||
External::Table(_) => {}
|
||||
External::Memory(_) => {}
|
||||
External::Global(g) => self.add_value_type(&g.content_type()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,7 +501,7 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
if let Some(s) = m.function_section() {
|
||||
for i in 0..(s.entries().len() as u32) {
|
||||
if analysis.codes.contains(&i) {
|
||||
if analysis.functions.contains(&(i + analysis.imported_functions)) {
|
||||
functions.push(nfunctions);
|
||||
nfunctions += 1;
|
||||
} else {
|
||||
@ -501,7 +512,7 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
if let Some(s) = m.global_section() {
|
||||
for i in 0..(s.entries().len() as u32) {
|
||||
if analysis.globals.contains(&i) {
|
||||
if analysis.globals.contains(&(i + analysis.imported_globals)) {
|
||||
globals.push(nglobals);
|
||||
nglobals += 1;
|
||||
} else {
|
||||
@ -512,7 +523,7 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
if let Some(s) = m.table_section() {
|
||||
for i in 0..(s.entries().len() as u32) {
|
||||
if analysis.tables.contains(&i) {
|
||||
if analysis.tables.contains(&(i + analysis.imported_tables)) {
|
||||
tables.push(ntables);
|
||||
ntables += 1;
|
||||
} else {
|
||||
@ -523,7 +534,7 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
if let Some(s) = m.memory_section() {
|
||||
for i in 0..(s.entries().len() as u32) {
|
||||
if analysis.memories.contains(&i) {
|
||||
if analysis.memories.contains(&(i + analysis.imported_memories)) {
|
||||
memories.push(nmemories);
|
||||
nmemories += 1;
|
||||
} else {
|
||||
@ -544,9 +555,9 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn retain<T>(&self, set: &BitSet, list: &mut Vec<T>, name: &str) {
|
||||
fn retain<T>(&self, set: &BitSet, list: &mut Vec<T>, name: &str, offset: u32) {
|
||||
for i in (0..list.len()).rev().map(|x| x as u32) {
|
||||
if !set.contains(&i) {
|
||||
if !set.contains(&(i + offset)) {
|
||||
debug!("removing {} {}", name, i);
|
||||
list.remove(i as usize);
|
||||
}
|
||||
@ -554,7 +565,7 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_type_section(&self, s: &mut TypeSection) -> bool {
|
||||
self.retain(&self.analysis.types, s.types_mut(), "type");
|
||||
self.retain(&self.analysis.types, s.types_mut(), "type", 0);
|
||||
for t in s.types_mut() {
|
||||
self.remap_type(t);
|
||||
}
|
||||
@ -577,11 +588,17 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_value_type(&self, t: &mut ValueType) {
|
||||
drop(t);
|
||||
match t {
|
||||
ValueType::I32 => {}
|
||||
ValueType::I64 => {}
|
||||
ValueType::F32 => {}
|
||||
ValueType::F64 => {}
|
||||
ValueType::V128 => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn remap_import_section(&self, s: &mut ImportSection) -> bool {
|
||||
self.retain(&self.analysis.imports, s.entries_mut(), "import");
|
||||
self.retain(&self.analysis.imports, s.entries_mut(), "import", 0);
|
||||
for i in s.entries_mut() {
|
||||
self.remap_import_entry(i);
|
||||
}
|
||||
@ -599,7 +616,12 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_function_section(&self, s: &mut FunctionSection) -> bool {
|
||||
self.retain(&self.analysis.codes, s.entries_mut(), "function");
|
||||
self.retain(
|
||||
&self.analysis.functions,
|
||||
s.entries_mut(),
|
||||
"function",
|
||||
self.analysis.imported_functions,
|
||||
);
|
||||
for f in s.entries_mut() {
|
||||
self.remap_func(f);
|
||||
}
|
||||
@ -611,7 +633,12 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_table_section(&self, s: &mut TableSection) -> bool {
|
||||
self.retain(&self.analysis.tables, s.entries_mut(), "table");
|
||||
self.retain(
|
||||
&self.analysis.tables,
|
||||
s.entries_mut(),
|
||||
"table",
|
||||
self.analysis.imported_tables,
|
||||
);
|
||||
for t in s.entries_mut() {
|
||||
drop(t); // TODO
|
||||
}
|
||||
@ -619,7 +646,12 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_memory_section(&self, s: &mut MemorySection) -> bool {
|
||||
self.retain(&self.analysis.memories, s.entries_mut(), "memory");
|
||||
self.retain(
|
||||
&self.analysis.memories,
|
||||
s.entries_mut(),
|
||||
"memory",
|
||||
self.analysis.imported_memories,
|
||||
);
|
||||
for m in s.entries_mut() {
|
||||
drop(m); // TODO
|
||||
}
|
||||
@ -627,7 +659,12 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_global_section(&self, s: &mut GlobalSection) -> bool {
|
||||
self.retain(&self.analysis.globals, s.entries_mut(), "global");
|
||||
self.retain(
|
||||
&self.analysis.globals,
|
||||
s.entries_mut(),
|
||||
"global",
|
||||
self.analysis.imported_globals,
|
||||
);
|
||||
for g in s.entries_mut() {
|
||||
self.remap_global_entry(g);
|
||||
}
|
||||
@ -650,7 +687,7 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_export_section(&self, s: &mut ExportSection) -> bool {
|
||||
self.retain(&self.analysis.exports, s.entries_mut(), "export");
|
||||
self.retain(&self.analysis.exports, s.entries_mut(), "export", 0);
|
||||
for s in s.entries_mut() {
|
||||
self.remap_export_entry(s);
|
||||
}
|
||||
@ -686,7 +723,12 @@ impl<'a> RemapContext<'a> {
|
||||
}
|
||||
|
||||
fn remap_code_section(&self, s: &mut CodeSection) -> bool {
|
||||
self.retain(&self.analysis.codes, s.bodies_mut(), "code");
|
||||
self.retain(
|
||||
&self.analysis.functions,
|
||||
s.bodies_mut(),
|
||||
"code",
|
||||
self.analysis.imported_functions,
|
||||
);
|
||||
for s in s.bodies_mut() {
|
||||
self.remap_func_body(s);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user