xref: /wasmtime-44.0.1/crates/c-api/tests/val.cc (revision adff9d9d)
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