diff --git a/configure.py b/configure.py index 9b56a041c4b0..fc85ae303c29 100755 --- a/configure.py +++ b/configure.py @@ -1052,6 +1052,7 @@ def find_headers(repodir, excluded_dirs): 'service/raft/raft_group0.cc', 'direct_failure_detector/failure_detector.cc', 'service/raft/raft_group0_client.cc', + 'rust/wasmtime_bindings/src/lib.rs', ] + [Antlr3Grammar('cql3/Cql.g')] + [Thrift('interface/cassandra.thrift', 'Cassandra')] \ + scylla_raft_core ) @@ -1418,18 +1419,6 @@ def clang_inline_threshold(): for mode in modes: modes[mode]['cxxflags'] += f' -Wstack-usage={modes[mode]["stack-usage-threshold"]} -Wno-error=stack-usage=' -has_wasmtime = False - -if has_wasmtime: - if platform.machine() == 'aarch64': - print("wasmtime is temporarily not supported on aarch64. Ref: issue #9387") - has_wasmtime = False - else: - for mode in modes: - modes[mode]['cxxflags'] += ' -DSCYLLA_ENABLE_WASMTIME' -else: - print("wasmtime not found - WASM support will not be enabled in this build") - linker_flags = linker_flags(compiler=args.cxx) dbgflag = '-g -gz' if args.debuginfo else '' @@ -1747,8 +1736,6 @@ def configure_abseil(build_dir, mode, mode_config): maybe_static(args.staticboost, '-lboost_date_time -lboost_regex -licuuc -licui18n'), '-lxxhash', ]) -if has_wasmtime: - print("Found wasmtime dependency, linking with libwasmtime") if not args.staticboost: args.user_cflags += ' -DBOOST_TEST_DYN_LINK' @@ -1934,8 +1921,6 @@ def configure_abseil(build_dir, mode, mode_config): for src in srcs if src.endswith('.cc')] objs.append('$builddir/../utils/arch/powerpc/crc32-vpmsum/crc32.S') - if has_wasmtime: - objs.append('/usr/lib64/libwasmtime.a') has_thrift = False has_rust = False for dep in deps[binary]: diff --git a/lang/wasm.cc b/lang/wasm.cc index 933b593ea80f..9373e43826c7 100644 --- a/lang/wasm.cc +++ b/lang/wasm.cc @@ -6,8 +6,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifdef SCYLLA_ENABLE_WASMTIME - #include "wasm.hh" #include "wasm_instance_cache.hh" #include "concrete_types.hh" @@ -19,140 +17,54 @@ #include #include #include "seastarx.hh" +#include "rust/cxx.h" +#include "rust/wasmtime_bindings.hh" +#include static logging::logger wasm_logger("wasm"); namespace wasm { -context::context(wasm::engine* engine_ptr, std::string name, instance_cache* cache) : engine_ptr(engine_ptr), function_name(name), cache(cache) { +context::context(rust::Box* engine_ptr, std::string name, instance_cache* cache) : engine_ptr(engine_ptr), function_name(name), cache(cache) { } static constexpr size_t WASM_PAGE_SIZE = 64 * 1024; -static uint32_t get_abi(wasmtime::Instance& instance, wasmtime::Store& store, uint8_t* data) { - auto abi_export = instance.get(store, "_scylla_abi"); - if (!abi_export) { - throw wasm::exception(format("ABI version export not found - please export `_scylla_abi` in the wasm module")); - } - wasmtime::Global* abi_global = std::get_if(&*abi_export); - if (!abi_global) { - throw wasm::exception(format("Exported object {} is not a global", "_scylla_abi")); - } - wasmtime::Val abi_val = abi_global->get(store); - return seastar::read_le((char*)data + abi_val.i32()); -} - -static wasmtime::Func import_func(wasmtime::Instance& instance, wasmtime::Store& store, std::string_view name) { - auto func_export = instance.get(store, name); - if (func_export) { - wasmtime::Func* func = std::get_if(&*func_export); - if (!func) { - throw wasm::exception(format("Exported object {} is not a function", name)); - } - return std::move(*func); - } else { - throw wasm::exception(format("Function {} was not found in given wasm source code", name)); - } -} - -static wasmtime::Val call_func(wasmtime::Store& store, wasmtime::Func func, std::vector argv) { - auto result = func.call(store, argv); - if (!result) { - throw wasm::exception("Calling wasm function failed: " + result.err().message()); - } - std::vector result_vec = std::move(result).unwrap(); - if (result_vec.size() != 1) { - throw wasm::exception(format("Unexpected number of returned values: {} (expected: 1)", result_vec.size())); - } - return std::move(result_vec[0]); -} - -static void call_void_func(wasmtime::Store& store, wasmtime::Func func, std::vector argv) { - auto result = func.call(store, argv); - if (!result) { - throw wasm::exception("Calling wasm function failed: " + result.err().message()); - } - std::vector result_vec = std::move(result).unwrap(); - if (result_vec.size() != 0) { - throw wasm::exception(format("Unexpected number of returned values: {} (expected: 0)", result_vec.size())); - } -} - -static std::pair create_instance_and_func(context& ctx, wasmtime::Store& store) { - auto linker = wasmtime::Linker(ctx.engine_ptr->get()); - auto wasi_def = linker.define_wasi(); - if (!wasi_def) { - throw wasm::exception(format("Setting up wasi failed: {}", wasi_def.err().message())); - } - auto cfg = wasmtime::WasiConfig(); - auto set_cfg = store.context().set_wasi(std::move(cfg)); - if (!set_cfg) { - throw wasm::exception(format("Setting up wasi failed: {}", set_cfg.err().message())); - } - auto instance_res = linker.instantiate(store, *ctx.module); - if (!instance_res) { - throw wasm::exception(format("Creating a wasm runtime instance failed: {}", instance_res.err().message())); - } - auto instance = instance_res.unwrap(); - auto function_obj = instance.get(store, ctx.function_name); - if (!function_obj) { - throw wasm::exception(format("Function {} was not found in given wasm source code", ctx.function_name)); - } - wasmtime::Func* func = std::get_if(&*function_obj); - if (!func) { - throw wasm::exception(format("Exported object {} is not a function", ctx.function_name)); - } - return std::make_pair(std::move(instance), std::move(*func)); -} - -void compile(context& ctx, const std::vector& arg_names, std::string script) { - wasm_logger.debug("Compiling script {}", script); - auto module = wasmtime::Module::compile(ctx.engine_ptr->get(), script); - if (!module) { - throw wasm::exception(format("Compilation failed: {}", module.err().message())); - } - ctx.module = module.unwrap(); - // Create the instance and extract function definition for validation purposes only - wasmtime::Store store(ctx.engine_ptr->get()); - create_instance_and_func(ctx, store); -} - -static void init_abstract_arg(const abstract_type& t, const bytes_opt& param, std::vector& argv, wasmtime::Store& store, wasmtime::Instance& instance) { +static void init_abstract_arg(const abstract_type& t, const bytes_opt& param, wasmtime::ValVec& argv, wasmtime::Store& store, wasmtime::Instance& instance) { // set up exported memory's underlying buffer, // `memory` is required to be exported in the WebAssembly module - auto memory_export = instance.get(store, "memory"); - if (!memory_export) { - throw wasm::exception("memory export not found - please export `memory` in the wasm module"); - } - auto memory = std::get(*memory_export); - uint8_t* data = memory.data(store).data(); - size_t mem_size = memory.size(store) * WASM_PAGE_SIZE; - int32_t serialized_size = param ? param->size() : 0; - if (serialized_size > std::numeric_limits::max()) { + auto memory = wasmtime::get_memory(instance, store); + size_t mem_size = memory->size(store) * WASM_PAGE_SIZE; + if (param && param->size() > std::numeric_limits::max()) { throw wasm::exception(format("Serialized parameter is too large: {} > {}", param->size(), std::numeric_limits::max())); } - switch (uint32_t abi_ver = get_abi(instance, store, data)) { - case 1: { - auto grown = memory.grow(store, 1 + (sizeof(int32_t) + serialized_size - 1) / WASM_PAGE_SIZE); // for fitting serialized size + the buffer itself - if (!grown) { - throw wasm::exception(format("Failed to grow wasm memory to {}: {}", serialized_size, grown.err().message())); + int32_t serialized_size = param ? param->size() : 0; + if (param) { + switch (uint32_t abi_ver = wasmtime::get_abi(instance, store, *memory)) { + case 1: { + auto pre_grow = memory->grow(store, 1 + (serialized_size - 1) / WASM_PAGE_SIZE); + mem_size = pre_grow * WASM_PAGE_SIZE; + break; } - mem_size = std::move(grown).unwrap() * WASM_PAGE_SIZE; - break; - } - case 2: { - auto malloc_func = import_func(instance, store, "_scylla_malloc"); - import_func(instance, store, "_scylla_free"); - auto size = call_func(store, malloc_func, {int32_t(sizeof(int32_t) + serialized_size)}); - mem_size = size.i32(); - break; + case 2: { + auto malloc_func = wasmtime::create_func(instance, store, "_scylla_malloc"); + wasmtime::create_func(instance, store, "_scylla_free"); + auto argv = wasmtime::get_val_vec(); + argv->push_i32(serialized_size); + auto rets = wasmtime::get_val_vec(); + rets->push_i32(0); + + auto fut = wasmtime::get_func_future(store, *malloc_func, *argv, *rets); + while(!fut->resume()); + auto val = rets->pop_val(); + mem_size = val->i32(); + break; + } + default: + throw wasm::exception(format("ABI version {} not recognized", abi_ver)); } - default: - throw wasm::exception(format("ABI version {} not recognized", abi_ver)); - } - if (param) { // put the argument in wasm module's memory - std::memcpy(data + mem_size, param->data(), serialized_size); + std::memcpy(memory->data(store) + mem_size, param->data(), serialized_size); } else { // size of -1 means that the value is null serialized_size = -1; @@ -160,49 +72,42 @@ static void init_abstract_arg(const abstract_type& t, const bytes_opt& param, st // the size of the struct in top 32 bits and the place inside wasm memory where the struct is placed in the bottom 32 bits int64_t arg_combined = ((int64_t)serialized_size << 32) | mem_size; - argv.push_back(arg_combined); + argv.push_i64(arg_combined); } struct init_arg_visitor { const bytes_opt& param; - std::vector& argv; + wasmtime::ValVec& argv; wasmtime::Store& store; wasmtime::Instance& instance; void operator()(const boolean_type_impl&) { auto dv = boolean_type->deserialize(*param); - auto val = wasmtime::Val(int32_t(value_cast(dv))); - argv.push_back(std::move(val)); + argv.push_i32(int32_t(value_cast(dv))); } void operator()(const byte_type_impl&) { auto dv = byte_type->deserialize(*param); - auto val = wasmtime::Val(int32_t(value_cast(dv))); - argv.push_back(std::move(val)); + argv.push_i32(int32_t(value_cast(dv))); } void operator()(const short_type_impl&) { auto dv = short_type->deserialize(*param); - auto val = wasmtime::Val(int32_t(value_cast(dv))); - argv.push_back(std::move(val)); + argv.push_i32(int32_t(value_cast(dv))); } void operator()(const double_type_impl&) { auto dv = double_type->deserialize(*param); - auto val = wasmtime::Val(value_cast(dv)); - argv.push_back(std::move(val)); + argv.push_f64(value_cast(dv)); } void operator()(const float_type_impl&) { auto dv = float_type->deserialize(*param); - auto val = wasmtime::Val(value_cast(dv)); - argv.push_back(std::move(val)); + argv.push_f32(value_cast(dv)); } void operator()(const int32_type_impl&) { auto dv = int32_type->deserialize(*param); - auto val = wasmtime::Val(value_cast(dv)); - argv.push_back(std::move(val)); + argv.push_i32(value_cast(dv)); } void operator()(const long_type_impl&) { auto dv = long_type->deserialize(*param); - auto val = wasmtime::Val(value_cast(dv)); - argv.push_back(std::move(val)); + argv.push_i64(value_cast(dv)); } void operator()(const abstract_type& t) { @@ -215,7 +120,7 @@ struct init_arg_visitor { struct init_nullable_arg_visitor { const bytes_opt& param; - std::vector& argv; + wasmtime::ValVec& argv; wasmtime::Store& store; wasmtime::Instance& instance; @@ -261,12 +166,8 @@ struct from_val_visitor { bytes_opt operator()(const abstract_type& t) { expect_kind(wasmtime::ValKind::I64); - auto memory_export = instance.get(store, "memory"); - if (!memory_export) { - throw wasm::exception("memory export not found - please export `memory` in the wasm module"); - } - auto memory = std::get(*memory_export); - uint8_t* mem_base = memory.data(store).data(); + auto memory = wasmtime::get_memory(instance, store); + uint8_t* mem_base = memory->data(store); uint8_t* data = mem_base + (val.i64() & 0xffffffff); int32_t ret_size = val.i64() >> 32; if (ret_size == -1) { @@ -274,9 +175,13 @@ struct from_val_visitor { } bytes_opt ret = t.decompose(t.deserialize(bytes_view(reinterpret_cast(data), ret_size))); - if (get_abi(instance, store, mem_base) == 2) { - auto free_func = import_func(instance, store, "_scylla_free"); - call_void_func(store, free_func, {wasmtime::Val((int32_t)val.i64())}); + if (wasmtime::get_abi(instance, store, *memory) == 2) { + auto free_func = wasmtime::create_func(instance, store, "_scylla_free"); + auto argv = wasmtime::get_val_vec(); + argv->push_i32((int32_t)val.i64()); + auto rets = wasmtime::get_val_vec(); + auto free_fut = wasmtime::get_func_future(store, *free_func, *argv, *rets); + while(!free_fut->resume()); } return ret; @@ -290,8 +195,8 @@ struct from_val_visitor { "f32", "f64", "v128", - "externref", "funcref", + "externref", }; if (val.kind() != expected) { throw wasm::exception(format("Incorrect wasm value kind returned. Expected {}, got {}", kind_str[size_t(expected)], kind_str[size_t(val.kind())])); @@ -299,42 +204,51 @@ struct from_val_visitor { } }; +void compile(context& ctx, const std::vector& arg_names, std::string script) { + try { + ctx.module = wasmtime::create_module(**ctx.engine_ptr, rust::Str(script.data(), script.size())); + auto store = wasmtime::create_store(**ctx.engine_ptr); + auto inst = create_instance(**ctx.engine_ptr, **ctx.module, *store); + create_func(*inst, *store, ctx.function_name); + } catch (const rust::Error& e) { + throw wasm::exception(e.what()); + } +} seastar::future run_script(context& ctx, wasmtime::Store& store, wasmtime::Instance& instance, wasmtime::Func& func, const std::vector& arg_types, const std::vector& params, data_type return_type, bool allow_null_input) { wasm_logger.debug("Running function {}", ctx.function_name); - // Replenish the store with initial amount of fuel - auto added = store.context().add_fuel(ctx.engine_ptr->initial_fuel_amount()); - if (!added) { - co_await coroutine::return_exception(wasm::exception(added.err().message())); - } - std::vector argv; + rust::Box argv = wasmtime::get_val_vec(); for (size_t i = 0; i < arg_types.size(); ++i) { const abstract_type& type = *arg_types[i]; const bytes_opt& param = params[i]; // If nulls are allowed, each type will be passed indirectly // as a struct {bool is_null; int32_t serialized_size, char[] serialized_buf} if (allow_null_input) { - visit(type, init_nullable_arg_visitor{param, argv, store, instance}); + visit(type, init_nullable_arg_visitor{param, *argv, store, instance}); } else if (param) { - visit(type, init_arg_visitor{param, argv, store, instance}); + visit(type, init_arg_visitor{param, *argv, store, instance}); } else { co_await coroutine::return_exception(wasm::exception(format("Function {} cannot be called on null values", ctx.function_name))); } } - uint64_t fuel_before = *store.context().fuel_consumed(); - - auto result = func.call(store, argv); - - uint64_t consumed = *store.context().fuel_consumed() - fuel_before; - wasm_logger.debug("Consumed {} fuel units", consumed); - - if (!result) { - co_await coroutine::return_exception(wasm::instance_corrupting_exception("Calling wasm function failed: " + result.err().message())); - } - std::vector result_vec = std::move(result).unwrap(); - if (result_vec.size() != 1) { - co_await coroutine::return_exception(wasm::exception(format("Unexpected number of returned values: {} (expected: 1)", result_vec.size()))); + auto rets = wasmtime::get_val_vec(); + rets->push_i32(0); + + auto fut = wasmtime::get_func_future(store, func, *argv, *rets); + bool stop = false; + while (!stop) { + std::exception_ptr eptr; + try { + stop = fut->resume(); + } catch (const rust::Error& e) { + eptr = std::make_exception_ptr(wasm::instance_corrupting_exception(format("Calling wasm function failed: {}", e.what()))); + } + if (eptr) { + co_await coroutine::return_exception_ptr(eptr); + } + co_await coroutine::maybe_yield(); } + auto result = rets->pop_val(); // TODO: ABI for return values is experimental and subject to change in the future. // Currently, if a function is marked with `CALLED ON NULL INPUT` it is also capable @@ -352,16 +266,21 @@ seastar::future run_script(context& ctx, wasmtime::Store& store, wasm if (allow_null_input) { // Force calling the default method for abstract_type, which checks for nulls // and expects a serialized input - co_return from_val_visitor{result_vec[0], store, instance}(static_cast(*return_type)); + co_return from_val_visitor{*result, store, instance}(static_cast(*return_type)); } else { - co_return visit(*return_type, from_val_visitor{result_vec[0], store, instance}); + co_return visit(*return_type, from_val_visitor{*result, store, instance}); } } seastar::future run_script(context& ctx, const std::vector& arg_types, const std::vector& params, data_type return_type, bool allow_null_input) { - auto store = wasmtime::Store(ctx.engine_ptr->get()); - auto [instance, func] = create_instance_and_func(ctx, store); - return run_script(ctx, store, instance, func, arg_types, params, return_type, allow_null_input); + try { + auto store = wasmtime::create_store(**ctx.engine_ptr); + auto instance = wasmtime::create_instance(**ctx.engine_ptr, **ctx.module, *store); + auto func = wasmtime::create_func(*instance, *store, ctx.function_name); + return run_script(ctx, *store, *instance, *func, arg_types, params, return_type, allow_null_input); + } catch (const rust::Error& e) { + return make_exception_future(wasm::exception(e.what())); + } } seastar::future run_script(const db::functions::function_name& name, context& ctx, const std::vector& arg_types, const std::vector& params, data_type return_type, bool allow_null_input) { @@ -370,7 +289,7 @@ seastar::future run_script(const db::functions::function_name& name, bytes_opt ret; try { func_inst = ctx.cache->get(name, arg_types, ctx).get0(); - ret = wasm::run_script(ctx, func_inst->instance->store, func_inst->instance->instance, func_inst->instance->func, arg_types, params, return_type, allow_null_input).get0(); + ret = wasm::run_script(ctx, *func_inst->instance->store, *func_inst->instance->instance, *func_inst->instance->func, arg_types, params, return_type, allow_null_input).get0(); } catch (const wasm::instance_corrupting_exception& e) { func_inst->instance = std::nullopt; ex = std::current_exception(); @@ -384,5 +303,3 @@ seastar::future run_script(const db::functions::function_name& name, return make_ready_future(ret); } } - -#endif diff --git a/lang/wasm.hh b/lang/wasm.hh index cb54b80df0a0..ccab937b1d94 100644 --- a/lang/wasm.hh +++ b/lang/wasm.hh @@ -10,8 +10,8 @@ #include "types.hh" #include -#include "lang/wasm_engine.hh" #include "db/functions/function_name.hh" +#include "rust/wasmtime_bindings.hh" namespace wasm { @@ -30,15 +30,13 @@ struct instance_corrupting_exception : public exception { explicit instance_corrupting_exception(std::string_view msg) : exception(msg) {} }; -#ifdef SCYLLA_ENABLE_WASMTIME - struct context { - wasm::engine* engine_ptr; - std::optional module; + rust::Box* engine_ptr; + std::optional> module; std::string function_name; instance_cache* cache; - context(wasm::engine* engine_ptr, std::string name, instance_cache* cache); + context(rust::Box* engine_ptr, std::string name, instance_cache* cache); }; void compile(context& ctx, const std::vector& arg_names, std::string script); @@ -47,25 +45,4 @@ seastar::future run_script(context& ctx, const std::vector seastar::future run_script(const db::functions::function_name& name, context& ctx, const std::vector& arg_types, const std::vector& params, data_type return_type, bool allow_null_input); -#else - -struct context { - context(wasm::engine*, std::string, instance_cache*) { - throw wasm::exception("WASM support was not enabled during compilation!"); - } -}; - -inline void compile(context&, const std::vector&, std::string) { - throw wasm::exception("WASM support was not enabled during compilation!"); -} - -inline seastar::future run_script(context&, const std::vector&, const std::vector&, data_type, bool) { - throw wasm::exception("WASM support was not enabled during compilation!"); -} - -inline seastar::future run_script(const db::functions::function_name& name, context& ctx, const std::vector& arg_types, const std::vector& params, data_type return_type, bool allow_null_input) { - throw wasm::exception("WASM support was not enabled during compilation!"); -} -#endif - } diff --git a/lang/wasm_engine.hh b/lang/wasm_engine.hh deleted file mode 100644 index 480149002c91..000000000000 --- a/lang/wasm_engine.hh +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2021-present ScyllaDB - */ - -/* - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#pragma once - -#include -#include - -#ifdef SCYLLA_ENABLE_WASMTIME - -#include "wasmtime.hh" - -namespace wasm { - -// Fuel defines more or less how many bytecode instructions -// can be performed at once. Empirically, 20k units -// allow for considerably less than 0.5ms of preemption-free execution time. -// TODO: investigate other configuration variables. -// We're particularly interested in limiting resource usage -// and yielding in the middle of execution - which is possible -// in the original wasmtime implementation for Rust and tightly -// bound with its native async support, but not yet possible -// in wasmtime.hh binding at the time of this writing. -// It's highly probable that a more generic support for yielding -// can be contributed to wasmtime. -constexpr uint64_t default_initial_fuel_amount = 20*1024; - -class engine { - wasmtime::Engine _engine; - uint64_t _initial_fuel_amount; -public: - engine(uint64_t initial_fuel_amount = default_initial_fuel_amount) - : _engine(make_config()) - , _initial_fuel_amount(initial_fuel_amount) - {} - wasmtime::Engine& get() { return _engine; } - uint64_t initial_fuel_amount() { return _initial_fuel_amount; }; -private: - wasmtime::Config make_config() { - wasmtime::Config cfg; - cfg.consume_fuel(true); - return cfg; - } -}; - -} - -#else - -namespace wasm { -class engine {}; -} - -#endif diff --git a/lang/wasm_instance_cache.cc b/lang/wasm_instance_cache.cc index 28ff3d8d3f21..f6b1446a4115 100644 --- a/lang/wasm_instance_cache.cc +++ b/lang/wasm_instance_cache.cc @@ -6,8 +6,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -#ifdef SCYLLA_ENABLE_WASMTIME - #include "lang/wasm_instance_cache.hh" #include "seastar/core/metrics.hh" #include "seastar/core/scheduling.hh" @@ -49,37 +47,11 @@ instance_cache::instance_cache(size_t size, seastar::lowres_clock::duration time } wasm_instance instance_cache::load(wasm::context& ctx) { - auto store = wasmtime::Store(ctx.engine_ptr->get()); - auto linker = wasmtime::Linker(ctx.engine_ptr->get()); - auto wasi_def = linker.define_wasi(); - if (!wasi_def) { - throw wasm::exception(format("Setting up wasi failed: {}", wasi_def.err().message())); - } - auto cfg = wasmtime::WasiConfig(); - auto set_cfg = store.context().set_wasi(std::move(cfg)); - if (!set_cfg) { - throw wasm::exception(format("Setting up wasi failed: {}", set_cfg.err().message())); - } - auto instance_res = linker.instantiate(store, *ctx.module); - if (!instance_res) { - throw wasm::exception(format("Creating a wasm runtime instance failed: {}", instance_res.err().message())); - } - auto instance = instance_res.unwrap(); - auto function_obj = instance.get(store, ctx.function_name); - if (!function_obj) { - throw wasm::exception(format("Function {} was not found in given wasm source code", ctx.function_name)); - } - wasmtime::Func* func = std::get_if(&*function_obj); - if (!func) { - throw wasm::exception(format("Exported object {} is not a function", ctx.function_name)); - } - auto memory_export = instance.get(store, "memory"); - if (!memory_export) { - throw wasm::exception("memory export not found - please export `memory` in the wasm module"); - } - auto memory = std::get(*memory_export); - - return wasm::wasm_instance{.store=std::move(store), .instance=std::move(instance), .func=std::move(*func), .memory=std::move(memory)}; + auto store = wasmtime::create_store(**ctx.engine_ptr); + auto instance = wasmtime::create_instance(**ctx.engine_ptr, **ctx.module, *store); + auto func = wasmtime::create_func(*instance, *store, ctx.function_name); + auto memory = wasmtime::get_memory(*instance, *store); + return wasm_instance{.store=std::move(store), .instance=std::move(instance), .func=std::move(func), .memory=std::move(memory)}; } // lru must not be empty, and its elements must refer to entries in _cache @@ -100,7 +72,7 @@ void instance_cache::on_timer() noexcept { static uint32_t get_instance_size(wasm_instance& instance) { // reserve 1 wasm page for instance data other than the wasm memory - return WASM_PAGE_SIZE * (1 + instance.memory.size(instance.store)); + return WASM_PAGE_SIZE * (1 + instance.memory->size(*instance.store)); } seastar::future instance_cache::get(const db::functions::function_name& name, const std::vector& arg_types, wasm::context& ctx) { @@ -222,5 +194,3 @@ struct equal_to { }; } - -#endif diff --git a/lang/wasm_instance_cache.hh b/lang/wasm_instance_cache.hh index 8c93bffd1474..8bab5fcc9b28 100644 --- a/lang/wasm_instance_cache.hh +++ b/lang/wasm_instance_cache.hh @@ -8,30 +8,6 @@ #pragma once -#ifndef SCYLLA_ENABLE_WASMTIME - -#include -#include -#include "lang/wasm.hh" - -namespace wasm { - -struct instance_cache { - explicit instance_cache(size_t size, seastar::lowres_clock::duration timer_period) {} - - void remove(const db::functions::function_name& name, const std::vector& arg_types) { - throw wasm::exception("WASM support was not enabled during compilation!"); - } - - future<> stop() { - return seastar::make_ready_future<>(); - } -}; - -} - -#else - #include "db/functions/function_name.hh" #include #include @@ -41,15 +17,16 @@ struct instance_cache { #include #include #include "lang/wasm.hh" -#include "wasmtime.hh" +#include "rust/cxx.h" +#include "rust/wasmtime_bindings.hh" namespace wasm { struct wasm_instance { - wasmtime::Store store; - wasmtime::Instance instance; - wasmtime::Func func; - wasmtime::Memory memory; + rust::Box store; + rust::Box instance; + rust::Box func; + rust::Box memory; }; // For each UDF full name and a scheduling group, we store a wasmtime instance @@ -145,5 +122,3 @@ public: }; } - -#endif diff --git a/lang/wasmtime.hh b/lang/wasmtime.hh deleted file mode 100644 index a909eeae9341..000000000000 --- a/lang/wasmtime.hh +++ /dev/null @@ -1,2665 +0,0 @@ -/** - * Downloaded from https://github.com/bytecodealliance/wasmtime-cpp/blob/main/include/wasmtime.hh - * License: Apache License 2.0 - */ - -/** - * \mainpage - * - * This project is a C++ API for - * [Wasmtime](https://github.com/bytecodealliance/wasmtime). Support for the - * C++ API is exclusively built on the [C API of - * Wasmtime](https://docs.wasmtime.dev/c-api/), so the C++ support for this is - * simply a single header file. To use this header file, though, it must be - * combined with the header and binary of Wasmtime's C API. Note, though, that - * while this header is built on top of the `wasmtime.h` header file you should - * only need to use the contents of this header file to interact with Wasmtime. - * - * Examples can be [found - * online](https://github.com/bytecodealliance/wasmtime-cpp/tree/main/examples) - * and otherwise be sure to check out the - * [README](https://github.com/bytecodealliance/wasmtime-cpp/blob/main/README.md) - * for simple usage instructions. Otherwise you can dive right in to the - * reference documentation of \ref wasmtime.hh - * - * \example hello.cc - * \example gcd.cc - * \example linking.cc - * \example memory.cc - * \example interrupt.cc - * \example externref.cc - */ - -/** - * \file wasmtime.hh - */ - -#ifndef WASMTIME_HH -#define WASMTIME_HH - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __cpp_lib_span -#include -#endif - -#include "wasmtime.h" - -namespace wasmtime { - -#ifdef __cpp_lib_span - -/// \brief Alias to C++20 std::span when it is available -template -using Span = std::span; - -#else - -/// \brief Means number of elements determined at runtime -inline constexpr size_t dynamic_extent = - std::numeric_limits::max(); - -/** - * \brief Span class used when c++20 is not available - * @tparam T Type of data - * @tparam Extent Static size of data refered by Span class - */ -template class Span { -public: - /// \brief Type used to iterate over this span (a raw pointer) - using iterator = T *; - - /// \brief Constructor of Span class - Span(T *t, std::size_t n) : ptr_{t}, size_{n} {} - - /// \brief Constructor of Span class for containers - template