diff options
Diffstat (limited to 'third_party/rust/wast/src/core/binary.rs')
-rw-r--r-- | third_party/rust/wast/src/core/binary.rs | 1279 |
1 files changed, 1279 insertions, 0 deletions
diff --git a/third_party/rust/wast/src/core/binary.rs b/third_party/rust/wast/src/core/binary.rs new file mode 100644 index 0000000000..68facd6431 --- /dev/null +++ b/third_party/rust/wast/src/core/binary.rs @@ -0,0 +1,1279 @@ +use crate::core::*; +use crate::encode::Encode; +use crate::token::*; + +pub fn encode( + module_id: &Option<Id<'_>>, + module_name: &Option<NameAnnotation<'_>>, + fields: &[ModuleField<'_>], +) -> Vec<u8> { + use CustomPlace::*; + use CustomPlaceAnchor::*; + + let mut types = Vec::new(); + let mut imports = Vec::new(); + let mut funcs = Vec::new(); + let mut tables = Vec::new(); + let mut memories = Vec::new(); + let mut globals = Vec::new(); + let mut exports = Vec::new(); + let mut start = Vec::new(); + let mut elem = Vec::new(); + let mut data = Vec::new(); + let mut tags = Vec::new(); + let mut customs = Vec::new(); + for field in fields { + match field { + ModuleField::Type(i) => types.push(RecOrType::Type(i)), + ModuleField::Rec(i) => types.push(RecOrType::Rec(i)), + ModuleField::Import(i) => imports.push(i), + ModuleField::Func(i) => funcs.push(i), + ModuleField::Table(i) => tables.push(i), + ModuleField::Memory(i) => memories.push(i), + ModuleField::Global(i) => globals.push(i), + ModuleField::Export(i) => exports.push(i), + ModuleField::Start(i) => start.push(i), + ModuleField::Elem(i) => elem.push(i), + ModuleField::Data(i) => data.push(i), + ModuleField::Tag(i) => tags.push(i), + ModuleField::Custom(i) => customs.push(i), + } + } + + let mut e = Encoder { + wasm: Vec::new(), + tmp: Vec::new(), + customs: &customs, + }; + e.wasm.extend(b"\0asm"); + e.wasm.extend(b"\x01\0\0\0"); + + e.custom_sections(BeforeFirst); + + e.section_list(1, Type, &types); + e.section_list(2, Import, &imports); + + let functys = funcs.iter().map(|f| &f.ty).collect::<Vec<_>>(); + e.section_list(3, Func, &functys); + e.section_list(4, Table, &tables); + e.section_list(5, Memory, &memories); + e.section_list(13, Tag, &tags); + e.section_list(6, Global, &globals); + e.section_list(7, Export, &exports); + e.custom_sections(Before(Start)); + if let Some(start) = start.get(0) { + e.section(8, start); + } + e.custom_sections(After(Start)); + e.section_list(9, Elem, &elem); + if needs_data_count(&funcs) { + e.section(12, &data.len()); + } + e.section_list(10, Code, &funcs); + e.section_list(11, Data, &data); + + let names = find_names(module_id, module_name, fields); + if !names.is_empty() { + e.section(0, &("name", names)); + } + e.custom_sections(AfterLast); + + return e.wasm; + + fn needs_data_count(funcs: &[&crate::core::Func<'_>]) -> bool { + funcs + .iter() + .filter_map(|f| match &f.kind { + FuncKind::Inline { expression, .. } => Some(expression), + _ => None, + }) + .flat_map(|e| e.instrs.iter()) + .any(|i| i.needs_data_count()) + } +} + +struct Encoder<'a> { + wasm: Vec<u8>, + tmp: Vec<u8>, + customs: &'a [&'a Custom<'a>], +} + +impl Encoder<'_> { + fn section(&mut self, id: u8, section: &dyn Encode) { + self.tmp.truncate(0); + section.encode(&mut self.tmp); + self.wasm.push(id); + self.tmp.encode(&mut self.wasm); + } + + fn custom_sections(&mut self, place: CustomPlace) { + for entry in self.customs.iter() { + if entry.place() == place { + self.section(0, &(entry.name(), entry)); + } + } + } + + fn section_list(&mut self, id: u8, anchor: CustomPlaceAnchor, list: &[impl Encode]) { + self.custom_sections(CustomPlace::Before(anchor)); + if !list.is_empty() { + self.section(id, &list) + } + self.custom_sections(CustomPlace::After(anchor)); + } +} + +impl Encode for FunctionType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.params.len().encode(e); + for (_, _, ty) in self.params.iter() { + ty.encode(e); + } + self.results.encode(e); + } +} + +impl Encode for StructType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.fields.len().encode(e); + for field in self.fields.iter() { + field.ty.encode(e); + (field.mutable as i32).encode(e); + } + } +} + +impl Encode for ArrayType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.ty.encode(e); + (self.mutable as i32).encode(e); + } +} + +impl Encode for ExportType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.name.encode(e); + self.item.encode(e); + } +} + +enum RecOrType<'a> { + Type(&'a Type<'a>), + Rec(&'a Rec<'a>), +} + +impl Encode for RecOrType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + RecOrType::Type(ty) => ty.encode(e), + RecOrType::Rec(rec) => rec.encode(e), + } + } +} + +impl Encode for Type<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match (&self.parent, self.final_type) { + (Some(parent), Some(true)) => { + // Type is final with a supertype + e.push(0x4f); + e.push(0x01); + parent.encode(e); + } + (Some(parent), Some(false) | None) => { + // Type is not final and has a declared supertype + e.push(0x50); + e.push(0x01); + parent.encode(e); + } + (None, Some(false)) => { + // Sub was used without any declared supertype + e.push(0x50); + e.push(0x00); + } + (None, _) => {} // No supertype, sub wasn't used + } + match &self.def { + TypeDef::Func(func) => { + e.push(0x60); + func.encode(e) + } + TypeDef::Struct(r#struct) => { + e.push(0x5f); + r#struct.encode(e) + } + TypeDef::Array(array) => { + e.push(0x5e); + array.encode(e) + } + } + } +} + +impl Encode for Rec<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0x4e); + self.types.len().encode(e); + for ty in &self.types { + ty.encode(e); + } + } +} + +impl Encode for Option<Id<'_>> { + fn encode(&self, _e: &mut Vec<u8>) { + // used for parameters in the tuple impl as well as instruction labels + } +} + +impl<'a> Encode for ValType<'a> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + ValType::I32 => e.push(0x7f), + ValType::I64 => e.push(0x7e), + ValType::F32 => e.push(0x7d), + ValType::F64 => e.push(0x7c), + ValType::V128 => e.push(0x7b), + ValType::Ref(ty) => { + ty.encode(e); + } + } + } +} + +impl<'a> Encode for HeapType<'a> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + HeapType::Func => e.push(0x70), + HeapType::Extern => e.push(0x6f), + HeapType::Exn => e.push(0x69), + HeapType::Any => e.push(0x6e), + HeapType::Eq => e.push(0x6d), + HeapType::Struct => e.push(0x6b), + HeapType::Array => e.push(0x6a), + HeapType::I31 => e.push(0x6c), + HeapType::NoFunc => e.push(0x73), + HeapType::NoExtern => e.push(0x72), + HeapType::None => e.push(0x71), + // Note that this is encoded as a signed leb128 so be sure to cast + // to an i64 first + HeapType::Concrete(Index::Num(n, _)) => i64::from(*n).encode(e), + HeapType::Concrete(Index::Id(n)) => { + panic!("unresolved index in emission: {:?}", n) + } + } + } +} + +impl<'a> Encode for RefType<'a> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + // The 'funcref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::Func, + } => e.push(0x70), + // The 'externref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::Extern, + } => e.push(0x6f), + // The 'exnref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::Exn, + } => e.push(0x69), + // The 'eqref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::Eq, + } => e.push(0x6d), + // The 'structref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::Struct, + } => e.push(0x6b), + // The 'i31ref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::I31, + } => e.push(0x6c), + // The 'nullfuncref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::NoFunc, + } => e.push(0x73), + // The 'nullexternref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::NoExtern, + } => e.push(0x72), + // The 'nullref' binary abbreviation + RefType { + nullable: true, + heap: HeapType::None, + } => e.push(0x71), + + // Generic 'ref null <heaptype>' encoding + RefType { + nullable: true, + heap, + } => { + e.push(0x63); + heap.encode(e); + } + // Generic 'ref <heaptype>' encoding + RefType { + nullable: false, + heap, + } => { + e.push(0x64); + heap.encode(e); + } + } + } +} + +impl<'a> Encode for StorageType<'a> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + StorageType::I8 => e.push(0x78), + StorageType::I16 => e.push(0x77), + StorageType::Val(ty) => { + ty.encode(e); + } + } + } +} + +impl Encode for Import<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.module.encode(e); + self.field.encode(e); + self.item.encode(e); + } +} + +impl Encode for ItemSig<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match &self.kind { + ItemKind::Func(f) => { + e.push(0x00); + f.encode(e); + } + ItemKind::Table(f) => { + e.push(0x01); + f.encode(e); + } + ItemKind::Memory(f) => { + e.push(0x02); + f.encode(e); + } + ItemKind::Global(f) => { + e.push(0x03); + f.encode(e); + } + ItemKind::Tag(f) => { + e.push(0x04); + f.encode(e); + } + } + } +} + +impl<T> Encode for TypeUse<'_, T> { + fn encode(&self, e: &mut Vec<u8>) { + self.index + .as_ref() + .expect("TypeUse should be filled in by this point") + .encode(e) + } +} + +impl Encode for Index<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + Index::Num(n, _) => n.encode(e), + Index::Id(n) => panic!("unresolved index in emission: {:?}", n), + } + } +} + +impl<'a> Encode for TableType<'a> { + fn encode(&self, e: &mut Vec<u8>) { + self.elem.encode(e); + self.limits.encode(e); + } +} + +impl Encode for Limits { + fn encode(&self, e: &mut Vec<u8>) { + match self.max { + Some(max) => { + e.push(0x01); + self.min.encode(e); + max.encode(e); + } + None => { + e.push(0x00); + self.min.encode(e); + } + } + } +} + +impl Encode for MemoryType { + fn encode(&self, e: &mut Vec<u8>) { + match self { + MemoryType::B32 { limits, shared } => { + let flag_max = limits.max.is_some() as u8; + let flag_shared = *shared as u8; + let flags = flag_max | (flag_shared << 1); + e.push(flags); + limits.min.encode(e); + if let Some(max) = limits.max { + max.encode(e); + } + } + MemoryType::B64 { limits, shared } => { + let flag_max = limits.max.is_some() as u8; + let flag_shared = *shared as u8; + let flags = flag_max | (flag_shared << 1) | 0x04; + e.push(flags); + limits.min.encode(e); + if let Some(max) = limits.max { + max.encode(e); + } + } + } + } +} + +impl<'a> Encode for GlobalType<'a> { + fn encode(&self, e: &mut Vec<u8>) { + self.ty.encode(e); + if self.mutable { + e.push(0x01); + } else { + e.push(0x00); + } + } +} + +impl Encode for Table<'_> { + fn encode(&self, e: &mut Vec<u8>) { + assert!(self.exports.names.is_empty()); + match &self.kind { + TableKind::Normal { + ty, + init_expr: None, + } => ty.encode(e), + TableKind::Normal { + ty, + init_expr: Some(init_expr), + } => { + e.push(0x40); + e.push(0x00); + ty.encode(e); + init_expr.encode(e); + } + _ => panic!("TableKind should be normal during encoding"), + } + } +} + +impl Encode for Memory<'_> { + fn encode(&self, e: &mut Vec<u8>) { + assert!(self.exports.names.is_empty()); + match &self.kind { + MemoryKind::Normal(t) => t.encode(e), + _ => panic!("MemoryKind should be normal during encoding"), + } + } +} + +impl Encode for Global<'_> { + fn encode(&self, e: &mut Vec<u8>) { + assert!(self.exports.names.is_empty()); + self.ty.encode(e); + match &self.kind { + GlobalKind::Inline(expr) => expr.encode(e), + _ => panic!("GlobalKind should be inline during encoding"), + } + } +} + +impl Encode for Export<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.name.encode(e); + self.kind.encode(e); + self.item.encode(e); + } +} + +impl Encode for ExportKind { + fn encode(&self, e: &mut Vec<u8>) { + match self { + ExportKind::Func => e.push(0x00), + ExportKind::Table => e.push(0x01), + ExportKind::Memory => e.push(0x02), + ExportKind::Global => e.push(0x03), + ExportKind::Tag => e.push(0x04), + } + } +} + +impl Encode for Elem<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match (&self.kind, &self.payload) { + ( + ElemKind::Active { + table: Index::Num(0, _), + offset, + }, + ElemPayload::Indices(_), + ) => { + e.push(0x00); + offset.encode(e); + } + (ElemKind::Passive, ElemPayload::Indices(_)) => { + e.push(0x01); // flags + e.push(0x00); // extern_kind + } + (ElemKind::Active { table, offset }, ElemPayload::Indices(_)) => { + e.push(0x02); // flags + table.encode(e); + offset.encode(e); + e.push(0x00); // extern_kind + } + (ElemKind::Declared, ElemPayload::Indices(_)) => { + e.push(0x03); // flags + e.push(0x00); // extern_kind + } + ( + ElemKind::Active { + table: Index::Num(0, _), + offset, + }, + ElemPayload::Exprs { + ty: + RefType { + nullable: true, + heap: HeapType::Func, + }, + .. + }, + ) => { + e.push(0x04); + offset.encode(e); + } + (ElemKind::Passive, ElemPayload::Exprs { ty, .. }) => { + e.push(0x05); + ty.encode(e); + } + (ElemKind::Active { table, offset }, ElemPayload::Exprs { ty, .. }) => { + e.push(0x06); + table.encode(e); + offset.encode(e); + ty.encode(e); + } + (ElemKind::Declared, ElemPayload::Exprs { ty, .. }) => { + e.push(0x07); // flags + ty.encode(e); + } + } + + self.payload.encode(e); + } +} + +impl Encode for ElemPayload<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + ElemPayload::Indices(v) => v.encode(e), + ElemPayload::Exprs { exprs, ty: _ } => { + exprs.len().encode(e); + for expr in exprs { + expr.encode(e); + } + } + } + } +} + +impl Encode for Data<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match &self.kind { + DataKind::Passive => e.push(0x01), + DataKind::Active { + memory: Index::Num(0, _), + offset, + } => { + e.push(0x00); + offset.encode(e); + } + DataKind::Active { memory, offset } => { + e.push(0x02); + memory.encode(e); + offset.encode(e); + } + } + self.data.iter().map(|l| l.len()).sum::<usize>().encode(e); + for val in self.data.iter() { + val.push_onto(e); + } + } +} + +impl Encode for Func<'_> { + fn encode(&self, e: &mut Vec<u8>) { + assert!(self.exports.names.is_empty()); + let mut tmp = Vec::new(); + let (expr, locals) = match &self.kind { + FuncKind::Inline { expression, locals } => (expression, locals), + _ => panic!("should only have inline functions in emission"), + }; + + locals.encode(&mut tmp); + expr.encode(&mut tmp); + + tmp.len().encode(e); + e.extend_from_slice(&tmp); + } +} + +impl Encode for Box<[Local<'_>]> { + fn encode(&self, e: &mut Vec<u8>) { + let mut locals_compressed = Vec::<(u32, ValType)>::new(); + for local in self.iter() { + if let Some((cnt, prev)) = locals_compressed.last_mut() { + if *prev == local.ty { + *cnt += 1; + continue; + } + } + locals_compressed.push((1, local.ty)); + } + locals_compressed.encode(e); + } +} + +impl Encode for Expression<'_> { + fn encode(&self, e: &mut Vec<u8>) { + for instr in self.instrs.iter() { + instr.encode(e); + } + e.push(0x0b); + } +} + +impl Encode for BlockType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + // block types using an index are encoded as an sleb, not a uleb + if let Some(Index::Num(n, _)) = &self.ty.index { + return i64::from(*n).encode(e); + } + let ty = self + .ty + .inline + .as_ref() + .expect("function type not filled in"); + if ty.params.is_empty() && ty.results.is_empty() { + return e.push(0x40); + } + if ty.params.is_empty() && ty.results.len() == 1 { + return ty.results[0].encode(e); + } + panic!("multi-value block types should have an index"); + } +} + +impl Encode for FuncBindType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.ty.encode(e); + } +} + +impl Encode for LetType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.block.encode(e); + self.locals.encode(e); + } +} + +impl Encode for LaneArg { + fn encode(&self, e: &mut Vec<u8>) { + self.lane.encode(e); + } +} + +impl Encode for MemArg<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match &self.memory { + Index::Num(0, _) => { + self.align.trailing_zeros().encode(e); + self.offset.encode(e); + } + _ => { + (self.align.trailing_zeros() | (1 << 6)).encode(e); + self.memory.encode(e); + self.offset.encode(e); + } + } + } +} + +impl Encode for LoadOrStoreLane<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.memarg.encode(e); + self.lane.encode(e); + } +} + +impl Encode for CallIndirect<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.ty.encode(e); + self.table.encode(e); + } +} + +impl Encode for TableInit<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.elem.encode(e); + self.table.encode(e); + } +} + +impl Encode for TableCopy<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.dst.encode(e); + self.src.encode(e); + } +} + +impl Encode for TableArg<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.dst.encode(e); + } +} + +impl Encode for MemoryArg<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.mem.encode(e); + } +} + +impl Encode for MemoryInit<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.data.encode(e); + self.mem.encode(e); + } +} + +impl Encode for MemoryCopy<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.dst.encode(e); + self.src.encode(e); + } +} + +impl Encode for BrTableIndices<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.labels.encode(e); + self.default.encode(e); + } +} + +impl Encode for Float32 { + fn encode(&self, e: &mut Vec<u8>) { + e.extend_from_slice(&self.bits.to_le_bytes()); + } +} + +impl Encode for Float64 { + fn encode(&self, e: &mut Vec<u8>) { + e.extend_from_slice(&self.bits.to_le_bytes()); + } +} + +#[derive(Default)] +struct Names<'a> { + module: Option<&'a str>, + funcs: Vec<(u32, &'a str)>, + func_idx: u32, + locals: Vec<(u32, Vec<(u32, &'a str)>)>, + labels: Vec<(u32, Vec<(u32, &'a str)>)>, + globals: Vec<(u32, &'a str)>, + global_idx: u32, + memories: Vec<(u32, &'a str)>, + memory_idx: u32, + tables: Vec<(u32, &'a str)>, + table_idx: u32, + tags: Vec<(u32, &'a str)>, + tag_idx: u32, + types: Vec<(u32, &'a str)>, + type_idx: u32, + data: Vec<(u32, &'a str)>, + data_idx: u32, + elems: Vec<(u32, &'a str)>, + elem_idx: u32, +} + +fn find_names<'a>( + module_id: &Option<Id<'a>>, + module_name: &Option<NameAnnotation<'a>>, + fields: &[ModuleField<'a>], +) -> Names<'a> { + fn get_name<'a>(id: &Option<Id<'a>>, name: &Option<NameAnnotation<'a>>) -> Option<&'a str> { + name.as_ref().map(|n| n.name).or(id.and_then(|id| { + if id.is_gensym() { + None + } else { + Some(id.name()) + } + })) + } + + enum Name { + Type, + Global, + Func, + Memory, + Table, + Tag, + Elem, + Data, + } + + let mut ret = Names::default(); + ret.module = get_name(module_id, module_name); + let mut names = Vec::new(); + for field in fields { + // Extract the kind/id/name from whatever kind of field this is... + let (kind, id, name) = match field { + ModuleField::Import(i) => ( + match i.item.kind { + ItemKind::Func(_) => Name::Func, + ItemKind::Table(_) => Name::Table, + ItemKind::Memory(_) => Name::Memory, + ItemKind::Global(_) => Name::Global, + ItemKind::Tag(_) => Name::Tag, + }, + &i.item.id, + &i.item.name, + ), + ModuleField::Global(g) => (Name::Global, &g.id, &g.name), + ModuleField::Table(t) => (Name::Table, &t.id, &t.name), + ModuleField::Memory(m) => (Name::Memory, &m.id, &m.name), + ModuleField::Tag(t) => (Name::Tag, &t.id, &t.name), + ModuleField::Type(t) => (Name::Type, &t.id, &t.name), + ModuleField::Rec(r) => { + for ty in &r.types { + names.push((Name::Type, &ty.id, &ty.name, field)); + } + continue; + } + ModuleField::Elem(e) => (Name::Elem, &e.id, &e.name), + ModuleField::Data(d) => (Name::Data, &d.id, &d.name), + ModuleField::Func(f) => (Name::Func, &f.id, &f.name), + ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => continue, + }; + names.push((kind, id, name, field)); + } + + for (kind, id, name, field) in names { + // .. and using the kind we can figure out where to place this name + let (list, idx) = match kind { + Name::Func => (&mut ret.funcs, &mut ret.func_idx), + Name::Table => (&mut ret.tables, &mut ret.table_idx), + Name::Memory => (&mut ret.memories, &mut ret.memory_idx), + Name::Global => (&mut ret.globals, &mut ret.global_idx), + Name::Tag => (&mut ret.tags, &mut ret.tag_idx), + Name::Type => (&mut ret.types, &mut ret.type_idx), + Name::Elem => (&mut ret.elems, &mut ret.elem_idx), + Name::Data => (&mut ret.data, &mut ret.data_idx), + }; + if let Some(name) = get_name(id, name) { + list.push((*idx, name)); + } + + // Handle module locals separately from above + if let ModuleField::Func(f) = field { + let mut local_names = Vec::new(); + let mut label_names = Vec::new(); + let mut local_idx = 0; + let mut label_idx = 0; + + // Consult the inline type listed for local names of parameters. + // This is specifically preserved during the name resolution + // pass, but only for functions, so here we can look at the + // original source's names. + if let Some(ty) = &f.ty.inline { + for (id, name, _) in ty.params.iter() { + if let Some(name) = get_name(id, name) { + local_names.push((local_idx, name)); + } + local_idx += 1; + } + } + if let FuncKind::Inline { + locals, expression, .. + } = &f.kind + { + for local in locals.iter() { + if let Some(name) = get_name(&local.id, &local.name) { + local_names.push((local_idx, name)); + } + local_idx += 1; + } + + for i in expression.instrs.iter() { + match i { + Instruction::If(block) + | Instruction::Block(block) + | Instruction::Loop(block) + | Instruction::Try(block) + | Instruction::TryTable(TryTable { block, .. }) + | Instruction::Let(LetType { block, .. }) => { + if let Some(name) = get_name(&block.label, &block.label_name) { + label_names.push((label_idx, name)); + } + label_idx += 1; + } + _ => {} + } + } + } + if local_names.len() > 0 { + ret.locals.push((*idx, local_names)); + } + if label_names.len() > 0 { + ret.labels.push((*idx, label_names)); + } + } + + *idx += 1; + } + + return ret; +} + +impl Names<'_> { + fn is_empty(&self) -> bool { + self.module.is_none() + && self.funcs.is_empty() + && self.locals.is_empty() + && self.labels.is_empty() + && self.globals.is_empty() + && self.memories.is_empty() + && self.tables.is_empty() + && self.types.is_empty() + && self.data.is_empty() + && self.elems.is_empty() + && self.tags.is_empty() + // NB: specifically don't check modules/instances since they're + // not encoded for now. + } +} + +impl Encode for Names<'_> { + fn encode(&self, dst: &mut Vec<u8>) { + let mut tmp = Vec::new(); + + let mut subsec = |id: u8, data: &mut Vec<u8>| { + dst.push(id); + data.encode(dst); + data.truncate(0); + }; + + if let Some(id) = self.module { + id.encode(&mut tmp); + subsec(0, &mut tmp); + } + if self.funcs.len() > 0 { + self.funcs.encode(&mut tmp); + subsec(1, &mut tmp); + } + if self.locals.len() > 0 { + self.locals.encode(&mut tmp); + subsec(2, &mut tmp); + } + if self.labels.len() > 0 { + self.labels.encode(&mut tmp); + subsec(3, &mut tmp); + } + if self.types.len() > 0 { + self.types.encode(&mut tmp); + subsec(4, &mut tmp); + } + if self.tables.len() > 0 { + self.tables.encode(&mut tmp); + subsec(5, &mut tmp); + } + if self.memories.len() > 0 { + self.memories.encode(&mut tmp); + subsec(6, &mut tmp); + } + if self.globals.len() > 0 { + self.globals.encode(&mut tmp); + subsec(7, &mut tmp); + } + if self.elems.len() > 0 { + self.elems.encode(&mut tmp); + subsec(8, &mut tmp); + } + if self.data.len() > 0 { + self.data.encode(&mut tmp); + subsec(9, &mut tmp); + } + if self.tags.len() > 0 { + self.tags.encode(&mut tmp); + subsec(11, &mut tmp); + } + } +} + +impl Encode for Id<'_> { + fn encode(&self, dst: &mut Vec<u8>) { + assert!(!self.is_gensym()); + self.name().encode(dst); + } +} + +impl<'a> Encode for TryTable<'a> { + fn encode(&self, dst: &mut Vec<u8>) { + self.block.encode(dst); + self.catches.encode(dst); + } +} + +impl<'a> Encode for TryTableCatch<'a> { + fn encode(&self, dst: &mut Vec<u8>) { + let flag_byte: u8 = match self.kind { + TryTableCatchKind::Catch(..) => 0, + TryTableCatchKind::CatchRef(..) => 1, + TryTableCatchKind::CatchAll => 2, + TryTableCatchKind::CatchAllRef => 3, + }; + flag_byte.encode(dst); + match self.kind { + TryTableCatchKind::Catch(tag) | TryTableCatchKind::CatchRef(tag) => { + tag.encode(dst); + } + TryTableCatchKind::CatchAll | TryTableCatchKind::CatchAllRef => {} + } + self.label.encode(dst); + } +} + +impl Encode for V128Const { + fn encode(&self, dst: &mut Vec<u8>) { + dst.extend_from_slice(&self.to_le_bytes()); + } +} + +impl Encode for I8x16Shuffle { + fn encode(&self, dst: &mut Vec<u8>) { + dst.extend_from_slice(&self.lanes); + } +} + +impl<'a> Encode for SelectTypes<'a> { + fn encode(&self, dst: &mut Vec<u8>) { + match &self.tys { + Some(list) => { + dst.push(0x1c); + list.encode(dst); + } + None => dst.push(0x1b), + } + } +} + +impl Encode for Custom<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + Custom::Raw(r) => r.encode(e), + Custom::Producers(p) => p.encode(e), + Custom::Dylink0(p) => p.encode(e), + } + } +} + +impl Encode for RawCustomSection<'_> { + fn encode(&self, e: &mut Vec<u8>) { + for list in self.data.iter() { + e.extend_from_slice(list); + } + } +} + +impl Encode for Producers<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.fields.encode(e); + } +} + +impl Encode for Dylink0<'_> { + fn encode(&self, e: &mut Vec<u8>) { + for section in self.subsections.iter() { + e.push(section.id()); + let mut tmp = Vec::new(); + section.encode(&mut tmp); + tmp.encode(e); + } + } +} + +impl Encode for Dylink0Subsection<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + Dylink0Subsection::MemInfo { + memory_size, + memory_align, + table_size, + table_align, + } => { + memory_size.encode(e); + memory_align.encode(e); + table_size.encode(e); + table_align.encode(e); + } + Dylink0Subsection::Needed(libs) => libs.encode(e), + Dylink0Subsection::ExportInfo(list) => list.encode(e), + Dylink0Subsection::ImportInfo(list) => list.encode(e), + } + } +} + +impl Encode for Tag<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.ty.encode(e); + match &self.kind { + TagKind::Inline() => {} + _ => panic!("TagKind should be inline during encoding"), + } + } +} + +impl Encode for TagType<'_> { + fn encode(&self, e: &mut Vec<u8>) { + match self { + TagType::Exception(ty) => { + e.push(0x00); + ty.encode(e); + } + } + } +} + +impl Encode for StructAccess<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.r#struct.encode(e); + self.field.encode(e); + } +} + +impl Encode for ArrayFill<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.array.encode(e); + } +} + +impl Encode for ArrayCopy<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.dest_array.encode(e); + self.src_array.encode(e); + } +} + +impl Encode for ArrayInit<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.array.encode(e); + self.segment.encode(e); + } +} + +impl Encode for ArrayNewFixed<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.array.encode(e); + self.length.encode(e); + } +} + +impl Encode for ArrayNewData<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.array.encode(e); + self.data_idx.encode(e); + } +} + +impl Encode for ArrayNewElem<'_> { + fn encode(&self, e: &mut Vec<u8>) { + self.array.encode(e); + self.elem_idx.encode(e); + } +} + +impl Encode for RefTest<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + if self.r#type.nullable { + e.push(0x15); + } else { + e.push(0x14); + } + self.r#type.heap.encode(e); + } +} + +impl Encode for RefCast<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + if self.r#type.nullable { + e.push(0x17); + } else { + e.push(0x16); + } + self.r#type.heap.encode(e); + } +} + +fn br_on_cast_flags(from_nullable: bool, to_nullable: bool) -> u8 { + let mut flag = 0; + if from_nullable { + flag |= 1 << 0; + } + if to_nullable { + flag |= 1 << 1; + } + flag +} + +impl Encode for BrOnCast<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + e.push(0x18); + e.push(br_on_cast_flags( + self.from_type.nullable, + self.to_type.nullable, + )); + self.label.encode(e); + self.from_type.heap.encode(e); + self.to_type.heap.encode(e); + } +} + +impl Encode for BrOnCastFail<'_> { + fn encode(&self, e: &mut Vec<u8>) { + e.push(0xfb); + e.push(0x19); + e.push(br_on_cast_flags( + self.from_type.nullable, + self.to_type.nullable, + )); + self.label.encode(e); + self.from_type.heap.encode(e); + self.to_type.heap.encode(e); + } +} |