1 #include <iostream>
2 #include <fstream>
3 #include <cstdlib>
4 #include <string>
5 #include <cinttypes>
6
7 #include "wasm.hh"
8
9 // Print a Wasm value
operator <<(std::ostream & out,const wasm::Val & val)10 auto operator<<(std::ostream& out, const wasm::Val& val) -> std::ostream& {
11 switch (val.kind()) {
12 case wasm::I32: {
13 out << val.i32();
14 } break;
15 case wasm::I64: {
16 out << val.i64();
17 } break;
18 case wasm::F32: {
19 out << val.f32();
20 } break;
21 case wasm::F64: {
22 out << val.f64();
23 } break;
24 case wasm::ANYREF:
25 case wasm::FUNCREF: {
26 if (val.ref() == nullptr) {
27 out << "null";
28 } else {
29 out << "ref(" << val.ref() << ")";
30 }
31 } break;
32 }
33 return out;
34 }
35
36 // A function to be called from Wasm code.
print_callback(const wasm::Val args[],wasm::Val results[])37 auto print_callback(
38 const wasm::Val args[], wasm::Val results[]
39 ) -> wasm::own<wasm::Trap> {
40 std::cout << "Calling back..." << std::endl << "> " << args[0] << std::endl;
41 results[0] = args[0].copy();
42 return nullptr;
43 }
44
45
46 // A function closure.
closure_callback(void * env,const wasm::Val args[],wasm::Val results[])47 auto closure_callback(
48 void* env, const wasm::Val args[], wasm::Val results[]
49 ) -> wasm::own<wasm::Trap> {
50 auto i = *reinterpret_cast<int*>(env);
51 std::cout << "Calling back closure..." << std::endl;
52 std::cout << "> " << i << std::endl;
53 results[0] = wasm::Val::i32(static_cast<int32_t>(i));
54 return nullptr;
55 }
56
57
run()58 void run() {
59 // Initialize.
60 std::cout << "Initializing..." << std::endl;
61 auto engine = wasm::Engine::make();
62 auto store_ = wasm::Store::make(engine.get());
63 auto store = store_.get();
64
65 // Load binary.
66 std::cout << "Loading binary..." << std::endl;
67 std::ifstream file("callback.wasm");
68 file.seekg(0, std::ios_base::end);
69 auto file_size = file.tellg();
70 file.seekg(0);
71 auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
72 file.read(binary.get(), file_size);
73 file.close();
74 if (file.fail()) {
75 std::cout << "> Error loading module!" << std::endl;
76 exit(1);
77 }
78
79 // Compile.
80 std::cout << "Compiling module..." << std::endl;
81 auto module = wasm::Module::make(store, binary);
82 if (!module) {
83 std::cout << "> Error compiling module!" << std::endl;
84 exit(1);
85 }
86
87 // Create external print functions.
88 std::cout << "Creating callback..." << std::endl;
89 auto print_type = wasm::FuncType::make(
90 wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32)),
91 wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32))
92 );
93 auto print_func = wasm::Func::make(store, print_type.get(), print_callback);
94
95 // Creating closure.
96 std::cout << "Creating closure..." << std::endl;
97 int i = 42;
98 auto closure_type = wasm::FuncType::make(
99 wasm::ownvec<wasm::ValType>::make(),
100 wasm::ownvec<wasm::ValType>::make(wasm::ValType::make(wasm::I32))
101 );
102 auto closure_func = wasm::Func::make(store, closure_type.get(), closure_callback, &i);
103
104 // Instantiate.
105 std::cout << "Instantiating module..." << std::endl;
106 wasm::Extern* imports[] = {print_func.get(), closure_func.get()};
107 auto instance = wasm::Instance::make(store, module.get(), imports);
108 if (!instance) {
109 std::cout << "> Error instantiating module!" << std::endl;
110 exit(1);
111 }
112
113 // Extract export.
114 std::cout << "Extracting export..." << std::endl;
115 auto exports = instance->exports();
116 if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
117 std::cout << "> Error accessing export!" << std::endl;
118 exit(1);
119 }
120 auto run_func = exports[0]->func();
121
122 // Call.
123 std::cout << "Calling export..." << std::endl;
124 wasm::Val args[] = {wasm::Val::i32(3), wasm::Val::i32(4)};
125 wasm::Val results[1];
126 if (run_func->call(args, results)) {
127 std::cout << "> Error calling function!" << std::endl;
128 exit(1);
129 }
130
131 // Print result.
132 std::cout << "Printing result..." << std::endl;
133 std::cout << "> " << results[0].i32() << std::endl;
134
135 // Shut down.
136 std::cout << "Shutting down..." << std::endl;
137 }
138
139
main(int argc,const char * argv[])140 int main(int argc, const char* argv[]) {
141 run();
142 std::cout << "Done." << std::endl;
143 return 0;
144 }
145
146