Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update wasm3 to 0.5.0 #739

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
9 changes: 4 additions & 5 deletions cmake/ProjectWasm3.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,19 @@ endif()
ExternalProject_Add(wasm3
EXCLUDE_FROM_ALL 1
PREFIX ${prefix}
DOWNLOAD_NAME wasm3-v0.4.7.tar.gz
DOWNLOAD_NAME wasm3-v0.5.0.tar.gz
DOWNLOAD_DIR ${prefix}/downloads
SOURCE_DIR ${source_dir}
BINARY_DIR ${binary_dir}
URL https://github.com/wasm3/wasm3/archive/v0.4.7.tar.gz
URL_HASH SHA256=11e863a643f605d62a5276e342abb01a65d33d138d01ea0070622a3f78fa1bd5
PATCH_COMMAND ${CMAKE_CURRENT_LIST_DIR}/apply_patches.sh
URL https://github.com/wasm3/wasm3/archive/v0.5.0.tar.gz
URL_HASH SHA256=b778dd72ee2251f4fe9e2666ee3fe1c26f06f517c3ffce572416db067546536c
CMAKE_ARGS
${toolchain_file}
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DBUILD_WASI=none
-DBUILD_PORTABLE=ON
-DBUILD_NATIVE=OFF
INSTALL_COMMAND ""
BUILD_BYPRODUCTS ${wasm3_library}
)
Expand Down
76 changes: 0 additions & 76 deletions cmake/wasm3_01_extapi.patch

This file was deleted.

26 changes: 0 additions & 26 deletions cmake/wasm3_02_portable.patch

This file was deleted.

20 changes: 0 additions & 20 deletions cmake/wasm3_03_startfunc.patch

This file was deleted.

7 changes: 3 additions & 4 deletions test/unittests/wasm_engine_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ TEST(wasm_engine, find_function)
const auto wasm =
from_hex("0061736d0100000001080160037f7e7f017f03020100070801047465737400000a05010300000b");

// NOTE: only fizzy checks the signature
for (auto engine_create_fn : {create_fizzy_engine})
// NOTE: fizzy_c and wabt do not yet check signature
for (auto engine_create_fn : {create_fizzy_engine, create_wasm3_engine})
{
auto engine = engine_create_fn();
EXPECT_TRUE(engine->instantiate(wasm));
Expand Down Expand Up @@ -389,8 +389,7 @@ TEST(wasm_engine, start_with_host_function)
"0205030100010606017f0141000b071102066d656d6f72790200047465737400020801010a1c021500410041aa"
"aba9ad0536020041004120100024000b040023000b");

