Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,167 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// Print a Wasm value
void wasm_val_print(wasm_val_t val) {
switch (val.kind) {
case WASM_I32: {
printf("%" PRIu32, val.of.i32);
} break;
case WASM_I64: {
printf("%" PRIu64, val.of.i64);
} break;
case WASM_F32: {
printf("%f", val.of.f32);
} break;
case WASM_F64: {
printf("%g", val.of.f64);
} break;
case WASM_EXTERNREF:
case WASM_FUNCREF: {
if (val.of.ref == NULL) {
printf("null");
} else {
printf("ref(%p)", val.of.ref);
}
} break;
}
}
// A function to be called from Wasm code.
own wasm_trap_t* print_callback(
const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n> ");
wasm_val_print(args->data[0]);
printf("\n");
wasm_val_copy(&results->data[0], &args->data[0]);
return NULL;
}
// A function closure.
own wasm_trap_t* closure_callback(
void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
int i = *(int*)env;
printf("Calling back closure...\n");
printf("> %d\n", i);
results->data[0].kind = WASM_I32;
results->data[0].of.i32 = (int32_t)i;
return NULL;
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("callback.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external print functions.
printf("Creating callback...\n");
own wasm_functype_t* print_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32());
own wasm_func_t* print_func = wasm_func_new(store, print_type, print_callback);
int i = 42;
own wasm_functype_t* closure_type = wasm_functype_new_0_1(wasm_valtype_new_i32());
own wasm_func_t* closure_func = wasm_func_new_with_env(store, closure_type, closure_callback, &i, NULL);
wasm_functype_delete(print_type);
wasm_functype_delete(closure_type);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_t* externs[] = {
wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func)
};
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(print_func);
wasm_func_delete(closure_func);
// Extract export.
printf("Extracting export...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size == 0) {
printf("> Error accessing exports!\n");
return 1;
}
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
if (run_func == NULL) {
printf("> Error accessing export!\n");
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
wasm_val_t as[2] = { WASM_I32_VAL(3), WASM_I32_VAL(4) };
wasm_val_t rs[1] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_ARRAY_VEC(as);
wasm_val_vec_t results = WASM_ARRAY_VEC(rs);
if (wasm_func_call(run_func, &args, &results)) {
printf("> Error calling function!\n");
return 1;
}
wasm_extern_vec_delete(&exports);
// Print result.
printf("Printing result...\n");
printf("> %u\n", rs[0].of.i32);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,144 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// Print a Wasm value
auto operator<<(std::ostream& out, const wasm::Val& val) -> std::ostream& {
switch (val.kind()) {
case wasm::ValKind::I32: {
out << val.i32();
} break;
case wasm::ValKind::I64: {
out << val.i64();
} break;
case wasm::ValKind::F32: {
out << val.f32();
} break;
case wasm::ValKind::F64: {
out << val.f64();
} break;
case wasm::ValKind::EXTERNREF:
case wasm::ValKind::FUNCREF: {
if (val.ref() == nullptr) {
out << "null";
} else {
out << "ref(" << val.ref() << ")";
}
} break;
}
return out;
}
// A function to be called from Wasm code.
auto print_callback(const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl << "> " << args[0] << std::endl;
results[0] = args[0].copy();
return nullptr;
}
// A function closure.
auto closure_callback(void* env, const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
auto i = *reinterpret_cast<int*>(env);
std::cout << "Calling back closure..." << std::endl;
std::cout << "> " << i << std::endl;
results[0] = wasm::Val::i32(static_cast<int32_t>(i));
return nullptr;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("callback.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto print_type =
wasm::FuncType::make(wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)),
wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)));
auto print_func = wasm::Func::make(store, print_type.get(), print_callback);
// Creating closure.
std::cout << "Creating closure..." << std::endl;
int i = 42;
auto closure_type =
wasm::FuncType::make(wasm::ownvec<wasm::ValType>::make(),
wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)));
auto closure_func = wasm::Func::make(store, closure_type.get(), closure_callback, &i);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports =
wasm::vec<wasm::Extern*>::make(print_func.get(), closure_func.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::ExternKind::FUNC ||
!exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
exit(1);
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
auto args = wasm::vec<wasm::Val>::make(wasm::Val::i32(3), wasm::Val::i32(4));
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (run_func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
// Print result.
std::cout << "Printing result..." << std::endl;
std::cout << "> " << results[0].i32() << std::endl;
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,10 @@
(module
(func $print (import "" "print") (param i32) (result i32))
(func $closure (import "" "closure") (result i32))
(func (export "run") (param $x i32) (param $y i32) (result i32)
(i32.add
(call $print (i32.add (local.get $x) (local.get $y)))
(call $closure)
)
)
)

View File

@ -0,0 +1,110 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
const int iterations = 100000;
int live_count = 0;
void finalize(void* data) {
intptr_t i = (intptr_t)data;
if (i % (iterations / 10) == 0) printf("Finalizing #%" PRIdPTR "...\n", i);
--live_count;
}
void run_in_store(wasm_store_t* store) {
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("finalize.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
exit(1);
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
exit(1);
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
exit(1);
}
wasm_byte_vec_delete(&binary);
// Instantiate.
printf("Instantiating modules...\n");
for (int i = 0; i <= iterations; ++i) {
if (i % (iterations / 10) == 0) printf("%d\n", i);
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module %d!\n", i);
exit(1);
}
void* data = (void*)(intptr_t)i;
wasm_instance_set_host_info_with_finalizer(instance, data, &finalize);
wasm_instance_delete(instance);
++live_count;
}
wasm_module_delete(module);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
printf("Live count %d\n", live_count);
printf("Creating store 1...\n");
wasm_store_t* store1 = wasm_store_new(engine);
printf("Running in store 1...\n");
run_in_store(store1);
printf("Live count %d\n", live_count);
printf("Creating store 2...\n");
wasm_store_t* store2 = wasm_store_new(engine);
printf("Running in store 2...\n");
run_in_store(store2);
printf("Live count %d\n", live_count);
printf("Deleting store 2...\n");
wasm_store_delete(store2);
printf("Live count %d\n", live_count);
printf("Running in store 1...\n");
run_in_store(store1);
printf("Live count %d\n", live_count);
printf("Deleting store 1...\n");
wasm_store_delete(store1);
printf("Live count %d\n", live_count);
assert(live_count == 0);
// Shut down.
printf("Shutting down...\n");
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,104 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
const int iterations = 100000;
int live_count = 0;
void finalize(void* data) {
intptr_t i = reinterpret_cast<intptr_t>(data);
if (i % (iterations / 10) == 0) {
std::cout << "Finalizing #" << i << "..." << std::endl;
}
--live_count;
}
void run_in_store(wasm::Store* store) {
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("finalize.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Instantiate.
std::cout << "Instantiating modules..." << std::endl;
for (int i = 0; i <= iterations; ++i) {
if (i % (iterations / 10) == 0) std::cout << i << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make();
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module " << i << "!" << std::endl;
exit(1);
}
instance->set_host_info(reinterpret_cast<void*>(i), &finalize);
++live_count;
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
std::cout << "Live count " << live_count << std::endl;
std::cout << "Creating store 1..." << std::endl;
auto store1 = wasm::Store::make(engine.get());
std::cout << "Running in store 1..." << std::endl;
run_in_store(store1.get());
std::cout << "Live count " << live_count << std::endl;
{
std::cout << "Creating store 2..." << std::endl;
auto store2 = wasm::Store::make(engine.get());
std::cout << "Running in store 2..." << std::endl;
run_in_store(store2.get());
std::cout << "Live count " << live_count << std::endl;
std::cout << "Deleting store 2..." << std::endl;
std::cout << "Live count " << live_count << std::endl;
}
std::cout << "Running in store 1..." << std::endl;
run_in_store(store1.get());
std::cout << "Live count " << live_count << std::endl;
std::cout << "Deleting store 1..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Live count " << live_count << std::endl;
assert(live_count == 0);
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,5 @@
(module
(func (export "f"))
(func (export "g"))
(func (export "h"))
)

View File

@ -0,0 +1,240 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) {
printf("> Error accessing global export %zu!\n", i);
exit(1);
}
return wasm_extern_as_global(exports->data[i]);
}
wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
printf("> Error accessing function export %zu!\n", i);
exit(1);
}
return wasm_extern_as_func(exports->data[i]);
}
#define check(val, type, expected) \
if (val.of.type != expected) { \
printf("> Error reading value\n"); \
exit(1); \
}
#define check_global(global, type, expected) \
{ \
wasm_val_t val; \
wasm_global_get(global, &val); \
check(val, type, expected); \
}
#define check_call(func, type, expected) \
{ \
wasm_val_t vs[1]; \
wasm_val_vec_t args = WASM_EMPTY_VEC; \
wasm_val_vec_t results = WASM_ARRAY_VEC(vs); \
wasm_func_call(func, &args, &results); \
check(vs[0], type, expected); \
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("global.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external globals.
printf("Creating globals...\n");
own wasm_globaltype_t* const_f32_type = wasm_globaltype_new(
wasm_valtype_new(WASM_F32), WASM_CONST);
own wasm_globaltype_t* const_i64_type = wasm_globaltype_new(
wasm_valtype_new(WASM_I64), WASM_CONST);
own wasm_globaltype_t* var_f32_type = wasm_globaltype_new(
wasm_valtype_new(WASM_F32), WASM_VAR);
own wasm_globaltype_t* var_i64_type = wasm_globaltype_new(
wasm_valtype_new(WASM_I64), WASM_VAR);
wasm_val_t val_f32_1 = WASM_F32_VAL(1);
own wasm_global_t* const_f32_import =
wasm_global_new(store, const_f32_type, &val_f32_1);
wasm_val_t val_i64_2 = WASM_I64_VAL(2);
own wasm_global_t* const_i64_import =
wasm_global_new(store, const_i64_type, &val_i64_2);
wasm_val_t val_f32_3 = WASM_F32_VAL(3);
own wasm_global_t* var_f32_import =
wasm_global_new(store, var_f32_type, &val_f32_3);
wasm_val_t val_i64_4 = WASM_I64_VAL(4);
own wasm_global_t* var_i64_import =
wasm_global_new(store, var_i64_type, &val_i64_4);
wasm_globaltype_delete(const_f32_type);
wasm_globaltype_delete(const_i64_type);
wasm_globaltype_delete(var_f32_type);
wasm_globaltype_delete(var_i64_type);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_t* externs[] = {
wasm_global_as_extern(const_f32_import),
wasm_global_as_extern(const_i64_import),
wasm_global_as_extern(var_f32_import),
wasm_global_as_extern(var_i64_import)
};
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_module_delete(module);
// Extract export.
printf("Extracting exports...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
size_t i = 0;
wasm_global_t* const_f32_export = get_export_global(&exports, i++);
wasm_global_t* const_i64_export = get_export_global(&exports, i++);
wasm_global_t* var_f32_export = get_export_global(&exports, i++);
wasm_global_t* var_i64_export = get_export_global(&exports, i++);
wasm_func_t* get_const_f32_import = get_export_func(&exports, i++);
wasm_func_t* get_const_i64_import = get_export_func(&exports, i++);
wasm_func_t* get_var_f32_import = get_export_func(&exports, i++);
wasm_func_t* get_var_i64_import = get_export_func(&exports, i++);
wasm_func_t* get_const_f32_export = get_export_func(&exports, i++);
wasm_func_t* get_const_i64_export = get_export_func(&exports, i++);
wasm_func_t* get_var_f32_export = get_export_func(&exports, i++);
wasm_func_t* get_var_i64_export = get_export_func(&exports, i++);
wasm_func_t* set_var_f32_import = get_export_func(&exports, i++);
wasm_func_t* set_var_i64_import = get_export_func(&exports, i++);
wasm_func_t* set_var_f32_export = get_export_func(&exports, i++);
wasm_func_t* set_var_i64_export = get_export_func(&exports, i++);
// Try cloning.
own wasm_global_t* copy = wasm_global_copy(var_f32_import);
assert(wasm_global_same(var_f32_import, copy));
wasm_global_delete(copy);
// Interact.
printf("Accessing globals...\n");
// Check initial values.
check_global(const_f32_import, f32, 1);
check_global(const_i64_import, i64, 2);
check_global(var_f32_import, f32, 3);
check_global(var_i64_import, i64, 4);
check_global(const_f32_export, f32, 5);
check_global(const_i64_export, i64, 6);
check_global(var_f32_export, f32, 7);
check_global(var_i64_export, i64, 8);
check_call(get_const_f32_import, f32, 1);
check_call(get_const_i64_import, i64, 2);
check_call(get_var_f32_import, f32, 3);
check_call(get_var_i64_import, i64, 4);
check_call(get_const_f32_export, f32, 5);
check_call(get_const_i64_export, i64, 6);
check_call(get_var_f32_export, f32, 7);
check_call(get_var_i64_export, i64, 8);
// Modify variables through API and check again.
wasm_val_t val33 = WASM_F32_VAL(33);
wasm_global_set(var_f32_import, &val33);
wasm_val_t val34 = WASM_I64_VAL(34);
wasm_global_set(var_i64_import, &val34);
wasm_val_t val37 = WASM_F32_VAL(37);
wasm_global_set(var_f32_export, &val37);
wasm_val_t val38 = WASM_I64_VAL(38);
wasm_global_set(var_i64_export, &val38);
check_global(var_f32_import, f32, 33);
check_global(var_i64_import, i64, 34);
check_global(var_f32_export, f32, 37);
check_global(var_i64_export, i64, 38);
check_call(get_var_f32_import, f32, 33);
check_call(get_var_i64_import, i64, 34);
check_call(get_var_f32_export, f32, 37);
check_call(get_var_i64_export, i64, 38);
// Modify variables through calls and check again.
wasm_val_vec_t res = WASM_EMPTY_VEC;
wasm_val_t vs73[] = { WASM_F32_VAL(73) };
wasm_val_vec_t args73 = WASM_ARRAY_VEC(vs73);
wasm_func_call(set_var_f32_import, &args73, &res);
wasm_val_t vs74[] = { WASM_I64_VAL(74) };
wasm_val_vec_t args74 = WASM_ARRAY_VEC(vs74);
wasm_func_call(set_var_i64_import, &args74, &res);
wasm_val_t vs77[] = { WASM_F32_VAL(77) };
wasm_val_vec_t args77 = WASM_ARRAY_VEC(vs77);
wasm_func_call(set_var_f32_export, &args77, &res);
wasm_val_t vs78[] = { WASM_I64_VAL(78) };
wasm_val_vec_t args78 = WASM_ARRAY_VEC(vs78);
wasm_func_call(set_var_i64_export, &args78, &res);
check_global(var_f32_import, f32, 73);
check_global(var_i64_import, i64, 74);
check_global(var_f32_export, f32, 77);
check_global(var_i64_export, i64, 78);
check_call(get_var_f32_import, f32, 73);
check_call(get_var_i64_import, i64, 74);
check_call(get_var_f32_export, f32, 77);
check_call(get_var_i64_export, i64, 78);
wasm_global_delete(const_f32_import);
wasm_global_delete(const_i64_import);
wasm_global_delete(var_f32_import);
wasm_global_delete(var_i64_import);
wasm_extern_vec_delete(&exports);
wasm_instance_delete(instance);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,197 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
auto get_export_global(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Global* {
if (exports.size() <= i || !exports[i]->global()) {
std::cout << "> Error accessing global export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->global();
}
auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->func();
}
template<class T, class U>
void check(T actual, U expected) {
if (actual != expected) {
std::cout << "> Error reading value, expected " << expected << ", got " << actual << std::endl;
exit(1);
}
}
auto call(const wasm::Func* func) -> wasm::Val {
auto args = wasm::vec<wasm::Val>::make();
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
return results[0].copy();
}
void call(const wasm::Func* func, wasm::Val&& arg) {
auto args = wasm::vec<wasm::Val>::make(std::move(arg));
auto results = wasm::vec<wasm::Val>::make();
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("global.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Create external globals.
std::cout << "Creating globals..." << std::endl;
auto const_f32_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::ValKind::F32), wasm::Mutability::CONST);
auto const_i64_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::ValKind::I64), wasm::Mutability::CONST);
auto var_f32_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::ValKind::F32), wasm::Mutability::VAR);
auto var_i64_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::ValKind::I64), wasm::Mutability::VAR);
auto const_f32_import = wasm::Global::make(store, const_f32_type.get(), wasm::Val::f32(1));
auto const_i64_import = wasm::Global::make(store, const_i64_type.get(), wasm::Val::i64(2));
auto var_f32_import = wasm::Global::make(store, var_f32_type.get(), wasm::Val::f32(3));
auto var_i64_import = wasm::Global::make(store, var_i64_type.get(), wasm::Val::i64(4));
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make(
const_f32_import.get(), const_i64_import.get(), var_f32_import.get(),
var_i64_import.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting exports..." << std::endl;
auto exports = instance->exports();
size_t i = 0;
auto const_f32_export = get_export_global(exports, i++);
auto const_i64_export = get_export_global(exports, i++);
auto var_f32_export = get_export_global(exports, i++);
auto var_i64_export = get_export_global(exports, i++);
auto get_const_f32_import = get_export_func(exports, i++);
auto get_const_i64_import = get_export_func(exports, i++);
auto get_var_f32_import = get_export_func(exports, i++);
auto get_var_i64_import = get_export_func(exports, i++);
auto get_const_f32_export = get_export_func(exports, i++);
auto get_const_i64_export = get_export_func(exports, i++);
auto get_var_f32_export = get_export_func(exports, i++);
auto get_var_i64_export = get_export_func(exports, i++);
auto set_var_f32_import = get_export_func(exports, i++);
auto set_var_i64_import = get_export_func(exports, i++);
auto set_var_f32_export = get_export_func(exports, i++);
auto set_var_i64_export = get_export_func(exports, i++);
// Try cloning.
assert(var_f32_import->copy()->same(var_f32_import.get()));
// Interact.
std::cout << "Accessing globals..." << std::endl;
// Check initial values.
check(const_f32_import->get().f32(), 1);
check(const_i64_import->get().i64(), 2);
check(var_f32_import->get().f32(), 3);
check(var_i64_import->get().i64(), 4);
check(const_f32_export->get().f32(), 5);
check(const_i64_export->get().i64(), 6);
check(var_f32_export->get().f32(), 7);
check(var_i64_export->get().i64(), 8);
check(call(get_const_f32_import).f32(), 1);
check(call(get_const_i64_import).i64(), 2);
check(call(get_var_f32_import).f32(), 3);
check(call(get_var_i64_import).i64(), 4);
check(call(get_const_f32_export).f32(), 5);
check(call(get_const_i64_export).i64(), 6);
check(call(get_var_f32_export).f32(), 7);
check(call(get_var_i64_export).i64(), 8);
// Modify variables through API and check again.
var_f32_import->set(wasm::Val::f32(33));
var_i64_import->set(wasm::Val::i64(34));
var_f32_export->set(wasm::Val::f32(37));
var_i64_export->set(wasm::Val::i64(38));
check(var_f32_import->get().f32(), 33);
check(var_i64_import->get().i64(), 34);
check(var_f32_export->get().f32(), 37);
check(var_i64_export->get().i64(), 38);
check(call(get_var_f32_import).f32(), 33);
check(call(get_var_i64_import).i64(), 34);
check(call(get_var_f32_export).f32(), 37);
check(call(get_var_i64_export).i64(), 38);
// Modify variables through calls and check again.
call(set_var_f32_import, wasm::Val::f32(73));
call(set_var_i64_import, wasm::Val::i64(74));
call(set_var_f32_export, wasm::Val::f32(77));
call(set_var_i64_export, wasm::Val::i64(78));
check(var_f32_import->get().f32(), 73);
check(var_i64_import->get().i64(), 74);
check(var_f32_export->get().f32(), 77);
check(var_i64_export->get().i64(), 78);
check(call(get_var_f32_import).f32(), 73);
check(call(get_var_i64_import).i64(), 74);
check(call(get_var_f32_export).f32(), 77);
check(call(get_var_i64_export).i64(), 78);
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,27 @@
(module
(global $f32_import (import "" "const f32") f32)
(global $i64_import (import "" "const i64") i64)
(global $mut_f32_import (import "" "var f32") (mut f32))
(global $mut_i64_import (import "" "var i64") (mut i64))
(global $f32_export (export "const f32") f32 (f32.const 5))
(global $i64_export (export "const i64") i64 (i64.const 6))
(global $mut_f32_export (export "var f32") (mut f32) (f32.const 7))
(global $mut_i64_export (export "var i64") (mut i64) (i64.const 8))
(func (export "get const f32 import") (result f32) (global.get $f32_import))
(func (export "get const i64 import") (result i64) (global.get $i64_import))
(func (export "get var f32 import") (result f32) (global.get $mut_f32_import))
(func (export "get var i64 import") (result i64) (global.get $mut_i64_import))
(func (export "get const f32 export") (result f32) (global.get $f32_export))
(func (export "get const i64 export") (result i64) (global.get $i64_export))
(func (export "get var f32 export") (result f32) (global.get $mut_f32_export))
(func (export "get var i64 export") (result i64) (global.get $mut_i64_export))
(func (export "set var f32 import") (param f32) (global.set $mut_f32_import (local.get 0)))
(func (export "set var i64 import") (param i64) (global.set $mut_i64_import (local.get 0)))
(func (export "set var f32 export") (param f32) (global.set $mut_f32_export (local.get 0)))
(func (export "set var f64 export") (param i64) (global.set $mut_i64_export (local.get 0)))
)

View File

@ -0,0 +1,118 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* hello_callback(
const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n");
printf("> Hello World!\n");
return NULL;
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("hello.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Validate.
printf("Validating module...\n");
if (!wasm_module_validate(store, &binary)) {
printf("> Error validating module!\n");
return 1;
}
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external print functions.
printf("Creating callback...\n");
own wasm_functype_t* hello_type = wasm_functype_new_0_0();
own wasm_func_t* hello_func =
wasm_func_new(store, hello_type, hello_callback);
wasm_functype_delete(hello_type);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_t* externs[] = { wasm_func_as_extern(hello_func) };
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(hello_func);
// Extract export.
printf("Extracting export...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size == 0) {
printf("> Error accessing exports!\n");
return 1;
}
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
if (run_func == NULL) {
printf("> Error accessing export!\n");
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
if (wasm_func_call(run_func, &args, &results)) {
printf("> Error calling function!\n");
return 1;
}
wasm_extern_vec_delete(&exports);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,99 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto hello_callback(const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> Hello world!" << std::endl;
return nullptr;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("hello.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Validate.
std::cout << "Validating module..." << std::endl;
if (!wasm::Module::validate(store, binary)) {
std::cout << "> Error validating module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto hello_type = wasm::FuncType::make(
wasm::ownvec<wasm::ValType>::make(), wasm::ownvec<wasm::ValType>::make()
);
auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make(hello_func.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::ExternKind::FUNC ||
!exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
exit(1);
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
auto args = wasm::vec<wasm::Val>::make();
auto results = wasm::vec<wasm::Val>::make();
if (run_func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,4 @@
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)

View File

@ -0,0 +1,270 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* callback(
const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n> ");
printf("> %p\n",
args->data[0].of.ref ? wasm_ref_get_host_info(args->data[0].of.ref) : NULL);
wasm_val_copy(&results->data[0], &args->data[0]);
return NULL;
}
wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
printf("> Error accessing function export %zu!\n", i);
exit(1);
}
return wasm_extern_as_func(exports->data[i]);
}
wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) {
printf("> Error accessing global export %zu!\n", i);
exit(1);
}
return wasm_extern_as_global(exports->data[i]);
}
wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
printf("> Error accessing table export %zu!\n", i);
exit(1);
}
return wasm_extern_as_table(exports->data[i]);
}
own wasm_ref_t* call_v_r(const wasm_func_t* func) {
printf("call_v_r... "); fflush(stdout);
wasm_val_t rs[] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_ARRAY_VEC(rs);
if (wasm_func_call(func, &args, &results)) {
printf("> Error calling function!\n");
exit(1);
}
printf("okay\n");
return rs[0].of.ref;
}
void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) {
printf("call_r_v... "); fflush(stdout);
wasm_val_t vs[1] = { WASM_REF_VAL(ref) };
wasm_val_vec_t args = WASM_ARRAY_VEC(vs);
wasm_val_vec_t results = WASM_EMPTY_VEC;
if (wasm_func_call(func, &args, &results)) {
printf("> Error calling function!\n");
exit(1);
}
printf("okay\n");
}
own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) {
printf("call_r_r... "); fflush(stdout);
wasm_val_t vs[1] = { WASM_REF_VAL(ref) };
wasm_val_t rs[1] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_ARRAY_VEC(vs);
wasm_val_vec_t results = WASM_ARRAY_VEC(rs);
if (wasm_func_call(func, &args, &results)) {
printf("> Error calling function!\n");
exit(1);
}
printf("okay\n");
return rs[0].of.ref;
}
void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) {
printf("call_ir_v... "); fflush(stdout);
wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) };
wasm_val_vec_t args = WASM_ARRAY_VEC(vs);
wasm_val_vec_t results = WASM_EMPTY_VEC;
if (wasm_func_call(func, &args, &results)) {
printf("> Error calling function!\n");
exit(1);
}
printf("okay\n");
}
own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) {
printf("call_i_r... "); fflush(stdout);
wasm_val_t vs[1] = { WASM_I32_VAL(i) };
wasm_val_t rs[1] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_ARRAY_VEC(vs);
wasm_val_vec_t results = WASM_ARRAY_VEC(rs);
if (wasm_func_call(func, &args, &results)) {
printf("> Error calling function!\n");
exit(1);
}
printf("okay\n");
return rs[0].of.ref;
}
void check(own wasm_ref_t* actual, const wasm_ref_t* expected) {
if (actual != expected &&
!(actual && expected && wasm_ref_same(actual, expected))) {
printf("> Error reading reference, expected %p, got %p\n",
expected ? wasm_ref_get_host_info(expected) : NULL,
actual ? wasm_ref_get_host_info(actual) : NULL);
exit(1);
}
if (actual) wasm_ref_delete(actual);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("hostref.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external callback function.
printf("Creating callback...\n");
own wasm_functype_t* callback_type = wasm_functype_new_1_1(
wasm_valtype_new(WASM_EXTERNREF), wasm_valtype_new(WASM_EXTERNREF));
own wasm_func_t* callback_func =
wasm_func_new(store, callback_type, callback);
wasm_functype_delete(callback_type);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) };
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(callback_func);
wasm_module_delete(module);
// Extract export.
printf("Extracting exports...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
size_t i = 0;
wasm_global_t* global = get_export_global(&exports, i++);
wasm_table_t* table = get_export_table(&exports, i++);
wasm_func_t* global_set = get_export_func(&exports, i++);
wasm_func_t* global_get = get_export_func(&exports, i++);
wasm_func_t* table_set = get_export_func(&exports, i++);
wasm_func_t* table_get = get_export_func(&exports, i++);
wasm_func_t* func_call = get_export_func(&exports, i++);
wasm_instance_delete(instance);
// Create host references.
printf("Creating host references...\n");
own wasm_ref_t* host1 = wasm_foreign_as_ref(wasm_foreign_new(store));
own wasm_ref_t* host2 = wasm_foreign_as_ref(wasm_foreign_new(store));
wasm_ref_set_host_info(host1, (void*)1);
wasm_ref_set_host_info(host2, (void*)2);
// Some sanity checks.
check(NULL, NULL);
check(wasm_ref_copy(host1), host1);
check(wasm_ref_copy(host2), host2);
own wasm_val_t val;
val.kind = WASM_EXTERNREF;
val.of.ref = wasm_ref_copy(host1);
check(wasm_ref_copy(val.of.ref), host1);
own wasm_ref_t* ref = val.of.ref;
check(wasm_ref_copy(ref), host1);
wasm_val_delete(&val);
// Interact.
printf("Accessing global...\n");
check(call_v_r(global_get), NULL);
call_r_v(global_set, host1);
check(call_v_r(global_get), host1);
call_r_v(global_set, host2);
check(call_v_r(global_get), host2);
call_r_v(global_set, NULL);
check(call_v_r(global_get), NULL);
wasm_global_get(global, &val);
assert(val.kind == WASM_EXTERNREF);
check(val.of.ref, NULL);
val.of.ref = host2;
wasm_global_set(global, &val);
check(call_v_r(global_get), host2);
wasm_global_get(global, &val);
assert(val.kind == WASM_EXTERNREF);
check(val.of.ref, host2);
printf("Accessing table...\n");
check(call_i_r(table_get, 0), NULL);
check(call_i_r(table_get, 1), NULL);
call_ir_v(table_set, 0, host1);
call_ir_v(table_set, 1, host2);
check(call_i_r(table_get, 0), host1);
check(call_i_r(table_get, 1), host2);
call_ir_v(table_set, 0, NULL);
check(call_i_r(table_get, 0), NULL);
check(wasm_table_get(table, 2), NULL);
wasm_table_set(table, 2, host1);
check(call_i_r(table_get, 2), host1);
check(wasm_table_get(table, 2), host1);
printf("Accessing function...\n");
check(call_r_r(func_call, NULL), NULL);
check(call_r_r(func_call, host1), host1);
check(call_r_r(func_call, host2), host2);
wasm_ref_delete(host1);
wasm_ref_delete(host2);
wasm_extern_vec_delete(&exports);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,238 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto callback(const wasm::vec<wasm::Val>& args, wasm::vec<wasm::Val>& results)
-> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> " << (args[0].ref() ? args[0].ref()->get_host_info() : nullptr) << std::endl;
results[0] = args[0].copy();
return nullptr;
}
auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "/" << exports.size() << "!" << std::endl;
exit(1);
}
return exports[i]->func();
}
auto get_export_global(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Global* {
if (exports.size() <= i || !exports[i]->global()) {
std::cout << "> Error accessing global export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->global();
}
auto get_export_table(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Table* {
if (exports.size() <= i || !exports[i]->table()) {
std::cout << "> Error accessing table export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->table();
}
void call_r_v(const wasm::Func* func, const wasm::Ref* ref) {
std::cout << "call_r_v... " << std::flush;
auto args = wasm::vec<wasm::Val>::make(
wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>()));
auto results = wasm::vec<wasm::Val>::make();
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
std::cout << "okay" << std::endl;
}
auto call_v_r(const wasm::Func* func) -> wasm::own<wasm::Ref> {
std::cout << "call_v_r... " << std::flush;
auto args = wasm::vec<wasm::Val>::make();
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
std::cout << "okay" << std::endl;
return results[0].release_ref();
}
auto call_r_r(const wasm::Func* func, const wasm::Ref* ref) -> wasm::own<wasm::Ref> {
std::cout << "call_r_r... " << std::flush;
auto args = wasm::vec<wasm::Val>::make(
wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>()));
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
std::cout << "okay" << std::endl;
return results[0].release_ref();
}
void call_ir_v(const wasm::Func* func, int32_t i, const wasm::Ref* ref) {
std::cout << "call_ir_v... " << std::flush;
auto args = wasm::vec<wasm::Val>::make(
wasm::Val::i32(i),
wasm::Val::ref(ref ? ref->copy() : wasm::own<wasm::Ref>()));
auto results = wasm::vec<wasm::Val>::make();
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
std::cout << "okay" << std::endl;
}
auto call_i_r(const wasm::Func* func, int32_t i) -> wasm::own<wasm::Ref> {
std::cout << "call_i_r... " << std::flush;
auto args = wasm::vec<wasm::Val>::make(wasm::Val::i32(i));
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
std::cout << "okay" << std::endl;
return results[0].release_ref();
}
void check(wasm::own<wasm::Ref> actual, const wasm::Ref* expected) {
if (actual.get() != expected &&
!(actual && expected && actual->same(expected))) {
std::cout << "> Error reading reference, expected "
<< (expected ? expected->get_host_info() : nullptr) << ", got "
<< (actual ? actual->get_host_info() : nullptr) << std::endl;
exit(1);
}
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("hostref.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
return;
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
return;
}
// Create external callback function.
std::cout << "Creating callback..." << std::endl;
auto callback_type =
wasm::FuncType::make(wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::EXTERNREF)),
wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::EXTERNREF)));
auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make(callback_func.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
return;
}
// Extract export.
std::cout << "Extracting exports..." << std::endl;
auto exports = instance->exports();
size_t i = 0;
auto global = get_export_global(exports, i++);
auto table = get_export_table(exports, i++);
auto global_set = get_export_func(exports, i++);
auto global_get = get_export_func(exports, i++);
auto table_set = get_export_func(exports, i++);
auto table_get = get_export_func(exports, i++);
auto func_call = get_export_func(exports, i++);
// Create host references.
std::cout << "Creating host references..." << std::endl;
auto host1 = wasm::Foreign::make(store);
auto host2 = wasm::Foreign::make(store);
host1->set_host_info(reinterpret_cast<void*>(1));
host2->set_host_info(reinterpret_cast<void*>(2));
// Some sanity checks.
check(nullptr, nullptr);
check(host1->copy(), host1.get());
check(host2->copy(), host2.get());
wasm::Val val = wasm::Val::ref(host1->copy());
check(val.ref()->copy(), host1.get());
auto ref = val.release_ref();
assert(val.ref() == nullptr);
check(ref->copy(), host1.get());
// Interact.
std::cout << "Accessing global..." << std::endl;
check(call_v_r(global_get), nullptr);
call_r_v(global_set, host1.get());
check(call_v_r(global_get), host1.get());
call_r_v(global_set, host2.get());
check(call_v_r(global_get), host2.get());
call_r_v(global_set, nullptr);
check(call_v_r(global_get), nullptr);
check(global->get().release_ref(), nullptr);
global->set(wasm::Val(host2->copy()));
check(call_v_r(global_get), host2.get());
check(global->get().release_ref(), host2.get());
std::cout << "Accessing table..." << std::endl;
check(call_i_r(table_get, 0), nullptr);
check(call_i_r(table_get, 1), nullptr);
call_ir_v(table_set, 0, host1.get());
call_ir_v(table_set, 1, host2.get());
check(call_i_r(table_get, 0), host1.get());
check(call_i_r(table_get, 1), host2.get());
call_ir_v(table_set, 0, nullptr);
check(call_i_r(table_get, 0), nullptr);
check(table->get(2), nullptr);
table->set(2, host1.get());
check(call_i_r(table_get, 2), host1.get());
check(table->get(2), host1.get());
std::cout << "Accessing function..." << std::endl;
check(call_r_r(func_call, nullptr), nullptr);
check(call_r_r(func_call, host1.get()), host1.get());
check(call_r_r(func_call, host2.get()), host2.get());
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,24 @@
(module
(import "" "f" (func $fun (param externref) (result externref)))
(global $glob (export "global") (mut externref) (ref.null))
(table $tab (export "table") 10 externref)
(func (export "global.set") (param $r externref)
(global.set $glob (local.get $r))
)
(func (export "global.get") (result externref)
(global.get $glob)
)
(func (export "table.set") (param $i i32) (param $r externref)
(table.set $tab (local.get $i) (local.get $r))
)
(func (export "table.get") (param $i i32) (result externref)
(table.get $tab (local.get $i))
)
(func (export "func.call") (param $r externref) (result externref)
(call $fun (local.get $r))
)
)

