194 lines
6.4 KiB
C++
194 lines
6.4 KiB
C++
|
#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;
|
||
|
}
|
||
|
|