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

henrythasler / rust-tiny-wasm / 28735373045

05 Jul 2026 08:52AM UTC coverage: 94.977% (-0.4%) from 95.369%
28735373045

push

github

henrythasler
finalize call instruction for integers

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

71 of 71 new or added lines in 5 files covered. (100.0%)

27 existing lines in 3 files now uncovered.

2269 of 2389 relevant lines covered (94.98%)

64.01 hits per line

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

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

3
use super::*;
4

5
pub fn compile_function(
185✔
6
    reader: &mut wasmparser::OperatorsReader<'_>,
185✔
7
    module_ctx: &ModuleContext,
185✔
8
    function: &ModuleFunction,
185✔
9
    locals: &[(u32, ValType)],
185✔
10
    call_patches: &mut Vec<FunctionPatch>,
185✔
11
    machinecode: &mut Vec<u32>,
185✔
12
) -> Result<usize> {
185✔
13
    // Value stack starts empty
14
    let mut value_stack: Vec<StackElement> = vec![];
185✔
15
    let func_type = module_ctx.types.get(function.type_index).unwrap();
185✔
16

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

30
    let mut trap_locations: Vec<Patch> = vec![];
185✔
31

32
    let initial_size = machinecode.len();
185✔
33
    let mut register_pool = RegisterPool::new();
185✔
34

35
    // calculate initial stack size from all parameters and locals
36
    let (_variables_size, stack_size) = get_initial_stack_size(func_type, locals);
185✔
37
    // println!("{} {:?}", _variables_size, stack_size);
38

39
    // every functions starts with an epilogue to save the initial state and create a new stack frame
40
    emit_prologue(stack_size, &mut register_pool, machinecode);
185✔
41

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

53
    if !locals.is_empty() {
185✔
54
        variables.extend(save_locals_to_stack(&mut stack_offset, locals, machinecode));
20✔
55
    }
165✔
56

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

241
    // move result values to result registers according to Aarch64 Procedure Call Standard (X0..X7)
242
    // X0: Return Code (0=Ok, 1=Trap),
243
    // X1: Result or Trap code
244
    if func_type.results().is_empty() {
184✔
245
        // Return Code =Ok (0)
12✔
246
        machinecode.push(processing::mov_imm(
12✔
247
            IReg::X0,
12✔
248
            WasmReturnCode::Ok as u32,
12✔
249
            RegSize::Int64bit,
12✔
250
        ));
12✔
251
        // Result=0
12✔
252
        machinecode.push(processing::mov_reg(IReg::X1, IReg::XZR, RegSize::Int64bit));
12✔
253
    } else {
12✔
254
        load_results(&mut value_stack, func_type.results().len(), machinecode)?;
172✔
255
    }
256

257
    for patch in trap_locations {
184✔
258
        let offset = (machinecode.len() - patch.location) as i32 * 4;
34✔
259
        let location = machinecode
34✔
260
            .get_mut(patch.location)
34✔
261
            .expect("patch location should point to valid location");
34✔
262

263
        match patch.instruction {
34✔
264
            Instruction::Br => {
28✔
265
                branch::patch_branch(offset, location);
28✔
266
            }
28✔
267
            Instruction::Cbnz => {
6✔
268
                branch::patch_cbnz(offset, location);
6✔
269
            }
6✔
UNCOV
270
            _ => panic!("unexpected instruction"),
×
271
        }
272
    }
273

274
    // restore initial state before returning to the caller
275
    emit_epilogue(stack_size, machinecode);
184✔
276

277
    // add padding to INSTRUCTION_SIZE to align subsequent functions to the correct size
278
    let padding_instructions =
184✔
279
        ((machinecode.len() * INSTRUCTION_SIZE) % mem::align_of::<fn()>()) / INSTRUCTION_SIZE;
184✔
280
    for _ in 0..padding_instructions {
184✔
281
        machinecode.push(hint::nop());
134✔
282
    }
134✔
283

284
    Ok(machinecode.len() - initial_size)
184✔
285
}
185✔
286

287
pub fn map_op_to_valtype(op: &Operator) -> ValType {
402✔
288
    match op {
402✔
289
        Operator::I32Add
290
        | Operator::I32Sub
291
        | Operator::I32Mul
292
        | Operator::I32Const { .. }
293
        | Operator::I32Ctz
294
        | Operator::I32LtS
295
        | Operator::I32LeU
296
        | Operator::I32Eqz
297
        | Operator::I32DivS
298
        | Operator::I32DivU => ValType::I32,
246✔
299
        Operator::I64Add
300
        | Operator::I64Sub
301
        | Operator::I64Mul
302
        | Operator::I64Const { .. }
303
        | Operator::I64Ctz
304
        | Operator::I64LtS
305
        | Operator::I64LeU
306
        | Operator::I64Eqz
307
        | Operator::I64DivS
308
        | Operator::I64DivU => ValType::I64,
136✔
309
        Operator::F32Const { .. } => ValType::F32,
2✔
310
        Operator::F64Const { .. } => ValType::F64,
2✔
311
        Operator::F32Add | Operator::F32Sub | Operator::F32Mul | Operator::F32Div => ValType::F32,
8✔
312
        Operator::F64Add | Operator::F64Sub | Operator::F64Mul | Operator::F64Div => ValType::F64,
8✔
UNCOV
313
        _ => panic!("Operator '{:?}' not supported", op),
×
314
    }
315
}
402✔
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