1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "test/wasm-api-tests/wasm-api-test.h"
6
7 namespace v8 {
8 namespace internal {
9 namespace wasm {
10
11 namespace {
12
13 int g_instances_finalized = 0;
14 int g_functions_finalized = 0;
15 int g_foreigns_finalized = 0;
16 int g_modules_finalized = 0;
17
18 const int kModuleMagic = 42;
19
FinalizeInstance(void * data)20 void FinalizeInstance(void* data) {
21 int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
22 g_instances_finalized += iteration;
23 }
24
FinalizeFunction(void * data)25 void FinalizeFunction(void* data) {
26 int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
27 g_functions_finalized += iteration;
28 }
29
FinalizeForeign(void * data)30 void FinalizeForeign(void* data) {
31 int iteration = static_cast<int>(reinterpret_cast<intptr_t>(data));
32 g_foreigns_finalized += iteration;
33 }
34
FinalizeModule(void * data)35 void FinalizeModule(void* data) {
36 g_modules_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
37 }
38
RunInStore(Store * store,ZoneBuffer * wire_bytes,int iterations)39 void RunInStore(Store* store, ZoneBuffer* wire_bytes, int iterations) {
40 size_t size = wire_bytes->end() - wire_bytes->begin();
41 vec<byte_t> binary = vec<byte_t>::make(
42 size, reinterpret_cast<byte_t*>(const_cast<byte*>(wire_bytes->begin())));
43 own<Module> module = Module::make(store, binary);
44 module->set_host_info(reinterpret_cast<void*>(kModuleMagic), &FinalizeModule);
45 for (int iteration = 0; iteration < iterations; iteration++) {
46 void* finalizer_data = reinterpret_cast<void*>(iteration);
47 own<Instance> instance = Instance::make(store, module.get(), nullptr);
48 EXPECT_NE(nullptr, instance.get());
49 instance->set_host_info(finalizer_data, &FinalizeInstance);
50
51 own<Func> func = instance->exports()[0]->func()->copy();
52 ASSERT_NE(func, nullptr);
53 func->set_host_info(finalizer_data, &FinalizeFunction);
54 Val args[] = {Val::i32(iteration)};
55 Val results[1];
56 func->call(args, results);
57 EXPECT_EQ(iteration, results[0].i32());
58
59 own<Foreign> foreign = Foreign::make(store);
60 foreign->set_host_info(finalizer_data, &FinalizeForeign);
61 }
62 }
63
64 } // namespace
65
TEST_F(WasmCapiTest,InstanceFinalization)66 TEST_F(WasmCapiTest, InstanceFinalization) {
67 // Add a dummy function: f(x) { return x; }
68 byte code[] = {WASM_RETURN(WASM_LOCAL_GET(0))};
69 AddExportedFunction(base::CStrVector("f"), code, sizeof(code),
70 wasm_i_i_sig());
71 Compile();
72 g_instances_finalized = 0;
73 g_functions_finalized = 0;
74 g_foreigns_finalized = 0;
75 g_modules_finalized = 0;
76 module()->set_host_info(reinterpret_cast<void*>(kModuleMagic),
77 &FinalizeModule);
78 static const int kIterations = 10;
79 RunInStore(store(), wire_bytes(), kIterations);
80 {
81 own<Store> store2 = Store::make(engine());
82 RunInStore(store2.get(), wire_bytes(), kIterations);
83 }
84 RunInStore(store(), wire_bytes(), kIterations);
85 Shutdown();
86 // Verify that (1) all finalizers were called, and (2) they passed the
87 // correct host data: the loop above sets {i} as data, and the finalizer
88 // callbacks add them all up, so the expected value after three rounds is
89 // 3 * sum([0, 1, ..., kIterations - 1]), which per Gauss's formula is:
90 static const int kExpected = 3 * ((kIterations * (kIterations - 1)) / 2);
91 EXPECT_EQ(g_instances_finalized, kExpected);
92 // There are two functions per iteration.
93 EXPECT_EQ(g_functions_finalized, kExpected);
94 EXPECT_EQ(g_foreigns_finalized, kExpected);
95 EXPECT_EQ(g_modules_finalized, 4 * kModuleMagic);
96 }
97
98 namespace {
99
CapiFunction(void * env,const Val args[],Val results[])100 own<Trap> CapiFunction(void* env, const Val args[], Val results[]) {
101 int offset = static_cast<int>(reinterpret_cast<intptr_t>(env));
102 results[0] = Val::i32(offset + args[0].i32());
103 return nullptr;
104 }
105
106 int g_host_data_finalized = 0;
107 int g_capi_function_finalized = 0;
108
FinalizeCapiFunction(void * data)109 void FinalizeCapiFunction(void* data) {
110 int value = static_cast<int>(reinterpret_cast<intptr_t>(data));
111 g_capi_function_finalized += value;
112 }
113
FinalizeHostData(void * data)114 void FinalizeHostData(void* data) {
115 g_host_data_finalized += static_cast<int>(reinterpret_cast<intptr_t>(data));
116 }
117
118 } // namespace
119
TEST_F(WasmCapiTest,CapiFunctionLifetimes)120 TEST_F(WasmCapiTest, CapiFunctionLifetimes) {
121 uint32_t func_index =
122 builder()->AddImport(base::CStrVector("f"), wasm_i_i_sig());
123 builder()->ExportImportedFunction(base::CStrVector("f"), func_index);
124 Compile();
125 own<Instance> instance;
126 void* kHostData = reinterpret_cast<void*>(1234);
127 int base_summand = 1000;
128 {
129 // Test that the own<> pointers for Func and FuncType can go out of scope
130 // without affecting the ability of the Func to be called later.
131 own<FuncType> capi_func_type =
132 FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
133 ownvec<ValType>::make(ValType::make(::wasm::I32)));
134 own<Func> capi_func =
135 Func::make(store(), capi_func_type.get(), &CapiFunction,
136 reinterpret_cast<void*>(base_summand));
137 Extern* imports[] = {capi_func.get()};
138 instance = Instance::make(store(), module(), imports);
139 // TODO(jkummerow): It may or may not be desirable to be able to set
140 // host data even here and have it survive the import/export dance.
141 // We are awaiting resolution of the discussion at:
142 // https://github.com/WebAssembly/wasm-c-api/issues/100
143 }
144 {
145 ownvec<Extern> exports = instance->exports();
146 Func* exported_func = exports[0]->func();
147 constexpr int kArg = 123;
148 Val args[] = {Val::i32(kArg)};
149 Val results[1];
150 exported_func->call(args, results);
151 EXPECT_EQ(base_summand + kArg, results[0].i32());
152 // Host data should survive destruction of the own<> pointer.
153 exported_func->set_host_info(kHostData);
154 }
155 {
156 ownvec<Extern> exports = instance->exports();
157 Func* exported_func = exports[0]->func();
158 EXPECT_EQ(kHostData, exported_func->get_host_info());
159 }
160 // Test that a Func can have its own internal metadata, an {env}, and
161 // separate {host info}, without any of that interfering with each other.
162 g_host_data_finalized = 0;
163 g_capi_function_finalized = 0;
164 base_summand = 23;
165 constexpr int kFinalizerData = 345;
166 {
167 own<FuncType> capi_func_type =
168 FuncType::make(ownvec<ValType>::make(ValType::make(::wasm::I32)),
169 ownvec<ValType>::make(ValType::make(::wasm::I32)));
170 own<Func> capi_func = Func::make(
171 store(), capi_func_type.get(), &CapiFunction,
172 reinterpret_cast<void*>(base_summand), &FinalizeCapiFunction);
173 capi_func->set_host_info(reinterpret_cast<void*>(kFinalizerData),
174 &FinalizeHostData);
175 constexpr int kArg = 19;
176 Val args[] = {Val::i32(kArg)};
177 Val results[1];
178 capi_func->call(args, results);
179 EXPECT_EQ(base_summand + kArg, results[0].i32());
180 }
181 instance.reset();
182 Shutdown();
183 EXPECT_EQ(base_summand, g_capi_function_finalized);
184 EXPECT_EQ(kFinalizerData, g_host_data_finalized);
185 }
186
187 } // namespace wasm
188 } // namespace internal
189 } // namespace v8
190