2727#include "validation.h"
2828#include "xlog.h"
2929
30+ struct exec_instruction_desc {
31+ /*
32+ * fetch_exec is called after fetching the first byte of
33+ * the instrution. '*p' points to the second byte.
34+ * it fetches and decodes the rest of the instrution,
35+ * and then executes it.
36+ */
37+ int (* fetch_exec )(const uint8_t * p , struct cell * stack ,
38+ struct exec_context * ctx );
39+ };
40+
41+ struct instruction_desc {
42+ const char * name ;
43+ int (* process )(const uint8_t * * pp , const uint8_t * ep ,
44+ struct context * ctx );
45+ #if defined(TOYWASM_USE_SEPARATE_VALIDATE )
46+ int (* validate )(const uint8_t * p , const uint8_t * ep ,
47+ struct validation_context * vctx );
48+ #endif
49+ const struct instruction_desc * next_table ;
50+ unsigned int next_table_size ;
51+ unsigned int flags ;
52+ };
53+
54+ #define INSN_FLAG_CONST 1
55+ #if defined(TOYWASM_ENABLE_WASM_EXTENDED_CONST )
56+ #define INSN_FLAG_EXTENDED_CONST INSN_FLAG_CONST
57+ #else
58+ #define INSN_FLAG_EXTENDED_CONST 0
59+ #endif
60+
3061/*
3162 * https://webassembly.github.io/spec/core/binary/instructions.html
3263 * https://webassembly.github.io/spec/core/appendix/index-instructions.html
@@ -957,7 +988,7 @@ const static struct instruction_desc instructions_fe[] = {
957988 * 0xff below doesn't waste much space. on the other hand, it might allow
958989 * a few optimizations in the parser by allowing full uint8_t index.
959990 */
960- const struct instruction_desc instructions [256 ] = {
991+ static const struct instruction_desc instructions [256 ] = {
961992#include "insn_list_base.h"
962993#if defined(TOYWASM_ENABLE_WASM_TAILCALL )
963994#include "insn_list_tailcall.h"
@@ -967,7 +998,7 @@ const struct instruction_desc instructions[256] = {
967998#endif /* defined(TOYWASM_ENABLE_WASM_EXCEPTION_HANDLING) */
968999};
9691000
970- const size_t instructions_size = ARRAYCOUNT (instructions );
1001+ static const size_t instructions_size = ARRAYCOUNT (instructions );
9711002
9721003#if defined(TOYWASM_USE_SEPARATE_EXECUTE ) && \
9731004 defined(TOYWASM_ENABLE_TRACING_INSN )
@@ -1031,3 +1062,143 @@ fetch_exec_next_insn(const uint8_t *p, struct cell *stack,
10311062 return desc -> process (& ctx -> p , NULL , & common_ctx );
10321063#endif
10331064}
1065+
1066+ uint32_t
1067+ read_insn (const uint8_t * * pp )
1068+ {
1069+ const uint8_t * p = * pp ;
1070+ struct context ctx ;
1071+ memset (& ctx , 0 , sizeof (ctx ));
1072+
1073+ uint32_t op = * p ++ ;
1074+ const struct instruction_desc * desc = & instructions [op ];
1075+ if (desc -> next_table != NULL ) {
1076+ uint32_t op2 = read_leb_u32_nocheck (& p );
1077+ desc = & desc -> next_table [op2 ];
1078+ }
1079+ assert (desc -> process != NULL );
1080+ int ret = desc -> process (& p , NULL , & ctx );
1081+ assert (ret == 0 );
1082+ * pp = p ;
1083+ return op ;
1084+ }
1085+
1086+ static int
1087+ read_insn_and_get_desc (const uint8_t * * pp , const uint8_t * ep ,
1088+ const struct instruction_desc * * descp ,
1089+ struct validation_context * vctx )
1090+ {
1091+ const struct instruction_desc * table = instructions ;
1092+ size_t table_size = instructions_size ;
1093+ const char * group = "base" ;
1094+ int ret ;
1095+ uint8_t inst8 ;
1096+ uint32_t inst ;
1097+
1098+ #if defined(TOYWASM_ENABLE_TRACING_INSN )
1099+ uint32_t pc = ptr2pc (vctx -> module , * pp );
1100+ #endif
1101+ ret = read_u8 (pp , ep , & inst8 );
1102+ if (ret != 0 ) {
1103+ goto fail ;
1104+ }
1105+ inst = inst8 ;
1106+ while (true) {
1107+ const struct instruction_desc * desc ;
1108+ if (inst >= table_size ) {
1109+ goto invalid_inst ;
1110+ }
1111+ desc = & table [inst ];
1112+ if (desc -> next_table != NULL ) {
1113+ table = desc -> next_table ;
1114+ table_size = desc -> next_table_size ;
1115+ group = desc -> name ;
1116+ /*
1117+ * Note: wasm "sub" opcodes are LEB128.
1118+ * cf. https://github.com/WebAssembly/spec/issues/1228
1119+ */
1120+ ret = read_leb_u32 (pp , ep , & inst );
1121+ if (ret != 0 ) {
1122+ goto fail ;
1123+ }
1124+ continue ;
1125+ }
1126+ if (desc -> name == NULL ) {
1127+ invalid_inst :
1128+ ret = validation_failure (
1129+ vctx ,
1130+ "unimplemented instruction %02" PRIx32
1131+ " in group '%s'" ,
1132+ inst , group );
1133+ goto fail ;
1134+ }
1135+ * descp = desc ;
1136+ xlog_trace_insn ("inst %06" PRIx32 " %s" , pc , desc -> name );
1137+ break ;
1138+ }
1139+ ret = 0 ;
1140+ fail :
1141+ return ret ;
1142+ }
1143+
1144+ static int
1145+ check_const_instruction (const struct instruction_desc * desc ,
1146+ struct validation_context * vctx )
1147+ {
1148+ if (vctx -> const_expr && (desc -> flags & INSN_FLAG_CONST ) == 0 ) {
1149+ return validation_failure (vctx ,
1150+ "instruction \"%s\" not "
1151+ "allowed in a const expr" ,
1152+ desc -> name );
1153+ }
1154+ return 0 ;
1155+ }
1156+
1157+ #if defined(TOYWASM_USE_SEPARATE_VALIDATE )
1158+ int
1159+ fetch_validate_next_insn (const uint8_t * p , const uint8_t * ep ,
1160+ struct validation_context * vctx )
1161+ {
1162+ xassert (ep != NULL );
1163+ const struct instruction_desc * desc ;
1164+ int ret ;
1165+
1166+ ret = read_insn_and_get_desc (& p , ep , & desc , vctx );
1167+ if (ret != 0 ) {
1168+ goto fail ;
1169+ }
1170+ ret = check_const_instruction (desc , vctx );
1171+ if (ret != 0 ) {
1172+ goto fail ;
1173+ }
1174+ #if defined(TOYWASM_USE_TAILCALL )
1175+ __musttail
1176+ #endif
1177+ return desc -> validate (p , ep , vctx );
1178+ fail :
1179+ return ret ;
1180+ }
1181+ #else
1182+ int
1183+ fetch_process_next_insn (const uint8_t * * pp , const uint8_t * ep ,
1184+ struct context * ctx )
1185+ {
1186+ xassert (ep != NULL );
1187+ struct validation_context * vctx = ctx -> validation ;
1188+
1189+ const struct instruction_desc * desc ;
1190+ int ret ;
1191+
1192+ ret = read_insn_and_get_desc (pp , ep , & desc , vctx );
1193+ if (ret != 0 ) {
1194+ goto fail ;
1195+ }
1196+ ret = check_const_instruction (desc , vctx );
1197+ if (ret != 0 ) {
1198+ goto fail ;
1199+ }
1200+ return desc -> process (pp , ep , ctx );
1201+ fail :
1202+ return ret ;
1203+ }
1204+ #endif /* defined(TOYWASM_USE_SEPARATE_VALIDATE) */
0 commit comments