From a636ba8e1d8b57bce354db0e20b25d04658f8170 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 19 Jan 2026 08:19:16 +0100 Subject: [PATCH] Add optional Liftoff compiler support for V8 Signed-off-by: Matthieu MOREL --- include/proxy-wasm/v8.h | 11 +++++++ src/v8/v8.cc | 65 ++++++++++++++++++++++++++++++++++++++--- test/BUILD | 15 ++++++++++ test/v8_options_test.cc | 61 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 test/v8_options_test.cc diff --git a/include/proxy-wasm/v8.h b/include/proxy-wasm/v8.h index 73c91b956..448b1053d 100644 --- a/include/proxy-wasm/v8.h +++ b/include/proxy-wasm/v8.h @@ -21,6 +21,17 @@ namespace proxy_wasm { +// Enable or disable the Liftoff compiler for V8 WebAssembly. +// This function uses atomic operations internally but must be called before +// creating any V8 VMs to take effect. Calls after the first VM creation are +// silently ignored. +// +// @param enable when false (default), only TurboFan is used for eager compilation, +// which is beneficial for use cases where VMs are cloned to share compiled code. +// When true, Liftoff is enabled for faster startup time at the cost of +// potentially slower execution. +void setV8LiftoffEnabled(bool enable); + std::unique_ptr createV8Vm(); } // namespace proxy_wasm diff --git a/src/v8/v8.cc b/src/v8/v8.cc index f5a73b130..87aec6796 100644 --- a/src/v8/v8.cc +++ b/src/v8/v8.cc @@ -15,6 +15,7 @@ #include "include/proxy-wasm/v8.h" +#include #include #include #include @@ -38,19 +39,60 @@ namespace proxy_wasm { namespace v8 { +// Global configuration for V8 options. Must be set before the first VM is created. +// Using atomic for thread-safe read access during engine initialization. +static std::atomic g_enable_liftoff{false}; +static std::atomic g_engine_initialized{false}; + +// Builder class for constructing V8 command-line arguments. +class V8ArgsBuilder { +public: + V8ArgsBuilder() = default; + + V8ArgsBuilder &setMaxMemoryPages(uint32_t max_pages) { + max_memory_pages_ = max_pages; + return *this; + } + + V8ArgsBuilder &setLiftoffEnabled(bool enabled) { + liftoff_enabled_ = enabled; + return *this; + } + + std::string build() const { + std::string args = absl::StrFormat("--wasm_max_mem_pages=%u", max_memory_pages_); + + if (!liftoff_enabled_) { + args += " --no-liftoff"; + } + + return args; + } + +private: + uint32_t max_memory_pages_ = + PROXY_WASM_HOST_MAX_WASM_MEMORY_SIZE_BYTES / PROXY_WASM_HOST_WASM_MEMORY_PAGE_SIZE_BYTES; + bool liftoff_enabled_ = false; +}; + wasm::Engine *engine() { static std::once_flag init; static wasm::own engine; std::call_once(init, []() { - // Disable the Liftoff compiler to force optimized JIT up-front. - std::string args = absl::StrFormat("--wasm_max_mem_pages=%u --no-liftoff", - PROXY_WASM_HOST_MAX_WASM_MEMORY_SIZE_BYTES / - PROXY_WASM_HOST_WASM_MEMORY_PAGE_SIZE_BYTES); + // Build V8 command-line arguments using the builder pattern. + // When Liftoff is disabled (default), force optimized JIT up-front with TurboFan only. + // When enabled, allow Liftoff for faster startup time. + std::string args = V8ArgsBuilder() + .setMaxMemoryPages(PROXY_WASM_HOST_MAX_WASM_MEMORY_SIZE_BYTES / + PROXY_WASM_HOST_WASM_MEMORY_PAGE_SIZE_BYTES) + .setLiftoffEnabled(g_enable_liftoff.load(std::memory_order_acquire)) + .build(); ::v8::V8::SetFlagsFromString(args.c_str(), args.size()); ::v8::V8::EnableWebAssemblyTrapHandler(true); engine = wasm::Engine::make(); + g_engine_initialized.store(true, std::memory_order_release); }); return engine.get(); @@ -757,8 +799,23 @@ std::string V8::getFailMessage(std::string_view function_name, wasm::own createV8Vm() { return std::make_unique(); } } // namespace proxy_wasm diff --git a/test/BUILD b/test/BUILD index 97e70558a..c0413fe1a 100644 --- a/test/BUILD +++ b/test/BUILD @@ -223,6 +223,21 @@ cc_test( ], ) +cc_test( + name = "v8_options_test", + srcs = ["v8_options_test.cc"], + data = [ + "//test/test_data:abi_export.wasm", + ], + linkstatic = 1, + deps = [ + ":utility_lib", + "//:lib", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + cc_library( name = "utility_lib", testonly = True, diff --git a/test/v8_options_test.cc b/test/v8_options_test.cc new file mode 100644 index 000000000..dfb835833 --- /dev/null +++ b/test/v8_options_test.cc @@ -0,0 +1,61 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#if defined(PROXY_WASM_HOST_ENGINE_V8) + +#include +#include + +#include "include/proxy-wasm/v8.h" +#include "include/proxy-wasm/wasm_vm.h" +#include "test/utility.h" + +namespace proxy_wasm { +namespace { + +// Test that setV8LiftoffEnabled can be called before creating a VM. +// Note: This test cannot verify the actual V8 flags are set correctly +// since the V8 engine is initialized once per process. However, it +// verifies that the API works correctly. +TEST(V8LiftoffTest, EnableLiftoffBeforeVMCreation) { + // This should not crash or cause errors + setV8LiftoffEnabled(true); // Enable Liftoff + + auto vm = createV8Vm(); + ASSERT_NE(vm, nullptr); + vm->integration() = std::make_unique(); + + EXPECT_EQ(vm->getEngineName(), "v8"); +} + +// Test that VMs can be created with default options (Liftoff disabled). +TEST(V8LiftoffTest, DefaultOptionsDisableLiftoff) { + auto vm = createV8Vm(); + ASSERT_NE(vm, nullptr); + vm->integration() = std::make_unique(); + + EXPECT_EQ(vm->getEngineName(), "v8"); + + // Load and link a simple wasm module to verify functionality + auto source = readTestWasmFile("abi_export.wasm"); + ASSERT_TRUE(vm->load(source, {}, {})); + ASSERT_TRUE(vm->link("")); +} + +} // namespace +} // namespace proxy_wasm + +#endif // PROXY_WASM_HOST_ENGINE_V8