Commit 912b3912 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-c-api] Add upstream examples as tests

Plus a script to compile/link/run them.

Change-Id: Iac8ffcda3a73902261c07a7b4e5d967a19414c75
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1564058
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarMichael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60911}
parent f80bfeaf
......@@ -13,5 +13,5 @@ Provides a "black box" API for embedding a Wasm engine in C/C++ applications.
Local modifications:
None.
This is only the contents of the "include/" directory of the upstream
repository.
The contents of the upstream "include/" directory are directly in here.
The upstream "example/" directory is copied as-is.
#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_ANYREF:
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_t args[], wasm_val_t results[]
) {
printf("Calling back...\n> ");
wasm_val_print(args[0]);
printf("\n");
wasm_val_copy(&results[0], &args[0]);
return NULL;
}
// A function closure.
own wasm_trap_t* closure_callback(
void* env, const wasm_val_t args[], wasm_val_t results[]
) {
int i = *(int*)env;
printf("Calling back closure...\n");
printf("> %d\n", i);
results[0].kind = WASM_I32;
results[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", "r");
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");
const wasm_extern_t* imports[] = {
wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func)
};
own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
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 args[2];
args[0].kind = WASM_I32;
args[0].of.i32 = 3;
args[1].kind = WASM_I32;
args[1].of.i32 = 4;
wasm_val_t results[1];
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", results[0].of.i32);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}
#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::I32: {
out << val.i32();
} break;
case wasm::I64: {
out << val.i64();
} break;
case wasm::F32: {
out << val.f32();
} break;
case wasm::F64: {
out << val.f64();
} break;
case wasm::ANYREF:
case wasm::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::Val args[], 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::Val args[], 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;
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 print functions.
std::cout << "Creating callback..." << std::endl;
auto print_type = wasm::FuncType::make(
wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)),
wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::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::vec<wasm::ValType*>::make(),
wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
);
auto closure_func = wasm::Func::make(store, closure_type.get(), closure_callback, &i);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
wasm::Extern* imports[] = {print_func.get(), closure_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 export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
return;
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
wasm::Val args[] = {wasm::Val::i32(3), wasm::Val::i32(4)};
wasm::Val results[1];
if (run_func->call(args, results)) {
std::cout << "> Error calling function!" << std::endl;
return;
}
// 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;
}
(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)
)
)
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
const int iterations = 100000;
void finalize(void* data) {
int i = (int)data;
if (i % (iterations / 10) == 0) printf("Finalizing #%d...\n", i);
}
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("finalize.wasm", "r");
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 modules...\n");
for (int i = 0; i <= iterations; ++i) {
if (i % (iterations / 10) == 0) printf("%d\n", i);
own wasm_instance_t* instance = wasm_instance_new(store, module, NULL);
if (!instance) {
printf("> Error instantiating module %d!\n", i);
return 1;
}
void* data = (void*)(intptr_t)i;
wasm_instance_set_host_info_with_finalizer(instance, data, &finalize);
wasm_instance_delete(instance);
}
wasm_module_delete(module);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
const int iterations = 100000;
void finalize(void* data) {
intptr_t i = reinterpret_cast<intptr_t>(data);
if (i % (iterations / 10) == 0) {
std::cout << "Finalizing #" << i << "..." << 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("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;
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;
}
// 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 instance = wasm::Instance::make(store, module.get(), nullptr);
if (!instance) {
std::cout << "> Error instantiating module " << i << "!" << std::endl;
return;
}
instance->set_host_info(reinterpret_cast<void*>(i), &finalize);
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}
(module
(func (export "f"))
(func (export "g"))
(func (export "h"))
)
#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 results[1]; \
wasm_func_call(func, NULL, results); \
check(results[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", "r");
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 = {.kind = WASM_F32, .of = {.f32 = 1}};
own wasm_global_t* const_f32_import = wasm_global_new(store, const_f32_type, &val_f32_1);
wasm_val_t val_i64_2 = {.kind = WASM_I64, .of = {.i64 = 2}};
own wasm_global_t* const_i64_import = wasm_global_new(store, const_i64_type, &val_i64_2);
wasm_val_t val_f32_3 = {.kind = WASM_F32, .of = {.f32 = 3}};
own wasm_global_t* var_f32_import = wasm_global_new(store, var_f32_type, &val_f32_3);
wasm_val_t val_i64_4 = {.kind = WASM_I64, .of = {.i64 = 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");
const wasm_extern_t* imports[] = {
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)
};
own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
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++);
// 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 = {.kind = WASM_F32, .of = {.f32 = 33}};
wasm_global_set(var_f32_import, &val33);
wasm_val_t val34 = {.kind = WASM_I64, .of = {.i64 = 34}};
wasm_global_set(var_i64_import, &val34);
wasm_val_t val37 = {.kind = WASM_F32, .of = {.f32 = 37}};
wasm_global_set(var_f32_export, &val37);
wasm_val_t val38 = {.kind = WASM_I64, .of = {.i64 = 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_t args73[] = { {.kind = WASM_F32, .of = {.f32 = 73}} };
wasm_func_call(set_var_f32_import, args73, NULL);
wasm_val_t args74[] = { {.kind = WASM_I64, .of = {.i64 = 74}} };
wasm_func_call(set_var_i64_import, args74, NULL);
wasm_val_t args77[] = { {.kind = WASM_F32, .of = {.f32 = 77}} };
wasm_func_call(set_var_f32_export, args77, NULL);
wasm_val_t args78[] = { {.kind = WASM_I64, .of = {.i64 = 78}} };
wasm_func_call(set_var_i64_export, args78, NULL);
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;
}
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
auto get_export_global(wasm::vec<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::vec<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 {
wasm::Val results[1];
if (func->call(nullptr, results)) {
std::cout << "> Error calling function!" << std::endl;
exit(1);
}
return results[0].copy();
}
void call(const wasm::Func* func, wasm::Val&& arg) {
wasm::Val args[1] = {std::move(arg)};
if (func->call(args)) {
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;
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 globals.
std::cout << "Creating globals..." << std::endl;
auto const_f32_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::F32), wasm::CONST);
auto const_i64_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::I64), wasm::CONST);
auto var_f32_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::F32), wasm::VAR);
auto var_i64_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::I64), wasm::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;
wasm::Extern* imports[] = {
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;
return;
}
// 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++);
// 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;
}
(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)))
)
#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_t args[], wasm_val_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", "r");
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* 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");
const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) };
own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
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");
if (wasm_func_call(run_func, NULL, NULL)) {
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;
}
#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::Val args[], 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;
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 print functions.
std::cout << "Creating callback..." << std::endl;
auto hello_type = wasm::FuncType::make(
wasm::vec<wasm::ValType*>::make(), wasm::vec<wasm::ValType*>::make()
);
auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
wasm::Extern* imports[] = {hello_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 export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
return;
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
if (run_func->call()) {
std::cout << "> Error calling function!" << std::endl;
return;
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)
#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, wasm_val_t args[], int32_t expected) {
wasm_val_t results[1];
if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) {
printf("> Error on result\n");
exit(1);
}
}
void check_call0(wasm_func_t* func, int32_t expected) {
check_call(func, NULL, expected);
}
void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) {
wasm_val_t args[] = { {.kind = WASM_I32, .of = {.i32 = arg}} };
check_call(func, args, expected);
}
void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) {
wasm_val_t args[2] = {
{.kind = WASM_I32, .of = {.i32 = arg1}},
{.kind = WASM_I32, .of = {.i32 = arg2}}
};
check_call(func, args, expected);
}
void check_ok(wasm_func_t* func, wasm_val_t args[]) {
if (wasm_func_call(func, args, NULL)) {
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[2] = {
{.kind = WASM_I32, .of = {.i32 = arg1}},
{.kind = WASM_I32, .of = {.i32 = arg2}}
};
check_ok(func, args);
}
void check_trap(wasm_func_t* func, wasm_val_t args[]) {
wasm_val_t results[1];
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[1] = { {.kind = WASM_I32, .of = {.i32 = arg}} };
check_trap(func, args);
}
void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
wasm_val_t args[2] = {
{.kind = WASM_I32, .of = {.i32 = arg1}},
{.kind = WASM_I32, .of = {.i32 = arg2}}
};
check_trap(func, 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", "r");
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");
own wasm_instance_t* instance = wasm_instance_new(store, module, 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);
// 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;
}
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
auto get_export_memory(wasm::vec<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::vec<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) {
wasm::Val args[] = {wasm::Val::i32(xs)...};
if (func->call(args)) {
std::cout << "> Error on result, expected return" << std::endl;
exit(1);
}
}
template<class... Args>
void check_trap(const wasm::Func* func, Args... xs) {
wasm::Val args[] = {wasm::Val::i32(xs)...};
if (! func->call(args)) {
std::cout << "> Error on result, expected trap" << std::endl;
exit(1);
}
}
template<class... Args>
auto call(const wasm::Func* func, Args... xs) -> int32_t {
wasm::Val args[] = {wasm::Val::i32(xs)...};
wasm::Val results[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;
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;
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto instance = wasm::Instance::make(store, module.get(), nullptr);
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 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++);
// 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;
}
(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")
)
#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_ANYREF: printf("anyref"); 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", "r");
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");
own wasm_instance_t* instance = wasm_instance_new(store, module, 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;
}
#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::VAR: return out << "var";
case wasm::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::I32: return out << "i32";
case wasm::I64: return out << "i64";
case wasm::F32: return out << "f32";
case wasm::F64: return out << "f64";
case wasm::ANYREF: return out << "anyref";
case wasm::FUNCREF: return out << "funcref";
}
return out;
}
auto operator<<(std::ostream& out, const wasm::vec<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::EXTERN_FUNC: {
out << "func " << type.func()->params() << " -> " << type.func()->results();
} break;
case wasm::EXTERN_GLOBAL: {
out << "global " << type.global()->mutability() << " " << *type.global()->content();
} break;
case wasm::EXTERN_TABLE: {
out << "table " << type.table()->limits() << " " << *type.table()->element();
} break;
case wasm::EXTERN_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;
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;
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto instance = wasm::Instance::make(store, module.get(), nullptr);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
return;
}
// 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::EXTERN_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;
}
(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)
)
#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_t args[], wasm_val_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", "r");
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");
const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) };
own wasm_instance_t* instance = wasm_instance_new(store, deserialized, imports);
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");
if (wasm_func_call(run_func, NULL, NULL)) {
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;
}
#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::Val args[], 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;
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;
}
// 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;
return;
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto hello_type = wasm::FuncType::make(
wasm::vec<wasm::ValType*>::make(), wasm::vec<wasm::ValType*>::make()
);
auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback);
// Instantiate.
std::cout << "Instantiating deserialized module..." << std::endl;
wasm::Extern* imports[] = {hello_func.get()};
auto instance = wasm::Instance::make(store, deserialized.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
return;
}
// Extract export.
std::cout << "Extracting export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
return;
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
if (! run_func->call()) {
std::cout << "> Error calling function!" << std::endl;
return;
}
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}
(module
(func $hello (import "" "hello"))
(func (export "run") (call $hello))
)
#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_t args[], wasm_val_t results[]
) {
printf("Calling back...\n");
results[0].kind = WASM_I32;
results[0].of.i32 = -args[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 args[2] = {
{.kind = WASM_I32, .of = {.i32 = arg1}},
{.kind = WASM_I32, .of = {.i32 = arg2}}
};
wasm_val_t results[1];
if (wasm_func_call(func, args, results) || results[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 args[2] = {
{.kind = WASM_I32, .of = {.i32 = arg1}},
{.kind = WASM_I32, .of = {.i32 = arg2}}
};
own wasm_trap_t* trap = wasm_func_call(func, args, NULL);
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", "r");
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");
own wasm_instance_t* instance = wasm_instance_new(store, module, 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);
// 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;
}
#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::Val args[], 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::vec<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::vec<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 {
wasm::Val args[2] = {std::move(arg1), std::move(arg2)};
wasm::Val results[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) {
wasm::Val args[2] = {std::move(arg1), std::move(arg2)};
wasm::Val results[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;
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;
}
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
auto instance = wasm::Instance::make(store, module.get(), nullptr);
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 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::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)),
wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
);
auto h = wasm::Func::make(store, neg_type.get(), neg_callback);
// 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::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;
}
(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)
)
#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_t args[], wasm_val_t results[]) {
assert(args[0].kind == WASM_I32);
printf("> Thread %d running\n", args[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;
// Rereate 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 = {.kind = WASM_I32, .of = {.i32 = (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.
const wasm_extern_t* imports[] = {
wasm_func_as_extern(func), wasm_global_as_extern(global),
};
own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
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.
if (wasm_func_call(run_func, NULL, NULL)) {
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", "r");
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;
}
#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::Val args[], wasm::Val results[]
) -> wasm::own<wasm::Trap*> {
assert(args[0].kind() == wasm::I32);
std::lock_guard<std::mutex>(*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;
return;
}
// 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::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)),
wasm::vec<wasm::ValType*>::make()
);
auto func = wasm::Func::make(store, func_type.get(), callback, mutex);
auto global_type = wasm::GlobalType::make(
wasm::ValType::make(wasm::I32), wasm::CONST);
auto global = wasm::Global::make(
store, global_type.get(), wasm::Val::i32(i));
// Instantiate.
wasm::Extern* imports[] = {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;
return;
}
// Extract export.
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::lock_guard<std::mutex> lock(*mutex);
std::cout << "> Error accessing export!" << std::endl;
return;
}
auto run_func = exports[0]->func();
// Call.
run_func->call();
}
}
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;
}
(module
(func $message (import "" "hello") (param i32))
(global $id (import "" "id") i32)
(func (export "run") (call $message (global.get $id)))
)
#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_t args[], wasm_val_t results[]
) {
printf("Calling back...\n");
own wasm_name_t message;
wasm_name_new_from_string(&message, "callback abort");
own wasm_trap_t* trap = wasm_trap_new((wasm_store_t*)env, &message);
wasm_name_delete(&message);
return 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("trap.wasm", "r");
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");
const wasm_extern_t* imports[] = { wasm_func_as_extern(fail_func) };
own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
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);
own wasm_trap_t* trap = wasm_func_call(func, NULL, NULL);
if (! trap) {
printf("> Error calling function!\n");
return 1;
}
printf("Printing message...\n");
own wasm_name_t message;
wasm_trap_message(trap, &message);
printf("> %s\n", message.data);
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;
}
#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::Val args[], 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(std::string("callback abort"));
return wasm::Trap::make(store, message);
}
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;
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 print functions.
std::cout << "Creating callback..." << std::endl;
auto fail_type = wasm::FuncType::make(
wasm::vec<wasm::ValType*>::make(),
wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32))
);
auto fail_func =
wasm::Func::make(store, fail_type.get(), fail_callback, store);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
wasm::Extern* imports[] = {fail_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();
if (exports.size() < 2 ||
exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func() ||
exports[1]->kind() != wasm::EXTERN_FUNC || !exports[1]->func()) {
std::cout << "> Error accessing exports!" << std::endl;
return;
}
// Call.
for (size_t i = 0; i < 2; ++i) {
std::cout << "Calling export " << i << "..." << std::endl;
auto trap = exports[i]->func()->call();
if (!trap) {
std::cout << "> Error calling function!" << std::endl;
return;
}
std::cout << "Printing message..." << std::endl;
std::cout << "> " << trap->message().get() << 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;
}
(module
(func $callback (import "" "callback") (result i32))
(func (export "callback") (result i32) (call $callback))
(func (export "unreachable") (result i32) (unreachable) (i32.const 1))
)
#!/usr/bin/env python
#
# Copyright 2019 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""\
Helper script for compiling and running the Wasm C/C++ API examples.
Usage: tools/run-wasm-api-tests.py outdir tempdir [filters...]
"outdir" is the build output directory containing libwee8, e.g. out/x64.release
"tempdir" is a temporary dir where this script may put its artifacts. It is
the caller's responsibility to clean it up afterwards.
By default, this script builds and runs all examples, both the respective
C and C++ versions, both with GCC ("gcc" and "g++" binaries found in $PATH)
and V8's bundled Clang in third_party/llvm-build/. You can use any number
of "filters" arguments to run only a subset:
- "c": run C versions of examples
- "cc": run C++ versions of examples
- "gcc": compile with GCC
- "clang": compile with Clang
- "hello" etc.: run "hello" example
"""
from __future__ import print_function
import os
import shutil
import subprocess
import sys
CFLAGS = "-DDEBUG -Wall -Werror -O0 -fsanitize=address"
CHECKOUT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
WASM_PATH = os.path.join(CHECKOUT_PATH, "third_party", "wasm-api")
CLANG_PATH = os.path.join(CHECKOUT_PATH, "third_party", "llvm-build",
"Release+Asserts", "bin")
EXAMPLES = ["hello", "callback", "trap", "reflect", "global", "table",
"memory", "finalize", "serialize", "threads"]
CLANG = {
"name": "Clang",
"c": os.path.join(CLANG_PATH, "clang"),
"cc": os.path.join(CLANG_PATH, "clang++"),
"ldflags": "-fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor",
}
GCC = {
"name": "GCC",
"c": "gcc",
"cc": "g++",
"ldflags": "",
}
C = {
"name": "C",
"suffix": "c",
"cflags": "",
}
CXX = {
"name": "C++",
"suffix": "cc",
"cflags": "-std=c++11",
}
MIN_ARGS = 3 # Script, outdir, tempdir
def _Call(cmd_list, silent=False):
cmd = " ".join(cmd_list)
if not silent: print("# %s" % cmd)
return subprocess.call(cmd, shell=True)
class Runner(object):
def __init__(self, name, outdir, tempdir):
self.name = name
self.outdir = outdir
self.tempdir = tempdir
self.src_file_basename = os.path.join(WASM_PATH, "example", name)
self.dst_file_basename = os.path.join(tempdir, name)
self.lib_file = os.path.join(outdir, "obj", "libwee8.a")
if not os.path.exists(self.lib_file):
print("libwee8 library not found, make sure to pass the outdir as "
"first argument; see --help")
sys.exit(1)
src_wasm_file = self.src_file_basename + ".wasm"
dst_wasm_file = self.dst_file_basename + ".wasm"
shutil.copyfile(src_wasm_file, dst_wasm_file)
def _Error(self, step, lang, compiler):
print("Error: %s failed. To repro: tools/run-wasm-api-tests.py "
"%s %s %s %s %s" %
(step, self.outdir, self.tempdir, self.name, lang,
compiler["name"].lower()))
def CompileAndRun(self, compiler, language):
print("==== %s %s/%s ====" %
(self.name, language["name"], compiler["name"]))
lang = language["suffix"]
src_file = self.src_file_basename + "." + lang
exe_file = self.dst_file_basename + "-" + lang
obj_file = exe_file + ".o"
# Compile.
c = _Call([compiler[lang], "-c", language["cflags"], CFLAGS,
"-I", WASM_PATH, "-o", obj_file, src_file])
if c: return self._Error("compilation", lang, compiler)
# Link.
c = _Call([compiler["cc"], CFLAGS, compiler["ldflags"], obj_file,
"-o", exe_file, self.lib_file, "-ldl -pthread"])
if c: return self._Error("linking", lang, compiler)
# Execute.
exe_file = "./%s-%s" % (self.name, lang)
c = _Call(["cd", self.tempdir, ";", exe_file])
if c: return self._Error("execution", lang, compiler)
return 0
def Main(args):
if (len(args) < MIN_ARGS or args[1] in ("-h", "--help", "help")):
print(__doc__)
return 1
outdir = sys.argv[1]
tempdir = sys.argv[2]
result = 0
examples = EXAMPLES
compilers = (GCC, CLANG)
languages = (C, CXX)
if len(args) > MIN_ARGS:
custom_compilers = []
custom_languages = []
custom_examples = []
for i in range(MIN_ARGS, len(args)):
arg = args[i]
if arg == "c" and C not in custom_languages:
custom_languages.append(C)
elif arg in ("cc", "cpp", "cxx", "c++") and CXX not in custom_languages:
custom_languages.append(CXX)
elif arg in ("gcc", "g++") and GCC not in custom_compilers:
custom_compilers.append(GCC)
elif arg in ("clang", "clang++") and CLANG not in custom_compilers:
custom_compilers.append(CLANG)
elif arg in EXAMPLES and arg not in custom_examples:
custom_examples.append(arg)
else:
print("Didn't understand '%s'" % arg)
return 1
if custom_compilers:
compilers = custom_compilers
if custom_languages:
languages = custom_languages
if custom_examples:
examples = custom_examples
for example in examples:
runner = Runner(example, outdir, tempdir)
for compiler in compilers:
for language in languages:
c = runner.CompileAndRun(compiler, language)
if c: result = c
return result
if __name__ == "__main__":
sys.exit(Main(sys.argv))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment