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