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

henrythasler / rust-tiny-wasm / 25594974763

09 May 2026 07:09AM UTC coverage: 95.511% (+0.2%) from 95.333%
25594974763

push

github

henrythasler
fix block end register alignment

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

1 of 1 new or added line in 1 file covered. (100.0%)

6 existing lines in 3 files now uncovered.

1617 of 1693 relevant lines covered (95.51%)

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

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

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

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

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

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

45
    if !locals.is_empty() {
116✔
46
        variables.extend(save_locals_to_stack(&mut stack_offset, locals, machinecode));
12✔
47
    }
104✔
48

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

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

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

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

207
    Ok(machinecode.len() - initial_size)
115✔
208
}
116✔
209

210
pub fn map_op_to_valtype(op: &Operator) -> ValType {
281✔
211
    match op {
281✔
212
        Operator::I32Add
213
        | Operator::I32Sub
214
        | Operator::I32Mul
215
        | Operator::I32Const { .. }
216
        | Operator::I32Ctz
217
        | Operator::I32LtS
218
        | Operator::I32LeU
219
        | Operator::I32Eqz => ValType::I32,
163✔
220
        Operator::I64Add
221
        | Operator::I64Sub
222
        | Operator::I64Mul
223
        | Operator::I64Const { .. }
224
        | Operator::I64Ctz
225
        | Operator::I64LtS
226
        | Operator::I64LeU
227
        | Operator::I64Eqz => ValType::I64,
118✔
UNCOV
228
        _ => panic!("Operator '{:?}' not supported", op),
×
229
    }
230
}
281✔
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