1use byteorder::{ByteOrder, LittleEndian};
2use core_wasm_ast as ast;
3use log::warn;
4use std::io::Write;
5
6type BoxError = Box<dyn std::error::Error + Sync + Send>;
7
8pub fn print(module: &ast::Module) -> Result<Vec<u8>, BoxError> {
9 let mut buffer = vec![];
10
11 write_header(&mut buffer)?;
12
13 for section in module.sections.lock().unwrap().iter() {
14 write_section(&mut buffer, §ion.value)?;
15 }
16
17 Ok(buffer)
18}
19
20pub fn write_header(buffer: &mut Vec<u8>) -> Result<(), BoxError> {
21 buffer.write(b"\0asm")?;
22 buffer.write(&1u32.to_le_bytes())?;
23 Ok(())
24}
25
26macro_rules! write_section {
27 ($b:expr, $o:expr, $id:expr, $write_fn:expr) => {
28 $b.push($id); let before_offset = $b.len();
31 $b.push(0x0); $write_fn($b, &$o)?;
34
35 let after_offset = $b.len();
36
37 let section_len = after_offset - before_offset - 1;
39
40 write_unsigned_leb128_at_offset($b, before_offset, section_len);
42 };
43}
44
45pub fn write_section(buffer: &mut Vec<u8>, section: &ast::Section) -> Result<(), BoxError> {
46 match section {
47 ast::Section::Import((_size, content)) => {
48 write_section!(buffer, content.lock().unwrap(), 2, write_section_import);
49 Ok(())
50 }
51 ast::Section::Table((_size, content)) => {
52 write_section!(buffer, content.lock().unwrap(), 4, write_section_table);
53 Ok(())
54 }
55 ast::Section::Memory((_size, content)) => {
56 write_section!(buffer, content, 5, write_section_memory);
57 Ok(())
58 }
59 ast::Section::Code((_size, content)) => {
60 write_section!(buffer, content.lock().unwrap(), 10, write_section_code);
61 Ok(())
62 }
63 ast::Section::Type((_size, content)) => {
64 write_section!(buffer, content.lock().unwrap(), 1, write_section_type);
65 Ok(())
66 }
67 ast::Section::Element((_size, content)) => {
68 write_section!(buffer, content.lock().unwrap(), 9, write_section_element);
69 Ok(())
70 }
71 ast::Section::Custom((_size, content)) => {
72 write_section!(buffer, content.lock().unwrap(), 0, write_section_custom);
73 Ok(())
74 }
75 ast::Section::Unknown((id, size, content)) => {
76 buffer.push(*id);
77 write_unsigned_leb128(buffer, *size as u64);
78 buffer.write(content)?;
79 Ok(())
80 }
81 ast::Section::Data((_size, content)) => {
82 write_section!(buffer, content.lock().unwrap(), 11, write_section_data);
83 Ok(())
84 }
85 ast::Section::Func((_size, content)) => {
86 write_section!(buffer, content.lock().unwrap(), 3, write_section_func);
87 Ok(())
88 }
89 ast::Section::Export((_size, content)) => {
90 write_section!(buffer, content.lock().unwrap(), 7, write_section_export);
91 Ok(())
92 }
93 ast::Section::Global((_size, content)) => {
94 write_section!(buffer, content.lock().unwrap(), 6, write_section_global);
95 Ok(())
96 }
97 }
98}
99
100fn write_section_import(buffer: &mut Vec<u8>, content: &Vec<ast::Import>) -> Result<(), BoxError> {
101 write_vec_len(buffer, content); for import in content {
104 write_utf8(buffer, &import.module);
105 write_utf8(buffer, &import.name);
106 match &import.import_type {
107 ast::ImportType::Func(funcidx) => {
108 buffer.push(0x0);
109 write_unsigned_leb128(buffer, *funcidx as u64);
110 }
111
112 ast::ImportType::Table(table) => {
113 buffer.push(0x1);
114 write_table(buffer, table)?;
115 }
116
117 ast::ImportType::Memory(mem) => {
118 buffer.push(0x2);
119 write_memory(buffer, mem)?;
120 }
121
122 ast::ImportType::Global(globaltype) => {
123 buffer.push(0x3);
124
125 write_value_type(buffer, &globaltype.valtype);
126 if globaltype.mutable {
127 buffer.push(0x01);
128 } else {
129 buffer.push(0x00);
130 }
131 }
132 }
133 }
134
135 Ok(())
136}
137
138fn write_section_table(buffer: &mut Vec<u8>, content: &Vec<ast::Table>) -> Result<(), BoxError> {
139 write_vec_len(buffer, content); for table in content {
142 write_table(buffer, table)?;
143 }
144
145 Ok(())
146}
147
148fn write_table(buffer: &mut Vec<u8>, table: &ast::Table) -> Result<(), BoxError> {
149 write_reftype(buffer, &table.reftype);
150 write_limits(buffer, &table.limits);
151 Ok(())
152}
153
154fn write_limits(buffer: &mut Vec<u8>, limits: &ast::Limits) {
155 if let Some(max) = limits.max {
156 buffer.push(0x01);
157 write_unsigned_leb128(buffer, limits.min as u64);
158 write_unsigned_leb128(buffer, max as u64);
159 } else {
160 buffer.push(0x00);
161 write_unsigned_leb128(buffer, limits.min as u64);
162 }
163}
164
165fn write_reftype(buffer: &mut Vec<u8>, typeref: &ast::Reftype) {
166 let b = match typeref {
167 ast::Reftype::Func => 0x70,
168 ast::Reftype::Extern => 0x6F,
169 };
170 buffer.push(b);
171}
172
173pub(crate) fn write_utf8(buffer: &mut Vec<u8>, v: &str) {
174 let bytes = v.as_bytes().to_vec();
175 write_vec_len(buffer, &bytes);
176 buffer.write_all(&bytes).unwrap();
177}
178
179fn write_section_memory(buffer: &mut Vec<u8>, content: &Vec<ast::Memory>) -> Result<(), BoxError> {
180 write_vec_len(buffer, content); for mem in content {
183 write_memory(buffer, mem)?;
184 }
185
186 Ok(())
187}
188
189fn write_memory(buffer: &mut Vec<u8>, mem: &ast::Memory) -> Result<(), BoxError> {
190 if let Some(max) = mem.max {
191 buffer.push(0x1);
192 write_unsigned_leb128(buffer, mem.min.value as u64);
193 write_unsigned_leb128(buffer, max as u64);
194 } else {
195 buffer.push(0x0);
196 write_unsigned_leb128(buffer, mem.min.value as u64);
197 }
198
199 Ok(())
200}
201
202fn write_section_global(buffer: &mut Vec<u8>, content: &Vec<ast::Global>) -> Result<(), BoxError> {
203 write_vec_len(buffer, &content); for global in content {
206 write_value_type(buffer, &global.global_type.valtype);
207 if global.global_type.mutable {
208 buffer.push(0x01);
209 } else {
210 buffer.push(0x00);
211 }
212
213 write_code_expr(buffer, &global.expr.value);
214 }
215
216 Ok(())
217}
218
219fn write_section_export(buffer: &mut Vec<u8>, content: &Vec<ast::Export>) -> Result<(), BoxError> {
220 write_vec_len(buffer, &content); for export in content {
223 write_utf8(buffer, &export.name);
224 match &export.descr {
225 ast::ExportDescr::Func(idx) => {
226 buffer.push(0x00);
227 write_unsigned_leb128(buffer, *idx.lock().unwrap() as u64);
228 }
229 ast::ExportDescr::Table(idx) => {
230 buffer.push(0x01);
231 write_unsigned_leb128(buffer, *idx.lock().unwrap() as u64);
232 }
233 ast::ExportDescr::Mem(idx) => {
234 buffer.push(0x02);
235 write_unsigned_leb128(buffer, *idx.lock().unwrap() as u64);
236 }
237 ast::ExportDescr::Global(idx) => {
238 buffer.push(0x03);
239 write_unsigned_leb128(buffer, *idx.lock().unwrap() as u64);
240 }
241 };
242 }
243
244 Ok(())
245}
246
247fn write_section_func(buffer: &mut Vec<u8>, content: &Vec<u32>) -> Result<(), BoxError> {
248 write_vec_len(buffer, &content); for idx in content {
251 write_unsigned_leb128(buffer, *idx as u64);
252 }
253
254 Ok(())
255}
256
257fn write_section_data(
258 buffer: &mut Vec<u8>,
259 content: &Vec<ast::DataSegment>,
260) -> Result<(), BoxError> {
261 write_vec_len(buffer, &content); for data_segment in content {
264 if data_segment.mode == ast::DataSegmentMode::Active {
265 write_unsigned_leb128(buffer, 0);
266 if let Some(offset) = &data_segment.offset {
267 write_code_expr(buffer, &offset.value);
268 }
269 } else {
270 write_unsigned_leb128(buffer, 1);
271 }
272
273 write_vec_len(buffer, &data_segment.bytes); buffer.write(&data_segment.bytes)?;
275 }
276
277 Ok(())
278}
279
280fn write_section_type(buffer: &mut Vec<u8>, content: &Vec<ast::Type>) -> Result<(), BoxError> {
281 write_vec_len(buffer, &content); for t in content {
284 buffer.push(0x60);
285
286 write_vec_len(buffer, &t.params); for param in &t.params {
288 write_value_type(buffer, param);
289 }
290
291 write_vec_len(buffer, &t.results); for result in &t.results {
293 write_value_type(buffer, result);
294 }
295 }
296 Ok(())
297}
298
299fn write_section_custom(
300 buffer: &mut Vec<u8>,
301 content: &ast::CustomSection,
302) -> Result<(), BoxError> {
303 match content {
304 ast::CustomSection::Unknown(name, bytes) => {
305 write_utf8(buffer, &name);
306 buffer.extend_from_slice(&bytes);
307 }
308 ast::CustomSection::Name(content) => {
309 write_utf8(buffer, "name");
310 write_section_custom_name(buffer, &content)?
311 }
312
313 ast::CustomSection::BuildId(id) => {
314 write_utf8(buffer, "build_id");
315 write_section_custom_build_id(buffer, id)?
316 }
317
318 ast::CustomSection::CoredumpCore(content) => {
319 write_utf8(buffer, "core");
320 wasm_coredump_encoder::encode_coredump_process(buffer, content)?;
321 }
322
323 ast::CustomSection::CoredumpCoreStack(content) => {
324 write_utf8(buffer, "corestack");
325 wasm_coredump_encoder::encode_coredump_stack(buffer, content)?;
326 }
327 }
328
329 Ok(())
330}
331
332fn write_section_custom_build_id(buffer: &mut Vec<u8>, id: &[u8]) -> Result<(), BoxError> {
333 write_unsigned_leb128(buffer, id.len() as u64);
334 buffer.extend_from_slice(id);
335 Ok(())
336}
337
338pub fn write_section_custom_name(
339 buffer: &mut Vec<u8>,
340 content: &ast::DebugNames,
341) -> Result<(), BoxError> {
342 if let Some(_module_name) = &content.module {
343 warn!("Module Name not implemented yet")
344 }
345
346 if let Some(func_names) = &content.func_names {
347 buffer.push(1);
348
349 let mut subsection = vec![];
350 {
351 let func_names = func_names.lock().unwrap();
352
353 write_unsigned_leb128(&mut subsection, func_names.len() as u64);
354
355 for funcidx in 0..func_names.len() {
356 if let Some(name) = func_names.get(&(funcidx as u32)) {
357 write_unsigned_leb128(&mut subsection, funcidx as u64);
358 write_utf8(&mut subsection, name);
359 }
360 }
361 }
362
363 write_unsigned_leb128(buffer, subsection.len() as u64);
364 buffer.extend_from_slice(&subsection)
365 }
366
367 {
369 buffer.push(7);
370
371 let mut subsection = vec![];
372 {
373 let global_names = content.global_names.lock().unwrap();
374
375 write_unsigned_leb128(&mut subsection, global_names.len() as u64);
376
377 for idx in 0..global_names.len() {
378 if let Some(name) = global_names.get(&(idx as u32)) {
379 write_unsigned_leb128(&mut subsection, idx as u64);
380 write_utf8(&mut subsection, name);
381 }
382 }
383 }
384
385 write_unsigned_leb128(buffer, subsection.len() as u64);
386 buffer.extend_from_slice(&subsection)
387 }
388
389 Ok(())
390}
391
392fn write_section_element(
393 buffer: &mut Vec<u8>,
394 content: &Vec<ast::Element>,
395) -> Result<(), BoxError> {
396 write_vec_len(buffer, &content); for t in content {
399 match t {
400 ast::Element::FuncActive(expr, vec) => {
401 buffer.push(0);
402 write_code_expr(buffer, &expr.value);
403 write_vec_len(buffer, &vec.lock().unwrap());
404 for funcidx in vec.lock().unwrap().iter() {
405 write_unsigned_leb128(buffer, *funcidx as u64);
406 }
407 }
408 }
409 }
410 Ok(())
411}
412
413fn write_section_code(
414 buffer: &mut Vec<u8>,
415 content: &ast::Value<Vec<ast::Code>>,
416) -> Result<(), BoxError> {
417 write_vec_len(buffer, &content.value); for func in &content.value {
420 let before_offset = buffer.len();
421 buffer.push(0x0); write_code_local(buffer, &func.locals);
424 write_code_expr(buffer, &func.body.lock().unwrap().value);
425
426 {
428 let after_offset = buffer.len();
429 let func_len = after_offset - before_offset - 1;
430
431 write_unsigned_leb128_at_offset(buffer, before_offset, func_len);
432 }
433 }
434 Ok(())
435}
436
437fn write_vec_len<T>(buffer: &mut Vec<u8>, vec: &Vec<T>) {
438 write_unsigned_leb128(buffer, vec.len() as u64);
439}
440
441fn write_code_local(buffer: &mut Vec<u8>, locals: &Vec<ast::CodeLocal>) {
442 write_vec_len(buffer, locals); for local in locals {
445 write_unsigned_leb128(buffer, local.count as u64);
446 write_value_type(buffer, &local.value_type);
447 }
448}
449
450fn write_value_type(buffer: &mut Vec<u8>, value_type: &ast::ValueType) {
451 use ast::NumType::*;
452 use ast::ValueType::*;
453 let b: u8 = match value_type {
454 NumType(I32) => 0x7F,
455 NumType(I64) => 0x7E,
456 NumType(F32) => 0x7D,
457 NumType(F64) => 0x7C,
458 };
459 buffer.push(b);
460}
461
462fn write_code_expr(buffer: &mut Vec<u8>, expr: &Vec<ast::Value<ast::Instr>>) {
463 for instr in expr {
464 let id = instr.value.clone();
465
466 macro_rules! write_instr {
467 ($byte:expr, $instr:ident) => {
468 if matches!(id, ast::Instr::$instr) {
469 buffer.push($byte);
470 continue;
471 }
472 };
473 ($byte:expr, $instr:ident(u8)) => {
474 if let ast::Instr::$instr(imm0) = id {
475 buffer.push($byte);
476 buffer.push(imm0);
477 continue;
478 }
479 };
480
481 ($byte:expr, $instr:ident(f32)) => {
482 if let ast::Instr::$instr(imm0) = id {
483 buffer.push($byte);
484 write_float_f32(buffer, imm0);
485 continue;
486 }
487 };
488
489 ($byte:expr, $instr:ident(f64)) => {
490 if let ast::Instr::$instr(imm0) = id {
491 buffer.push($byte);
492 write_float_f64(buffer, imm0);
493 continue;
494 }
495 };
496
497 ($byte:expr, $instr:ident(i32)) => {
498 if let ast::Instr::$instr(imm0) = id {
499 buffer.push($byte);
500 write_signed_leb128(buffer, imm0 as i64);
501 continue;
502 }
503 };
504
505 ($byte:expr, $instr:ident(i64)) => {
506 if let ast::Instr::$instr(imm0) = id {
507 buffer.push($byte);
508 write_signed_leb128(buffer, imm0);
509 continue;
510 }
511 };
512
513 ($byte:expr, $instr:ident(u32)) => {
514 if let ast::Instr::$instr(imm0) = id {
515 buffer.push($byte);
516 write_unsigned_leb128(buffer, imm0 as u64);
517 continue;
518 }
519 };
520
521 ($byte:expr, $instr:ident(MutableValue<u32>)) => {
522 if let ast::Instr::$instr(imm0) = id {
523 buffer.push($byte);
524 write_unsigned_leb128(buffer, imm0.lock().unwrap().value as u64);
525 continue;
526 }
527 };
528
529 ($byte:expr, $instr:ident(u32, u32)) => {
530 if let ast::Instr::$instr(imm0, imm1) = id {
531 buffer.push($byte);
532 write_unsigned_leb128(buffer, imm0 as u64);
533 write_unsigned_leb128(buffer, imm1 as u64);
534 continue;
535 }
536 };
537
538 ($byte:expr, $instr:ident(MutableValue<u32>, u32)) => {
539 if let ast::Instr::$instr(imm0, imm1) = id {
540 buffer.push($byte);
541 let imm0 = imm0.lock().unwrap().value;
542 write_unsigned_leb128(buffer, imm0 as u64);
543 write_unsigned_leb128(buffer, imm1 as u64);
544 continue;
545 }
546 };
547
548 ($byte:expr, $instr:ident(Vec<u32>, u32)) => {
549 if let ast::Instr::$instr(imm0, imm1) = id.clone() {
550 buffer.push($byte);
551 write_vec_len(buffer, &imm0); for imm in imm0 {
553 write_unsigned_leb128(buffer, imm as u64);
554 }
555 write_unsigned_leb128(buffer, imm1 as u64);
556 continue;
557 }
558 };
559 }
560
561 write_instr!(0x00, unreachable);
562 write_instr!(0x01, nop);
563
564 if let ast::Instr::Block(ref block_type, body) = id {
565 buffer.push(0x02);
566 write_blocktype(buffer, block_type);
567 write_code_expr(buffer, &body.lock().unwrap().value);
568 continue;
569 }
570
571 if let ast::Instr::Loop(ref block_type, body) = id {
572 buffer.push(0x03);
573 write_blocktype(buffer, block_type);
574 write_code_expr(buffer, &body.lock().unwrap().value);
575 continue;
576 }
577
578 if let ast::Instr::If(ref block_type, body) = id {
579 buffer.push(0x04);
581 write_blocktype(buffer, block_type);
582 write_code_expr(buffer, &body.lock().unwrap().value);
583 continue;
584 }
585
586 write_instr!(0xc, br(u32));
587 write_instr!(0xd, br_if(u32));
588 write_instr!(0x0b, end);
589 write_instr!(0x05, else_end);
590 write_instr!(0x0e, br_table(Vec<u32>, u32));
591 write_instr!(0x0f, Return);
592 write_instr!(0x10, call(MutableValue<u32>));
593 write_instr!(0x11, call_indirect(u32, u32));
594
595 write_instr!(0x1a, drop);
596 write_instr!(0x1b, select);
597 write_instr!(0x20, local_get(u32));
600 write_instr!(0x21, local_set(u32));
601 write_instr!(0x22, local_tee(u32));
602 write_instr!(0x23, global_get(u32));
603 write_instr!(0x24, global_set(u32));
604 write_instr!(0x25, table_get(u32));
605 write_instr!(0x26, table_set(u32));
606
607 write_instr!(0x28, i32_load(MutableValue<u32>, u32));
608 write_instr!(0x29, i64_load(MutableValue<u32>, u32));
609 write_instr!(0x2a, f32_load(MutableValue<u32>, u32));
610 write_instr!(0x2b, f64_load(MutableValue<u32>, u32));
611 write_instr!(0x2c, i32_load8_s(MutableValue<u32>, u32));
612 write_instr!(0x2d, i32_load8_u(MutableValue<u32>, u32));
613 write_instr!(0x2e, i32_load16_s(MutableValue<u32>, u32));
614 write_instr!(0x2f, i32_load16_u(MutableValue<u32>, u32));
615 write_instr!(0x30, i64_load8_s(MutableValue<u32>, u32));
616 write_instr!(0x31, i64_load8_u(MutableValue<u32>, u32));
617 write_instr!(0x32, i64_load16_s(MutableValue<u32>, u32));
618 write_instr!(0x33, i64_load16_u(MutableValue<u32>, u32));
619 write_instr!(0x34, i64_load32_s(MutableValue<u32>, u32));
620 write_instr!(0x35, i64_load32_u(MutableValue<u32>, u32));
621
622 write_instr!(0x36, i32_store(MutableValue<u32>, u32));
623 write_instr!(0x37, i64_store(MutableValue<u32>, u32));
624 write_instr!(0x38, f32_store(MutableValue<u32>, u32));
625 write_instr!(0x39, f64_store(MutableValue<u32>, u32));
626 write_instr!(0x3a, i32_store8(MutableValue<u32>, u32));
627 write_instr!(0x3b, i32_store16(MutableValue<u32>, u32));
628 write_instr!(0x3c, i64_store8(MutableValue<u32>, u32));
629 write_instr!(0x3d, i64_store16(MutableValue<u32>, u32));
630 write_instr!(0x3e, i64_store32(MutableValue<u32>, u32));
631
632 write_instr!(0x3f, memory_size(u8));
633 write_instr!(0x40, memory_grow(u8));
634
635 write_instr!(0x41, i32_const(i32));
636 write_instr!(0x42, i64_const(i64));
637 write_instr!(0x43, f32_const(f32));
638 write_instr!(0x44, f64_const(f64));
639
640 write_instr!(0x45, i32_eqz);
641 write_instr!(0x46, i32_eq);
642 write_instr!(0x47, i32_ne);
643 write_instr!(0x48, i32_lt_s);
644 write_instr!(0x49, i32_lt_u);
645 write_instr!(0x4a, i32_gt_s);
646 write_instr!(0x4b, i32_gt_u);
647 write_instr!(0x4c, i32_le_s);
648 write_instr!(0x4d, i32_le_u);
649 write_instr!(0x4e, i32_ge_s);
650 write_instr!(0x4f, i32_ge_u);
651
652 write_instr!(0x50, i64_eqz);
653 write_instr!(0x51, i64_eq);
654 write_instr!(0x52, i64_ne);
655 write_instr!(0x53, i64_lt_s);
656 write_instr!(0x54, i64_lt_u);
657 write_instr!(0x55, i64_gt_s);
658 write_instr!(0x56, i64_gt_u);
659 write_instr!(0x57, i64_le_s);
660 write_instr!(0x58, i64_le_u);
661 write_instr!(0x59, i64_ge_s);
662 write_instr!(0x5a, i64_ge_u);
663
664 write_instr!(0x5b, f32_eq);
665 write_instr!(0x5c, f32_ne);
666 write_instr!(0x5d, f32_lt);
667 write_instr!(0x5e, f32_gt);
668 write_instr!(0x5f, f32_le);
669 write_instr!(0x60, f32_ge);
670
671 write_instr!(0x61, f64_eq);
672 write_instr!(0x62, f64_ne);
673 write_instr!(0x63, f64_lt);
674 write_instr!(0x64, f64_gt);
675 write_instr!(0x65, f64_le);
676 write_instr!(0x66, f64_ge);
677
678 write_instr!(0x67, i32_clz);
679 write_instr!(0x68, i32_ctz);
680 write_instr!(0x69, i32_popcnt);
681 write_instr!(0x6a, i32_add);
682 write_instr!(0x6b, i32_sub);
683 write_instr!(0x6c, i32_mul);
684 write_instr!(0x6d, i32_div_s);
685 write_instr!(0x6e, i32_div_u);
686 write_instr!(0x6f, i32_rem_s);
687 write_instr!(0x70, i32_rem_u);
688 write_instr!(0x71, i32_and);
689 write_instr!(0x72, i32_or);
690 write_instr!(0x73, i32_xor);
691 write_instr!(0x74, i32_shl);
692 write_instr!(0x75, i32_shr_s);
693 write_instr!(0x76, i32_shr_u);
694 write_instr!(0x77, i32_rotl);
695 write_instr!(0x78, i32_rotr);
696
697 write_instr!(0x79, i64_clz);
698 write_instr!(0x7a, i64_ctz);
699 write_instr!(0x7b, i64_popcnt);
700 write_instr!(0x7c, i64_add);
701 write_instr!(0x7d, i64_sub);
702 write_instr!(0x7e, i64_mul);
703 write_instr!(0x7f, i64_div_s);
704 write_instr!(0x80, i64_div_u);
705 write_instr!(0x81, i64_rem_s);
706 write_instr!(0x82, i64_rem_u);
707 write_instr!(0x83, i64_and);
708 write_instr!(0x84, i64_or);
709 write_instr!(0x85, i64_xor);
710 write_instr!(0x86, i64_shl);
711 write_instr!(0x87, i64_shr_s);
712 write_instr!(0x88, i64_shr_u);
713 write_instr!(0x89, i64_rotl);
714 write_instr!(0x8a, i64_rotr);
715
716 write_instr!(0x8b, f32_abs);
717 write_instr!(0x8c, f32_neg);
718 write_instr!(0x8d, f32_ceil);
719 write_instr!(0x8e, f32_floor);
720 write_instr!(0x8f, f32_trunc);
721 write_instr!(0x90, f32_nearest);
722 write_instr!(0x91, f32_sqrt);
723 write_instr!(0x92, f32_add);
724 write_instr!(0x93, f32_sub);
725 write_instr!(0x94, f32_mul);
726 write_instr!(0x95, f32_div);
727 write_instr!(0x96, f32_min);
728 write_instr!(0x97, f32_max);
729 write_instr!(0x98, f32_copysign);
730
731 write_instr!(0x99, f64_abs);
732 write_instr!(0x9a, f64_neg);
733 write_instr!(0x9b, f64_ceil);
734 write_instr!(0x9c, f64_floor);
735 write_instr!(0x9d, f64_trunc);
736 write_instr!(0x9e, f64_nearest);
737 write_instr!(0x9f, f64_sqrt);
738 write_instr!(0xa0, f64_add);
739 write_instr!(0xa1, f64_sub);
740 write_instr!(0xa2, f64_mul);
741 write_instr!(0xa3, f64_div);
742 write_instr!(0xa4, f64_min);
743 write_instr!(0xa5, f64_max);
744 write_instr!(0xa6, f64_copysign);
745
746 write_instr!(0xa7, i32_wrap_i64);
747 write_instr!(0xa8, i32_trunc_f32_s);
748 write_instr!(0xa9, i32_trunc_f32_u);
749 write_instr!(0xaa, i32_trunc_f64_s);
750 write_instr!(0xab, i32_trunc_f64_u);
751 write_instr!(0xac, i64_extend_i32_s);
752 write_instr!(0xad, i64_extend_i32_u);
753 write_instr!(0xae, i64_trunc_f32_s);
754 write_instr!(0xaf, i64_trunc_f32_u);
755 write_instr!(0xb0, i64_trunc_f64_s);
756 write_instr!(0xb1, i64_trunc_f64_u);
757 write_instr!(0xb2, f32_convert_i32_s);
758 write_instr!(0xb3, f32_convert_i32_u);
759 write_instr!(0xb4, f32_convert_i64_s);
760 write_instr!(0xb5, f32_convert_i64_u);
761 write_instr!(0xb6, f32_demote_f64);
762 write_instr!(0xb7, f64_convert_i32_s);
763 write_instr!(0xb8, f64_convert_i32_u);
764 write_instr!(0xb9, f64_convert_i64_s);
765 write_instr!(0xba, f64_convert_i64_u);
766 write_instr!(0xbb, f64_promote_f32);
767
768 write_instr!(0xbc, i32_reinterpret_f32);
769 write_instr!(0xbd, i64_reinterpret_f64);
770 write_instr!(0xbe, f32_reinterpret_i32);
771 write_instr!(0xbf, f64_reinterpret_i64);
772
773 write_instr!(0xc0, i32_extend8_s);
774 write_instr!(0xc1, i32_extend16_s);
775 write_instr!(0xc2, i64_extend8_s);
776 write_instr!(0xc3, i64_extend16_s);
777 write_instr!(0xc4, i64_extend32_s);
778
779 if matches!(id, ast::Instr::i32_trunc_sat_f32_s) {
782 buffer.push(0xfc);
783 buffer.push(0);
784 continue;
785 }
786 if matches!(id, ast::Instr::i32_trunc_sat_f32_u) {
787 buffer.push(0xfc);
788 buffer.push(1);
789 continue;
790 }
791 if matches!(id, ast::Instr::i32_trunc_sat_f64_s) {
792 buffer.push(0xfc);
793 buffer.push(2);
794 continue;
795 }
796 if matches!(id, ast::Instr::i32_trunc_sat_f64_u) {
797 buffer.push(0xfc);
798 buffer.push(3);
799 continue;
800 }
801 if matches!(id, ast::Instr::i64_trunc_sat_f32_s) {
802 buffer.push(0xfc);
803 buffer.push(4);
804 continue;
805 }
806 if matches!(id, ast::Instr::i64_trunc_sat_f32_u) {
807 buffer.push(0xfc);
808 buffer.push(5);
809 continue;
810 }
811 if matches!(id, ast::Instr::i64_trunc_sat_f64_s) {
812 buffer.push(0xfc);
813 buffer.push(6);
814 continue;
815 }
816 if matches!(id, ast::Instr::i64_trunc_sat_f64_u) {
817 buffer.push(0xfc);
818 buffer.push(7);
819 continue;
820 }
821
822 if let ast::Instr::memory_copy(imm0, imm1) = id {
823 buffer.push(0xfc);
824 buffer.push(10);
825 buffer.push(imm0);
826 buffer.push(imm1);
827 continue;
828 }
829 if let ast::Instr::memory_fill(imm0) = id {
830 buffer.push(0xfc);
831 buffer.push(11);
832 buffer.push(imm0);
833 continue;
834 }
835
836 unimplemented!("unknown instruction: {:#?}", id);
837 }
838}
839
840fn write_unsigned_leb128_at_offset(bytes: &mut Vec<u8>, offset: usize, n: usize) {
841 bytes.remove(offset);
843
844 let mut buffer = vec![];
845
846 leb128::write::unsigned(&mut buffer, n as u64).expect("could not write LEB128");
847
848 let mut i = 0;
849 for byte in buffer {
850 bytes.insert(offset + i, byte);
851 i += 1;
852 }
853}
854
855pub(crate) fn write_unsigned_leb128(buffer: &mut Vec<u8>, n: u64) {
856 leb128::write::unsigned(buffer, n).expect("could not write LEB128");
857}
858
859fn write_signed_leb128(buffer: &mut Vec<u8>, n: i64) {
860 leb128::write::signed(buffer, n).expect("could not write LEB128");
861}
862
863fn write_float_f64(buffer: &mut Vec<u8>, n: f64) {
864 let mut b = [0; 8];
865 LittleEndian::write_f64(&mut b, n);
866 buffer.extend(b.iter())
867}
868
869fn write_float_f32(buffer: &mut Vec<u8>, n: f32) {
870 let mut b = [0; 4];
871 LittleEndian::write_f32(&mut b, n);
872 buffer.extend(b.iter())
873}
874
875fn write_blocktype(buffer: &mut Vec<u8>, block_type: &ast::BlockType) {
876 match block_type {
877 ast::BlockType::Empty => {
878 buffer.push(0x40);
879 }
880 ast::BlockType::ValueType(valtype) => {
881 write_value_type(buffer, valtype);
882 }
883 ast::BlockType::Typeidx(valtype) => {
884 write_signed_leb128(buffer, *valtype as i64);
885 }
886 }
887}