3#include <sysio/vm/allocator.hpp>
4#include <sysio/vm/constants.hpp>
5#include <sysio/vm/exceptions.hpp>
6#include <sysio/vm/execution_interface.hpp>
7#include <sysio/vm/host_function.hpp>
8#include <sysio/vm/opcodes.hpp>
9#include <sysio/vm/signals.hpp>
10#include <sysio/vm/types.hpp>
11#include <sysio/vm/utils.hpp>
12#include <sysio/vm/wasm_stack.hpp>
24#include <system_error>
30#define _XOPEN_SOURCE 700
35namespace sysio {
namespace vm {
38 template<
typename...
A>
41 "Should never get here because it's impossible to link a module "
42 "that imports any host functions, when no host functions are available");
47 template <
typename HostFunctions>
49 using type =
typename HostFunctions::host_type_t;
53 using type = std::nullptr_t;
56 template <
typename HF>
59 template <
typename HostFunctions>
61 using type =
typename HostFunctions::type_converter_t;
68 template <
typename HF>
71 template <
typename HostFunctions>
73 using type = HostFunctions;
79 template <
typename HF>
83 template<
typename Derived,
typename Host>
87 Derived&
derived() {
return static_cast<Derived&
>(*this); }
106 inline void exit(std::error_code err = std::error_code()) {
109 throw wasm_exit_exception{
"Exiting"};
112 inline module& get_module() { return _mod; }
124 SYS_VM_ASSERT(_mod.error ==
nullptr, wasm_interpreter_exception, _mod.error);
126 _linear_memory = _wasm_alloc->get_base_ptr<
char>();
127 if(_mod.memories.size()) {
128 SYS_VM_ASSERT(_mod.memories[0].limits.initial <= _max_pages, wasm_bad_alloc,
"Cannot allocate initial linear memory.");
129 _wasm_alloc->reset(_mod.memories[0].limits.initial);
131 _wasm_alloc->reset();
133 for (
uint32_t i = 0; i < _mod.data.size(); i++) {
134 const auto& data_seg = _mod.data[i];
135 uint32_t offset = data_seg.offset.value.i32;
136 auto available_memory = _mod.memories[0].limits.initial *
static_cast<uint64_t>(
page_size);
137 auto required_memory =
static_cast<uint64_t>(offset) + data_seg.data.size();
138 SYS_VM_ASSERT(required_memory <= available_memory, wasm_memory_exception,
"data out of range");
139 auto addr = _linear_memory + offset;
140 memcpy((
char*)(addr), data_seg.data.raw(), data_seg.data.size());
144 for (
uint32_t i = 0; i < _mod.globals.size(); i++) {
145 if (_mod.globals[i].type.mutability)
146 _mod.globals[i].current = _mod.globals[i].init;
150 template <
typename Visitor,
typename... Args>
151 inline std::optional<operand_stack_elem>
execute(host_type* host, Visitor&&
visitor,
const std::string_view
func,
154 return derived().execute(host, std::forward<Visitor>(
visitor), func_index, std::forward<Args>(args)...);
157 template <
typename Visitor,
typename... Args>
159 if (_mod.start != std::numeric_limits<uint32_t>::max())
160 derived().execute(host, std::forward<Visitor>(
visitor), _mod.start);
165 template<
typename... Args>
182 throw wasm_memory_exception{
"wasm memory out-of-bounds" };
185 char* _linear_memory =
nullptr;
190 std::error_code _error_code;
196 template<
typename Host>
203 template<
bool EnableBacktrace>
207 void*
volatile _bottom_frame =
nullptr;
208 void*
volatile _top_frame =
nullptr;
211 template<
typename Host,
bool EnableBacktrace = false>
216 using base_type::execute;
217 using base_type::base_type;
218 using base_type::_mod;
219 using base_type::_rhf;
220 using base_type::_error_code;
221 using base_type::handle_signal;
222 using base_type::get_operand_stack;
223 using base_type::linear_memory;
224 using base_type::get_interface;
233 const auto& ft = _mod.get_function_type(index);
234 uint32_t num_params = ft.param_types.size();
236 uint32_t original_operands = get_operand_stack().size();
238 for(
uint32_t i = 0; i < ft.param_types.size(); ++i) {
239 switch(ft.param_types[i]) {
240 case i32: get_operand_stack().push(i32_const_t{
stack[num_params - i - 1].i32});
break;
241 case i64: get_operand_stack().push(i64_const_t{
stack[num_params - i - 1].i64});
break;
242 case f32: get_operand_stack().push(f32_const_t{
stack[num_params - i - 1].f32});
break;
243 case f64: get_operand_stack().push(f64_const_t{
stack[num_params - i - 1].f64});
break;
244 default: assert(!
"Unexpected type in param_types.");
247 _rhf(_host, get_interface(), _mod.import_functions[index]);
250 auto set_result = [&result](
auto val) { std::memcpy(&result, &val,
sizeof(val)); };
251 if(ft.return_count) {
253 switch(ft.return_type) {
254 case i32: set_result(el.
to_ui32());
break;
255 case i64: set_result(el.
to_ui64());
break;
256 case f32: set_result(el.
to_f32());
break;
257 case f64: set_result(el.
to_f64());
break;
258 default: assert(!
"Unexpected function return type.");
262 assert(get_operand_stack().size() == original_operands);
268 get_operand_stack().eat(0);
271 template <
typename... Args>
273 auto saved_host = _host;
274 auto saved_os_size = get_operand_stack().size();
275 auto g =
scope_guard([&](){ _host = saved_host; get_operand_stack().eat(saved_os_size); });
279 const func_type& ft = _mod.get_function_type(func_index);
280 this->type_check_args(ft,
static_cast<Args&&
>(args)...);
282 native_value args_raw[] = { transform_arg(
static_cast<Args&&
>(args))... };
285 if (func_index < _mod.get_imported_functions_size()) {
286 std::reverse(args_raw + 0, args_raw +
sizeof...(Args));
287 result = call_host_function(args_raw, func_index);
289 std::size_t maximum_stack_usage =
290 (_mod.maximum_stack + 2 ) * (_remaining_call_depth + 1) +
291 sizeof...(Args) + 4 ;
298 auto fn =
reinterpret_cast<native_value (*)(
void*,
void*)
>(_mod.code[func_index - _mod.get_imported_functions_size()].jit_code_offset + _mod.allocator._code_base);
300 if constexpr(EnableBacktrace) {
302 sigemptyset(&block_mask);
303 sigaddset(&block_mask, SIGPROF);
304 pthread_sigmask(SIG_BLOCK, &block_mask, nullptr);
305 auto restore = scope_guard{[this, &block_mask] {
306 this->_top_frame = nullptr;
307 this->_bottom_frame = nullptr;
308 pthread_sigmask(SIG_UNBLOCK, &block_mask, nullptr);
311 vm::invoke_with_signal_handler([&]() {
312 result = execute<sizeof...(Args)>(args_raw, fn, this, base_type::linear_memory(), stack);
315 vm::invoke_with_signal_handler([&]() {
316 result = execute<
sizeof...(Args)>(args_raw, fn,
this, base_type::linear_memory(),
stack);
320 }
catch(wasm_exit_exception&) {
326 else switch (ft.return_type) {
327 case i32:
return {i32_const_t{result.i32}};
328 case i64:
return {i64_const_t{result.i64}};
329 case f32:
return {f32_const_t{result.f32}};
330 case f64:
return {f64_const_t{result.f64}};
331 default: assert(!
"Unexpected function return type");
333 __builtin_unreachable();
337 int backtrace(
void** out,
int count,
void* uc)
const {
338 static_assert(EnableBacktrace);
339 void* end = this->_top_frame;
340 if(end ==
nullptr)
return 0;
343 if(this->_bottom_frame) {
344 rbp = this->_bottom_frame;
345 }
else if(
count != 0) {
348 auto rip =
reinterpret_cast<unsigned char*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext->__ss.__rip);
349 rbp =
reinterpret_cast<void*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext->__ss.__rbp);
350 auto rsp =
reinterpret_cast<void*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext->__ss.__rsp);
351#elif defined __FreeBSD__
352 auto rip =
reinterpret_cast<unsigned char*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext.mc_rip);
353 rbp =
reinterpret_cast<void*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext.mc_rbp);
354 auto rsp =
reinterpret_cast<void*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext.mc_rsp);
356 auto rip =
reinterpret_cast<unsigned char*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext.gregs[REG_RIP]);
357 rbp =
reinterpret_cast<void*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext.gregs[REG_RBP]);
358 auto rsp =
reinterpret_cast<void*
>(
static_cast<ucontext_t*
>(uc)->uc_mcontext.gregs[REG_RSP]);
363 auto code_base =
reinterpret_cast<const unsigned char*
>(_mod.allocator.get_code_start());
364 auto code_end = code_base + _mod.allocator._code_size;
365 if(rip >= code_base && rip < code_end && count > 1) {
367 if(*
reinterpret_cast<const unsigned char*
>(rip) == 0x55) {
368 if(rip != *
static_cast<void**
>(rsp)) {
369 out[i++] = *
static_cast<void**
>(rsp);
371 }
else if(rip[0] == 0x48 && rip[1] == 0x89 && (rip[2] == 0xe5 || rip[2] == 0x27)) {
372 if((rip - 1) !=
static_cast<void**
>(rsp)[1]) {
373 out[i++] =
static_cast<void**
>(rsp)[1];
377 else if(rip[0] == 0xc3) {
378 out[i++] = *
static_cast<void**
>(rsp);
382 rbp = __builtin_frame_address(0);
386 void* rip =
static_cast<void**
>(rbp)[1];
387 if(rbp == end)
break;
389 rbp = *
static_cast<void**
>(rbp);
394 static constexpr bool async_backtrace() {
return EnableBacktrace; }
403 std::memset(&result, 0,
sizeof(result));
405 auto transformed_value = detail::resolve_result(tc,
static_cast<T&&
>(
value)).data;
406 std::memcpy(&result, &transformed_value,
sizeof(transformed_value));
414 static_assert(
sizeof(
native_value) == 8,
"8-bytes expected for native_value");
416 unsigned stack_check =
context->_remaining_call_depth;
419 register void* stack_top
asm (
"r12") =
stack;
421#define ASM_CODE(before, after) \
423 "test %[stack_top], %[stack_top]; " \
425 "mov %%rsp, %[stack_top]; " \
426 "sub $0x98, %%rsp; " \
427 "mov %[stack_top], (%%rsp); " \
430 "mov %%rsp, (%[stack_top]); " \
431 "mov %[stack_top], %%rsp; " \
433 "stmxcsr 16(%%rsp); " \
434 "mov $0x1f80, %%rax; " \
435 "mov %%rax, 8(%%rsp); " \
436 "ldmxcsr 8(%%rsp); " \
437 "mov %[Count], %%rax; " \
438 "test %%rax, %%rax; " \
441 "movq (%[data]), %%r8; " \
442 "lea 8(%[data]), %[data]; " \
450 "add %[StackOffset], %%rsp; " \
451 "ldmxcsr 16(%%rsp); " \
452 "mov (%%rsp), %%rsp; " \
454 : [result] "=&a" (result), \
455 [data] "+d" (data), [fun] "+c" (fun), [stack_top] "+r" (stack_top) \
456 : [context] "D" (context), [linear_memory] "S" (linear_memory), \
457 [StackOffset] "n" (Count*8), [Count] "n" (Count), "b" (stack_check) \
460 "r8", "r9", "r10", "r11", \
461 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", \
462 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", \
463 "mm0","mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm6", \
464 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)" \
466 if constexpr (!EnableBacktrace) {
469 ASM_CODE(
"movq %%rbp, 8(%[context]); ",
470 "xor %[fun], %[fun]; "
471 "mov %[fun], 8(%[context]); ");
478 host_type * _host =
nullptr;
482 template <
typename Host>
487 using base_type::_mod;
488 using base_type::_rhf;
489 using base_type::_error_code;
490 using base_type::handle_signal;
491 using base_type::get_operand_stack;
492 using base_type::linear_memory;
493 using base_type::get_interface;
500 static_assert(std::is_trivially_move_assignable_v<call_stack>,
"This is seriously broken if call_stack move assignment might use the existing memory");
502 if(mem_size > _base_allocator.mem_size) {
506 _base_allocator.index = 0;
513 if (index < _mod.get_imported_functions_size()) {
515 const auto& ft = _mod.types[_mod.imports[index].type.func_t];
519 _rhf(_state.host, get_interface(), _mod.import_functions[index]);
526 set_pc( _mod.get_function_pc(index) );
531 std::cout <<
"STACK { ";
532 for (
int i = 0; i < get_operand_stack().size(); i++) {
533 std::cout <<
"(" << i <<
")";
534 visit(
overloaded { [&](i32_const_t el) { std::cout <<
"i32:" << el.data.ui <<
", "; },
535 [&](i64_const_t el) { std::cout <<
"i64:" << el.data.ui <<
", "; },
536 [&](f32_const_t el) { std::cout <<
"f32:" << el.data.f <<
", "; },
537 [&](f64_const_t el) { std::cout <<
"f64:" << el.data.f <<
", "; },
538 [&](
auto el) { std::cout <<
"(INDEX " << el.index() <<
"), "; } }, get_operand_stack().get(i));
553 template <
bool Should_Exit=false>
556 if constexpr (!Should_Exit)
557 return_pc = _state.pc + 1;
560 _last_op_index = get_operand_stack().size() - _mod.get_function_type(index).param_types.size();
564 const auto& af = _as.pop();
566 _last_op_index = af.last_op_index;
568 compact_operand(get_operand_stack().size() - num_locals - 1);
570 eat_operands(get_operand_stack().size() - num_locals);
575 SYS_VM_ASSERT(index < _mod.globals.size(), wasm_interpreter_exception,
"global index out of range");
576 const auto& gl = _mod.globals[index];
577 switch (gl.type.content_type) {
578 case types::i32:
return i32_const_t{ *(
uint32_t*)&gl.current.value.i32 };
579 case types::i64:
return i64_const_t{ *(
uint64_t*)&gl.current.value.i64 };
580 case types::f32:
return f32_const_t{ gl.current.value.f32 };
581 case types::f64:
return f64_const_t{ gl.current.value.f64 };
582 default:
throw wasm_interpreter_exception{
"invalid global type" };
587 SYS_VM_ASSERT(index < _mod.globals.size(), wasm_interpreter_exception,
"global index out of range");
588 auto& gl = _mod.globals[index];
589 SYS_VM_ASSERT(gl.type.mutability, wasm_interpreter_exception,
"global is not mutable");
591 SYS_VM_ASSERT(gl.type.content_type == types::i32, wasm_interpreter_exception,
592 "expected i32 global type");
593 gl.current.value.i32 = i.data.ui;
595 [&](
const i64_const_t& i) {
596 SYS_VM_ASSERT(gl.type.content_type == types::i64, wasm_interpreter_exception,
597 "expected i64 global type");
598 gl.current.value.i64 = i.data.ui;
600 [&](
const f32_const_t&
f) {
601 SYS_VM_ASSERT(gl.type.content_type == types::f32, wasm_interpreter_exception,
602 "expected f32 global type");
603 gl.current.value.f32 =
f.data.ui;
605 [&](
const f64_const_t&
f) {
606 SYS_VM_ASSERT(gl.type.content_type == types::f64, wasm_interpreter_exception,
607 "expected f64 global type");
608 gl.current.value.f64 =
f.data.ui;
610 [](
auto) {
throw wasm_interpreter_exception{
"invalid global type" }; } },
615 bool ret_val =
false;
616 visit(
overloaded{ [&](
const i32_const_t& i32) { ret_val = i32.data.ui; },
617 [&](
auto) {
throw wasm_invalid_element{
"should be an i32 type" }; } },
624 const auto&
op = peek_operand((ft.
param_types.size() - 1) - i);
627 "function param type mismatch");
629 [&](
const f32_const_t&) {
631 "function param type mismatch");
633 [&](
const i64_const_t&) {
635 "function param type mismatch");
637 [&](
const f64_const_t&) {
639 "function param type mismatch");
641 [&](
auto) {
throw wasm_interpreter_exception{
"function param invalid type" }; } },
648 _state.pc = _mod.code[0].code + pc_offset;
652 inline void exit(std::error_code err = std::error_code()) {
655 _state.exiting =
true;
660 _state = execution_state{};
661 get_operand_stack().eat(_state.os_index);
662 _as.eat(_state.as_index);
665 template <
typename Visitor,
typename... Args>
668 return execute(host, std::forward<Visitor>(
visitor), table_elem(table_index), std::forward<Args>(args)...);
671 template <
typename Visitor,
typename... Args>
672 inline std::optional<operand_stack_elem>
execute(host_type* host, Visitor&&
visitor,
const std::string_view func,
675 return execute(host, std::forward<Visitor>(
visitor), func_index, std::forward<Args>(args)...);
678 template <
typename Visitor,
typename... Args>
680 if (_mod.start != std::numeric_limits<uint32_t>::max())
681 execute(host, std::forward<Visitor>(
visitor), _mod.start);
684 template <
typename Visitor,
typename... Args>
685 inline std::optional<operand_stack_elem>
execute(host_type* host, Visitor&&
visitor,
uint32_t func_index, Args... args) {
686 SYS_VM_ASSERT(func_index < std::numeric_limits<uint32_t>::max(), wasm_interpreter_exception,
687 "cannot execute function, function not found");
689 auto last_last_op_index = _last_op_index;
692 execution_state saved_state = _state;
695 _state.as_index = _as.size();
696 _state.os_index = get_operand_stack().size();
699 get_operand_stack().eat(_state.os_index);
700 _as.eat(_state.as_index);
701 _state = saved_state;
703 _last_op_index = last_last_op_index;
706 this->type_check_args(_mod.get_function_type(func_index),
static_cast<Args&&
>(args)...);
708 push_call<true>(func_index);
710 if (func_index < _mod.get_imported_functions_size()) {
711 _rhf(_state.host, get_interface(), _mod.import_functions[func_index]);
713 _state.pc = _mod.get_function_pc(func_index);
714 setup_locals(func_index);
715 vm::invoke_with_signal_handler([&]() {
720 if (_mod.get_function_type(func_index).return_count && !_state.exiting) {
721 return pop_operand();
728 set_relative_pc(new_pc);
729 if ((pop_info & 0x80000000u)) {
730 const auto&
op = pop_operand();
731 eat_operands(get_operand_stack().size() - ((pop_info & 0x7FFFFFFFu) - 1));
734 eat_operands(get_operand_stack().size() - pop_info);
743 data[out++] = _state.pc;
745 for(
int i = 0; out < limit && i < _as.size(); ++i) {
746 data[out++] = _as.get_back(i).pc;
753 template <
typename... Args>
754 void push_args(Args&&... args) {
757 (... , push_operand(detail::resolve_result(tc, std::move(args))));
760 inline void setup_locals(
uint32_t index) {
761 const auto& fn = _mod.code[index - _mod.get_imported_functions_size()];
762 for (
uint32_t i = 0; i < fn.locals.size(); i++) {
764 switch (fn.locals[i].type) {
765 case types::i32: push_operand(i32_const_t{ (
uint32_t)0 });
break;
766 case types::i64: push_operand(i64_const_t{ (
uint64_t)0 });
break;
767 case types::f32: push_operand(f32_const_t{ (
uint32_t)0 });
break;
768 case types::f64: push_operand(f64_const_t{ (
uint64_t)0 });
break;
769 default:
throw wasm_interpreter_exception{
"invalid function param type" };
774#define CREATE_TABLE_ENTRY(NAME, CODE) &&ev_label_##NAME,
775#define CREATE_LABEL(NAME, CODE) \
776 ev_label_##NAME : visitor(ev_variant->template get<sysio::vm::SYS_VM_OPCODE_T(NAME)>()); \
777 ev_variant = _state.pc; \
778 goto* dispatch_table[ev_variant->index()];
779#define CREATE_EXIT_LABEL(NAME, CODE) ev_label_##NAME : \
781#define CREATE_EMPTY_LABEL(NAME, CODE) ev_label_##NAME : \
782 throw wasm_interpreter_exception{"empty operand"};
784 template <
typename Visitor>
785 void execute(Visitor&& visitor) {
786 static void* dispatch_table[] = {
807 auto* ev_variant = _state.pc;
808 goto *dispatch_table[ev_variant->index()];
829 throw wasm_interpreter_exception{
"should never reach here"};
833#undef CREATE_EMPTY_LABEL
835#undef CREATE_TABLE_ENTRY
837 struct execution_state {
838 host_type* host =
nullptr;
842 bool exiting =
false;
845 bounded_allocator _base_allocator = {
846 (constants::max_call_depth + 1) *
sizeof(activation_frame)
848 execution_state _state;
852 host_type* _host =
nullptr;
auto & get_operand_stack()
execution_context_base(module &m)
static void type_check_args(const func_type &ft, Args &&...)
int32_t grow_linear_memory(int32_t pages)
std::error_code _error_code
std::error_code get_error_code() const
auto get_wasm_allocator()
void set_wasm_allocator(wasm_allocator *alloc)
void execute_start(host_type *host, Visitor &&visitor)
const auto & get_operand_stack() const
std::optional< operand_stack_elem > execute(host_type *host, Visitor &&visitor, const std::string_view func, Args... args)
static void handle_signal(int sig)
void set_max_pages(std::uint32_t max_pages)
wasm_allocator * _wasm_alloc
int32_t current_linear_memory() const
void exit(std::error_code err=std::error_code())
void type_check(const func_type &ft)
void apply_pop_call(uint32_t num_locals, uint16_t return_count)
operand_stack_elem get_global(uint32_t index)
void push_call(uint32_t index)
activation_frame pop_call()
void execute_start(host_type *host, Visitor &&visitor)
uint32_t current_operands_index() const
bool is_true(const operand_stack_elem &el)
operand_stack_elem get_operand(uint32_t index) const
void eat_operands(uint32_t index)
void set_operand(uint32_t index, const operand_stack_elem &el)
uint32_t call_depth() const
void call(uint32_t index)
void push_call(activation_frame &&el)
std::optional< operand_stack_elem > execute(host_type *host, Visitor &&visitor, uint32_t func_index, Args... args)
uint32_t table_elem(uint32_t i)
void set_max_call_depth(uint32_t max_call_depth)
int backtrace(void **data, int limit, void *uc) const
std::optional< operand_stack_elem > execute_func_table(host_type *host, Visitor &&visitor, uint32_t table_index, Args... args)
void jump(uint32_t pop_info, uint32_t new_pc)
void exit(std::error_code err=std::error_code())
execution_context(module &m, uint32_t max_call_depth)
void set_global(uint32_t index, const operand_stack_elem &el)
operand_stack_elem & peek_operand(size_t i=0)
void inc_pc(uint32_t offset=1)
std::optional< operand_stack_elem > execute(host_type *host, Visitor &&visitor, const std::string_view func, Args... args)
operand_stack_elem pop_operand()
void push_operand(operand_stack_elem el)
void set_relative_pc(uint32_t pc_offset)
void compact_operand(uint32_t index)
std::optional< operand_stack_elem > execute(host_type *host, jit_visitor, uint32_t func_index, Args... args)
void set_max_call_depth(std::uint32_t max_call_depth)
native_value call_host_function(native_value *stack, uint32_t index)
native_value transform_arg(T &&value)
jit_execution_context(module &m, std::uint32_t max_call_depth)
null_execution_context(module &m, std::uint32_t max_call_depth)
constexpr const auto & get() const &
void free(std::size_t size)
void alloc(size_t size=1)
int32_t get_current_page() const
typename type_converter< HF >::type type_converter_t
typename host_type< HF >::type host_type_t
typename host_invoker< HF >::type host_invoker_t
constexpr auto visit(Visitor &&vis, Variant &&var)
stack< activation_frame, constants::max_call_depth+1, bounded_allocator > call_stack
constexpr auto to_wasm_type_v
#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
unsigned __int64 uint64_t
typename HostFunctions::host_type_t type
typename HostFunctions::type_converter_t type
guarded_vector< value_type > param_types
guarded_vector< memory_type > memories
void operator()(A &&...) const
#define SYS_VM_ASSERT(expr, exc_type, msg)
#define CREATE_EMPTY_LABEL(NAME, CODE)
#define CREATE_LABEL(NAME, CODE)
#define CREATE_EXIT_LABEL(NAME, CODE)
#define CREATE_TABLE_ENTRY(NAME, CODE)
#define SYS_VM_F64_CONSTANT_OPS(opcode_macro)
#define SYS_VM_RETURN_OP(opcode_macro)
#define SYS_VM_EXIT_OP(opcode_macro)
#define SYS_VM_COMPARISON_OPS(opcode_macro)
#define SYS_VM_MEMORY_OPS(opcode_macro)
#define SYS_VM_I64_CONSTANT_OPS(opcode_macro)
#define SYS_VM_I32_CONSTANT_OPS(opcode_macro)
#define SYS_VM_CALL_OPS(opcode_macro)
#define SYS_VM_NUMERIC_OPS(opcode_macro)
#define SYS_VM_CONVERSION_OPS(opcode_macro)
#define SYS_VM_VARIABLE_ACCESS_OPS(opcode_macro)
#define SYS_VM_EMPTY_OPS(opcode_macro)
#define SYS_VM_CALL_IMM_OPS(opcode_macro)
#define SYS_VM_CONTROL_FLOW_OPS(opcode_macro)
#define SYS_VM_ERROR_OPS(opcode_macro)
#define SYS_VM_PARAMETRIC_OPS(opcode_macro)
#define SYS_VM_F32_CONSTANT_OPS(opcode_macro)
#define SYS_VM_BR_TABLE_OP(opcode_macro)
memcpy((char *) pInfo->slotDescription, s, l)
c_gkp_out sizeof(template))