74e1f119d343dd053b57eda028884e05422c099d
[platform/framework/web/lwnode.git] /
1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib>
4 #include <string>
5 #include <cinttypes>
6
7 #include "wasm.hh"
8
9
10 // A function to be called from Wasm code.
11 auto callback(
12   const wasm::Val args[], wasm::Val results[]
13 ) -> wasm::own<wasm::Trap> {
14   std::cout << "Calling back..." << std::endl;
15   std::cout << "> " << (args[0].ref() ? args[0].ref()->get_host_info() : nullptr) << std::endl;
16   results[0] = args[0].copy();
17   return nullptr;
18 }
19
20
21 auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
22   if (exports.size() <= i || !exports[i]->func()) {
23     std::cout << "> Error accessing function export " << i << "/" << exports.size() << "!" << std::endl;
24     exit(1);
25   }
26   return exports[i]->func();
27 }
28
29 auto get_export_global(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Global* {
30   if (exports.size() <= i || !exports[i]->global()) {
31     std::cout << "> Error accessing global export " << i << "!" << std::endl;
32     exit(1);
33   }
34   return exports[i]->global();
35 }
36
37 auto get_export_table(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Table* {
38   if (exports.size() <= i || !exports[i]->table()) {
39     std::cout << "> Error accessing table export " << i << "!" << std::endl;
40     exit(1);
41   }
42   return exports[i]->table();
43 }
44
45
46 void call_r_v(const wasm::Func* func, const wasm::Ref* ref) {
47   std::cout << "call_r_v... " << std::flush;
48   wasm::Val args[1] = {wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
49   if (func->call(args, nullptr)) {
50     std::cout << "> Error calling function!" << std::endl;
51     exit(1);
52   }
53   std::cout << "okay" << std::endl;
54 }
55
56 auto call_v_r(const wasm::Func* func) -> wasm::own<wasm::Ref> {
57   std::cout << "call_v_r... " << std::flush;
58   wasm::Val results[1];
59   if (func->call(nullptr, results)) {
60     std::cout << "> Error calling function!" << std::endl;
61     exit(1);
62   }
63   std::cout << "okay" << std::endl;
64   return results[0].release_ref();
65 }
66
67 auto call_r_r(const wasm::Func* func, const wasm::Ref* ref) -> wasm::own<wasm::Ref> {
68   std::cout << "call_r_r... " << std::flush;
69   wasm::Val args[1] = {wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
70   wasm::Val results[1];
71   if (func->call(args, results)) {
72     std::cout << "> Error calling function!" << std::endl;
73     exit(1);
74   }
75   std::cout << "okay" << std::endl;
76   return results[0].release_ref();
77 }
78
79 void call_ir_v(const wasm::Func* func, int32_t i, const wasm::Ref* ref) {
80   std::cout << "call_ir_v... " << std::flush;
81   wasm::Val args[2] = {wasm::Val::i32(i), wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>())};
82   if (func->call(args, nullptr)) {
83     std::cout << "> Error calling function!" << std::endl;
84     exit(1);
85   }
86   std::cout << "okay" << std::endl;
87 }
88
89 auto call_i_r(const wasm::Func* func, int32_t i) -> wasm::own<wasm::Ref> {
90   std::cout << "call_i_r... " << std::flush;
91   wasm::Val args[1] = {wasm::Val::i32(i)};
92   wasm::Val results[1];
93   if (func->call(args, results)) {
94     std::cout << "> Error calling function!" << std::endl;
95     exit(1);
96   }
97   std::cout << "okay" << std::endl;
98   return results[0].release_ref();
99 }
100
101 void check(wasm::own<wasm::Ref> actual, const wasm::Ref* expected) {
102   if (actual.get() != expected &&
103       !(actual && expected && actual->same(expected))) {
104     std::cout << "> Error reading reference, expected "
105       << (expected ? expected->get_host_info() : nullptr) << ", got "
106       << (actual ? actual->get_host_info() : nullptr) << std::endl;
107     exit(1);
108   }
109 }
110
111 void run() {
112   // Initialize.
113   std::cout << "Initializing..." << std::endl;
114   auto engine = wasm::Engine::make();
115   auto store_ = wasm::Store::make(engine.get());
116   auto store = store_.get();
117
118   // Load binary.
119   std::cout << "Loading binary..." << std::endl;
120   std::ifstream file("hostref.wasm");
121   file.seekg(0, std::ios_base::end);
122   auto file_size = file.tellg();
123   file.seekg(0);
124   auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
125   file.read(binary.get(), file_size);
126   file.close();
127   if (file.fail()) {
128     std::cout << "> Error loading module!" << std::endl;
129     return;
130   }
131
132   // Compile.
133   std::cout << "Compiling module..." << std::endl;
134   auto module = wasm::Module::make(store, binary);
135   if (!module) {
136     std::cout << "> Error compiling module!" << std::endl;
137     return;
138   }
139
140   // Create external callback function.
141   std::cout << "Creating callback..." << std::endl;
142   auto callback_type = wasm::FuncType::make(
143     wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::ANYREF)),
144     wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::ANYREF))
145   );
146   auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
147
148   // Instantiate.
149   std::cout << "Instantiating module..." << std::endl;
150   wasm::Extern* imports[] = {callback_func.get()};
151   auto instance = wasm::Instance::make(store, module.get(), imports);
152   if (!instance) {
153     std::cout << "> Error instantiating module!" << std::endl;
154     return;
155   }
156
157   // Extract export.
158   std::cout << "Extracting exports..." << std::endl;
159   auto exports = instance->exports();
160   size_t i = 0;
161   auto global = get_export_global(exports, i++);
162   auto table = get_export_table(exports, i++);
163   auto global_set = get_export_func(exports, i++);
164   auto global_get = get_export_func(exports, i++);
165   auto table_set = get_export_func(exports, i++);
166   auto table_get = get_export_func(exports, i++);
167   auto func_call = get_export_func(exports, i++);
168
169   // Create host references.
170   std::cout << "Creating host references..." << std::endl;
171   auto host1 = wasm::Foreign::make(store);
172   auto host2 = wasm::Foreign::make(store);
173   host1->set_host_info(reinterpret_cast<void*>(1));
174   host2->set_host_info(reinterpret_cast<void*>(2));
175
176   // Some sanity checks.
177   check(nullptr, nullptr);
178   check(host1->copy(), host1.get());
179   check(host2->copy(), host2.get());
180
181   wasm::Val val = wasm::Val::ref(host1->copy());
182   check(val.ref()->copy(), host1.get());
183   auto ref = val.release_ref();
184   assert(val.ref() == nullptr);
185   check(ref->copy(), host1.get());
186
187   // Interact.
188   std::cout << "Accessing global..." << std::endl;
189   check(call_v_r(global_get), nullptr);
190   call_r_v(global_set, host1.get());
191   check(call_v_r(global_get), host1.get());
192   call_r_v(global_set, host2.get());
193   check(call_v_r(global_get), host2.get());
194   call_r_v(global_set, nullptr);
195   check(call_v_r(global_get), nullptr);
196
197   check(global->get().release_ref(), nullptr);
198   global->set(wasm::Val(host2->copy()));
199   check(call_v_r(global_get), host2.get());
200   check(global->get().release_ref(), host2.get());
201
202   std::cout << "Accessing table..." << std::endl;
203   check(call_i_r(table_get, 0), nullptr);
204   check(call_i_r(table_get, 1), nullptr);
205   call_ir_v(table_set, 0, host1.get());
206   call_ir_v(table_set, 1, host2.get());
207   check(call_i_r(table_get, 0), host1.get());
208   check(call_i_r(table_get, 1), host2.get());
209   call_ir_v(table_set, 0, nullptr);
210   check(call_i_r(table_get, 0), nullptr);
211
212   check(table->get(2), nullptr);
213   table->set(2, host1.get());
214   check(call_i_r(table_get, 2), host1.get());
215   check(table->get(2), host1.get());
216
217   std::cout << "Accessing function..." << std::endl;
218   check(call_r_r(func_call, nullptr), nullptr);
219   check(call_r_r(func_call, host1.get()), host1.get());
220   check(call_r_r(func_call, host2.get()), host2.get());
221
222   // Shut down.
223   std::cout << "Shutting down..." << std::endl;
224 }
225
226
227 int main(int argc, const char* argv[]) {
228   run();
229   std::cout << "Done." << std::endl;
230   return 0;
231 }
232