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

henrythasler / rust-tiny-wasm / 24008295295

05 Apr 2026 07:01PM UTC coverage: 83.564% (-11.9%) from 95.455%
24008295295

push

github

web-flow
Merge pull request #4 from henrythasler/feature/valent-blocks

Feature/valent blocks

146 of 333 new or added lines in 7 files covered. (43.84%)

1210 of 1448 relevant lines covered (83.56%)

22.73 hits per line

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

25.49
/src/valentblock/function.rs
1
use super::*;
2

3
#[derive(Debug)]
4
enum Opcode {
5
    Func,
6
    Block,
7
    Loop,
8
    If,
9
    Else,
10
}
11

12
#[derive(Debug)]
13
enum Instruction {
14
    Br,
15
}
16

17
#[derive(Debug)]
18
struct Patch {
19
    pub location: usize,
20
    pub instruction: Instruction,
21
}
22

23
#[derive(Debug)]
24
struct ControlFrame {
25
    pub opcode: Opcode,
26
    pub start_types: Vec<ValType>,
27
    pub end_types: Vec<ValType>,
28
    pub stack_height: usize,
29
    pub patches: Vec<Patch>,
30
}
31

32
#[derive(Debug)]
33
pub struct StackElement {
34
    pub reg: Option<Reg>,
35
    pub valtype: wasmparser::ValType,
36
    pub value: i64,
37
}
38

