3#include <sysio/vm/config.hpp>
4#include <sysio/vm/base_visitor.hpp>
5#include <sysio/vm/exceptions.hpp>
6#include <sysio/vm/opcodes.hpp>
7#include <sysio/vm/softfloat.hpp>
8#include <sysio/vm/stack_elem.hpp>
9#include <sysio/vm/utils.hpp>
10#include <sysio/vm/wasm_stack.hpp>
17namespace sysio {
namespace vm {
19 template <
typename ExecutionContext>
20 struct interpret_visitor : base_visitor {
21 using base_visitor::operator();
27 static inline constexpr void*
align_address(
void* addr,
size_t align_amt) {
29 addr = (
void*)(((
uintptr_t)addr + (1 << align_amt) - 1) & ~((1 << align_amt) - 1));
38 std::memcpy(&result, addr,
sizeof(
T));
43 std::memcpy(addr, &
value,
sizeof(
T));
46 [[gnu::always_inline]]
inline void operator()(
const unreachable_t&
op) {
48 throw wasm_interpreter_exception{
"unreachable" };
59 const auto& oper =
context.pop_operand();
60 if (!oper.to_ui32()) {
67 const auto& val =
context.pop_operand();
75 [[gnu::always_inline]]
inline void operator()(
const br_table_data_t&
op) {
78 [[gnu::always_inline]]
inline void operator()(
const br_table_t&
op) {
79 const auto& in =
context.pop_operand().to_ui32();
80 const auto& entry =
op.table[std::min(in,
op.size)];
81 context.jump(entry.stack_pop, entry.pc);
86 [[gnu::always_inline]]
inline void operator()(
const call_indirect_t&
op) {
87 const auto& index =
context.pop_operand().to_ui32();
89 const auto& expected_type =
context.get_module().types.at(
op.index);
90 const auto& actual_type =
context.get_module().get_function_type(fn);
91 SYS_VM_ASSERT(actual_type == expected_type, wasm_interpreter_exception,
"bad call_indirect type");
98 [[gnu::always_inline]]
inline void operator()(
const select_t&
op) {
99 const auto& c =
context.pop_operand();
100 const auto& v2 =
context.pop_operand();
101 if (c.to_ui32() == 0) {
116 const auto& oper =
context.pop_operand();
120 [[gnu::always_inline]]
inline void operator()(
const get_global_t&
op) {
122 const auto& gl =
context.get_global(
op.index);
125 [[gnu::always_inline]]
inline void operator()(
const set_global_t&
op) {
127 const auto& oper =
context.pop_operand();
130 template<
typename Op>
132 const auto& ptr =
context.pop_operand();
140 [[gnu::always_inline]]
inline void operator()(
const i32_load8_s_t&
op) {
145 [[gnu::always_inline]]
inline void operator()(
const i32_load16_s_t&
op) {
150 [[gnu::always_inline]]
inline void operator()(
const i32_load8_u_t&
op) {
155 [[gnu::always_inline]]
inline void operator()(
const i32_load16_u_t&
op) {
165 [[gnu::always_inline]]
inline void operator()(
const i64_load8_s_t&
op) {
170 [[gnu::always_inline]]
inline void operator()(
const i64_load16_s_t&
op) {
175 [[gnu::always_inline]]
inline void operator()(
const i64_load32_s_t&
op) {
180 [[gnu::always_inline]]
inline void operator()(
const i64_load8_u_t&
op) {
185 [[gnu::always_inline]]
inline void operator()(
const i64_load16_u_t&
op) {
190 [[gnu::always_inline]]
inline void operator()(
const i64_load32_u_t&
op) {
207 const auto& val =
context.pop_operand();
211 [[gnu::always_inline]]
inline void operator()(
const i32_store8_t&
op) {
213 const auto& val =
context.pop_operand();
217 [[gnu::always_inline]]
inline void operator()(
const i32_store16_t&
op) {
219 const auto& val =
context.pop_operand();
225 const auto& val =
context.pop_operand();
229 [[gnu::always_inline]]
inline void operator()(
const i64_store8_t&
op) {
231 const auto& val =
context.pop_operand();
235 [[gnu::always_inline]]
inline void operator()(
const i64_store16_t&
op) {
237 const auto& val =
context.pop_operand();
241 [[gnu::always_inline]]
inline void operator()(
const i64_store32_t&
op) {
243 const auto& val =
context.pop_operand();
249 const auto& val =
context.pop_operand();
255 const auto& val =
context.pop_operand();
259 [[gnu::always_inline]]
inline void operator()(
const current_memory_t&
op) {
261 context.push_operand(i32_const_t{
context.current_linear_memory() });
263 [[gnu::always_inline]]
inline void operator()(
const grow_memory_t&
op) {
265 auto& oper =
context.peek_operand().to_ui32();
266 oper =
context.grow_linear_memory(oper);
286 auto& t =
context.peek_operand().to_ui32();
291 const auto& rhs =
context.pop_operand().to_ui32();
292 auto& lhs =
context.peek_operand().to_ui32();
297 const auto& rhs =
context.pop_operand().to_ui32();
298 auto& lhs =
context.peek_operand().to_ui32();
303 const auto& rhs =
context.pop_operand().to_i32();
304 auto& lhs =
context.peek_operand().to_i32();
309 const auto& rhs =
context.pop_operand().to_ui32();
310 auto& lhs =
context.peek_operand().to_ui32();
315 const auto& rhs =
context.pop_operand().to_i32();
316 auto& lhs =
context.peek_operand().to_i32();
321 const auto& rhs =
context.pop_operand().to_ui32();
322 auto& lhs =
context.peek_operand().to_ui32();
327 const auto& rhs =
context.pop_operand().to_i32();
328 auto& lhs =
context.peek_operand().to_i32();
333 const auto& rhs =
context.pop_operand().to_ui32();
334 auto& lhs =
context.peek_operand().to_ui32();
339 const auto& rhs =
context.pop_operand().to_i32();
340 auto& lhs =
context.peek_operand().to_i32();
345 const auto& rhs =
context.pop_operand().to_ui32();
346 auto& lhs =
context.peek_operand().to_ui32();
351 auto& oper =
context.peek_operand();
352 oper = i32_const_t{ oper.to_ui64() == 0 };
356 const auto& rhs =
context.pop_operand().to_ui64();
357 auto& lhs =
context.peek_operand();
358 lhs = i32_const_t{ lhs.to_ui64() == rhs };
362 const auto& rhs =
context.pop_operand().to_ui64();
363 auto& lhs =
context.peek_operand();
364 lhs = i32_const_t{ lhs.to_ui64() != rhs };
368 const auto& rhs =
context.pop_operand().to_i64();
369 auto& lhs =
context.peek_operand();
370 lhs = i32_const_t{ lhs.to_i64() < rhs };
374 const auto& rhs =
context.pop_operand().to_ui64();
375 auto& lhs =
context.peek_operand();
376 lhs = i32_const_t{ lhs.to_ui64() < rhs };
380 const auto& rhs =
context.pop_operand().to_i64();
381 auto& lhs =
context.peek_operand();
382 lhs = i32_const_t{ lhs.to_i64() <= rhs };
386 const auto& rhs =
context.pop_operand().to_ui64();
387 auto& lhs =
context.peek_operand();
388 lhs = i32_const_t{ lhs.to_ui64() <= rhs };
392 const auto& rhs =
context.pop_operand().to_i64();
393 auto& lhs =
context.peek_operand();
394 lhs = i32_const_t{ lhs.to_i64() > rhs };
398 const auto& rhs =
context.pop_operand().to_ui64();
399 auto& lhs =
context.peek_operand();
400 lhs = i32_const_t{ lhs.to_ui64() > rhs };
404 const auto& rhs =
context.pop_operand().to_i64();
405 auto& lhs =
context.peek_operand();
406 lhs = i32_const_t{ lhs.to_i64() >= rhs };
410 const auto& rhs =
context.pop_operand().to_ui64();
411 auto& lhs =
context.peek_operand();
412 lhs = i32_const_t{ lhs.to_ui64() >= rhs };
416 const auto& rhs =
context.pop_operand().to_f32();
417 auto& lhs =
context.peek_operand();
419 lhs = i32_const_t{ (
uint32_t)_sysio_f32_eq(lhs.to_f32(), rhs) };
421 lhs = i32_const_t{ (
uint32_t)(lhs.to_f32() == rhs) };
425 const auto& rhs =
context.pop_operand().to_f32();
426 auto& lhs =
context.peek_operand();
428 lhs = i32_const_t{ (
uint32_t)_sysio_f32_ne(lhs.to_f32(), rhs) };
430 lhs = i32_const_t{ (
uint32_t)(lhs.to_f32() != rhs) };
434 const auto& rhs =
context.pop_operand().to_f32();
435 auto& lhs =
context.peek_operand();
437 lhs = i32_const_t{ (
uint32_t)_sysio_f32_lt(lhs.to_f32(), rhs) };
439 lhs = i32_const_t{ (
uint32_t)(lhs.to_f32() < rhs) };
443 const auto& rhs =
context.pop_operand().to_f32();
444 auto& lhs =
context.peek_operand();
446 lhs = i32_const_t{ (
uint32_t)_sysio_f32_gt(lhs.to_f32(), rhs) };
448 lhs = i32_const_t{ (
uint32_t)(lhs.to_f32() > rhs) };
452 const auto& rhs =
context.pop_operand().to_f32();
453 auto& lhs =
context.peek_operand();
455 lhs = i32_const_t{ (
uint32_t)_sysio_f32_le(lhs.to_f32(), rhs) };
457 lhs = i32_const_t{ (
uint32_t)(lhs.to_f32() <= rhs) };
461 const auto& rhs =
context.pop_operand().to_f32();
462 auto& lhs =
context.peek_operand();
464 lhs = i32_const_t{ (
uint32_t)_sysio_f32_ge(lhs.to_f32(), rhs) };
466 lhs = i32_const_t{ (
uint32_t)(lhs.to_f32() >= rhs) };
470 const auto& rhs =
context.pop_operand().to_f64();
471 auto& lhs =
context.peek_operand();
473 lhs = i32_const_t{ (
uint32_t)_sysio_f64_eq(lhs.to_f64(), rhs) };
475 lhs = i32_const_t{ (
uint32_t)(lhs.to_f64() == rhs) };
479 const auto& rhs =
context.pop_operand().to_f64();
480 auto& lhs =
context.peek_operand();
482 lhs = i32_const_t{ (
uint32_t)_sysio_f64_ne(lhs.to_f64(), rhs) };
484 lhs = i32_const_t{ (
uint32_t)(lhs.to_f64() != rhs) };
488 const auto& rhs =
context.pop_operand().to_f64();
489 auto& lhs =
context.peek_operand();
491 lhs = i32_const_t{ (
uint32_t)_sysio_f64_lt(lhs.to_f64(), rhs) };
493 lhs = i32_const_t{ (
uint32_t)(lhs.to_f64() < rhs) };
497 const auto& rhs =
context.pop_operand().to_f64();
498 auto& lhs =
context.peek_operand();
500 lhs = i32_const_t{ (
uint32_t)_sysio_f64_gt(lhs.to_f64(), rhs) };
502 lhs = i32_const_t{ (
uint32_t)(lhs.to_f64() > rhs) };
506 const auto& rhs =
context.pop_operand().to_f64();
507 auto& lhs =
context.peek_operand();
509 lhs = i32_const_t{ (
uint32_t)_sysio_f64_le(lhs.to_f64(), rhs) };
511 lhs = i32_const_t{ (
uint32_t)(lhs.to_f64() <= rhs) };
515 const auto& rhs =
context.pop_operand().to_f64();
516 auto& lhs =
context.peek_operand();
518 lhs = i32_const_t{ (
uint32_t)_sysio_f64_ge(lhs.to_f64(), rhs) };
520 lhs = i32_const_t{ (
uint32_t)(lhs.to_f64() >= rhs) };
524 auto& oper =
context.peek_operand().to_ui32();
526 oper = oper == 0 ? 32 : __builtin_clz(oper);
530 auto& oper =
context.peek_operand().to_ui32();
533 oper = oper == 0 ? 32 : __builtin_ctz(oper);
535 [[gnu::always_inline]]
inline void operator()(
const i32_popcnt_t&
op) {
537 auto& oper =
context.peek_operand().to_ui32();
538 oper = __builtin_popcount(oper);
542 const auto& rhs =
context.pop_operand().to_ui32();
543 auto& lhs =
context.peek_operand().to_ui32();
548 const auto& rhs =
context.pop_operand().to_ui32();
549 auto& lhs =
context.peek_operand().to_ui32();
554 const auto& rhs =
context.pop_operand().to_ui32();
555 auto& lhs =
context.peek_operand().to_ui32();
560 const auto& rhs =
context.pop_operand().to_i32();
561 auto& lhs =
context.peek_operand().to_i32();
562 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i32.div_s divide by zero");
563 SYS_VM_ASSERT(!(lhs == std::numeric_limits<int32_t>::min() && rhs == -1), wasm_interpreter_exception,
564 "i32.div_s traps when I32_MAX/-1");
569 const auto& rhs =
context.pop_operand().to_ui32();
570 auto& lhs =
context.peek_operand().to_ui32();
571 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i32.div_u divide by zero");
576 const auto& rhs =
context.pop_operand().to_i32();
577 auto& lhs =
context.peek_operand().to_i32();
578 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i32.rem_s divide by zero");
579 if (
UNLIKELY(lhs == std::numeric_limits<int32_t>::min() && rhs == -1))
586 const auto& rhs =
context.pop_operand().to_ui32();
587 auto& lhs =
context.peek_operand().to_ui32();
588 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i32.rem_u divide by zero");
593 const auto& rhs =
context.pop_operand().to_ui32();
594 auto& lhs =
context.peek_operand().to_ui32();
599 const auto& rhs =
context.pop_operand().to_ui32();
600 auto& lhs =
context.peek_operand().to_ui32();
605 const auto& rhs =
context.pop_operand().to_ui32();
606 auto& lhs =
context.peek_operand().to_ui32();
612 const auto& rhs =
context.pop_operand().to_ui32();
613 auto& lhs =
context.peek_operand().to_ui32();
614 lhs <<= (rhs & mask);
619 const auto& rhs =
context.pop_operand().to_ui32();
620 auto& lhs =
context.peek_operand().to_i32();
621 lhs >>= (rhs & mask);
626 const auto& rhs =
context.pop_operand().to_ui32();
627 auto& lhs =
context.peek_operand().to_ui32();
628 lhs >>= (rhs & mask);
634 const auto& rhs =
context.pop_operand().to_ui32();
635 auto& lhs =
context.peek_operand().to_ui32();
638 lhs = (lhs << c) | (lhs >> ((-c) & mask));
643 const auto& rhs =
context.pop_operand().to_ui32();
644 auto& lhs =
context.peek_operand().to_ui32();
647 lhs = (lhs >> c) | (lhs << ((-c) & mask));
651 auto& oper =
context.peek_operand().to_ui64();
653 oper = oper == 0 ? 64 : __builtin_clzll(oper);
657 auto& oper =
context.peek_operand().to_ui64();
659 oper = oper == 0 ? 64 : __builtin_ctzll(oper);
661 [[gnu::always_inline]]
inline void operator()(
const i64_popcnt_t&
op) {
663 auto& oper =
context.peek_operand().to_ui64();
664 oper = __builtin_popcountll(oper);
668 const auto& rhs =
context.pop_operand().to_ui64();
669 auto& lhs =
context.peek_operand().to_ui64();
674 const auto& rhs =
context.pop_operand().to_ui64();
675 auto& lhs =
context.peek_operand().to_ui64();
680 const auto& rhs =
context.pop_operand().to_ui64();
681 auto& lhs =
context.peek_operand().to_ui64();
686 const auto& rhs =
context.pop_operand().to_i64();
687 auto& lhs =
context.peek_operand().to_i64();
688 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i64.div_s divide by zero");
689 SYS_VM_ASSERT(!(lhs == std::numeric_limits<int64_t>::min() && rhs == -1), wasm_interpreter_exception,
690 "i64.div_s traps when I64_MAX/-1");
695 const auto& rhs =
context.pop_operand().to_ui64();
696 auto& lhs =
context.peek_operand().to_ui64();
697 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i64.div_u divide by zero");
702 const auto& rhs =
context.pop_operand().to_i64();
703 auto& lhs =
context.peek_operand().to_i64();
704 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i64.rem_s divide by zero");
705 if (
UNLIKELY(lhs == std::numeric_limits<int64_t>::min() && rhs == -1))
712 const auto& rhs =
context.pop_operand().to_ui64();
713 auto& lhs =
context.peek_operand().to_ui64();
714 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception,
"i64.rem_s divide by zero");
719 const auto& rhs =
context.pop_operand().to_ui64();
720 auto& lhs =
context.peek_operand().to_ui64();
725 const auto& rhs =
context.pop_operand().to_ui64();
726 auto& lhs =
context.peek_operand().to_ui64();
731 const auto& rhs =
context.pop_operand().to_ui64();
732 auto& lhs =
context.peek_operand().to_ui64();
738 const auto& rhs =
context.pop_operand().to_ui64();
739 auto& lhs =
context.peek_operand().to_ui64();
740 lhs <<= (rhs & mask);
745 const auto& rhs =
context.pop_operand().to_ui64();
746 auto& lhs =
context.peek_operand().to_i64();
747 lhs >>= (rhs & mask);
752 const auto& rhs =
context.pop_operand().to_ui64();
753 auto& lhs =
context.peek_operand().to_ui64();
754 lhs >>= (rhs & mask);
759 const auto& rhs =
context.pop_operand().to_ui64();
760 auto& lhs =
context.peek_operand().to_ui64();
763 lhs = (lhs << c) | (lhs >> (-c & mask));
768 const auto& rhs =
context.pop_operand().to_ui64();
769 auto& lhs =
context.peek_operand().to_ui64();
772 lhs = (lhs >> c) | (lhs << (-c & mask));
776 auto& oper =
context.peek_operand().to_f32();
778 oper = _sysio_f32_abs(oper);
780 oper = __builtin_fabsf(oper);
784 auto& oper =
context.peek_operand().to_f32();
786 oper = _sysio_f32_neg(oper);
792 auto& oper =
context.peek_operand().to_f32();
794 oper = _sysio_f32_ceil(oper);
796 oper = __builtin_ceilf(oper);
800 auto& oper =
context.peek_operand().to_f32();
802 oper = _sysio_f32_floor(oper);
804 oper = __builtin_floorf(oper);
808 auto& oper =
context.peek_operand().to_f32();
810 oper = _sysio_f32_trunc(oper);
812 oper = __builtin_trunc(oper);
814 [[gnu::always_inline]]
inline void operator()(
const f32_nearest_t&
op) {
816 auto& oper =
context.peek_operand().to_f32();
818 oper = _sysio_f32_nearest(oper);
820 oper = __builtin_nearbyintf(oper);
824 auto& oper =
context.peek_operand().to_f32();
826 oper = _sysio_f32_sqrt(oper);
828 oper = __builtin_sqrtf(oper);
832 const auto& rhs =
context.pop_operand();
833 auto& lhs =
context.peek_operand().to_f32();
835 lhs = _sysio_f32_add(lhs, rhs.to_f32());
841 const auto& rhs =
context.pop_operand();
842 auto& lhs =
context.peek_operand().to_f32();
844 lhs = _sysio_f32_sub(lhs, rhs.to_f32());
850 const auto& rhs =
context.pop_operand();
851 auto& lhs =
context.peek_operand().to_f32();
853 lhs = _sysio_f32_mul(lhs, rhs.to_f32());
859 const auto& rhs =
context.pop_operand();
860 auto& lhs =
context.peek_operand().to_f32();
862 lhs = _sysio_f32_div(lhs, rhs.to_f32());
868 const auto& rhs =
context.pop_operand();
869 auto& lhs =
context.peek_operand().to_f32();
871 lhs = _sysio_f32_min(lhs, rhs.to_f32());
873 lhs = __builtin_fminf(lhs, rhs.to_f32());
877 const auto& rhs =
context.pop_operand();
878 auto& lhs =
context.peek_operand().to_f32();
880 lhs = _sysio_f32_max(lhs, rhs.to_f32());
882 lhs = __builtin_fmaxf(lhs, rhs.to_f32());
884 [[gnu::always_inline]]
inline void operator()(
const f32_copysign_t&
op) {
886 const auto& rhs =
context.pop_operand();
887 auto& lhs =
context.peek_operand().to_f32();
889 lhs = _sysio_f32_copysign(lhs, rhs.to_f32());
891 lhs = __builtin_copysignf(lhs, rhs.to_f32());
895 auto& oper =
context.peek_operand().to_f64();
897 oper = _sysio_f64_abs(oper);
899 oper = __builtin_fabs(oper);
903 auto& oper =
context.peek_operand().to_f64();
905 oper = _sysio_f64_neg(oper);
912 auto& oper =
context.peek_operand().to_f64();
914 oper = _sysio_f64_ceil(oper);
916 oper = __builtin_ceil(oper);
920 auto& oper =
context.peek_operand().to_f64();
922 oper = _sysio_f64_floor(oper);
924 oper = __builtin_floor(oper);
928 auto& oper =
context.peek_operand().to_f64();
930 oper = _sysio_f64_trunc(oper);
932 oper = __builtin_trunc(oper);
934 [[gnu::always_inline]]
inline void operator()(
const f64_nearest_t&
op) {
936 auto& oper =
context.peek_operand().to_f64();
938 oper = _sysio_f64_nearest(oper);
940 oper = __builtin_nearbyint(oper);
944 auto& oper =
context.peek_operand().to_f64();
946 oper = _sysio_f64_sqrt(oper);
948 oper = __builtin_sqrt(oper);
952 const auto& rhs =
context.pop_operand();
953 auto& lhs =
context.peek_operand().to_f64();
955 lhs = _sysio_f64_add(lhs, rhs.to_f64());
961 const auto& rhs =
context.pop_operand();
962 auto& lhs =
context.peek_operand().to_f64();
964 lhs = _sysio_f64_sub(lhs, rhs.to_f64());
970 const auto& rhs =
context.pop_operand();
971 auto& lhs =
context.peek_operand().to_f64();
973 lhs = _sysio_f64_mul(lhs, rhs.to_f64());
979 const auto& rhs =
context.pop_operand();
980 auto& lhs =
context.peek_operand().to_f64();
982 lhs = _sysio_f64_div(lhs, rhs.to_f64());
988 const auto& rhs =
context.pop_operand();
989 auto& lhs =
context.peek_operand().to_f64();
991 lhs = _sysio_f64_min(lhs, rhs.to_f64());
993 lhs = __builtin_fmin(lhs, rhs.to_f64());
997 const auto& rhs =
context.pop_operand();
998 auto& lhs =
context.peek_operand().to_f64();
1000 lhs = _sysio_f64_max(lhs, rhs.to_f64());
1002 lhs = __builtin_fmax(lhs, rhs.to_f64());
1006 const auto& rhs =
context.pop_operand();
1007 auto& lhs =
context.peek_operand().to_f64();
1009 lhs = _sysio_f64_copysign(lhs, rhs.to_f64());
1011 lhs = __builtin_copysign(lhs, rhs.to_f64());
1015 auto& oper =
context.peek_operand();
1016 oper = i32_const_t{
static_cast<int32_t>(oper.to_i64()) };
1018 [[gnu::always_inline]]
inline void operator()(
const i32_trunc_s_f32_t&
op) {
1020 auto& oper =
context.peek_operand();
1022 oper = i32_const_t{ _sysio_f32_trunc_i32s(oper.to_f32()) };
1024 float af = oper.to_f32();
1025 SYS_VM_ASSERT(!((af >= 2147483648.0f) || (af < -2147483648.0f)), wasm_interpreter_exception,
"Error, f32.trunc_s/i32 overflow" );
1026 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f32.trunc_s/i32 unrepresentable");
1027 oper = i32_const_t{
static_cast<int32_t>(af) };
1030 [[gnu::always_inline]]
inline void operator()(
const i32_trunc_u_f32_t&
op) {
1032 auto& oper =
context.peek_operand();
1034 oper = i32_const_t{ _sysio_f32_trunc_i32u(oper.to_f32()) };
1036 float af = oper.to_f32();
1037 SYS_VM_ASSERT(!((af >= 4294967296.0f) || (af <= -1.0f)),wasm_interpreter_exception,
"Error, f32.trunc_u/i32 overflow");
1038 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f32.trunc_u/i32 unrepresentable");
1039 oper = i32_const_t{
static_cast<uint32_t>(af) };
1042 [[gnu::always_inline]]
inline void operator()(
const i32_trunc_s_f64_t&
op) {
1044 auto& oper =
context.peek_operand();
1046 oper = i32_const_t{ _sysio_f64_trunc_i32s(oper.to_f64()) };
1048 double af = oper.to_f64();
1049 SYS_VM_ASSERT(!((af >= 2147483648.0) || (af < -2147483648.0)), wasm_interpreter_exception,
"Error, f64.trunc_s/i32 overflow");
1050 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f64.trunc_s/i32 unrepresentable");
1051 oper = i32_const_t{
static_cast<int32_t>(af) };
1054 [[gnu::always_inline]]
inline void operator()(
const i32_trunc_u_f64_t&
op) {
1056 auto& oper =
context.peek_operand();
1058 oper = i32_const_t{ _sysio_f64_trunc_i32u(oper.to_f64()) };
1060 double af = oper.to_f64();
1061 SYS_VM_ASSERT(!((af >= 4294967296.0) || (af <= -1.0)), wasm_interpreter_exception,
"Error, f64.trunc_u/i32 overflow");
1062 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f64.trunc_u/i32 unrepresentable");
1063 oper = i32_const_t{
static_cast<uint32_t>(af) };
1066 [[gnu::always_inline]]
inline void operator()(
const i64_extend_s_i32_t&
op) {
1068 auto& oper =
context.peek_operand();
1069 oper = i64_const_t{
static_cast<int64_t>(oper.to_i32()) };
1071 [[gnu::always_inline]]
inline void operator()(
const i64_extend_u_i32_t&
op) {
1073 auto& oper =
context.peek_operand();
1074 oper = i64_const_t{
static_cast<uint64_t>(oper.to_ui32()) };
1076 [[gnu::always_inline]]
inline void operator()(
const i64_trunc_s_f32_t&
op) {
1078 auto& oper =
context.peek_operand();
1080 oper = i64_const_t{ _sysio_f32_trunc_i64s(oper.to_f32()) };
1082 float af = oper.to_f32();
1083 SYS_VM_ASSERT(!((af >= 9223372036854775808.0f) || (af < -9223372036854775808.0f)), wasm_interpreter_exception,
"Error, f32.trunc_s/i64 overflow");
1084 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f32.trunc_s/i64 unrepresentable");
1085 oper = i64_const_t{
static_cast<int64_t>(af) };
1088 [[gnu::always_inline]]
inline void operator()(
const i64_trunc_u_f32_t&
op) {
1090 auto& oper =
context.peek_operand();
1092 oper = i64_const_t{ _sysio_f32_trunc_i64u(oper.to_f32()) };
1094 float af = oper.to_f32();
1095 SYS_VM_ASSERT(!((af >= 18446744073709551616.0f) || (af <= -1.0f)), wasm_interpreter_exception,
"Error, f32.trunc_u/i64 overflow");
1096 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f32.trunc_u/i64 unrepresentable");
1097 oper = i64_const_t{
static_cast<uint64_t>(af) };
1100 [[gnu::always_inline]]
inline void operator()(
const i64_trunc_s_f64_t&
op) {
1102 auto& oper =
context.peek_operand();
1104 oper = i64_const_t{ _sysio_f64_trunc_i64s(oper.to_f64()) };
1106 double af = oper.to_f64();
1107 SYS_VM_ASSERT(!((af >= 9223372036854775808.0) || (af < -9223372036854775808.0)), wasm_interpreter_exception,
"Error, f64.trunc_s/i64 overflow");
1108 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f64.trunc_s/i64 unrepresentable");
1109 oper = i64_const_t{
static_cast<int64_t>(af) };
1112 [[gnu::always_inline]]
inline void operator()(
const i64_trunc_u_f64_t&
op) {
1114 auto& oper =
context.peek_operand();
1116 oper = i64_const_t{ _sysio_f64_trunc_i64u(oper.to_f64()) };
1118 double af = oper.to_f64();
1119 SYS_VM_ASSERT(!((af >= 18446744073709551616.0) || (af <= -1.0)), wasm_interpreter_exception,
"Error, f64.trunc_u/i64 overflow");
1120 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception,
"Error, f64.trunc_u/i64 unrepresentable");
1121 oper = i64_const_t{
static_cast<uint64_t>(af) };
1124 [[gnu::always_inline]]
inline void operator()(
const f32_convert_s_i32_t&
op) {
1126 auto& oper =
context.peek_operand();
1128 oper = f32_const_t{ _sysio_i32_to_f32(oper.to_i32()) };
1130 oper = f32_const_t{
static_cast<float>(oper.to_i32()) };
1133 [[gnu::always_inline]]
inline void operator()(
const f32_convert_u_i32_t&
op) {
1135 auto& oper =
context.peek_operand();
1137 oper = f32_const_t{ _sysio_ui32_to_f32(oper.to_ui32()) };
1139 oper = f32_const_t{
static_cast<float>(oper.to_ui32()) };
1142 [[gnu::always_inline]]
inline void operator()(
const f32_convert_s_i64_t&
op) {
1144 auto& oper =
context.peek_operand();
1146 oper = f32_const_t{ _sysio_i64_to_f32(oper.to_i64()) };
1148 oper = f32_const_t{
static_cast<float>(oper.to_i64()) };
1151 [[gnu::always_inline]]
inline void operator()(
const f32_convert_u_i64_t&
op) {
1153 auto& oper =
context.peek_operand();
1155 oper = f32_const_t{ _sysio_ui64_to_f32(oper.to_ui64()) };
1157 oper = f32_const_t{
static_cast<float>(oper.to_ui64()) };
1160 [[gnu::always_inline]]
inline void operator()(
const f32_demote_f64_t&
op) {
1162 auto& oper =
context.peek_operand();
1164 oper = f32_const_t{ _sysio_f64_demote(oper.to_f64()) };
1166 oper = f32_const_t{
static_cast<float>(oper.to_f64()) };
1169 [[gnu::always_inline]]
inline void operator()(
const f64_convert_s_i32_t&
op) {
1171 auto& oper =
context.peek_operand();
1173 oper = f64_const_t{ _sysio_i32_to_f64(oper.to_i32()) };
1175 oper = f64_const_t{
static_cast<double>(oper.to_i32()) };
1178 [[gnu::always_inline]]
inline void operator()(
const f64_convert_u_i32_t&
op) {
1180 auto& oper =
context.peek_operand();
1182 oper = f64_const_t{ _sysio_ui32_to_f64(oper.to_ui32()) };
1184 oper = f64_const_t{
static_cast<double>(oper.to_ui32()) };
1187 [[gnu::always_inline]]
inline void operator()(
const f64_convert_s_i64_t&
op) {
1189 auto& oper =
context.peek_operand();
1191 oper = f64_const_t{ _sysio_i64_to_f64(oper.to_i64()) };
1193 oper = f64_const_t{
static_cast<double>(oper.to_i64()) };
1196 [[gnu::always_inline]]
inline void operator()(
const f64_convert_u_i64_t&
op) {
1198 auto& oper =
context.peek_operand();
1200 oper = f64_const_t{ _sysio_ui64_to_f64(oper.to_ui64()) };
1202 oper = f64_const_t{
static_cast<double>(oper.to_ui64()) };
1205 [[gnu::always_inline]]
inline void operator()(
const f64_promote_f32_t&
op) {
1207 auto& oper =
context.peek_operand();
1209 oper = f64_const_t{ _sysio_f32_promote(oper.to_f32()) };
1211 oper = f64_const_t{
static_cast<double>(oper.to_f32()) };
1214 [[gnu::always_inline]]
inline void operator()(
const i32_reinterpret_f32_t&
op) {
1216 auto& oper =
context.peek_operand();
1217 oper = i32_const_t{ oper.to_fui32() };
1219 [[gnu::always_inline]]
inline void operator()(
const i64_reinterpret_f64_t&
op) {
1221 auto& oper =
context.peek_operand();
1222 oper = i64_const_t{ oper.to_fui64() };
1224 [[gnu::always_inline]]
inline void operator()(
const f32_reinterpret_i32_t&
op) {
1226 auto& oper =
context.peek_operand();
1227 oper = f32_const_t{ oper.to_ui32() };
1229 [[gnu::always_inline]]
inline void operator()(
const f64_reinterpret_i64_t&
op) {
1231 auto& oper =
context.peek_operand();
1232 oper = f64_const_t{ oper.to_ui64() };
constexpr bool should_align_memory_ops
constexpr bool use_softfloat
#define T(meth, val, expected)
_W64 unsigned int uintptr_t
unsigned __int64 uint64_t
void operator()(const f64_ne_t &op)
void operator()(const i32_gt_u_t &op)
void operator()(const f32_trunc_t &op)
void operator()(const i64_reinterpret_f64_t &op)
void operator()(const f32_copysign_t &op)
void operator()(const i64_ge_u_t &op)
void operator()(const call_t &op)
void operator()(const f64_load_t &op)
void operator()(const i64_rem_s_t &op)
void operator()(const f32_eq_t &op)
void operator()(const i64_extend_u_i32_t &op)
void operator()(const nop_t &op)
void operator()(const i32_eqz_t &op)
void operator()(const i64_trunc_u_f32_t &op)
void operator()(const f32_store_t &op)
void operator()(const i32_load8_s_t &op)
void operator()(const i32_const_t &op)
void operator()(const i32_load16_u_t &op)
void operator()(const i64_eqz_t &op)
void operator()(const loop_t &op)
void operator()(const end_t &op)
void operator()(const i64_load16_s_t &op)
void operator()(const f64_div_t &op)
void operator()(const i64_load32_s_t &op)
void operator()(const f64_trunc_t &op)
void operator()(const i64_load32_u_t &op)
void operator()(const f64_abs_t &op)
void operator()(const f32_ne_t &op)
void operator()(const i64_xor_t &op)
void operator()(const i64_load16_u_t &op)
void operator()(const i64_popcnt_t &op)
interpret_visitor(ExecutionContext &ec)
void operator()(const f64_max_t &op)
void operator()(const f64_add_t &op)
void operator()(const i32_store_t &op)
void operator()(const i64_const_t &op)
void operator()(const i64_store_t &op)
void operator()(const i64_div_u_t &op)
static constexpr void * align_address(void *addr, size_t align_amt)
void operator()(const f64_nearest_t &op)
void operator()(const current_memory_t &op)
void operator()(const i32_trunc_s_f64_t &op)
void operator()(const i32_ge_s_t &op)
void operator()(const br_table_t &op)
void operator()(const else_t &op)
void operator()(const i64_shl_t &op)
void operator()(const i64_rotr_t &op)
void operator()(const f32_div_t &op)
void operator()(const i32_wrap_i64_t &op)
void operator()(const i64_gt_u_t &op)
ExecutionContext & get_context()
void operator()(const f64_lt_t &op)
void operator()(const i64_le_s_t &op)
void operator()(const tee_local_t &op)
void operator()(const f64_eq_t &op)
void operator()(const i32_load8_u_t &op)
void operator()(const grow_memory_t &op)
void operator()(const f32_max_t &op)
void operator()(const i64_eq_t &op)
void operator()(const f64_promote_f32_t &op)
void operator()(const f32_demote_f64_t &op)
void operator()(const i32_or_t &op)
static T read_unaligned(const void *addr)
void operator()(const i32_div_u_t &op)
static void write_unaligned(void *addr, T value)
void operator()(const f64_sub_t &op)
void operator()(const f64_reinterpret_i64_t &op)
void operator()(const f32_ceil_t &op)
void operator()(const i32_shr_u_t &op)
void operator()(const f64_store_t &op)
void operator()(const i64_trunc_s_f64_t &op)
void operator()(const f64_const_t &op)
void operator()(const i32_reinterpret_f32_t &op)
void operator()(const i32_sub_t &op)
void operator()(const i32_ne_t &op)
void operator()(const f64_copysign_t &op)
void operator()(const f32_min_t &op)
void operator()(const f64_convert_u_i64_t &op)
void operator()(const i32_gt_s_t &op)
void operator()(const f32_le_t &op)
void operator()(const i64_lt_u_t &op)
void operator()(const return_t &op)
void operator()(const i32_trunc_s_f32_t &op)
void operator()(const i32_le_u_t &op)
void operator()(const i64_and_t &op)
void operator()(const i32_rem_s_t &op)
void operator()(const f32_sub_t &op)
void operator()(const br_t &op)
void operator()(const i32_add_t &op)
void operator()(const f64_neg_t &op)
void operator()(const f64_floor_t &op)
void operator()(const i32_load16_s_t &op)
void operator()(const i64_load_t &op)
void operator()(const i64_rem_u_t &op)
void operator()(const i64_lt_s_t &op)
void operator()(const i32_rotr_t &op)
ExecutionContext & context
void operator()(const i64_add_t &op)
void operator()(const f32_convert_s_i32_t &op)
void operator()(const i64_store8_t &op)
void operator()(const f32_convert_u_i64_t &op)
void operator()(const select_t &op)
void operator()(const i32_and_t &op)
void operator()(const i32_load_t &op)
void operator()(const i64_load8_u_t &op)
void operator()(const call_indirect_t &op)
void operator()(const f32_ge_t &op)
void operator()(const i32_rotl_t &op)
void operator()(const f64_mul_t &op)
void * pop_memop_addr(const Op &op)
void operator()(const i64_or_t &op)
void operator()(const i64_shr_u_t &op)
void operator()(const i64_store16_t &op)
void operator()(const set_local_t &op)
void operator()(const get_global_t &op)
void operator()(const f64_sqrt_t &op)
void operator()(const i64_shr_s_t &op)
void operator()(const f32_abs_t &op)
void operator()(const i64_trunc_s_f32_t &op)
void operator()(const i32_mul_t &op)
void operator()(const i32_popcnt_t &op)
void operator()(const i32_store8_t &op)
void operator()(const i32_rem_u_t &op)
void operator()(const i32_store16_t &op)
void operator()(const f32_const_t &op)
void operator()(const f64_convert_u_i32_t &op)
void operator()(const f64_gt_t &op)
void operator()(const i64_sub_t &op)
void operator()(const i64_div_s_t &op)
void operator()(const f32_nearest_t &op)
void operator()(const unreachable_t &op)
void operator()(const i32_div_s_t &op)
void operator()(const get_local_t &op)
void operator()(const i64_ctz_t &op)
void operator()(const i32_shl_t &op)
void operator()(const i32_clz_t &op)
void operator()(const f64_convert_s_i64_t &op)
void operator()(const f32_floor_t &op)
void operator()(const f64_convert_s_i32_t &op)
void operator()(const f32_gt_t &op)
void operator()(const i32_le_s_t &op)
void operator()(const f64_le_t &op)
void operator()(const br_if_t &op)
void operator()(const set_global_t &op)
void operator()(const drop_t &op)
void operator()(const i32_shr_s_t &op)
void operator()(const i64_rotl_t &op)
void operator()(const i64_le_u_t &op)
void operator()(const i64_gt_s_t &op)
void operator()(const i64_trunc_u_f64_t &op)
void operator()(const block_t &op)
void operator()(const i32_trunc_u_f64_t &op)
void operator()(const i32_ctz_t &op)
void operator()(const f32_load_t &op)
void operator()(const i32_ge_u_t &op)
void operator()(const i32_trunc_u_f32_t &op)
void operator()(const i64_store32_t &op)
void operator()(const i64_ge_s_t &op)
void operator()(const f32_reinterpret_i32_t &op)
void operator()(const f64_ceil_t &op)
void operator()(const f32_convert_u_i32_t &op)
void operator()(const i64_clz_t &op)
void operator()(const i64_extend_s_i32_t &op)
void operator()(const f32_mul_t &op)
void operator()(const i32_lt_s_t &op)
void operator()(const f64_ge_t &op)
void operator()(const i64_mul_t &op)
void operator()(const f32_sqrt_t &op)
void operator()(const br_table_data_t &op)
void operator()(const f64_min_t &op)
void operator()(const i32_lt_u_t &op)
void operator()(const i32_xor_t &op)
void operator()(const if_t &op)
void operator()(const f32_lt_t &op)
void operator()(const i64_ne_t &op)
void operator()(const i32_eq_t &op)
void operator()(const i64_load8_s_t &op)
void operator()(const f32_neg_t &op)
void operator()(const f32_convert_s_i64_t &op)
void operator()(const f32_add_t &op)
#define SYS_VM_ASSERT(expr, exc_type, msg)