Skip to content

Commit 96ebc37

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 96ebc37

6 files changed

Lines changed: 164 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: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,10 +3307,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
33073307
break;
33083308

33093309
case WASM_OP_CALL:
3310+
#if WASM_ENABLE_TAIL_CALL != 0
3311+
case WASM_OP_RETURN_CALL:
3312+
#endif
33103313
skip_leb_uint32(p, p_end); /* funcidx */
33113314
break;
33123315

33133316
case WASM_OP_CALL_INDIRECT:
3317+
#if WASM_ENABLE_TAIL_CALL != 0
3318+
case WASM_OP_RETURN_CALL_INDIRECT:
3319+
#endif
33143320
skip_leb_uint32(p, p_end); /* typeidx */
33153321
CHECK_BUF(p, p_end, 1);
33163322
u8 = read_uint8(p); /* 0x00 */
@@ -5812,6 +5818,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
58125818
}
58135819

58145820
case WASM_OP_CALL:
5821+
#if WASM_ENABLE_TAIL_CALL != 0
5822+
case WASM_OP_RETURN_CALL:
5823+
#endif
58155824
{
58165825
WASMType *func_type;
58175826
uint32 func_idx;
@@ -5844,22 +5853,53 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
58445853
}
58455854
}
58465855

5847-
for (i = 0; i < func_type->result_count; i++) {
5848-
PUSH_TYPE(func_type->types[func_type->param_count + i]);
5856+
#if WASM_ENABLE_TAIL_CALL != 0
5857+
if (opcode == WASM_OP_CALL) {
5858+
#endif
5859+
for (i = 0; i < func_type->result_count; i++) {
5860+
PUSH_TYPE(func_type->types[func_type->param_count + i]);
58495861
#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]);
5862+
/* Here we emit each return value's dynamic_offset. But in fact
5863+
* these offsets are continuous, so interpreter only need to get
5864+
* the first return value's offset.
5865+
*/
5866+
PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
58555867
#endif
5868+
}
5869+
#if WASM_ENABLE_TAIL_CALL != 0
58565870
}
5857-
5871+
else {
5872+
char *type_str[] = { "f64", "f32", "i64", "i32" };
5873+
uint8 type;
5874+
if (func_type->result_count != func->func_type->result_count) {
5875+
set_error_buf_v(error_buf, error_buf_size,
5876+
"%s%u%s", "type mismatch: expect ",
5877+
func->func_type->result_count,
5878+
" return values but got other");
5879+
goto fail;
5880+
}
5881+
for (i = 0; i < func_type->result_count; i++) {
5882+
type = func->func_type->types[func->func_type->param_count + i];
5883+
if (func_type->types[func_type->param_count + i] != type) {
5884+
set_error_buf_v(error_buf, error_buf_size,
5885+
"%s%s%s", "type mismatch: expect ",
5886+
type_str[type - VALUE_TYPE_F64],
5887+
" but got other");
5888+
goto fail;
5889+
}
5890+
}
5891+
RESET_STACK();
5892+
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
5893+
}
5894+
#endif
58585895
func->has_op_func_call = true;
58595896
break;
58605897
}
58615898

58625899
case WASM_OP_CALL_INDIRECT:
5900+
#if WASM_ENABLE_TAIL_CALL != 0
5901+
case WASM_OP_RETURN_CALL_INDIRECT:
5902+
#endif
58635903
{
58645904
int32 idx;
58655905
WASMType *func_type;
@@ -5904,13 +5944,40 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
59045944
}
59055945
}
59065946

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

core/iwasm/interpreter/wasm_mini_loader.c

Lines changed: 35 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,35 @@ 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+
#if WASM_ENABLE_TAIL_CALL != 0
4603+
handle_op_return:
4604+
{
4605+
#endif
4606+
int32 idx;
4607+
uint8 ret_type;
4608+
for (idx = (int32)func->func_type->result_count - 1; idx >= 0; idx--) {
4609+
ret_type = *(func->func_type->types
4610+
+ func->func_type->param_count + idx);
4611+
POP_TYPE(ret_type);
46024612
#if WASM_ENABLE_FAST_INTERP != 0
46034613
/* emit the offset after return opcode */
46044614
POP_OFFSET_TYPE(ret_type);
46054615
#endif
4606-
}
4616+
}
46074617

4608-
RESET_STACK();
4609-
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
4618+
RESET_STACK();
4619+
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
46104620

4611-
break;
4621+
break;
4622+
#if WASM_ENABLE_TAIL_CALL != 0
4623+
}
4624+
#endif
46124625
}
46134626

46144627
case WASM_OP_CALL:
4628+
#if WASM_ENABLE_TAIL_CALL != 0
4629+
case WASM_OP_RETURN_CALL:
4630+
#endif
46154631
{
46164632
WASMType *func_type;
46174633
uint32 func_idx;
@@ -4653,10 +4669,16 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
46534669
}
46544670

46554671
func->has_op_func_call = true;
4672+
#if WASM_ENABLE_TAIL_CALL != 0
4673+
if (opcode == WASM_OP_RETURN_CALL) { goto handle_op_return; }
4674+
#endif
46564675
break;
46574676
}
46584677

46594678
case WASM_OP_CALL_INDIRECT:
4679+
#if WASM_ENABLE_TAIL_CALL != 0
4680+
case WASM_OP_RETURN_CALL_INDIRECT:
4681+
#endif
46604682
{
46614683
int32 idx;
46624684
WASMType *func_type;
@@ -4698,6 +4720,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
46984720
}
46994721

47004722
func->has_op_func_call = true;
4723+
#if WASM_ENABLE_TAIL_CALL != 0
4724+
if (opcode == WASM_OP_RETURN_CALL_INDIRECT) { goto handle_op_return; }
4725+
#endif
47014726
break;
47024727
}
47034728

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)