opam-2.0.0
Vova 3 years ago
commit db514ecadc

@ -1,3 +1,2 @@
build
cmake-build-debug
wasm/test_prog.wasm

@ -14,3 +14,12 @@ target_link_libraries(${target} PRIVATE wasm3_cpp)
target_compile_options(${target} PUBLIC -g)
target_compile_options(m3 PUBLIC -g)
# Copy the 'wasm' directory into the build directory, so that
# wasm/test_prog.wasm is found even if wasm3_cpp_example is executed
# from the build directory.
add_custom_target(copy_wasm ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_LIST_DIR}/wasm
${CMAKE_BINARY_DIR}/wasm
)
add_dependencies(${CMAKE_PROJECT_NAME} copy_wasm)

@ -54,7 +54,7 @@ If the module doesn't reference an imported function named `func`, an exception
`template <typename Ret> Ret function::call()` — call a WebAssembly function which doesn't take any arguments. The return value of the function is automatically converted to the type `Ret`. Note that you need to specify the return type when using this template function, and the type has to match the type returned by the WebAssembly function.
`template <typename Ret, typename ...Args> Ret function::call(Args...)` — same as above, but also allows passing arguments to the WebAssembly function. Note that due to a limitation of WASM3 API, the arguments are first converted to strings, and then passed to WASM3. The strings are then converted to the appropriate types based on the WebAssembly function signature. This conversion is limited to the following types: `int32_t`, `int64_t`, `float`, `double`.
`template <typename Ret, typename ...Args> Ret function::call(Args...)` — same as above, but also allows passing arguments to the WebAssembly function.
`template <typename Ret, typename ...Args> Ret function::call_argv(Args...)` — same as above, except that this function takes arguments as C strings (`const char*`).