View File

@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) {
printf("> Error accessing memory export %zu!\n", i);
exit(1);
}
return wasm_extern_as_memory(exports->data[i]);
}
wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
printf("> Error accessing function export %zu!\n", i);
exit(1);
}
return wasm_extern_as_func(exports->data[i]);
}
void check(bool success) {
if (!success) {
printf("> Error, expected success\n");
exit(1);
}
}
void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) {
wasm_val_t r = WASM_INIT_VAL;
wasm_val_vec_t args_ = {i, args};
wasm_val_vec_t results = {1, &r};
if (wasm_func_call(func, &args_, &results) || r.of.i32 != expected) {
printf("> Error on result\n");
exit(1);
}
}
void check_call0(wasm_func_t* func, int32_t expected) {
check_call(func, 0, NULL, expected);
}
void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) {
wasm_val_t args[] = { WASM_I32_VAL(arg) };
check_call(func, 1, args, expected);
}
void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
check_call(func, 2, args, expected);
}
void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) {
wasm_val_vec_t args_ = {i, args};
wasm_val_vec_t results = {0, NULL};
if (wasm_func_call(func, &args_, &results)) {
printf("> Error on result, expected empty\n");
exit(1);
}
}
void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
check_ok(func, 2, args);
}
void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) {
wasm_val_t r = WASM_INIT_VAL;
wasm_val_vec_t args_ = {i, args};
wasm_val_vec_t results = {1, &r};
own wasm_trap_t* trap = wasm_func_call(func, &args_, &results);
if (! trap) {
printf("> Error on result, expected trap\n");
exit(1);
}
wasm_trap_delete(trap);
}
void check_trap1(wasm_func_t* func, int32_t arg) {
wasm_val_t args[] = { WASM_I32_VAL(arg) };
check_trap(func, 1, args);
}
void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
wasm_val_t args[] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
check_trap(func, 2, args);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("memory.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
// Extract export.
printf("Extracting exports...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
size_t i = 0;
wasm_memory_t* memory = get_export_memory(&exports, i++);
wasm_func_t* size_func = get_export_func(&exports, i++);
wasm_func_t* load_func = get_export_func(&exports, i++);
wasm_func_t* store_func = get_export_func(&exports, i++);
wasm_module_delete(module);
// Try cloning.
own wasm_memory_t* copy = wasm_memory_copy(memory);
assert(wasm_memory_same(memory, copy));
wasm_memory_delete(copy);
// Check initial memory.
printf("Checking memory...\n");
check(wasm_memory_size(memory) == 2);
check(wasm_memory_data_size(memory) == 0x20000);
check(wasm_memory_data(memory)[0] == 0);
check(wasm_memory_data(memory)[0x1000] == 1);
check(wasm_memory_data(memory)[0x1003] == 4);
check_call0(size_func, 2);
check_call1(load_func, 0, 0);
check_call1(load_func, 0x1000, 1);
check_call1(load_func, 0x1003, 4);
check_call1(load_func, 0x1ffff, 0);
check_trap1(load_func, 0x20000);
// Mutate memory.
printf("Mutating memory...\n");
wasm_memory_data(memory)[0x1003] = 5;
check_ok2(store_func, 0x1002, 6);
check_trap2(store_func, 0x20000, 0);
check(wasm_memory_data(memory)[0x1002] == 6);
check(wasm_memory_data(memory)[0x1003] == 5);
check_call1(load_func, 0x1002, 6);
check_call1(load_func, 0x1003, 5);
// Grow memory.
printf("Growing memory...\n");
check(wasm_memory_grow(memory, 1));
check(wasm_memory_size(memory) == 3);
check(wasm_memory_data_size(memory) == 0x30000);
check_call1(load_func, 0x20000, 0);
check_ok2(store_func, 0x20000, 0);
check_trap1(load_func, 0x30000);
check_trap2(store_func, 0x30000, 0);
check(! wasm_memory_grow(memory, 1));
check(wasm_memory_grow(memory, 0));
wasm_extern_vec_delete(&exports);
wasm_instance_delete(instance);
// Create stand-alone memory.
// TODO(wasm+): Once Wasm allows multiple memories, turn this into import.
printf("Creating stand-alone memory...\n");
wasm_limits_t limits = {5, 5};
own wasm_memorytype_t* memorytype = wasm_memorytype_new(&limits);
own wasm_memory_t* memory2 = wasm_memory_new(store, memorytype);
check(wasm_memory_size(memory2) == 5);
check(! wasm_memory_grow(memory2, 1));
check(wasm_memory_grow(memory2, 0));
wasm_memorytype_delete(memorytype);
wasm_memory_delete(memory2);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,175 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
auto get_export_memory(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Memory* {
if (exports.size() <= i || !exports[i]->memory()) {
std::cout << "> Error accessing memory export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->memory();
}
auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->func();
}
template<class T, class U>
void check(T actual, U expected) {
if (actual != expected) {
std::cout << "> Error on result, expected " << expected << ", got " << actual << std::endl;
exit(1);
}
}
template<class... Args>
void check_ok(const wasm::Func* func, Args... xs) {
auto args = wasm::vec<wasm::Val>::make(wasm::Val::i32(xs)...);
auto results = wasm::vec<wasm::Val>::make();
if (func->call(args, results)) {
std::cout << "> Error on result, expected return" << std::endl;
exit(1);
}
}
template<class... Args>
void check_trap(const wasm::Func* func, Args... xs) {
auto args = wasm::vec<wasm::Val>::make(wasm::Val::i32(xs)...);
auto results = wasm::vec<wasm::Val>::make();
if (!func->call(args, results)) {
std::cout << "> Error on result, expected trap" << std::endl;
exit(1);
}
}
template<class... Args>
auto call(const wasm::Func* func, Args... xs) -> int32_t {
auto args = wasm::vec<wasm::Val>::make(wasm::Val::i32(xs)...);
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (func->call(args, results)) {
std::cout << "> Error on result, expected return" << std::endl;
exit(1);
}
return results[0].i32();
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("memory.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make();
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting exports..." << std::endl;
auto exports = instance->exports();
size_t i = 0;
auto memory = get_export_memory(exports, i++);
auto size_func = get_export_func(exports, i++);
auto load_func = get_export_func(exports, i++);
auto store_func = get_export_func(exports, i++);
// Try cloning.
assert(memory->copy()->same(memory));
// Check initial memory.
std::cout << "Checking memory..." << std::endl;
check(memory->size(), 2u);
check(memory->data_size(), 0x20000u);
check(memory->data()[0], 0);
check(memory->data()[0x1000], 1);
check(memory->data()[0x1003], 4);
check(call(size_func), 2);
check(call(load_func, 0), 0);
check(call(load_func, 0x1000), 1);
check(call(load_func, 0x1003), 4);
check(call(load_func, 0x1ffff), 0);
check_trap(load_func, 0x20000);
// Mutate memory.
std::cout << "Mutating memory..." << std::endl;
memory->data()[0x1003] = 5;
check_ok(store_func, 0x1002, 6);
check_trap(store_func, 0x20000, 0);
check(memory->data()[0x1002], 6);
check(memory->data()[0x1003], 5);
check(call(load_func, 0x1002), 6);
check(call(load_func, 0x1003), 5);
// Grow memory.
std::cout << "Growing memory..." << std::endl;
check(memory->grow(1), true);
check(memory->size(), 3u);
check(memory->data_size(), 0x30000u);
check(call(load_func, 0x20000), 0);
check_ok(store_func, 0x20000, 0);
check_trap(load_func, 0x30000);
check_trap(store_func, 0x30000, 0);
check(memory->grow(1), false);
check(memory->grow(0), true);
// Create stand-alone memory.
// TODO(wasm+): Once Wasm allows multiple memories, turn this into import.
std::cout << "Creating stand-alone memory..." << std::endl;
auto memorytype = wasm::MemoryType::make(wasm::Limits(5, 5));
auto memory2 = wasm::Memory::make(store, memorytype.get());
check(memory2->size(), 5u);
check(memory2->grow(1), false);
check(memory2->grow(0), true);
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
(module
(memory (export "memory") 2 3)
(func (export "size") (result i32) (memory.size))
(func (export "load") (param i32) (result i32) (i32.load8_s (local.get 0)))
(func (export "store") (param i32 i32)
(i32.store8 (local.get 0) (local.get 1))
)
(data (i32.const 0x1000) "\01\02\03\04")
)

View File

@ -0,0 +1,156 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* callback(
const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n> ");
printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n",
args->data[0].of.i32, args->data[1].of.i64,
args->data[2].of.i64, args->data[3].of.i32);
printf("\n");
wasm_val_copy(&results->data[0], &args->data[3]);
wasm_val_copy(&results->data[1], &args->data[1]);
wasm_val_copy(&results->data[2], &args->data[2]);
wasm_val_copy(&results->data[3], &args->data[0]);
return NULL;
}
// A function closure.
own wasm_trap_t* closure_callback(
void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
int i = *(int*)env;
printf("Calling back closure...\n");
printf("> %d\n", i);
results->data[0].kind = WASM_I32;
results->data[0].of.i32 = (int32_t)i;
return NULL;
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("multi.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external print functions.
printf("Creating callback...\n");
wasm_valtype_t* types[4] = {
wasm_valtype_new_i32(), wasm_valtype_new_i64(),
wasm_valtype_new_i64(), wasm_valtype_new_i32()
};
own wasm_valtype_vec_t tuple1, tuple2;
wasm_valtype_vec_new(&tuple1, 4, types);
wasm_valtype_vec_copy(&tuple2, &tuple1);
own wasm_functype_t* callback_type = wasm_functype_new(&tuple1, &tuple2);
own wasm_func_t* callback_func =
wasm_func_new(store, callback_type, callback);
wasm_functype_delete(callback_type);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_t* externs[] = { wasm_func_as_extern(callback_func) };
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(callback_func);
// Extract export.
printf("Extracting export...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size == 0) {
printf("> Error accessing exports!\n");
return 1;
}
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
if (run_func == NULL) {
printf("> Error accessing export!\n");
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
wasm_val_t vals[4] = {
WASM_I32_VAL(1), WASM_I64_VAL(2), WASM_I64_VAL(3), WASM_I32_VAL(4)
};
wasm_val_t res[4] = {
WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL, WASM_INIT_VAL
};
wasm_val_vec_t args = WASM_ARRAY_VEC(vals);
wasm_val_vec_t results = WASM_ARRAY_VEC(res);
if (wasm_func_call(run_func, &args, &results)) {
printf("> Error calling function!\n");
return 1;
}
wasm_extern_vec_delete(&exports);
// Print result.
printf("Printing result...\n");
printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n",
res[0].of.i32, res[1].of.i64, res[2].of.i64, res[3].of.i32);
assert(res[0].of.i32 == 4);
assert(res[1].of.i64 == 3);
assert(res[2].of.i64 == 2);
assert(res[3].of.i32 == 1);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,115 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto callback(const wasm::vec<wasm::Val>& args, wasm::vec<wasm::Val>& results)
-> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> " << args[0].i32();
std::cout << " " << args[1].i64();
std::cout << " " << args[2].i64();
std::cout << " " << args[3].i32() << std::endl;
results[0] = args[3].copy();
results[1] = args[1].copy();
results[2] = args[2].copy();
results[3] = args[0].copy();
return nullptr;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("multi.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto tuple = wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32),
wasm::ValType::make(wasm::ValKind::I64),
wasm::ValType::make(wasm::ValKind::I64),
wasm::ValType::make(wasm::ValKind::I32));
auto callback_type =
wasm::FuncType::make(tuple.deep_copy(), tuple.deep_copy());
auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make(callback_func.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::ExternKind::FUNC ||
!exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
exit(1);
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
auto args = wasm::vec<wasm::Val>::make(wasm::Val::i32(1), wasm::Val::i64(2),
wasm::Val::i64(3), wasm::Val::i32(4));
auto results = wasm::vec<wasm::Val>::make_uninitialized(4);
if (wasm::own<wasm::Trap> trap = run_func->call(args, results)) {
std::cout << "> Error calling function! " << trap->message().get() << std::endl;
exit(1);
}
// Print result.
std::cout << "Printing result..." << std::endl;
std::cout << "> " << results[0].i32();
std::cout << " " << results[1].i64();
std::cout << " " << results[2].i64();
std::cout << " " << results[3].i32() << std::endl;
assert(results[0].i32() == 4);
assert(results[1].i64() == 3);
assert(results[2].i64() == 2);
assert(results[3].i32() == 1);
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,7 @@
(module
(func $f (import "" "f") (param i32 i64 i64 i32) (result i32 i64 i64 i32))
(func $g (export "g") (param i32 i64 i64 i32) (result i32 i64 i64 i32)
(call $f (local.get 0) (local.get 2) (local.get 1) (local.get 3))
)
)

View File

@ -0,0 +1,171 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
void print_mutability(wasm_mutability_t mut) {
switch (mut) {
case WASM_VAR: printf("var"); break;
case WASM_CONST: printf("const"); break;
}
}
void print_limits(const wasm_limits_t* limits) {
printf("%ud", limits->min);
if (limits->max < wasm_limits_max_default) printf(" %ud", limits->max);
}
void print_valtype(const wasm_valtype_t* type) {
switch (wasm_valtype_kind(type)) {
case WASM_I32: printf("i32"); break;
case WASM_I64: printf("i64"); break;
case WASM_F32: printf("f32"); break;
case WASM_F64: printf("f64"); break;
case WASM_EXTERNREF: printf("externref"); break;
case WASM_FUNCREF: printf("funcref"); break;
}
}
void print_valtypes(const wasm_valtype_vec_t* types) {
bool first = true;
for (size_t i = 0; i < types->size; ++i) {
if (first) {
first = false;
} else {
printf(" ");
}
print_valtype(types->data[i]);
}
}
void print_externtype(const wasm_externtype_t* type) {
switch (wasm_externtype_kind(type)) {
case WASM_EXTERN_FUNC: {
const wasm_functype_t* functype =
wasm_externtype_as_functype_const(type);
printf("func ");
print_valtypes(wasm_functype_params(functype));
printf(" -> ");
print_valtypes(wasm_functype_results(functype));
} break;
case WASM_EXTERN_GLOBAL: {
const wasm_globaltype_t* globaltype =
wasm_externtype_as_globaltype_const(type);
printf("global ");
print_mutability(wasm_globaltype_mutability(globaltype));
printf(" ");
print_valtype(wasm_globaltype_content(globaltype));
} break;
case WASM_EXTERN_TABLE: {
const wasm_tabletype_t* tabletype =
wasm_externtype_as_tabletype_const(type);
printf("table ");
print_limits(wasm_tabletype_limits(tabletype));
printf(" ");
print_valtype(wasm_tabletype_element(tabletype));
} break;
case WASM_EXTERN_MEMORY: {
const wasm_memorytype_t* memorytype =
wasm_externtype_as_memorytype_const(type);
printf("memory ");
print_limits(wasm_memorytype_limits(memorytype));
} break;
}
}
void print_name(const wasm_name_t* name) {
printf("\"%.*s\"", (int)name->size, name->data);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("reflect.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
// Extract export.
printf("Extracting export...\n");
own wasm_exporttype_vec_t export_types;
own wasm_extern_vec_t exports;
wasm_module_exports(module, &export_types);
wasm_instance_exports(instance, &exports);
assert(exports.size == export_types.size);
for (size_t i = 0; i < exports.size; ++i) {
assert(wasm_extern_kind(exports.data[i]) ==
wasm_externtype_kind(wasm_exporttype_type(export_types.data[i])));
printf("> export %zu ", i);
print_name(wasm_exporttype_name(export_types.data[i]));
printf("\n");
printf(">> initial: ");
print_externtype(wasm_exporttype_type(export_types.data[i]));
printf("\n");
printf(">> current: ");
own wasm_externtype_t* current = wasm_extern_type(exports.data[i]);
print_externtype(current);
wasm_externtype_delete(current);
printf("\n");
if (wasm_extern_kind(exports.data[i]) == WASM_EXTERN_FUNC) {
wasm_func_t* func = wasm_extern_as_func(exports.data[i]);
printf(">> in-arity: %zu", wasm_func_param_arity(func));
printf(", out-arity: %zu\n", wasm_func_result_arity(func));
}
}
wasm_module_delete(module);
wasm_instance_delete(instance);
wasm_extern_vec_delete(&exports);
wasm_exporttype_vec_delete(&export_types);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,147 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
auto operator<<(std::ostream& out, wasm::Mutability mut) -> std::ostream& {
switch (mut) {
case wasm::Mutability::VAR:
return out << "var";
case wasm::Mutability::CONST:
return out << "const";
}
return out;
}
auto operator<<(std::ostream& out, wasm::Limits limits) -> std::ostream& {
out << limits.min;
if (limits.max < wasm::Limits(0).max) out << " " << limits.max;
return out;
}
auto operator<<(std::ostream& out, const wasm::ValType& type) -> std::ostream& {
switch (type.kind()) {
case wasm::ValKind::I32:
return out << "i32";
case wasm::ValKind::I64:
return out << "i64";
case wasm::ValKind::F32:
return out << "f32";
case wasm::ValKind::F64:
return out << "f64";
case wasm::ValKind::EXTERNREF:
return out << "externref";
case wasm::ValKind::FUNCREF:
return out << "funcref";
}
return out;
}
auto operator<<(std::ostream& out, const wasm::ownvec<wasm::ValType>& types) -> std::ostream& {
bool first = true;
for (size_t i = 0; i < types.size(); ++i) {
if (first) {
first = false;
} else {
out << " ";
}
out << *types[i].get();
}
return out;
}
auto operator<<(std::ostream& out, const wasm::ExternType& type) -> std::ostream& {
switch (type.kind()) {
case wasm::ExternKind::FUNC: {
out << "func " << type.func()->params() << " -> " << type.func()->results();
} break;
case wasm::ExternKind::GLOBAL: {
out << "global " << type.global()->mutability() << " " << *type.global()->content();
} break;
case wasm::ExternKind::TABLE: {
out << "table " << type.table()->limits() << " " << *type.table()->element();
} break;
case wasm::ExternKind::MEMORY: {
out << "memory " << type.memory()->limits();
} break;
}
return out;
}
auto operator<<(std::ostream& out, const wasm::Name& name) -> std::ostream& {
out << "\"" << std::string(name.get(), name.size()) << "\"";
return out;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("reflect.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make();
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract exports.
std::cout << "Extracting export..." << std::endl;
auto export_types = module->exports();
auto exports = instance->exports();
assert(exports.size() == export_types.size());
for (size_t i = 0; i < exports.size(); ++i) {
assert(exports[i]->kind() == export_types[i]->type()->kind());
std::cout << "> export " << i << " " << export_types[i]->name() << std::endl;
std::cout << ">> initial: " << *export_types[i]->type() << std::endl;
std::cout << ">> current: " << *exports[i]->type() << std::endl;
if (exports[i]->kind() == wasm::ExternKind::FUNC) {
auto func = exports[i]->func();
std::cout << ">> in-arity: " << func->param_arity();
std::cout << ", out-arity: " << func->result_arity() << std::endl;
}
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,6 @@
(module
(func (export "func") (param i32 f64 f32) (result i32) (unreachable))
(global (export "global") f64 (f64.const 0))
(table (export "table") 0 50 anyfunc)
(memory (export "memory") 1)
)

View File

@ -0,0 +1,127 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* hello_callback(
const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n");
printf("> Hello World!\n");
return NULL;
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("serialize.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Serialize module.
printf("Serializing module...\n");
own wasm_byte_vec_t serialized;
wasm_module_serialize(module, &serialized);
wasm_module_delete(module);
// Deserialize module.
printf("Deserializing module...\n");
own wasm_module_t* deserialized = wasm_module_deserialize(store, &serialized);
if (!deserialized) {
printf("> Error deserializing module!\n");
return 1;
}
wasm_byte_vec_delete(&serialized);
// Create external print functions.
printf("Creating callback...\n");
own wasm_functype_t* hello_type = wasm_functype_new_0_0();
own wasm_func_t* hello_func =
wasm_func_new(store, hello_type, hello_callback);
wasm_functype_delete(hello_type);
// Instantiate.
printf("Instantiating deserialized module...\n");
wasm_extern_t* externs[] = { wasm_func_as_extern(hello_func) };
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, deserialized, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(hello_func);
// Extract export.
printf("Extracting export...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size == 0) {
printf("> Error accessing exports!\n");
return 1;
}
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
if (run_func == NULL) {
printf("> Error accessing export!\n");
return 1;
}
wasm_module_delete(deserialized);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
wasm_val_vec_t empty = WASM_EMPTY_VEC;
if (wasm_func_call(run_func, &empty, &empty)) {
printf("> Error calling function!\n");
return 1;
}
wasm_extern_vec_delete(&exports);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,104 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto hello_callback(const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> Hello world!" << std::endl;
return nullptr;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("serialize.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Serialize module.
std::cout << "Serializing module..." << std::endl;
auto serialized = module->serialize();
// Deserialize module.
std::cout << "Deserializing module..." << std::endl;
auto deserialized = wasm::Module::deserialize(store, serialized);
if (!deserialized) {
std::cout << "> Error deserializing module!" << std::endl;
exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto hello_type = wasm::FuncType::make(
wasm::ownvec<wasm::ValType>::make(), wasm::ownvec<wasm::ValType>::make()
);
auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback);
// Instantiate.
std::cout << "Instantiating deserialized module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make(hello_func.get());
auto instance = wasm::Instance::make(store, deserialized.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::ExternKind::FUNC ||
!exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
exit(1);
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
auto args = wasm::vec<wasm::Val>::make();
auto results = wasm::vec<wasm::Val>::make();
if (run_func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,4 @@
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)

View File

@ -0,0 +1,106 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
void print_frame(wasm_frame_t* frame) {
printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
wasm_frame_instance(frame),
wasm_frame_module_offset(frame),
wasm_frame_func_index(frame),
wasm_frame_func_offset(frame)
);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("start.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
own wasm_trap_t* trap = NULL;
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, &trap);
if (instance || !trap) {
printf("> Error instantiating module, expected trap!\n");
return 1;
}
wasm_module_delete(module);
// Print result.
printf("Printing message...\n");
own wasm_name_t message;
wasm_trap_message(trap, &message);
printf("> %s\n", message.data);
printf("Printing origin...\n");
own wasm_frame_t* frame = wasm_trap_origin(trap);
if (frame) {
print_frame(frame);
wasm_frame_delete(frame);
} else {
printf("> Empty origin.\n");
}
printf("Printing trace...\n");
own wasm_frame_vec_t trace;
wasm_trap_trace(trap, &trace);
if (trace.size > 0) {
for (size_t i = 0; i < trace.size; ++i) {
print_frame(trace.data[i]);
}
} else {
printf("> Empty trace.\n");
}
wasm_frame_vec_delete(&trace);
wasm_trap_delete(trap);
wasm_name_delete(&message);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,89 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
void print_frame(const wasm::Frame* frame) {
std::cout << "> " << frame->instance();
std::cout << " @ 0x" << std::hex << frame->module_offset();
std::cout << " = " << frame->func_index();
std::cout << ".0x" << std::hex << frame->func_offset() << std::endl;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("start.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
wasm::own<wasm::Trap> trap;
auto imports = wasm::vec<wasm::Extern*>::make();
auto instance = wasm::Instance::make(store, module.get(), imports, &trap);
if (instance || !trap) {
std::cout << "> Error instantiating module, expected trap!" << std::endl;
exit(1);
}
// Print result.
std::cout << "Printing message..." << std::endl;
std::cout << "> " << trap->message().get() << std::endl;
std::cout << "Printing origin..." << std::endl;
auto frame = trap->origin();
if (frame) {
print_frame(frame.get());
} else {
std::cout << "> Empty origin." << std::endl;
}
std::cout << "Printing trace..." << std::endl;
auto trace = trap->trace();
if (trace.size() > 0) {
for (size_t i = 0; i < trace.size(); ++i) {
print_frame(trace[i].get());
}
} else {
std::cout << "> Empty trace." << std::endl;
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,4 @@
(module
(func $start (unreachable))
(start $start)
)

View File

@ -0,0 +1,214 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* neg_callback(
const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n");
results->data[0].kind = WASM_I32;
results->data[0].of.i32 = -args->data[0].of.i32;
return NULL;
}
wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) {
printf("> Error accessing table export %zu!\n", i);
exit(1);
}
return wasm_extern_as_table(exports->data[i]);
}
wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) {
if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) {
printf("> Error accessing function export %zu!\n", i);
exit(1);
}
return wasm_extern_as_func(exports->data[i]);
}
void check(bool success) {
if (!success) {
printf("> Error, expected success\n");
exit(1);
}
}
void check_table(wasm_table_t* table, int32_t i, bool expect_set) {
own wasm_ref_t* ref = wasm_table_get(table, i);
check((ref != NULL) == expect_set);
if (ref) wasm_ref_delete(ref);
}
void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
wasm_val_t r[1] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_ARRAY_VEC(vs);
wasm_val_vec_t results = WASM_ARRAY_VEC(r);
if (wasm_func_call(func, &args, &results) || r[0].of.i32 != expected) {
printf("> Error on result\n");
exit(1);
}
}
void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) {
wasm_val_t vs[2] = { WASM_I32_VAL(arg1), WASM_I32_VAL(arg2) };
wasm_val_t r[1] = { WASM_INIT_VAL };
wasm_val_vec_t args = WASM_ARRAY_VEC(vs);
wasm_val_vec_t results = WASM_ARRAY_VEC(r);
own wasm_trap_t* trap = wasm_func_call(func, &args, &results);
if (! trap) {
printf("> Error on result, expected trap\n");
exit(1);
}
wasm_trap_delete(trap);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("table.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_vec_t imports = WASM_EMPTY_VEC;
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
// Extract export.
printf("Extracting exports...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
size_t i = 0;
wasm_table_t* table = get_export_table(&exports, i++);
wasm_func_t* call_indirect = get_export_func(&exports, i++);
wasm_func_t* f = get_export_func(&exports, i++);
wasm_func_t* g = get_export_func(&exports, i++);
wasm_module_delete(module);
// Create external function.
printf("Creating callback...\n");
own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32());
own wasm_func_t* h = wasm_func_new(store, neg_type, neg_callback);
wasm_functype_delete(neg_type);
// Try cloning.
own wasm_table_t* copy = wasm_table_copy(table);
assert(wasm_table_same(table, copy));
wasm_table_delete(copy);
// Check initial table.
printf("Checking table...\n");
check(wasm_table_size(table) == 2);
check_table(table, 0, false);
check_table(table, 1, true);
check_trap(call_indirect, 0, 0);
check_call(call_indirect, 7, 1, 7);
check_trap(call_indirect, 0, 2);
// Mutate table.
printf("Mutating table...\n");
check(wasm_table_set(table, 0, wasm_func_as_ref(g)));
check(wasm_table_set(table, 1, NULL));
check(! wasm_table_set(table, 2, wasm_func_as_ref(f)));
check_table(table, 0, true);
check_table(table, 1, false);
check_call(call_indirect, 7, 0, 666);
check_trap(call_indirect, 0, 1);
check_trap(call_indirect, 0, 2);
// Grow table.
printf("Growing table...\n");
check(wasm_table_grow(table, 3, NULL));
check(wasm_table_size(table) == 5);
check(wasm_table_set(table, 2, wasm_func_as_ref(f)));
check(wasm_table_set(table, 3, wasm_func_as_ref(h)));
check(! wasm_table_set(table, 5, NULL));
check_table(table, 2, true);
check_table(table, 3, true);
check_table(table, 4, false);
check_call(call_indirect, 5, 2, 5);
check_call(call_indirect, 6, 3, -6);
check_trap(call_indirect, 0, 4);
check_trap(call_indirect, 0, 5);
check(wasm_table_grow(table, 2, wasm_func_as_ref(f)));
check(wasm_table_size(table) == 7);
check_table(table, 5, true);
check_table(table, 6, true);
check(! wasm_table_grow(table, 5, NULL));
check(wasm_table_grow(table, 3, NULL));
check(wasm_table_grow(table, 0, NULL));
wasm_func_delete(h);
wasm_extern_vec_delete(&exports);
wasm_instance_delete(instance);
// Create stand-alone table.
// TODO(wasm+): Once Wasm allows multiple tables, turn this into import.
printf("Creating stand-alone table...\n");
wasm_limits_t limits = {5, 5};
own wasm_tabletype_t* tabletype =
wasm_tabletype_new(wasm_valtype_new(WASM_FUNCREF), &limits);
own wasm_table_t* table2 = wasm_table_new(store, tabletype, NULL);
check(wasm_table_size(table2) == 5);
check(! wasm_table_grow(table2, 1, NULL));
check(wasm_table_grow(table2, 0, NULL));
wasm_tabletype_delete(tabletype);
wasm_table_delete(table2);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,192 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto neg_callback(const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
results[0] = wasm::Val(-args[0].i32());
return nullptr;
}
auto get_export_table(wasm::ownvec<wasm::Extern>& exports, size_t i) -> wasm::Table* {
if (exports.size() <= i || !exports[i]->table()) {
std::cout << "> Error accessing table export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->table();
}
auto get_export_func(const wasm::ownvec<wasm::Extern>& exports, size_t i) -> const wasm::Func* {
if (exports.size() <= i || !exports[i]->func()) {
std::cout << "> Error accessing function export " << i << "!" << std::endl;
exit(1);
}
return exports[i]->func();
}
template<class T, class U>
void check(T actual, U expected) {
if (actual != expected) {
std::cout << "> Error on result, expected " << expected << ", got " << actual << std::endl;
exit(1);
}
}
void check(bool success) {
if (! success) {
std::cout << "> Error, expected success" << std::endl;
exit(1);
}
}
auto call(
const wasm::Func* func, wasm::Val&& arg1, wasm::Val&& arg2
) -> wasm::Val {
auto args = wasm::vec<wasm::Val>::make(std::move(arg1), std::move(arg2));
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (func->call(args, results)) {
std::cout << "> Error on result, expected return" << std::endl;
exit(1);
}
return results[0].copy();
}
void check_trap(const wasm::Func* func, wasm::Val&& arg1, wasm::Val&& arg2) {
auto args = wasm::vec<wasm::Val>::make(std::move(arg1), std::move(arg2));
auto results = wasm::vec<wasm::Val>::make_uninitialized(1);
if (! func->call(args, results)) {
std::cout << "> Error on result, expected trap" << std::endl;
exit(1);
}
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("table.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make();
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting exports..." << std::endl;
auto exports = instance->exports();
size_t i = 0;
auto table = get_export_table(exports, i++);
auto call_indirect = get_export_func(exports, i++);
auto f = get_export_func(exports, i++);
auto g = get_export_func(exports, i++);
// Create external function.
std::cout << "Creating callback..." << std::endl;
auto neg_type =
wasm::FuncType::make(wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)),
wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)));
auto h = wasm::Func::make(store, neg_type.get(), neg_callback);
// Try cloning.
assert(table->copy()->same(table));
// Check initial table.
std::cout << "Checking table..." << std::endl;
check(table->size(), 2u);
check(table->get(0) == nullptr);
check(table->get(1) != nullptr);
check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(0));
check(call(call_indirect, wasm::Val::i32(7), wasm::Val::i32(1)).i32(), 7);
check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(2));
// Mutate table.
std::cout << "Mutating table..." << std::endl;
check(table->set(0, g));
check(table->set(1, nullptr));
check(! table->set(2, f));
check(table->get(0) != nullptr);
check(table->get(1) == nullptr);
check(call(call_indirect, wasm::Val::i32(7), wasm::Val::i32(0)).i32(), 666);
check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(1));
check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(2));
// Grow table.
std::cout << "Growing table..." << std::endl;
check(table->grow(3));
check(table->size(), 5u);
check(table->set(2, f));
check(table->set(3, h.get()));
check(! table->set(5, nullptr));
check(table->get(2) != nullptr);
check(table->get(3) != nullptr);
check(table->get(4) == nullptr);
check(call(call_indirect, wasm::Val::i32(5), wasm::Val::i32(2)).i32(), 5);
check(call(call_indirect, wasm::Val::i32(6), wasm::Val::i32(3)).i32(), -6);
check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(4));
check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(5));
check(table->grow(2, f));
check(table->size(), 7u);
check(table->get(5) != nullptr);
check(table->get(6) != nullptr);
check(! table->grow(5));
check(table->grow(3));
check(table->grow(0));
// Create stand-alone table.
// TODO(wasm+): Once Wasm allows multiple tables, turn this into import.
std::cout << "Creating stand-alone table..." << std::endl;
auto tabletype = wasm::TableType::make(
wasm::ValType::make(wasm::ValKind::FUNCREF), wasm::Limits(5, 5));
auto table2 = wasm::Table::make(store, tabletype.get());
check(table2->size() == 5);
check(! table2->grow(1));
check(table2->grow(0));
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,12 @@
(module
(table (export "table") 2 10 funcref)
(func (export "call_indirect") (param i32 i32) (result i32)
(call_indirect (param i32) (result i32) (local.get 0) (local.get 1))
)
(func $f (export "f") (param i32) (result i32) (local.get 0))
(func (export "g") (param i32) (result i32) (i32.const 666))
(elem (i32.const 1) $f)
)

View File

@ -0,0 +1,155 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include "wasm.h"
#define own
const int N_THREADS = 10;
const int N_REPS = 3;
// A function to be called from Wasm code.
own wasm_trap_t* callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
assert(args->data[0].kind == WASM_I32);
printf("> Thread %d running\n", args->data[0].of.i32);
return NULL;
}
typedef struct {
wasm_engine_t* engine;
wasm_shared_module_t* module;
int id;
} thread_args;
void* run(void* args_abs) {
thread_args* args = (thread_args*)args_abs;
// Recreate store and module.
own wasm_store_t* store = wasm_store_new(args->engine);
own wasm_module_t* module = wasm_module_obtain(store, args->module);
// Run the example N times.
for (int i = 0; i < N_REPS; ++i) {
usleep(100000);
// Create imports.
own wasm_functype_t* func_type = wasm_functype_new_1_0(wasm_valtype_new_i32());
own wasm_func_t* func = wasm_func_new(store, func_type, callback);
wasm_functype_delete(func_type);
wasm_val_t val = WASM_I32_VAL((int32_t)args->id);
own wasm_globaltype_t* global_type =
wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST);
own wasm_global_t* global = wasm_global_new(store, global_type, &val);
wasm_globaltype_delete(global_type);
// Instantiate.
wasm_extern_t* externs[] = {
wasm_func_as_extern(func), wasm_global_as_extern(global),
};
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return NULL;
}
wasm_func_delete(func);
wasm_global_delete(global);
// Extract export.
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size == 0) {
printf("> Error accessing exports!\n");
return NULL;
}
const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]);
if (run_func == NULL) {
printf("> Error accessing export!\n");
return NULL;
}
wasm_instance_delete(instance);
// Call.
wasm_val_vec_t empty = WASM_EMPTY_VEC;
if (wasm_func_call(run_func, &empty, &empty)) {
printf("> Error calling function!\n");
return NULL;
}
wasm_extern_vec_delete(&exports);
}
wasm_module_delete(module);
wasm_store_delete(store);
free(args_abs);
return NULL;
}
int main(int argc, const char *argv[]) {
// Initialize.
wasm_engine_t* engine = wasm_engine_new();
// Load binary.
FILE* file = fopen("threads.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile and share.
own wasm_store_t* store = wasm_store_new(engine);
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
own wasm_shared_module_t* shared = wasm_module_share(module);
wasm_module_delete(module);
wasm_store_delete(store);
// Spawn threads.
pthread_t threads[N_THREADS];
for (int i = 0; i < N_THREADS; i++) {
thread_args* args = malloc(sizeof(thread_args));
args->id = i;
args->engine = engine;
args->module = shared;
printf("Initializing thread %d...\n", i);
pthread_create(&threads[i], NULL, &run, args);
}
for (int i = 0; i < N_THREADS; i++) {
printf("Waiting for thread: %d\n", i);
pthread_join(threads[i], NULL);
}
wasm_shared_module_delete(shared);
wasm_engine_delete(engine);
return 0;
}

View File

@ -0,0 +1,124 @@
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include "wasm.hh"
const int N_THREADS = 10;
const int N_REPS = 3;
// A function to be called from Wasm code.
auto callback(void* env, const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
assert(args[0].kind() == wasm::ValKind::I32);
std::lock_guard<std::mutex> lock(*reinterpret_cast<std::mutex*>(env));
std::cout << "Thread " << args[0].i32() << " running..." << std::endl;
std::cout.flush();
return nullptr;
}
void run(
wasm::Engine* engine, const wasm::Shared<wasm::Module>* shared,
std::mutex* mutex, int id
) {
// Create store.
auto store_ = wasm::Store::make(engine);
auto store = store_.get();
// Obtain.
auto module = wasm::Module::obtain(store, shared);
if (!module) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Run the example N times.
for (int i = 0; i < N_REPS; ++i) {
std::this_thread::sleep_for(std::chrono::nanoseconds(100000));
// Create imports.
auto func_type =
wasm::FuncType::make(wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)),
wasm::ownvec<wasm::ValType>::make());
auto func = wasm::Func::make(store, func_type.get(), callback, mutex);
auto global_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::ValKind::I32), wasm::Mutability::CONST);
auto global = wasm::Global::make(
store, global_type.get(), wasm::Val::i32(i));
// Instantiate.
auto imports = wasm::vec<wasm::Extern*>::make(func.get(), global.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::ExternKind::FUNC ||
!exports[0]->func()) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error accessing export!" << std::endl;
exit(1);
}
auto run_func = exports[0]->func();
// Call.
auto empty = wasm::vec<wasm::Val>::make();
run_func->call(empty, empty);
}
}
int main(int argc, const char *argv[]) {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("threads.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
return 1;
}
// Compile and share.
std::cout << "Compiling and sharing module..." << std::endl;
auto store = wasm::Store::make(engine.get());
auto module = wasm::Module::make(store.get(), binary);
auto shared = module->share();
// Spawn threads.
std::cout << "Spawning threads..." << std::endl;
std::mutex mutex;
std::thread threads[N_THREADS];
for (int i = 0; i < N_THREADS; ++i) {
{
std::lock_guard<std::mutex> lock(mutex);
std::cout << "Initializing thread " << i << "..." << std::endl;
}
threads[i] = std::thread(run, engine.get(), shared.get(), &mutex, i);
}
for (int i = 0; i < N_THREADS; ++i) {
{
std::lock_guard<std::mutex> lock(mutex);
std::cout << "Waiting for thread " << i << "..." << std::endl;
}
threads[i].join();
}
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,5 @@
(module
(func $message (import "" "hello") (param i32))
(global $id (import "" "id") i32)
(func (export "run") (call $message (global.get $id)))
)

View File

@ -0,0 +1,158 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* fail_callback(
void* env, const wasm_val_vec_t* args, wasm_val_vec_t* results
) {
printf("Calling back...\n");
own wasm_name_t message;
wasm_name_new_from_string_nt(&message, "callback abort");
own wasm_trap_t* trap = wasm_trap_new((wasm_store_t*)env, &message);
wasm_name_delete(&message);
return trap;
}
void print_frame(wasm_frame_t* frame) {
printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n",
wasm_frame_instance(frame),
wasm_frame_module_offset(frame),
wasm_frame_func_index(frame),
wasm_frame_func_offset(frame)
);
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("trap.wasm", "rb");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external print functions.
printf("Creating callback...\n");
own wasm_functype_t* fail_type =
wasm_functype_new_0_1(wasm_valtype_new_i32());
own wasm_func_t* fail_func =
wasm_func_new_with_env(store, fail_type, fail_callback, store, NULL);
wasm_functype_delete(fail_type);
// Instantiate.
printf("Instantiating module...\n");
wasm_extern_t* externs[] = { wasm_func_as_extern(fail_func) };
wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
own wasm_instance_t* instance =
wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(fail_func);
// Extract export.
printf("Extracting exports...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size < 2) {
printf("> Error accessing exports!\n");
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
for (int i = 0; i < 2; ++i) {
const wasm_func_t* func = wasm_extern_as_func(exports.data[i]);
if (func == NULL) {
printf("> Error accessing export!\n");
return 1;
}
printf("Calling export %d...\n", i);
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
own wasm_trap_t* trap = wasm_func_call(func, &args, &results);
if (!trap) {
printf("> Error calling function, expected trap!\n");
return 1;
}
printf("Printing message...\n");
own wasm_name_t message;
wasm_trap_message(trap, &message);
printf("> %s\n", message.data);
printf("Printing origin...\n");
own wasm_frame_t* frame = wasm_trap_origin(trap);
if (frame) {
print_frame(frame);
wasm_frame_delete(frame);
} else {
printf("> Empty origin.\n");
}
printf("Printing trace...\n");
own wasm_frame_vec_t trace;
wasm_trap_trace(trap, &trace);
if (trace.size > 0) {
for (size_t i = 0; i < trace.size; ++i) {
print_frame(trace.data[i]);
}
} else {
printf("> Empty trace.\n");
}
wasm_frame_vec_delete(&trace);
wasm_trap_delete(trap);
wasm_name_delete(&message);
}
wasm_extern_vec_delete(&exports);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}

View File

@ -0,0 +1,126 @@
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto fail_callback(void* env, const wasm::vec<wasm::Val>& args,
wasm::vec<wasm::Val>& results) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
auto store = reinterpret_cast<wasm::Store*>(env);
auto message = wasm::Name::make_nt(std::string("callback abort"));
return wasm::Trap::make(store, message);
}
void print_frame(const wasm::Frame* frame) {
std::cout << "> " << frame->instance();
std::cout << " @ 0x" << std::hex << frame->module_offset();
std::cout << " = " << frame->func_index();
std::cout << ".0x" << std::hex << frame->func_offset() << std::endl;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("trap.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto fail_type =
wasm::FuncType::make(wasm::ownvec<wasm::ValType>::make(),
wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::ValKind::I32)));
auto fail_func =
wasm::Func::make(store, fail_type.get(), fail_callback, store);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto imports = wasm::vec<wasm::Extern*>::make(fail_func.get());
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting exports..." << std::endl;
auto exports = instance->exports();
if (exports.size() < 2 || exports[0]->kind() != wasm::ExternKind::FUNC ||
!exports[0]->func() || exports[1]->kind() != wasm::ExternKind::FUNC ||
!exports[1]->func()) {
std::cout << "> Error accessing exports!" << std::endl;
exit(1);
}
// Call.
for (size_t i = 0; i < 2; ++i) {
std::cout << "Calling export " << i << "..." << std::endl;
auto args = wasm::vec<wasm::Val>::make();
auto results = wasm::vec<wasm::Val>::make();
auto trap = exports[i]->func()->call(args, results);
if (!trap) {
std::cout << "> Error calling function, expected trap!" << std::endl;
exit(1);
}
std::cout << "Printing message..." << std::endl;
std::cout << "> " << trap->message().get() << std::endl;
std::cout << "Printing origin..." << std::endl;
auto frame = trap->origin();
if (frame) {
print_frame(frame.get());
} else {
std::cout << "> Empty origin." << std::endl;
}
std::cout << "Printing trace..." << std::endl;
auto trace = trap->trace();
if (trace.size() > 0) {
for (size_t i = 0; i < trace.size(); ++i) {
print_frame(trace[i].get());
}
} else {
std::cout << "> Empty trace." << std::endl;
}
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,5 @@
(module
(func $callback (import "" "callback") (result i32))
(func (export "callback") (result i32) (call $callback))
(func (export "unreachable") (result i32) (unreachable) (i32.const 1))
)