diff --git a/source/extensions/common/wasm/wavm/wavm.cc b/source/extensions/common/wasm/wavm/wavm.cc index 4d8ff4256be19..8f846f8cd4dcc 100644 --- a/source/extensions/common/wasm/wavm/wavm.cc +++ b/source/extensions/common/wasm/wavm/wavm.cc @@ -240,7 +240,6 @@ Wavm::~Wavm() { moduleInstance_ = nullptr; if (emscriptenInstance_) { emscriptenInstance_->env = nullptr; - emscriptenInstance_->asm2wasm = nullptr; emscriptenInstance_->global = nullptr; emscriptenInstance_->emscriptenMemory = nullptr; delete emscriptenInstance_; @@ -306,7 +305,6 @@ void Wavm::link(absl::string_view name, bool needs_emscripten) { if (needs_emscripten) { emscriptenInstance_ = Emscripten::instantiate(compartment_, irModule_); rootResolver.moduleNameToInstanceMap().set("env", emscriptenInstance_->env); - rootResolver.moduleNameToInstanceMap().set("asm2wasm", emscriptenInstance_->asm2wasm); } WAVM::Runtime::LinkResult linkResult = linkModule(irModule_, rootResolver); moduleInstance_ = instantiateModule(compartment_, module_, std::move(linkResult.resolvedImports), diff --git a/test/extensions/wasm/test_data/Makefile b/test/extensions/wasm/test_data/Makefile index d5bac2092441e..440fc49ef2877 100644 --- a/test/extensions/wasm/test_data/Makefile +++ b/test/extensions/wasm/test_data/Makefile @@ -1,5 +1,5 @@ NO_CONTEXT = true -all: logging.wasm bad_signature.wasm segv.wasm emscript.wasm +all: logging.wasm bad_signature.wasm segv.wasm emscript.wasm asm2wasm.wasm include ../../../../api/wasm/cpp/Makefile.base diff --git a/test/extensions/wasm/test_data/asm2wasm.cc b/test/extensions/wasm/test_data/asm2wasm.cc new file mode 100644 index 0000000000000..3a4c4372ef9dd --- /dev/null +++ b/test/extensions/wasm/test_data/asm2wasm.cc @@ -0,0 +1,19 @@ +// NOLINT(namespace-envoy) +#include + +#include + +#include "proxy_wasm_intrinsics.h" + +// Use global variables so the compiler cannot optimize the operations away. +int32_t i32a = 0; +int32_t i32b = 1; +double f64a = 0.0; +double f64b = 1.0; + +// Emscripten in some modes and versions would use functions from the asm2wasm module to implement +// these operations: int32_t % /, double conversion to int32_t and remainder(). +extern "C" EMSCRIPTEN_KEEPALIVE void proxy_onStart() { + logInfo(std::string("out ") + std::to_string(i32a / i32b) + " " + std::to_string(i32a % i32b) + + " " + std::to_string((int32_t)remainder(f64a, f64b))); +} diff --git a/test/extensions/wasm/wasm_test.cc b/test/extensions/wasm/wasm_test.cc index 458e4f74a85d6..b087dc1fe7ec9 100644 --- a/test/extensions/wasm/wasm_test.cc +++ b/test/extensions/wasm/wasm_test.cc @@ -156,6 +156,31 @@ TEST(WasmTest, IntrinsicGlobals) { wasm->start(); } +// The asm2wasm.wasm file uses operations which would require the asm2wasm Emscripten module *if* +// em++ is invoked with the trap mode "clamp". See +// https://emscripten.org/docs/compiling/WebAssembly.html This test demonstrates that the asm2wasm +// module is not required with the trap mode is set to "allow". Note: future WASM standards will +// change this behavior by providing non-trapping instructions, but in the mean time we support the +// default Emscripten behavior. +TEST(WasmTest, Asm2Wasm) { + Stats::IsolatedStoreImpl stats_store; + Api::ApiPtr api = Api::createApiForTest(stats_store); + Upstream::MockClusterManager cluster_manager; + Event::SimulatedTimeSystem time_system; + Event::DispatcherImpl dispatcher(time_system, *api); + auto wasm = std::make_shared("envoy.wasm.vm.wavm", "", "", + cluster_manager, dispatcher); + EXPECT_NE(wasm, nullptr); + const auto code = TestEnvironment::readFileToStringForTest(TestEnvironment::substitute( + "{{ test_rundir }}/test/extensions/wasm/test_data/asm2wasm.wasm")); + EXPECT_FALSE(code.empty()); + auto context = std::make_unique(wasm.get()); + EXPECT_CALL(*context, scriptLog(spdlog::level::info, Eq("out 0 0 0"))); + EXPECT_TRUE(wasm->initialize(code, "", false)); + wasm->setGeneralContext(std::move(context)); + wasm->start(); +} + } // namespace Wasm } // namespace Extensions } // namespace Envoy