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

henrythasler / rust-tiny-wasm / 26724500385

31 May 2026 09:07PM UTC coverage: 93.974% (-1.2%) from 95.172%
26724500385

push

github

henrythasler
switch to inline trap handling

48 of 55 new or added lines in 7 files covered. (87.27%)

19 existing lines in 1 file now uncovered.

1731 of 1842 relevant lines covered (93.97%)

63.96 hits per line

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

98.98
/src/compiler/function.rs
1
use crate::runtime::WasmReturnCode;
2

3
use super::*;
4

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

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

27
    let mut trap_locations: Vec<Patch> = vec![];
143✔
28

29
    let initial_size = machinecode.len();
143✔
30
    let mut register_pool = RegisterPool::new();
143✔
31

32
    // calculate initial stack size from all parameters and locals
33
    let (_variables_size, stack_size) = get_aligned_stack_size(func_type, locals);
143✔
34
    // println!("{} {:?}", _variables_size, stack_size);
35

36
    // every functions starts with an epilogue to save the initial state and create a new stack frame
37
    emit_prologue(stack_size, &mut register_pool, machinecode);
143✔
38

39
    let mut variables: Vec<LocalVar> = vec![];
143✔
40
    let mut stack_offset = 0;
143✔
41
    // save parameters to stack
42
    if !func_type.params().is_empty() {
143✔
43
        variables.extend(save_parameters_to_stack(
78✔
44
            &mut stack_offset,
78✔
45
            func_type.params(),
78✔
46
            machinecode,
78✔
47
        ));
78✔
48
    }
78✔
49

50
    if !locals.is_empty() {
143✔
51
        variables.extend(save_locals_to_stack(&mut stack_offset, locals, machinecode));
16✔
52
    }
127✔
53

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

201
    // move result values to result registers according to Aarch64 Procedure Call Standard (X0..X7)
202
    // X0: Return Code (0=Ok, 1=Trap),
203
    // X1: Result or Trap code
204
    if func_type.results().is_empty() {
142✔
205
        // Return Code =Ok (0)
10✔
206
        machinecode.push(processing::mov_imm(
10✔
207
            Reg::X0,
10✔
208
            WasmReturnCode::Ok as u32,
10✔
209
            RegSize::Reg64bit,
10✔
210
        ));
10✔
211
        // Result=0
10✔
212
        machinecode.push(processing::mov_reg(Reg::X1, Reg::XZR, RegSize::Reg64bit));
10✔
213
    } else {
10✔
214
        load_results(&mut value_stack, func_type.results().len(), machinecode)?;
132✔
215
    }
216

217
    for patch in trap_locations {
142✔
218
        match patch.instruction {
4✔
219
            Instruction::Br => {
4✔
220
                let offset = (machinecode.len() - patch.location) as i32 * 4;
4✔
221
                let location = machinecode
4✔
222
                    .get_mut(patch.location)
4✔
223
                    .expect("patch location should point to valid location");
4✔
224
                branch::patch_branch(offset, location);
4✔
225
            }
4✔
NEW
226
            _ => panic!("unexpected instruction"),
×
227
        }
228
    }
229

230
    // restore initial state before returning to the caller
231
    emit_epilogue(stack_size, machinecode);
142✔
232

233
    // add padding to INSTRUCTION_SIZE to align subsequent functions to the correct size
234
    let padding_instructions =
142✔
235
        ((machinecode.len() * INSTRUCTION_SIZE) % mem::align_of::<fn()>()) / INSTRUCTION_SIZE;
142✔
236
    for _ in 0..padding_instructions {
142✔
237
        machinecode.push(hint::nop());
96✔
238
    }
96✔
239

240
    Ok(machinecode.len() - initial_size)
142✔
241
}
143✔
242

243
pub fn map_op_to_valtype(op: &Operator) -> ValType {
358✔
244
    match op {
358✔
245
        Operator::I32Add
246
        | Operator::I32Sub
247
        | Operator::I32Mul
248
        | Operator::I32Const { .. }
249
        | Operator::I32Ctz
250
        | Operator::I32LtS
251
        | Operator::I32LeU
252
        | Operator::I32Eqz
253
        | Operator::I32DivS
254
        | Operator::I32DivU => ValType::I32,
232✔
255
        Operator::I64Add
256
        | Operator::I64Sub
257
        | Operator::I64Mul
258
        | Operator::I64Const { .. }
259
        | Operator::I64Ctz
260
        | Operator::I64LtS
261
        | Operator::I64LeU
262
        | Operator::I64Eqz
263
        | Operator::I64DivS
264
        | Operator::I64DivU => ValType::I64,
126✔
265
        _ => panic!("Operator '{:?}' not supported", op),
×
266
    }
267
}
358✔
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