1 use super::gc_store; 2 use wasmtime::*; 3 use wasmtime_test_macros::wasmtime_test; 4 5 #[test] 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] 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] 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"] 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"] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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)] 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)] 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)] 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)] 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)] 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)] 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] 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] 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)] 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)] 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