Skip to content

Commit a28deff

Browse files
committed
Add the tail-call feature support for classic-interp
Signed-off-by: Xiaokang Qin <xiaokang.qxk@antgroup.com>
1 parent a7e7711 commit a28deff

6 files changed

Lines changed: 158 additions & 32 deletions

File tree

build-scripts/config_common.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,8 @@ if (WAMR_BUILD_CUSTOM_NAME_SECTION EQUAL 1)
173173
add_definitions (-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
174174
message (" Custom name section enabled")
175175
endif ()
176+
if (WAMR_BUILD_TAIL_CALL EQUAL 1)
177+
add_definitions (-DWASM_ENABLE_TAIL_CALL=1)
178+
message (" Tail call enabled")
179+
endif ()
176180

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,11 +1285,33 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
12851285
cur_func = module->functions + fidx;
12861286
goto call_func_from_interp;
12871287

1288+
#if WASM_ENABLE_TAIL_CALL != 0
1289+
HANDLE_OP (WASM_OP_RETURN_CALL):
1290+
#if WASM_ENABLE_THREAD_MGR != 0
1291+
CHECK_SUSPEND_FLAGS();
1292+
#endif
1293+
read_leb_uint32(frame_ip, frame_ip_end, fidx);
1294+
#if WASM_ENABLE_MULTI_MODULE != 0
1295+
if (fidx >= module->function_count) {
1296+
wasm_set_exception(module, "unknown function");
1297+
goto got_exception;
1298+
}
1299+
#endif
1300+
cur_func = module->functions + fidx;
1301+
1302+
goto call_func_from_return_call;
1303+
#endif /* WASM_ENABLE_TAIL_CALL */
1304+
12881305
HANDLE_OP (WASM_OP_CALL_INDIRECT):
1306+
#if WASM_ENABLE_TAIL_CALL != 0
1307+
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
1308+
#endif
12891309
{
12901310
WASMType *cur_type, *cur_func_type;
12911311
WASMTableInstance *cur_table_inst;
1292-
1312+
#if WASM_ENABLE_TAIL_CALL != 0
1313+
opcode = *(frame_ip - 1);
1314+
#endif
12931315
#if WASM_ENABLE_THREAD_MGR != 0
12941316
CHECK_SUSPEND_FLAGS();
12951317
#endif
@@ -1352,7 +1374,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
13521374
wasm_set_exception(module, "indirect call type mismatch");
13531375
goto got_exception;
13541376
}
1355-
1377+
#if WASM_ENABLE_TAIL_CALL != 0
1378+
if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
1379+
goto call_func_from_return_call;
1380+
#endif
13561381
goto call_func_from_interp;
13571382
}
13581383

@@ -3121,8 +3146,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
31213146
HANDLE_OP (WASM_OP_UNUSED_0x08):
31223147
HANDLE_OP (WASM_OP_UNUSED_0x09):
31233148
HANDLE_OP (WASM_OP_UNUSED_0x0a):
3124-
HANDLE_OP (WASM_OP_UNUSED_0x12):
3125-
HANDLE_OP (WASM_OP_UNUSED_0x13):
3149+
#if WASM_ENABLE_TAIL_CALL == 0
3150+
HANDLE_OP (WASM_OP_RETURN_CALL):
3151+
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
3152+
#endif
31263153
HANDLE_OP (WASM_OP_UNUSED_0x14):
31273154
HANDLE_OP (WASM_OP_UNUSED_0x15):
31283155
HANDLE_OP (WASM_OP_UNUSED_0x16):
@@ -3151,6 +3178,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
31513178
FETCH_OPCODE_AND_DISPATCH ();
31523179
#endif
31533180

