numcodecs_wasm_host_reproducible/transform/
instcnt.rs1use std::sync::OnceLock;
2
3use anyhow::{Error, anyhow};
4use semver::Version;
5use wasm_component_layer::{InterfaceIdentifier, PackageIdentifier, PackageName};
6use wasm_encoder::reencode::{self, Reencode};
7
8pub enum InstructionCounterInjecter {}
9
10impl InstructionCounterInjecter {
11 pub fn apply_to_module(
12 wasm: &[u8],
13 features: wasmparser::WasmFeatures,
14 ) -> Result<Vec<u8>, anyhow::Error> {
15 let mut parser = wasmparser::Parser::new(0);
16 parser.set_features(features);
17
18 let mut module = wasm_encoder::Module::new();
19
20 let mut reencoder = InstructionCounterInjecterReencoder {
21 instruction_counter_global: None,
22 num_imported_funcs: 0,
23 instruction_counter_func_index: None,
24 func_index: 0,
25 };
26 reencoder
27 .parse_core_module(&mut module, parser, wasm)
28 .map_err(|err| anyhow::format_err!("{}", err))?;
29
30 if let Some(instruction_counter_func_index) = reencoder.instruction_counter_func_index {
31 anyhow::ensure!(
32 reencoder.func_index > instruction_counter_func_index,
33 "missing WASM instruction counter reader function body"
34 );
35 }
36
37 let wasm = module.finish();
38 wasmparser::Validator::new_with_features(features).validate_all(&wasm)?;
39 Ok(wasm)
40 }
41}
42
43struct InstructionCounterInjecterReencoder {
44 instruction_counter_global: Option<u32>,
45 num_imported_funcs: u32,
46 instruction_counter_func_index: Option<u32>,
47 func_index: u32,
48}
49
50impl wasm_encoder::reencode::Reencode for InstructionCounterInjecterReencoder {
51 type Error = Error;
52
53 fn global_index(&mut self, global: u32) -> Result<u32, reencode::Error<Self::Error>> {
54 match self.instruction_counter_global {
55 Some(instruction_counter_global) if global >= instruction_counter_global => {
56 Ok(global + 1)
57 }
58 _ => Ok(global),
59 }
60 }
61
62 fn parse_import_section(
63 &mut self,
64 imports: &mut wasm_encoder::ImportSection,
65 section: wasmparser::ImportSectionReader<'_>,
66 ) -> Result<(), reencode::Error<Self::Error>> {
67 self.instruction_counter_global.get_or_insert(0);
68 for import in section {
69 let import = import?;
70 match import.ty {
71 wasmparser::TypeRef::Func(_) => self.num_imported_funcs += 1,
72 wasmparser::TypeRef::Global(_) => {
73 *self.instruction_counter_global.get_or_insert(0) += 1;
74 }
75 wasmparser::TypeRef::Table(_)
76 | wasmparser::TypeRef::Memory(_)
77 | wasmparser::TypeRef::Tag(_) => (),
78 }
79 self.parse_import(imports, import)?;
80 }
81 Self::inject_instruction_counter_import(imports);
82 Ok(())
83 }
84
85 fn intersperse_section_hook(
86 &mut self,
87 module: &mut wasm_encoder::Module,
88 _after: Option<wasm_encoder::SectionId>,
89 before: Option<wasm_encoder::SectionId>,
90 ) -> Result<(), reencode::Error<Self::Error>> {
91 let Some(wasm_encoder::SectionId::Function) = before else {
95 return Ok(());
96 };
97
98 if self.instruction_counter_global.is_none() {
99 self.instruction_counter_global = Some(0);
100
101 let mut imports = wasm_encoder::ImportSection::new();
102 Self::inject_instruction_counter_import(&mut imports);
103 module.section(&imports);
104 }
105
106 Ok(())
107 }
108
109 fn parse_export_section(
110 &mut self,
111 exports: &mut wasm_encoder::ExportSection,
112 section: wasmparser::ExportSectionReader<'_>,
113 ) -> Result<(), reencode::Error<Self::Error>> {
114 let instruction_counter_export_name = {
115 let PerfWitInterfaces {
116 perf: perf_interface,
117 instruction_counter,
118 ..
119 } = PerfWitInterfaces::get();
120
121 format!("{perf_interface}#{instruction_counter}")
122 };
123
124 for export in section {
125 let export = export?;
126 if export.name == instruction_counter_export_name {
127 if !matches!(export.kind, wasmparser::ExternalKind::Func) {
128 return Err(reencode::Error::UserError(anyhow!(
129 "instruction counter reader export must be a function",
130 )));
131 }
132 if self.instruction_counter_func_index.is_some() {
133 return Err(reencode::Error::UserError(anyhow!(
134 "duplicate instruction counter reader export",
135 )));
136 }
137 self.instruction_counter_func_index = Some(export.index - self.num_imported_funcs);
138 }
139
140 self.parse_export(exports, export)?;
141 }
142 Ok(())
143 }
144
145 fn parse_function_body(
146 &mut self,
147 code: &mut wasm_encoder::CodeSection,
148 func: wasmparser::FunctionBody<'_>,
149 ) -> Result<(), reencode::Error<Self::Error>> {
150 let Some(instruction_counter_global) = self.instruction_counter_global else {
151 return Err(reencode::Error::UserError(anyhow!(
152 "missing instruction counter import",
153 )));
154 };
155
156 let mut function = self.new_function_with_parsed_locals(&func)?;
157 let instructions = func.get_operators_reader()?;
158
159 if Some(self.func_index) == self.instruction_counter_func_index {
160 let locals = func.get_locals_reader()?;
161
162 if locals.get_count() > 0 {
163 return Err(reencode::Error::UserError(anyhow!(
164 "instruction counter function has no locals",
165 )));
166 }
167 let instructions = instructions.into_iter().collect::<Result<Vec<_>, _>>()?;
168 if !matches!(
169 instructions.as_slice(),
170 [wasmparser::Operator::Unreachable, wasmparser::Operator::End]
171 ) {
172 return Err(reencode::Error::UserError(anyhow!(
173 "instruction counter function has a single instruction and is unreachable",
174 )));
175 }
176
177 function.instruction(&wasm_encoder::Instruction::GlobalGet(
178 instruction_counter_global,
179 ));
180 function.instruction(&wasm_encoder::Instruction::Return);
181 function.instruction(&wasm_encoder::Instruction::End);
182 } else {
183 let mut counter: i64 = 0;
184
185 for instruction in instructions {
186 let instruction = instruction?;
187
188 if let Some(update) = Self::instruction_needs_counter_update(&instruction) {
189 counter += 1;
190
191 if update {
192 for count_instruction in Self::generate_instruction_counter_update(
193 instruction_counter_global,
194 counter,
195 ) {
196 function.instruction(&count_instruction);
197 }
198 }
199
200 counter = 0;
201 }
202
203 function.instruction(&self.instruction(instruction)?);
204 }
205 }
206 code.function(&function);
207 self.func_index += 1;
208 Ok(())
209 }
210}
211
212impl InstructionCounterInjecterReencoder {
213 fn inject_instruction_counter_import(imports: &mut wasm_encoder::ImportSection) {
214 let PerfWitInterfaces {
215 perf: perf_interface,
216 instruction_counter,
217 } = PerfWitInterfaces::get();
218
219 imports.import(
220 &format!("{perf_interface}"),
221 instruction_counter,
222 wasm_encoder::EntityType::Global(wasm_encoder::GlobalType {
223 val_type: wasm_encoder::ValType::I64,
224 mutable: true,
225 shared: false,
226 }),
227 );
228 }
229
230 const fn generate_instruction_counter_update(
231 instruction_counter_global: u32,
232 delta: i64,
233 ) -> impl IntoIterator<Item = wasm_encoder::Instruction<'static>> {
234 [
235 wasm_encoder::Instruction::GlobalGet(instruction_counter_global),
236 wasm_encoder::Instruction::I64Const(delta),
237 wasm_encoder::Instruction::I64Add,
238 wasm_encoder::Instruction::GlobalSet(instruction_counter_global),
239 ]
240 }
241
242 #[expect(clippy::too_many_lines)]
243 fn instruction_needs_counter_update(instr: &wasmparser::Operator) -> Option<bool> {
244 match instr {
245 wasmparser::Operator::Unreachable => Some(false),
249 wasmparser::Operator::Nop => None,
251 wasmparser::Operator::Block { .. }
254 | wasmparser::Operator::Loop { .. }
255 | wasmparser::Operator::If { .. }
256 | wasmparser::Operator::Else => Some(true),
257 wasmparser::Operator::TryTable { .. } => Some(true),
261 wasmparser::Operator::Throw { .. } | wasmparser::Operator::ThrowRef => Some(true),
263 wasmparser::Operator::Try { .. } => Some(true),
267 wasmparser::Operator::Catch { .. }
269 | wasmparser::Operator::Rethrow { .. }
270 | wasmparser::Operator::Delegate { .. }
271 | wasmparser::Operator::CatchAll => Some(true),
272 wasmparser::Operator::End => Some(true),
275 wasmparser::Operator::Br { .. }
277 | wasmparser::Operator::BrIf { .. }
278 | wasmparser::Operator::BrTable { .. } => Some(true),
279 wasmparser::Operator::Return => Some(true),
281 wasmparser::Operator::Call { .. } | wasmparser::Operator::CallIndirect { .. } => {
284 Some(false)
285 }
286 wasmparser::Operator::ReturnCall { .. }
289 | wasmparser::Operator::ReturnCallIndirect { .. } => Some(true),
290 wasmparser::Operator::Drop | wasmparser::Operator::Select => Some(false),
293 wasmparser::Operator::TypedSelect { .. } => Some(false),
296 wasmparser::Operator::LocalGet { .. }
299 | wasmparser::Operator::LocalSet { .. }
300 | wasmparser::Operator::LocalTee { .. }
301 | wasmparser::Operator::GlobalGet { .. }
302 | wasmparser::Operator::GlobalSet { .. }
303 | wasmparser::Operator::I32Load { .. }
304 | wasmparser::Operator::I64Load { .. }
305 | wasmparser::Operator::F32Load { .. }
306 | wasmparser::Operator::F64Load { .. }
307 | wasmparser::Operator::I32Load8S { .. }
308 | wasmparser::Operator::I32Load8U { .. }
309 | wasmparser::Operator::I32Load16S { .. }
310 | wasmparser::Operator::I32Load16U { .. }
311 | wasmparser::Operator::I64Load8S { .. }
312 | wasmparser::Operator::I64Load8U { .. }
313 | wasmparser::Operator::I64Load16S { .. }
314 | wasmparser::Operator::I64Load16U { .. }
315 | wasmparser::Operator::I64Load32S { .. }
316 | wasmparser::Operator::I64Load32U { .. }
317 | wasmparser::Operator::I32Store { .. }
318 | wasmparser::Operator::I64Store { .. }
319 | wasmparser::Operator::F32Store { .. }
320 | wasmparser::Operator::F64Store { .. }
321 | wasmparser::Operator::I32Store8 { .. }
322 | wasmparser::Operator::I32Store16 { .. }
323 | wasmparser::Operator::I64Store8 { .. }
324 | wasmparser::Operator::I64Store16 { .. }
325 | wasmparser::Operator::I64Store32 { .. }
326 | wasmparser::Operator::MemorySize { .. }
327 | wasmparser::Operator::MemoryGrow { .. }
328 | wasmparser::Operator::I32Const { .. }
329 | wasmparser::Operator::I64Const { .. }
330 | wasmparser::Operator::F32Const { .. }
331 | wasmparser::Operator::F64Const { .. } => Some(false),
332 wasmparser::Operator::RefNull { .. }
335 | wasmparser::Operator::RefIsNull
336 | wasmparser::Operator::RefFunc { .. } => Some(false),
337 wasmparser::Operator::RefEq => Some(false),
340 wasmparser::Operator::I32Eqz
343 | wasmparser::Operator::I32Eq
344 | wasmparser::Operator::I32Ne
345 | wasmparser::Operator::I32LtS
346 | wasmparser::Operator::I32LtU
347 | wasmparser::Operator::I32GtS
348 | wasmparser::Operator::I32GtU
349 | wasmparser::Operator::I32LeS
350 | wasmparser::Operator::I32LeU
351 | wasmparser::Operator::I32GeS
352 | wasmparser::Operator::I32GeU
353 | wasmparser::Operator::I64Eqz
354 | wasmparser::Operator::I64Eq
355 | wasmparser::Operator::I64Ne
356 | wasmparser::Operator::I64LtS
357 | wasmparser::Operator::I64LtU
358 | wasmparser::Operator::I64GtS
359 | wasmparser::Operator::I64GtU
360 | wasmparser::Operator::I64LeS
361 | wasmparser::Operator::I64LeU
362 | wasmparser::Operator::I64GeS
363 | wasmparser::Operator::I64GeU
364 | wasmparser::Operator::F32Eq
365 | wasmparser::Operator::F32Ne
366 | wasmparser::Operator::F32Lt
367 | wasmparser::Operator::F32Gt
368 | wasmparser::Operator::F32Le
369 | wasmparser::Operator::F32Ge
370 | wasmparser::Operator::F64Eq
371 | wasmparser::Operator::F64Ne
372 | wasmparser::Operator::F64Lt
373 | wasmparser::Operator::F64Gt
374 | wasmparser::Operator::F64Le
375 | wasmparser::Operator::F64Ge
376 | wasmparser::Operator::I32Clz
377 | wasmparser::Operator::I32Ctz
378 | wasmparser::Operator::I32Popcnt
379 | wasmparser::Operator::I32Add
380 | wasmparser::Operator::I32Sub
381 | wasmparser::Operator::I32Mul
382 | wasmparser::Operator::I32DivS
383 | wasmparser::Operator::I32DivU
384 | wasmparser::Operator::I32RemS
385 | wasmparser::Operator::I32RemU
386 | wasmparser::Operator::I32And
387 | wasmparser::Operator::I32Or
388 | wasmparser::Operator::I32Xor
389 | wasmparser::Operator::I32Shl
390 | wasmparser::Operator::I32ShrS
391 | wasmparser::Operator::I32ShrU
392 | wasmparser::Operator::I32Rotl
393 | wasmparser::Operator::I32Rotr
394 | wasmparser::Operator::I64Clz
395 | wasmparser::Operator::I64Ctz
396 | wasmparser::Operator::I64Popcnt
397 | wasmparser::Operator::I64Add
398 | wasmparser::Operator::I64Sub
399 | wasmparser::Operator::I64Mul
400 | wasmparser::Operator::I64DivS
401 | wasmparser::Operator::I64DivU
402 | wasmparser::Operator::I64RemS
403 | wasmparser::Operator::I64RemU
404 | wasmparser::Operator::I64And
405 | wasmparser::Operator::I64Or
406 | wasmparser::Operator::I64Xor
407 | wasmparser::Operator::I64Shl
408 | wasmparser::Operator::I64ShrS
409 | wasmparser::Operator::I64ShrU
410 | wasmparser::Operator::I64Rotl
411 | wasmparser::Operator::I64Rotr
412 | wasmparser::Operator::F32Abs
413 | wasmparser::Operator::F32Neg
414 | wasmparser::Operator::F32Ceil
415 | wasmparser::Operator::F32Floor
416 | wasmparser::Operator::F32Trunc
417 | wasmparser::Operator::F32Nearest
418 | wasmparser::Operator::F32Sqrt
419 | wasmparser::Operator::F32Add
420 | wasmparser::Operator::F32Sub
421 | wasmparser::Operator::F32Mul
422 | wasmparser::Operator::F32Div
423 | wasmparser::Operator::F32Min
424 | wasmparser::Operator::F32Max
425 | wasmparser::Operator::F32Copysign
426 | wasmparser::Operator::F64Abs
427 | wasmparser::Operator::F64Neg
428 | wasmparser::Operator::F64Ceil
429 | wasmparser::Operator::F64Floor
430 | wasmparser::Operator::F64Trunc
431 | wasmparser::Operator::F64Nearest
432 | wasmparser::Operator::F64Sqrt
433 | wasmparser::Operator::F64Add
434 | wasmparser::Operator::F64Sub
435 | wasmparser::Operator::F64Mul
436 | wasmparser::Operator::F64Div
437 | wasmparser::Operator::F64Min
438 | wasmparser::Operator::F64Max
439 | wasmparser::Operator::F64Copysign
440 | wasmparser::Operator::I32WrapI64
441 | wasmparser::Operator::I32TruncF32S
442 | wasmparser::Operator::I32TruncF32U
443 | wasmparser::Operator::I32TruncF64S
444 | wasmparser::Operator::I32TruncF64U
445 | wasmparser::Operator::I64ExtendI32S
446 | wasmparser::Operator::I64ExtendI32U
447 | wasmparser::Operator::I64TruncF32S
448 | wasmparser::Operator::I64TruncF32U
449 | wasmparser::Operator::I64TruncF64S
450 | wasmparser::Operator::I64TruncF64U
451 | wasmparser::Operator::F32ConvertI32S
452 | wasmparser::Operator::F32ConvertI32U
453 | wasmparser::Operator::F32ConvertI64S
454 | wasmparser::Operator::F32ConvertI64U
455 | wasmparser::Operator::F32DemoteF64
456 | wasmparser::Operator::F64ConvertI32S
457 | wasmparser::Operator::F64ConvertI32U
458 | wasmparser::Operator::F64ConvertI64S
459 | wasmparser::Operator::F64ConvertI64U
460 | wasmparser::Operator::F64PromoteF32
461 | wasmparser::Operator::I32ReinterpretF32
462 | wasmparser::Operator::I64ReinterpretF64
463 | wasmparser::Operator::F32ReinterpretI32
464 | wasmparser::Operator::F64ReinterpretI64 => Some(false),
465 wasmparser::Operator::I32Extend8S
468 | wasmparser::Operator::I32Extend16S
469 | wasmparser::Operator::I64Extend8S
470 | wasmparser::Operator::I64Extend16S
471 | wasmparser::Operator::I64Extend32S => Some(false),
472 wasmparser::Operator::StructNew { .. }
475 | wasmparser::Operator::StructNewDefault { .. }
476 | wasmparser::Operator::StructGet { .. }
477 | wasmparser::Operator::StructGetS { .. }
478 | wasmparser::Operator::StructGetU { .. }
479 | wasmparser::Operator::StructSet { .. }
480 | wasmparser::Operator::ArrayNew { .. }
481 | wasmparser::Operator::ArrayNewDefault { .. }
482 | wasmparser::Operator::ArrayNewFixed { .. }
483 | wasmparser::Operator::ArrayNewData { .. }
484 | wasmparser::Operator::ArrayNewElem { .. }
485 | wasmparser::Operator::ArrayGet { .. }
486 | wasmparser::Operator::ArrayGetS { .. }
487 | wasmparser::Operator::ArrayGetU { .. }
488 | wasmparser::Operator::ArraySet { .. }
489 | wasmparser::Operator::ArrayLen
490 | wasmparser::Operator::ArrayFill { .. }
491 | wasmparser::Operator::ArrayCopy { .. }
492 | wasmparser::Operator::ArrayInitData { .. }
493 | wasmparser::Operator::ArrayInitElem { .. } => Some(false),
494 wasmparser::Operator::RefTestNonNull { .. }
496 | wasmparser::Operator::RefTestNullable { .. } => Some(false),
497 wasmparser::Operator::RefCastNonNull { .. }
499 | wasmparser::Operator::RefCastNullable { .. } => Some(false),
500 wasmparser::Operator::BrOnCast { .. } | wasmparser::Operator::BrOnCastFail { .. } => {
502 Some(true)
503 }
504 wasmparser::Operator::AnyConvertExtern
506 | wasmparser::Operator::ExternConvertAny
507 | wasmparser::Operator::RefI31
508 | wasmparser::Operator::I31GetS
509 | wasmparser::Operator::I31GetU => Some(false),
510 wasmparser::Operator::I32TruncSatF32S
513 | wasmparser::Operator::I32TruncSatF32U
514 | wasmparser::Operator::I32TruncSatF64S
515 | wasmparser::Operator::I32TruncSatF64U
516 | wasmparser::Operator::I64TruncSatF32S
517 | wasmparser::Operator::I64TruncSatF32U
518 | wasmparser::Operator::I64TruncSatF64S
519 | wasmparser::Operator::I64TruncSatF64U => Some(false),
520 wasmparser::Operator::MemoryInit { .. }
523 | wasmparser::Operator::DataDrop { .. }
524 | wasmparser::Operator::MemoryCopy { .. }
525 | wasmparser::Operator::MemoryFill { .. }
526 | wasmparser::Operator::TableInit { .. }
527 | wasmparser::Operator::ElemDrop { .. }
528 | wasmparser::Operator::TableCopy { .. } => Some(false),
529 wasmparser::Operator::TableFill { .. }
532 | wasmparser::Operator::TableGet { .. }
533 | wasmparser::Operator::TableSet { .. }
534 | wasmparser::Operator::TableGrow { .. }
535 | wasmparser::Operator::TableSize { .. } => Some(false),
536 wasmparser::Operator::MemoryDiscard { .. } => Some(false),
539 wasmparser::Operator::MemoryAtomicNotify { .. }
542 | wasmparser::Operator::MemoryAtomicWait32 { .. }
543 | wasmparser::Operator::MemoryAtomicWait64 { .. }
544 | wasmparser::Operator::AtomicFence
545 | wasmparser::Operator::I32AtomicLoad { .. }
546 | wasmparser::Operator::I64AtomicLoad { .. }
547 | wasmparser::Operator::I32AtomicLoad8U { .. }
548 | wasmparser::Operator::I32AtomicLoad16U { .. }
549 | wasmparser::Operator::I64AtomicLoad8U { .. }
550 | wasmparser::Operator::I64AtomicLoad16U { .. }
551 | wasmparser::Operator::I64AtomicLoad32U { .. }
552 | wasmparser::Operator::I32AtomicStore { .. }
553 | wasmparser::Operator::I64AtomicStore { .. }
554 | wasmparser::Operator::I32AtomicStore8 { .. }
555 | wasmparser::Operator::I32AtomicStore16 { .. }
556 | wasmparser::Operator::I64AtomicStore8 { .. }
557 | wasmparser::Operator::I64AtomicStore16 { .. }
558 | wasmparser::Operator::I64AtomicStore32 { .. }
559 | wasmparser::Operator::I32AtomicRmwAdd { .. }
560 | wasmparser::Operator::I64AtomicRmwAdd { .. }
561 | wasmparser::Operator::I32AtomicRmw8AddU { .. }
562 | wasmparser::Operator::I32AtomicRmw16AddU { .. }
563 | wasmparser::Operator::I64AtomicRmw8AddU { .. }
564 | wasmparser::Operator::I64AtomicRmw16AddU { .. }
565 | wasmparser::Operator::I64AtomicRmw32AddU { .. }
566 | wasmparser::Operator::I32AtomicRmwSub { .. }
567 | wasmparser::Operator::I64AtomicRmwSub { .. }
568 | wasmparser::Operator::I32AtomicRmw8SubU { .. }
569 | wasmparser::Operator::I32AtomicRmw16SubU { .. }
570 | wasmparser::Operator::I64AtomicRmw8SubU { .. }
571 | wasmparser::Operator::I64AtomicRmw16SubU { .. }
572 | wasmparser::Operator::I64AtomicRmw32SubU { .. }
573 | wasmparser::Operator::I32AtomicRmwAnd { .. }
574 | wasmparser::Operator::I64AtomicRmwAnd { .. }
575 | wasmparser::Operator::I32AtomicRmw8AndU { .. }
576 | wasmparser::Operator::I32AtomicRmw16AndU { .. }
577 | wasmparser::Operator::I64AtomicRmw8AndU { .. }
578 | wasmparser::Operator::I64AtomicRmw16AndU { .. }
579 | wasmparser::Operator::I64AtomicRmw32AndU { .. }
580 | wasmparser::Operator::I32AtomicRmwOr { .. }
581 | wasmparser::Operator::I64AtomicRmwOr { .. }
582 | wasmparser::Operator::I32AtomicRmw8OrU { .. }
583 | wasmparser::Operator::I32AtomicRmw16OrU { .. }
584 | wasmparser::Operator::I64AtomicRmw8OrU { .. }
585 | wasmparser::Operator::I64AtomicRmw16OrU { .. }
586 | wasmparser::Operator::I64AtomicRmw32OrU { .. }
587 | wasmparser::Operator::I32AtomicRmwXor { .. }
588 | wasmparser::Operator::I64AtomicRmwXor { .. }
589 | wasmparser::Operator::I32AtomicRmw8XorU { .. }
590 | wasmparser::Operator::I32AtomicRmw16XorU { .. }
591 | wasmparser::Operator::I64AtomicRmw8XorU { .. }
592 | wasmparser::Operator::I64AtomicRmw16XorU { .. }
593 | wasmparser::Operator::I64AtomicRmw32XorU { .. }
594 | wasmparser::Operator::I32AtomicRmwXchg { .. }
595 | wasmparser::Operator::I64AtomicRmwXchg { .. }
596 | wasmparser::Operator::I32AtomicRmw8XchgU { .. }
597 | wasmparser::Operator::I32AtomicRmw16XchgU { .. }
598 | wasmparser::Operator::I64AtomicRmw8XchgU { .. }
599 | wasmparser::Operator::I64AtomicRmw16XchgU { .. }
600 | wasmparser::Operator::I64AtomicRmw32XchgU { .. }
601 | wasmparser::Operator::I32AtomicRmwCmpxchg { .. }
602 | wasmparser::Operator::I64AtomicRmwCmpxchg { .. }
603 | wasmparser::Operator::I32AtomicRmw8CmpxchgU { .. }
604 | wasmparser::Operator::I32AtomicRmw16CmpxchgU { .. }
605 | wasmparser::Operator::I64AtomicRmw8CmpxchgU { .. }
606 | wasmparser::Operator::I64AtomicRmw16CmpxchgU { .. }
607 | wasmparser::Operator::I64AtomicRmw32CmpxchgU { .. } => Some(false),
608 wasmparser::Operator::GlobalAtomicGet { .. }
611 | wasmparser::Operator::GlobalAtomicSet { .. }
612 | wasmparser::Operator::GlobalAtomicRmwAdd { .. }
613 | wasmparser::Operator::GlobalAtomicRmwSub { .. }
614 | wasmparser::Operator::GlobalAtomicRmwAnd { .. }
615 | wasmparser::Operator::GlobalAtomicRmwOr { .. }
616 | wasmparser::Operator::GlobalAtomicRmwXor { .. }
617 | wasmparser::Operator::GlobalAtomicRmwXchg { .. }
618 | wasmparser::Operator::GlobalAtomicRmwCmpxchg { .. }
619 | wasmparser::Operator::TableAtomicGet { .. }
620 | wasmparser::Operator::TableAtomicSet { .. }
621 | wasmparser::Operator::TableAtomicRmwXchg { .. }
622 | wasmparser::Operator::TableAtomicRmwCmpxchg { .. }
623 | wasmparser::Operator::StructAtomicGet { .. }
624 | wasmparser::Operator::StructAtomicGetS { .. }
625 | wasmparser::Operator::StructAtomicGetU { .. }
626 | wasmparser::Operator::StructAtomicSet { .. }
627 | wasmparser::Operator::StructAtomicRmwAdd { .. }
628 | wasmparser::Operator::StructAtomicRmwSub { .. }
629 | wasmparser::Operator::StructAtomicRmwAnd { .. }
630 | wasmparser::Operator::StructAtomicRmwOr { .. }
631 | wasmparser::Operator::StructAtomicRmwXor { .. }
632 | wasmparser::Operator::StructAtomicRmwXchg { .. }
633 | wasmparser::Operator::StructAtomicRmwCmpxchg { .. }
634 | wasmparser::Operator::ArrayAtomicGet { .. }
635 | wasmparser::Operator::ArrayAtomicGetS { .. }
636 | wasmparser::Operator::ArrayAtomicGetU { .. }
637 | wasmparser::Operator::ArrayAtomicSet { .. }
638 | wasmparser::Operator::ArrayAtomicRmwAdd { .. }
639 | wasmparser::Operator::ArrayAtomicRmwSub { .. }
640 | wasmparser::Operator::ArrayAtomicRmwAnd { .. }
641 | wasmparser::Operator::ArrayAtomicRmwOr { .. }
642 | wasmparser::Operator::ArrayAtomicRmwXor { .. }
643 | wasmparser::Operator::ArrayAtomicRmwXchg { .. }
644 | wasmparser::Operator::ArrayAtomicRmwCmpxchg { .. }
645 | wasmparser::Operator::RefI31Shared => Some(false),
646 wasmparser::Operator::V128Load { .. }
649 | wasmparser::Operator::V128Load8x8S { .. }
650 | wasmparser::Operator::V128Load8x8U { .. }
651 | wasmparser::Operator::V128Load16x4S { .. }
652 | wasmparser::Operator::V128Load16x4U { .. }
653 | wasmparser::Operator::V128Load32x2S { .. }
654 | wasmparser::Operator::V128Load32x2U { .. }
655 | wasmparser::Operator::V128Load8Splat { .. }
656 | wasmparser::Operator::V128Load16Splat { .. }
657 | wasmparser::Operator::V128Load32Splat { .. }
658 | wasmparser::Operator::V128Load64Splat { .. }
659 | wasmparser::Operator::V128Load32Zero { .. }
660 | wasmparser::Operator::V128Load64Zero { .. }
661 | wasmparser::Operator::V128Store { .. }
662 | wasmparser::Operator::V128Load8Lane { .. }
663 | wasmparser::Operator::V128Load16Lane { .. }
664 | wasmparser::Operator::V128Load32Lane { .. }
665 | wasmparser::Operator::V128Load64Lane { .. }
666 | wasmparser::Operator::V128Store8Lane { .. }
667 | wasmparser::Operator::V128Store16Lane { .. }
668 | wasmparser::Operator::V128Store32Lane { .. }
669 | wasmparser::Operator::V128Store64Lane { .. }
670 | wasmparser::Operator::V128Const { .. }
671 | wasmparser::Operator::I8x16Shuffle { .. }
672 | wasmparser::Operator::I8x16ExtractLaneS { .. }
673 | wasmparser::Operator::I8x16ExtractLaneU { .. }
674 | wasmparser::Operator::I8x16ReplaceLane { .. }
675 | wasmparser::Operator::I16x8ExtractLaneS { .. }
676 | wasmparser::Operator::I16x8ExtractLaneU { .. }
677 | wasmparser::Operator::I16x8ReplaceLane { .. }
678 | wasmparser::Operator::I32x4ExtractLane { .. }
679 | wasmparser::Operator::I32x4ReplaceLane { .. }
680 | wasmparser::Operator::I64x2ExtractLane { .. }
681 | wasmparser::Operator::I64x2ReplaceLane { .. }
682 | wasmparser::Operator::F32x4ExtractLane { .. }
683 | wasmparser::Operator::F32x4ReplaceLane { .. }
684 | wasmparser::Operator::F64x2ExtractLane { .. }
685 | wasmparser::Operator::F64x2ReplaceLane { .. }
686 | wasmparser::Operator::I8x16Swizzle
687 | wasmparser::Operator::I8x16Splat
688 | wasmparser::Operator::I16x8Splat
689 | wasmparser::Operator::I32x4Splat
690 | wasmparser::Operator::I64x2Splat
691 | wasmparser::Operator::F32x4Splat
692 | wasmparser::Operator::F64x2Splat
693 | wasmparser::Operator::I8x16Eq
694 | wasmparser::Operator::I8x16Ne
695 | wasmparser::Operator::I8x16LtS
696 | wasmparser::Operator::I8x16LtU
697 | wasmparser::Operator::I8x16GtS
698 | wasmparser::Operator::I8x16GtU
699 | wasmparser::Operator::I8x16LeS
700 | wasmparser::Operator::I8x16LeU
701 | wasmparser::Operator::I8x16GeS
702 | wasmparser::Operator::I8x16GeU
703 | wasmparser::Operator::I16x8Eq
704 | wasmparser::Operator::I16x8Ne
705 | wasmparser::Operator::I16x8LtS
706 | wasmparser::Operator::I16x8LtU
707 | wasmparser::Operator::I16x8GtS
708 | wasmparser::Operator::I16x8GtU
709 | wasmparser::Operator::I16x8LeS
710 | wasmparser::Operator::I16x8LeU
711 | wasmparser::Operator::I16x8GeS
712 | wasmparser::Operator::I16x8GeU
713 | wasmparser::Operator::I32x4Eq
714 | wasmparser::Operator::I32x4Ne
715 | wasmparser::Operator::I32x4LtS
716 | wasmparser::Operator::I32x4LtU
717 | wasmparser::Operator::I32x4GtS
718 | wasmparser::Operator::I32x4GtU
719 | wasmparser::Operator::I32x4LeS
720 | wasmparser::Operator::I32x4LeU
721 | wasmparser::Operator::I32x4GeS
722 | wasmparser::Operator::I32x4GeU
723 | wasmparser::Operator::I64x2Eq
724 | wasmparser::Operator::I64x2Ne
725 | wasmparser::Operator::I64x2LtS
726 | wasmparser::Operator::I64x2GtS
727 | wasmparser::Operator::I64x2LeS
728 | wasmparser::Operator::I64x2GeS
729 | wasmparser::Operator::F32x4Eq
730 | wasmparser::Operator::F32x4Ne
731 | wasmparser::Operator::F32x4Lt
732 | wasmparser::Operator::F32x4Gt
733 | wasmparser::Operator::F32x4Le
734 | wasmparser::Operator::F32x4Ge
735 | wasmparser::Operator::F64x2Eq
736 | wasmparser::Operator::F64x2Ne
737 | wasmparser::Operator::F64x2Lt
738 | wasmparser::Operator::F64x2Gt
739 | wasmparser::Operator::F64x2Le
740 | wasmparser::Operator::F64x2Ge
741 | wasmparser::Operator::V128Not
742 | wasmparser::Operator::V128And
743 | wasmparser::Operator::V128AndNot
744 | wasmparser::Operator::V128Or
745 | wasmparser::Operator::V128Xor
746 | wasmparser::Operator::V128Bitselect
747 | wasmparser::Operator::V128AnyTrue
748 | wasmparser::Operator::I8x16Abs
749 | wasmparser::Operator::I8x16Neg
750 | wasmparser::Operator::I8x16Popcnt
751 | wasmparser::Operator::I8x16AllTrue
752 | wasmparser::Operator::I8x16Bitmask
753 | wasmparser::Operator::I8x16NarrowI16x8S
754 | wasmparser::Operator::I8x16NarrowI16x8U
755 | wasmparser::Operator::I8x16Shl
756 | wasmparser::Operator::I8x16ShrS
757 | wasmparser::Operator::I8x16ShrU
758 | wasmparser::Operator::I8x16Add
759 | wasmparser::Operator::I8x16AddSatS
760 | wasmparser::Operator::I8x16AddSatU
761 | wasmparser::Operator::I8x16Sub
762 | wasmparser::Operator::I8x16SubSatS
763 | wasmparser::Operator::I8x16SubSatU
764 | wasmparser::Operator::I8x16MinS
765 | wasmparser::Operator::I8x16MinU
766 | wasmparser::Operator::I8x16MaxS
767 | wasmparser::Operator::I8x16MaxU
768 | wasmparser::Operator::I8x16AvgrU
769 | wasmparser::Operator::I16x8ExtAddPairwiseI8x16S
770 | wasmparser::Operator::I16x8ExtAddPairwiseI8x16U
771 | wasmparser::Operator::I16x8Abs
772 | wasmparser::Operator::I16x8Neg
773 | wasmparser::Operator::I16x8Q15MulrSatS
774 | wasmparser::Operator::I16x8AllTrue
775 | wasmparser::Operator::I16x8Bitmask
776 | wasmparser::Operator::I16x8NarrowI32x4S
777 | wasmparser::Operator::I16x8NarrowI32x4U
778 | wasmparser::Operator::I16x8ExtendLowI8x16S
779 | wasmparser::Operator::I16x8ExtendHighI8x16S
780 | wasmparser::Operator::I16x8ExtendLowI8x16U
781 | wasmparser::Operator::I16x8ExtendHighI8x16U
782 | wasmparser::Operator::I16x8Shl
783 | wasmparser::Operator::I16x8ShrS
784 | wasmparser::Operator::I16x8ShrU
785 | wasmparser::Operator::I16x8Add
786 | wasmparser::Operator::I16x8AddSatS
787 | wasmparser::Operator::I16x8AddSatU
788 | wasmparser::Operator::I16x8Sub
789 | wasmparser::Operator::I16x8SubSatS
790 | wasmparser::Operator::I16x8SubSatU
791 | wasmparser::Operator::I16x8Mul
792 | wasmparser::Operator::I16x8MinS
793 | wasmparser::Operator::I16x8MinU
794 | wasmparser::Operator::I16x8MaxS
795 | wasmparser::Operator::I16x8MaxU
796 | wasmparser::Operator::I16x8AvgrU
797 | wasmparser::Operator::I16x8ExtMulLowI8x16S
798 | wasmparser::Operator::I16x8ExtMulHighI8x16S
799 | wasmparser::Operator::I16x8ExtMulLowI8x16U
800 | wasmparser::Operator::I16x8ExtMulHighI8x16U
801 | wasmparser::Operator::I32x4ExtAddPairwiseI16x8S
802 | wasmparser::Operator::I32x4ExtAddPairwiseI16x8U
803 | wasmparser::Operator::I32x4Abs
804 | wasmparser::Operator::I32x4Neg
805 | wasmparser::Operator::I32x4AllTrue
806 | wasmparser::Operator::I32x4Bitmask
807 | wasmparser::Operator::I32x4ExtendLowI16x8S
808 | wasmparser::Operator::I32x4ExtendHighI16x8S
809 | wasmparser::Operator::I32x4ExtendLowI16x8U
810 | wasmparser::Operator::I32x4ExtendHighI16x8U
811 | wasmparser::Operator::I32x4Shl
812 | wasmparser::Operator::I32x4ShrS
813 | wasmparser::Operator::I32x4ShrU
814 | wasmparser::Operator::I32x4Add
815 | wasmparser::Operator::I32x4Sub
816 | wasmparser::Operator::I32x4Mul
817 | wasmparser::Operator::I32x4MinS
818 | wasmparser::Operator::I32x4MinU
819 | wasmparser::Operator::I32x4MaxS
820 | wasmparser::Operator::I32x4MaxU
821 | wasmparser::Operator::I32x4DotI16x8S
822 | wasmparser::Operator::I32x4ExtMulLowI16x8S
823 | wasmparser::Operator::I32x4ExtMulHighI16x8S
824 | wasmparser::Operator::I32x4ExtMulLowI16x8U
825 | wasmparser::Operator::I32x4ExtMulHighI16x8U
826 | wasmparser::Operator::I64x2Abs
827 | wasmparser::Operator::I64x2Neg
828 | wasmparser::Operator::I64x2AllTrue
829 | wasmparser::Operator::I64x2Bitmask
830 | wasmparser::Operator::I64x2ExtendLowI32x4S
831 | wasmparser::Operator::I64x2ExtendHighI32x4S
832 | wasmparser::Operator::I64x2ExtendLowI32x4U
833 | wasmparser::Operator::I64x2ExtendHighI32x4U
834 | wasmparser::Operator::I64x2Shl
835 | wasmparser::Operator::I64x2ShrS
836 | wasmparser::Operator::I64x2ShrU
837 | wasmparser::Operator::I64x2Add
838 | wasmparser::Operator::I64x2Sub
839 | wasmparser::Operator::I64x2Mul
840 | wasmparser::Operator::I64x2ExtMulLowI32x4S
841 | wasmparser::Operator::I64x2ExtMulHighI32x4S
842 | wasmparser::Operator::I64x2ExtMulLowI32x4U
843 | wasmparser::Operator::I64x2ExtMulHighI32x4U
844 | wasmparser::Operator::F32x4Ceil
845 | wasmparser::Operator::F32x4Floor
846 | wasmparser::Operator::F32x4Trunc
847 | wasmparser::Operator::F32x4Nearest
848 | wasmparser::Operator::F32x4Abs
849 | wasmparser::Operator::F32x4Neg
850 | wasmparser::Operator::F32x4Sqrt
851 | wasmparser::Operator::F32x4Add
852 | wasmparser::Operator::F32x4Sub
853 | wasmparser::Operator::F32x4Mul
854 | wasmparser::Operator::F32x4Div
855 | wasmparser::Operator::F32x4Min
856 | wasmparser::Operator::F32x4Max
857 | wasmparser::Operator::F32x4PMin
858 | wasmparser::Operator::F32x4PMax
859 | wasmparser::Operator::F64x2Ceil
860 | wasmparser::Operator::F64x2Floor
861 | wasmparser::Operator::F64x2Trunc
862 | wasmparser::Operator::F64x2Nearest
863 | wasmparser::Operator::F64x2Abs
864 | wasmparser::Operator::F64x2Neg
865 | wasmparser::Operator::F64x2Sqrt
866 | wasmparser::Operator::F64x2Add
867 | wasmparser::Operator::F64x2Sub
868 | wasmparser::Operator::F64x2Mul
869 | wasmparser::Operator::F64x2Div
870 | wasmparser::Operator::F64x2Min
871 | wasmparser::Operator::F64x2Max
872 | wasmparser::Operator::F64x2PMin
873 | wasmparser::Operator::F64x2PMax
874 | wasmparser::Operator::I32x4TruncSatF32x4S
875 | wasmparser::Operator::I32x4TruncSatF32x4U
876 | wasmparser::Operator::F32x4ConvertI32x4S
877 | wasmparser::Operator::F32x4ConvertI32x4U
878 | wasmparser::Operator::I32x4TruncSatF64x2SZero
879 | wasmparser::Operator::I32x4TruncSatF64x2UZero
880 | wasmparser::Operator::F64x2ConvertLowI32x4S
881 | wasmparser::Operator::F64x2ConvertLowI32x4U
882 | wasmparser::Operator::F32x4DemoteF64x2Zero
883 | wasmparser::Operator::F64x2PromoteLowF32x4 => Some(false),
884 wasmparser::Operator::I8x16RelaxedSwizzle
887 | wasmparser::Operator::I32x4RelaxedTruncF32x4S
888 | wasmparser::Operator::I32x4RelaxedTruncF32x4U
889 | wasmparser::Operator::I32x4RelaxedTruncF64x2SZero
890 | wasmparser::Operator::I32x4RelaxedTruncF64x2UZero
891 | wasmparser::Operator::F32x4RelaxedMadd
892 | wasmparser::Operator::F32x4RelaxedNmadd
893 | wasmparser::Operator::F64x2RelaxedMadd
894 | wasmparser::Operator::F64x2RelaxedNmadd
895 | wasmparser::Operator::I8x16RelaxedLaneselect
896 | wasmparser::Operator::I16x8RelaxedLaneselect
897 | wasmparser::Operator::I32x4RelaxedLaneselect
898 | wasmparser::Operator::I64x2RelaxedLaneselect
899 | wasmparser::Operator::F32x4RelaxedMin
900 | wasmparser::Operator::F32x4RelaxedMax
901 | wasmparser::Operator::F64x2RelaxedMin
902 | wasmparser::Operator::F64x2RelaxedMax
903 | wasmparser::Operator::I16x8RelaxedQ15mulrS
904 | wasmparser::Operator::I16x8RelaxedDotI8x16I7x16S
905 | wasmparser::Operator::I32x4RelaxedDotI8x16I7x16AddS => Some(false),
906 wasmparser::Operator::CallRef { .. } => Some(false),
910 wasmparser::Operator::ReturnCallRef { .. } => Some(true),
913 wasmparser::Operator::RefAsNonNull => Some(false),
915 wasmparser::Operator::BrOnNull { .. } | wasmparser::Operator::BrOnNonNull { .. } => {
917 Some(true)
918 }
919 wasmparser::Operator::ContNew { .. } | wasmparser::Operator::ContBind { .. } => {
922 Some(false)
923 }
924 wasmparser::Operator::Suspend { .. }
927 | wasmparser::Operator::Resume { .. }
928 | wasmparser::Operator::ResumeThrow { .. } => Some(true),
929 wasmparser::Operator::Switch { .. } => Some(true),
932 wasmparser::Operator::I64Add128
935 | wasmparser::Operator::I64Sub128
936 | wasmparser::Operator::I64MulWideS
937 | wasmparser::Operator::I64MulWideU => Some(false),
938 #[cfg(not(test))]
940 #[expect(clippy::panic)]
941 _ => panic!("unsupported instruction"),
942 #[cfg(test)]
943 #[expect(unsafe_code)]
944 _ => {
945 unsafe extern "C" {
946 fn instruction_counter_unhandled_operator() -> !;
947 }
948 unsafe { instruction_counter_unhandled_operator() }
949 }
950 }
951 }
952}
953
954pub struct PerfWitInterfaces {
955 pub perf: InterfaceIdentifier,
956 pub instruction_counter: String,
957}
958
959impl PerfWitInterfaces {
960 #[must_use]
961 pub fn get() -> &'static Self {
962 static PERF_WIT_INTERFACES: OnceLock<PerfWitInterfaces> = OnceLock::new();
963
964 PERF_WIT_INTERFACES.get_or_init(|| Self {
965 perf: InterfaceIdentifier::new(
966 PackageIdentifier::new(
967 PackageName::new("numcodecs", "wasm"),
968 Some(Version::new(0, 1, 0)),
969 ),
970 "perf",
971 ),
972 instruction_counter: String::from("instruction-counter"),
973 })
974 }
975}