1use crate::{CustomSection, Encode, Section, SectionId};
2use 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)]
57pub 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)]
64pub 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
72impl 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
107impl Encode for BranchHints {
108 fn encode(&self, sink: &mut Vec<u8>) {
109 let mut data: Vec = 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
121impl Section for BranchHints {
122 fn id(&self) -> u8 {
123 SectionId::Custom.into()
124 }
125}
126