3181+
#if WASM_ENABLE_TAIL_CALL != 0
3182+
call_func_from_return_call:
3183+
POP(cur_func->param_cell_num);
3184+
FREE_FRAME(exec_env, frame);
3185+
word_copy(frame->lp, frame_sp, cur_func->param_cell_num);
3186+
wasm_exec_env_set_cur_frame(exec_env,
3187+
(WASMRuntimeFrame *)prev_frame);
3188+
goto call_func_from_entry;
3189+
#endif
31543190
call_func_from_interp:
31553191
/* Only do the copy when it's called from interpreter. */
31563192
{

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3125,8 +3125,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
31253125
HANDLE_OP (WASM_OP_UNUSED_0x08):
31263126
HANDLE_OP (WASM_OP_UNUSED_0x09):
31273127
HANDLE_OP (WASM_OP_UNUSED_0x0a):
3128-
HANDLE_OP (WASM_OP_UNUSED_0x12):
3129-
HANDLE_OP (WASM_OP_UNUSED_0x13):
3128+
HANDLE_OP (WASM_OP_RETURN_CALL):
3129+
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
31303130
HANDLE_OP (WASM_OP_UNUSED_0x14):
31313131
HANDLE_OP (WASM_OP_UNUSED_0x15):
31323132
HANDLE_OP (WASM_OP_UNUSED_0x16):

core/iwasm/interpreter/wasm_loader.c

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,10 +3307,12 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
33073307
break;
33083308

33093309
case WASM_OP_CALL:
3310+
case WASM_OP_RETURN_CALL:
33103311
skip_leb_uint32(p, p_end); /* funcidx */
33113312
break;
33123313

33133314
case WASM_OP_CALL_INDIRECT:
3315+
case WASM_OP_RETURN_CALL_INDIRECT:
33143316
skip_leb_uint32(p, p_end); /* typeidx */
33153317
CHECK_BUF(p, p_end, 1);
33163318
u8 = read_uint8(p); /* 0x00 */
@@ -5795,6 +5797,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
57955797
{
57965798
int32 idx;
57975799
uint8 ret_type;
5800+
57985801
for (idx = (int32)func->func_type->result_count - 1; idx >= 0; idx--) {
57995802
ret_type = *(func->func_type->types
58005803
+ func->func_type->param_count + idx);
@@ -5812,6 +5815,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
58125815
}
58135816

58145817
case WASM_OP_CALL:
5818+
#if WASM_ENABLE_TAIL_CALL != 0
5819+
case WASM_OP_RETURN_CALL:
5820+
#endif
58155821
{
58165822
WASMType *func_type;
58175823
uint32 func_idx;
@@ -5844,22 +5850,53 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
58445850
}
58455851
}
58465852

5847-
for (i = 0; i < func_type->result_count; i++) {
5848-
PUSH_TYPE(func_type->types[func_type->param_count + i]);
5853+
#if WASM_ENABLE_TAIL_CALL != 0
5854+
if (opcode == WASM_OP_CALL) {
5855+
#endif
5856+
for (i = 0; i < func_type->result_count; i++) {
5857+
PUSH_TYPE(func_type->types[func_type->param_count + i]);
58495858
#if WASM_ENABLE_FAST_INTERP != 0
5850-
/* Here we emit each return value's dynamic_offset. But in fact
5851-
* these offsets are continuous, so interpreter only need to get
5852-
* the first return value's offset.
5853-
*/
5854-
PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
5859+
/* Here we emit each return value's dynamic_offset. But in fact
5860+
* these offsets are continuous, so interpreter only need to get
5861+
* the first return value's offset.
5862+
*/
5863+
PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
58555864
#endif
5865+
}
5866+
#if WASM_ENABLE_TAIL_CALL != 0
58565867
}
5857-
5868+
else {
5869+
char *type_str[] = { "f64", "f32", "i64", "i32" };
5870+
uint8 type;
5871+
if (func_type->result_count != func->func_type->result_count) {
5872+
set_error_buf_v(error_buf, error_buf_size,
5873+
"%s%u%s", "type mismatch: expect ",
5874+
func->func_type->result_count,
5875+
" return values but got other");
5876+
goto fail;
5877+
}
5878+
for (i = 0; i < func_type->result_count; i++) {
5879+
type = func->func_type->types[func->func_type->param_count + i];
5880+
if (func_type->types[func_type->param_count + i] != type) {
5881+
set_error_buf_v(error_buf, error_buf_size,
5882+
"%s%s%s", "type mismatch: expect ",
5883+
type_str[type - VALUE_TYPE_F64],
5884+
" but got other");
5885+
goto fail;
5886+
}
5887+
}
5888+
RESET_STACK();
5889+
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
5890+
}
5891+
#endif
58585892
func->has_op_func_call = true;
58595893
break;
58605894
}
58615895

58625896
case WASM_OP_CALL_INDIRECT:
5897+
#if WASM_ENABLE_TAIL_CALL != 0
5898+
case WASM_OP_RETURN_CALL_INDIRECT:
5899+
#endif
58635900
{
58645901
int32 idx;
58655902
WASMType *func_type;
@@ -5904,13 +5941,40 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
59045941
}
59055942
}
59065943