// wasm3 fails on this
for (auto engine_create_fn : {create_fizzy_engine, create_fizzy_c_engine, create_wabt_engine})
for (auto engine_create_fn : all_engines)
{
auto engine = engine_create_fn();
ASSERT_TRUE(engine->parse(wasm));
Expand Down
67 changes: 51 additions & 16 deletions test/utils/wasm3_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <test/utils/wasm_engine.hpp>
#include <cassert>
#include <cstring>
#include <stdexcept>

namespace fizzy::test
{
Expand Down Expand Up @@ -38,10 +39,11 @@ class Wasm3Engine final : public WasmEngine

namespace
{
const void* env_adler32(IM3Runtime /*runtime*/, uint64_t* stack, void* mem) noexcept
const void* env_adler32(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on https://github.com/wasm3/wasm3/blob/main/source/wasm3.h#L327-L340 this would be the correct way:

m3ApiRawFunction(env_adler32)
{
    (void)runtime;
    (void)_ctx;

    m3ApiReturnType (uint32_t)
    m3ApiGetArgMem  (const uint8_t*, offset)
    m3ApiGetArg     (uint32_t, length)

    // This would be the correct way, but it traps. Although the numbers seem to be correct.
    // mem + offset + length <= mem + m3_getMemorySize
    m3ApiCheckMem(offset, length);

    m3ApiReturn(fizzy::test::adler32({offset, length}));
}

See also an example wasi function: https://github.com/wasm3/wasm3/blob/main/source/m3_api_meta_wasi.c#L146

IM3Runtime /*runtime*/, IM3ImportContext /*context*/, uint64_t* stack, void* mem) noexcept
{
const uint32_t offset = static_cast<uint32_t>(stack[0]);
const uint32_t length = static_cast<uint32_t>(stack[1]);
const uint32_t offset = static_cast<uint32_t>(stack[1]);
const uint32_t length = static_cast<uint32_t>(stack[2]);
stack[0] = fizzy::test::adler32({reinterpret_cast<uint8_t*>(mem) + offset, length});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stack order has changed. Now the return value is on the bottom.

return m3Err_none;
}
Expand Down Expand Up @@ -83,12 +85,15 @@ bool Wasm3Engine::instantiate(bytes_view wasm_binary)
// Transfers ownership to runtime.
if (m3_LoadModule(m_runtime, module) != m3Err_none)
{
// NOTE: apparently m3_FreeModule isn't needed in neither the failure nor the success case
m3_FreeModule(module);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Only modules not loaded into a M3Runtime need to be freed. A module is considered unloaded if

// a. m3_LoadModule has not yet been called on that module. Or,
// b. m3_LoadModule returned a result.
void m3_FreeModule (IM3Module i_module);

Plus wasm3/wasm3#160 (comment)

return false;
}

auto ret = m3_LinkRawFunction(module, "env", "adler32", "i(ii)", env_adler32);
return ret == m3Err_none || ret == m3Err_functionLookupFailed;
const auto ret = m3_LinkRawFunction(module, "env", "adler32", "i(ii)", env_adler32);
if (ret != m3Err_none && ret != m3Err_functionLookupFailed)
return false;

return m3_RunStart(module) == m3Err_none;
axic marked this conversation as resolved.
Show resolved Hide resolved
}

bool Wasm3Engine::init_memory(fizzy::bytes_view memory)
Expand All @@ -111,24 +116,54 @@ fizzy::bytes_view Wasm3Engine::get_memory() const
}

std::optional<WasmEngine::FuncRef> Wasm3Engine::find_function(
std::string_view name, std::string_view) const
std::string_view name, std::string_view signature) const
{
IM3Function function;
if (m3_FindFunction(&function, m_runtime, name.data()) == m3Err_none)
return reinterpret_cast<WasmEngine::FuncRef>(function);
return std::nullopt;
if (m3_FindFunction(&function, m_runtime, name.data()) != m3Err_none)
return std::nullopt;

const auto [inputs, outputs] = translate_function_signature<M3ValueType,
M3ValueType::c_m3Type_i32, M3ValueType::c_m3Type_i64>(signature);

if (inputs.size() != m3_GetArgCount(function))
return std::nullopt;
for (unsigned i = 0; i < m3_GetArgCount(function); i++)
if (inputs[i] != m3_GetArgType(function, i))
return std::nullopt;

if (outputs.size() != m3_GetRetCount(function))
return std::nullopt;
for (unsigned i = 0; i < m3_GetRetCount(function); i++)
if (outputs[i] != m3_GetRetType(function, i))
return std::nullopt;

return reinterpret_cast<WasmEngine::FuncRef>(function);
}

WasmEngine::Result Wasm3Engine::execute(
WasmEngine::FuncRef func_ref, const std::vector<uint64_t>& args)
{
unsigned ret_valid;
uint64_t ret_value;
auto function = reinterpret_cast<IM3Function>(func_ref); // NOLINT(performance-no-int-to-ptr)
auto const result = m3_CallProper(
function, static_cast<uint32_t>(args.size()), args.data(), &ret_valid, &ret_value);
if (result == m3Err_none)
return {false, ret_valid ? ret_value : std::optional<uint64_t>{}};

if (args.size() > 32)
throw std::runtime_error{"Does not support more than 32 arguments"};
const void* argPtrs[32];
for (unsigned i = 0; i < args.size(); i++)
argPtrs[i] = &args[i];

// This ensures input count/type matches. For the return value we assume find_function did the
// validation.
if (m3_Call(function, static_cast<uint32_t>(args.size()), argPtrs) == m3Err_none)
{
if (m3_GetRetCount(function) == 0)
return {false, std::nullopt};

uint64_t ret_value = 0;
// This should not fail because we check GetRetCount.
[[maybe_unused]] const auto ret = m3_GetResultsV(function, &ret_value);
assert(ret == m3Err_none);
return {false, ret_value};
}
return {true, std::nullopt};
}
} // namespace fizzy::test