Skip to content

Commit c83a571

Browse files
authored
Add the fast-interp tail call support (#409)
And also fix one bug in loader for tail-call Signed-off-by: Xiaokang Qin <[email protected]>
1 parent dc53653 commit c83a571

File tree

4 files changed

+74
-4
lines changed

4 files changed

+74
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ iwasm VM core
3535
- [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory)
3636
- [Multi-value](https://github.com/WebAssembly/multi-value)
3737
- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api)
38+
- [Tail-call](https://github.com/WebAssembly/tail-call)
3839

3940
### Performance and memory usage
4041
The WAMR performance, footprint and memory usage data are available at the [performance](../../wiki/Performance) wiki page.

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,10 +1301,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
13011301
goto return_func;
13021302

13031303
HANDLE_OP (WASM_OP_CALL_INDIRECT):
1304+
#if WASM_ENABLE_TAIL_CALL != 0
1305+
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
1306+
#endif
13041307
{
13051308
WASMType *cur_type, *cur_func_type;
13061309
WASMTableInstance *cur_table_inst;
13071310

1311+
#if WASM_ENABLE_TAIL_CALL != 0
1312+
GET_OPCODE();
1313+
#endif
13081314
#if WASM_ENABLE_THREAD_MGR != 0
13091315
CHECK_SUSPEND_FLAGS();
13101316
#endif
@@ -1360,6 +1366,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
13601366
wasm_set_exception(module, "indirect call type mismatch");
13611367
goto got_exception;
13621368
}
1369+
#if WASM_ENABLE_TAIL_CALL != 0
1370+
if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
1371+
goto call_func_from_return_call;
1372+
#endif
13631373
goto call_func_from_interp;
13641374
}
13651375

@@ -3112,6 +3122,22 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
31123122
cur_func = module->functions + fidx;
31133123
goto call_func_from_interp;
31143124

3125+
#if WASM_ENABLE_TAIL_CALL != 0
3126+
HANDLE_OP (WASM_OP_RETURN_CALL):
3127+
#if WASM_ENABLE_THREAD_MGR != 0
3128+
CHECK_SUSPEND_FLAGS();
3129+
#endif
3130+
fidx = read_uint32(frame_ip);
3131+
#if WASM_ENABLE_MULTI_MODULE != 0
3132+
if (fidx >= module->function_count) {
3133+
wasm_set_exception(module, "unknown function");
3134+
goto got_exception;
3135+
}
3136+
#endif
3137+
cur_func = module->functions + fidx;
3138+
goto call_func_from_return_call;
3139+
#endif /* WASM_ENABLE_TAIL_CALL */
3140+
31153141
#if WASM_ENABLE_LABELS_AS_VALUES == 0
31163142
default:
31173143
wasm_set_exception(module, "unsupported opcode");
@@ -3125,8 +3151,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
31253151
HANDLE_OP (WASM_OP_UNUSED_0x08):
31263152
HANDLE_OP (WASM_OP_UNUSED_0x09):
31273153
HANDLE_OP (WASM_OP_UNUSED_0x0a):
3154+
#if WASM_ENABLE_TAIL_CALL == 0
31283155
HANDLE_OP (WASM_OP_RETURN_CALL):
31293156
HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
3157+
#endif
31303158
HANDLE_OP (WASM_OP_UNUSED_0x14):
31313159
HANDLE_OP (WASM_OP_UNUSED_0x15):
31323160
HANDLE_OP (WASM_OP_UNUSED_0x16):
@@ -3169,6 +3197,40 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
31693197
FETCH_OPCODE_AND_DISPATCH ();
31703198
#endif
31713199

3200+
#if WASM_ENABLE_TAIL_CALL !=0
3201+
call_func_from_return_call:
3202+
{
3203+
uint32 *lp_base;
3204+
uint32 *lp;
3205+
int i;
3206+
3207+
if (!(lp_base = lp = wasm_runtime_malloc(cur_func->param_cell_num * sizeof(uint32)))) {
3208+
wasm_set_exception(module, "allocate memory failed");
3209+
goto got_exception;
3210+
}
3211+
for (i = 0; i < cur_func->param_count; i++) {
3212+
if (cur_func->param_types[i] == VALUE_TYPE_I64
3213+
|| cur_func->param_types[i] == VALUE_TYPE_F64) {
3214+
*(int64*)(lp) =
3215+
GET_OPERAND(int64, (2 * (cur_func->param_count - i - 1)));
3216+
lp += 2;
3217+
}
3218+
else {
3219+
*(lp) = GET_OPERAND(int32, (2 * (cur_func->param_count - i - 1)));
3220+
lp ++;
3221+
}
3222+
}
3223+
frame->lp = frame->operand + cur_func->const_cell_num;
3224+
bh_memcpy_s(frame->lp, (lp - lp_base) * sizeof(uint32),
3225+
lp_base, (lp - lp_base) * sizeof(uint32));
3226+
wasm_runtime_free(lp_base);
3227+
FREE_FRAME(exec_env, frame);
3228+
frame_ip += cur_func->param_count * sizeof(int16);
3229+
wasm_exec_env_set_cur_frame(exec_env,
3230+
(WASMRuntimeFrame *)prev_frame);
3231+
goto call_func_from_entry;
3232+
}
3233+
#endif /* WASM_ENABLE_TAIL_CALL */
31723234
call_func_from_interp:
31733235
/* Only do the copy when it's called from interpreter. */
31743236
{

core/iwasm/interpreter/wasm_loader.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5970,6 +5970,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
59705970

59715971
read_leb_uint32(p, p_end, type_idx);
59725972
#if WASM_ENABLE_FAST_INTERP != 0
5973+
#if WASM_ENABLE_TAIL_CALL != 0
5974+
emit_byte(loader_ctx, opcode);
5975+
#endif
59735976
/* we need to emit func_idx before arguments */
59745977
emit_uint32(loader_ctx, type_idx);
59755978
#endif
@@ -6023,12 +6026,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
60236026
}
60246027
for (i = 0; i < func_type->result_count; i++) {
60256028
type = func->func_type->types[func->func_type->param_count + i];
6026-
if (func_type->types[func_type->param_count + i] != type)
6027-
set_error_buf_v(error_buf, error_buf_size, "%s%s%s",
6028-
"type mismatch: expect ",
6029+
if (func_type->types[func_type->param_count + i] != type) {
6030+
set_error_buf_v(error_buf, error_buf_size,
6031+
"%s%s%s", "type mismatch: expect ",
60296032
type_str[type - VALUE_TYPE_F64],
60306033
" but got other");
6031-
goto fail;
6034+
goto fail;
6035+
}
60326036
}
60336037
RESET_STACK();
60346038
SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);

doc/build_wamr.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ Currently we only profile the memory consumption of module, module_instance and
8383
- **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set
8484
> Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB).
8585
86+
#### **Enable tail call feature**
87+
- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set
88+
8689
**Combination of configurations:**
8790

8891
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:

0 commit comments

Comments
 (0)