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