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