Skip to content

Commit ce3458d

Browse files
authored
Refine AOT exception check when function return (#1752)
Refine AOT exception check in the caller when returning from callee function, remove the exception check instructions when hw bound check is enabled to improve the performance: create guard page to trigger signal handler when exception occurs.
1 parent 7cb1ebc commit ce3458d

File tree

8 files changed

+163
-50
lines changed

8 files changed

+163
-50
lines changed

core/iwasm/aot/aot_runtime.c

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,7 +1500,11 @@ aot_set_exception(AOTModuleInstance *module_inst, const char *exception)
15001500
void
15011501
aot_set_exception_with_id(AOTModuleInstance *module_inst, uint32 id)
15021502
{
1503-
wasm_set_exception_with_id(module_inst, id);
1503+
if (id != EXCE_ALREADY_THROWN)
1504+
wasm_set_exception_with_id(module_inst, id);
1505+
#ifdef OS_ENABLE_HW_BOUND_CHECK
1506+
wasm_runtime_access_exce_check_guard_page();
1507+
#endif
15041508
}
15051509

15061510
const char *
@@ -1755,6 +1759,7 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
17551759
const char *signature;
17561760
void *attachment;
17571761
char buf[96];
1762+
bool ret = false;
17581763

17591764
bh_assert(func_idx < aot_module->import_func_count);
17601765

@@ -1764,27 +1769,34 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc,
17641769
"failed to call unlinked import function (%s, %s)",
17651770
import_func->module_name, import_func->func_name);
17661771
aot_set_exception(module_inst, buf);
1767-
return false;
1772+
goto fail;
17681773
}
17691774

17701775
attachment = import_func->attachment;
17711776
if (import_func->call_conv_wasm_c_api) {
1772-
return wasm_runtime_invoke_c_api_native(
1777+
ret = wasm_runtime_invoke_c_api_native(
17731778
(WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc,
17741779
argv, import_func->wasm_c_api_with_env, attachment);
17751780
}
17761781
else if (!import_func->call_conv_raw) {
17771782
signature = import_func->signature;
1778-
return wasm_runtime_invoke_native(exec_env, func_ptr, func_type,
1779-
signature, attachment, argv, argc,
1780-
argv);
1783+
ret =
1784+
wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature,
1785+
attachment, argv, argc, argv);
17811786
}
17821787
else {
17831788
signature = import_func->signature;
1784-
return wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
1785-
signature, attachment, argv, argc,
1786-
argv);
1789+
ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
1790+
signature, attachment, argv, argc,
1791+
argv);
17871792
}
1793+
1794+
fail:
1795+
#ifdef OS_ENABLE_HW_BOUND_CHECK
1796+
if (!ret)
1797+
wasm_runtime_access_exce_check_guard_page();
1798+
#endif
1799+
return ret;
17881800
}
17891801

17901802
bool
@@ -1811,21 +1823,21 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
18111823

18121824
if ((uint8 *)&module_inst < exec_env->native_stack_boundary) {
18131825
aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW);
1814-
return false;
1826+
goto fail;
18151827
}
18161828

18171829
tbl_inst = module_inst->tables[tbl_idx];
18181830
bh_assert(tbl_inst);
18191831

18201832
if (table_elem_idx >= tbl_inst->cur_size) {
18211833
aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT);
1822-
return false;
1834+
goto fail;
18231835
}
18241836

18251837
func_idx = tbl_inst->elems[table_elem_idx];
18261838
if (func_idx == NULL_REF) {
18271839
aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT);
1828-
return false;
1840+
goto fail;
18291841
}
18301842

18311843
func_type_idx = func_type_indexes[func_idx];
@@ -1843,7 +1855,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
18431855
"failed to call unlinked import function (%s, %s)",
18441856
import_func->module_name, import_func->func_name);
18451857
aot_set_exception(module_inst, buf);
1846-
return false;
1858+
goto fail;
18471859
}
18481860

18491861
if (func_idx < aot_module->import_func_count) {
@@ -1852,9 +1864,13 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
18521864
signature = import_func->signature;
18531865
if (import_func->call_conv_raw) {
18541866
attachment = import_func->attachment;
1855-
return wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
1856-
signature, attachment, argv,
1857-
argc, argv);
1867+
ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type,
1868+
signature, attachment, argv,
1869+
argc, argv);
1870+
if (!ret)
1871+
goto fail;
1872+
1873+
return true;
18581874
}
18591875
}
18601876

@@ -1878,7 +1894,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
18781894
&& !(argv1 = runtime_malloc(size, module_inst->cur_exception,
18791895
sizeof(module_inst->cur_exception)))) {
18801896
aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY);
1881-
return false;
1897+
goto fail;
18821898
}
18831899