5907-
for (i = 0; i < func_type->result_count; i++) {
5908-
PUSH_TYPE(func_type->types[func_type->param_count + i]);
5944+
#if WASM_ENABLE_TAIL_CALL != 0
5945+
if (opcode == WASM_OP_CALL) {
5946+
#endif
5947+
for (i = 0; i < func_type->result_count; i++) {
5948+
PUSH_TYPE(func_type->types[func_type->param_count + i]);
59095949
#if WASM_ENABLE_FAST_INTERP != 0
5910-
PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
5950+
PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
59115951
#endif
5952+
}
5953+
#if WASM_ENABLE_TAIL_CALL != 0
59125954
}
5913-
5955+
else {
5956+
char *type_str[] = { "f64", "f32", "i64", "i32" };
5957+
uint8 type;
5958+
if (func_type->result_count != func->func_type->result_count) {
5959+
set_error_buf_v(error_buf, error_buf_size,
5960+
"%s%u%s", "type mismatch: expect ",
5961+
func->func_type->result_count,
5962+
" return values but got other");
5963+
goto fail;
5964+
}
5965+
for (i = 0; i < func_type->result_count; i++) {
5966+
type = func->func_type->types[func->func_type->param_count + i];
5967+
if (func_type->types[func_type->param_count + i] != type)
5968+
set_error_buf_v(error_buf, error_buf_size, "%s%s%s",
5969+
"type mismatch: expect ",
5970+
type_str[type - VALUE_TYPE_F64],
5971+
" but got other");
5972+
goto fail;
5973+
}
5974+
RESET_STACK();
5975+
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
5976+
}
5977+
#endif
59145978
func->has_op_func_call = true;
59155979
break;
59165980
}

core/iwasm/interpreter/wasm_mini_loader.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2235,10 +2235,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
22352235
break;
22362236

22372237
case WASM_OP_CALL:
2238+
#if WASM_ENABLE_TAIL_CALL != 0
2239+
case WASM_OP_RETURN_CALL:
2240+
#endif
22382241
skip_leb_uint32(p, p_end); /* funcidx */
22392242
break;
22402243

22412244
case WASM_OP_CALL_INDIRECT:
2245+
#if WASM_ENABLE_TAIL_CALL != 0
2246+
case WASM_OP_RETURN_CALL_INDIRECT:
2247+
#endif
22422248
skip_leb_uint32(p, p_end); /* typeidx */
22432249
CHECK_BUF(p, p_end, 1);
22442250
u8 = read_uint8(p); /* 0x00 */
@@ -4593,25 +4599,32 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
45934599

