mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-17 23:11:23 +00:00
Update the walrus
dependency (#2125)
This commit updates the `walrus` crate used in `wasm-bindgen`. The major change here is how `walrus` handles element segments, exposing segments rather than trying to keep a contiugous array of all the elements and doing the splitting itself. That means that we need to do mroe logic here in `wasm-bindgen` to juggle indices, segments, etc.
This commit is contained in:
@ -3,12 +3,12 @@ use crate::intrinsic::Intrinsic;
|
||||
use crate::wit::AuxImport;
|
||||
use crate::wit::{AdapterKind, Instruction, NonstandardWitSection};
|
||||
use crate::wit::{AdapterType, InstructionData, StackChange, WasmBindgenAux};
|
||||
use anyhow::Error;
|
||||
use anyhow::Result;
|
||||
use std::collections::HashMap;
|
||||
use walrus::Module;
|
||||
use walrus::{ir::Value, ElementKind, InitExpr, Module};
|
||||
use wasm_bindgen_anyref_xform::Context;
|
||||
|
||||
pub fn process(module: &mut Module) -> Result<(), Error> {
|
||||
pub fn process(module: &mut Module) -> Result<()> {
|
||||
let mut cfg = Context::default();
|
||||
cfg.prepare(module)?;
|
||||
let section = module
|
||||
@ -382,3 +382,86 @@ fn module_needs_anyref_metadata(aux: &WasmBindgenAux, section: &NonstandardWitSe
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// In MVP wasm all element segments must be contiguous lists of function
|
||||
/// indices. Post-MVP with reference types element segments can have holes.
|
||||
/// While `walrus` will select the encoding that fits, this function forces the
|
||||
/// listing of segments to be MVP-compatible.
|
||||
pub fn force_contiguous_elements(module: &mut Module) -> Result<()> {
|
||||
// List of new element segments we're going to be adding.
|
||||
let mut new_segments = Vec::new();
|
||||
|
||||
// Here we take a look at all element segments in the module to see if we
|
||||
// need to split them.
|
||||
for segment in module.elements.iter_mut() {
|
||||
// If this segment has all-`Some` members then it's alrady contiguous
|
||||
// and we can skip it.
|
||||
if segment.members.iter().all(|m| m.is_some()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For now active segments are all we're interested in since
|
||||
// passive/declared have no hope of being MVP-compatible anyway.
|
||||
// Additionally we only handle active segments with i32 offsets, since
|
||||
// global offsets get funky since we'd need to add an offset.
|
||||
let (table, offset) = match &segment.kind {
|
||||
ElementKind::Active {
|
||||
table,
|
||||
offset: InitExpr::Value(Value::I32(n)),
|
||||
} => (*table, *n),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
// `block` keeps track of a block of contiguous segment of functions
|
||||
let mut block = None;
|
||||
// This keeps track of where we're going to truncate the current segment
|
||||
// after we split out all the blocks.
|
||||
let mut truncate = 0;
|
||||
// This commits a block of contiguous functions into the `new_segments`
|
||||
// list, accounting for the new offset which is relative to the old
|
||||
// offset.
|
||||
let mut commit = |last_idx: usize, block: Vec<_>| {
|
||||
let new_offset = offset + (last_idx - block.len()) as i32;
|
||||
let new_offset = InitExpr::Value(Value::I32(new_offset));
|
||||
new_segments.push((table, new_offset, segment.ty, block));
|
||||
};
|
||||
for (i, id) in segment.members.iter().enumerate() {
|
||||
match id {
|
||||
// If we find a function, then we either start a new block or
|
||||
// push it onto the existing block.
|
||||
Some(id) => block.get_or_insert(Vec::new()).push(Some(*id)),
|
||||
None => {
|
||||
let block = match block.take() {
|
||||
Some(b) => b,
|
||||
None => continue,
|
||||
};
|
||||
// If this is the first block (truncate isn't set and the
|
||||
// length of the block means it starts from the beginning),
|
||||
// then we leave it in the original list and don't commit
|
||||
// anything, we'll just edit where to truncate later.
|
||||
// Otherwise we commit this block to the new segment list.
|
||||
if truncate == 0 && block.len() == i {
|
||||
truncate = i;
|
||||
} else {
|
||||
commit(i, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no trailing empty slots then we commit the last block onto
|
||||
// the new segment list.
|
||||
if let Some(block) = block {
|
||||
commit(segment.members.len(), block);
|
||||
}
|
||||
segment.members.truncate(truncate);
|
||||
}
|
||||
|
||||
for (table, offset, ty, members) in new_segments {
|
||||
let id = module
|
||||
.elements
|
||||
.add(ElementKind::Active { table, offset }, ty, members);
|
||||
module.tables.get_mut(table).elem_segments.insert(id);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -107,19 +107,9 @@ impl WasmBindgenDescriptorsSection {
|
||||
// For all indirect functions that were closure descriptors, delete them
|
||||
// from the function table since we've executed them and they're not
|
||||
// necessary in the final binary.
|
||||
let table_id = match interpreter.function_table_id() {
|
||||
Some(id) => id,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let table = module.tables.get_mut(table_id);
|
||||
let table = match &mut table.kind {
|
||||
walrus::TableKind::Function(f) => f,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
for idx in element_removal_list {
|
||||
for (segment, idx) in element_removal_list {
|
||||
log::trace!("delete element {}", idx);
|
||||
assert!(table.elements[idx].is_some());
|
||||
table.elements[idx] = None;
|
||||
module.elements.get_mut(segment).members[idx] = None;
|
||||
}
|
||||
|
||||
// And finally replace all calls of `wbindgen_describe_closure` with a
|
||||
|
@ -1145,18 +1145,9 @@ impl Invocation {
|
||||
// The function table never changes right now, so we can statically
|
||||
// look up the desired function.
|
||||
CallTableElement(idx) => {
|
||||
let table = module
|
||||
.tables
|
||||
.main_function_table()?
|
||||
.ok_or_else(|| anyhow!("no function table found"))?;
|
||||
let functions = match &module.tables.get(table).kind {
|
||||
walrus::TableKind::Function(f) => f,
|
||||
_ => bail!("should have found a function table"),
|
||||
};
|
||||
let id = functions
|
||||
.elements
|
||||
.get(*idx as usize)
|
||||
.and_then(|id| *id)
|
||||
let entry = wasm_bindgen_wasm_conventions::get_function_table_entry(module, *idx)?;
|
||||
let id = entry
|
||||
.func
|
||||
.ok_or_else(|| anyhow!("function table wasn't filled in a {}", idx))?;
|
||||
Invocation::Core { id, defer: false }
|
||||
}
|
||||
|
@ -373,6 +373,11 @@ impl Bindgen {
|
||||
for id in ids {
|
||||
module.exports.delete(id);
|
||||
}
|
||||
// Clean up element segments as well if they have holes in them
|
||||
// after some of our transformations, because non-anyref engines
|
||||
// only support contiguous arrays of function references in element
|
||||
// segments.
|
||||
anyref::force_contiguous_elements(&mut module)?;
|
||||
}
|
||||
|
||||
// If wasm interface types are enabled then the `__wbindgen_throw`
|
||||
@ -564,13 +569,6 @@ impl OutputMode {
|
||||
}
|
||||
}
|
||||
|
||||
fn bundler(&self) -> bool {
|
||||
match self {
|
||||
OutputMode::Bundler { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn esm_integration(&self) -> bool {
|
||||
match self {
|
||||
OutputMode::Bundler { .. }
|
||||
|
@ -220,18 +220,11 @@ fn translate_instruction(
|
||||
_ => bail!("can only call exported functions"),
|
||||
},
|
||||
CallTableElement(e) => {
|
||||
let table = module
|
||||
.tables
|
||||
.main_function_table()?
|
||||
.ok_or_else(|| anyhow!("no function table found in module"))?;
|
||||
let functions = match &module.tables.get(table).kind {
|
||||
walrus::TableKind::Function(f) => f,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
match functions.elements.get(*e as usize) {
|
||||
Some(Some(f)) => Ok(wit_walrus::Instruction::CallCore(*f)),
|
||||
_ => bail!("expected to find an element of the function table"),
|
||||
}
|
||||
let entry = wasm_bindgen_wasm_conventions::get_function_table_entry(module, *e)?;
|
||||
let id = entry
|
||||
.func
|
||||
.ok_or_else(|| anyhow!("function table wasn't filled in a {}", e))?;
|
||||
Ok(wit_walrus::Instruction::CallCore(id))
|
||||
}
|
||||
StringToMemory {
|
||||
mem,
|
||||
|
@ -313,7 +313,9 @@ impl AdapterType {
|
||||
walrus::ValType::F32 => AdapterType::F32,
|
||||
walrus::ValType::F64 => AdapterType::F64,
|
||||
walrus::ValType::Anyref => AdapterType::Anyref,
|
||||
walrus::ValType::V128 => return None,
|
||||
walrus::ValType::Funcref | walrus::ValType::Nullref | walrus::ValType::V128 => {
|
||||
return None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user