xref: /wasmtime-44.0.1/tests/all/structs.rs (revision dfc4358d)
1 use wasmtime::*;
2 
3 fn gc_store() -> Result<Store<()>> {
4     let _ = env_logger::try_init();
5 
6     let mut config = Config::new();
7     config.wasm_function_references(true);
8     config.wasm_gc(true);
9 
10     let engine = Engine::new(&config)?;
11     Ok(Store::new(&engine, ()))
12 }
13 
14 #[test]
15 fn struct_new_empty() -> Result<()> {
16     let mut store = gc_store()?;
17     let struct_ty = StructType::new(store.engine(), [])?;
18     let pre = StructRefPre::new(&mut store, struct_ty);
19     StructRef::new(store, &pre, &[])?;
20     Ok(())
21 }
22 
23 #[test]
24 fn struct_new_with_fields() -> Result<()> {
25     let mut store = gc_store()?;
26     let struct_ty = StructType::new(
27         store.engine(),
28         [
29             FieldType::new(Mutability::Const, StorageType::I8),
30             FieldType::new(Mutability::Const, StorageType::ValType(ValType::I32)),
31             FieldType::new(Mutability::Var, StorageType::ValType(ValType::ANYREF)),
32         ],
33     )?;
34     let pre = StructRefPre::new(&mut store, struct_ty);
35     StructRef::new(
36         store,
37         &pre,
38         &[Val::I32(1), Val::I32(2), Val::null_any_ref()],
39     )?;
40     Ok(())
41 }
42 
43 #[test]
44 fn struct_new_unrooted_field() -> Result<()> {
45     let mut store = gc_store()?;
46     let struct_ty = StructType::new(
47         store.engine(),
48         [FieldType::new(
49             Mutability::Var,
50             StorageType::ValType(ValType::ANYREF),
51         )],
52     )?;
53     // Passing an unrooted `anyref` to `StructRef::new` results in an error.
54     let anyref = {
55         let mut scope = RootScope::new(&mut store);
56         AnyRef::from_i31(&mut scope, I31::new_i32(1234).unwrap())
57     };
58     assert!(anyref.is_i31(&store).is_err());
59     let pre = StructRefPre::new(&mut store, struct_ty);
60     assert!(StructRef::new(store, &pre, &[anyref.into()]).is_err());
61     Ok(())
62 }
63 
64 #[test]
65 #[should_panic = "wrong store"]
66 fn struct_new_cross_store_field() {
67     let mut store = gc_store().unwrap();
68     let struct_ty = StructType::new(
69         store.engine(),
70         [FieldType::new(
71             Mutability::Var,
72             StorageType::ValType(ValType::ANYREF),
73         )],
74     )
75     .unwrap();
76 
77     let mut other_store = gc_store().unwrap();
78     let anyref = AnyRef::from_i31(&mut other_store, I31::new_i32(1234).unwrap());
79 
80     let pre = StructRefPre::new(&mut store, struct_ty);
81 
82     // This should panic.
83     let _ = StructRef::new(store, &pre, &[anyref.into()]);
84 }
85 
86 #[test]
87 #[should_panic = "wrong store"]
88 fn struct_new_cross_store_pre() {
89     let mut store = gc_store().unwrap();
90     let struct_ty = StructType::new(store.engine(), []).unwrap();
91 
92     let mut other_store = gc_store().unwrap();
93     let pre = StructRefPre::new(&mut other_store, struct_ty);
94 
95     // This should panic.
96     let _ = StructRef::new(&mut store, &pre, &[]);
97 }
98 
99 #[test]
100 fn anyref_as_struct() -> Result<()> {
101     let mut store = gc_store()?;
102 
103     let struct_ty = StructType::new(
104         store.engine(),
105         [FieldType::new(Mutability::Const, StorageType::I8)],
106     )?;
107     let pre = StructRefPre::new(&mut store, struct_ty.clone());
108     let s0 = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
109 
110     let anyref: Rooted<AnyRef> = s0.into();
111     assert!(anyref.is_struct(&store)?);
112     let s1 = anyref.as_struct(&store)?.unwrap();
113     assert_eq!(s1.field(&mut store, 0)?.unwrap_i32(), 42);
114     assert!(Rooted::ref_eq(&store, &s0, &s1)?);
115 
116     let anyref: Rooted<AnyRef> = AnyRef::from_i31(&mut store, I31::new_i32(42).unwrap());
117     assert!(!anyref.is_struct(&store)?);
118     assert!(anyref.as_struct(&store)?.is_none());
119 
120     Ok(())
121 }
122 
123 #[test]
124 fn struct_field_simple() -> Result<()> {
125     let mut store = gc_store()?;
126     let struct_ty = StructType::new(
127         store.engine(),
128         [FieldType::new(
129             Mutability::Var,
130             StorageType::ValType(ValType::I32),
131         )],
132     )?;
133     let pre = StructRefPre::new(&mut store, struct_ty);
134     let s = StructRef::new(&mut store, &pre, &[Val::I32(1234)])?;
135     let val = s.field(&mut store, 0)?;
136     assert_eq!(val.unwrap_i32(), 1234);
137     Ok(())
138 }
139 
140 #[test]
141 fn struct_field_out_of_bounds() -> Result<()> {
142     let mut store = gc_store()?;
143     let struct_ty = StructType::new(
144         store.engine(),
145         [FieldType::new(
146             Mutability::Var,
147             StorageType::ValType(ValType::I32),
148         )],
149     )?;
150     let pre = StructRefPre::new(&mut store, struct_ty);
151     let s = StructRef::new(&mut store, &pre, &[Val::I32(1234)])?;
152     assert!(s.field(&mut store, 1).is_err());
153     Ok(())
154 }
155 
156 #[test]
157 fn struct_field_on_unrooted() -> Result<()> {
158     let mut store = gc_store()?;
159     let struct_ty = StructType::new(
160         store.engine(),
161         [FieldType::new(
162             Mutability::Var,
163             StorageType::ValType(ValType::I32),
164         )],
165     )?;
166     let pre = StructRefPre::new(&mut store, struct_ty);
167     let s = {
168         let mut scope = RootScope::new(&mut store);
169         StructRef::new(&mut scope, &pre, &[Val::I32(1234)])?
170     };
171     // The root scope ended and unrooted `s`.
172     assert!(s.field(&mut store, 0).is_err());
173     Ok(())
174 }
175 
176 #[test]
177 fn struct_set_field_simple() -> Result<()> {
178     let mut store = gc_store()?;
179     let struct_ty = StructType::new(
180         store.engine(),
181         [FieldType::new(
182             Mutability::Var,
183             StorageType::ValType(ValType::I32),
184         )],
185     )?;
186     let pre = StructRefPre::new(&mut store, struct_ty);
187     let s = StructRef::new(&mut store, &pre, &[Val::I32(1234)])?;
188     s.set_field(&mut store, 0, Val::I32(5678))?;
189     let val = s.field(&mut store, 0)?;
190     assert_eq!(val.unwrap_i32(), 5678);
191     Ok(())
192 }
193 
194 #[test]
195 fn struct_set_field_out_of_bounds() -> Result<()> {
196     let mut store = gc_store()?;
197     let struct_ty = StructType::new(
198         store.engine(),
199         [FieldType::new(
200             Mutability::Var,
201             StorageType::ValType(ValType::I32),
202         )],
203     )?;
204     let pre = StructRefPre::new(&mut store, struct_ty);
205     let s = StructRef::new(&mut store, &pre, &[Val::I32(1234)])?;
206     assert!(s.set_field(&mut store, 1, Val::I32(1)).is_err());
207     Ok(())
208 }
209 
210 #[test]
211 fn struct_set_field_on_unrooted() -> Result<()> {
212     let mut store = gc_store()?;
213     let struct_ty = StructType::new(
214         store.engine(),
215         [FieldType::new(
216             Mutability::Var,
217             StorageType::ValType(ValType::I32),
218         )],
219     )?;
220     let pre = StructRefPre::new(&mut store, struct_ty);
221     let s = {
222         let mut scope = RootScope::new(&mut store);
223         StructRef::new(&mut scope, &pre, &[Val::I32(1234)])?
224     };
225     // The root scope ended and unrooted `s`.
226     assert!(s.set_field(&mut store, 0, Val::I32(1)).is_err());
227     Ok(())
228 }
229 
230 #[test]
231 fn struct_set_field_with_unrooted() -> Result<()> {
232     let mut store = gc_store()?;
233     let struct_ty = StructType::new(
234         store.engine(),
235         [FieldType::new(
236             Mutability::Var,
237             StorageType::ValType(ValType::ANYREF),
238         )],
239     )?;
240     let pre = StructRefPre::new(&mut store, struct_ty);
241     let s = StructRef::new(&mut store, &pre, &[Val::null_any_ref()])?;
242     let anyref = {
243         let mut scope = RootScope::new(&mut store);
244         AnyRef::from_i31(&mut scope, I31::wrapping_i32(42))
245     };
246     // The root scope ended and `anyref` is unrooted.
247     assert!(s.set_field(&mut store, 0, anyref.into()).is_err());
248     Ok(())
249 }
250 
251 #[test]
252 fn struct_set_field_cross_store_value() -> Result<()> {
253     let mut store = gc_store()?;
254     let struct_ty = StructType::new(
255         store.engine(),
256         [FieldType::new(
257             Mutability::Var,
258             StorageType::ValType(ValType::EXTERNREF),
259         )],
260     )?;
261     let pre = StructRefPre::new(&mut store, struct_ty);
262     let s = StructRef::new(&mut store, &pre, &[Val::null_extern_ref()])?;
263 
264     let mut other_store = gc_store()?;
265     let externref = ExternRef::new(&mut other_store, "blah")?;
266 
267     assert!(s.set_field(&mut store, 0, externref.into()).is_err());
268     Ok(())
269 }
270 
271 #[test]
272 fn struct_set_field_immutable() -> Result<()> {
273     let mut store = gc_store()?;
274     let struct_ty = StructType::new(
275         store.engine(),
276         [FieldType::new(
277             Mutability::Const,
278             StorageType::ValType(ValType::I32),
279         )],
280     )?;
281     let pre = StructRefPre::new(&mut store, struct_ty);
282     let s = StructRef::new(&mut store, &pre, &[Val::I32(1234)])?;
283     assert!(s.set_field(&mut store, 0, Val::I32(5678)).is_err());
284     Ok(())
285 }
286 
287 #[test]
288 fn struct_set_field_wrong_type() -> Result<()> {
289     let mut store = gc_store()?;
290     let struct_ty = StructType::new(
291         store.engine(),
292         [FieldType::new(
293             Mutability::Const,
294             StorageType::ValType(ValType::I32),
295         )],
296     )?;
297     let pre = StructRefPre::new(&mut store, struct_ty);
298     let s = StructRef::new(&mut store, &pre, &[Val::I32(1234)])?;
299     assert!(s.set_field(&mut store, 0, Val::I64(5678)).is_err());
300     Ok(())
301 }
302 
303 #[test]
304 fn struct_ty() -> Result<()> {
305     let mut store = gc_store()?;
306     let struct_ty = StructType::new(store.engine(), [])?;
307     let pre = StructRefPre::new(&mut store, struct_ty.clone());
308     let s = StructRef::new(&mut store, &pre, &[])?;
309     assert!(StructType::eq(&struct_ty, &s.ty(&store)?));
310     Ok(())
311 }
312 
313 #[test]
314 fn struct_ty_unrooted() -> Result<()> {
315     let mut store = gc_store()?;
316     let struct_ty = StructType::new(store.engine(), [])?;
317     let pre = StructRefPre::new(&mut store, struct_ty);
318     let s = {
319         let mut scope = RootScope::new(&mut store);
320         StructRef::new(&mut scope, &pre, &[])?
321     };
322     // The root scope ended and `s` is unrooted.
323     assert!(s.ty(&mut store).is_err());
324     Ok(())
325 }
326 
327 #[test]
328 fn struct_fields_empty() -> Result<()> {
329     let mut store = gc_store()?;
330     let struct_ty = StructType::new(store.engine(), [])?;
331     let pre = StructRefPre::new(&mut store, struct_ty.clone());
332     let s = StructRef::new(&mut store, &pre, &[])?;
333     let fields = s.fields(&mut store)?;
334     assert_eq!(fields.len(), 0);
335     assert!(fields.collect::<Vec<_>>().is_empty());
336     Ok(())
337 }
338 
339 #[test]
340 fn struct_fields_non_empty() -> Result<()> {
341     let mut store = gc_store()?;
342     let struct_ty = StructType::new(
343         store.engine(),
344         [
345             FieldType::new(Mutability::Const, StorageType::I8),
346             FieldType::new(Mutability::Var, StorageType::ValType(ValType::ANYREF)),
347         ],
348     )?;
349     let pre = StructRefPre::new(&mut store, struct_ty.clone());
350     let s = StructRef::new(&mut store, &pre, &[Val::I32(36), Val::null_any_ref()])?;
351     let mut fields = s.fields(&mut store)?;
352     assert_eq!(fields.len(), 2);
353     assert_eq!(fields.next().unwrap().unwrap_i32(), 36);
354     assert!(fields.next().unwrap().unwrap_any_ref().is_none());
355     assert!(fields.next().is_none());
356     Ok(())
357 }
358 
359 #[test]
360 fn struct_fields_unrooted() -> Result<()> {
361     let mut store = gc_store()?;
362     let struct_ty = StructType::new(store.engine(), [])?;
363     let pre = StructRefPre::new(&mut store, struct_ty);
364     let s = {
365         let mut scope = RootScope::new(&mut store);
366         StructRef::new(&mut scope, &pre, &[])?
367     };
368     // The root scope ended and `s` is unrooted.
369     assert!(s.fields(&mut store).is_err());
370     Ok(())
371 }
372 
373 #[test]
374 #[cfg_attr(miri, ignore)]
375 fn passing_structs_through_wasm_with_untyped_calls() -> Result<()> {
376     let mut store = gc_store()?;
377 
378     let module = Module::new(
379         store.engine(),
380         r#"
381             (module
382                 (type (struct (field i8)))
383                 (import "" "" (func $f (param (ref 0)) (result (ref 0))))
384                 (func (export "run") (param (ref 0)) (result (ref 0))
385                     (call $f (local.get 0))
386                 )
387             )
388         "#,
389     )?;
390 
391     let struct_ty = StructType::new(
392         store.engine(),
393         [FieldType::new(Mutability::Const, StorageType::I8)],
394     )?;
395 
396     let ref_ty = RefType::new(false, HeapType::ConcreteStruct(struct_ty.clone()));
397     let func_ty = FuncType::new(store.engine(), [ref_ty.clone().into()], [ref_ty.into()]);
398 
399     let func = Func::new(&mut store, func_ty, |mut caller, args, results| {
400         let s = args[0].unwrap_any_ref().unwrap();
401         let s = s.unwrap_struct(&mut caller)?;
402         assert_eq!(s.field(&mut caller, 0)?.unwrap_i32(), 42);
403         results[0] = args[0].clone();
404         Ok(())
405     });
406 
407     let instance = Instance::new(&mut store, &module, &[func.into()])?;
408     let run = instance.get_func(&mut store, "run").unwrap();
409 
410     let pre = StructRefPre::new(&mut store, struct_ty.clone());
411     let s = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
412 
413     let mut results = vec![Val::null_any_ref()];
414     run.call(&mut store, &[s.into()], &mut results)?;
415 
416     let t = results[0].unwrap_any_ref().unwrap();
417     let t = t.unwrap_struct(&mut store)?;
418     assert_eq!(t.field(&mut store, 0)?.unwrap_i32(), 42);
419     assert!(Rooted::ref_eq(&store, &s, &t)?);
420 
421     Ok(())
422 }
423 
424 #[test]
425 #[cfg_attr(miri, ignore)]
426 fn passing_structs_through_wasm_with_typed_calls() -> Result<()> {
427     let mut store = gc_store()?;
428 
429     let module = Module::new(
430         store.engine(),
431         r#"
432             (module
433                 (type (struct (field i8)))
434                 (import "" "" (func $f (param (ref struct)) (result (ref struct))))
435                 (func (export "run") (param (ref 0)) (result (ref struct))
436                     (call $f (local.get 0))
437                 )
438             )
439         "#,
440     )?;
441 
442     let struct_ty = StructType::new(
443         store.engine(),
444         [FieldType::new(Mutability::Const, StorageType::I8)],
445     )?;
446 
447     let func = Func::wrap(
448         &mut store,
449         |mut caller: Caller<()>, s: Rooted<StructRef>| -> Result<Rooted<StructRef>> {
450             assert_eq!(s.field(&mut caller, 0)?.unwrap_i32(), 42);
451             Ok(s)
452         },
453     );
454 
455     let instance = Instance::new(&mut store, &module, &[func.into()])?;
456     let run = instance.get_typed_func::<Rooted<StructRef>, Rooted<StructRef>>(&mut store, "run")?;
457 
458     let pre = StructRefPre::new(&mut store, struct_ty.clone());
459     let s = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
460 
461     let t = run.call(&mut store, s)?;
462 
463     assert_eq!(t.field(&mut store, 0)?.unwrap_i32(), 42);
464     assert!(Rooted::ref_eq(&store, &s, &t)?);
465 
466     Ok(())
467 }
468 
469 #[test]
470 #[cfg_attr(miri, ignore)]
471 fn host_sets_struct_global() -> Result<()> {
472     let mut store = gc_store()?;
473 
474     let module = Module::new(
475         store.engine(),
476         r#"
477             (module
478                 (type (struct (field i8)))
479                 (global $g (export "g") (mut (ref null 0)) (ref.null 0))
480                 (func (export "f") (result (ref null 0))
481                     global.get $g
482                 )
483             )
484         "#,
485     )?;
486 
487     let instance = Instance::new(&mut store, &module, &[])?;
488     let g = instance.get_global(&mut store, "g").unwrap();
489 
490     let struct_ty = StructType::new(
491         store.engine(),
492         [FieldType::new(Mutability::Const, StorageType::I8)],
493     )?;
494     let pre = StructRefPre::new(&mut store, struct_ty.clone());
495     let s0 = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
496     g.set(&mut store, s0.into())?;
497 
498     // Get the global from the host.
499     let val = g.get(&mut store);
500     let anyref = val.unwrap_anyref().expect("non-null");
501     let s1 = anyref.unwrap_struct(&store)?;
502     assert_eq!(s1.field(&mut store, 0)?.unwrap_i32(), 42);
503     assert!(Rooted::ref_eq(&store, &s0, &s1)?);
504 
505     // Get the global from the guest.
506     let f = instance.get_typed_func::<(), Option<Rooted<StructRef>>>(&mut store, "f")?;
507     let s2 = f.call(&mut store, ())?.expect("non-null");
508     assert_eq!(s2.field(&mut store, 0)?.unwrap_i32(), 42);
509     assert!(Rooted::ref_eq(&store, &s0, &s2)?);
510 
511     Ok(())
512 }
513 
514 #[test]
515 #[cfg_attr(miri, ignore)]
516 fn wasm_sets_struct_global() -> Result<()> {
517     let mut store = gc_store()?;
518 
519     let module = Module::new(
520         store.engine(),
521         r#"
522             (module
523                 (type (struct (field i8)))
524                 (global $g (export "g") (mut (ref null 0)) (ref.null 0))
525                 (func (export "get") (result (ref null 0))
526                     global.get $g
527                 )
528                 (func (export "set") (param (ref null 0))
529                     local.get 0
530                     global.set $g
531                 )
532             )
533         "#,
534     )?;
535 
536     let struct_ty = StructType::new(
537         store.engine(),
538         [FieldType::new(Mutability::Const, StorageType::I8)],
539     )?;
540     let pre = StructRefPre::new(&mut store, struct_ty.clone());
541     let s0 = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
542 
543     let instance = Instance::new(&mut store, &module, &[])?;
544     let set = instance.get_func(&mut store, "set").unwrap();
545     set.call(&mut store, &[s0.into()], &mut [])?;
546 
547     // Get the global from the host.
548     let g = instance.get_global(&mut store, "g").unwrap();
549     let val = g.get(&mut store);
550     let anyref = val.unwrap_anyref().expect("non-null");
551     let s1 = anyref.unwrap_struct(&store)?;
552     assert_eq!(s1.field(&mut store, 0)?.unwrap_i32(), 42);
553     assert!(Rooted::ref_eq(&store, &s0, &s1)?);
554 
555     // Get the global from the guest.
556     let f = instance.get_typed_func::<(), Option<Rooted<StructRef>>>(&mut store, "get")?;
557     let s2 = f.call(&mut store, ())?.expect("non-null");
558     assert_eq!(s2.field(&mut store, 0)?.unwrap_i32(), 42);
559     assert!(Rooted::ref_eq(&store, &s0, &s2)?);
560 
561     Ok(())
562 }
563 
564 #[test]
565 #[cfg_attr(miri, ignore)]
566 fn host_sets_struct_in_table() -> Result<()> {
567     let mut store = gc_store()?;
568 
569     let module = Module::new(
570         store.engine(),
571         r#"
572             (module
573                 (type (struct (field i8)))
574                 (table $t (export "t") 1 1 (ref null 0) (ref.null 0))
575                 (func (export "f") (result (ref null 0))
576                     i32.const 0
577                     table.get $t
578                 )
579             )
580         "#,
581     )?;
582 
583     let instance = Instance::new(&mut store, &module, &[])?;
584     let t = instance.get_table(&mut store, "t").unwrap();
585 
586     let struct_ty = StructType::new(
587         store.engine(),
588         [FieldType::new(Mutability::Const, StorageType::I8)],
589     )?;
590     let pre = StructRefPre::new(&mut store, struct_ty.clone());
591     let s0 = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
592     t.set(&mut store, 0, s0.into())?;
593 
594     // Get the global from the host.
595     let val = t.get(&mut store, 0).expect("in bounds");
596     let anyref = val.unwrap_any().expect("non-null");
597     let s1 = anyref.unwrap_struct(&store)?;
598     assert_eq!(s1.field(&mut store, 0)?.unwrap_i32(), 42);
599     assert!(Rooted::ref_eq(&store, &s0, &s1)?);
600 
601     // Get the global from the guest.
602     let f = instance.get_typed_func::<(), Option<Rooted<StructRef>>>(&mut store, "f")?;
603     let s2 = f.call(&mut store, ())?.expect("non-null");
604     assert_eq!(s2.field(&mut store, 0)?.unwrap_i32(), 42);
605     assert!(Rooted::ref_eq(&store, &s0, &s2)?);
606 
607     Ok(())
608 }
609 
610 #[test]
611 #[cfg_attr(miri, ignore)]
612 fn wasm_sets_struct_in_table() -> Result<()> {
613     let mut store = gc_store()?;
614 
615     let module = Module::new(
616         store.engine(),
617         r#"
618             (module
619                 (type (struct (field i8)))
620                 (table $t (export "t") 1 1 (ref null 0) (ref.null 0))
621                 (func (export "get") (result (ref null 0))
622                     i32.const 0
623                     table.get $t
624                 )
625                 (func (export "set") (param (ref null 0))
626                     i32.const 0
627                     local.get 0
628                     table.set $t
629                 )
630             )
631         "#,
632     )?;
633 
634     let struct_ty = StructType::new(
635         store.engine(),
636         [FieldType::new(Mutability::Const, StorageType::I8)],
637     )?;
638     let pre = StructRefPre::new(&mut store, struct_ty.clone());
639     let s0 = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
640 
641     let instance = Instance::new(&mut store, &module, &[])?;
642     let set = instance.get_func(&mut store, "set").unwrap();
643     set.call(&mut store, &[s0.into()], &mut [])?;
644 
645     // Get the global from the host.
646     let t = instance.get_table(&mut store, "t").unwrap();
647     let val = t.get(&mut store, 0).expect("in bounds");
648     let anyref = val.unwrap_any().expect("non-null");
649     let s1 = anyref.unwrap_struct(&store)?;
650     assert_eq!(s1.field(&mut store, 0)?.unwrap_i32(), 42);
651     assert!(Rooted::ref_eq(&store, &s0, &s1)?);
652 
653     // Get the global from the guest.
654     let f = instance.get_typed_func::<(), Option<Rooted<StructRef>>>(&mut store, "get")?;
655     let s2 = f.call(&mut store, ())?.expect("non-null");
656     assert_eq!(s2.field(&mut store, 0)?.unwrap_i32(), 42);
657     assert!(Rooted::ref_eq(&store, &s0, &s2)?);
658 
659     Ok(())
660 }
661 
662 #[test]
663 fn instantiate_with_struct_global() -> Result<()> {
664     let mut store = gc_store()?;
665 
666     let module = Module::new(
667         store.engine(),
668         r#"
669             (module
670                 (type (struct (field i8)))
671                 (import "" "" (global (ref null 0)))
672                 (export "g" (global 0))
673             )
674         "#,
675     )?;
676 
677     let struct_ty = StructType::new(
678         store.engine(),
679         [FieldType::new(Mutability::Const, StorageType::I8)],
680     )?;
681     let global_ty = GlobalType::new(
682         ValType::Ref(RefType::new(
683             true,
684             HeapType::ConcreteStruct(struct_ty.clone()),
685         )),
686         Mutability::Const,
687     );
688 
689     // Instantiate with a null-ref global.
690     let g = Global::new(&mut store, global_ty.clone(), Val::AnyRef(None))?;
691     let instance = Instance::new(&mut store, &module, &[g.into()])?;
692     let g = instance.get_global(&mut store, "g").expect("export exists");
693     let val = g.get(&mut store);
694     assert!(val.unwrap_anyref().is_none());
695 
696     // Instantiate with a non-null-ref global.
697     let pre = StructRefPre::new(&mut store, struct_ty);
698     let s0 = StructRef::new(&mut store, &pre, &[Val::I32(42)])?;
699     let g = Global::new(&mut store, global_ty, s0.into())?;
700     let instance = Instance::new(&mut store, &module, &[g.into()])?;
701     let g = instance.get_global(&mut store, "g").expect("export exists");
702     let val = g.get(&mut store);
703     let anyref = val.unwrap_anyref().expect("non-null");
704     let s1 = anyref.unwrap_struct(&store)?;
705     assert_eq!(s1.field(&mut store, 0)?.unwrap_i32(), 42);
706     assert!(Rooted::ref_eq(&store, &s0, &s1)?);
707 
708     Ok(())
709 }
710