Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
host_function.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <sysio/vm/allocator.hpp>
4#include <sysio/vm/execution_interface.hpp>
5#include <sysio/vm/function_traits.hpp>
6#include <sysio/vm/argument_proxy.hpp>
7#include <sysio/vm/span.hpp>
8#include <sysio/vm/utils.hpp>
9#include <sysio/vm/wasm_stack.hpp>
10
11#include <cstddef>
12#include <cstdint>
13#include <functional>
14#include <limits>
15#include <memory>
16#include <optional>
17#include <string>
18#include <tuple>
19#include <type_traits>
20#include <unordered_map>
21#include <utility>
22#include <vector>
23
24namespace sysio { namespace vm {
25 // types for host functions to use
26 typedef std::nullptr_t standalone_function_t;
27 struct no_match_t {};
28 struct invoke_on_all_t {};
29
30 template <typename Host_Type=standalone_function_t, typename Execution_Interface=execution_interface>
33 inline explicit running_context(Host_Type* host, const Execution_Interface& ei) : host(host), interface(ei) {}
34 inline explicit running_context(Host_Type* host, Execution_Interface&& ei) : host(host), interface(ei) {}
35
36 inline void* access(wasm_ptr_t addr=0) const { return (char*)interface.get_memory() + addr; }
37
38 inline Execution_Interface& get_interface() { return interface; }
39 inline const Execution_Interface& get_interface() const { return interface; }
40
41 inline decltype(auto) get_host() { return *host; }
42
43 template <typename T, typename U>
44 inline auto validate_pointer(U ptr, wasm_size_t len) const {
45 return get_interface().template validate_pointer<T>(ptr, len);
46 }
47
48 template<typename T>
49 inline auto validate_null_terminated_pointer(T ptr) const {
50 return get_interface().validate_null_terminated_pointer(ptr);
51 }
52
53 Host_Type* host;
54 Execution_Interface interface;
55 };
56
57 // Used to prevent base class overloads of from_wasm from being hidden.
58 template<typename T>
59 struct tag {};
60
61#define SYS_VM_FROM_WASM_ADD_TAG(...) (__VA_ARGS__, ::sysio::vm::tag<T> = {})
62
63#define SYS_VM_FROM_WASM(TYPE, PARAMS) \
64 template <typename T> \
65 auto from_wasm SYS_VM_FROM_WASM_ADD_TAG PARAMS const -> std::enable_if_t<std::is_same_v<T, TYPE>, TYPE>
66
67 template <typename Host, typename Execution_Interface=execution_interface>
68 struct type_converter : public running_context<Host, Execution_Interface> {
72
73 // TODO clean this up and figure out a more elegant way to get this for the macro
75
76 SYS_VM_FROM_WASM(bool, (uint32_t value)) { return value ? 1 : 0; }
77 uint32_t to_wasm(bool&& value) { return value ? 1 : 0; }
78 template<typename T>
80
81 template <typename T>
82 auto from_wasm(wasm_ptr_t ptr, wasm_size_t len, tag<T> = {}) const
83 -> std::enable_if_t<is_span_type_v<T>, T> {
84 auto p = this->template validate_pointer<typename T::value_type>(ptr, len);
85 return {static_cast<typename T::pointer>(p), len};
86 }
87
88 template <typename T>
89 auto from_wasm(wasm_ptr_t ptr, wasm_size_t len, tag<T> = {}) const
90 -> std::enable_if_t< is_argument_proxy_type_v<T> &&
91 is_span_type_v<typename T::proxy_type>, T> {
92 auto p = this->template validate_pointer<typename T::pointee_type>(ptr, len);
93 return {p, len};
94 }
95
96 template <typename T>
97 auto from_wasm(wasm_ptr_t ptr, tag<T> = {}) const
98 -> std::enable_if_t< is_argument_proxy_type_v<T> &&
99 std::is_pointer_v<typename T::proxy_type>, T> {
100 auto p = this->template validate_pointer<typename T::pointee_type>(ptr, 1);
101 return {p};
102 }
103
104 template<typename T>
105 inline decltype(auto) as_value(const elem_type& val) const {
106 if constexpr (std::is_integral_v<T> && sizeof(T) == 4)
107 return static_cast<T>(val.template get<i32_const_t>().data.ui);
108 else if constexpr (std::is_integral_v<T> && sizeof(T) == 8)
109 return static_cast<T>(val.template get<i64_const_t>().data.ui);
110 else if constexpr (std::is_floating_point_v<T> && sizeof(T) == 4)
111 return static_cast<T>(val.template get<f32_const_t>().data.f);
112 else if constexpr (std::is_floating_point_v<T> && sizeof(T) == 8)
113 return static_cast<T>(val.template get<f64_const_t>().data.f);
114 else if constexpr (std::is_void_v<std::decay_t<std::remove_pointer_t<T>>>)
115 return base_type::access(val.template get<i32_const_t>().data.ui);
116 else
117 return no_match_t{};
118 }
119
120 template <typename T>
121 inline constexpr auto as_result(T&& val) const {
122 if constexpr (std::is_integral_v<T> && sizeof(T) == 4)
123 return i32_const_t{ static_cast<uint32_t>(val) };
124 else if constexpr (std::is_integral_v<T> && sizeof(T) == 8)
125 return i64_const_t{ static_cast<uint64_t>(val) };
126 else if constexpr (std::is_floating_point_v<T> && sizeof(T) == 4)
127 return f32_const_t{ static_cast<float>(val) };
128 else if constexpr (std::is_floating_point_v<T> && sizeof(T) == 8)
129 return f64_const_t{ static_cast<double>(val) };
130 else if constexpr (std::is_void_v<std::decay_t<std::remove_pointer_t<T>>>)
131 return i32_const_t{ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(val) -
132 reinterpret_cast<uintptr_t>(this->access())) };
133 else
134 return no_match_t{};
135 }
136 };
137
138 namespace detail {
139 template<typename T>
140 constexpr bool is_tag_v = false;
141 template<typename T>
142 constexpr bool is_tag_v<tag<T>> = true;
143
144 template<typename Tuple, std::size_t... N>
145 std::tuple<std::tuple_element_t<N, Tuple>...> tuple_select(std::index_sequence<N...>);
146
147 template<typename T>
148 using strip_tag = std::conditional_t<is_tag_v<std::tuple_element_t<std::tuple_size_v<T> - 1, T>>,
149 decltype(tuple_select<T>(std::make_index_sequence<std::tuple_size_v<T> - 1>())),
150 T>;
151
152 template <class TC, typename T>
154 template <class TC, typename T>
155 using to_wasm_type_deducer_t = decltype(std::declval<TC>().to_wasm(std::declval<T>()));
156
157 template <std::size_t N, typename Type_Converter>
158 inline constexpr const auto& pop_value(Type_Converter& tc) { return tc.get_interface().operand_from_back(N); }
159
160 template <typename S, typename Type_Converter>
161 constexpr bool has_as_value() {
162 return !std::is_same_v<no_match_t, std::decay_t<decltype(
163 std::declval<Type_Converter>().template as_value<S>(pop_value<0>(std::declval<Type_Converter&>())))>>;
164 }
165
166 template <typename S, typename Type_Converter>
167 constexpr bool has_as_result() {
168 return !std::is_same_v<no_match_t, std::decay_t<decltype(
169 std::declval<Type_Converter>().template as_result<S>(std::declval<S&&>()))>>;
170 }
171
172 template <typename T, class Type_Converter>
173 inline constexpr std::size_t value_operand_size() {
174 if constexpr (has_as_value<T, Type_Converter>())
175 return 1;
176 else
177 return std::tuple_size_v<from_wasm_type_deducer_t<Type_Converter, T>>;
178 }
179
180 template <typename T, class Type_Converter>
181 static inline constexpr std::size_t value_operand_size_v = value_operand_size<T, Type_Converter>();
182
183 template <typename Args, std::size_t I, class Type_Converter>
184 inline constexpr std::size_t total_operands() {
185 if constexpr (I >= std::tuple_size_v<Args>)
186 return 0;
187 else {
188 constexpr std::size_t sz = value_operand_size_v<std::tuple_element_t<I, Args>, Type_Converter>;
190 }
191 }
192
193 template <typename Args, class Type_Converter>
194 static inline constexpr std::size_t total_operands_v = total_operands<Args, 0, Type_Converter>();
195
196 template <typename S, typename Type_Converter>
197 constexpr inline static bool has_from_wasm_v = SYS_VM_HAS_TEMPLATE_MEMBER_TY(Type_Converter, from_wasm<S>);
198
199 template <typename S, typename Type_Converter>
200 constexpr inline static bool has_to_wasm_v =
201 !std::is_same_v<no_match_t, to_wasm_type_deducer_t<Type_Converter, S>>;
202
203 template <typename Args, typename S, std::size_t At, class Type_Converter, std::size_t... Is>
204 inline constexpr decltype(auto) create_value(Type_Converter& tc, std::index_sequence<Is...>) {
205 constexpr std::size_t offset = total_operands_v<Args, Type_Converter> - 1;
206 if constexpr (has_from_wasm_v<S, Type_Converter>) {
208 return tc.template from_wasm<S>(tc.template as_value<std::tuple_element_t<Is, arg_types>>(pop_value<offset - (At + Is)>(tc))...);
209 } else {
210 static_assert(has_as_value<S, Type_Converter>(), "no type conversion found for type, define a from_wasm for this type");
211 return tc.template as_value<S>(pop_value<offset - At>(tc));
212 }
213 }
214
215 template <typename S, typename Type_Converter>
216 inline constexpr std::size_t skip_amount() {
217 if constexpr (has_as_value<S, Type_Converter>()) {
218 return 1;
219 } else {
220 return std::tuple_size_v<from_wasm_type_deducer_t<Type_Converter, S>>;
221 }
222 }
223
224 template <typename Args, std::size_t At, std::size_t Skip_Amt, class Type_Converter>
225 inline constexpr auto get_values(Type_Converter& tc) {
226 if constexpr (At >= std::tuple_size_v<Args>)
227 return std::tuple<>{};
228 else {
229 using source_t = std::tuple_element_t<At, Args>;
230 constexpr std::size_t skip_amt = skip_amount<source_t, Type_Converter>();
231 using converted_t = decltype(create_value<Args, source_t, Skip_Amt>(tc, std::make_index_sequence<skip_amt>{}));
233 return std::tuple_cat(std::tuple<converted_t>(create_value<Args, source_t, Skip_Amt>(tc, std::make_index_sequence<skip_amt>{})),
234 std::move(tail));
235 }
236 }
237
238 template <typename Type_Converter, typename T>
239 constexpr auto resolve_result(Type_Converter& tc, T&& val) {
240 if constexpr (has_to_wasm_v<T, Type_Converter>) {
241 return tc.as_result(tc.to_wasm(static_cast<T&&>(val)));
242 } else {
243 return tc.as_result(static_cast<T&&>(val));
244 }
245 }
246
247 template <bool Once, std::size_t Cnt, typename T, typename F>
248 inline constexpr void invoke_on_impl(F&& fn) {
249 if constexpr (Once && Cnt == 0) {
250 std::invoke(fn);
251 }
252 }
253
254 template <bool Once, std::size_t Cnt, typename T, typename F, typename Arg, typename... Args>
255 inline constexpr void invoke_on_impl(F&& fn, const Arg& arg, const Args&... args) {
256 if constexpr (Once) {
257 if constexpr (Cnt == 0)
258 std::invoke(fn, arg, args...);
259 } else {
260 if constexpr (std::is_same_v<T, Arg> || std::is_same_v<T, invoke_on_all_t>)
261 std::invoke(fn, arg, args...);
262 invoke_on_impl<Once, Cnt+1, T>(std::forward<F>(fn), args...);
263 }
264 }
265
266 template <typename Precondition, typename Type_Converter, typename Args, std::size_t... Is>
267 inline static void precondition_runner(Type_Converter& ctx, const Args& args, std::index_sequence<Is...>) {
268 Precondition::condition(ctx, std::get<Is>(args)...);
269 }
270
271 template <std::size_t I, typename Preconditions, typename Type_Converter, typename Args>
272 inline static void preconditions_runner(Type_Converter& ctx, const Args& args) {
273 constexpr std::size_t args_size = std::tuple_size_v<Args>;
274 constexpr std::size_t preconds_size = std::tuple_size_v<Preconditions>;
275 if constexpr (I < preconds_size) {
276 precondition_runner<std::tuple_element_t<I, Preconditions>>(ctx, args, std::make_index_sequence<args_size>{});
277 preconditions_runner<I+1, Preconditions>(ctx, args);
278 }
279 }
280 } //ns detail
281
282 template <bool Once, typename T, typename F, typename... Args>
283 void invoke_on(F&& func, const Args&... args) {
284 detail::invoke_on_impl<Once, 0, T>(static_cast<F&&>(func), args...);
285 }
286
287#define SYS_VM_INVOKE_ON(TYPE, CONDITION) \
288 sysio::vm::invoke_on<false, TYPE>(CONDITION, args...);
289
290#define SYS_VM_INVOKE_ON_ALL(CONDITION) \
291 sysio::vm::invoke_on<false, sysio::vm::invoke_on_all_t>(CONDITION, args...);
292
293#define SYS_VM_INVOKE_ONCE(CONDITION) \
294 sysio::vm::invoke_on<true, sysio::vm::invoke_on_all_t>(CONDITION, args...);
295
296#define SYS_VM_PRECONDITION(NAME, ...) \
297 struct NAME { \
298 template <typename Type_Converter, typename... Args> \
299 inline static decltype(auto) condition(Type_Converter& ctx, const Args&... args) { \
300 __VA_ARGS__; \
301 } \
302 };
303
304 template <auto F, typename Preconditions, typename Type_Converter, typename Host, typename... Args>
305 decltype(auto) invoke_impl(Type_Converter& tc, Host* host, Args&&... args) {
306 if constexpr (std::is_same_v<Host, standalone_function_t>)
307 return std::invoke(F, static_cast<Args&&>(args)...);
308 else
309 return std::invoke(F, host, static_cast<Args&&>(args)...);
310 }
311
312 template <auto F, typename Preconditions, typename Host, typename Args, typename Type_Converter, std::size_t... Is>
313 decltype(auto) invoke_with_host_impl(Type_Converter& tc, Host* host, Args&& args, std::index_sequence<Is...>) {
314 detail::preconditions_runner<0, Preconditions>(tc, args);
315 return invoke_impl<F, Preconditions>(tc, host, std::get<Is>(static_cast<Args&&>(args))...);
316 }
317
318 template <auto F, typename Preconditions, typename Args, typename Type_Converter, typename Host, std::size_t... Is>
319 decltype(auto) invoke_with_host(Type_Converter& tc, Host* host, std::index_sequence<Is...>) {
320 constexpr std::size_t args_size = std::tuple_size_v<decltype(detail::get_values<Args, 0, 0>(tc))>;
321 return invoke_with_host_impl<F, Preconditions>(tc, host, detail::get_values<Args, 0, 0>(tc), std::make_index_sequence<args_size>{});
322 }
323
324 template<typename Type_Converter, typename T>
325 void maybe_push_result(Type_Converter& tc, T&& res, std::size_t trim_amt) {
326 if constexpr (!std::is_same_v<std::decay_t<T>, maybe_void_t>) {
327 tc.get_interface().trim_operands(trim_amt);
328 tc.get_interface().push_operand(detail::resolve_result(tc, static_cast<T&&>(res)));
329 } else {
330 tc.get_interface().trim_operands(trim_amt);
331 }
332 }
333
334 template <typename Cls, auto F, typename Preconditions, typename R, typename Args, typename Type_Converter, size_t... Is>
335 auto create_function(std::index_sequence<Is...>) {
336 return std::function<void(Cls*, Type_Converter& )>{ [](Cls* self, Type_Converter& tc) {
337 maybe_push_result(tc, (invoke_with_host<F, Preconditions, Args>(tc, self, std::index_sequence<Is...>{}), maybe_void),
338 detail::total_operands_v<Args, Type_Converter>);
339 }
340 };
341 }
342
343 template<typename T>
344 auto to_wasm_type();
345 template<>
346 constexpr auto to_wasm_type<i32_const_t>() { return types::i32; }
347 template<>
348 constexpr auto to_wasm_type<i64_const_t>() { return types::i64; }
349 template<>
350 constexpr auto to_wasm_type<f32_const_t>() { return types::f32; }
351 template<>
352 constexpr auto to_wasm_type<f64_const_t>() { return types::f64; }
353
354 template <typename TC, typename T>
356 template <typename TC>
357 constexpr auto to_wasm_type_v<TC, void> = types::ret_void;
358
360 std::vector<value_type> params;
361 std::vector<value_type> ret;
362 };
363
364 inline bool operator==(const host_function& lhs, const func_type& rhs) {
365 return lhs.params.size() == rhs.param_types.size() &&
366 std::equal(lhs.params.begin(), lhs.params.end(), rhs.param_types.raw()) &&
367 lhs.ret.size() == rhs.return_count &&
368 (lhs.ret.size() == 0 || lhs.ret[0] == rhs.return_type);
369 }
370 inline bool operator==(const func_type& lhs, const host_function& rhs) {
371 return rhs == lhs;
372 }
373
374 template<typename TC, typename Args, std::size_t... Is>
375 void get_args(value_type*& out, std::index_sequence<Is...>) {
377 }
378
379 template<typename Type_Converter, typename T>
380 void get_args(value_type*& out) {
381 if constexpr (detail::has_from_wasm_v<T, Type_Converter>) {
383 get_args<Type_Converter, args_tuple>(out, std::make_index_sequence<std::tuple_size_v<args_tuple>>());
384 } else {
386 }
387 }
388
389 template <typename Type_Converter, typename Ret, typename Args, std::size_t... Is>
390 host_function function_types_provider(std::index_sequence<Is...>) {
391 host_function hf;
392 hf.params.resize(detail::total_operands_v<Args, Type_Converter>);
393#if (defined(__GNUC__) && !defined(__clang__))
394#pragma GCC diagnostic push
395#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
396 value_type* iter = hf.params.data();
398# pragma GCC diagnostic pop
399#else
400 value_type* iter = hf.params.data();
402#endif
403 if constexpr (to_wasm_type_v<Type_Converter, Ret> != types::ret_void) {
405 }
406 return hf;
407 }
408
409 using host_func_pair = std::pair<std::string, std::string>;
410
412 template <class T, class U>
413 std::size_t operator()(const std::pair<T, U>& p) const {
414 return std::hash<T>()(p.first) ^ std::hash<U>()(p.second);
415 }
416 };
417
418 template <typename Cls, typename Execution_Interface=execution_interface, typename Type_Converter=type_converter<Cls, Execution_Interface>>
420 using host_type_t = Cls;
421 using execution_interface_t = Execution_Interface;
422 using type_converter_t = Type_Converter;
423
424 struct mappings {
425 std::unordered_map<host_func_pair, uint32_t, host_func_pair_hash> named_mapping;
426 std::vector<std::function<void(Cls*, Type_Converter&)>> functions;
427 std::vector<host_function> host_functions;
428 size_t current_index = 0;
429
430 template <auto F, typename R, typename Args, typename Preconditions>
431 void add_mapping(const std::string& mod, const std::string& name) {
432 named_mapping[{mod, name}] = current_index++;
433 functions.push_back(
435 std::make_index_sequence<std::tuple_size_v<Args>>()));
436 host_functions.push_back(
438 std::make_index_sequence<std::tuple_size_v<Args>>()));
439 }
440
441 static mappings& get() {
442 static mappings instance;
443 return instance;
444 }
445 };
446
447 template <auto Func, typename... Preconditions>
448 static void add(const std::string& mod, const std::string& name) {
450 using res = return_type_t<AUTO_PARAM_WORKAROUND(Func)>;
451 using preconditions = std::tuple<Preconditions...>;
452 mappings::get().template add_mapping<Func, res, args, preconditions>(mod, name);
453 }
454
455 template <typename Module>
456 static void resolve(Module& mod) {
457 auto& imports = mod.import_functions;
458 auto& current_mappings = mappings::get();
459 for (std::size_t i = 0; i < mod.imports.size(); i++) {
460 std::string mod_name =
461 std::string((char*)mod.imports[i].module_str.raw(), mod.imports[i].module_str.size());
462 std::string fn_name = std::string((char*)mod.imports[i].field_str.raw(), mod.imports[i].field_str.size());
463 SYS_VM_ASSERT(current_mappings.named_mapping.count({ mod_name, fn_name }), wasm_link_exception,
464 std::string("no mapping for imported function ") + fn_name);
465 imports[i] = current_mappings.named_mapping[{ mod_name, fn_name }];
466 const import_entry& entry = mod.imports[i];
467 SYS_VM_ASSERT(entry.kind == Function, wasm_link_exception, std::string("importing non-function ") + fn_name);
468 SYS_VM_ASSERT(current_mappings.host_functions[imports[i]] == mod.types[entry.type.func_t], wasm_link_exception, std::string("wrong type for imported function ") + fn_name);
469 }
470 }
471
472 void operator()(Cls* host, Execution_Interface ei, uint32_t index) {
473 const auto& _func = mappings::get().functions[index];
474 auto tc = Type_Converter{host, std::move(ei)};
475 std::invoke(_func, host, tc);
476 }
477 };
478}} // namespace sysio::vm
const mie::Vuint & p
Definition bn.cpp:27
std::tuple< std::tuple_element_t< N, Tuple >... > tuple_select(std::index_sequence< N... >)
std::conditional_t< is_tag_v< std::tuple_element_t< std::tuple_size_v< T > - 1, T > >, decltype(tuple_select< T >(std::make_index_sequence< std::tuple_size_v< T > - 1 >())), T > strip_tag
constexpr bool has_as_value()
constexpr const auto & pop_value(Type_Converter &tc)
decltype(std::declval< TC >().to_wasm(std::declval< T >())) to_wasm_type_deducer_t
constexpr std::size_t value_operand_size()
constexpr bool is_tag_v
constexpr void invoke_on_impl(F &&fn)
constexpr auto resolve_result(Type_Converter &tc, T &&val)
constexpr std::size_t total_operands()
constexpr std::size_t skip_amount()
constexpr decltype(auto) create_value(Type_Converter &tc, std::index_sequence< Is... >)
constexpr auto get_values(Type_Converter &tc)
strip_tag< flatten_parameters_t<&TC::template from_wasm< T > > > from_wasm_type_deducer_t
constexpr bool has_as_result()
decltype(return_type(AUTO_PARAM_WORKAROUND(FN))) return_type_t
uint8_t value_type
Definition types.hpp:24
constexpr auto to_wasm_type< i32_const_t >()
host_function function_types_provider(std::index_sequence< Is... >)
constexpr auto to_wasm_type_v< TC, void >
constexpr auto to_wasm_type< i64_const_t >()
void get_args(value_type *&out, std::index_sequence< Is... >)
@ Function
Definition types.hpp:22
bool operator==(const host_function &lhs, const func_type &rhs)
decltype(auto) invoke_with_host(Type_Converter &tc, Host *host, std::index_sequence< Is... >)
maybe_void_t maybe_void
Definition utils.hpp:82
std::nullptr_t standalone_function_t
std::uint32_t wasm_ptr_t
Definition types.hpp:149
decltype(flatten_parameters(AUTO_PARAM_WORKAROUND(FN))) flatten_parameters_t
constexpr auto to_wasm_type< f64_const_t >()
decltype(auto) invoke_impl(Type_Converter &tc, Host *host, Args &&... args)
decltype(auto) invoke_with_host_impl(Type_Converter &tc, Host *host, Args &&args, std::index_sequence< Is... >)
auto create_function(std::index_sequence< Is... >)
std::uint32_t wasm_size_t
Definition types.hpp:150
constexpr auto to_wasm_type_v
std::pair< std::string, std::string > host_func_pair
auto to_wasm_type()
constexpr auto to_wasm_type< f32_const_t >()
void maybe_push_result(Type_Converter &tc, T &&res, std::size_t trim_amt)
void invoke_on(F &&func, const Args &... args)
@ self
the connection is to itself
Definition protocol.hpp:48
#define value
Definition pkcs11.h:157
#define S(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
#define T(meth, val, expected)
schedule config_dir_name data_dir_name p2p_port http_port file_size name host(p2p_endpoint)) FC_REFLECT(tn_node_def
const int N
Definition quantize.cpp:54
_W64 unsigned int uintptr_t
Definition stdint.h:165
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
Immutable except for fc::from_variant.
Definition name.hpp:43
uint8_t return_count
Definition types.hpp:45
guarded_vector< value_type > param_types
Definition types.hpp:44
value_type return_type
Definition types.hpp:46
std::size_t operator()(const std::pair< T, U > &p) const
std::vector< value_type > params
std::vector< value_type > ret
Definition types.hpp:98
import_type type
Definition types.hpp:102
external_kind kind
Definition types.hpp:101
std::vector< std::function< void(Cls *, Type_Converter &)> > functions
std::unordered_map< host_func_pair, uint32_t, host_func_pair_hash > named_mapping
void add_mapping(const std::string &mod, const std::string &name)
void operator()(Cls *host, Execution_Interface ei, uint32_t index)
static void add(const std::string &mod, const std::string &name)
Execution_Interface & get_interface()
auto validate_null_terminated_pointer(T ptr) const
running_context(Host_Type *host, Execution_Interface &&ei)
auto validate_pointer(U ptr, wasm_size_t len) const
const Execution_Interface & get_interface() const
running_context(Host_Type *host, const Execution_Interface &ei)
Execution_Interface interface
void * access(wasm_ptr_t addr=0) const
constexpr auto as_result(T &&val) const
auto from_wasm(wasm_ptr_t ptr, wasm_size_t len, tag< T >={}) const -> std::enable_if_t< is_argument_proxy_type_v< T > &&is_span_type_v< typename T::proxy_type >, T >
uint32_t to_wasm(bool &&value)
SYS_VM_FROM_WASM(bool,(uint32_t value))
decltype(auto) as_value(const elem_type &val) const
auto from_wasm(wasm_ptr_t ptr, wasm_size_t len, tag< T >={}) const -> std::enable_if_t< is_span_type_v< T >, T >
auto from_wasm(wasm_ptr_t ptr, tag< T >={}) const -> std::enable_if_t< is_argument_proxy_type_v< T > &&std::is_pointer_v< typename T::proxy_type >, T >
no_match_t to_wasm(T &&)
#define SYS_VM_ASSERT(expr, exc_type, msg)
Definition exceptions.hpp:8
#define R
F _func
Definition sys-vm.cpp:43
#define SYS_VM_HAS_TEMPLATE_MEMBER_TY(TY, NAME)
#define AUTO_PARAM_WORKAROUND(X)
Definition dtoa.c:306
size_t len