Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/host_funcs.rs
3050 views
1
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
2
use wasmtime::bail;
3
use wasmtime::*;
4
5
#[test]
6
fn wrap_func() -> Result<()> {
7
let engine = Engine::default();
8
let mut linker = Linker::<()>::new(&engine);
9
linker.allow_shadowing(true);
10
11
linker.func_wrap("", "", || {})?;
12
linker.func_wrap("m", "f", |_: i32| {})?;
13
linker.func_wrap("m", "f2", |_: i32, _: i64| {})?;
14
linker.func_wrap("m2", "f", |_: f32, _: f64| {})?;
15
linker.func_wrap("m2", "f2", || -> i32 { 0 })?;
16
linker.func_wrap("", "", || -> i64 { 0 })?;
17
linker.func_wrap("m", "f", || -> f32 { 0.0 })?;
18
linker.func_wrap("m2", "f", || -> f64 { 0.0 })?;
19
linker.func_wrap("m3", "", || -> Option<Rooted<ExternRef>> { None })?;
20
linker.func_wrap("m3", "f", || -> Option<Func> { None })?;
21
22
linker.func_wrap("", "f1", || -> Result<()> {
23
loop {}
24
})?;
25
linker.func_wrap("", "f2", || -> Result<i32> {
26
loop {}
27
})?;
28
linker.func_wrap("", "f3", || -> Result<i64> {
29
loop {}
30
})?;
31
linker.func_wrap("", "f4", || -> Result<f32> {
32
loop {}
33
})?;
34
linker.func_wrap("", "f5", || -> Result<f64> {
35
loop {}
36
})?;
37
linker.func_wrap("", "f6", || -> Result<Option<Rooted<ExternRef>>> {
38
loop {}
39
})?;
40
linker.func_wrap("", "f7", || -> Result<Option<Func>> {
41
loop {}
42
})?;
43
Ok(())
44
}
45
46
#[test]
47
fn drop_func() -> Result<()> {
48
static HITS: AtomicUsize = AtomicUsize::new(0);
49
struct A;
50
51
impl Drop for A {
52
fn drop(&mut self) {
53
HITS.fetch_add(1, SeqCst);
54
}
55
}
56
57
let engine = Engine::default();
58
let mut linker = Linker::<()>::new(&engine);
59
linker.allow_shadowing(true);
60
61
let a = A;
62
linker.func_wrap("", "", move || {
63
let _ = &a;
64
})?;
65
66
assert_eq!(HITS.load(SeqCst), 0);
67
68
// Define the function again to ensure redefined functions are dropped
69
70
let a = A;
71
linker.func_wrap("", "", move || {
72
let _ = &a;
73
})?;
74
75
assert_eq!(HITS.load(SeqCst), 1);
76
77
drop(linker);
78
79
assert_eq!(HITS.load(SeqCst), 2);
80
81
Ok(())
82
}
83
84
#[test]
85
#[cfg_attr(miri, ignore)]
86
fn drop_delayed() -> Result<()> {
87
static HITS: AtomicUsize = AtomicUsize::new(0);
88
89
struct A;
90
91
impl Drop for A {
92
fn drop(&mut self) {
93
HITS.fetch_add(1, SeqCst);
94
}
95
}
96
97
let engine = Engine::default();
98
let mut linker = Linker::<()>::new(&engine);
99
100
let a = A;
101
linker.func_wrap("", "", move || {
102
let _ = &a;
103
})?;
104
105
assert_eq!(HITS.load(SeqCst), 0);
106
107
let module = Module::new(&engine, &wat::parse_str(r#"(import "" "" (func))"#)?)?;
108
109
let mut store = Store::new(&engine, ());
110
let func = linker.get(&mut store, "", "").unwrap();
111
Instance::new(&mut store, &module, &[func])?;
112
113
drop(store);
114
115
assert_eq!(HITS.load(SeqCst), 0);
116
117
let mut store = Store::new(&engine, ());
118
let func = linker.get(&mut store, "", "").unwrap();
119
Instance::new(&mut store, &module, &[func])?;
120
121
drop(store);
122
123
assert_eq!(HITS.load(SeqCst), 0);
124
125
drop(linker);
126
127
assert_eq!(HITS.load(SeqCst), 1);
128
129
Ok(())
130
}
131
132
#[test]
133
fn signatures_match() -> Result<()> {
134
let engine = Engine::default();
135
let mut linker = Linker::<()>::new(&engine);
136
137
linker.func_wrap("", "f1", || {})?;
138
linker.func_wrap("", "f2", || -> i32 {
139
loop {}
140
})?;
141
linker.func_wrap("", "f3", || -> i64 {
142
loop {}
143
})?;
144
linker.func_wrap("", "f4", || -> f32 {
145
loop {}
146
})?;
147
linker.func_wrap("", "f5", || -> f64 {
148
loop {}
149
})?;
150
linker.func_wrap(
151
"",
152
"f6",
153
|_: f32,
154
_: f64,
155
_: i32,
156
_: i64,
157
_: i32,
158
_: Option<Rooted<ExternRef>>,
159
_: Option<Func>|
160
-> f64 { loop {} },
161
)?;
162
163
let mut store = Store::new(&engine, ());
164
165
let f = linker
166
.get(&mut store, "", "f1")
167
.unwrap()
168
.into_func()
169
.unwrap();
170
assert_eq!(f.ty(&store).params().len(), 0);
171
assert_eq!(f.ty(&store).results().len(), 0);
172
173
let f = linker
174
.get(&mut store, "", "f2")
175
.unwrap()
176
.into_func()
177
.unwrap();
178
assert_eq!(f.ty(&store).params().len(), 0);
179
assert_eq!(f.ty(&store).results().len(), 1);
180
assert!(f.ty(&store).results().nth(0).unwrap().is_i32());
181
182
let f = linker
183
.get(&mut store, "", "f3")
184
.unwrap()
185
.into_func()
186
.unwrap();
187
assert_eq!(f.ty(&store).params().len(), 0);
188
assert_eq!(f.ty(&store).results().len(), 1);
189
assert!(f.ty(&store).results().nth(0).unwrap().is_i64());
190
191
let f = linker
192
.get(&mut store, "", "f4")
193
.unwrap()
194
.into_func()
195
.unwrap();
196
assert_eq!(f.ty(&store).params().len(), 0);
197
assert_eq!(f.ty(&store).results().len(), 1);
198
assert!(f.ty(&store).results().nth(0).unwrap().is_f32());
199
200
let f = linker
201
.get(&mut store, "", "f5")
202
.unwrap()
203
.into_func()
204
.unwrap();
205
assert_eq!(f.ty(&store).params().len(), 0);
206
assert_eq!(f.ty(&store).results().len(), 1);
207
assert!(f.ty(&store).results().nth(0).unwrap().is_f64());
208
209
let f = linker
210
.get(&mut store, "", "f6")
211
.unwrap()
212
.into_func()
213
.unwrap();
214
215
assert_eq!(f.ty(&store).params().len(), 7);
216
assert!(f.ty(&store).params().nth(0).unwrap().is_f32());
217
assert!(f.ty(&store).params().nth(1).unwrap().is_f64());
218
assert!(f.ty(&store).params().nth(2).unwrap().is_i32());
219
assert!(f.ty(&store).params().nth(3).unwrap().is_i64());
220
assert!(f.ty(&store).params().nth(4).unwrap().is_i32());
221
assert!(f.ty(&store).params().nth(5).unwrap().is_externref());
222
assert!(f.ty(&store).params().nth(6).unwrap().is_funcref());
223
224
assert_eq!(f.ty(&store).results().len(), 1);
225
assert!(f.ty(&store).results().nth(0).unwrap().is_f64());
226
227
Ok(())
228
}
229
230
#[test]
231
#[cfg_attr(miri, ignore)]
232
fn import_works() -> Result<()> {
233
static HITS: AtomicUsize = AtomicUsize::new(0);
234
235
let wasm = wat::parse_str(
236
r#"
237
(import "" "f1" (func))
238
(import "" "f2" (func (param i32) (result i32)))
239
(import "" "f3" (func (param i32) (param i64)))
240
(import "" "f4" (func (param i32 i64 i32 f32 f64 externref funcref)))
241
242
(func (export "run") (param externref funcref)
243
call 0
244
i32.const 0
245
call 1
246
i32.const 1
247
i32.add
248
i64.const 3
249
call 2
250
251
i32.const 100
252
i64.const 200
253
i32.const 300
254
f32.const 400
255
f64.const 500
256
local.get 0
257
local.get 1
258
call 3
259
)
260
"#,
261
)?;
262
263
let engine = Engine::default();
264
let mut linker = Linker::<()>::new(&engine);
265
266
linker.func_wrap("", "f1", || {
267
assert_eq!(HITS.fetch_add(1, SeqCst), 0);
268
})?;
269
270
linker.func_wrap("", "f2", |x: i32| -> i32 {
271
assert_eq!(x, 0);
272
assert_eq!(HITS.fetch_add(1, SeqCst), 1);
273
1
274
})?;
275
276
linker.func_wrap("", "f3", |x: i32, y: i64| {
277
assert_eq!(x, 2);
278
assert_eq!(y, 3);
279
assert_eq!(HITS.fetch_add(1, SeqCst), 2);
280
})?;
281
282
linker.func_wrap(
283
"",
284
"f4",
285
|mut caller: Caller<'_, _>,
286
a: i32,
287
b: i64,
288
c: i32,
289
d: f32,
290
e: f64,
291
f: Option<Rooted<ExternRef>>,
292
g: Option<Func>| {
293
assert_eq!(a, 100);
294
assert_eq!(b, 200);
295
assert_eq!(c, 300);
296
assert_eq!(d, 400.0);
297
assert_eq!(e, 500.0);
298
assert_eq!(
299
f.as_ref()
300
.unwrap()
301
.data(&caller)
302
.unwrap()
303
.unwrap()
304
.downcast_ref::<String>()
305
.unwrap(),
306
"hello"
307
);
308
let mut results = [Val::I32(0)];
309
g.as_ref()
310
.unwrap()
311
.call(&mut caller, &[], &mut results)
312
.unwrap();
313
assert_eq!(results[0].unwrap_i32(), 42);
314
assert_eq!(HITS.fetch_add(1, SeqCst), 3);
315
},
316
)?;
317
318
let module = Module::new(&engine, &wasm)?;
319
320
let mut store = Store::new(&engine, ());
321
let instance = linker.instantiate(&mut store, &module)?;
322
let run = instance.get_func(&mut store, "run").unwrap();
323
let funcref = Val::FuncRef(Some(Func::wrap(&mut store, || -> i32 { 42 })));
324
let externref = Val::ExternRef(Some(ExternRef::new(&mut store, "hello".to_string())?));
325
run.call(&mut store, &[externref, funcref], &mut [])?;
326
327
assert_eq!(HITS.load(SeqCst), 4);
328
329
Ok(())
330
}
331
332
#[test]
333
#[cfg_attr(miri, ignore)]
334
fn call_import_many_args() -> Result<()> {
335
let wasm = wat::parse_str(
336
r#"
337
(import "" "host" (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
338
(func (export "run")
339
i32.const 1
340
i32.const 2
341
i32.const 3
342
i32.const 4
343
i32.const 5
344
i32.const 6
345
i32.const 7
346
i32.const 8
347
i32.const 9
348
i32.const 10
349
call 0
350
)
351
"#,
352
)?;
353
354
let engine = Engine::default();
355
let mut linker = Linker::<()>::new(&engine);
356
357
linker.func_wrap(
358
"",
359
"host",
360
|x1: i32,
361
x2: i32,
362
x3: i32,
363
x4: i32,
364
x5: i32,
365
x6: i32,
366
x7: i32,
367
x8: i32,
368
x9: i32,
369
x10: i32| {
370
assert_eq!(x1, 1);
371
assert_eq!(x2, 2);
372
assert_eq!(x3, 3);
373
assert_eq!(x4, 4);
374
assert_eq!(x5, 5);
375
assert_eq!(x6, 6);
376
assert_eq!(x7, 7);
377
assert_eq!(x8, 8);
378
assert_eq!(x9, 9);
379
assert_eq!(x10, 10);
380
},
381
)?;
382
383
let module = Module::new(&engine, &wasm)?;
384
let mut store = Store::new(&engine, ());
385
let instance = linker.instantiate(&mut store, &module)?;
386
let run = instance.get_func(&mut store, "run").unwrap();
387
run.call(&mut store, &[], &mut [])?;
388
389
Ok(())
390
}
391
392
#[test]
393
#[cfg_attr(miri, ignore)]
394
fn call_wasm_many_args() -> Result<()> {
395
let wasm = wat::parse_str(
396
r#"
397
(func (export "run") (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
398
i32.const 1
399
local.get 0
400
i32.ne
401
if
402
unreachable
403
end
404
405
i32.const 10
406
local.get 9
407
i32.ne
408
if
409
unreachable
410
end
411
)
412
413
(func (export "test")
414
i32.const 1
415
i32.const 2
416
i32.const 3
417
i32.const 4
418
i32.const 5
419
i32.const 6
420
i32.const 7
421
i32.const 8
422
i32.const 9
423
i32.const 10
424
call 0
425
)
426
"#,
427
)?;
428
429
let engine = Engine::default();
430
let module = Module::new(&engine, &wasm)?;
431
432
let mut store = Store::new(&engine, ());
433
let instance = Instance::new(&mut store, &module, &[])?;
434
435
let run = instance.get_func(&mut store, "run").unwrap();
436
run.call(
437
&mut store,
438
&[
439
1.into(),
440
2.into(),
441
3.into(),
442
4.into(),
443
5.into(),
444
6.into(),
445
7.into(),
446
8.into(),
447
9.into(),
448
10.into(),
449
],
450
&mut [],
451
)?;
452
453
let typed_run = instance
454
.get_typed_func::<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), ()>(
455
&mut store, "run",
456
)?;
457
typed_run.call(&mut store, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))?;
458
459
let test = instance.get_func(&mut store, "test").unwrap();
460
test.call(&mut store, &[], &mut [])?;
461
462
Ok(())
463
}
464
465
#[test]
466
#[cfg_attr(miri, ignore)]
467
fn trap_smoke() -> Result<()> {
468
let engine = Engine::default();
469
let mut linker = Linker::<()>::new(&engine);
470
linker.func_wrap("", "", || -> Result<()> { bail!("test") })?;
471
472
let mut store = Store::new(&engine, ());
473
474
let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
475
476
let err = f.call(&mut store, &[], &mut []).unwrap_err();
477
478
assert!(err.to_string().contains("test"));
479
480
Ok(())
481
}
482
483
#[test]
484
#[cfg_attr(miri, ignore)]
485
fn trap_import() -> Result<()> {
486
let wasm = wat::parse_str(
487
r#"
488
(import "" "" (func))
489
(start 0)
490
"#,
491
)?;
492
493
let engine = Engine::default();
494
let mut linker = Linker::new(&engine);
495
linker.func_wrap("", "", || -> Result<()> { bail!("foo") })?;
496
497
let module = Module::new(&engine, &wasm)?;
498
let mut store = Store::new(&engine, ());
499
500
let trap = linker.instantiate(&mut store, &module).unwrap_err();
501
502
assert!(trap.to_string().contains("foo"));
503
504
Ok(())
505
}
506
507
#[test]
508
#[cfg_attr(miri, ignore)]
509
fn new_from_signature() -> Result<()> {
510
let engine = Engine::default();
511
let mut linker = Linker::new(&engine);
512
513
let ty = FuncType::new(&engine, None, None);
514
linker.func_new("", "f1", ty, |_, _, _| panic!())?;
515
516
let ty = FuncType::new(&engine, Some(ValType::I32), Some(ValType::F64));
517
linker.func_new("", "f2", ty, |_, _, _| panic!())?;
518
519
let mut store = Store::new(&engine, ());
520
521
let f = linker
522
.get(&mut store, "", "f1")
523
.unwrap()
524
.into_func()
525
.unwrap();
526
assert!(f.typed::<(), ()>(&store).is_ok());
527
assert!(f.typed::<(), i32>(&store).is_err());
528
assert!(f.typed::<i32, ()>(&store).is_err());
529
530
let f = linker
531
.get(&mut store, "", "f2")
532
.unwrap()
533
.into_func()
534
.unwrap();
535
assert!(f.typed::<(), ()>(&store).is_err());
536
assert!(f.typed::<(), i32>(&store).is_err());
537
assert!(f.typed::<i32, ()>(&store).is_err());
538
assert!(f.typed::<i32, f64>(&store).is_ok());
539
540
Ok(())
541
}
542
543
#[test]
544
fn call_wrapped_func() -> Result<()> {
545
let engine = Engine::default();
546
let mut linker = Linker::new(&engine);
547
let mut results = [Val::I32(0)];
548
549
linker.func_wrap("", "f1", |a: i32, b: i64, c: f32, d: f64| {
550
assert_eq!(a, 1);
551
assert_eq!(b, 2);
552
assert_eq!(c, 3.0);
553
assert_eq!(d, 4.0);
554
})?;
555
556
linker.func_wrap("", "f2", || 1i32)?;
557
558
linker.func_wrap("", "f3", || 2i64)?;
559
560
linker.func_wrap("", "f4", || 3.0f32)?;
561
562
linker.func_wrap("", "f5", || 4.0f64)?;
563
564
let mut store = Store::new(&engine, ());
565
566
let f = linker
567
.get(&mut store, "", "f1")
568
.unwrap()
569
.into_func()
570
.unwrap();
571
f.call(
572
&mut store,
573
&[Val::I32(1), Val::I64(2), 3.0f32.into(), 4.0f64.into()],
574
&mut [],
575
)?;
576
f.typed::<(i32, i64, f32, f64), ()>(&store)?
577
.call(&mut store, (1, 2, 3.0, 4.0))?;
578
579
let f = linker
580
.get(&mut store, "", "f2")
581
.unwrap()
582
.into_func()
583
.unwrap();
584
f.call(&mut store, &[], &mut results)?;
585
assert_eq!(results[0].unwrap_i32(), 1);
586
assert_eq!(f.typed::<(), i32>(&store)?.call(&mut store, ())?, 1);
587
588
let f = linker
589
.get(&mut store, "", "f3")
590
.unwrap()
591
.into_func()
592
.unwrap();
593
f.call(&mut store, &[], &mut results)?;
594
assert_eq!(results[0].unwrap_i64(), 2);
595
assert_eq!(f.typed::<(), i64>(&store)?.call(&mut store, ())?, 2);
596
597
let f = linker
598
.get(&mut store, "", "f4")
599
.unwrap()
600
.into_func()
601
.unwrap();
602
f.call(&mut store, &[], &mut results)?;
603
assert_eq!(results[0].unwrap_f32(), 3.0);
604
assert_eq!(f.typed::<(), f32>(&store)?.call(&mut store, ())?, 3.0);
605
606
let f = linker
607
.get(&mut store, "", "f5")
608
.unwrap()
609
.into_func()
610
.unwrap();
611
f.call(&mut store, &[], &mut results)?;
612
assert_eq!(results[0].unwrap_f64(), 4.0);
613
assert_eq!(f.typed::<(), f64>(&store)?.call(&mut store, ())?, 4.0);
614
615
Ok(())
616
}
617
618
#[test]
619
#[cfg_attr(miri, ignore)]
620
fn func_return_nothing() -> Result<()> {
621
let engine = Engine::default();
622
let mut linker = Linker::new(&engine);
623
let ty = FuncType::new(&engine, None, Some(ValType::I32));
624
linker.func_new("", "", ty, |_, _, _| Ok(()))?;
625
626
let mut store = Store::new(&engine, ());
627
let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
628
let err = f.call(&mut store, &[], &mut [Val::I32(0)]).unwrap_err();
629
assert!(
630
err.to_string()
631
.contains("function attempted to return an incompatible value")
632
);
633
Ok(())
634
}
635
636
#[test]
637
#[cfg_attr(miri, ignore)]
638
fn call_via_funcref() -> Result<()> {
639
static HITS: AtomicUsize = AtomicUsize::new(0);
640
641
struct A;
642
643
impl Drop for A {
644
fn drop(&mut self) {
645
HITS.fetch_add(1, SeqCst);
646
}
647
}
648
649
let wasm = wat::parse_str(
650
r#"
651
(table $t 1 funcref)
652
(type $add (func (param i32 i32) (result i32)))
653
(func (export "call") (param funcref) (result i32 funcref)
654
(table.set $t (i32.const 0) (local.get 0))
655
(call_indirect (type $add) (i32.const 3) (i32.const 4) (i32.const 0))
656
(local.get 0)
657
)
658
"#,
659
)?;
660
661
let engine = Engine::default();
662
let mut linker = Linker::new(&engine);
663
let a = A;
664
linker.func_wrap("", "", move |x: i32, y: i32| {
665
let _ = &a;
666
x + y
667
})?;
668
669
let module = Module::new(&engine, &wasm)?;
670
let mut store = Store::new(&engine, ());
671
let instance = Instance::new(&mut store, &module, &[])?;
672
673
let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
674
let mut results = [Val::I32(0), Val::I32(0)];
675
instance
676
.get_func(&mut store, "call")
677
.unwrap()
678
.call(&mut store, &[f.into()], &mut results)?;
679
assert_eq!(results[0].unwrap_i32(), 7);
680
681
{
682
let f = results[1].unwrap_funcref().unwrap();
683
let mut results = [Val::I32(0)];
684
f.call(&mut store, &[1.into(), 2.into()], &mut results)?;
685
assert_eq!(results[0].unwrap_i32(), 3);
686
}
687
688
assert_eq!(HITS.load(SeqCst), 0);
689
690
drop(store);
691
692
assert_eq!(HITS.load(SeqCst), 0);
693
694
drop(linker);
695
696
assert_eq!(HITS.load(SeqCst), 1);
697
698
Ok(())
699
}
700
701
#[test]
702
fn store_with_context() -> Result<()> {
703
struct Ctx {
704
called: bool,
705
}
706
707
let engine = Engine::default();
708
let mut linker = Linker::new(&engine);
709
710
linker.func_wrap("", "", |mut caller: Caller<'_, Ctx>| {
711
caller.data_mut().called = true;
712
})?;
713
714
let mut store = Store::new(&engine, Ctx { called: false });
715
716
let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
717
f.call(&mut store, &[], &mut [])?;
718
719
assert!(store.data().called);
720
721
Ok(())
722
}
723
724
#[test]
725
#[cfg_attr(miri, ignore)]
726
fn wasi_imports() -> Result<()> {
727
let engine = Engine::default();
728
let mut linker = Linker::new(&engine);
729
wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |t| t)?;
730
731
let wasm = wat::parse_str(
732
r#"
733
(import "wasi_snapshot_preview1" "proc_exit" (func $__wasi_proc_exit (param i32)))
734
(memory (export "memory") 0)
735
(func (export "_start")
736
(call $__wasi_proc_exit (i32.const 123))
737
)
738
"#,
739
)?;
740
741
let module = Module::new(&engine, wasm)?;
742
let mut store = Store::new(&engine, wasmtime_wasi::WasiCtxBuilder::new().build_p1());
743
let instance = linker.instantiate(&mut store, &module)?;
744
745
let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?;
746
let exit = start
747
.call(&mut store, ())
748
.unwrap_err()
749
.downcast::<wasmtime_wasi::I32Exit>()?;
750
assert_eq!(exit.0, 123);
751
752
Ok(())
753
}
754
755