45944600
case WASM_OP_RETURN:
45954601
{
4596-
int32 idx;
4597-
uint8 ret_type;
4598-
for (idx = (int32)func->func_type->result_count - 1; idx >= 0; idx--) {
4599-
ret_type = *(func->func_type->types
4600-
+ func->func_type->param_count + idx);
4601-
POP_TYPE(ret_type);
4602+
handle_op_return:
4603+
{
4604+
int32 idx;
4605+
uint8 ret_type;
4606+
for (idx = (int32)func->func_type->result_count - 1; idx >= 0;
4607+
idx--) {
4608+
ret_type = *(func->func_type->types
4609+
+ func->func_type->param_count + idx);
4610+
POP_TYPE(ret_type);
46024611
#if WASM_ENABLE_FAST_INTERP != 0
46034612
/* emit the offset after return opcode */
46044613
POP_OFFSET_TYPE(ret_type);
46054614
#endif
4606-
}
4615+
}
46074616

4608-
RESET_STACK();
4609-
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
4617+
RESET_STACK();
4618+
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
46104619

4611-
break;
4620+
break;
4621+
}
46124622
}
46134623

46144624
case WASM_OP_CALL:
4625+
#if WASM_ENABLE_TAIL_CALL != 0
4626+
case WASM_OP_RETURN_CALL:
4627+
#endif
46154628
{
46164629
WASMType *func_type;
46174630
uint32 func_idx;
@@ -4653,10 +4666,16 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
46534666
}
46544667

46554668
func->has_op_func_call = true;
4669+
#if WASM_ENABLE_TAIL_CALL != 0
4670+
if (opcode == WASM_OP_RETURN_CALL) { goto handle_op_return; }
4671+
#endif
46564672
break;
46574673
}
46584674

46594675
case WASM_OP_CALL_INDIRECT:
4676+
#if WASM_ENABLE_TAIL_CALL != 0
4677+
case WASM_OP_RETURN_CALL_INDIRECT:
4678+
#endif
46604679
{
46614680
int32 idx;
46624681
WASMType *func_type;
@@ -4698,6 +4717,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
46984717
}
46994718

47004719
func->has_op_func_call = true;
4720+
#if WASM_ENABLE_TAIL_CALL != 0
4721+
if (opcode == WASM_OP_RETURN_CALL_INDIRECT) { goto handle_op_return; }
4722+
#endif
47014723
break;
47024724
}
47034725

core/iwasm/interpreter/wasm_opcode.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ typedef enum WASMOpcode {
3434
WASM_OP_RETURN = 0x0f, /* return */
3535
WASM_OP_CALL = 0x10, /* call */
3636
WASM_OP_CALL_INDIRECT = 0x11, /* call_indirect */
37+
WASM_OP_RETURN_CALL = 0x12, /* return_call */
38+
WASM_OP_RETURN_CALL_INDIRECT = 0x13, /* return_call_indirect */
3739

38-
WASM_OP_UNUSED_0x12 = 0x12,
39-
WASM_OP_UNUSED_0x13 = 0x13,
4040
WASM_OP_UNUSED_0x14 = 0x14,
4141
WASM_OP_UNUSED_0x15 = 0x15,
4242
WASM_OP_UNUSED_0x16 = 0x16,
@@ -403,8 +403,8 @@ static type _name[WASM_INSTRUCTION_NUM] = { \
403403
HANDLE_OPCODE (WASM_OP_RETURN), /* 0x0f */ \
404404
HANDLE_OPCODE (WASM_OP_CALL), /* 0x10 */ \
405405
HANDLE_OPCODE (WASM_OP_CALL_INDIRECT), /* 0x11 */ \
406-
HANDLE_OPCODE (WASM_OP_UNUSED_0x12), /* 0x12 */ \
407-
HANDLE_OPCODE (WASM_OP_UNUSED_0x13), /* 0x13 */ \
406+
HANDLE_OPCODE (WASM_OP_RETURN_CALL), /* 0x12 */ \
407+
HANDLE_OPCODE (WASM_OP_RETURN_CALL_INDIRECT), /* 0x13 */ \
408408
HANDLE_OPCODE (WASM_OP_UNUSED_0x14), /* 0x14 */ \
409409
HANDLE_OPCODE (WASM_OP_UNUSED_0x15), /* 0x15 */ \
410410
HANDLE_OPCODE (WASM_OP_UNUSED_0x16), /* 0x16 */ \

0 commit comments

Comments
 (0)