Skip to content

Commit 156960b

Browse files
authored
Transition more encoding in wast to using wasm-encoder (#1803)
* wast: Use wasm-encoder for import sections * wast: Use wasm-encoder for the table section * wast: Use wasm-encoder for the memory section * wast: Use wasm-encoder for the tag section * wast: Use wasm-encoder for the global section * wast: Use wasm-encoder for the element section * wast: Use wasm-encoder for the data section * wast: Use wasm-encoder for the func section * wast: Use wasm-encoder for the name section * wast: Use wasm-encoder for more custom sections * wast: Use wasm-encoder for encoding branch hints This additionally entailed adding support to wasm-encoder for emitting branch hints. * Add example for `wasm_encoder::BranchHints` * Fix rebase conflict
1 parent a28e134 commit 156960b

File tree

6 files changed

+434
-475
lines changed

6 files changed

+434
-475
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/wasm-encoder/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ wasmparser = { optional = true, workspace = true }
3030
anyhow = { workspace = true }
3131
tempfile = "3.2.0"
3232
wasmparser = { path = "../wasmparser" }
33+
wasmprinter = { path = "../wasmprinter" }

crates/wasm-encoder/src/core.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod branch_hints;
12
mod code;
23
mod custom;
34
mod data;
@@ -16,6 +17,7 @@ mod tables;
1617
mod tags;
1718
mod types;
1819

20+
pub use branch_hints::*;
1921
pub use code::*;
2022
pub use custom::*;
2123
pub use data::*;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use crate::{CustomSection, Encode, Section, SectionId};
2+
use std::borrow::Cow;
3+
4+
/// Helper structure to encode the `metadata.code.branch_hint` custom section.
5+
///
6+
/// This section was defined in the branch-hinting proposal for WebAssembly:
7+
/// <https://github.com/WebAssembly/branch-hinting>.
8+
///
9+
/// # Example
10+
///
11+
/// ```
12+
/// use wasm_encoder::*;
13+
///
14+
/// let mut module = Module::new();
15+
///
16+
/// let mut types = TypeSection::new();
17+
/// types.ty().function([], []);
18+
/// module.section(&types);
19+
///
20+
/// let mut funcs = FunctionSection::new();
21+
/// funcs.function(0);
22+
/// module.section(&funcs);
23+
///
24+
/// let mut code = CodeSection::new();
25+
/// let mut body = Function::new([]);
26+
///
27+
/// body.instruction(&Instruction::I32Const(1));
28+
/// let if_offset = body.byte_len();
29+
/// body.instruction(&Instruction::If(BlockType::Empty));
30+
/// body.instruction(&Instruction::End);
31+
/// body.instruction(&Instruction::End);
32+
/// code.function(&body);
33+
///
34+
/// let mut hints = BranchHints::new();
35+
/// hints.function_hints(0, [BranchHint {
36+
/// branch_func_offset: if_offset as u32,
37+
/// branch_hint_value: 1, // taken
38+
/// }]);
39+
/// module.section(&hints);
40+
/// module.section(&code);
41+
///
42+
/// let wasm = module.finish();
43+
/// let wat = wasmprinter::print_bytes(&wasm).unwrap();
44+
/// assert_eq!(wat, r#"(module
45+
/// (type (;0;) (func))
46+
/// (func (;0;) (type 0)
47+
/// i32.const 1
48+
/// (@metadata.code.branch_hint "\01")
49+
/// if ;; label = @1
50+
/// end
51+
/// )
52+
/// )
53+
/// "#);
54+
///
55+
/// ```
56+
#[derive(Default, Debug)]
57+
pub struct BranchHints {
58+
bytes: Vec<u8>,
59+
num_hints: u32,
60+
}
61+
62+
/// A single branch hint within a function.
63+
#[derive(Debug, Clone, Copy)]
64+
pub struct BranchHint {
65+
/// The offset, in bytes from the beginning of the function, to the `if`
66+
/// instruction that this is hinting.
67+
pub branch_func_offset: u32,
68+
/// The value of the hint, 0 for not taken and 1 for taken.
69+
pub branch_hint_value: u32,
70+
}
71+
72+
impl BranchHints {
73+
/// Construct an empty encoder for the branch hints custom section.
74+
pub fn new() -> Self {
75+
Self::default()
76+
}
77+
78+
/// Adds a new set of function hints for the `func` specified.
79+
pub fn function_hints<I>(&mut self, func: u32, hints: I)
80+
where
81+
I: IntoIterator<Item = BranchHint>,
82+
I::IntoIter: ExactSizeIterator,
83+
{
84+
self.num_hints += 1;
85+
func.encode(&mut self.bytes);
86+
let hints = hints.into_iter();
87+
hints.len().encode(&mut self.bytes);
88+
for hint in hints {
89+
hint.branch_func_offset.encode(&mut self.bytes);
90+
1u32.encode(&mut self.bytes);
91+
hint.branch_hint_value.encode(&mut self.bytes);
92+
}
93+
}
94+
95+
/// Returns if this is an empty section.
96+
pub fn is_empty(&self) -> bool {
97+
self.num_hints == 0
98+
}
99+
100+
/// Returns the number of functions that have hints registered in this
101+
/// sectino.
102+
pub fn len(&self) -> u32 {
103+
self.num_hints
104+
}
105+
}
106+
107+
impl Encode for BranchHints {
108+
fn encode(&self, sink: &mut Vec<u8>) {
109+
let mut data = Vec::new();
110+
self.num_hints.encode(&mut data);
111+
data.extend(&self.bytes);
112+
113+
CustomSection {
114+
name: "metadata.code.branch_hint".into(),
115+
data: Cow::Borrowed(&data),
116+
}
117+
.encode(sink);
118+
}
119+
}
120+
121+
impl Section for BranchHints {
122+
fn id(&self) -> u8 {
123+
SectionId::Custom.into()
124+
}
125+
}

crates/wast/src/component/binary.rs

Lines changed: 16 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use crate::component::*;
22
use crate::core;
33
use crate::core::EncodeOptions;
4-
use crate::token::{Id, Index, NameAnnotation, Span};
4+
use crate::token::{Id, Index, NameAnnotation};
55
use wasm_encoder::{
66
CanonicalFunctionSection, ComponentAliasSection, ComponentCoreTypeEncoder,
77
ComponentDefinedTypeEncoder, ComponentExportSection, ComponentImportSection,
88
ComponentInstanceSection, ComponentNameSection, ComponentSection, ComponentSectionId,
99
ComponentStartSection, ComponentTypeEncoder, ComponentTypeSection, CoreTypeSection,
10-
InstanceSection, NameMap, NestedComponentSection, RawSection, SectionId, SubType,
10+
InstanceSection, NameMap, NestedComponentSection, RawSection, SubType,
1111
};
1212

1313
pub fn encode(component: &Component<'_>, options: &EncodeOptions) -> Vec<u8> {
@@ -177,19 +177,12 @@ impl<'a> Encoder<'a> {
177177
fn encode_custom(&mut self, custom: &Custom) {
178178
// Flush any in-progress section before encoding the customs section
179179
self.flush(None);
180-
self.component.section(custom);
180+
self.component.section(&custom.to_section());
181181
}
182182

183183
fn encode_producers(&mut self, custom: &core::Producers) {
184-
use crate::encode::Encode;
185-
186-
let mut data = Vec::new();
187-
custom.encode(&mut data);
188-
self.encode_custom(&Custom {
189-
name: "producers",
190-
span: Span::from_offset(0),
191-
data: vec![&data],
192-
})
184+
self.flush(None);
185+
self.component.section(&custom.to_section());
193186
}
194187

195188
fn encode_core_module(&mut self, module: &CoreModule<'a>, options: &EncodeOptions) {
@@ -549,32 +542,16 @@ fn get_name<'a>(id: &Option<Id<'a>>, name: &Option<NameAnnotation<'a>>) -> Optio
549542
})
550543
}
551544

552-
// This implementation is much like `wasm_encoder::CustomSection`, except
553-
// that it extends via a list of slices instead of a single slice.
554-
impl wasm_encoder::Encode for Custom<'_> {
555-
fn encode(&self, sink: &mut Vec<u8>) {
556-
let mut buf = [0u8; 5];
557-
let encoded_name_len =
558-
leb128::write::unsigned(&mut &mut buf[..], u64::try_from(self.name.len()).unwrap())
559-
.unwrap();
560-
let data_len = self.data.iter().fold(0, |acc, s| acc + s.len());
561-
562-
// name length
563-
(encoded_name_len + self.name.len() + data_len).encode(sink);
564-
565-
// name
566-
self.name.encode(sink);
567-
568-
// data
569-
for s in &self.data {
570-
sink.extend(*s);
545+
impl Custom<'_> {
546+
fn to_section(&self) -> wasm_encoder::CustomSection<'_> {
547+
let mut ret = Vec::new();
548+
for list in self.data.iter() {
549+
ret.extend_from_slice(list);
550+
}
551+
wasm_encoder::CustomSection {
552+
name: self.name.into(),
553+
data: ret.into(),
571554
}
572-
}
573-
}
574-
575-
impl wasm_encoder::ComponentSection for Custom<'_> {
576-
fn id(&self) -> u8 {
577-
SectionId::Custom.into()
578555
}
579556
}
580557

