diff --git a/cmake/ProjectWasm3.cmake b/cmake/ProjectWasm3.cmake index 079eefd18..cb7ae6a43 100644 --- a/cmake/ProjectWasm3.cmake +++ b/cmake/ProjectWasm3.cmake @@ -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= -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} ) diff --git a/cmake/wasm3_01_extapi.patch b/cmake/wasm3_01_extapi.patch deleted file mode 100644 index fa73899bf..000000000 --- a/cmake/wasm3_01_extapi.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff --git a/source/m3_env.c b/source/m3_env.c -index 40ccf9b..bad855f 100644 ---- a/source/m3_env.c -+++ b/source/m3_env.c -@@ -810,6 +810,58 @@ _ ((M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memo - _catch: return result; - } - -+M3Result m3_CallProper (IM3Function i_function, uint32_t i_argc, const uint64_t* i_argv, unsigned *o_hasRet, uint64_t* o_ret) -+{ -+ M3Result result = m3Err_none; -+ -+ if (i_function->compiled) -+ { -+ IM3Module module = i_function->module; -+ -+ IM3Runtime runtime = module->runtime; -+ // FIXME: support wasi? -+ -+ IM3FuncType ftype = i_function->funcType; -+ -+ if (i_argc != ftype->numArgs) { -+ _throw("arguments count mismatch"); -+ } -+ -+ // args are always 64-bit aligned -+ u64 * stack = (u64 *) runtime->stack; -+ -+ for (u32 i = 0; i < ftype->numArgs; ++i) -+ { -+ stack[i] = i_argv[i]; -+ -+ switch (ftype->argTypes[i]) { -+ case c_m3Type_i32: -+ case c_m3Type_f32: -+ case c_m3Type_i64: -+ case c_m3Type_f64: break; -+ default: _throw("unknown argument type"); -+ } -+ } -+ -+ m3StackCheckInit(); -+_ ((M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memory.mallocated, d_m3OpDefaultArgs)); -+ -+ *o_hasRet = 1; -+ switch (ftype->returnType) { -+ case c_m3Type_none: *o_hasRet = 0; break; -+ case c_m3Type_i32: *o_ret = (uint64_t)(stack[0] & 0xffffffff); break; -+ case c_m3Type_i64: *o_ret = (uint64_t)stack[0]; break; -+ // FIXME: not sure what happens with f32 -+ case c_m3Type_f32: *o_ret = (uint64_t)(f32)stack[0]; break; -+ case c_m3Type_f64: *o_ret = (uint64_t)stack[0]; break; -+ default: _throw("unknown return type"); -+ } -+ } -+ else _throw (m3Err_missingCompiledCode); -+ -+ _catch: return result; -+} -+ - #if 0 - M3Result m3_CallMain (IM3Function i_function, uint32_t i_argc, const char * const * i_argv) - { -diff --git a/source/wasm3.h b/source/wasm3.h -index 0c2b7ef..ebba7f4 100644 ---- a/source/wasm3.h -+++ b/source/wasm3.h -@@ -217,6 +217,8 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow") - M3Result m3_Call (IM3Function i_function); - M3Result m3_CallWithArgs (IM3Function i_function, uint32_t i_argc, const char * const * i_argv); - -+ M3Result m3_CallProper (IM3Function i_function, uint32_t i_argc, const uint64_t* i_argv, unsigned *o_hasRet, uint64_t* o_ret); -+ - // IM3Functions are valid during the lifetime of the originating runtime - - void m3_GetErrorInfo (IM3Runtime i_runtime, M3ErrorInfo* info); diff --git a/cmake/wasm3_02_portable.patch b/cmake/wasm3_02_portable.patch deleted file mode 100644 index 0493431d1..000000000 --- a/cmake/wasm3_02_portable.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 1b263e5..aea4253 100755 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -1,5 +1,7 @@ - cmake_minimum_required(VERSION 3.11) - -+set(BUILD_PORTABLE "Build without machine specific optimisations" OFF) -+ - set(BUILD_WASI "uvwasi" CACHE STRING "WASI implementation") - set_property(CACHE BUILD_WASI PROPERTY STRINGS none simple uvwasi metawasi) - -@@ -149,7 +151,12 @@ else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=shadow") - endif() - -- set(CMAKE_C_FLAGS_RELEASE "-O3 -march=native -Wfatal-errors -fomit-frame-pointer -fno-stack-check -fno-stack-protector") #-fno-inline -+ set(CMAKE_C_FLAGS_RELEASE "-O3 -Wfatal-errors -fomit-frame-pointer -fno-stack-check -fno-stack-protector") #-fno-inline -+ -+ if(NOT BUILD_PORTABLE) -+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -march=native") -+ endif() -+ - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-O0") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-O3") - diff --git a/cmake/wasm3_03_startfunc.patch b/cmake/wasm3_03_startfunc.patch deleted file mode 100644 index 9831b269c..000000000 --- a/cmake/wasm3_03_startfunc.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/source/m3_env.c b/source/m3_env.c -index 9292006..73628f4 100644 ---- a/source/m3_env.c -+++ b/source/m3_env.c -@@ -638,7 +638,14 @@ M3Result InitStartFunc (IM3Module io_module) - _ (Compile_Function (function)); - } - --_ (m3_Call(function)); -+ IM3FuncType ftype = function->funcType; -+ if (ftype->numArgs != 0 || ftype->returnType != c_m3Type_none) -+ _throw (m3Err_argumentCountMismatch); -+ -+ IM3Module module = function->module; -+ IM3Runtime runtime = module->runtime; -+ -+_ ((M3Result) Call (function->compiled, runtime->stack, runtime->memory.mallocated, d_m3OpDefaultArgs)); - } - - _catch: return result; diff --git a/test/unittests/wasm_engine_test.cpp b/test/unittests/wasm_engine_test.cpp index 0f517e3b2..25eb005c9 100644 --- a/test/unittests/wasm_engine_test.cpp +++ b/test/unittests/wasm_engine_test.cpp @@ -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)); @@ -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)); diff --git a/test/utils/wasm3_engine.cpp b/test/utils/wasm3_engine.cpp index da93356f1..efeb7a32b 100644 --- a/test/utils/wasm3_engine.cpp +++ b/test/utils/wasm3_engine.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace fizzy::test { @@ -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( + IM3Runtime /*runtime*/, IM3ImportContext /*context*/, uint64_t* stack, void* mem) noexcept { - const uint32_t offset = static_cast(stack[0]); - const uint32_t length = static_cast(stack[1]); + const uint32_t offset = static_cast(stack[1]); + const uint32_t length = static_cast(stack[2]); stack[0] = fizzy::test::adler32({reinterpret_cast(mem) + offset, length}); return m3Err_none; } @@ -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); 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; } bool Wasm3Engine::init_memory(fizzy::bytes_view memory) @@ -111,24 +116,54 @@ fizzy::bytes_view Wasm3Engine::get_memory() const } std::optional 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(function); - return std::nullopt; + if (m3_FindFunction(&function, m_runtime, name.data()) != m3Err_none) + return std::nullopt; + + const auto [inputs, outputs] = translate_function_signature(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(function); } WasmEngine::Result Wasm3Engine::execute( WasmEngine::FuncRef func_ref, const std::vector& args) { - unsigned ret_valid; - uint64_t ret_value; auto function = reinterpret_cast(func_ref); // NOLINT(performance-no-int-to-ptr) - auto const result = m3_CallProper( - function, static_cast(args.size()), args.data(), &ret_valid, &ret_value); - if (result == m3Err_none) - return {false, ret_valid ? ret_value : std::optional{}}; + + 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(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