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