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

henrythasler / rust-tiny-wasm / 27492556297

14 Jun 2026 07:57AM UTC coverage: 92.969% (-1.2%) from 94.121%
27492556297

Pull #6

github

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

533 of 584 new or added lines in 19 files covered. (91.27%)

5 existing lines in 3 files now uncovered.

2023 of 2176 relevant lines covered (92.97%)

62.72 hits per line

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

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

3
use super::*;
4

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

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

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

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

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

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

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

54
    'expression: while !reader.eof() {
1,141✔
55
        let index = reader.original_position();
1,141✔
56
        let op = reader.read().unwrap();
1,141✔
57
        match op {
1,141✔
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(
242✔
115
                    &mut control_stack,
242✔
116
                    &mut value_stack,
242✔
117
                    &mut register_pool,
242✔
118
                    machinecode,
242✔
119
                ) {
120
                    break 'expression;
160✔
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 } => {
208✔
166
                let var = variables.get(local_index as usize).unwrap();
208✔
167
                compile_local_get(
208✔
168
                    var,
208✔
169
                    var.offset,
208✔
170
                    &mut value_stack,
208✔
171
                    &mut register_pool,
208✔
172
                    machinecode,
208✔
173
                );
208✔
174
            }
208✔
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
199
            | Operator::F32Add
200
            | Operator::F64Add => {
78✔
201
                compile_binop(
78✔
202
                    &op,
78✔
203
                    &mut value_stack,
78✔
204
                    &mut register_pool,
78✔
205
                    &mut trap_locations,
78✔
206
                    machinecode,
78✔
207
                );
78✔
208
            }
78✔
209
            Operator::I32Ctz | Operator::I64Ctz => {
8✔
210
                compile_unop(&op, &mut value_stack, machinecode);
8✔
211
            }
8✔
212
            _ => {
213
                return Err(TinyWasmError::Compiler(format!(
1✔
214
                    "unsupported instruction: {:?} at position {}",
1✔
215
                    op, index
1✔
216
                )));
1✔
217
            }
218
        }
219
    }
220

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

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

250
    // restore initial state before returning to the caller
251
    emit_epilogue(stack_size, machinecode);
160✔
252

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

260
    Ok(machinecode.len() - initial_size)
160✔
261
}
161✔
262

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