18841900
/* Copy original arguments */
@@ -1897,12 +1913,10 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
18971913

18981914
ret = invoke_native_internal(exec_env, func_ptr, func_type, signature,
18991915
attachment, argv1, argc, argv);
1900-
if (!ret || aot_get_exception(module_inst)) {
1916+
if (!ret) {
19011917
if (argv1 != argv1_buf)
19021918
wasm_runtime_free(argv1);
1903-
if (clear_wasi_proc_exit_exception(module_inst))
1904-
return true;
1905-
return false;
1919+
goto fail;
19061920
}
19071921

19081922
/* Get extra result values */
@@ -1941,19 +1955,38 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx,
19411955
else {
19421956
ret = invoke_native_internal(exec_env, func_ptr, func_type, signature,
19431957
attachment, argv, argc, argv);
1944-
if (clear_wasi_proc_exit_exception(module_inst))
1945-
return true;
1946-
return ret;
1958+
if (!ret)
1959+
goto fail;
1960+
1961+
return true;
19471962
}
1963+
1964+
fail:
1965+
if (clear_wasi_proc_exit_exception(module_inst))
1966+
return true;
1967+
1968+
#ifdef OS_ENABLE_HW_BOUND_CHECK
1969+
wasm_runtime_access_exce_check_guard_page();
1970+
#endif
1971+
return false;
19481972
}
19491973

19501974
bool
19511975
aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str,
19521976
uint32 app_buf_addr, uint32 app_buf_size,
19531977
void **p_native_addr)
19541978
{
1955-
return wasm_check_app_addr_and_convert(module_inst, is_str, app_buf_addr,
1956-
app_buf_size, p_native_addr);
1979+
bool ret;
1980+
1981+
ret = wasm_check_app_addr_and_convert(module_inst, is_str, app_buf_addr,
1982+
app_buf_size, p_native_addr);
1983+
1984+
#ifdef OS_ENABLE_HW_BOUND_CHECK
1985+
if (!ret)
1986+
wasm_runtime_access_exce_check_guard_page();
1987+
#endif
1988+
1989+
return ret;
19571990
}
19581991

19591992
void *

core/iwasm/common/wasm_exec_env.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
5656
#endif
5757
#endif
5858

59+
#ifdef OS_ENABLE_HW_BOUND_CHECK
60+
if (!(exec_env->exce_check_guard_page =
61+
os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE)))
62+
goto fail5;
63+
#endif
64+
5965
exec_env->module_inst = module_inst;
6066
exec_env->wasm_stack_size = stack_size;
6167
exec_env->wasm_stack.s.top_boundary =
@@ -76,6 +82,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
7682

7783
return exec_env;
7884

85+
#ifdef OS_ENABLE_HW_BOUND_CHECK
86+
fail5:
87+
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
88+
wasm_cluster_destroy_exenv_status(exec_env->current_status);
89+
#endif
90+
#endif
7991
#if WASM_ENABLE_THREAD_MGR != 0
8092
#if WASM_ENABLE_DEBUG_INTERP != 0
8193
fail4:
@@ -96,6 +108,9 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
96108
void
97109
wasm_exec_env_destroy_internal(WASMExecEnv *exec_env)
98110
{
111+
#ifdef OS_ENABLE_HW_BOUND_CHECK
112+
os_munmap(exec_env->exce_check_guard_page, os_getpagesize());
113+
#endif
99114
#if WASM_ENABLE_THREAD_MGR != 0
100115
os_mutex_destroy(&exec_env->wait_lock);
101116
os_cond_destroy(&exec_env->wait_cond);

core/iwasm/common/wasm_exec_env.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ typedef struct WASMExecEnv {
137137

138138
#ifdef OS_ENABLE_HW_BOUND_CHECK
139139
WASMJmpBuf *jmpbuf_stack_top;
140+
/* One guard page for the exception check */
141+
uint8 *exce_check_guard_page;
140142
#endif
141143

142144
#if WASM_ENABLE_MEMORY_PROFILING != 0
@@ -199,7 +201,8 @@ wasm_exec_env_alloc_wasm_frame(WASMExecEnv *exec_env, unsigned size)
199201
the outs area contains const cells, its size may be larger than current
200202
frame size, we should check again before putting the function arguments
201203
into the outs area. */
202-
if (addr + size * 2 > exec_env->wasm_stack.s.top_boundary) {
204+
if (size * 2
205+
> (uint32)(uintptr_t)(exec_env->wasm_stack.s.top_boundary - addr)) {
203206
/* WASM stack overflow. */
204207
return NULL;
205208
}

core/iwasm/common/wasm_runtime_common.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ runtime_signal_handler(void *sig_addr)
185185
os_longjmp(jmpbuf_node->jmpbuf, 1);
186186
}
187187
#endif
188+
else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr
189+
&& (uint8 *)sig_addr
190+
< exec_env_tls->exce_check_guard_page + page_size) {
191+
bh_assert(wasm_get_exception(module_inst));
192+
os_longjmp(jmpbuf_node->jmpbuf, 1);
193+
}
188194
}
189195
}
190196
#else
@@ -1435,6 +1441,17 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env)
14351441
return exec_env->user_data;
14361442
}
14371443