39
pub fn compile_function(
1✔
40
    reader: &mut wasmparser::OperatorsReader<'_>,
1✔
41
    func_type: &wasmparser::FuncType,
1✔
42
    locals: &[(u32, ValType)],
1✔
43
    machinecode: &mut Vec<u32>,
1✔
44
) -> Result<usize> {
1✔
45
    // Value stack starts empty
46
    let mut value_stack: Vec<StackElement> = vec![];
1✔
47

48
    // Control stack is initialized with the (implicit) outer func-block
49
    // let mut control_stack: Vec<ControlFrame> = vec![ControlFrame {
50
    //     opcode: Opcode::Func,
51
    //     start_types: func_type.params().to_vec(),
52
    //     end_types: func_type.results().to_vec(),
53
    //     stack_height: value_stack.len(),
54
    //     patches: vec![],
55
    // }];
56

57
    let initial_size = machinecode.len();
1✔
58
    let mut register_pool = RegisterPool::default();
1✔
59

60
    // calculate initial stack size from all parameters and locals
61
    let (_variables_size, stack_size) = get_aligned_stack_size(func_type, locals);
1✔
62
    // println!("{} {:?}", _variables_size, stack_size);
63

64
    // every functions starts with an epilogue to save the initial state and create a new stack frame
65
    emit_prologue(stack_size, &mut register_pool, machinecode);
1✔
66

67
    let mut variables: Vec<LocalVar> = vec![];
1✔
68
    let mut stack_offset = 0;
1✔
69
    // save parameters to stack
70
    if !func_type.params().is_empty() {
1✔
NEW
71
        variables.extend(save_parameters_to_stack(
×
NEW
72
            &mut stack_offset,
×
NEW
73
            func_type.params(),
×
NEW
74
            machinecode,
×
NEW
75
        ));
×
76
    }
1✔
77

78
    if !locals.is_empty() {
1✔
NEW
79
        variables.extend(save_locals_to_stack(&mut stack_offset, locals, machinecode));
×
80
    }
1✔
81

82
    // 'expression: while !reader.eof() {
83
    while !reader.eof() {
1✔
84
        let index = reader.original_position();
1✔
85
        let op = reader.read().unwrap();
1✔
86
        match op {
1✔
NEW
87
            Operator::End => {
×
NEW
88
                // if compile_end(&mut control_stack, &mut value_stack, machinecode) {
×
NEW
89
                //     break 'expression;
×
NEW
90
                // }
×
NEW
91
            }
×
NEW
92
            Operator::Return => {
×
NEW
93
                // compile_return(&mut control_stack, machinecode);
×
NEW
94
            }
×
NEW
95
            Operator::I32Const { .. } => {
×
NEW
96
                // compile_const(
×
NEW
97
                //     &op,
×
NEW
98
                //     value,
×
NEW
99
                //     &mut value_stack,
×
NEW
100
                //     &mut register_pool,
×
NEW
101
                //     machinecode,
×
NEW
102
                // );
×
NEW
103
            }
×
NEW
104
            Operator::I64Const { .. } => {
×
NEW
105
                // compile_const(
×
NEW
106
                //     &op,
×
NEW
107
                //     value,
×
NEW
108
                //     &mut value_stack,
×
NEW
109
                //     &mut register_pool,
×
NEW
110
                //     machinecode,
×
NEW
111
                // );
×
NEW
112
            }
×
NEW
113
            Operator::LocalGet { .. } => {
×
NEW
114
                // let var = variables.get(local_index as usize).unwrap();
×
NEW
115
                // compile_local_get(
×
NEW
116
                //     var,
×
NEW
117
                //     var.offset,
×
NEW
118
                //     &mut value_stack,
×
NEW
119
                //     &mut register_pool,
×
NEW
120
                //     machinecode,
×
NEW
121
                // );
×
NEW
122
            }
×
NEW
123
            Operator::LocalSet { .. } => {
×
NEW
124
                // let var = variables.get(local_index as usize).unwrap();
×
NEW
125
                // compile_local_set(
×
NEW
126
                //     var,
×
NEW
127
                //     var.offset,
×
NEW
128
                //     &mut value_stack,
×
NEW
129
                //     &mut register_pool,
×
NEW
130
                //     machinecode,
×
NEW
131
                // );
×
NEW
132
            }
×
133
            Operator::I32Add
134
            | Operator::I64Add
135
            | Operator::I32Sub
136
            | Operator::I64Sub
137
            | Operator::I32Mul
NEW
138
            | Operator::I64Mul => {
×
NEW
139
                // compile_binop(&op, &mut value_stack, &mut register_pool, machinecode);
×
NEW
140
            }
×
141
            _ => {
142
                return Err(TinyWasmError::Compiler(format!(
1✔
143
                    "unsupported instruction: {:?} at position {}",
1✔
144
                    op, index
1✔
145
                )));
1✔
146
            }
147
        }
148
    }
149

150
    // move result values to result registers according to Aarch64 Procedure Call Standard (X0..X7)
151
    // X0: Result, X1: Tag (0=Ok, 1=Trap)
NEW
152
    if !func_type.results().is_empty() {
×
NEW
153
        load_results(&mut value_stack, func_type.results().len(), machinecode)?;
×
NEW
154
    } else {
×
NEW
155
        // Result=0
×
NEW
156
        machinecode.push(processing::mov_reg(Reg::X0, Reg::XZR, RegSize::Reg64bit));
×
NEW
157
        // Tag=Ok (0)
×
NEW
158
        machinecode.push(processing::mov_reg(Reg::X1, Reg::XZR, RegSize::Reg64bit));
×
NEW
159
    }
×
160

161
    // restore initial state before returning to the caller
NEW
162
    emit_epilogue(stack_size, machinecode);
×
163

164
    // add padding to INSTRUCTION_SIZE to align subsequent functions to the correct size
NEW
165
    let padding_instructions =
×
NEW
166
        ((machinecode.len() * INSTRUCTION_SIZE) % mem::align_of::<fn()>()) / INSTRUCTION_SIZE;
×
NEW
167
    for _ in 0..padding_instructions {
×
NEW
168
        machinecode.push(hint::nop());
×
NEW
169
    }
×
170

NEW
171
    Ok(machinecode.len() - initial_size)
×
172
}
1✔
173

NEW
174
pub fn map_op_to_valtype(op: &Operator) -> ValType {
×
NEW
175
    match op {
×
176
        Operator::I32Add | Operator::I32Sub | Operator::I32Mul | Operator::I32Const { .. } => {
NEW
177
            ValType::I32
×
178
        }
179
        Operator::I64Add | Operator::I64Sub | Operator::I64Mul | Operator::I64Const { .. } => {
NEW
180
            ValType::I64
×
181
        }
NEW
182
        _ => panic!("Operator '{:?}' not supported", op),
×
183
    }
NEW
184
}
×
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