1 #![cfg(not(miri))]
2 
3 use super::{ApiStyle, REALLOC_AND_FREE};
4 use std::sync::Arc;
5 use wasmtime::Result;
6 use wasmtime::component::*;
7 use wasmtime::{Config, Engine, Store, StoreContextMut, Trap};
8 
9 const CANON_32BIT_NAN: u32 = 0b01111111110000000000000000000000;
10 const CANON_64BIT_NAN: u64 = 0b0111111111111000000000000000000000000000000000000000000000000000;
11 
12 #[test]
13 fn thunks() -> Result<()> {
14     let component = r#"
15         (component
16             (core module $m
17                 (func (export "thunk"))
18                 (func (export "thunk-trap") unreachable)
19             )
20             (core instance $i (instantiate $m))
21             (func (export "thunk")
22                 (canon lift (core func $i "thunk"))
23             )
24             (func (export "thunk-trap")
25                 (canon lift (core func $i "thunk-trap"))
26             )
27         )
28     "#;
29 
30     let engine = super::engine();
31     let component = Component::new(&engine, component)?;
32     let mut store = Store::new(&engine, ());
33     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
34     instance
35         .get_typed_func::<(), ()>(&mut store, "thunk")?
36         .call(&mut store, ())?;
37     let err = instance
38         .get_typed_func::<(), ()>(&mut store, "thunk-trap")?
39         .call(&mut store, ())
40         .unwrap_err();
41     assert_eq!(err.downcast::<Trap>()?, Trap::UnreachableCodeReached);
42 
43     Ok(())
44 }
45 
46 #[test]
47 fn typecheck() -> Result<()> {
48     let component = r#"
49         (component
50             (core module $m
51                 (func (export "thunk"))
52                 (func (export "take-string") (param i32 i32))
53                 (func (export "two-args") (param i32 i32 i32))
54                 (func (export "ret-one") (result i32) unreachable)
55 
56                 (memory (export "memory") 1)
57                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
58                     unreachable)
59             )
60             (core instance $i (instantiate (module $m)))
61             (func (export "thunk")
62                 (canon lift (core func $i "thunk"))
63             )
64             (func (export "take-string") (param "a" string)
65                 (canon lift (core func $i "take-string") (memory $i "memory") (realloc (func $i "realloc")))
66             )
67             (func (export "take-two-args") (param "a" s32) (param "b" (list u8))
68                 (canon lift (core func $i "two-args") (memory $i "memory") (realloc (func $i "realloc")))
69             )
70             (func (export "ret-tuple") (result (tuple u8 s8))
71                 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
72             )
73             (func (export "ret-tuple1") (result (tuple u32))
74                 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
75             )
76             (func (export "ret-string") (result string)
77                 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
78             )
79             (func (export "ret-list-u8") (result (list u8))
80                 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
81             )
82         )
83     "#;
84 
85     let engine = Engine::default();
86     let component = Component::new(&engine, component)?;
87     let mut store = Store::new(&engine, ());
88     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
89     let thunk = instance.get_func(&mut store, "thunk").unwrap();
90     let take_string = instance.get_func(&mut store, "take-string").unwrap();
91     let take_two_args = instance.get_func(&mut store, "take-two-args").unwrap();
92     let ret_tuple = instance.get_func(&mut store, "ret-tuple").unwrap();
93     let ret_tuple1 = instance.get_func(&mut store, "ret-tuple1").unwrap();
94     let ret_string = instance.get_func(&mut store, "ret-string").unwrap();
95     let ret_list_u8 = instance.get_func(&mut store, "ret-list-u8").unwrap();
96     assert!(thunk.typed::<(), (u32,)>(&store).is_err());
97     assert!(thunk.typed::<(u32,), ()>(&store).is_err());
98     assert!(thunk.typed::<(), ()>(&store).is_ok());
99     assert!(take_string.typed::<(), ()>(&store).is_err());
100     assert!(take_string.typed::<(String,), ()>(&store).is_ok());
101     assert!(take_string.typed::<(&str,), ()>(&store).is_ok());
102     assert!(take_string.typed::<(&[u8],), ()>(&store).is_err());
103     assert!(take_two_args.typed::<(), ()>(&store).is_err());
104     assert!(take_two_args.typed::<(i32, &[u8]), (u32,)>(&store).is_err());
105     assert!(take_two_args.typed::<(u32, &[u8]), ()>(&store).is_err());
106     assert!(take_two_args.typed::<(i32, &[u8]), ()>(&store).is_ok());
107     assert!(ret_tuple.typed::<(), ()>(&store).is_err());
108     assert!(ret_tuple.typed::<(), (u8,)>(&store).is_err());
109     assert!(ret_tuple.typed::<(), ((u8, i8),)>(&store).is_ok());
110     assert!(ret_tuple1.typed::<(), ((u32,),)>(&store).is_ok());
111     assert!(ret_tuple1.typed::<(), (u32,)>(&store).is_err());
112     assert!(ret_string.typed::<(), ()>(&store).is_err());
113     assert!(ret_string.typed::<(), (WasmStr,)>(&store).is_ok());
114     assert!(ret_list_u8.typed::<(), (WasmList<u16>,)>(&store).is_err());
115     assert!(ret_list_u8.typed::<(), (WasmList<i8>,)>(&store).is_err());
116     assert!(ret_list_u8.typed::<(), (WasmList<u8>,)>(&store).is_ok());
117 
118     Ok(())
119 }
120 
121 #[test]
122 fn integers() -> Result<()> {
123     let component = r#"
124         (component
125             (core module $m
126                 (func (export "take-i32-100") (param i32)
127                     local.get 0
128                     i32.const 100
129                     i32.eq
130                     br_if 0
131                     unreachable
132                 )
133                 (func (export "take-i64-100") (param i64)
134                     local.get 0
135                     i64.const 100
136                     i64.eq
137                     br_if 0
138                     unreachable
139                 )
140                 (func (export "ret-i32-0") (result i32) i32.const 0)
141                 (func (export "ret-i64-0") (result i64) i64.const 0)
142                 (func (export "ret-i32-minus-1") (result i32) i32.const -1)
143                 (func (export "ret-i64-minus-1") (result i64) i64.const -1)
144                 (func (export "ret-i32-100000") (result i32) i32.const 100000)
145             )
146             (core instance $i (instantiate (module $m)))
147             (func (export "take-u8") (param "a" u8) (canon lift (core func $i "take-i32-100")))
148             (func (export "take-s8") (param "a" s8) (canon lift (core func $i "take-i32-100")))
149             (func (export "take-u16") (param "a" u16) (canon lift (core func $i "take-i32-100")))
150             (func (export "take-s16") (param "a" s16) (canon lift (core func $i "take-i32-100")))
151             (func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))
152             (func (export "take-s32") (param "a" s32) (canon lift (core func $i "take-i32-100")))
153             (func (export "take-u64") (param "a" u64) (canon lift (core func $i "take-i64-100")))
154             (func (export "take-s64") (param "a" s64) (canon lift (core func $i "take-i64-100")))
155 
156             (func (export "ret-u8") (result u8) (canon lift (core func $i "ret-i32-0")))
157             (func (export "ret-s8") (result s8) (canon lift (core func $i "ret-i32-0")))
158             (func (export "ret-u16") (result u16) (canon lift (core func $i "ret-i32-0")))
159             (func (export "ret-s16") (result s16) (canon lift (core func $i "ret-i32-0")))
160             (func (export "ret-u32") (result u32) (canon lift (core func $i "ret-i32-0")))
161             (func (export "ret-s32") (result s32) (canon lift (core func $i "ret-i32-0")))
162             (func (export "ret-u64") (result u64) (canon lift (core func $i "ret-i64-0")))
163             (func (export "ret-s64") (result s64) (canon lift (core func $i "ret-i64-0")))
164 
165             (func (export "retm1-u8") (result u8) (canon lift (core func $i "ret-i32-minus-1")))
166             (func (export "retm1-s8") (result s8) (canon lift (core func $i "ret-i32-minus-1")))
167             (func (export "retm1-u16") (result u16) (canon lift (core func $i "ret-i32-minus-1")))
168             (func (export "retm1-s16") (result s16) (canon lift (core func $i "ret-i32-minus-1")))
169             (func (export "retm1-u32") (result u32) (canon lift (core func $i "ret-i32-minus-1")))
170             (func (export "retm1-s32") (result s32) (canon lift (core func $i "ret-i32-minus-1")))
171             (func (export "retm1-u64") (result u64) (canon lift (core func $i "ret-i64-minus-1")))
172             (func (export "retm1-s64") (result s64) (canon lift (core func $i "ret-i64-minus-1")))
173 
174             (func (export "retbig-u8") (result u8) (canon lift (core func $i "ret-i32-100000")))
175             (func (export "retbig-s8") (result s8) (canon lift (core func $i "ret-i32-100000")))
176             (func (export "retbig-u16") (result u16) (canon lift (core func $i "ret-i32-100000")))
177             (func (export "retbig-s16") (result s16) (canon lift (core func $i "ret-i32-100000")))
178             (func (export "retbig-u32") (result u32) (canon lift (core func $i "ret-i32-100000")))
179             (func (export "retbig-s32") (result s32) (canon lift (core func $i "ret-i32-100000")))
180         )
181     "#;
182 
183     let engine = super::engine();
184     let component = Component::new(&engine, component)?;
185     let mut store = Store::new(&engine, ());
186     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
187 
188     // Passing in 100 is valid for all primitives
189     instance
190         .get_typed_func::<(u8,), ()>(&mut store, "take-u8")?
191         .call(&mut store, (100,))?;
192     instance
193         .get_typed_func::<(i8,), ()>(&mut store, "take-s8")?
194         .call(&mut store, (100,))?;
195     instance
196         .get_typed_func::<(u16,), ()>(&mut store, "take-u16")?
197         .call(&mut store, (100,))?;
198     instance
199         .get_typed_func::<(i16,), ()>(&mut store, "take-s16")?
200         .call(&mut store, (100,))?;
201     instance
202         .get_typed_func::<(u32,), ()>(&mut store, "take-u32")?
203         .call(&mut store, (100,))?;
204     instance
205         .get_typed_func::<(i32,), ()>(&mut store, "take-s32")?
206         .call(&mut store, (100,))?;
207     instance
208         .get_typed_func::<(u64,), ()>(&mut store, "take-u64")?
209         .call(&mut store, (100,))?;
210     instance
211         .get_typed_func::<(i64,), ()>(&mut store, "take-s64")?
212         .call(&mut store, (100,))?;
213 
214     // This specific wasm instance traps if any value other than 100 is passed
215     with_new_instance(&engine, &component, |store, instance| {
216         instance
217             .get_typed_func::<(u8,), ()>(&mut *store, "take-u8")?
218             .call(store, (101,))
219             .unwrap_err()
220             .downcast::<Trap>()
221     })?;
222     with_new_instance(&engine, &component, |store, instance| {
223         instance
224             .get_typed_func::<(i8,), ()>(&mut *store, "take-s8")?
225             .call(store, (101,))
226             .unwrap_err()
227             .downcast::<Trap>()
228     })?;
229     with_new_instance(&engine, &component, |store, instance| {
230         instance
231             .get_typed_func::<(u16,), ()>(&mut *store, "take-u16")?
232             .call(store, (101,))
233             .unwrap_err()
234             .downcast::<Trap>()
235     })?;
236     with_new_instance(&engine, &component, |store, instance| {
237         instance
238             .get_typed_func::<(i16,), ()>(&mut *store, "take-s16")?
239             .call(store, (101,))
240             .unwrap_err()
241             .downcast::<Trap>()
242     })?;
243     with_new_instance(&engine, &component, |store, instance| {
244         instance
245             .get_typed_func::<(u32,), ()>(&mut *store, "take-u32")?
246             .call(store, (101,))
247             .unwrap_err()
248             .downcast::<Trap>()
249     })?;
250     with_new_instance(&engine, &component, |store, instance| {
251         instance
252             .get_typed_func::<(i32,), ()>(&mut *store, "take-s32")?
253             .call(store, (101,))
254             .unwrap_err()
255             .downcast::<Trap>()
256     })?;
257     with_new_instance(&engine, &component, |store, instance| {
258         instance
259             .get_typed_func::<(u64,), ()>(&mut *store, "take-u64")?
260             .call(store, (101,))
261             .unwrap_err()
262             .downcast::<Trap>()
263     })?;
264     with_new_instance(&engine, &component, |store, instance| {
265         instance
266             .get_typed_func::<(i64,), ()>(&mut *store, "take-s64")?
267             .call(store, (101,))
268             .unwrap_err()
269             .downcast::<Trap>()
270     })?;
271 
272     // Zero can be returned as any integer
273     assert_eq!(
274         instance
275             .get_typed_func::<(), (u8,)>(&mut store, "ret-u8")?
276             .call(&mut store, ())?,
277         (0,)
278     );
279     assert_eq!(
280         instance
281             .get_typed_func::<(), (i8,)>(&mut store, "ret-s8")?
282             .call(&mut store, ())?,
283         (0,)
284     );
285     assert_eq!(
286         instance
287             .get_typed_func::<(), (u16,)>(&mut store, "ret-u16")?
288             .call(&mut store, ())?,
289         (0,)
290     );
291     assert_eq!(
292         instance
293             .get_typed_func::<(), (i16,)>(&mut store, "ret-s16")?
294             .call(&mut store, ())?,
295         (0,)
296     );
297     assert_eq!(
298         instance
299             .get_typed_func::<(), (u32,)>(&mut store, "ret-u32")?
300             .call(&mut store, ())?,
301         (0,)
302     );
303     assert_eq!(
304         instance
305             .get_typed_func::<(), (i32,)>(&mut store, "ret-s32")?
306             .call(&mut store, ())?,
307         (0,)
308     );
309     assert_eq!(
310         instance
311             .get_typed_func::<(), (u64,)>(&mut store, "ret-u64")?
312             .call(&mut store, ())?,
313         (0,)
314     );
315     assert_eq!(
316         instance
317             .get_typed_func::<(), (i64,)>(&mut store, "ret-s64")?
318             .call(&mut store, ())?,
319         (0,)
320     );
321 
322     // Returning -1 should reinterpret the bytes as defined by each type.
323     assert_eq!(
324         instance
325             .get_typed_func::<(), (u8,)>(&mut store, "retm1-u8")?
326             .call(&mut store, ())?,
327         (0xff,)
328     );
329     assert_eq!(
330         instance
331             .get_typed_func::<(), (i8,)>(&mut store, "retm1-s8")?
332             .call(&mut store, ())?,
333         (-1,)
334     );
335     assert_eq!(
336         instance
337             .get_typed_func::<(), (u16,)>(&mut store, "retm1-u16")?
338             .call(&mut store, ())?,
339         (0xffff,)
340     );
341     assert_eq!(
342         instance
343             .get_typed_func::<(), (i16,)>(&mut store, "retm1-s16")?
344             .call(&mut store, ())?,
345         (-1,)
346     );
347     assert_eq!(
348         instance
349             .get_typed_func::<(), (u32,)>(&mut store, "retm1-u32")?
350             .call(&mut store, ())?,
351         (0xffffffff,)
352     );
353     assert_eq!(
354         instance
355             .get_typed_func::<(), (i32,)>(&mut store, "retm1-s32")?
356             .call(&mut store, ())?,
357         (-1,)
358     );
359     assert_eq!(
360         instance
361             .get_typed_func::<(), (u64,)>(&mut store, "retm1-u64")?
362             .call(&mut store, ())?,
363         (0xffffffff_ffffffff,)
364     );
365     assert_eq!(
366         instance
367             .get_typed_func::<(), (i64,)>(&mut store, "retm1-s64")?
368             .call(&mut store, ())?,
369         (-1,)
370     );
371 
372     // Returning 100000 should chop off bytes as necessary
373     let ret: u32 = 100000;
374     assert_eq!(
375         instance
376             .get_typed_func::<(), (u8,)>(&mut store, "retbig-u8")?
377             .call(&mut store, ())?,
378         (ret as u8,),
379     );
380     assert_eq!(
381         instance
382             .get_typed_func::<(), (i8,)>(&mut store, "retbig-s8")?
383             .call(&mut store, ())?,
384         (ret as i8,),
385     );
386     assert_eq!(
387         instance
388             .get_typed_func::<(), (u16,)>(&mut store, "retbig-u16")?
389             .call(&mut store, ())?,
390         (ret as u16,),
391     );
392     assert_eq!(
393         instance
394             .get_typed_func::<(), (i16,)>(&mut store, "retbig-s16")?
395             .call(&mut store, ())?,
396         (ret as i16,),
397     );
398     assert_eq!(
399         instance
400             .get_typed_func::<(), (u32,)>(&mut store, "retbig-u32")?
401             .call(&mut store, ())?,
402         (ret,),
403     );
404     assert_eq!(
405         instance
406             .get_typed_func::<(), (i32,)>(&mut store, "retbig-s32")?
407             .call(&mut store, ())?,
408         (ret as i32,),
409     );
410 
411     Ok(())
412 }
413 
414 #[test]
415 fn type_layers() -> Result<()> {
416     let component = r#"
417         (component
418             (core module $m
419                 (func (export "take-i32-100") (param i32)
420                     local.get 0
421                     i32.const 2
422                     i32.eq
423                     br_if 0
424                     unreachable
425                 )
426             )
427             (core instance $i (instantiate $m))
428             (func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))
429         )
430     "#;
431 
432     let engine = super::engine();
433     let component = Component::new(&engine, component)?;
434     let mut store = Store::new(&engine, ());
435     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
436 
437     instance
438         .get_typed_func::<(Box<u32>,), ()>(&mut store, "take-u32")?
439         .call(&mut store, (Box::new(2),))?;
440     instance
441         .get_typed_func::<(&u32,), ()>(&mut store, "take-u32")?
442         .call(&mut store, (&2,))?;
443     instance
444         .get_typed_func::<(Arc<u32>,), ()>(&mut store, "take-u32")?
445         .call(&mut store, (Arc::new(2),))?;
446     instance
447         .get_typed_func::<(&Box<Arc<Box<u32>>>,), ()>(&mut store, "take-u32")?
448         .call(&mut store, (&Box::new(Arc::new(Box::new(2))),))?;
449 
450     Ok(())
451 }
452 
453 #[test]
454 fn floats() -> Result<()> {
455     let component = r#"
456         (component
457             (core module $m
458                 (func (export "i32.reinterpret_f32") (param f32) (result i32)
459                     local.get 0
460                     i32.reinterpret_f32
461                 )
462                 (func (export "i64.reinterpret_f64") (param f64) (result i64)
463                     local.get 0
464                     i64.reinterpret_f64
465                 )
466                 (func (export "f32.reinterpret_i32") (param i32) (result f32)
467                     local.get 0
468                     f32.reinterpret_i32
469                 )
470                 (func (export "f64.reinterpret_i64") (param i64) (result f64)
471                     local.get 0
472                     f64.reinterpret_i64
473                 )
474             )
475             (core instance $i (instantiate $m))
476 
477             (func (export "f32-to-u32") (param "a" float32) (result u32)
478                 (canon lift (core func $i "i32.reinterpret_f32"))
479             )
480             (func (export "f64-to-u64") (param "a" float64) (result u64)
481                 (canon lift (core func $i "i64.reinterpret_f64"))
482             )
483             (func (export "u32-to-f32") (param "a" u32) (result float32)
484                 (canon lift (core func $i "f32.reinterpret_i32"))
485             )
486             (func (export "u64-to-f64") (param "a" u64) (result float64)
487                 (canon lift (core func $i "f64.reinterpret_i64"))
488             )
489         )
490     "#;
491 
492     let engine = super::engine();
493     let component = Component::new(&engine, component)?;
494     let mut store = Store::new(&engine, ());
495     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
496     let f32_to_u32 = instance.get_typed_func::<(f32,), (u32,)>(&mut store, "f32-to-u32")?;
497     let f64_to_u64 = instance.get_typed_func::<(f64,), (u64,)>(&mut store, "f64-to-u64")?;
498     let u32_to_f32 = instance.get_typed_func::<(u32,), (f32,)>(&mut store, "u32-to-f32")?;
499     let u64_to_f64 = instance.get_typed_func::<(u64,), (f64,)>(&mut store, "u64-to-f64")?;
500 
501     assert_eq!(f32_to_u32.call(&mut store, (1.0,))?, (1.0f32.to_bits(),));
502     assert_eq!(f64_to_u64.call(&mut store, (2.0,))?, (2.0f64.to_bits(),));
503     assert_eq!(u32_to_f32.call(&mut store, (3.0f32.to_bits(),))?, (3.0,));
504     assert_eq!(u64_to_f64.call(&mut store, (4.0f64.to_bits(),))?, (4.0,));
505 
506     assert_eq!(
507         u32_to_f32
508             .call(&mut store, (CANON_32BIT_NAN | 1,))?
509             .0
510             .to_bits(),
511         CANON_32BIT_NAN | 1
512     );
513     assert_eq!(
514         u64_to_f64
515             .call(&mut store, (CANON_64BIT_NAN | 1,))?
516             .0
517             .to_bits(),
518         CANON_64BIT_NAN | 1,
519     );
520 
521     assert_eq!(
522         f32_to_u32.call(&mut store, (f32::from_bits(CANON_32BIT_NAN | 1),))?,
523         (CANON_32BIT_NAN | 1,)
524     );
525     assert_eq!(
526         f64_to_u64.call(&mut store, (f64::from_bits(CANON_64BIT_NAN | 1),))?,
527         (CANON_64BIT_NAN | 1,)
528     );
529 
530     Ok(())
531 }
532 
533 #[test]
534 fn bools() -> Result<()> {
535     let component = r#"
536         (component
537             (core module $m
538                 (func (export "pass") (param i32) (result i32) local.get 0)
539             )
540             (core instance $i (instantiate $m))
541 
542             (func (export "u32-to-bool") (param "a" u32) (result bool)
543                 (canon lift (core func $i "pass"))
544             )
545             (func (export "bool-to-u32") (param "a" bool) (result u32)
546                 (canon lift (core func $i "pass"))
547             )
548         )
549     "#;
550 
551     let engine = super::engine();
552     let component = Component::new(&engine, component)?;
553     let mut store = Store::new(&engine, ());
554     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
555     let u32_to_bool = instance.get_typed_func::<(u32,), (bool,)>(&mut store, "u32-to-bool")?;
556     let bool_to_u32 = instance.get_typed_func::<(bool,), (u32,)>(&mut store, "bool-to-u32")?;
557 
558     assert_eq!(bool_to_u32.call(&mut store, (false,))?, (0,));
559     assert_eq!(bool_to_u32.call(&mut store, (true,))?, (1,));
560     assert_eq!(u32_to_bool.call(&mut store, (0,))?, (false,));
561     assert_eq!(u32_to_bool.call(&mut store, (1,))?, (true,));
562     assert_eq!(u32_to_bool.call(&mut store, (2,))?, (true,));
563 
564     Ok(())
565 }
566 
567 #[test]
568 fn chars() -> Result<()> {
569     let component = r#"
570         (component
571             (core module $m
572                 (func (export "pass") (param i32) (result i32) local.get 0)
573             )
574             (core instance $i (instantiate $m))
575 
576             (func (export "u32-to-char") (param "a" u32) (result char)
577                 (canon lift (core func $i "pass"))
578             )
579             (func (export "char-to-u32") (param "a" char) (result u32)
580                 (canon lift (core func $i "pass"))
581             )
582         )
583     "#;
584 
585     let engine = super::engine();
586     let component = Component::new(&engine, component)?;
587     let mut store = Store::new(&engine, ());
588     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
589     let u32_to_char = instance.get_typed_func::<(u32,), (char,)>(&mut store, "u32-to-char")?;
590     let char_to_u32 = instance.get_typed_func::<(char,), (u32,)>(&mut store, "char-to-u32")?;
591 
592     let mut roundtrip = |x: char| -> Result<()> {
593         assert_eq!(char_to_u32.call(&mut store, (x,))?, (x as u32,));
594         assert_eq!(u32_to_char.call(&mut store, (x as u32,))?, (x,));
595         Ok(())
596     };
597 
598     roundtrip('x')?;
599     roundtrip('a')?;
600     roundtrip('\0')?;
601     roundtrip('\n')?;
602     roundtrip('��')?;
603 
604     let u32_to_char = |store: &mut Store<()>| {
605         Linker::new(&engine)
606             .instantiate(&mut *store, &component)?
607             .get_typed_func::<(u32,), (char,)>(&mut *store, "u32-to-char")
608     };
609     let err = u32_to_char(&mut store)?
610         .call(&mut store, (0xd800,))
611         .unwrap_err();
612     assert!(err.to_string().contains("integer out of range"), "{}", err);
613     let err = u32_to_char(&mut store)?
614         .call(&mut store, (0xdfff,))
615         .unwrap_err();
616     assert!(err.to_string().contains("integer out of range"), "{}", err);
617     let err = u32_to_char(&mut store)?
618         .call(&mut store, (0x110000,))
619         .unwrap_err();
620     assert!(err.to_string().contains("integer out of range"), "{}", err);
621     let err = u32_to_char(&mut store)?
622         .call(&mut store, (u32::MAX,))
623         .unwrap_err();
624     assert!(err.to_string().contains("integer out of range"), "{}", err);
625 
626     Ok(())
627 }
628 
629 #[test]
630 fn tuple_result() -> Result<()> {
631     let component = r#"
632         (component
633             (core module $m
634                 (memory (export "memory") 1)
635                 (func (export "foo") (param i32 i32 f32 f64) (result i32)
636                     (local $base i32)
637                     (local.set $base (i32.const 8))
638                     (i32.store8 offset=0 (local.get $base) (local.get 0))
639                     (i32.store16 offset=2 (local.get $base) (local.get 1))
640                     (f32.store offset=4 (local.get $base) (local.get 2))
641                     (f64.store offset=8 (local.get $base) (local.get 3))
642                     local.get $base
643                 )
644 
645                 (func (export "invalid") (result i32)
646                     i32.const -8
647                 )
648             )
649             (core instance $i (instantiate $m))
650 
651             (type $result (tuple s8 u16 float32 float64))
652             (func (export "tuple")
653                 (param "a" s8) (param "b" u16) (param "c" float32) (param "d" float64) (result $result)
654                 (canon lift (core func $i "foo") (memory $i "memory"))
655             )
656             (func (export "invalid") (result $result)
657                 (canon lift (core func $i "invalid") (memory $i "memory"))
658             )
659         )
660     "#;
661 
662     let engine = super::engine();
663     let component = Component::new(&engine, component)?;
664     let mut store = Store::new(&engine, ());
665     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
666 
667     let input = (-1, 100, 3.0, 100.0);
668     let output = instance
669         .get_typed_func::<(i8, u16, f32, f64), ((i8, u16, f32, f64),)>(&mut store, "tuple")?
670         .call(&mut store, input)?;
671     assert_eq!((input,), output);
672 
673     let invalid_func =
674         instance.get_typed_func::<(), ((i8, u16, f32, f64),)>(&mut store, "invalid")?;
675     let err = invalid_func.call(&mut store, ()).err().unwrap();
676     assert!(
677         err.to_string().contains("pointer out of bounds of memory"),
678         "{}",
679         err
680     );
681 
682     Ok(())
683 }
684 
685 #[test]
686 fn strings() -> Result<()> {
687     let component = format!(
688         r#"(component
689             (core module $m
690                 (memory (export "memory") 1)
691                 (func (export "roundtrip") (param i32 i32) (result i32)
692                     (local $base i32)
693                     (local.set $base
694                         (call $realloc
695                             (i32.const 0)
696                             (i32.const 0)
697                             (i32.const 4)
698                             (i32.const 8)))
699                     (i32.store offset=0
700                         (local.get $base)
701                         (local.get 0))
702                     (i32.store offset=4
703                         (local.get $base)
704                         (local.get 1))
705                     (local.get $base)
706                 )
707 
708                 {REALLOC_AND_FREE}
709             )
710             (core instance $i (instantiate $m))
711 
712             (func (export "list8-to-str") (param "a" (list u8)) (result string)
713                 (canon lift
714                     (core func $i "roundtrip")
715                     (memory $i "memory")
716                     (realloc (func $i "realloc"))
717                 )
718             )
719             (func (export "str-to-list8") (param "a" string) (result (list u8))
720                 (canon lift
721                     (core func $i "roundtrip")
722                     (memory $i "memory")
723                     (realloc (func $i "realloc"))
724                 )
725             )
726             (func (export "list16-to-str") (param "a" (list u16)) (result string)
727                 (canon lift
728                     (core func $i "roundtrip")
729                     string-encoding=utf16
730                     (memory $i "memory")
731                     (realloc (func $i "realloc"))
732                 )
733             )
734             (func (export "str-to-list16") (param "a" string) (result (list u16))
735                 (canon lift
736                     (core func $i "roundtrip")
737                     string-encoding=utf16
738                     (memory $i "memory")
739                     (realloc (func $i "realloc"))
740                 )
741             )
742         )"#
743     );
744 
745     let engine = super::engine();
746     let component = Component::new(&engine, component)?;
747     let mut store = Store::new(&engine, ());
748     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
749     let list8_to_str =
750         instance.get_typed_func::<(&[u8],), (WasmStr,)>(&mut store, "list8-to-str")?;
751     let str_to_list8 =
752         instance.get_typed_func::<(&str,), (WasmList<u8>,)>(&mut store, "str-to-list8")?;
753     let list16_to_str =
754         instance.get_typed_func::<(&[u16],), (WasmStr,)>(&mut store, "list16-to-str")?;
755     let str_to_list16 =
756         instance.get_typed_func::<(&str,), (WasmList<u16>,)>(&mut store, "str-to-list16")?;
757 
758     let mut roundtrip = |x: &str| -> Result<()> {
759         let ret = list8_to_str.call(&mut store, (x.as_bytes(),))?.0;
760         assert_eq!(ret.to_str(&store)?, x);
761 
762         let utf16 = x.encode_utf16().collect::<Vec<_>>();
763         let ret = list16_to_str.call(&mut store, (&utf16[..],))?.0;
764         assert_eq!(ret.to_str(&store)?, x);
765 
766         let ret = str_to_list8.call(&mut store, (x,))?.0;
767         assert_eq!(
768             ret.iter(&mut store).collect::<Result<Vec<_>>>()?,
769             x.as_bytes()
770         );
771 
772         let ret = str_to_list16.call(&mut store, (x,))?.0;
773         assert_eq!(ret.iter(&mut store).collect::<Result<Vec<_>>>()?, utf16,);
774 
775         Ok(())
776     };
777 
778     roundtrip("")?;
779     roundtrip("foo")?;
780     roundtrip("hello there")?;
781     roundtrip("��")?;
782     roundtrip("Löwe 老虎 Léopard")?;
783 
784     let ret = list8_to_str.call(&mut store, (b"\xff",))?.0;
785     let err = ret.to_str(&store).unwrap_err();
786     assert!(err.to_string().contains("invalid utf-8"), "{}", err);
787 
788     let ret = list8_to_str
789         .call(&mut store, (b"hello there \xff invalid",))?
790         .0;
791     let err = ret.to_str(&store).unwrap_err();
792     assert!(err.to_string().contains("invalid utf-8"), "{}", err);
793 
794     let ret = list16_to_str.call(&mut store, (&[0xd800],))?.0;
795     let err = ret.to_str(&store).unwrap_err();
796     assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
797 
798     let ret = list16_to_str.call(&mut store, (&[0xdfff],))?.0;
799     let err = ret.to_str(&store).unwrap_err();
800     assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
801 
802     let ret = list16_to_str.call(&mut store, (&[0xd800, 0xff00],))?.0;
803     let err = ret.to_str(&store).unwrap_err();
804     assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
805 
806     Ok(())
807 }
808 
809 #[tokio::test]
810 async fn async_reentrance() -> Result<()> {
811     _ = env_logger::try_init();
812 
813     let component = r#"
814         (component
815             (core module $shim
816                 (import "" "task.return" (func $task-return (param i32)))
817                 (table (export "funcs") 1 1 funcref)
818                 (func (export "export") (param i32) (result i32)
819                     (call_indirect (i32.const 0) (local.get 0))
820                 )
821                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
822             )
823             (core func $task-return (canon task.return (result u32)))
824             (core instance $shim (instantiate $shim
825                 (with "" (instance (export "task.return" (func $task-return))))
826             ))
827             (func $shim-export (param "p1" u32) (result u32)
828                 (canon lift (core func $shim "export") async (callback (func $shim "callback")))
829             )
830 
831             (component $inner
832                 (import "import" (func $import (param "p1" u32) (result u32)))
833                 (core module $libc (memory (export "memory") 1))
834                 (core instance $libc (instantiate $libc))
835                 (core func $import (canon lower (func $import) async (memory $libc "memory")))
836 
837                 (core module $m
838                     (import "libc" "memory" (memory 1))
839                     (import "" "import" (func $import (param i32 i32) (result i32)))
840                     (import "" "task.return" (func $task-return (param i32)))
841                     (func (export "export") (param i32) (result i32)
842                         (i32.store offset=0 (i32.const 1200) (local.get 0))
843                         (call $import (i32.const 1200) (i32.const 1204))
844                         drop
845                         (call $task-return (i32.load offset=0 (i32.const 1204)))
846                         i32.const 0
847                     )
848                     (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
849                 )
850                 (core type $task-return-type (func (param i32)))
851                 (core func $task-return (canon task.return (result u32)))
852                 (core instance $i (instantiate $m
853                     (with "" (instance
854                         (export "task.return" (func $task-return))
855                         (export "import" (func $import))
856                     ))
857                     (with "libc" (instance $libc))
858                 ))
859                 (func (export "export") (param "p1" u32) (result u32)
860                     (canon lift (core func $i "export") async (callback (func $i "callback")))
861                 )
862             )
863             (instance $inner (instantiate $inner (with "import" (func $shim-export))))
864 
865             (core module $libc (memory (export "memory") 1))
866             (core instance $libc (instantiate $libc))
867             (core func $inner-export (canon lower (func $inner "export") async (memory $libc "memory")))
868 
869             (core module $donut
870                 (import "" "funcs" (table 1 1 funcref))
871                 (import "libc" "memory" (memory 1))
872                 (import "" "import" (func $import (param i32 i32) (result i32)))
873                 (import "" "task.return" (func $task-return (param i32)))
874                 (func $host-export (export "export") (param i32) (result i32)
875                     (i32.store offset=0 (i32.const 1200) (local.get 0))
876                     (call $import (i32.const 1200) (i32.const 1204))
877                     drop
878                     (call $task-return (i32.load offset=0 (i32.const 1204)))
879                     i32.const 0
880                 )
881                 (func $guest-export (export "guest-export") (param i32) (result i32) unreachable)
882                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
883                 (func $start
884                     (table.set (i32.const 0) (ref.func $guest-export))
885                 )
886                 (start $start)
887             )
888 
889             (core instance $donut (instantiate $donut
890                 (with "" (instance
891                     (export "task.return" (func $task-return))
892                     (export "import" (func $inner-export))
893                     (export "funcs" (table $shim "funcs"))
894                 ))
895                 (with "libc" (instance $libc))
896             ))
897             (func (export "export") (param "p1" u32) (result u32)
898                 (canon lift (core func $donut "export") async (callback (func $donut "callback")))
899             )
900         )"#;
901 
902     let mut config = Config::new();
903     config.wasm_component_model_async(true);
904     config.wasm_component_model_async_stackful(true);
905     config.wasm_component_model_threading(true);
906     let engine = &Engine::new(&config)?;
907     let component = Component::new(&engine, component)?;
908     let mut store = Store::new(&engine, ());
909 
910     let instance = Linker::new(&engine)
911         .instantiate_async(&mut store, &component)
912         .await?;
913     let func = instance.get_typed_func::<(u32,), (u32,)>(&mut store, "export")?;
914     let message = "cannot enter component instance";
915     match store
916         .run_concurrent(async move |accessor| {
917             wasmtime::error::Ok(func.call_concurrent(accessor, (42,)).await?.0)
918         })
919         .await
920     {
921         Ok(_) => panic!(),
922         Err(e) => assert!(
923             format!("{e:?}").contains(message),
924             "expected `{message}`; got `{e:?}`"
925         ),
926     }
927 
928     Ok(())
929 }
930 
931 #[tokio::test]
932 async fn missing_task_return_call_stackless() -> Result<()> {
933     task_return_trap(
934         r#"(component
935             (core module $m
936                 (import "" "task.return" (func $task-return))
937                 (func (export "foo") (result i32)
938                     i32.const 0
939                 )
940                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
941             )
942             (core func $task-return (canon task.return))
943             (core instance $i (instantiate $m
944                 (with "" (instance (export "task.return" (func $task-return))))
945             ))
946             (func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
947         )"#,
948         "wasm trap: async-lifted export failed to produce a result",
949     )
950     .await
951 }
952 
953 #[tokio::test]
954 async fn missing_task_return_call_stackless_explicit_thread() -> Result<()> {
955     task_return_trap(
956         r#"(component
957             (core module $libc
958                 (table (export "__indirect_function_table") 1 funcref))
959             (core module $m
960                 (import "" "task.return" (func $task-return))
961                 (import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32)))
962                 (import "" "thread.unsuspend" (func $thread-unsuspend (param i32)))
963                 (import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref))
964                 (func $thread-start (param i32) (; empty ;))
965                 (elem (table $indirect-function-table) (i32.const 0) func $thread-start)
966                 (func (export "foo") (result i32)
967                     (call $thread-unsuspend
968                         (call $thread-new-indirect (i32.const 0) (i32.const 0)))
969                     i32.const 0
970                 )
971                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
972             )
973             (core instance $libc (instantiate $libc))
974             (core type $start-func-ty (func (param i32)))
975             (alias core export $libc "__indirect_function_table" (core table $indirect-function-table))
976             (core func $thread-new-indirect
977                 (canon thread.new-indirect $start-func-ty (table $indirect-function-table)))
978             (core func $thread-unsuspend (canon thread.unsuspend))
979             (core func $task-return (canon task.return))
980             (core instance $i (instantiate $m
981                 (with "" (instance
982                     (export "thread.new-indirect" (func $thread-new-indirect))
983                     (export "thread.unsuspend" (func $thread-unsuspend))
984                     (export "task.return" (func $task-return))
985                 ))
986                 (with "libc" (instance $libc))
987             ))
988             (func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
989         )"#,
990         "wasm trap: async-lifted export failed to produce a result",
991     )
992     .await
993 }
994 
995 #[tokio::test]
996 async fn missing_task_return_call_stackful_explicit_thread() -> Result<()> {
997     task_return_trap(
998         r#"(component
999             (core module $libc
1000                 (table (export "__indirect_function_table") 1 funcref))
1001             (core module $m
1002                 (import "" "task.return" (func $task-return))
1003                 (import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32)))
1004                 (import "" "thread.unsuspend" (func $thread-unsuspend (param i32)))
1005                 (import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref))
1006                 (func $thread-start (param i32) (; empty ;))
1007                 (elem (table $indirect-function-table) (i32.const 0) func $thread-start)
1008                 (func (export "foo")
1009                     (call $thread-unsuspend
1010                         (call $thread-new-indirect (i32.const 0) (i32.const 0)))
1011                 )
1012             )
1013             (core instance $libc (instantiate $libc))
1014             (core type $start-func-ty (func (param i32)))
1015             (alias core export $libc "__indirect_function_table" (core table $indirect-function-table))
1016             (core func $thread-new-indirect
1017                 (canon thread.new-indirect $start-func-ty (table $indirect-function-table)))
1018             (core func $thread-unsuspend (canon thread.unsuspend))
1019             (core func $task-return (canon task.return))
1020             (core instance $i (instantiate $m
1021                 (with "" (instance
1022                     (export "thread.new-indirect" (func $thread-new-indirect))
1023                     (export "thread.unsuspend" (func $thread-unsuspend))
1024                     (export "task.return" (func $task-return))
1025                 ))
1026                 (with "libc" (instance $libc))
1027             ))
1028             (func (export "foo") (canon lift (core func $i "foo") async))
1029         )"#,
1030         "wasm trap: async-lifted export failed to produce a result",
1031     )
1032     .await
1033 }
1034 
1035 #[tokio::test]
1036 async fn missing_task_return_call_stackful() -> Result<()> {
1037     task_return_trap(
1038         r#"(component
1039             (core module $m
1040                 (import "" "task.return" (func $task-return))
1041                 (func (export "foo"))
1042             )
1043             (core func $task-return (canon task.return))
1044             (core instance $i (instantiate $m
1045                 (with "" (instance (export "task.return" (func $task-return))))
1046             ))
1047             (func (export "foo") (canon lift (core func $i "foo") async))
1048         )"#,
1049         "wasm trap: async-lifted export failed to produce a result",
1050     )
1051     .await
1052 }
1053 
1054 #[tokio::test]
1055 async fn task_return_type_mismatch() -> Result<()> {
1056     task_return_trap(
1057         r#"(component
1058             (core module $m
1059                 (import "" "task.return" (func $task-return (param i32)))
1060                 (func (export "foo") (call $task-return (i32.const 42)))
1061             )
1062             (core func $task-return (canon task.return (result u32)))
1063             (core instance $i (instantiate $m
1064                 (with "" (instance (export "task.return" (func $task-return))))
1065             ))
1066             (func (export "foo") (canon lift (core func $i "foo") async))
1067         )"#,
1068         "invalid `task.return` signature and/or options for current task",
1069     )
1070     .await
1071 }
1072 
1073 #[tokio::test]
1074 async fn task_return_memory_mismatch() -> Result<()> {
1075     task_return_trap(
1076         r#"(component
1077             (core module $libc (memory (export "memory") 1))
1078             (core instance $libc (instantiate $libc))
1079             (core module $m
1080                 (import "" "task.return" (func $task-return))
1081                 (func (export "foo") (call $task-return))
1082             )
1083             (core func $task-return (canon task.return (memory $libc "memory")))
1084             (core instance $i (instantiate $m
1085                 (with "" (instance (export "task.return" (func $task-return))))
1086             ))
1087             (func (export "foo") (canon lift (core func $i "foo") async))
1088         )"#,
1089         "invalid `task.return` signature and/or options for current task",
1090     )
1091     .await
1092 }
1093 
1094 #[tokio::test]
1095 async fn task_return_string_encoding_mismatch() -> Result<()> {
1096     task_return_trap(
1097         r#"(component
1098             (core module $m
1099                 (import "" "task.return" (func $task-return))
1100                 (func (export "foo") (call $task-return))
1101             )
1102             (core func $task-return (canon task.return string-encoding=utf16))
1103             (core instance $i (instantiate $m
1104                 (with "" (instance (export "task.return" (func $task-return))))
1105             ))
1106             (func (export "foo") (canon lift (core func $i "foo") async))
1107         )"#,
1108         "invalid `task.return` signature and/or options for current task",
1109     )
1110     .await
1111 }
1112 
1113 async fn task_return_trap(component: &str, substring: &str) -> Result<()> {
1114     let mut config = Config::new();
1115     config.wasm_component_model_async(true);
1116     config.wasm_component_model_async_stackful(true);
1117     config.wasm_component_model_threading(true);
1118     let engine = &Engine::new(&config)?;
1119     let component = Component::new(&engine, component)?;
1120     let mut store = Store::new(&engine, ());
1121 
1122     let instance = Linker::new(&engine)
1123         .instantiate_async(&mut store, &component)
1124         .await?;
1125 
1126     let func = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
1127     match store
1128         .run_concurrent(async move |accessor| {
1129             wasmtime::error::Ok(func.call_concurrent(accessor, ()).await?.0)
1130         })
1131         .await
1132     {
1133         Ok(_) => panic!(),
1134         Err(e) => {
1135             assert!(
1136                 format!("{e:?}").contains(substring),
1137                 "could not find `{substring}` in `{e:?}`"
1138             )
1139         }
1140     }
1141 
1142     Ok(())
1143 }
1144 
1145 #[tokio::test]
1146 async fn many_parameters() -> Result<()> {
1147     test_many_parameters(false, false).await
1148 }
1149 
1150 #[tokio::test]
1151 async fn many_parameters_concurrent() -> Result<()> {
1152     test_many_parameters(false, true).await
1153 }
1154 
1155 #[tokio::test]
1156 async fn many_parameters_dynamic() -> Result<()> {
1157     test_many_parameters(true, false).await
1158 }
1159 
1160 #[tokio::test]
1161 async fn many_parameters_dynamic_concurrent() -> Result<()> {
1162     test_many_parameters(true, true).await
1163 }
1164 
1165 async fn test_many_parameters(dynamic: bool, concurrent: bool) -> Result<()> {
1166     let (body, async_opts) = if concurrent {
1167         (
1168             r#"
1169                     (call $task-return
1170                         (i32.const 0)
1171                         (i32.mul
1172                             (memory.size)
1173                             (i32.const 65536)
1174                         )
1175                         (local.get 0)
1176                     )
1177 
1178                     (i32.const 0)
1179             "#,
1180             r#"async (callback (func $i "callback"))"#,
1181         )
1182     } else {
1183         (
1184             r#"
1185                     (local $base i32)
1186 
1187                     ;; Allocate space for the return
1188                     (local.set $base
1189                         (call $realloc
1190                             (i32.const 0)
1191                             (i32.const 0)
1192                             (i32.const 4)
1193                             (i32.const 12)))
1194 
1195                     ;; Store the pointer/length of the entire linear memory
1196                     ;; so we have access to everything.
1197                     (i32.store offset=0
1198                         (local.get $base)
1199                         (i32.const 0))
1200                     (i32.store offset=4
1201                         (local.get $base)
1202                         (i32.mul
1203                             (memory.size)
1204                             (i32.const 65536)))
1205 
1206                     ;; And also store our pointer parameter
1207                     (i32.store offset=8
1208                         (local.get $base)
1209                         (local.get 0))
1210 
1211                     (local.get $base)
1212             "#,
1213             "",
1214         )
1215     };
1216 
1217     let component = format!(
1218         r#"(component
1219             (core module $libc
1220                 (memory (export "memory") 1)
1221 
1222                 {REALLOC_AND_FREE}
1223             )
1224             (core instance $libc (instantiate $libc))
1225             (core module $m
1226                 (import "libc" "memory" (memory 1))
1227                 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1228                 (import "" "task.return" (func $task-return (param i32 i32 i32)))
1229                 (func (export "foo") (param i32) (result i32)
1230                     {body}
1231                 )
1232                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1233             )
1234             (type $tuple (tuple (list u8) u32))
1235             (core func $task-return (canon task.return
1236                 (result $tuple)
1237                 (memory $libc "memory")
1238             ))
1239             (core instance $i (instantiate $m
1240                 (with "" (instance (export "task.return" (func $task-return))))
1241                 (with "libc" (instance $libc))
1242             ))
1243 
1244             (type $t (func
1245                 (param "p1" s8)              ;; offset  0, size 1
1246                 (param "p2" u64)             ;; offset  8, size 8
1247                 (param "p3" float32)         ;; offset 16, size 4
1248                 (param "p4" u8)              ;; offset 20, size 1
1249                 (param "p5" s16)             ;; offset 22, size 2
1250                 (param "p6" string)          ;; offset 24, size 8
1251                 (param "p7" (list u32))      ;; offset 32, size 8
1252                 (param "p8" bool)            ;; offset 40, size 1
1253                 (param "p9" bool)            ;; offset 41, size 1
1254                 (param "p0" char)            ;; offset 44, size 4
1255                 (param "pa" (list bool))     ;; offset 48, size 8
1256                 (param "pb" (list char))     ;; offset 56, size 8
1257                 (param "pc" (list string))   ;; offset 64, size 8
1258 
1259                 (result $tuple)
1260             ))
1261             (func (export "many-param") (type $t)
1262                 (canon lift
1263                     (core func $i "foo")
1264                     (memory $libc "memory")
1265                     (realloc (func $libc "realloc"))
1266                     {async_opts}
1267                 )
1268             )
1269         )"#
1270     );
1271 
1272     let mut config = Config::new();
1273     config.wasm_component_model_async(true);
1274     let engine = &Engine::new(&config)?;
1275     let component = Component::new(&engine, component)?;
1276     let mut store = Store::new(&engine, ());
1277 
1278     let instance = Linker::new(&engine)
1279         .instantiate_async(&mut store, &component)
1280         .await?;
1281 
1282     let input = (
1283         -100,
1284         u64::MAX / 2,
1285         f32::from_bits(CANON_32BIT_NAN | 1),
1286         38,
1287         18831,
1288         "this is the first string",
1289         [1, 2, 3, 4, 5, 6, 7, 8].as_slice(),
1290         true,
1291         false,
1292         '��',
1293         [false, true, false, true, true].as_slice(),
1294         ['��', '��', '��', '��', '��'].as_slice(),
1295         [
1296             "the quick",
1297             "brown fox",
1298             "was too lazy",
1299             "to jump over the dog",
1300             "what a demanding dog",
1301         ]
1302         .as_slice(),
1303     );
1304 
1305     let (memory, pointer) = if dynamic {
1306         let input = vec![
1307             Val::S8(input.0),
1308             Val::U64(input.1),
1309             Val::Float32(input.2),
1310             Val::U8(input.3),
1311             Val::S16(input.4),
1312             Val::String(input.5.into()),
1313             Val::List(input.6.iter().copied().map(Val::U32).collect()),
1314             Val::Bool(input.7),
1315             Val::Bool(input.8),
1316             Val::Char(input.9),
1317             Val::List(input.10.iter().copied().map(Val::Bool).collect()),
1318             Val::List(input.11.iter().copied().map(Val::Char).collect()),
1319             Val::List(input.12.iter().map(|&s| Val::String(s.into())).collect()),
1320         ];
1321         let func = instance.get_func(&mut store, "many-param").unwrap();
1322 
1323         let mut results = vec![Val::Bool(false)];
1324         if concurrent {
1325             store
1326                 .run_concurrent(async |store| {
1327                     func.call_concurrent(store, &input, &mut results).await?;
1328                     wasmtime::error::Ok(())
1329                 })
1330                 .await??;
1331         } else {
1332             func.call_async(&mut store, &input, &mut results).await?;
1333         };
1334         let mut results = results.into_iter();
1335         let Some(Val::Tuple(results)) = results.next() else {
1336             panic!()
1337         };
1338         let mut results = results.into_iter();
1339         let Some(Val::List(memory)) = results.next() else {
1340             panic!()
1341         };
1342         let Some(Val::U32(pointer)) = results.next() else {
1343             panic!()
1344         };
1345         (
1346             memory
1347                 .into_iter()
1348                 .map(|v| if let Val::U8(v) = v { v } else { panic!() })
1349                 .collect(),
1350             pointer,
1351         )
1352     } else {
1353         let func = instance.get_typed_func::<(
1354             i8,
1355             u64,
1356             f32,
1357             u8,
1358             i16,
1359             &str,
1360             &[u32],
1361             bool,
1362             bool,
1363             char,
1364             &[bool],
1365             &[char],
1366             &[&str],
1367         ), ((Vec<u8>, u32),)>(&mut store, "many-param")?;
1368 
1369         if concurrent {
1370             store
1371                 .run_concurrent(async move |accessor| {
1372                     wasmtime::error::Ok(func.call_concurrent(accessor, input).await?.0)
1373                 })
1374                 .await??
1375                 .0
1376         } else {
1377             func.call_async(&mut store, input).await?.0
1378         }
1379     };
1380     let memory = &memory[..];
1381 
1382     let mut actual = &memory[pointer as usize..][..72];
1383     assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0);
1384     actual.skip::<7>();
1385     assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1);
1386     assert_eq!(
1387         u32::from_le_bytes(*actual.take_n::<4>()),
1388         CANON_32BIT_NAN | 1
1389     );
1390     assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3);
1391     actual.skip::<1>();
1392     assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4);
1393     assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes());
1394     let mut mem = actual.ptr_len(memory, 4);
1395     for expected in input.6.iter() {
1396         assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected);
1397     }
1398     assert!(mem.is_empty());
1399     assert_eq!(actual.take_n::<1>(), &[input.7 as u8]);
1400     assert_eq!(actual.take_n::<1>(), &[input.8 as u8]);
1401     actual.skip::<2>();
1402     assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32);
1403 
1404     // (list bool)
1405     mem = actual.ptr_len(memory, 1);
1406     for expected in input.10.iter() {
1407         assert_eq!(mem.take_n::<1>(), &[*expected as u8]);
1408     }
1409     assert!(mem.is_empty());
1410 
1411     // (list char)
1412     mem = actual.ptr_len(memory, 4);
1413     for expected in input.11.iter() {
1414         assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32);
1415     }
1416     assert!(mem.is_empty());
1417 
1418     // (list string)
1419     mem = actual.ptr_len(memory, 8);
1420     for expected in input.12.iter() {
1421         let actual = mem.ptr_len(memory, 1);
1422         assert_eq!(actual, expected.as_bytes());
1423     }
1424     assert!(mem.is_empty());
1425     assert!(actual.is_empty());
1426 
1427     Ok(())
1428 }
1429 
1430 #[tokio::test]
1431 async fn many_results() -> Result<()> {
1432     test_many_results(false, false).await
1433 }
1434 
1435 #[tokio::test]
1436 async fn many_results_concurrent() -> Result<()> {
1437     test_many_results(false, true).await
1438 }
1439 
1440 #[tokio::test]
1441 async fn many_results_dynamic() -> Result<()> {
1442     test_many_results(true, false).await
1443 }
1444 
1445 #[tokio::test]
1446 async fn many_results_dynamic_concurrent() -> Result<()> {
1447     test_many_results(true, true).await
1448 }
1449 
1450 async fn test_many_results(dynamic: bool, concurrent: bool) -> Result<()> {
1451     let (ret, async_opts) = if concurrent {
1452         (
1453             r#"
1454                    call $task-return
1455                    i32.const 0
1456             "#,
1457             r#"async (callback (func $i "callback"))"#,
1458         )
1459     } else {
1460         ("", "")
1461     };
1462 
1463     let my_nan = CANON_32BIT_NAN | 1;
1464 
1465     let component = format!(
1466         r#"(component
1467             (core module $libc
1468                 (memory (export "memory") 1)
1469 
1470                 {REALLOC_AND_FREE}
1471             )
1472             (core instance $libc (instantiate $libc))
1473             (core module $m
1474                 (import "libc" "memory" (memory 1))
1475                 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1476                 (import "" "task.return" (func $task-return (param i32)))
1477                 (func (export "foo") (result i32)
1478                     (local $base i32)
1479                     (local $string i32)
1480                     (local $list i32)
1481 
1482                     (local.set $base
1483                         (call $realloc
1484                             (i32.const 0)
1485                             (i32.const 0)
1486                             (i32.const 8)
1487                             (i32.const 72)))
1488 
1489                     (i32.store8 offset=0
1490                         (local.get $base)
1491                         (i32.const -100))
1492 
1493                     (i64.store offset=8
1494                         (local.get $base)
1495                         (i64.const 9223372036854775807))
1496 
1497                     (f32.store offset=16
1498                         (local.get $base)
1499                         (f32.reinterpret_i32 (i32.const {my_nan})))
1500 
1501                     (i32.store8 offset=20
1502                         (local.get $base)
1503                         (i32.const 38))
1504 
1505                     (i32.store16 offset=22
1506                         (local.get $base)
1507                         (i32.const 18831))
1508 
1509                     (local.set $string
1510                         (call $realloc
1511                             (i32.const 0)
1512                             (i32.const 0)
1513                             (i32.const 1)
1514                             (i32.const 6)))
1515 
1516                     (i32.store8 offset=0
1517                         (local.get $string)
1518                         (i32.const 97)) ;; 'a'
1519                     (i32.store8 offset=1
1520                         (local.get $string)
1521                         (i32.const 98)) ;; 'b'
1522                     (i32.store8 offset=2
1523                         (local.get $string)
1524                         (i32.const 99)) ;; 'c'
1525                     (i32.store8 offset=3
1526                         (local.get $string)
1527                         (i32.const 100)) ;; 'd'
1528                     (i32.store8 offset=4
1529                         (local.get $string)
1530                         (i32.const 101)) ;; 'e'
1531                     (i32.store8 offset=5
1532                         (local.get $string)
1533                         (i32.const 102)) ;; 'f'
1534 
1535                     (i32.store offset=24
1536                         (local.get $base)
1537                         (local.get $string))
1538 
1539                     (i32.store offset=28
1540                         (local.get $base)
1541                         (i32.const 2))
1542 
1543                     (local.set $list
1544                         (call $realloc
1545                             (i32.const 0)
1546                             (i32.const 0)
1547                             (i32.const 4)
1548                             (i32.const 32)))
1549 
1550                     (i32.store offset=0
1551                         (local.get $list)
1552                         (i32.const 1))
1553                     (i32.store offset=4
1554                         (local.get $list)
1555                         (i32.const 2))
1556                     (i32.store offset=8
1557                         (local.get $list)
1558                         (i32.const 3))
1559                     (i32.store offset=12
1560                         (local.get $list)
1561                         (i32.const 4))
1562                     (i32.store offset=16
1563                         (local.get $list)
1564                         (i32.const 5))
1565                     (i32.store offset=20
1566                         (local.get $list)
1567                         (i32.const 6))
1568                     (i32.store offset=24
1569                         (local.get $list)
1570                         (i32.const 7))
1571                     (i32.store offset=28
1572                         (local.get $list)
1573                         (i32.const 8))
1574 
1575                     (i32.store offset=32
1576                         (local.get $base)
1577                         (local.get $list))
1578 
1579                     (i32.store offset=36
1580                         (local.get $base)
1581                         (i32.const 8))
1582 
1583                     (i32.store8 offset=40
1584                         (local.get $base)
1585                         (i32.const 1))
1586 
1587                     (i32.store8 offset=41
1588                         (local.get $base)
1589                         (i32.const 0))
1590 
1591                     (i32.store offset=44
1592                         (local.get $base)
1593                         (i32.const 128681)) ;; '��'
1594 
1595                     (local.set $list
1596                         (call $realloc
1597                             (i32.const 0)
1598                             (i32.const 0)
1599                             (i32.const 1)
1600                             (i32.const 5)))
1601 
1602                     (i32.store8 offset=0
1603                         (local.get $list)
1604                         (i32.const 0))
1605                     (i32.store8 offset=1
1606                         (local.get $list)
1607                         (i32.const 1))
1608                     (i32.store8 offset=2
1609                         (local.get $list)
1610                         (i32.const 0))
1611                     (i32.store8 offset=3
1612                         (local.get $list)
1613                         (i32.const 1))
1614                     (i32.store8 offset=4
1615                         (local.get $list)
1616                         (i32.const 1))
1617 
1618                     (i32.store offset=48
1619                         (local.get $base)
1620                         (local.get $list))
1621 
1622                     (i32.store offset=52
1623                         (local.get $base)
1624                         (i32.const 5))
1625 
1626                     (local.set $list
1627                         (call $realloc
1628                             (i32.const 0)
1629                             (i32.const 0)
1630                             (i32.const 4)
1631                             (i32.const 20)))
1632 
1633                     (i32.store offset=0
1634                         (local.get $list)
1635                         (i32.const 127820)) ;; '��'
1636                     (i32.store offset=4
1637                         (local.get $list)
1638                         (i32.const 129360)) ;; '��'
1639                     (i32.store offset=8
1640                         (local.get $list)
1641                         (i32.const 127831)) ;; '��'
1642                     (i32.store offset=12
1643                         (local.get $list)
1644                         (i32.const 127833)) ;; '��'
1645                     (i32.store offset=16
1646                         (local.get $list)
1647                         (i32.const 127841)) ;; '��'
1648 
1649                     (i32.store offset=56
1650                         (local.get $base)
1651                         (local.get $list))
1652 
1653                     (i32.store offset=60
1654                         (local.get $base)
1655                         (i32.const 5))
1656 
1657                     (local.set $list
1658                         (call $realloc
1659                             (i32.const 0)
1660                             (i32.const 0)
1661                             (i32.const 4)
1662                             (i32.const 16)))
1663 
1664                     (i32.store offset=0
1665                         (local.get $list)
1666                         (i32.add (local.get $string) (i32.const 2)))
1667                     (i32.store offset=4
1668                         (local.get $list)
1669                         (i32.const 2))
1670                     (i32.store offset=8
1671                         (local.get $list)
1672                         (i32.add (local.get $string) (i32.const 4)))
1673                     (i32.store offset=12
1674                         (local.get $list)
1675                         (i32.const 2))
1676 
1677                     (i32.store offset=64
1678                         (local.get $base)
1679                         (local.get $list))
1680 
1681                     (i32.store offset=68
1682                         (local.get $base)
1683                         (i32.const 2))
1684 
1685                     local.get $base
1686 
1687                     {ret}
1688                 )
1689                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1690             )
1691             (type $tuple (tuple
1692                 s8
1693                 u64
1694                 float32
1695                 u8
1696                 s16
1697                 string
1698                 (list u32)
1699                 bool
1700                 bool
1701                 char
1702                 (list bool)
1703                 (list char)
1704                 (list string)
1705             ))
1706             (core func $task-return (canon task.return
1707                 (result $tuple)
1708                 (memory $libc "memory")
1709             ))
1710             (core instance $i (instantiate $m
1711                 (with "" (instance (export "task.return" (func $task-return))))
1712                 (with "libc" (instance $libc))
1713             ))
1714 
1715             (type $t (func (result $tuple)))
1716             (func (export "many-results") (type $t)
1717                 (canon lift
1718                     (core func $i "foo")
1719                     (memory $libc "memory")
1720                     (realloc (func $libc "realloc"))
1721                     {async_opts}
1722                 )
1723             )
1724         )"#
1725     );
1726 
1727     let mut config = Config::new();
1728     config.wasm_component_model_async(true);
1729     let engine = &Engine::new(&config)?;
1730     let component = Component::new(&engine, component)?;
1731     let mut store = Store::new(&engine, ());
1732 
1733     let instance = Linker::new(&engine)
1734         .instantiate_async(&mut store, &component)
1735         .await?;
1736 
1737     let expected = (
1738         -100i8,
1739         u64::MAX / 2,
1740         f32::from_bits(CANON_32BIT_NAN | 1),
1741         38u8,
1742         18831i16,
1743         "ab".to_string(),
1744         vec![1u32, 2, 3, 4, 5, 6, 7, 8],
1745         true,
1746         false,
1747         '��',
1748         vec![false, true, false, true, true],
1749         vec!['��', '��', '��', '��', '��'],
1750         vec!["cd".to_string(), "ef".to_string()],
1751     );
1752 
1753     let actual = if dynamic {
1754         let func = instance.get_func(&mut store, "many-results").unwrap();
1755 
1756         let mut results = vec![Val::Bool(false)];
1757         if concurrent {
1758             store
1759                 .run_concurrent(async |store| {
1760                     func.call_concurrent(store, &[], &mut results).await?;
1761                     wasmtime::error::Ok(())
1762                 })
1763                 .await??;
1764         } else {
1765             func.call_async(&mut store, &[], &mut results).await?;
1766         };
1767         let mut results = results.into_iter();
1768 
1769         let Some(Val::Tuple(results)) = results.next() else {
1770             panic!()
1771         };
1772         let mut results = results.into_iter();
1773         let Some(Val::S8(p1)) = results.next() else {
1774             panic!()
1775         };
1776         let Some(Val::U64(p2)) = results.next() else {
1777             panic!()
1778         };
1779         let Some(Val::Float32(p3)) = results.next() else {
1780             panic!()
1781         };
1782         let Some(Val::U8(p4)) = results.next() else {
1783             panic!()
1784         };
1785         let Some(Val::S16(p5)) = results.next() else {
1786             panic!()
1787         };
1788         let Some(Val::String(p6)) = results.next() else {
1789             panic!()
1790         };
1791         let Some(Val::List(p7)) = results.next() else {
1792             panic!()
1793         };
1794         let p7 = p7
1795             .into_iter()
1796             .map(|v| if let Val::U32(v) = v { v } else { panic!() })
1797             .collect();
1798         let Some(Val::Bool(p8)) = results.next() else {
1799             panic!()
1800         };
1801         let Some(Val::Bool(p9)) = results.next() else {
1802             panic!()
1803         };
1804         let Some(Val::Char(p0)) = results.next() else {
1805             panic!()
1806         };
1807         let Some(Val::List(pa)) = results.next() else {
1808             panic!()
1809         };
1810         let pa = pa
1811             .into_iter()
1812             .map(|v| if let Val::Bool(v) = v { v } else { panic!() })
1813             .collect();
1814         let Some(Val::List(pb)) = results.next() else {
1815             panic!()
1816         };
1817         let pb = pb
1818             .into_iter()
1819             .map(|v| if let Val::Char(v) = v { v } else { panic!() })
1820             .collect();
1821         let Some(Val::List(pc)) = results.next() else {
1822             panic!()
1823         };
1824         let pc = pc
1825             .into_iter()
1826             .map(|v| if let Val::String(v) = v { v } else { panic!() })
1827             .collect();
1828 
1829         (p1, p2, p3, p4, p5, p6, p7, p8, p9, p0, pa, pb, pc)
1830     } else {
1831         let func = instance.get_typed_func::<(), ((
1832             i8,
1833             u64,
1834             f32,
1835             u8,
1836             i16,
1837             String,
1838             Vec<u32>,
1839             bool,
1840             bool,
1841             char,
1842             Vec<bool>,
1843             Vec<char>,
1844             Vec<String>,
1845         ),)>(&mut store, "many-results")?;
1846 
1847         if concurrent {
1848             store
1849                 .run_concurrent(async move |accessor| {
1850                     wasmtime::error::Ok(func.call_concurrent(accessor, ()).await?.0)
1851                 })
1852                 .await??
1853                 .0
1854         } else {
1855             func.call_async(&mut store, ()).await?.0
1856         }
1857     };
1858 
1859     assert_eq!(expected.0, actual.0);
1860     assert_eq!(expected.1, actual.1);
1861     assert!(expected.2.is_nan());
1862     assert!(actual.2.is_nan());
1863     assert_eq!(expected.3, actual.3);
1864     assert_eq!(expected.4, actual.4);
1865     assert_eq!(expected.5, actual.5);
1866     assert_eq!(expected.6, actual.6);
1867     assert_eq!(expected.7, actual.7);
1868     assert_eq!(expected.8, actual.8);
1869     assert_eq!(expected.9, actual.9);
1870     assert_eq!(expected.10, actual.10);
1871     assert_eq!(expected.11, actual.11);
1872     assert_eq!(expected.12, actual.12);
1873 
1874     Ok(())
1875 }
1876 
1877 #[test]
1878 fn some_traps() -> Result<()> {
1879     let middle_of_memory = (i32::MAX / 2) & (!0xff);
1880     let component = format!(
1881         r#"(component
1882             (core module $m
1883                 (memory (export "memory") 1)
1884                 (func (export "take-many") (param i32))
1885                 (func (export "take-list") (param i32 i32))
1886 
1887                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1888                     unreachable)
1889             )
1890             (core instance $i (instantiate $m))
1891 
1892             (func (export "take-list-unreachable") (param "a" (list u8))
1893                 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1894             )
1895             (func (export "take-string-unreachable") (param "a" string)
1896                 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1897             )
1898 
1899             (type $t (func
1900                 (param "s1" string)
1901                 (param "s2" string)
1902                 (param "s3" string)
1903                 (param "s4" string)
1904                 (param "s5" string)
1905                 (param "s6" string)
1906                 (param "s7" string)
1907                 (param "s8" string)
1908                 (param "s9" string)
1909                 (param "s10" string)
1910             ))
1911             (func (export "take-many-unreachable") (type $t)
1912                 (canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc")))
1913             )
1914 
1915             (core module $m2
1916                 (memory (export "memory") 1)
1917                 (func (export "take-many") (param i32))
1918                 (func (export "take-list") (param i32 i32))
1919 
1920                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1921                     i32.const {middle_of_memory})
1922             )
1923             (core instance $i2 (instantiate $m2))
1924 
1925             (func (export "take-list-base-oob") (param "a" (list u8))
1926                 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1927             )
1928             (func (export "take-string-base-oob") (param "a" string)
1929                 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1930             )
1931             (func (export "take-many-base-oob") (type $t)
1932                 (canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1933             )
1934 
1935             (core module $m3
1936                 (memory (export "memory") 1)
1937                 (func (export "take-many") (param i32))
1938                 (func (export "take-list") (param i32 i32))
1939 
1940                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1941                     i32.const 65532)
1942             )
1943             (core instance $i3 (instantiate $m3))
1944 
1945             (func (export "take-list-end-oob") (param "a" (list u8))
1946                 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1947             )
1948             (func (export "take-string-end-oob") (param "a" string)
1949                 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1950             )
1951             (func (export "take-many-end-oob") (type $t)
1952                 (canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1953             )
1954 
1955             (core module $m4
1956                 (memory (export "memory") 1)
1957                 (func (export "take-many") (param i32))
1958 
1959                 (global $cnt (mut i32) (i32.const 0))
1960                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1961                     global.get $cnt
1962                     if (result i32)
1963                         i32.const 100000
1964                     else
1965                         i32.const 1
1966                         global.set $cnt
1967                         i32.const 0
1968                     end
1969                 )
1970             )
1971             (core instance $i4 (instantiate $m4))
1972 
1973             (func (export "take-many-second-oob") (type $t)
1974                 (canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc")))
1975             )
1976         )"#
1977     );
1978 
1979     let engine = super::engine();
1980     let component = Component::new(&engine, component)?;
1981 
1982     // This should fail when calling the allocator function for the argument
1983     let err = with_new_instance(&engine, &component, |store, instance| {
1984         instance
1985             .get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-unreachable")?
1986             .call(store, (&[],))
1987             .unwrap_err()
1988             .downcast::<Trap>()
1989     })?;
1990     assert_eq!(err, Trap::UnreachableCodeReached);
1991 
1992     // This should fail when calling the allocator function for the argument
1993     let err = with_new_instance(&engine, &component, |store, instance| {
1994         instance
1995             .get_typed_func::<(&str,), ()>(&mut *store, "take-string-unreachable")?
1996             .call(store, ("",))
1997             .unwrap_err()
1998             .downcast::<Trap>()
1999     })?;
2000     assert_eq!(err, Trap::UnreachableCodeReached);
2001 
2002     // This should fail when calling the allocator function for the space
2003     // to store the arguments (before arguments are even lowered)
2004     let err = with_new_instance(&engine, &component, |store, instance| {
2005         instance
2006             .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2007                 &mut *store,
2008                 "take-many-unreachable",
2009             )?
2010             .call(store, ("", "", "", "", "", "", "", "", "", ""))
2011             .unwrap_err()
2012             .downcast::<Trap>()
2013     })?;
2014     assert_eq!(err, Trap::UnreachableCodeReached);
2015 
2016     // Assert that when the base pointer returned by malloc is out of bounds
2017     // that errors are reported as such. Both empty and lists with contents
2018     // should all be invalid here.
2019     //
2020     // FIXME(WebAssembly/component-model#32) confirm the semantics here are
2021     // what's desired.
2022     #[track_caller]
2023     fn assert_oob(err: &wasmtime::Error) {
2024         assert!(
2025             err.to_string()
2026                 .contains("realloc return: beyond end of memory"),
2027             "{err:?}",
2028         );
2029     }
2030     let err = with_new_instance(&engine, &component, |store, instance| {
2031         instance
2032             .get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-base-oob")?
2033             .call(store, (&[],))
2034     })
2035     .unwrap_err();
2036     assert_oob(&err);
2037     let err = with_new_instance(&engine, &component, |store, instance| {
2038         instance
2039             .get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-base-oob")?
2040             .call(store, (&[1],))
2041     })
2042     .unwrap_err();
2043     assert_oob(&err);
2044     let err = with_new_instance(&engine, &component, |store, instance| {
2045         instance
2046             .get_typed_func::<(&str,), ()>(&mut *store, "take-string-base-oob")?
2047             .call(store, ("",))
2048     })
2049     .unwrap_err();
2050     assert_oob(&err);
2051     let err = with_new_instance(&engine, &component, |store, instance| {
2052         instance
2053             .get_typed_func::<(&str,), ()>(&mut *store, "take-string-base-oob")?
2054             .call(store, ("x",))
2055     })
2056     .unwrap_err();
2057     assert_oob(&err);
2058     let err = with_new_instance(&engine, &component, |store, instance| {
2059         instance
2060             .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2061                 &mut *store,
2062                 "take-many-base-oob",
2063             )?
2064             .call(store, ("", "", "", "", "", "", "", "", "", ""))
2065     })
2066     .unwrap_err();
2067     assert_oob(&err);
2068 
2069     // Test here that when the returned pointer from malloc is one byte from the
2070     // end of memory that empty things are fine, but larger things are not.
2071 
2072     with_new_instance(&engine, &component, |store, instance| {
2073         instance
2074             .get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-end-oob")?
2075             .call(store, (&[],))
2076     })?;
2077     with_new_instance(&engine, &component, |store, instance| {
2078         instance
2079             .get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-end-oob")?
2080             .call(store, (&[1, 2, 3, 4],))
2081     })?;
2082     let err = with_new_instance(&engine, &component, |store, instance| {
2083         instance
2084             .get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-end-oob")?
2085             .call(store, (&[1, 2, 3, 4, 5],))
2086     })
2087     .unwrap_err();
2088     assert_oob(&err);
2089     with_new_instance(&engine, &component, |store, instance| {
2090         instance
2091             .get_typed_func::<(&str,), ()>(&mut *store, "take-string-end-oob")?
2092             .call(store, ("",))
2093     })?;
2094     with_new_instance(&engine, &component, |store, instance| {
2095         instance
2096             .get_typed_func::<(&str,), ()>(&mut *store, "take-string-end-oob")?
2097             .call(store, ("abcd",))
2098     })?;
2099     let err = with_new_instance(&engine, &component, |store, instance| {
2100         instance
2101             .get_typed_func::<(&str,), ()>(&mut *store, "take-string-end-oob")?
2102             .call(store, ("abcde",))
2103     })
2104     .unwrap_err();
2105     assert_oob(&err);
2106     let err = with_new_instance(&engine, &component, |store, instance| {
2107         instance
2108             .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2109                 &mut *store,
2110                 "take-many-end-oob",
2111             )?
2112             .call(store, ("", "", "", "", "", "", "", "", "", ""))
2113     })
2114     .unwrap_err();
2115     assert_oob(&err);
2116 
2117     // For this function the first allocation, the space to store all the
2118     // arguments, is in-bounds but then all further allocations, such as for
2119     // each individual string, are all out of bounds.
2120     let err = with_new_instance(&engine, &component, |store, instance| {
2121         instance
2122             .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2123                 &mut *store,
2124                 "take-many-second-oob",
2125             )?
2126             .call(store, ("", "", "", "", "", "", "", "", "", ""))
2127     })
2128     .unwrap_err();
2129     assert_oob(&err);
2130     let err = with_new_instance(&engine, &component, |store, instance| {
2131         instance
2132             .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2133                 &mut *store,
2134                 "take-many-second-oob",
2135             )?
2136             .call(store, ("", "", "", "", "", "", "", "", "", "x"))
2137     })
2138     .unwrap_err();
2139     assert_oob(&err);
2140     Ok(())
2141 }
2142 
2143 #[test]
2144 fn char_bool_memory() -> Result<()> {
2145     let component = format!(
2146         r#"(component
2147             (core module $m
2148                 (memory (export "memory") 1)
2149                 (func (export "ret-tuple") (param i32 i32) (result i32)
2150                     (local $base i32)
2151 
2152                     ;; Allocate space for the return
2153                     (local.set $base
2154                         (call $realloc
2155                             (i32.const 0)
2156                             (i32.const 0)
2157                             (i32.const 4)
2158                             (i32.const 8)))
2159 
2160                     ;; store the boolean
2161                     (i32.store offset=0
2162                         (local.get $base)
2163                         (local.get 0))
2164 
2165                     ;; store the char
2166                     (i32.store offset=4
2167                         (local.get $base)
2168                         (local.get 1))
2169 
2170                     (local.get $base)
2171                 )
2172 
2173                 {REALLOC_AND_FREE}
2174             )
2175             (core instance $i (instantiate $m))
2176 
2177             (func (export "ret-tuple") (param "a" u32) (param "b" u32) (result (tuple bool char))
2178                 (canon lift (core func $i "ret-tuple")
2179                     (memory $i "memory")
2180                     (realloc (func $i "realloc")))
2181             )
2182         )"#
2183     );
2184 
2185     let engine = super::engine();
2186     let component = Component::new(&engine, component)?;
2187     let mut store = Store::new(&engine, ());
2188     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2189     let func = instance.get_typed_func::<(u32, u32), ((bool, char),)>(&mut store, "ret-tuple")?;
2190 
2191     let (ret,) = func.call(&mut store, (0, 'a' as u32))?;
2192     assert_eq!(ret, (false, 'a'));
2193 
2194     let (ret,) = func.call(&mut store, (1, '��' as u32))?;
2195     assert_eq!(ret, (true, '��'));
2196 
2197     let (ret,) = func.call(&mut store, (2, 'a' as u32))?;
2198     assert_eq!(ret, (true, 'a'));
2199 
2200     assert!(func.call(&mut store, (0, 0xd800)).is_err());
2201 
2202     Ok(())
2203 }
2204 
2205 #[test]
2206 fn string_list_oob() -> Result<()> {
2207     let component = format!(
2208         r#"(component
2209             (core module $m
2210                 (memory (export "memory") 1)
2211                 (func (export "ret-list") (result i32)
2212                     (local $base i32)
2213 
2214                     ;; Allocate space for the return
2215                     (local.set $base
2216                         (call $realloc
2217                             (i32.const 0)
2218                             (i32.const 0)
2219                             (i32.const 4)
2220                             (i32.const 8)))
2221 
2222                     (i32.store offset=0
2223                         (local.get $base)
2224                         (i32.const 100000))
2225                     (i32.store offset=4
2226                         (local.get $base)
2227                         (i32.const 1))
2228 
2229                     (local.get $base)
2230                 )
2231 
2232                 {REALLOC_AND_FREE}
2233             )
2234             (core instance $i (instantiate $m))
2235 
2236             (func (export "ret-list-u8") (result (list u8))
2237                 (canon lift (core func $i "ret-list")
2238                     (memory $i "memory")
2239                     (realloc (func $i "realloc"))
2240                 )
2241             )
2242             (func (export "ret-string") (result string)
2243                 (canon lift (core func $i "ret-list")
2244                     (memory $i "memory")
2245                     (realloc (func $i "realloc"))
2246                 )
2247             )
2248         )"#
2249     );
2250 
2251     let engine = super::engine();
2252     let component = Component::new(&engine, component)?;
2253     let mut store = Store::new(&engine, ());
2254     let ret_list_u8 = Linker::new(&engine)
2255         .instantiate(&mut store, &component)?
2256         .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?;
2257     let ret_string = Linker::new(&engine)
2258         .instantiate(&mut store, &component)?
2259         .get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?;
2260 
2261     let err = ret_list_u8.call(&mut store, ()).err().unwrap();
2262     assert!(err.to_string().contains("out of bounds"), "{}", err);
2263 
2264     let err = ret_string.call(&mut store, ()).err().unwrap();
2265     assert!(err.to_string().contains("out of bounds"), "{}", err);
2266 
2267     Ok(())
2268 }
2269 
2270 #[test]
2271 fn tuples() -> Result<()> {
2272     let component = format!(
2273         r#"(component
2274             (core module $m
2275                 (memory (export "memory") 1)
2276                 (func (export "foo")
2277                     (param i32 f64 i32)
2278                     (result i32)
2279 
2280                     local.get 0
2281                     i32.const 0
2282                     i32.ne
2283                     if unreachable end
2284 
2285                     local.get 1
2286                     f64.const 1
2287                     f64.ne
2288                     if unreachable end
2289 
2290                     local.get 2
2291                     i32.const 2
2292                     i32.ne
2293                     if unreachable end
2294 
2295                     i32.const 3
2296                 )
2297             )
2298             (core instance $i (instantiate $m))
2299 
2300             (func (export "foo")
2301                 (param "a" (tuple s32 float64))
2302                 (param "b" (tuple s8))
2303                 (result (tuple u16))
2304                 (canon lift (core func $i "foo"))
2305             )
2306         )"#
2307     );
2308 
2309     let engine = super::engine();
2310     let component = Component::new(&engine, component)?;
2311     let mut store = Store::new(&engine, ());
2312     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2313     let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?;
2314     assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),));
2315 
2316     Ok(())
2317 }
2318 
2319 #[test]
2320 fn option() -> Result<()> {
2321     let component = format!(
2322         r#"(component
2323             (core module $m
2324                 (memory (export "memory") 1)
2325                 (func (export "pass1") (param i32 i32) (result i32)
2326                     (local $base i32)
2327                     (local.set $base
2328                         (call $realloc
2329                             (i32.const 0)
2330                             (i32.const 0)
2331                             (i32.const 4)
2332                             (i32.const 8)))
2333 
2334                     (i32.store offset=0
2335                         (local.get $base)
2336                         (local.get 0))
2337                     (i32.store offset=4
2338                         (local.get $base)
2339                         (local.get 1))
2340 
2341                     (local.get $base)
2342                 )
2343                 (func (export "pass2") (param i32 i32 i32) (result i32)
2344                     (local $base i32)
2345                     (local.set $base
2346                         (call $realloc
2347                             (i32.const 0)
2348                             (i32.const 0)
2349                             (i32.const 4)
2350                             (i32.const 12)))
2351 
2352                     (i32.store offset=0
2353                         (local.get $base)
2354                         (local.get 0))
2355                     (i32.store offset=4
2356                         (local.get $base)
2357                         (local.get 1))
2358                     (i32.store offset=8
2359                         (local.get $base)
2360                         (local.get 2))
2361 
2362                     (local.get $base)
2363                 )
2364 
2365                 {REALLOC_AND_FREE}
2366             )
2367             (core instance $i (instantiate $m))
2368 
2369             (func (export "option-u8-to-tuple") (param "a" (option u8)) (result (tuple u32 u32))
2370                 (canon lift (core func $i "pass1") (memory $i "memory"))
2371             )
2372             (func (export "option-u32-to-tuple") (param "a" (option u32)) (result (tuple u32 u32))
2373                 (canon lift (core func $i "pass1") (memory $i "memory"))
2374             )
2375             (func (export "option-string-to-tuple") (param "a" (option string)) (result (tuple u32 string))
2376                 (canon lift
2377                     (core func $i "pass2")
2378                     (memory $i "memory")
2379                     (realloc (func $i "realloc"))
2380                 )
2381             )
2382             (func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8))
2383                 (canon lift (core func $i "pass1") (memory $i "memory"))
2384             )
2385             (func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32))
2386                 (canon lift
2387                     (core func $i "pass1")
2388                     (memory $i "memory")
2389                 )
2390             )
2391             (func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string))
2392                 (canon lift
2393                     (core func $i "pass2")
2394                     (memory $i "memory")
2395                     (realloc (func $i "realloc"))
2396                 )
2397             )
2398         )"#
2399     );
2400 
2401     let engine = super::engine();
2402     let component = Component::new(&engine, component)?;
2403     let mut store = Store::new(&engine, ());
2404     let linker = Linker::new(&engine);
2405     let instance = linker.instantiate(&mut store, &component)?;
2406 
2407     let option_u8_to_tuple = instance
2408         .get_typed_func::<(Option<u8>,), ((u32, u32),)>(&mut store, "option-u8-to-tuple")?;
2409     assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2410     assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2411     assert_eq!(
2412         option_u8_to_tuple.call(&mut store, (Some(100),))?,
2413         ((1, 100),)
2414     );
2415 
2416     let option_u32_to_tuple = instance
2417         .get_typed_func::<(Option<u32>,), ((u32, u32),)>(&mut store, "option-u32-to-tuple")?;
2418     assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2419     assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2420     assert_eq!(
2421         option_u32_to_tuple.call(&mut store, (Some(100),))?,
2422         ((1, 100),)
2423     );
2424 
2425     let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), ((u32, WasmStr),)>(
2426         &mut store,
2427         "option-string-to-tuple",
2428     )?;
2429     let ((a, b),) = option_string_to_tuple.call(&mut store, (None,))?;
2430     assert_eq!(a, 0);
2431     assert_eq!(b.to_str(&store)?, "");
2432     let ((a, b),) = option_string_to_tuple.call(&mut store, (Some(""),))?;
2433     assert_eq!(a, 1);
2434     assert_eq!(b.to_str(&store)?, "");
2435     let ((a, b),) = option_string_to_tuple.call(&mut store, (Some("hello"),))?;
2436     assert_eq!(a, 1);
2437     assert_eq!(b.to_str(&store)?, "hello");
2438 
2439     let instance = linker.instantiate(&mut store, &component)?;
2440     let to_option_u8 =
2441         instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?;
2442     assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,));
2443     assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),));
2444     assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),));
2445     assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err());
2446 
2447     let instance = linker.instantiate(&mut store, &component)?;
2448     let to_option_u32 =
2449         instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?;
2450     assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,));
2451     assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),));
2452     assert_eq!(
2453         to_option_u32.call(&mut store, (1, 0x1234fead))?,
2454         (Some(0x1234fead),)
2455     );
2456     assert!(to_option_u32.call(&mut store, (2, 0)).is_err());
2457 
2458     let instance = linker.instantiate(&mut store, &component)?;
2459     let to_option_string = instance
2460         .get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?;
2461     let ret = to_option_string.call(&mut store, (0, ""))?.0;
2462     assert!(ret.is_none());
2463     let ret = to_option_string.call(&mut store, (1, ""))?.0;
2464     assert_eq!(ret.unwrap().to_str(&store)?, "");
2465     let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0;
2466     assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake");
2467     assert!(to_option_string.call(&mut store, (2, "")).is_err());
2468 
2469     Ok(())
2470 }
2471 
2472 #[test]
2473 fn expected() -> Result<()> {
2474     let component = format!(
2475         r#"(component
2476             (core module $m
2477                 (memory (export "memory") 1)
2478                 (func (export "pass0") (param i32) (result i32)
2479                     local.get 0
2480                 )
2481                 (func (export "pass1") (param i32 i32) (result i32)
2482                     (local $base i32)
2483                     (local.set $base
2484                         (call $realloc
2485                             (i32.const 0)
2486                             (i32.const 0)
2487                             (i32.const 4)
2488                             (i32.const 8)))
2489 
2490                     (i32.store offset=0
2491                         (local.get $base)
2492                         (local.get 0))
2493                     (i32.store offset=4
2494                         (local.get $base)
2495                         (local.get 1))
2496 
2497                     (local.get $base)
2498                 )
2499                 (func (export "pass2") (param i32 i32 i32) (result i32)
2500                     (local $base i32)
2501                     (local.set $base
2502                         (call $realloc
2503                             (i32.const 0)
2504                             (i32.const 0)
2505                             (i32.const 4)
2506                             (i32.const 12)))
2507 
2508                     (i32.store offset=0
2509                         (local.get $base)
2510                         (local.get 0))
2511                     (i32.store offset=4
2512                         (local.get $base)
2513                         (local.get 1))
2514                     (i32.store offset=8
2515                         (local.get $base)
2516                         (local.get 2))
2517 
2518                     (local.get $base)
2519                 )
2520 
2521                 {REALLOC_AND_FREE}
2522             )
2523             (core instance $i (instantiate $m))
2524 
2525             (func (export "take-expected-unit") (param "a" (result)) (result u32)
2526                 (canon lift (core func $i "pass0"))
2527             )
2528             (func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result (tuple u32 u32))
2529                 (canon lift (core func $i "pass1") (memory $i "memory"))
2530             )
2531             (type $list (list u8))
2532             (func (export "take-expected-string") (param "a" (result string (error $list))) (result (tuple u32 string))
2533                 (canon lift
2534                     (core func $i "pass2")
2535                     (memory $i "memory")
2536                     (realloc (func $i "realloc"))
2537                 )
2538             )
2539             (func (export "to-expected-unit") (param "a" u32) (result (result))
2540                 (canon lift (core func $i "pass0"))
2541             )
2542             (func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32)))
2543                 (canon lift
2544                     (core func $i "pass1")
2545                     (memory $i "memory")
2546                     (realloc (func $i "realloc"))
2547                 )
2548             )
2549         )"#
2550     );
2551 
2552     let engine = super::engine();
2553     let component = Component::new(&engine, component)?;
2554     let mut store = Store::new(&engine, ());
2555     let linker = Linker::new(&engine);
2556     let instance = linker.instantiate(&mut store, &component)?;
2557     let take_expected_unit =
2558         instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?;
2559     assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,));
2560     assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,));
2561 
2562     let take_expected_u8_f32 = instance
2563         .get_typed_func::<(Result<u8, f32>,), ((u32, u32),)>(&mut store, "take-expected-u8-f32")?;
2564     assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, ((0, 1),));
2565     assert_eq!(
2566         take_expected_u8_f32.call(&mut store, (Err(2.0),))?,
2567         ((1, 2.0f32.to_bits()),)
2568     );
2569 
2570     let take_expected_string = instance
2571         .get_typed_func::<(Result<&str, &[u8]>,), ((u32, WasmStr),)>(
2572             &mut store,
2573             "take-expected-string",
2574         )?;
2575     let ((a, b),) = take_expected_string.call(&mut store, (Ok("hello"),))?;
2576     assert_eq!(a, 0);
2577     assert_eq!(b.to_str(&store)?, "hello");
2578     let ((a, b),) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?;
2579     assert_eq!(a, 1);
2580     assert_eq!(b.to_str(&store)?, "goodbye");
2581 
2582     let instance = linker.instantiate(&mut store, &component)?;
2583     let to_expected_unit =
2584         instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?;
2585     assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),));
2586     assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),));
2587     let err = to_expected_unit.call(&mut store, (2,)).unwrap_err();
2588     assert!(err.to_string().contains("invalid expected"), "{}", err);
2589 
2590     let instance = linker.instantiate(&mut store, &component)?;
2591     let to_expected_s16_f32 = instance
2592         .get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?;
2593     assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),));
2594     assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),));
2595     assert_eq!(
2596         to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?,
2597         (Err(1.0),)
2598     );
2599     let ret = to_expected_s16_f32
2600         .call(&mut store, (1, CANON_32BIT_NAN | 1))?
2601         .0;
2602     assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN | 1);
2603     assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err());
2604 
2605     Ok(())
2606 }
2607 
2608 #[test]
2609 fn fancy_list() -> Result<()> {
2610     let component = format!(
2611         r#"(component
2612             (core module $m
2613                 (memory (export "memory") 1)
2614                 (func (export "take") (param i32 i32) (result i32)
2615                     (local $base i32)
2616                     (local.set $base
2617                         (call $realloc
2618                             (i32.const 0)
2619                             (i32.const 0)
2620                             (i32.const 4)
2621                             (i32.const 16)))
2622 
2623                     (i32.store offset=0
2624                         (local.get $base)
2625                         (local.get 0))
2626                     (i32.store offset=4
2627                         (local.get $base)
2628                         (local.get 1))
2629                     (i32.store offset=8
2630                         (local.get $base)
2631                         (i32.const 0))
2632                     (i32.store offset=12
2633                         (local.get $base)
2634                         (i32.mul
2635                             (memory.size)
2636                             (i32.const 65536)))
2637 
2638                     (local.get $base)
2639                 )
2640 
2641                 {REALLOC_AND_FREE}
2642             )
2643             (core instance $i (instantiate $m))
2644 
2645             (type $a (option u8))
2646             (type $b (result (error string)))
2647             (type $input (list (tuple $a $b)))
2648             (func (export "take")
2649                 (param "a" $input)
2650                 (result (tuple u32 u32 (list u8)))
2651                 (canon lift
2652                     (core func $i "take")
2653                     (memory $i "memory")
2654                     (realloc (func $i "realloc"))
2655                 )
2656             )
2657         )"#
2658     );
2659 
2660     let engine = super::engine();
2661     let component = Component::new(&engine, component)?;
2662     let mut store = Store::new(&engine, ());
2663     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2664 
2665     let func = instance
2666         .get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), ((u32, u32, WasmList<u8>),)>(
2667             &mut store, "take",
2668         )?;
2669 
2670     let input = [
2671         (None, Ok(())),
2672         (Some(2), Err("hello there")),
2673         (Some(200), Err("general kenobi")),
2674     ];
2675     let ((ptr, len, list),) = func.call(&mut store, (&input,))?;
2676     let memory = list.as_le_slice(&store);
2677     let ptr = usize::try_from(ptr).unwrap();
2678     let len = usize::try_from(len).unwrap();
2679     let mut array = &memory[ptr..][..len * 16];
2680 
2681     for (a, b) in input.iter() {
2682         match a {
2683             Some(val) => {
2684                 assert_eq!(*array.take_n::<2>(), [1, *val]);
2685             }
2686             None => {
2687                 assert_eq!(*array.take_n::<1>(), [0]);
2688                 array.skip::<1>();
2689             }
2690         }
2691         array.skip::<2>();
2692         match b {
2693             Ok(()) => {
2694                 assert_eq!(*array.take_n::<1>(), [0]);
2695                 array.skip::<11>();
2696             }
2697             Err(s) => {
2698                 assert_eq!(*array.take_n::<1>(), [1]);
2699                 array.skip::<3>();
2700                 assert_eq!(array.ptr_len(memory, 1), s.as_bytes());
2701             }
2702         }
2703     }
2704     assert!(array.is_empty());
2705 
2706     Ok(())
2707 }
2708 
2709 trait SliceExt<'a> {
2710     fn take_n<const N: usize>(&mut self) -> &'a [u8; N];
2711 
2712     fn skip<const N: usize>(&mut self) {
2713         self.take_n::<N>();
2714     }
2715 
2716     fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] {
2717         let ptr = u32::from_le_bytes(*self.take_n::<4>());
2718         let len = u32::from_le_bytes(*self.take_n::<4>());
2719         let ptr = usize::try_from(ptr).unwrap();
2720         let len = usize::try_from(len).unwrap();
2721         &all_memory[ptr..][..len * size]
2722     }
2723 }
2724 
2725 impl<'a> SliceExt<'a> for &'a [u8] {
2726     fn take_n<const N: usize>(&mut self) -> &'a [u8; N] {
2727         let (a, b) = self.split_at(N);
2728         *self = b;
2729         a.try_into().unwrap()
2730     }
2731 }
2732 
2733 #[test]
2734 fn invalid_alignment() -> Result<()> {
2735     let component = format!(
2736         r#"(component
2737             (core module $m
2738                 (memory (export "memory") 1)
2739                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
2740                     i32.const 1)
2741 
2742                 (func (export "take-i32") (param i32))
2743                 (func (export "ret-1") (result i32) i32.const 1)
2744                 (func (export "ret-unaligned-list") (result i32)
2745                     (i32.store offset=0 (i32.const 8) (i32.const 1))
2746                     (i32.store offset=4 (i32.const 8) (i32.const 1))
2747                     i32.const 8)
2748             )
2749             (core instance $i (instantiate $m))
2750 
2751             (func (export "many-params")
2752                 (param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string)
2753                 (param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string)
2754                 (param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string)
2755                 (canon lift
2756                     (core func $i "take-i32")
2757                     (memory $i "memory")
2758                     (realloc (func $i "realloc"))
2759                 )
2760             )
2761             (func (export "string-ret") (result string)
2762                 (canon lift
2763                     (core func $i "ret-1")
2764                     (memory $i "memory")
2765                     (realloc (func $i "realloc"))
2766                 )
2767             )
2768             (func (export "list-u32-ret") (result (list u32))
2769                 (canon lift
2770                     (core func $i "ret-unaligned-list")
2771                     (memory $i "memory")
2772                     (realloc (func $i "realloc"))
2773                 )
2774             )
2775         )"#
2776     );
2777 
2778     let engine = super::engine();
2779     let component = Component::new(&engine, component)?;
2780     let mut store = Store::new(&engine, ());
2781     let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
2782 
2783     let err = instance(&mut store)?
2784         .get_typed_func::<(
2785             &str,
2786             &str,
2787             &str,
2788             &str,
2789             &str,
2790             &str,
2791             &str,
2792             &str,
2793             &str,
2794             &str,
2795             &str,
2796             &str,
2797         ), ()>(&mut store, "many-params")?
2798         .call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", ""))
2799         .unwrap_err();
2800     assert!(
2801         err.to_string()
2802             .contains("realloc return: result not aligned"),
2803         "{}",
2804         err
2805     );
2806 
2807     let err = instance(&mut store)?
2808         .get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")?
2809         .call(&mut store, ())
2810         .err()
2811         .unwrap();
2812     assert!(
2813         err.to_string().contains("return pointer not aligned"),
2814         "{}",
2815         err
2816     );
2817 
2818     let err = instance(&mut store)?
2819         .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")?
2820         .call(&mut store, ())
2821         .err()
2822         .unwrap();
2823     assert!(
2824         err.to_string().contains("list pointer is not aligned"),
2825         "{}",
2826         err
2827     );
2828 
2829     Ok(())
2830 }
2831 
2832 #[test]
2833 fn drop_component_still_works() -> Result<()> {
2834     let component = r#"
2835         (component
2836             (import "f" (func $f))
2837 
2838             (core func $f_lower
2839                 (canon lower (func $f))
2840             )
2841             (core module $m
2842                 (import "" "" (func $f))
2843 
2844                 (func $f2
2845                     call $f
2846                     call $f
2847                 )
2848 
2849                 (export "f" (func $f2))
2850             )
2851             (core instance $i (instantiate $m
2852                 (with "" (instance
2853                     (export "" (func $f_lower))
2854                 ))
2855             ))
2856             (func (export "g")
2857                 (canon lift
2858                     (core func $i "f")
2859                 )
2860             )
2861         )
2862     "#;
2863 
2864     let (mut store, instance) = {
2865         let engine = super::engine();
2866         let component = Component::new(&engine, component)?;
2867         let mut store = Store::new(&engine, 0);
2868         let mut linker = Linker::new(&engine);
2869         linker.root().func_wrap(
2870             "f",
2871             |mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> {
2872                 *store.data_mut() += 1;
2873                 Ok(())
2874             },
2875         )?;
2876         let instance = linker.instantiate(&mut store, &component)?;
2877         (store, instance)
2878     };
2879 
2880     let f = instance.get_typed_func::<(), ()>(&mut store, "g")?;
2881     assert_eq!(*store.data(), 0);
2882     f.call(&mut store, ())?;
2883     assert_eq!(*store.data(), 2);
2884 
2885     Ok(())
2886 }
2887 
2888 #[test]
2889 fn raw_slice_of_various_types() -> Result<()> {
2890     let component = r#"
2891         (component
2892             (core module $m
2893                 (memory (export "memory") 1)
2894 
2895                 (func (export "list8") (result i32)
2896                     (call $setup_list (i32.const 16))
2897                 )
2898                 (func (export "list16") (result i32)
2899                     (call $setup_list (i32.const 8))
2900                 )
2901                 (func (export "list32") (result i32)
2902                     (call $setup_list (i32.const 4))
2903                 )
2904                 (func (export "list64") (result i32)
2905                     (call $setup_list (i32.const 2))
2906                 )
2907 
2908                 (func $setup_list (param i32) (result i32)
2909                     (i32.store offset=0 (i32.const 100) (i32.const 8))
2910                     (i32.store offset=4 (i32.const 100) (local.get 0))
2911                     i32.const 100
2912                 )
2913 
2914                 (data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f")
2915             )
2916             (core instance $i (instantiate $m))
2917             (func (export "list-u8") (result (list u8))
2918                 (canon lift (core func $i "list8") (memory $i "memory"))
2919             )
2920             (func (export "list-i8") (result (list s8))
2921                 (canon lift (core func $i "list8") (memory $i "memory"))
2922             )
2923             (func (export "list-u16") (result (list u16))
2924                 (canon lift (core func $i "list16") (memory $i "memory"))
2925             )
2926             (func (export "list-i16") (result (list s16))
2927                 (canon lift (core func $i "list16") (memory $i "memory"))
2928             )
2929             (func (export "list-u32") (result (list u32))
2930                 (canon lift (core func $i "list32") (memory $i "memory"))
2931             )
2932             (func (export "list-i32") (result (list s32))
2933                 (canon lift (core func $i "list32") (memory $i "memory"))
2934             )
2935             (func (export "list-u64") (result (list u64))
2936                 (canon lift (core func $i "list64") (memory $i "memory"))
2937             )
2938             (func (export "list-i64") (result (list s64))
2939                 (canon lift (core func $i "list64") (memory $i "memory"))
2940             )
2941         )
2942     "#;
2943 
2944     let (mut store, instance) = {
2945         let engine = super::engine();
2946         let component = Component::new(&engine, component)?;
2947         let mut store = Store::new(&engine, ());
2948         let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2949         (store, instance)
2950     };
2951 
2952     let list = instance
2953         .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")?
2954         .call(&mut store, ())?
2955         .0;
2956     assert_eq!(
2957         list.as_le_slice(&store),
2958         [
2959             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2960             0x0e, 0x0f,
2961         ]
2962     );
2963     let list = instance
2964         .get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")?
2965         .call(&mut store, ())?
2966         .0;
2967     assert_eq!(
2968         list.as_le_slice(&store),
2969         [
2970             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2971             0x0e, 0x0f,
2972         ]
2973     );
2974 
2975     let list = instance
2976         .get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")?
2977         .call(&mut store, ())?
2978         .0;
2979     assert_eq!(
2980         list.as_le_slice(&store),
2981         [
2982             u16::to_le(0x01_00),
2983             u16::to_le(0x03_02),
2984             u16::to_le(0x05_04),
2985             u16::to_le(0x07_06),
2986             u16::to_le(0x09_08),
2987             u16::to_le(0x0b_0a),
2988             u16::to_le(0x0d_0c),
2989             u16::to_le(0x0f_0e),
2990         ]
2991     );
2992     let list = instance
2993         .get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")?
2994         .call(&mut store, ())?
2995         .0;
2996     assert_eq!(
2997         list.as_le_slice(&store),
2998         [
2999             i16::to_le(0x01_00),
3000             i16::to_le(0x03_02),
3001             i16::to_le(0x05_04),
3002             i16::to_le(0x07_06),
3003             i16::to_le(0x09_08),
3004             i16::to_le(0x0b_0a),
3005             i16::to_le(0x0d_0c),
3006             i16::to_le(0x0f_0e),
3007         ]
3008     );
3009     let list = instance
3010         .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")?
3011         .call(&mut store, ())?
3012         .0;
3013     assert_eq!(
3014         list.as_le_slice(&store),
3015         [
3016             u32::to_le(0x03_02_01_00),
3017             u32::to_le(0x07_06_05_04),
3018             u32::to_le(0x0b_0a_09_08),
3019             u32::to_le(0x0f_0e_0d_0c),
3020         ]
3021     );
3022     let list = instance
3023         .get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")?
3024         .call(&mut store, ())?
3025         .0;
3026     assert_eq!(
3027         list.as_le_slice(&store),
3028         [
3029             i32::to_le(0x03_02_01_00),
3030             i32::to_le(0x07_06_05_04),
3031             i32::to_le(0x0b_0a_09_08),
3032             i32::to_le(0x0f_0e_0d_0c),
3033         ]
3034     );
3035     let list = instance
3036         .get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")?
3037         .call(&mut store, ())?
3038         .0;
3039     assert_eq!(
3040         list.as_le_slice(&store),
3041         [
3042             u64::to_le(0x07_06_05_04_03_02_01_00),
3043             u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
3044         ]
3045     );
3046     let list = instance
3047         .get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")?
3048         .call(&mut store, ())?
3049         .0;
3050     assert_eq!(
3051         list.as_le_slice(&store),
3052         [
3053             i64::to_le(0x07_06_05_04_03_02_01_00),
3054             i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
3055         ]
3056     );
3057 
3058     Ok(())
3059 }
3060 
3061 #[test]
3062 fn lower_then_lift() -> Result<()> {
3063     // First test simple integers when the import/export ABI happen to line up
3064     let component = r#"
3065 (component $c
3066   (import "f" (func $f (result u32)))
3067 
3068   (core func $f_lower
3069     (canon lower (func $f))
3070   )
3071   (func $f2 (result s32)
3072     (canon lift (core func $f_lower))
3073   )
3074   (export "f2" (func $f2))
3075 )
3076     "#;
3077 
3078     let engine = super::engine();
3079     let component = Component::new(&engine, component)?;
3080     let mut store = Store::new(&engine, ());
3081     let mut linker = Linker::new(&engine);
3082     linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?;
3083     let instance = linker.instantiate(&mut store, &component)?;
3084 
3085     let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?;
3086     assert_eq!(f.call(&mut store, ())?, (2,));
3087 
3088     // First test strings when the import/export ABI happen to line up
3089     let component = format!(
3090         r#"
3091 (component $c
3092   (import "s" (func $f (param "a" string)))
3093 
3094   (core module $libc
3095     (memory (export "memory") 1)
3096     {REALLOC_AND_FREE}
3097   )
3098   (core instance $libc (instantiate $libc))
3099 
3100   (core func $f_lower
3101     (canon lower (func $f) (memory $libc "memory"))
3102   )
3103   (func $f2 (param "a" string)
3104     (canon lift (core func $f_lower)
3105         (memory $libc "memory")
3106         (realloc (func $libc "realloc"))
3107     )
3108   )
3109   (export "f" (func $f2))
3110 )
3111     "#
3112     );
3113 
3114     let component = Component::new(&engine, component)?;
3115     let mut store = Store::new(&engine, ());
3116     linker
3117         .root()
3118         .func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3119             assert_eq!(x.to_str(&store)?, "hello");
3120             Ok(())
3121         })?;
3122     let instance = linker.instantiate(&mut store, &component)?;
3123 
3124     let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?;
3125     f.call(&mut store, ("hello",))?;
3126 
3127     // Next test "type punning" where return values are reinterpreted just
3128     // because the return ABI happens to line up.
3129     let component = format!(
3130         r#"
3131 (component $c
3132   (import "s2" (func $f (param "a" string) (result u32)))
3133 
3134   (core module $libc
3135     (memory (export "memory") 1)
3136     {REALLOC_AND_FREE}
3137   )
3138   (core instance $libc (instantiate $libc))
3139 
3140   (core func $f_lower
3141     (canon lower (func $f) (memory $libc "memory"))
3142   )
3143   (func $f2 (param "a" string) (result string)
3144     (canon lift (core func $f_lower)
3145         (memory $libc "memory")
3146         (realloc (func $libc "realloc"))
3147     )
3148   )
3149   (export "f" (func $f2))
3150 )
3151     "#
3152     );
3153 
3154     let component = Component::new(&engine, component)?;
3155     let mut store = Store::new(&engine, ());
3156     linker
3157         .root()
3158         .func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3159             assert_eq!(x.to_str(&store)?, "hello");
3160             Ok((u32::MAX,))
3161         })?;
3162     let instance = linker.instantiate(&mut store, &component)?;
3163 
3164     let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?;
3165     let err = f.call(&mut store, ("hello",)).err().unwrap();
3166     assert!(
3167         err.to_string().contains("return pointer not aligned"),
3168         "{}",
3169         err
3170     );
3171 
3172     Ok(())
3173 }
3174 
3175 #[test]
3176 fn errors_that_poison_instance() -> Result<()> {
3177     let component = format!(
3178         r#"
3179 (component $c
3180   (core module $m1
3181     (func (export "f1") unreachable)
3182     (func (export "f2"))
3183   )
3184   (core instance $m1 (instantiate $m1))
3185   (func (export "f1") (canon lift (core func $m1 "f1")))
3186   (func (export "f2") (canon lift (core func $m1 "f2")))
3187 
3188   (core module $m2
3189     (func (export "f") (param i32 i32))
3190     (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable)
3191     (memory (export "m") 1)
3192   )
3193   (core instance $m2 (instantiate $m2))
3194   (func (export "f3") (param "a" string)
3195     (canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m"))
3196   )
3197 
3198   (core module $m3
3199     (func (export "f") (result i32) i32.const 1)
3200     (memory (export "m") 1)
3201   )
3202   (core instance $m3 (instantiate $m3))
3203   (func (export "f4") (result string)
3204     (canon lift (core func $m3 "f") (memory $m3 "m"))
3205   )
3206 )
3207     "#
3208     );
3209 
3210     let engine = super::engine();
3211     let component = Component::new(&engine, component)?;
3212     let linker = Linker::new(&engine);
3213 
3214     {
3215         let mut store = Store::new(&engine, ());
3216         let instance = linker.instantiate(&mut store, &component)?;
3217         let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?;
3218         let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?;
3219         assert_unreachable(f1.call(&mut store, ()));
3220         assert_poisoned(f1.call(&mut store, ()));
3221         assert_poisoned(f2.call(&mut store, ()));
3222     }
3223 
3224     {
3225         let mut store = Store::new(&engine, ());
3226         let instance = linker.instantiate(&mut store, &component)?;
3227         let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;
3228         assert_unreachable(f3.call(&mut store, ("x",)));
3229         assert_poisoned(f3.call(&mut store, ("x",)));
3230 
3231         // Since we actually poison the store, even an unrelated instance will
3232         // be considered poisoned:
3233         let instance = linker.instantiate(&mut store, &component)?;
3234         let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;
3235         assert_poisoned(f3.call(&mut store, ("x",)));
3236     }
3237 
3238     {
3239         let mut store = Store::new(&engine, ());
3240         let instance = linker.instantiate(&mut store, &component)?;
3241         let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?;
3242         assert!(f4.call(&mut store, ()).is_err());
3243         assert_poisoned(f4.call(&mut store, ()));
3244     }
3245 
3246     return Ok(());
3247 
3248     #[track_caller]
3249     fn assert_unreachable<T>(err: Result<T>) {
3250         let err = match err {
3251             Ok(_) => panic!("expected an error"),
3252             Err(e) => e,
3253         };
3254         assert_eq!(
3255             err.downcast::<Trap>().unwrap(),
3256             Trap::UnreachableCodeReached
3257         );
3258     }
3259 
3260     #[track_caller]
3261     fn assert_poisoned<T>(err: Result<T>) {
3262         let err = match err {
3263             Ok(_) => panic!("expected an error"),
3264             Err(e) => e,
3265         };
3266         assert_eq!(
3267             err.downcast_ref::<Trap>(),
3268             Some(&Trap::CannotEnterComponent),
3269             "{err}",
3270         );
3271     }
3272 }
3273 
3274 #[test]
3275 fn run_export_with_internal_adapter() -> Result<()> {
3276     let component = r#"
3277 (component
3278   (type $t (func (param "a" u32) (result u32)))
3279   (component $a
3280     (core module $m
3281       (func (export "add-five") (param i32) (result i32)
3282         local.get 0
3283         i32.const 5
3284         i32.add)
3285     )
3286     (core instance $m (instantiate $m))
3287     (func (export "add-five") (type $t) (canon lift (core func $m "add-five")))
3288   )
3289   (component $b
3290     (import "interface-v1" (instance $i
3291       (export "add-five" (func (type $t)))))
3292     (core module $m
3293       (func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32))
3294       (func) ;; causes index out of bounds
3295       (func (export "run") (result i32) i32.const 0 call $add-five)
3296     )
3297     (core func $add-five (canon lower (func $i "add-five")))
3298     (core instance $i (instantiate 0
3299       (with "interface-0.1.0" (instance
3300         (export "add-five" (func $add-five))
3301       ))
3302     ))
3303     (func (result u32) (canon lift (core func $i "run")))
3304     (export "run" (func 1))
3305   )
3306   (instance $a (instantiate $a))
3307   (instance $b (instantiate $b (with "interface-v1" (instance $a))))
3308   (export "run" (func $b "run"))
3309 )
3310 "#;
3311     let engine = super::engine();
3312     let component = Component::new(&engine, component)?;
3313     let mut store = Store::new(&engine, ());
3314     let linker = Linker::new(&engine);
3315     let instance = linker.instantiate(&mut store, &component)?;
3316     let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?;
3317     assert_eq!(run.call(&mut store, ())?, (5,));
3318     Ok(())
3319 }
3320 
3321 enum RecurseKind {
3322     AThenA,
3323     AThenB,
3324     AThenBThenA,
3325 }
3326 
3327 #[test]
3328 fn recurse() -> Result<()> {
3329     test_recurse(RecurseKind::AThenB)
3330 }
3331 
3332 #[test]
3333 fn recurse_trap() -> Result<()> {
3334     let error = test_recurse(RecurseKind::AThenA).unwrap_err();
3335 
3336     assert_eq!(error.downcast::<Trap>()?, Trap::CannotEnterComponent);
3337 
3338     Ok(())
3339 }
3340 
3341 #[test]
3342 fn recurse_more_trap() -> Result<()> {
3343     let error = test_recurse(RecurseKind::AThenBThenA).unwrap_err();
3344 
3345     assert_eq!(error.downcast::<Trap>()?, Trap::CannotEnterComponent);
3346 
3347     Ok(())
3348 }
3349 
3350 fn test_recurse(kind: RecurseKind) -> Result<()> {
3351     #[derive(Default)]
3352     struct Ctx {
3353         instances: Vec<Arc<Instance>>,
3354     }
3355 
3356     let component = r#"
3357 (component
3358   (import "import" (func $import))
3359   (core func $import (canon lower (func $import)))
3360   (core module $m
3361     (func $import (import "" "import"))
3362     (func (export "export") call $import)
3363   )
3364   (core instance $m (instantiate $m (with "" (instance
3365     (export "import" (func $import))
3366   ))))
3367   (func (export "export") (canon lift (core func $m "export")))
3368 )
3369 "#;
3370     let engine = super::engine();
3371     let component = Component::new(&engine, component)?;
3372     let mut store = Store::new(&engine, Ctx::default());
3373     let mut linker = Linker::<Ctx>::new(&engine);
3374     linker.root().func_wrap("import", |mut store, (): ()| {
3375         if let Some(instance) = store.data_mut().instances.pop() {
3376             let run = instance.get_typed_func::<(), ()>(&mut store, "export")?;
3377             run.call(&mut store, ())?;
3378             store.data_mut().instances.push(instance);
3379         }
3380         Ok(())
3381     })?;
3382     let instance = Arc::new(linker.instantiate(&mut store, &component)?);
3383     let instance = match kind {
3384         RecurseKind::AThenA => {
3385             store.data_mut().instances.push(instance.clone());
3386             instance
3387         }
3388         RecurseKind::AThenB => {
3389             let other = Arc::new(linker.instantiate(&mut store, &component)?);
3390             store.data_mut().instances.push(other);
3391             instance
3392         }
3393         RecurseKind::AThenBThenA => {
3394             store.data_mut().instances.push(instance.clone());
3395             let other = Arc::new(linker.instantiate(&mut store, &component)?);
3396             store.data_mut().instances.push(other);
3397             instance
3398         }
3399     };
3400 
3401     let export = instance.get_typed_func::<(), ()>(&mut store, "export")?;
3402     export.call(&mut store, ())?;
3403     Ok(())
3404 }
3405 
3406 #[tokio::test]
3407 async fn thread_index_via_instantiation_sync() -> Result<()> {
3408     thread_index_via_instantiation(ApiStyle::Sync).await
3409 }
3410 
3411 #[tokio::test]
3412 async fn thread_index_via_instantiation_async() -> Result<()> {
3413     thread_index_via_instantiation(ApiStyle::Async).await
3414 }
3415 
3416 async fn thread_index_via_instantiation(style: ApiStyle) -> Result<()> {
3417     let component = r#"
3418 (component
3419   (core module $m
3420     (import "" "thread.index" (func $thread-index (result i32)))
3421     (func $start
3422        (if (i32.eqz (call $thread-index)) (then unreachable))
3423     )
3424     (start $start)
3425   )
3426   (core func $thread-index (canon thread.index))
3427   (core instance $m (instantiate $m (with "" (instance
3428     (export "thread.index" (func $thread-index))
3429   ))))
3430 )
3431 "#;
3432     let engine = Engine::new(&style.config())?;
3433     let component = Component::new(&engine, component)?;
3434     let mut store = Store::new(&engine, ());
3435     let linker = Linker::new(&engine);
3436     style.instantiate(&mut store, &linker, &component).await?;
3437     Ok(())
3438 }
3439 
3440 #[tokio::test]
3441 async fn thread_index_via_call_sync() -> Result<()> {
3442     thread_index_via_call(ApiStyle::Sync).await
3443 }
3444 
3445 #[tokio::test]
3446 async fn thread_index_via_call_async() -> Result<()> {
3447     thread_index_via_call(ApiStyle::Async).await
3448 }
3449 
3450 #[tokio::test]
3451 async fn thread_index_via_call_concurrent() -> Result<()> {
3452     thread_index_via_call(ApiStyle::Concurrent).await
3453 }
3454 
3455 async fn thread_index_via_call(style: ApiStyle) -> Result<()> {
3456     let component = r#"
3457 (component
3458   (core module $m
3459     (import "" "thread.index" (func $thread-index (result i32)))
3460     (func (export "run")
3461        (if (i32.eqz (call $thread-index)) (then unreachable))
3462     )
3463   )
3464   (core func $thread-index (canon thread.index))
3465   (core instance $m (instantiate $m (with "" (instance
3466     (export "thread.index" (func $thread-index))
3467   ))))
3468   (func (export "run") (canon lift (core func $m "run")))
3469 )
3470 "#;
3471     let engine = Engine::new(&style.config())?;
3472     let component = Component::new(&engine, component)?;
3473     let mut store = Store::new(&engine, ());
3474     let linker = Linker::new(&engine);
3475     let instance = style.instantiate(&mut store, &linker, &component).await?;
3476     let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
3477     style.call(&mut store, run, ()).await?;
3478     Ok(())
3479 }
3480 
3481 #[tokio::test]
3482 async fn thread_index_via_post_return_sync() -> Result<()> {
3483     thread_index_via_post_return(ApiStyle::Sync).await
3484 }
3485 
3486 #[tokio::test]
3487 async fn thread_index_via_post_return_async() -> Result<()> {
3488     thread_index_via_post_return(ApiStyle::Async).await
3489 }
3490 
3491 #[tokio::test]
3492 async fn thread_index_via_post_return_concurrent() -> Result<()> {
3493     thread_index_via_post_return(ApiStyle::Concurrent).await
3494 }
3495 
3496 async fn thread_index_via_post_return(style: ApiStyle) -> Result<()> {
3497     let component = r#"
3498 (component
3499   (core module $m
3500     (import "" "thread.index" (func $thread-index (result i32)))
3501     (global $index (mut i32) (i32.const 0))
3502     (func (export "run")
3503        (global.set $index (call $thread-index))
3504        (if (i32.eqz (global.get $index)) (then unreachable))
3505     )
3506     (func (export "run-post-return")
3507        (local $index i32)
3508        (local.set $index (call $thread-index))
3509        (if (i32.eqz (local.get $index)) (then unreachable))
3510        (if (i32.ne (local.get $index) (global.get $index)) (then unreachable))
3511     )
3512   )
3513   (core func $thread-index (canon thread.index))
3514   (core instance $m (instantiate $m (with "" (instance
3515     (export "thread.index" (func $thread-index))
3516   ))))
3517   (func (export "run") (canon lift (core func $m "run") (post-return (func $m "run-post-return"))))
3518 )
3519 "#;
3520     let engine = Engine::new(&style.config())?;
3521     let component = Component::new(&engine, component)?;
3522     let mut store = Store::new(&engine, ());
3523     let linker = Linker::new(&engine);
3524     let instance = style.instantiate(&mut store, &linker, &component).await?;
3525     let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
3526     style.call(&mut store, run, ()).await?;
3527     Ok(())
3528 }
3529 
3530 #[tokio::test]
3531 async fn thread_index_via_cabi_realloc_sync() -> Result<()> {
3532     thread_index_via_cabi_realloc(ApiStyle::Sync).await
3533 }
3534 
3535 #[tokio::test]
3536 async fn thread_index_via_cabi_realloc_async() -> Result<()> {
3537     thread_index_via_cabi_realloc(ApiStyle::Async).await
3538 }
3539 
3540 #[tokio::test]
3541 async fn thread_index_via_cabi_realloc_concurrent() -> Result<()> {
3542     thread_index_via_cabi_realloc(ApiStyle::Concurrent).await
3543 }
3544 
3545 async fn thread_index_via_cabi_realloc(style: ApiStyle) -> Result<()> {
3546     let component = r#"
3547 (component
3548   (core module $m
3549     (import "" "thread.index" (func $thread-index (result i32)))
3550     (global $index (mut i32) (i32.const 0))
3551     (memory (export "memory") 1)
3552     (func (export "realloc") (param i32 i32 i32 i32) (result i32)
3553        (global.set $index (call $thread-index))
3554        (if (i32.eqz (global.get $index)) (then unreachable))
3555        (i32.const 100)
3556     )
3557     (func (export "run") (param i32 i32)
3558        (local $index i32)
3559        (local.set $index (call $thread-index))
3560        (if (i32.eqz (local.get $index)) (then unreachable))
3561        (if (i32.ne (local.get $index) (global.get $index)) (then unreachable))
3562     )
3563   )
3564   (core func $thread-index (canon thread.index))
3565   (core instance $m (instantiate $m (with "" (instance
3566     (export "thread.index" (func $thread-index))
3567   ))))
3568   (func (export "run") (param "s" string) (canon lift
3569     (core func $m "run")
3570     (memory $m "memory")
3571     (realloc (func $m "realloc"))
3572   ))
3573 )
3574 "#;
3575     let engine = Engine::new(&style.config())?;
3576     let component = Component::new(&engine, component)?;
3577     let mut store = Store::new(&engine, ());
3578     let linker = Linker::new(&engine);
3579     let instance = style.instantiate(&mut store, &linker, &component).await?;
3580     let run = instance.get_typed_func::<(String,), ()>(&mut store, "run")?;
3581     style.call(&mut store, run, ("hola".to_string(),)).await?;
3582     Ok(())
3583 }
3584 
3585 #[tokio::test]
3586 async fn thread_index_via_resource_drop_sync() -> Result<()> {
3587     thread_index_via_resource_drop(ApiStyle::Sync).await
3588 }
3589 
3590 #[tokio::test]
3591 async fn thread_index_via_resource_drop_async() -> Result<()> {
3592     thread_index_via_resource_drop(ApiStyle::Async).await
3593 }
3594 
3595 #[tokio::test]
3596 async fn thread_index_via_resource_drop_concurrent() -> Result<()> {
3597     thread_index_via_resource_drop(ApiStyle::Concurrent).await
3598 }
3599 
3600 async fn thread_index_via_resource_drop(style: ApiStyle) -> Result<()> {
3601     let component = r#"
3602 (component
3603   (core module $m
3604     (import "" "thread.index" (func $thread-index (result i32)))
3605     (func (export "dtor") (param i32)
3606        (if (i32.eqz (call $thread-index)) (then unreachable))
3607     )
3608   )
3609   (core func $thread-index (canon thread.index))
3610   (core instance $m (instantiate $m (with "" (instance
3611     (export "thread.index" (func $thread-index))
3612   ))))
3613   (type $r (resource (rep i32) (dtor (func $m "dtor"))))
3614   (core func $new (canon resource.new $r))
3615   (core module $m2
3616     (import "" "new" (func $new (param i32) (result i32)))
3617     (func (export "new") (result i32)
3618        (call $new (i32.const 100))
3619     )
3620   )
3621   (core instance $m2 (instantiate $m2 (with "" (instance
3622     (export "new" (func $new))
3623   ))))
3624   (func $new (result (own $r)) (canon lift (core func $m2 "new")))
3625   (component $c
3626     (import "r" (type $r (sub resource)))
3627     (import "new" (func $new (result (own $r))))
3628     (export $r-export "r" (type $r))
3629     (export "new" (func $new) (func (result (own $r-export))))
3630   )
3631   (instance $c (instantiate $c
3632     (with "r" (type $r))
3633     (with "new" (func $new))
3634   ))
3635   (export "i" (instance $c))
3636 )
3637 "#;
3638     let engine = Engine::new(&style.config())?;
3639     let component = Component::new(&engine, component)?;
3640     let mut store = Store::new(&engine, ());
3641     let linker = Linker::new(&engine);
3642     let instance = style.instantiate(&mut store, &linker, &component).await?;
3643     let instance_index = instance.get_export_index(&mut store, None, "i").unwrap();
3644     let func_index = instance
3645         .get_export_index(&mut store, Some(&instance_index), "new")
3646         .unwrap();
3647     let run = instance.get_typed_func::<(), (ResourceAny,)>(&mut store, &func_index)?;
3648     let (resource,) = style.call(&mut store, run, ()).await?;
3649     style.resource_drop(&mut store, resource).await?;
3650     Ok(())
3651 }
3652 
3653 #[tokio::test]
3654 async fn thread_index_via_guest_call_sync() -> Result<()> {
3655     thread_index_via_guest_call(ApiStyle::Sync).await
3656 }
3657 
3658 #[tokio::test]
3659 async fn thread_index_via_guest_call_async() -> Result<()> {
3660     thread_index_via_guest_call(ApiStyle::Async).await
3661 }
3662 
3663 #[tokio::test]
3664 async fn thread_index_via_guest_call_concurrent() -> Result<()> {
3665     thread_index_via_guest_call(ApiStyle::Concurrent).await
3666 }
3667 
3668 async fn thread_index_via_guest_call(style: ApiStyle) -> Result<()> {
3669     let component = r#"
3670 (component
3671   (component $c
3672     (core module $m
3673       (import "" "thread.index" (func $thread-index (result i32)))
3674       (func (export "run") (result i32)
3675          (call $thread-index)
3676       )
3677     )
3678     (core func $thread-index (canon thread.index))
3679     (core instance $m (instantiate $m (with "" (instance
3680       (export "thread.index" (func $thread-index))
3681     ))))
3682     (func (export "run") (result u32) (canon lift (core func $m "run")))
3683   )
3684   (instance $c (instantiate $c))
3685 
3686   (component $d
3687     (import "c" (instance $c
3688       (export "run" (func (result u32)))
3689     ))
3690     (core func $run (canon lower (func $c "run")))
3691     (core module $m
3692       (import "" "thread.index" (func $thread-index (result i32)))
3693       (import "" "run" (func $run (result i32)))
3694       (func (export "run")
3695          (local $mine i32)
3696          (local $theirs i32)
3697          (local.set $mine (call $thread-index))
3698          (if (i32.eqz (local.get $mine)) (then unreachable))
3699          (local.set $theirs (call $run))
3700          (if (i32.eqz (local.get $theirs)) (then unreachable))
3701       )
3702     )
3703     (core func $thread-index (canon thread.index))
3704     (core instance $m (instantiate $m (with "" (instance
3705       (export "thread.index" (func $thread-index))
3706       (export "run" (func $run))
3707     ))))
3708     (func (export "run") (canon lift (core func $m "run")))
3709   )
3710   (instance $d (instantiate $d (with "c" (instance $c))))
3711   (func (export "run") (alias export $d "run"))
3712 )
3713 "#;
3714     let engine = Engine::new(&style.config())?;
3715     let component = Component::new(&engine, component)?;
3716     let mut store = Store::new(&engine, ());
3717     let linker = Linker::new(&engine);
3718     let instance = style.instantiate(&mut store, &linker, &component).await?;
3719     let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
3720     style.call(&mut store, run, ()).await?;
3721     Ok(())
3722 }
3723 
3724 fn with_new_instance<T>(
3725     engine: &Engine,
3726     component: &Component,
3727     fun: impl Fn(&mut Store<()>, Instance) -> wasmtime::Result<T>,
3728 ) -> wasmtime::Result<T> {
3729     let mut store = Store::new(engine, ());
3730     let instance = Linker::new(engine).instantiate(&mut store, component)?;
3731     fun(&mut store, instance)
3732 }
3733