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

henrythasler / rust-tiny-wasm / 27089938512

07 Jun 2026 10:29AM UTC coverage: 92.847% (-1.3%) from 94.121%
27089938512

Pull #6

github

web-flow
Merge 0a4fe7baf into df49d44a8
Pull Request #6: Feature/floats

426 of 470 new or added lines in 17 files covered. (90.64%)

5 existing lines in 3 files now uncovered.

1921 of 2069 relevant lines covered (92.85%)

64.65 hits per line

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

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

3
use super::*;
4

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

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

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

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

32
    // calculate initial stack size from all parameters and locals
33
    let (_variables_size, stack_size) = get_aligned_stack_size(func_type, locals);
157✔
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);
157✔
38

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

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

54
    'expression: while !reader.eof() {
1,125✔
55
        let index = reader.original_position();
1,125✔
56
        let op = reader.read().unwrap();
1,125✔
57
        match op {
1,125✔
58
            Operator::Drop => compile_drop(&mut value_stack, &mut register_pool),
58✔
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(
238✔
115
                    &mut control_stack,
238✔
116
                    &mut value_stack,
238✔
117
                    &mut register_pool,
238✔
118
                    machinecode,
238✔
119
                ) {
120
                    break 'expression;
156✔
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 } => {
176✔
130
                compile_const(
176✔
131
                    &op,
176✔
132
                    value,
176✔
133
                    &mut value_stack,
176✔
134
                    &mut register_pool,
176✔
135
                    machinecode,
176✔
136
                );
176✔
137
            }
176✔
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::F32Const { value } => {
2✔
148
                compile_float_const(
2✔
149
                    &op,
2✔
150
                    IeeeFloat::F32(value),
2✔
151
                    &mut value_stack,
2✔
152
                    &mut register_pool,
2✔
153
                    machinecode,
2✔
154
                );
2✔
155
            }
2✔
156
            Operator::F64Const { value } => {
2✔
157
                compile_float_const(
2✔
158
                    &op,
2✔
159
                    IeeeFloat::F64(value),
2✔
160
                    &mut value_stack,
2✔
161
                    &mut register_pool,
2✔
162
                    machinecode,
2✔
163
                );
2✔
164
            }
2✔
165
            Operator::LocalGet { local_index } => {
200✔
166
                let var = variables.get(local_index as usize).unwrap();
200✔
167
                compile_local_get(
200✔
168
                    var,
200✔
169
                    var.offset,
200✔
170
                    &mut value_stack,
200✔
171
                    &mut register_pool,
200✔
172
                    machinecode,
200✔
173
                );
200✔
174
            }
200✔
175
            Operator::LocalSet { local_index } => {
56✔
176
                let var = variables.get(local_index as usize).unwrap();
56✔
177
                compile_local_set(
56✔
178
                    var,
56✔
179
                    var.offset,
56✔
180
                    &mut value_stack,
56✔
181
                    &mut register_pool,
56✔
182
                    machinecode,
56✔
183
                );
56✔
184
            }
56✔
185
            Operator::LocalTee { local_index } => {
6✔
186
                let var = variables.get(local_index as usize).unwrap();
6✔
187
                compile_local_tee(var, var.offset, &mut value_stack, machinecode);
6✔
188
            }
6✔
189
            Operator::I32Add
190
            | Operator::I64Add
191
            | Operator::I32Sub
192
            | Operator::I64Sub
193
            | Operator::I32Mul
194
            | Operator::I64Mul
195
            | Operator::I32DivU
196
            | Operator::I64DivU
197
            | Operator::I32DivS
198
            | Operator::I64DivS => {
74✔
199
                compile_binop(
74✔
200
                    &op,
74✔
201
                    &mut value_stack,
74✔
202
                    &mut register_pool,
74✔
203
                    &mut trap_locations,
74✔
204
                    machinecode,
74✔
205
                );
74✔
206
            }
74✔
207
            Operator::I32Ctz | Operator::I64Ctz => {
8✔
208
                compile_unop(&op, &mut value_stack, machinecode);
8✔
209
            }
8✔
210
            _ => {
211
                return Err(TinyWasmError::Compiler(format!(
1✔
212
                    "unsupported instruction: {:?} at position {}",
1✔
213
                    op, index
1✔
214
                )));
1✔
215
            }
216
        }
217
    }
218

219
    // move result values to result registers according to Aarch64 Procedure Call Standard (X0..X7)
220
    // X0: Return Code (0=Ok, 1=Trap),
221
    // X1: Result or Trap code
222
    if func_type.results().is_empty() {
156✔
223
        // Return Code =Ok (0)
12✔
224
        machinecode.push(processing::mov_imm(
12✔
225
            IReg::X0,
12✔
226
            WasmReturnCode::Ok as u32,
12✔
227
            RegSize::Reg64bit,
12✔
228
        ));
12✔
229
        // Result=0
12✔
230
        machinecode.push(processing::mov_reg(IReg::X1, IReg::XZR, RegSize::Reg64bit));
12✔
231
    } else {
12✔
232
        load_results(&mut value_stack, func_type.results().len(), machinecode)?;
144✔
233
    }
234

235
    for patch in trap_locations {
156✔
236
        match patch.instruction {
28✔
237
            Instruction::Br => {
28✔
238
                let offset = (machinecode.len() - patch.location) as i32 * 4;
28✔
239
                let location = machinecode
28✔
240
                    .get_mut(patch.location)
28✔
241
                    .expect("patch location should point to valid location");
28✔
242
                branch::patch_branch(offset, location);
28✔
243
            }
28✔
244
            _ => panic!("unexpected instruction"),
×
245
        }
246
    }
247

248
    // restore initial state before returning to the caller
249
    emit_epilogue(stack_size, machinecode);
156✔
250

251
    // add padding to INSTRUCTION_SIZE to align subsequent functions to the correct size
252
    let padding_instructions =
156✔
253
        ((machinecode.len() * INSTRUCTION_SIZE) % mem::align_of::<fn()>()) / INSTRUCTION_SIZE;
156✔
254
    for _ in 0..padding_instructions {
156✔
255
        machinecode.push(hint::nop());
110✔
256
    }
110✔
257

258
    Ok(machinecode.len() - initial_size)
156✔
259
}
157✔
260

261
pub fn map_op_to_valtype(op: &Operator) -> ValType {
376✔
262
    match op {
376✔
263
        Operator::I32Add
264
        | Operator::I32Sub
265
        | Operator::I32Mul
266
        | Operator::I32Const { .. }
267
        | Operator::I32Ctz
268
        | Operator::I32LtS
269
        | Operator::I32LeU
270
        | Operator::I32Eqz
271
        | Operator::I32DivS
272
        | Operator::I32DivU => ValType::I32,
242✔
273
        Operator::I64Add
274
        | Operator::I64Sub
275
        | Operator::I64Mul
276
        | Operator::I64Const { .. }
277
        | Operator::I64Ctz
278
        | Operator::I64LtS
279
        | Operator::I64LeU
280
        | Operator::I64Eqz
281
        | Operator::I64DivS
282
        | Operator::I64DivU => ValType::I64,
130✔
283
        Operator::F32Const { .. } => ValType::F32,
2✔
284
        Operator::F64Const { .. } => ValType::F64,
2✔
UNCOV
285
        _ => panic!("Operator '{:?}' not supported", op),
×
286
    }
287
}
376✔
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