1444+
#ifdef OS_ENABLE_HW_BOUND_CHECK
1445+
void
1446+
wasm_runtime_access_exce_check_guard_page()
1447+
{
1448+
if (exec_env_tls && exec_env_tls->handle == os_self_thread()) {
1449+
uint32 page_size = os_getpagesize();
1450+
memset(exec_env_tls->exce_check_guard_page, 0, page_size);
1451+
}
1452+
}
1453+
#endif
1454+
14381455
WASMType *
14391456
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
14401457
uint32 module_type)

core/iwasm/common/wasm_runtime_common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,12 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
554554
WASM_RUNTIME_API_EXTERN void *
555555
wasm_runtime_get_user_data(WASMExecEnv *exec_env);
556556

557+
#ifdef OS_ENABLE_HW_BOUND_CHECK
558+
/* Access exception check guard page to trigger the signal handler */
559+
void
560+
wasm_runtime_access_exce_check_guard_page();
561+
#endif
562+
557563
/* See wasm_export.h for description */
558564
WASM_RUNTIME_API_EXTERN bool
559565
wasm_runtime_call_wasm(WASMExecEnv *exec_env,

core/iwasm/compilation/aot_emit_function.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,14 @@ create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
3535
/* Create return IR */
3636
LLVMPositionBuilderAtEnd(comp_ctx->builder,
3737
func_ctx->func_return_block);
38-
if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
38+
if (!comp_ctx->enable_bound_check) {
39+
if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_ALREADY_THROWN,
40+
false, NULL, NULL)) {
41+
return false;
42+
}
43+
}
44+
else if (!aot_build_zero_function_ret(comp_ctx, func_ctx,
45+
aot_func_type)) {
3946
return false;
4047
}
4148
}
@@ -494,7 +501,8 @@ check_app_addr_and_convert(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
494501
}
495502

496503
/* Check whether exception was thrown when executing the function */
497-
if (!check_call_return(comp_ctx, func_ctx, res)) {
504+
if (comp_ctx->enable_bound_check
505+
&& !check_call_return(comp_ctx, func_ctx, res)) {
498506
return false;
499507
}
500508

@@ -707,7 +715,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
707715
goto fail;
708716
/* Check whether there was exception thrown when executing
709717
the function */
710-
if (!check_call_return(comp_ctx, func_ctx, res))
718+
if (comp_ctx->enable_bound_check
719+
&& !check_call_return(comp_ctx, func_ctx, res))
711720
goto fail;
712721
}
713722
else { /* call native func directly */
@@ -823,7 +832,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
823832

824833
/* Check whether there was exception thrown when executing
825834
the function */
826-
if (!tail_call && !recursive_call
835+
if (!tail_call && !recursive_call && comp_ctx->enable_bound_check
827836
&& !check_exception_thrown(comp_ctx, func_ctx))
828837
goto fail;
829838
}
@@ -1395,7 +1404,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
13951404
goto fail;
13961405

13971406
/* Check whether exception was thrown when executing the function */
1398-
if (!check_call_return(comp_ctx, func_ctx, res))
1407+
if (comp_ctx->enable_bound_check
1408+
&& !check_call_return(comp_ctx, func_ctx, res))
13991409
goto fail;
14001410

14011411
block_curr = LLVMGetInsertBlock(comp_ctx->builder);
@@ -1454,7 +1464,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
14541464
}
14551465

14561466
/* Check whether exception was thrown when executing the function */
1457-
if (!check_exception_thrown(comp_ctx, func_ctx))
1467+
if (comp_ctx->enable_bound_check
1468+
&& !check_exception_thrown(comp_ctx, func_ctx))
14581469
goto fail;
14591470

14601471
if (func_result_count > 0) {

core/iwasm/compilation/aot_llvm_extra.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,12 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
344344

345345
if (!disable_llvm_lto) {
346346
/* Apply LTO for AOT mode */
347-
#if LLVM_VERSION_MAJOR < 14
348-
MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL));
349-
#else
350-
MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL));
351-
#endif
347+
if (comp_ctx->comp_data->func_count >= 10)
348+
/* Adds the pre-link optimizations if the func count
349+
is large enough */
350+
MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL));
351+
else
352+
MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL));
352353
}
353354
else {
354355
MPM.addPass(PB.buildPerModuleDefaultPipeline(OL));

0 commit comments

Comments
 (0)