Skip to content

Commit 64bf9a5

Browse files
committed
make insn.c a bit more self contained
unexport instruction tables
1 parent 62ba842 commit 64bf9a5

File tree

6 files changed

+178
-184
lines changed

6 files changed

+178
-184
lines changed

lib/context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,7 @@ const uint8_t *pc2ptr(const struct module *m, uint32_t pc) __purefunc;
6767
int resulttype_alloc(struct mem_context *mctx, uint32_t ntypes,
6868
const enum valtype *types, struct resulttype **resultp);
6969
void resulttype_free(struct mem_context *mctx, struct resulttype *p);
70+
int fetch_process_next_insn(const uint8_t **pp, const uint8_t *ep,
71+
struct context *ctx);
7072

7173
__END_EXTERN_C

lib/exec.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,8 +1403,6 @@ bool
14031403
skip_expr(const uint8_t **pp, bool goto_else)
14041404
{
14051405
const uint8_t *p = *pp;
1406-
struct context ctx;
1407-
memset(&ctx, 0, sizeof(ctx));
14081406
uint32_t block_level = 0;
14091407
if (goto_else) {
14101408
assert(*p == FRAME_OP_IF);
@@ -1413,16 +1411,7 @@ skip_expr(const uint8_t **pp, bool goto_else)
14131411
*p == FRAME_OP_IF || *p == FRAME_OP_TRY_TABLE);
14141412
}
14151413
while (true) {
1416-
uint32_t op = *p++;
1417-
const struct instruction_desc *desc = &instructions[op];
1418-
if (desc->next_table != NULL) {
1419-
uint32_t op2 = read_leb_u32_nocheck(&p);
1420-
desc = &desc->next_table[op2];
1421-
}
1422-
assert(desc->process != NULL);
1423-
xlog_trace_insn("skipping %s", desc->name);
1424-
int ret = desc->process(&p, NULL, &ctx);
1425-
assert(ret == 0);
1414+
uint32_t op = read_insn(&p);
14261415
switch (op) {
14271416
case FRAME_OP_BLOCK:
14281417
case FRAME_OP_LOOP:

lib/expr.c

Lines changed: 0 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -19,125 +19,6 @@
1919
#include "validation.h"
2020
#include "xlog.h"
2121

22-
static int
23-
read_op(const uint8_t **pp, const uint8_t *ep,
24-
const struct instruction_desc **descp, struct validation_context *vctx)
25-
{
26-
const struct instruction_desc *table = instructions;
27-
size_t table_size = instructions_size;
28-
const char *group = "base";
29-
int ret;
30-
uint8_t inst8;
31-
uint32_t inst;
32-
33-
#if defined(TOYWASM_ENABLE_TRACING_INSN)
34-
uint32_t pc = ptr2pc(vctx->module, *pp);
35-
#endif
36-
ret = read_u8(pp, ep, &inst8);
37-
if (ret != 0) {
38-
goto fail;
39-
}
40-
inst = inst8;
41-
while (true) {
42-
const struct instruction_desc *desc;
43-
if (inst >= table_size) {
44-
goto invalid_inst;
45-
}
46-
desc = &table[inst];
47-
if (desc->next_table != NULL) {
48-
table = desc->next_table;
49-
table_size = desc->next_table_size;
50-
group = desc->name;
51-
/*
52-
* Note: wasm "sub" opcodes are LEB128.
53-
* cf. https://github.com/WebAssembly/spec/issues/1228
54-
*/
55-
ret = read_leb_u32(pp, ep, &inst);
56-
if (ret != 0) {
57-
goto fail;
58-
}
59-
continue;
60-
}
61-
if (desc->name == NULL) {
62-
invalid_inst:
63-
ret = validation_failure(
64-
vctx,
65-
"unimplemented instruction %02" PRIx32
66-
" in group '%s'",
67-
inst, group);
68-
goto fail;
69-
}
70-
*descp = desc;
71-
xlog_trace_insn("inst %06" PRIx32 " %s", pc, desc->name);
72-
break;
73-
}
74-
ret = 0;
75-
fail:
76-
return ret;
77-
}
78-
79-
static int
80-
check_const_instruction(const struct instruction_desc *desc,
81-
struct validation_context *vctx)
82-
{
83-
if (vctx->const_expr && (desc->flags & INSN_FLAG_CONST) == 0) {
84-
return validation_failure(vctx,
85-
"instruction \"%s\" not "
86-
"allowed in a const expr",
87-
desc->name);
88-
}
89-
return 0;
90-
}
91-
92-
#if defined(TOYWASM_USE_SEPARATE_VALIDATE)
93-
int
94-
fetch_validate_next_insn(const uint8_t *p, const uint8_t *ep,
95-
struct validation_context *vctx)
96-
{
97-
xassert(ep != NULL);
98-
const struct instruction_desc *desc;
99-
int ret;
100-
101-
ret = read_op(&p, ep, &desc, vctx);
102-
if (ret != 0) {
103-
goto fail;
104-
}
105-
ret = check_const_instruction(desc, vctx);
106-
if (ret != 0) {
107-
goto fail;
108-
}
109-
#if defined(TOYWASM_USE_TAILCALL)
110-
__musttail
111-
#endif
112-
return desc->validate(p, ep, vctx);
113-
fail:
114-
return ret;
115-
}
116-
#else
117-
int
118-
fetch_process_next_insn(const uint8_t **pp, const uint8_t *ep,
119-
struct context *ctx)
120-
{
121-
xassert(ep != NULL);
122-
struct validation_context *vctx = ctx->validation;
123-
124-
const struct instruction_desc *desc;
125-
int ret;
126-
127-
ret = read_op(pp, ep, &desc, vctx);
128-
if (ret != 0) {
129-
goto fail;
130-
}
131-
ret = check_const_instruction(desc, vctx);
132-
if (ret != 0) {
133-
goto fail;
134-
}
135-
return desc->process(pp, ep, ctx);
136-
fail:
137-
return ret;
138-
}
139-
#endif /* defined(TOYWASM_USE_SEPARATE_VALIDATE) */
140-
14122
static int
14223
read_expr_common(const uint8_t **pp, const uint8_t *ep, struct expr *expr,
14324
uint32_t nlocals, const struct localchunk *locals,

lib/expr_parser.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,7 @@ void
2222
parse_expr(const uint8_t **pp, struct parse_expr_context *pctx)
2323
{
2424
const uint8_t *p = *pp;
25-
struct context ctx;
26-
memset(&ctx, 0, sizeof(ctx));
27-
uint32_t op = *p++;
28-
const struct instruction_desc *desc = &instructions[op];
29-
if (desc->next_table != NULL) {
30-
uint32_t op2 = read_leb_u32_nocheck(&p);
31-
desc = &desc->next_table[op2];
32-
}
33-
assert(desc->process != NULL);
34-
int ret = desc->process(&p, NULL, &ctx);
35-
assert(ret == 0);
25+
uint32_t op = read_insn(&p);
3626
switch (op) {
3727
case FRAME_OP_BLOCK:
3828
case FRAME_OP_LOOP:

lib/insn.c

Lines changed: 173 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,37 @@
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

Comments
 (0)