@@ -629,63 +606,6 @@ impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
629606
}
630607
}
631608

632-
impl From<&core::ItemKind<'_>> for wasm_encoder::EntityType {
633-
fn from(kind: &core::ItemKind) -> Self {
634-
match kind {
635-
core::ItemKind::Func(t) => Self::Function(t.into()),
636-
core::ItemKind::Table(t) => Self::Table((*t).into()),
637-
core::ItemKind::Memory(t) => Self::Memory((*t).into()),
638-
core::ItemKind::Global(t) => Self::Global((*t).into()),
639-
core::ItemKind::Tag(t) => Self::Tag(t.into()),
640-
}
641-
}
642-
}
643-
644-
impl From<core::TableType<'_>> for wasm_encoder::TableType {
645-
fn from(ty: core::TableType) -> Self {
646-
Self {
647-
element_type: ty.elem.into(),
648-
minimum: ty.limits.min,
649-
maximum: ty.limits.max,
650-
table64: ty.limits.is64,
651-
shared: ty.shared,
652-
}
653-
}
654-
}
655-
656-
impl From<core::MemoryType> for wasm_encoder::MemoryType {
657-
fn from(ty: core::MemoryType) -> Self {
658-
Self {
659-
minimum: ty.limits.min,
660-
maximum: ty.limits.max,
661-
memory64: ty.limits.is64,
662-
shared: ty.shared,
663-
page_size_log2: ty.page_size_log2,
664-
}
665-
}
666-
}
667-
668-
impl From<core::GlobalType<'_>> for wasm_encoder::GlobalType {
669-
fn from(ty: core::GlobalType) -> Self {
670-
Self {
671-
val_type: ty.ty.into(),
672-
mutable: ty.mutable,
673-
shared: ty.shared,
674-
}
675-
}
676-
}
677-
678-
impl From<&core::TagType<'_>> for wasm_encoder::TagType {
679-
fn from(ty: &core::TagType) -> Self {
680-
match ty {
681-
core::TagType::Exception(r) => Self {
682-
kind: wasm_encoder::TagKind::Exception,
683-
func_type_idx: r.into(),
684-
},
685-
}
686-
}
687-
}
688-
689609
impl<T: std::fmt::Debug> From<&core::TypeUse<'_, T>> for u32 {
690610
fn from(u: &core::TypeUse<'_, T>) -> Self {
691611
match &u.index {
@@ -898,10 +818,10 @@ impl From<&ModuleType<'_>> for wasm_encoder::ModuleType {
898818
_ => unreachable!("only outer type aliases are supported"),
899819
},
900820
ModuleTypeDecl::Import(i) => {
901-
encoded.import(i.module, i.field, (&i.item.kind).into());
821+
encoded.import(i.module, i.field, i.item.to_entity_type());
902822
}
903823
ModuleTypeDecl::Export(name, item) => {
904-
encoded.export(name, (&item.kind).into());
824+
encoded.export(name, item.to_entity_type());
905825
}
906826
}
907827
}

0 commit comments

Comments
 (0)