@ -1,4 +1,5 @@
#include <cstdio>
#include <fstream>
#include "wasm3_cpp.h"
#include "wasm/test_prog.wasm.h"
@ -16,13 +17,35 @@ int main(void)
{
std::cout << "Loading WebAssembly..." << std::endl;
/* Wasm module can be loaded from a file */
try {
wasm3::environment env;
wasm3::runtime runtime = env.new_runtime(1024);
const char* file_name = "wasm/test_prog.wasm";
std::ifstream wasm_file(file_name, std::ios::binary | std::ios::in);
if (!wasm_file.is_open()) {
throw std::runtime_error("Failed to open wasm file");
}
wasm3::module mod = env.parse_module(wasm_file);
runtime.load(mod);
}
catch(std::runtime_error &e) {
std::cerr << "WASM3 error: " << e.what() << std::endl;
return 1;
}
/* Wasm module can also be loaded from an array */
try {
wasm3::environment env;
wasm3::runtime runtime = env.new_runtime(1024);
wasm3::module mod = env.parse_module(test_prog_wasm, test_prog_wasm_len);
runtime.load(mod);
/* link C++ functions "sum" and "ext_memcpy" to the module */
mod.link<sum>("*", "sum");
mod.link<ext_memcpy>("*", "ext_memcpy");
/* find and call functions defined in a wasm module */
{
wasm3::function test_fn = runtime.find_function("test");
auto res = test_fn.call<int>(20, 10);
@ -34,7 +57,6 @@ int main(void)
std::cout << "result: 0x" << std::hex << res << std::dec << std::endl;
}
}
catch(wasm3::error &e) {
std::cerr << "WASM3 error: " << e.what() << std::endl;
return 1;

Binary file not shown.

@ -11,8 +11,7 @@
#include <m3_api_defs.h>
#include "wasm3.h"
/* FIXME: remove when there is a public API to get function return value */
#include "m3_env.h"
namespace wasm3 {
/** @cond */
@ -24,19 +23,21 @@ namespace wasm3 {
typedef const void *(*m3_api_raw_fn)(IM3Runtime, uint64_t *, void *);
template<typename T>
void arg_from_stack(T &dest, stack_type &psp, mem_type mem) {
dest = *(T *) (psp);
psp++;
void arg_from_stack(T &dest, stack_type &_sp, mem_type mem) {
m3ApiGetArg(T, tmp);
dest = tmp;
}
template<typename T>
void arg_from_stack(T* &dest, stack_type &psp, mem_type _mem) {
dest = (void*) m3ApiOffsetToPtr(* ((u32 *) (psp++)));
void arg_from_stack(T* &dest, stack_type &_sp, mem_type _mem) {
m3ApiGetArgMem(T*, tmp);
dest = tmp;
};
template<typename T>
void arg_from_stack(const T* &dest, stack_type &psp, mem_type _mem) {
dest = (void*) m3ApiOffsetToPtr(* ((u32 *) (psp++)));
void arg_from_stack(const T* &dest, stack_type &_sp, mem_type _mem) {
m3ApiGetArgMem(const T*, tmp);
dest = tmp;
};
template<char c>
@ -77,13 +78,14 @@ namespace wasm3 {
template <typename Ret, typename ...Args, Ret (*Fn)(Args...)>
struct wrap_helper<Fn> {
static const void *wrap_fn(IM3Runtime rt, IM3ImportContext _ctx, stack_type sp, mem_type mem) {
Ret *ret_ptr = (Ret *) (sp);
static const void *wrap_fn(IM3Runtime rt, IM3ImportContext _ctx, stack_type _sp, mem_type mem) {
std::tuple<Args...> args;
get_args_from_stack(sp, mem, args);
// The order here matters: m3ApiReturnType should go before calling get_args_from_stack,
// since both modify `_sp`, and the return value on the stack is reserved before the arguments.
m3ApiReturnType(Ret);
get_args_from_stack(_sp, mem, args);
Ret r = std::apply(Fn, args);
*ret_ptr = r;
return m3Err_none;
m3ApiReturn(r);
}
};
@ -254,6 +256,7 @@ namespace wasm3 {
friend class runtime;
module(const std::shared_ptr<M3Environment> &env, std::istream &in_wasm) {
in_wasm.unsetf(std::ios::skipws);
std::vector<uint8_t> in_bytes;
std::copy(std::istream_iterator<uint8_t>(in_wasm),
std::istream_iterator<uint8_t>(),
@ -312,39 +315,27 @@ namespace wasm3 {
M3Result res = m3_CallArgv(m_func, sizeof...(args), argv);
detail::check_error(res);
Ret ret;
/* FIXME: there should be a public API to get the return value */
auto sp = (detail::stack_type) m_runtime->stack;
detail::arg_from_stack(ret, sp, nullptr);
res = m3_GetResults(m_func, 1, &ret);
detail::check_error(res);
return ret;
}
/**
* Call the function with the provided arguments (int/float types).
*
* WASM3 only accepts string arguments when calling WASM functions, and automatically converts them
* into the correct type based on the called function signature.
*
* This function provides a way to pass integer/float types, by first converting them to strings,
* and then letting WASM3 do the reverse conversion. This is to be fixed once WASM3 gains an equivalent
* of m3_CallArgv which can accept arbitrary types, not just strings.
*
* Note that the type of the return value must be explicitly specified as a template argument.
*
* @return the return value of the function.
*/
template<typename Ret, typename ... Args>
Ret call(Args... args) {
std::string argv_str[] = {std::to_string(args)...};
const char* argv[sizeof...(Args)];
for (size_t i = 0; i < sizeof...(Args); ++i) {
argv[i] = argv_str[i].c_str();
}
M3Result res = m3_CallArgv(m_func, sizeof...(args), argv);
const void *arg_ptrs[] = { reinterpret_cast<const void*>(&args)... };
M3Result res = m3_Call(m_func, sizeof...(args), arg_ptrs);
detail::check_error(res);
Ret ret;
/* FIXME: there should be a public API to get the return value */
auto sp = (detail::stack_type) m_runtime->stack;
detail::arg_from_stack(ret, sp, nullptr);
const void* ret_ptrs[] = { &ret };
res = m3_GetResults(m_func, 1, ret_ptrs);
detail::check_error(res);
return ret;
}

Loading…
Cancel
Save