1 #include <wasmtime/val.hh>
2
3 #include <gtest/gtest.h>
4 #include <wasmtime.hh>
5
6 using namespace wasmtime;
7
TEST(Val,Smoke)8 TEST(Val, Smoke) {
9 Val val(1);
10 EXPECT_EQ(val.kind(), ValKind::I32);
11 EXPECT_EQ(val.i32(), 1);
12
13 val = (int32_t)3;
14 EXPECT_EQ(val.kind(), ValKind::I32);
15 EXPECT_EQ(val.i32(), 3);
16
17 val = (int64_t)4;
18 EXPECT_EQ(val.kind(), ValKind::I64);
19 EXPECT_EQ(val.i64(), 4);
20
21 val = (float)5;
22 EXPECT_EQ(val.kind(), ValKind::F32);
23 EXPECT_EQ(val.f32(), 5);
24
25 val = (double)6;
26 EXPECT_EQ(val.kind(), ValKind::F64);
27 EXPECT_EQ(val.f64(), 6);
28
29 val = V128();
30 EXPECT_EQ(val.kind(), ValKind::V128);
31 for (int i = 0; i < 16; i++) {
32 EXPECT_EQ(val.v128().v128[i], 0);
33 }
34
35 Engine engine;
36 Store store(engine);
37 val = std::optional<ExternRef>(std::nullopt);
38 EXPECT_EQ(val.kind(), ValKind::ExternRef);
39 EXPECT_EQ(val.externref(), std::nullopt);
40
41 val = std::optional<ExternRef>(ExternRef(store, 5));
42 EXPECT_EQ(val.kind(), ValKind::ExternRef);
43 EXPECT_EQ(std::any_cast<int>(val.externref()->data(store)), 5);
44
45 val = ExternRef(store, 5);
46 EXPECT_EQ(val.kind(), ValKind::ExternRef);
47 EXPECT_EQ(std::any_cast<int>(val.externref()->data(store)), 5);
48
49 val = std::optional<AnyRef>(std::nullopt);
50 EXPECT_EQ(val.kind(), ValKind::AnyRef);
51 EXPECT_EQ(val.anyref(), std::nullopt);
52
53 val = std::optional<AnyRef>(AnyRef::i31(store, 5));
54 EXPECT_EQ(val.kind(), ValKind::AnyRef);
55 EXPECT_EQ(val.anyref()->i31(store), 5);
56 EXPECT_EQ(val.anyref()->u31(store), 5);
57
58 val = AnyRef::i31(store, -5);
59 EXPECT_EQ(val.kind(), ValKind::AnyRef);
60 EXPECT_EQ(val.anyref()->i31(store), -5);
61 EXPECT_EQ(val.anyref()->u31(store), 0x7ffffffb);
62
63 val = std::optional<Func>(std::nullopt);
64 EXPECT_EQ(val.kind(), ValKind::FuncRef);
65 EXPECT_EQ(val.funcref(), std::nullopt);
66
67 Func func(store, FuncType({}, {}),
68 [](auto caller, auto params, auto results) -> auto {
69 return std::monostate();
70 });
71
72 val = std::optional<Func>(func);
73 EXPECT_EQ(val.kind(), ValKind::FuncRef);
74
75 val = func;
76 EXPECT_EQ(val.kind(), ValKind::FuncRef);
77 }
78
79 class SetOnDrop {
80 std::shared_ptr<std::atomic<bool>> flag_;
81
82 public:
SetOnDrop()83 SetOnDrop() : flag_(std::make_shared<std::atomic<bool>>(false)) {}
84 SetOnDrop(const SetOnDrop &) = delete;
SetOnDrop(SetOnDrop && obj)85 SetOnDrop(SetOnDrop &&obj) : flag_(obj.flag_) { obj.flag_.reset(); }
~SetOnDrop()86 ~SetOnDrop() {
87 if (flag_)
88 flag_->store(true);
89 }
90
flag()91 const std::shared_ptr<std::atomic<bool>> &flag() { return this->flag_; }
92 };
93
TEST(Val,DropsExternRef)94 TEST(Val, DropsExternRef) {
95 std::shared_ptr<std::atomic<bool>> flag;
96 Engine engine;
97 Store store(engine);
98
99 // smoke test for `SetOnDrop` itself
100 {
101 SetOnDrop guard;
102 flag = guard.flag();
103 EXPECT_FALSE(flag->load());
104 }
105 EXPECT_TRUE(flag->load());
106
107 // Test that if an `ExternRef` is created and dropped it doesn't leak.
108 {
109 SetOnDrop guard;
110 flag = guard.flag();
111 ExternRef r(store, std::make_shared<SetOnDrop>(std::move(guard)));
112 EXPECT_FALSE(flag->load());
113 store.gc();
114 EXPECT_FALSE(flag->load());
115 }
116 EXPECT_FALSE(flag->load());
117 store.gc();
118 EXPECT_TRUE(flag->load());
119
120 // Test that if a `Val(ExternRef)` is created and dropped it doesn't leak.
121 {
122 SetOnDrop guard;
123 flag = guard.flag();
124 ExternRef r(store, std::make_shared<SetOnDrop>(std::move(guard)));
125 Val v(r);
126 EXPECT_FALSE(flag->load());
127 store.gc();
128 EXPECT_FALSE(flag->load());
129 }
130 EXPECT_FALSE(flag->load());
131 store.gc();
132 EXPECT_TRUE(flag->load());
133
134 // Similar to above testing a variety of APIs.
135 {
136 SetOnDrop guard;
137 flag = guard.flag();
138 ExternRef r(store, std::make_shared<SetOnDrop>(std::move(guard)));
139 ExternRef r2 = r;
140 ExternRef r3(r2);
141 r3 = r2;
142 r = std::move(r2);
143
144 Val v(r3);
145 Val v2 = v;
146 Val v3(v2);
147 v3 = v2;
148 v = std::move(v2);
149
150 store.gc();
151 EXPECT_FALSE(flag->load());
152 }
153 EXPECT_FALSE(flag->load());
154 store.gc();
155 EXPECT_TRUE(flag->load());
156 }
157