• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

henrythasler / rust-tiny-wasm / 25983716488

17 May 2026 06:39AM UTC coverage: 95.42% (-0.09%) from 95.511%
25983716488

push

github

henrythasler
fix block register alignment for branching

Co-authored-by: Copilot <copilot@github.com>

6 of 6 new or added lines in 2 files covered. (100.0%)

17 existing lines in 4 files now uncovered.

1646 of 1725 relevant lines covered (95.42%)

62.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.43
/src/compiler/function.rs
1
use super::*;
2

3
pub fn compile_function(
131✔
4
    reader: &mut wasmparser::OperatorsReader<'_>,
131✔
5
    func_type: &wasmparser::FuncType,
131✔
6
    locals: &[(u32, ValType)],
131✔
7
    machinecode: &mut Vec<u32>,
131✔
8
) -> Result<usize> {
131✔
9
    // Value stack starts empty
10
    let mut value_stack: Vec<StackElement> = vec![];
131✔
11

12
    // Control stack is initialized with the (implicit) outer func-block
13
    let mut control_stack: Vec<ControlFrame> = vec![ControlFrame {
131✔
14
        opcode: Opcode::Func,
131✔
15
        start_types: func_type.params().to_vec(),
131✔
16
        end_types: func_type.results().to_vec(),
131✔
17
        stack_height: value_stack.len(),
131✔
18
        value_stack: None,
131✔
19
        register_index: None,
131✔
20
        result_register: None,
131✔
21
        machinecode_offset: machinecode.len(),
131✔
22
        patches: vec![],
131✔
23
    }];
131✔
24

25
    let initial_size = machinecode.len();
131✔
26
    let mut register_pool = RegisterPool::new();
131✔
27

28
    // calculate initial stack size from all parameters and locals
29
    let (_variables_size, stack_size) = get_aligned_stack_size(func_type, locals);
131✔
30
    // println!("{} {:?}", _variables_size, stack_size);
31

32
    // every functions starts with an epilogue to save the initial state and create a new stack frame
33
    emit_prologue(stack_size, &mut register_pool, machinecode);
131✔
34

35
    let mut variables: Vec<LocalVar> = vec![];
131✔
36
    let mut stack_offset = 0;
131✔
37
    // save parameters to stack
38
    if !func_type.params().is_empty() {
131✔
39
        variables.extend(save_parameters_to_stack(
68✔
40
            &mut stack_offset,
68✔
41
            func_type.params(),
68✔
42
            machinecode,
68✔
43
        ));
68✔
44
    }
68✔
45

46
    if !locals.is_empty() {
131✔
47
        variables.extend(save_locals_to_stack(&mut stack_offset, locals, machinecode));
12✔
48
    }
119✔
49

50
    'expression: while !reader.eof() {
993✔
51
        let index = reader.original_position();
993✔
52
        let op = reader.read().unwrap();
993✔
53
        match op {
993✔
54
            Operator::Drop => compile_drop(&mut value_stack, &mut register_pool),
56✔
55
            Operator::Return => compile_return(&mut control_stack, &value_stack, machinecode),
24✔
56
            Operator::Block { blockty } => {
52✔
57
                compile_block(
52✔
58
                    blockty,
52✔
59
                    &mut control_stack,
52✔
60
                    &mut value_stack,
52✔
61
                    &mut register_pool,
52✔
62
                    machinecode,
52✔
63
                );
52✔
64
            }
52✔
65
            Operator::Br { relative_depth } => {
12✔
66
                compile_br(
12✔
67
                    relative_depth,
12✔
68
                    &mut control_stack,
12✔
69
                    &value_stack,
12✔
70
                    // &mut register_pool,
12✔
71
                    machinecode,
12✔
72
                );
12✔
73
            }
12✔
74
            Operator::BrIf { relative_depth } => {
50✔
75
                compile_brif(
50✔
76
                    relative_depth,
50✔
77
                    &mut control_stack,
50✔
78
                    &mut value_stack,
50✔
79
                    &mut register_pool,
50✔
80
                    machinecode,
50✔
81
                );
50✔
82
            }
50✔
83
            Operator::Loop { blockty } => {
4✔
84
                compile_loop(
4✔
85
                    blockty,
4✔
86
                    &mut control_stack,
4✔
87
                    &mut value_stack,
4✔
88
                    &mut register_pool,
4✔
89
                    machinecode,
4✔
90
                );
4✔
91
            }
4✔
92
            Operator::If { blockty } => {
20✔
93
                compile_if(
20✔
94
                    blockty,
20✔
95
                    &mut control_stack,
20✔
96
                    &mut value_stack,
20✔
97
                    &mut register_pool,
20✔
98
                    machinecode,
20✔
99
                );
20✔
100
            }
20✔
101
            Operator::Else => {
16✔
102
                compile_else(
16✔
103
                    &mut control_stack,
16✔
104
                    &mut value_stack,
16✔
105
                    &mut register_pool,
16✔
106
                    machinecode,
16✔
107
                );
16✔
108
            }
16✔
109
            Operator::End => {
110
                if compile_end(
206✔
111
                    &mut control_stack,
206✔
112
                    &mut value_stack,
206✔
113
                    &mut register_pool,
206✔
114
                    machinecode,
206✔
115
                ) {
116
                    break 'expression;
130✔
117
                }
76✔
118
            }
119
            Operator::I32LtS | Operator::I64LtS | Operator::I32LeU | Operator::I64LeU => {
120
                compile_relop(&op, &mut value_stack, &mut register_pool, machinecode)
28✔
121
            }
122
            Operator::I32Eqz | Operator::I64Eqz => {
123
                compile_testop(&op, &mut value_stack, machinecode)
2✔
124
            }
125
            Operator::I32Const { value } => {
166✔
126
                compile_const(
166✔
127
                    &op,
166✔
128
                    value,
166✔
129
                    &mut value_stack,
166✔
130
                    &mut register_pool,
166✔
131
                    machinecode,
166✔
132
                );
166✔
133
            }
166✔
134
            Operator::I64Const { value } => {
80✔
135
                compile_const(
80✔
136
                    &op,
80✔
137
                    value,
80✔
138
                    &mut value_stack,
80✔
139
                    &mut register_pool,
80✔
140
                    machinecode,
80✔
141
                );
80✔
142
            }
80✔
143
            Operator::LocalGet { local_index } => {
158✔
144
                let var = variables.get(local_index as usize).unwrap();
158✔
145
                compile_local_get(
158✔
146
                    var,
158✔
147
                    var.offset,
158✔
148
                    &mut value_stack,
158✔
149
                    &mut register_pool,
158✔
150
                    machinecode,
158✔
151
                );
158✔
152
            }
158✔
153
            Operator::LocalSet { local_index } => {
56✔
154
                let var = variables.get(local_index as usize).unwrap();
56✔
155
                compile_local_set(
56✔
156
                    var,
56✔
157
                    var.offset,
56✔
158
                    &mut value_stack,
56✔
159
                    &mut register_pool,
56✔
160
                    machinecode,
56✔
161
                );
56✔
162
            }
56✔
163
            Operator::LocalTee { local_index } => {
2✔
164
                let var = variables.get(local_index as usize).unwrap();
2✔
165
                compile_local_tee(var, var.offset, &mut value_stack, machinecode);
2✔
166
            }
2✔
167
            Operator::I32Add
168
            | Operator::I64Add
169
            | Operator::I32Sub
170
            | Operator::I64Sub
171
            | Operator::I32Mul
172
            | Operator::I64Mul => {
52✔
173
                compile_binop(&op, &mut value_stack, &mut register_pool, machinecode);
52✔
174
            }
52✔
175
            Operator::I32Ctz | Operator::I64Ctz => {
8✔
176
                compile_unop(&op, &mut value_stack, machinecode);
8✔
177
            }
8✔
178
            _ => {
179
                return Err(TinyWasmError::Compiler(format!(
1✔
180
                    "unsupported instruction: {:?} at position {}",
1✔
181
                    op, index
1✔
182
                )));
1✔
183
            }
184
        }
185
    }
