Module layout: Types: 0..num_tags tag signatures: (params) -> () num_tags..2*num_tags catch block types: () -> (params) 2*num_tags () -> (i32) (run & relay functions) 2*num_tags + 1 (i32, i32) -> () (check_i32) 2*num_tags + 2 () -> () (thrower functions) Tags: 0..num_tags (using type indices 0..nu
(&self)
| 195 | /// Functions: per-scenario call chains + "run" |
| 196 | /// Exports: "run" |
| 197 | fn encode(&self) -> Vec<u8> { |
| 198 | let num_tags = self.limits.num_tags; |
| 199 | let call_depth = self.limits.call_depth; |
| 200 | let num_scenarios = u32::try_from(self.scenarios.len()).unwrap(); |
| 201 | |
| 202 | let mut module = Module::new(); |
| 203 | |
| 204 | let mut types = TypeSection::new(); |
| 205 | |
| 206 | // Type indices 0..num_tags: tag signatures (params -> []) |
| 207 | for sig in &self.tag_sigs { |
| 208 | let params: Vec<ValType> = sig.params.iter().map(|t| t.to_val_type()).collect(); |
| 209 | types.ty().function(params, vec![]); |
| 210 | } |
| 211 | |
| 212 | // Type indices num_tags..2*num_tags: catch block types ([] -> params) |
| 213 | // These are used as block types for the catch target blocks, since |
| 214 | // `catch $tag $label` delivers the tag's param types at the label. |
| 215 | let catch_block_type_base = num_tags; |
| 216 | for sig in &self.tag_sigs { |
| 217 | let results: Vec<ValType> = sig.params.iter().map(|t| t.to_val_type()).collect(); |
| 218 | types.ty().function(vec![], results); |
| 219 | } |
| 220 | |
| 221 | // Utility function types |
| 222 | let fn_type_void_to_i32 = types.len(); |
| 223 | types.ty().function(vec![], vec![ValType::I32]); |
| 224 | |
| 225 | let fn_type_check = types.len(); |
| 226 | types |
| 227 | .ty() |
| 228 | .function(vec![ValType::I32, ValType::I32], vec![]); |
| 229 | |
| 230 | let fn_type_void_to_void = types.len(); |
| 231 | types.ty().function(vec![], vec![]); |
| 232 | |
| 233 | let mut tags = TagSection::new(); |
| 234 | for i in 0..num_tags { |
| 235 | tags.tag(TagType { |
| 236 | kind: TagKind::Exception, |
| 237 | func_type_idx: i, |
| 238 | }); |
| 239 | } |
| 240 | |
| 241 | let mut imports = ImportSection::new(); |
| 242 | let check_func_idx: u32 = 0; |
| 243 | imports.import("", "check_i32", EntityType::Function(fn_type_check)); |
| 244 | let import_count: u32 = imports.len(); |
| 245 | |
| 246 | // For each scenario: (call_depth + 1) functions at depths 0..=call_depth. |
| 247 | // - depth == catch_depth: handler function () -> (i32) |
| 248 | // - depth == throw_depth: thrower function () -> () |
| 249 | // - other depths < throw_depth: relay function () -> (i32) |
| 250 | // - other depths > throw_depth: unreachable () -> () |
| 251 | // |
| 252 | // Plus one "run" function that calls each scenario's depth-0 function. |
| 253 | |
| 254 | let funcs_per_scenario = call_depth + 1; |
no test coverage detected