1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <inttypes.h>
5 
6 #include "wasm.h"
7 
8 #define own
9 
10 // A function to be called from Wasm code.
neg_callback(const wasm_val_t args[],wasm_val_t results[])11 own wasm_trap_t* neg_callback(
12   const wasm_val_t args[], wasm_val_t results[]
13 ) {
14   printf("Calling back...\n");
15   results[0].kind = WASM_I32;
16   results[0].of.i32 = -args[0].of.i32;
17   return NULL;
18 }
19 
20 
get_export_table(const wasm_extern_vec_t * exports,size_t i)21 wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
22   if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
23     printf("> Error accessing table export %zu!\n", i);
24     exit(1);
25   }
26   return wasm_extern_as_table(exports->data[i]);
27 }
28 
get_export_func(const wasm_extern_vec_t * exports,size_t i)29 wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
30   if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
31     printf("> Error accessing function export %zu!\n", i);
32     exit(1);
33   }
34   return wasm_extern_as_func(exports->data[i]);
35 }
36 
37 
check(bool success)38 void check(bool success) {
39   if (!success) {
40     printf("> Error, expected success\n");
41     exit(1);
42   }
43 }
44 
check_table(wasm_table_t * table,int32_t i,bool expect_set)45 void check_table(wasm_table_t* table, int32_t i, bool expect_set) {
46   own wasm_ref_t* ref = wasm_table_get(table, i);
47   check((ref != NULL) == expect_set);
48   if (ref) wasm_ref_delete(ref);
49 }
50 
check_call(wasm_func_t * func,int32_t arg1,int32_t arg2,int32_t expected)51 void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
52   wasm_val_t args[2] = {
53     {.kind = WASM_I32, .of = {.i32 = arg1}},
54     {.kind = WASM_I32, .of = {.i32 = arg2}}
55   };
56   wasm_val_t results[1];
57   if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) {
58     printf("> Error on result\n");
59     exit(1);
60   }
61 }
62 
check_trap(wasm_func_t * func,int32_t arg1,int32_t arg2)63 void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) {
64   wasm_val_t args[2] = {
65     {.kind = WASM_I32, .of = {.i32 = arg1}},
66     {.kind = WASM_I32, .of = {.i32 = arg2}}
67   };
68   own wasm_trap_t* trap = wasm_func_call(func, args, NULL);
69   if (! trap) {
70     printf("> Error on result, expected trap\n");
71     exit(1);
72   }
73   wasm_trap_delete(trap);
74 }
75 
76 
main(int argc,const char * argv[])77 int main(int argc, const char* argv[]) {
78   // Initialize.
79   printf("Initializing...\n");
80   wasm_engine_t* engine = wasm_engine_new();
81   wasm_store_t* store = wasm_store_new(engine);
82 
83   // Load binary.
84   printf("Loading binary...\n");
85   FILE* file = fopen("table.wasm", "r");
86   if (!file) {
87     printf("> Error loading module!\n");
88     return 1;
89   }
90   fseek(file, 0L, SEEK_END);
91   size_t file_size = ftell(file);
92   fseek(file, 0L, SEEK_SET);
93   wasm_byte_vec_t binary;
94   wasm_byte_vec_new_uninitialized(&binary, file_size);
95   if (fread(binary.data, file_size, 1, file) != 1) {
96     printf("> Error loading module!\n");
97     return 1;
98   }
99   fclose(file);
100 
101   // Compile.
102   printf("Compiling module...\n");
103   own wasm_module_t* module = wasm_module_new(store, &binary);
104   if (!module) {
105     printf("> Error compiling module!\n");
106     return 1;
107   }
108 
109   wasm_byte_vec_delete(&binary);
110 
111   // Instantiate.
112   printf("Instantiating module...\n");
113   own wasm_instance_t* instance =
114     wasm_instance_new(store, module, NULL, NULL);
115   if (!instance) {
116     printf("> Error instantiating module!\n");
117     return 1;
118   }
119 
120   // Extract export.
121   printf("Extracting exports...\n");
122   own wasm_extern_vec_t exports;
123   wasm_instance_exports(instance, &exports);
124   size_t i = 0;
125   wasm_table_t* table = get_export_table(&exports, i++);
126   wasm_func_t* call_indirect = get_export_func(&exports, i++);
127   wasm_func_t* f = get_export_func(&exports, i++);
128   wasm_func_t* g = get_export_func(&exports, i++);
129 
130   wasm_module_delete(module);
131 
132   // Create external function.
133   printf("Creating callback...\n");
134   own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32());
135   own wasm_func_t* h = wasm_func_new(store, neg_type, neg_callback);
136 
137   wasm_functype_delete(neg_type);
138 
139   // Try cloning.
140   own wasm_table_t* copy = wasm_table_copy(table);
141   assert(wasm_table_same(table, copy));
142   wasm_table_delete(copy);
143 
144   // Check initial table.
145   printf("Checking table...\n");
146   check(wasm_table_size(table) == 2);
147   check_table(table, 0, false);
148   check_table(table, 1, true);
149   check_trap(call_indirect, 0, 0);
150   check_call(call_indirect, 7, 1, 7);
151   check_trap(call_indirect, 0, 2);
152 
153   // Mutate table.
154   printf("Mutating table...\n");
155   check(wasm_table_set(table, 0, wasm_func_as_ref(g)));
156   check(wasm_table_set(table, 1, NULL));
157   check(! wasm_table_set(table, 2, wasm_func_as_ref(f)));
158   check_table(table, 0, true);
159   check_table(table, 1, false);
160   check_call(call_indirect, 7, 0, 666);
161   check_trap(call_indirect, 0, 1);
162   check_trap(call_indirect, 0, 2);
163 
164   // Grow table.
165   printf("Growing table...\n");
166   check(wasm_table_grow(table, 3, NULL));
167   check(wasm_table_size(table) == 5);
168   check(wasm_table_set(table, 2, wasm_func_as_ref(f)));
169   check(wasm_table_set(table, 3, wasm_func_as_ref(h)));
170   check(! wasm_table_set(table, 5, NULL));
171   check_table(table, 2, true);
172   check_table(table, 3, true);
173   check_table(table, 4, false);
174   check_call(call_indirect, 5, 2, 5);
175   check_call(call_indirect, 6, 3, -6);
176   check_trap(call_indirect, 0, 4);
177   check_trap(call_indirect, 0, 5);
178 
179   check(wasm_table_grow(table, 2, wasm_func_as_ref(f)));
180   check(wasm_table_size(table) == 7);
181   check_table(table, 5, true);
182   check_table(table, 6, true);
183 
184   check(! wasm_table_grow(table, 5, NULL));
185   check(wasm_table_grow(table, 3, NULL));
186   check(wasm_table_grow(table, 0, NULL));
187 
188   wasm_func_delete(h);
189   wasm_extern_vec_delete(&exports);
190   wasm_instance_delete(instance);
191 
192   // Create stand-alone table.
193   // TODO(wasm+): Once Wasm allows multiple tables, turn this into import.
194   printf("Creating stand-alone table...\n");
195   wasm_limits_t limits = {5, 5};
196   own wasm_tabletype_t* tabletype =
197     wasm_tabletype_new(wasm_valtype_new(WASM_FUNCREF), &limits);
198   own wasm_table_t* table2 = wasm_table_new(store, tabletype, NULL);
199   check(wasm_table_size(table2) == 5);
200   check(! wasm_table_grow(table2, 1, NULL));
201   check(wasm_table_grow(table2, 0, NULL));
202 
203   wasm_tabletype_delete(tabletype);
204   wasm_table_delete(table2);
205 
206   // Shut down.
207   printf("Shutting down...\n");
208   wasm_store_delete(store);
209   wasm_engine_delete(engine);
210 
211   // All done.
212   printf("Done.\n");
213   return 0;
214 }
215