735 {
736
737
738 operand_stack_type_tracker op_stack{local_bytes_checker, _options};
739 std::vector<pc_element_t> pc_stack{{
740 op_stack.depth(),
741 ft.return_count ? ft.return_type :
static_cast<uint32_t>(types::pseudo),
743 false,
745
746
747
748
751 pc_element_t& branch_target = pc_stack[pc_stack.size() -
label - 1];
752 std::visit(
overloaded{ [&](
label_t target) { code_writer.fix_branch(address, target); },
753 [&](std::vector<branch_t>& relocations) { relocations.push_back(address); } },
754 branch_target.relocations);
755 };
756
757
758
759
760
763 pc_element_t& branch_target = pc_stack[pc_stack.size() -
label - 1];
764 uint32_t result = op_stack.depth() - branch_target.operand_depth;
765 if(branch_target.label_result != types::pseudo) {
766
767
768
769
770
771 result |= 0x80000000;
772 op_stack.top(branch_target.label_result);
773 }
774 return result;
775 };
776
777
778 auto exit_scope = [&]() {
779
780 SYS_VM_ASSERT(pc_stack.size(), wasm_parse_exception,
"unexpected end instruction");
781
782 SYS_VM_ASSERT(!pc_stack.back().is_if || pc_stack.back().expected_result == types::pseudo, wasm_parse_exception,
"wrong type");
783 auto end_pos = code_writer.emit_end();
784 if(auto* relocations = std::get_if<std::vector<branch_t>>(&pc_stack.back().relocations)) {
785 for(auto branch_op : *relocations) {
786 code_writer.fix_branch(branch_op, end_pos);
787 }
788 }
789 op_stack.pop_scope(pc_stack.back().expected_result);
790 pc_stack.pop_back();
791 };
792
793 auto check_in_bounds = [&]{
794 SYS_VM_ASSERT(!detail::get_allow_code_after_function_end(_options) || !pc_stack.empty(),
795 wasm_parse_exception, "code after function end");
796 };
797
798 while (code.offset() < bounds) {
799 SYS_VM_ASSERT(pc_stack.size() <= detail::get_max_nested_structures(_options), wasm_parse_exception,
800 "nested structures validation failure");
801
802 imap.on_instr_start(code_writer.get_addr(), code.raw());
803
804 switch (*code++) {
805 case opcodes::unreachable: check_in_bounds(); code_writer.emit_unreachable(); op_stack.start_unreachable(); break;
806 case opcodes::nop: code_writer.emit_nop(); break;
807 case opcodes::end: {
808 check_in_bounds();
809 exit_scope();
810 SYS_VM_ASSERT(detail::get_allow_code_after_function_end(_options) ||
811 !pc_stack.empty() || code.offset() == bounds, wasm_parse_exception, "function too short");
812 _nested_checker.on_end(_options);
813 break;
814 }
815 case opcodes::return_: {
816 check_in_bounds();
818 auto branch = code_writer.emit_return(compute_depth_change(
label));
819 handle_branch_target(
label, branch);
820 op_stack.start_unreachable();
821 } break;
822 case opcodes::block: {
829 "Invalid type code in block");
831 code_writer.emit_block();
832 op_stack.push_scope();
833 _nested_checker.on_control(_options);
834 } break;
835 case opcodes::loop: {
842 "Invalid type code in loop");
843 auto pos = code_writer.emit_loop();
844 pc_stack.push_back({op_stack.depth(),
expected_result, types::pseudo,
false, pos});
845 op_stack.push_scope();
846 _nested_checker.on_control(_options);
847 } break;
848 case opcodes::if_: {
849 check_in_bounds();
856 "Invalid type code in if");
857 auto branch = code_writer.emit_if();
858 op_stack.pop(types::i32);
860 op_stack.push_scope();
861 _nested_checker.on_control(_options);
862 } break;
863 case opcodes::else_: {
864 check_in_bounds();
865 auto& old_index = pc_stack.back();
866 SYS_VM_ASSERT(old_index.is_if, wasm_parse_exception,
"else outside if");
867 auto& relocations = std::get<std::vector<branch_t>>(old_index.relocations);
868
869 op_stack.pop(old_index.expected_result);
870 op_stack.pop_scope();
871 op_stack.push_scope();
872
873
874
875 relocations[0] = code_writer.emit_else(relocations[0]);
876 old_index.is_if = false;
877 _nested_checker.on_control(_options);
878 break;
879 }
880 case opcodes::br: {
881 check_in_bounds();
883 auto branch = code_writer.emit_br(compute_depth_change(
label));
884 handle_branch_target(
label, branch);
885 op_stack.start_unreachable();
886 } break;
887 case opcodes::br_if: {
888 check_in_bounds();
890 op_stack.pop(types::i32);
891 auto branch = code_writer.emit_br_if(compute_depth_change(
label));
892 handle_branch_target(
label, branch);
893 } break;
894 case opcodes::br_table: {
895 check_in_bounds();
897 SYS_VM_ASSERT(table_size <= detail::get_max_br_table_elements(_options), wasm_parse_exception,
"Too many labels in br_table");
899 op_stack.pop(types::i32);
900 auto handler = code_writer.emit_br_table(table_size);
901 for (size_t i = 0; i < table_size; i++) {
903 auto branch = handler.emit_case(compute_depth_change(
label));
904 handle_branch_target(
label, branch);
905 uint8_t one_result = pc_stack[pc_stack.size() -
label - 1].label_result;
906 if(i == 0) {
907 result_type = one_result;
908 } else {
909 SYS_VM_ASSERT(result_type == one_result, wasm_parse_exception,
"br_table labels must have the same type");
910 }
911 }
913 auto branch = handler.emit_default(compute_depth_change(
label));
914 handle_branch_target(
label, branch);
915 SYS_VM_ASSERT(table_size == 0 || result_type == pc_stack[pc_stack.size() -
label - 1].label_result,
916 wasm_parse_exception, "br_table labels must have the same type");
917 op_stack.start_unreachable();
918 } break;
919 case opcodes::call: {
920 check_in_bounds();
923 for(
uint32_t i = 0; i < ft.param_types.size(); ++i)
924 op_stack.pop(ft.param_types[ft.param_types.size() - i - 1]);
925 SYS_VM_ASSERT(ft.return_count <= 1, wasm_parse_exception,
"unsupported");
926 if(ft.return_count)
927 op_stack.push(ft.return_type);
928 code_writer.emit_call(ft, funcnum);
929 } break;
930 case opcodes::call_indirect: {
931 check_in_bounds();
933 const func_type& ft = _mod->
types.at(functypeidx);
934 SYS_VM_ASSERT(_mod->
tables.size() > 0, wasm_parse_exception,
"call_indirect requires a table");
935 op_stack.pop(types::i32);
936 for(
uint32_t i = 0; i < ft.param_types.size(); ++i)
937 op_stack.pop(ft.param_types[ft.param_types.size() - i - 1]);
938 SYS_VM_ASSERT(ft.return_count <= 1, wasm_parse_exception,
"unsupported");
939 if(ft.return_count)
940 op_stack.push(ft.return_type);
941 code_writer.emit_call_indirect(ft, functypeidx);
942 SYS_VM_ASSERT(*code == 0, wasm_parse_exception,
"call_indirect must end with 0x00.");
943 code++;
944 break;
945 }
946 case opcodes::drop: check_in_bounds(); code_writer.emit_drop(); op_stack.pop(); break;
947 case opcodes::select: {
948 check_in_bounds();
949 code_writer.emit_select();
950 op_stack.pop(types::i32);
954 op_stack.push(t0 !=
any_type? t0 : t1);
955 } break;
956 case opcodes::get_local: {
958 op_stack.push(local_types[local_idx]);
959 code_writer.emit_get_local(local_idx);
960 } break;
961 case opcodes::set_local: {
962 check_in_bounds();
964 op_stack.pop(local_types[local_idx]);
965 code_writer.emit_set_local(local_idx);
966 } break;
967 case opcodes::tee_local: {
968 check_in_bounds();
970 op_stack.top(local_types[local_idx]);
971 code_writer.emit_tee_local(local_idx);
972 } break;
973 case opcodes::get_global: {
975 op_stack.push(_mod->
globals.at(global_idx).type.content_type);
976 code_writer.emit_get_global(global_idx);
977 } break;
978 case opcodes::set_global: {
979 check_in_bounds();
981 SYS_VM_ASSERT(_mod->
globals.at(global_idx).type.mutability, wasm_parse_exception,
"cannot set const global");
982 op_stack.pop(_mod->
globals.at(global_idx).type.content_type);
983 code_writer.emit_set_global(global_idx);
984 } break;
985#define LOAD_OP(op_name, max_align, type) \
986 case opcodes::op_name: { \
987 check_in_bounds(); \
988 SYS_VM_ASSERT(_mod->memories.size() > 0, wasm_parse_exception, "load requires memory"); \
989 uint32_t alignment = parse_varuint32(code); \
990 uint32_t offset = parse_varuint32(code); \
991 SYS_VM_ASSERT(alignment <= uint32_t(max_align), wasm_parse_exception, "alignment cannot be greater than size."); \
992 SYS_VM_ASSERT(offset <= detail::get_max_memory_offset(_options), wasm_parse_exception, "load offset too large."); \
993 op_stack.pop(types::i32); \
994 op_stack.push(types::type); \
995 code_writer.emit_ ## op_name( alignment, offset ); \
996 } break;
997
1012
1013#undef LOAD_OP
1014
1015#define STORE_OP(op_name, max_align, type) \
1016 case opcodes::op_name: { \
1017 check_in_bounds(); \
1018 SYS_VM_ASSERT(_mod->memories.size() > 0, wasm_parse_exception, "store requires memory"); \
1019 uint32_t alignment = parse_varuint32(code); \
1020 uint32_t offset = parse_varuint32(code); \
1021 SYS_VM_ASSERT(alignment <= uint32_t(max_align), wasm_parse_exception, "alignment cannot be greater than size."); \
1022 SYS_VM_ASSERT(offset <= detail::get_max_memory_offset(_options), wasm_parse_exception, "store offset too large."); \
1023 op_stack.pop(types::type); \
1024 op_stack.pop(types::i32); \
1025 code_writer.emit_ ## op_name( alignment, offset ); \
1026 } break;
1027
1037
1038#undef STORE_OP
1039
1040 case opcodes::current_memory:
1042 op_stack.push(types::i32);
1043 SYS_VM_ASSERT(*code == 0, wasm_parse_exception,
"memory.size must end with 0x00");
1044 code++;
1045 code_writer.emit_current_memory();
1046 break;
1047 case opcodes::grow_memory:
1048 check_in_bounds();
1050 op_stack.pop(types::i32);
1051 op_stack.push(types::i32);
1052 SYS_VM_ASSERT(*code == 0, wasm_parse_exception,
"memory.grow must end with 0x00");
1053 code++;
1054 code_writer.emit_grow_memory();
1055 break;
1056 case opcodes::i32_const: code_writer.emit_i32_const(
parse_varint32(code) ); op_stack.push(types::i32);
break;
1057 case opcodes::i64_const: code_writer.emit_i64_const(
parse_varint64(code) ); op_stack.push(types::i64);
break;
1058 case opcodes::f32_const: {
1060 op_stack.push(types::f32);
1061 } break;
1062 case opcodes::f64_const: {
1064 op_stack.push(types::f64);
1065 } break;
1066
1067#define UNOP(opname) \
1068 case opcodes::opname: check_in_bounds(); code_writer.emit_ ## opname(); op_stack.pop(types::A); op_stack.push(types::R); break;
1069#define BINOP(opname) \
1070 case opcodes::opname: check_in_bounds(); code_writer.emit_ ## opname(); op_stack.pop(types::A); op_stack.pop(types::A); op_stack.push(types::R); break;
1071#define CASTOP(dst, opname, src) \
1072 case opcodes::dst ## _ ## opname ## _ ## src: check_in_bounds(); code_writer.emit_ ## dst ## _ ## opname ## _ ## src(); op_stack.pop(types::src); op_stack.push(types::dst); break;
1073
1074#define R i32
1075#define A i32
1087#undef A
1088#define A i64
1100#undef A
1101#define A f32
1108#undef A
1109#define A f64
1116#undef A
1117#undef R
1118#define R A
1119#define A i32
1138#undef A
1139#define A i64
1158#undef A
1159#define A f32
1174#undef A
1175#define A f64
1190#undef A
1191#undef R
1192
1218
1219#undef CASTOP
1220#undef UNOP
1221#undef BINOP
1222 default:
SYS_VM_ASSERT(
false, wasm_parse_exception,
"Illegal instruction");
1223 }
1224 }
1225 SYS_VM_ASSERT( pc_stack.empty(), wasm_parse_exception,
"function body too long" );
1227 }
decltype(std::declval< Writer >().emit_if()) branch_t
decltype(std::declval< Writer >().emit_end()) label_t
T parse_raw(wasm_code_ptr &code)
static int32_t parse_varint32(wasm_code_ptr &code)
static constexpr uint8_t any_type
static int64_t parse_varint64(wasm_code_ptr &code)
overloaded(Ts...) -> overloaded< Ts... >
float32_t f32_add(float32_t a, float32_t b)
float32_t f32_div(float32_t a, float32_t b)
bool f32_eq(float32_t a, float32_t b)
bool f32_le(float32_t a, float32_t b)
bool f32_lt(float32_t a, float32_t b)
float32_t f32_mul(float32_t a, float32_t b)
float32_t f32_sqrt(float32_t a)
float32_t f32_sub(float32_t a, float32_t b)
float64_t f64_add(float64_t a, float64_t b)
float64_t f64_div(float64_t a, float64_t b)
bool f64_eq(float64_t a, float64_t b)
bool f64_le(float64_t a, float64_t b)
bool f64_lt(float64_t a, float64_t b)
float64_t f64_mul(float64_t a, float64_t b)
float64_t f64_sqrt(float64_t a)
float64_t f64_sub(float64_t a, float64_t b)
const unsigned char expected_result[]
auto & get_function_type(uint32_t index) const
#define CASTOP(dst, opname, src)