186

187
    // move result values to result registers according to Aarch64 Procedure Call Standard (X0..X7)
188
    // X0: Result, X1: Tag (0=Ok, 1=Trap)
189
    if !func_type.results().is_empty() {
130✔
190
        load_results(&mut value_stack, func_type.results().len(), machinecode)?;
120✔
191
    } else {
10✔
192
        // Result=0
10✔
193
        machinecode.push(processing::mov_reg(Reg::X0, Reg::XZR, RegSize::Reg64bit));
10✔
194
        // Tag=Ok (0)
10✔
195
        machinecode.push(processing::mov_reg(Reg::X1, Reg::XZR, RegSize::Reg64bit));
10✔
196
    }
10✔
197

198
    // restore initial state before returning to the caller
199
    emit_epilogue(stack_size, machinecode);
130✔
200

201
    // add padding to INSTRUCTION_SIZE to align subsequent functions to the correct size
202
    let padding_instructions =
130✔
203
        ((machinecode.len() * INSTRUCTION_SIZE) % mem::align_of::<fn()>()) / INSTRUCTION_SIZE;
130✔
204
    for _ in 0..padding_instructions {
130✔
205
        machinecode.push(hint::nop());
84✔
206
    }
84✔
207

208
    Ok(machinecode.len() - initial_size)
130✔
209
}
131✔
210

211
pub fn map_op_to_valtype(op: &Operator) -> ValType {
336✔
212
    match op {
336✔
213
        Operator::I32Add
214
        | Operator::I32Sub
215
        | Operator::I32Mul
216
        | Operator::I32Const { .. }
217
        | Operator::I32Ctz
218
        | Operator::I32LtS
219
        | Operator::I32LeU
220
        | Operator::I32Eqz => ValType::I32,
214✔
221
        Operator::I64Add
222
        | Operator::I64Sub
223
        | Operator::I64Mul
224
        | Operator::I64Const { .. }
225
        | Operator::I64Ctz
226
        | Operator::I64LtS
227
        | Operator::I64LeU
228
        | Operator::I64Eqz => ValType::I64,
122✔
UNCOV
229
        _ => panic!("Operator '{:?}' not supported", op),
×
230
    }
231
}
336✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc