10 // A function to be called from Wasm code.
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();
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;
26 return exports[i]->func();
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;
34 return exports[i]->global();
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;
42 return exports[i]->table();
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;
53 std::cout << "okay" << std::endl;
56 auto call_v_r(const wasm::Func* func) -> wasm::own<wasm::Ref> {
57 std::cout << "call_v_r... " << std::flush;
59 if (func->call(nullptr, results)) {
60 std::cout << "> Error calling function!" << std::endl;
63 std::cout << "okay" << std::endl;
64 return results[0].release_ref();
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>())};
71 if (func->call(args, results)) {
72 std::cout << "> Error calling function!" << std::endl;
75 std::cout << "okay" << std::endl;
76 return results[0].release_ref();
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;
86 std::cout << "okay" << std::endl;
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)};
93 if (func->call(args, results)) {
94 std::cout << "> Error calling function!" << std::endl;
97 std::cout << "okay" << std::endl;
98 return results[0].release_ref();
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;
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();
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();
124 auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
125 file.read(binary.get(), file_size);
128 std::cout << "> Error loading module!" << std::endl;
133 std::cout << "Compiling module..." << std::endl;
134 auto module = wasm::Module::make(store, binary);
136 std::cout << "> Error compiling module!" << std::endl;
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))
146 auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
149 std::cout << "Instantiating module..." << std::endl;
150 wasm::Extern* imports[] = {callback_func.get()};
151 auto instance = wasm::Instance::make(store, module.get(), imports);
153 std::cout << "> Error instantiating module!" << std::endl;
158 std::cout << "Extracting exports..." << std::endl;
159 auto exports = instance->exports();
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++);
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));
176 // Some sanity checks.
177 check(nullptr, nullptr);
178 check(host1->copy(), host1.get());
179 check(host2->copy(), host2.get());
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());
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);
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());
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);
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());
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());
223 std::cout << "Shutting down..." << std::endl;
227 int main(int argc, const char* argv[]) {
229 std::cout << "Done." << std::endl;