@@ -90,8 +90,21 @@ typedef float64 CellType_F64;
9090 } while (0)
9191
9292#if WASM_ENABLE_INSTRUCTION_METERING != 0
93+ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0
94+ #define ROLLBACK_IP_AFTER_METERING_CHECK () \
95+ do { \
96+ frame_ip -= sizeof(void *); \
97+ } while (0)
98+ #else
99+ #define ROLLBACK_IP_AFTER_METERING_CHECK () \
100+ do { \
101+ frame_ip -= sizeof(int32); \
102+ } while (0)
103+ #endif
104+
93105#define CHECK_INSTRUCTION_LIMIT () \
94106 if (instructions_left == 0) { \
107+ ROLLBACK_IP_AFTER_METERING_CHECK(); \
95108 wasm_set_exception(module, "instruction limit exceeded"); \
96109 goto got_exception; \
97110 } \
@@ -102,6 +115,22 @@ typedef float64 CellType_F64;
102115#define CHECK_INSTRUCTION_LIMIT () (void)0
103116#endif
104117
118+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
119+ static inline bool
120+ is_instruction_metering_exception (WASMModuleInstance * module_inst )
121+ {
122+ const char * exception = wasm_get_exception (module_inst );
123+ return exception && strstr (exception , "instruction limit exceeded" );
124+ }
125+
126+ static inline void
127+ clear_metering_suspend_state (WASMExecEnv * exec_env )
128+ {
129+ exec_env -> metering_suspended = false;
130+ exec_env -> metering_suspend_frame = NULL ;
131+ }
132+ #endif
133+
105134static inline uint32
106135rotl32 (uint32 n , uint32 c )
107136{
@@ -1594,6 +1623,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
15941623 }
15951624#endif
15961625
1626+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
1627+ if (prev_frame && prev_frame -> function == cur_func && prev_frame -> ip ) {
1628+ RECOVER_CONTEXT (prev_frame );
1629+ #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
1630+ is_return_call = false;
1631+ #endif
1632+ goto resume_func ;
1633+ }
1634+ #endif
1635+
15971636#if WASM_ENABLE_LABELS_AS_VALUES == 0
15981637 while (frame_ip < frame_ip_end ) {
15991638 opcode = * frame_ip ++ ;
@@ -7788,6 +7827,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
77887827 HANDLE_OP_END ();
77897828 }
77907829
7830+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7831+ resume_func :
7832+ #if WASM_ENABLE_THREAD_MGR != 0
7833+ CHECK_SUSPEND_FLAGS ();
7834+ #endif
7835+ HANDLE_OP_END ();
7836+ #endif
7837+
77917838 return_func :
77927839 {
77937840 FREE_FRAME (exec_env , frame );
@@ -7888,13 +7935,17 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
78887935 WASMFunctionInstance * function , uint32 argc ,
78897936 uint32 argv [])
78907937{
7891- WASMRuntimeFrame * prev_frame = wasm_exec_env_get_cur_frame (exec_env );
7892- WASMInterpFrame * frame , * outs_area ;
7938+ WASMRuntimeFrame * frame = NULL , * prev_frame , * outs_area ;
78937939
78947940 /* Allocate sufficient cells for all kinds of return values. */
78957941 unsigned all_cell_num =
78967942 function -> ret_cell_num > 2 ? function -> ret_cell_num : 2 ,
78977943 i ;
7944+ bool alloc_frame = true;
7945+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7946+ bool resume_metering = false;
7947+ WASMRuntimeFrame * suspended_frame = NULL ;
7948+ #endif
78987949 /* This frame won't be used by JITed code, so only allocate interp
78997950 frame here. */
79007951 unsigned frame_size ;
@@ -7927,33 +7978,66 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
79277978 }
79287979#endif
79297980
7930- if (!(frame =
7931- ALLOC_FRAME (exec_env , frame_size , (WASMInterpFrame * )prev_frame )))
7932- return ;
7981+ prev_frame = wasm_exec_env_get_cur_frame (exec_env );
79337982
7934- outs_area = wasm_exec_env_wasm_stack_top (exec_env );
7935- frame -> function = NULL ;
7936- frame -> ip = NULL ;
7937- /* There is no local variable. */
7938- frame -> lp = frame -> operand + 0 ;
7983+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7984+ if (exec_env -> metering_suspended ) {
7985+ suspended_frame = exec_env -> metering_suspend_frame ;
7986+ if (!suspended_frame || suspended_frame -> function != function ) {
7987+ wasm_set_exception (module_inst ,
7988+ "cannot call different function while metering "
7989+ "resume is pending" );
7990+ return ;
7991+ }
7992+ if (!suspended_frame -> prev_frame ) {
7993+ wasm_set_exception (module_inst ,
7994+ "invalid metering resume frame state" );
7995+ clear_metering_suspend_state (exec_env );
7996+ return ;
7997+ }
7998+
7999+ resume_metering = true;
8000+ frame = suspended_frame -> prev_frame ;
8001+ prev_frame = frame -> prev_frame ;
8002+ wasm_exec_env_set_cur_frame (exec_env , suspended_frame );
8003+ }
8004+ #endif
8005+
8006+ if (alloc_frame
8007+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
8008+ && !resume_metering
8009+ #endif
8010+ ) {
8011+ if (!(frame = ALLOC_FRAME (exec_env , frame_size ,
8012+ (WASMInterpFrame * )prev_frame )))
8013+ return ;
8014+
8015+ outs_area = wasm_exec_env_wasm_stack_top (exec_env );
8016+ frame -> function = NULL ;
8017+ frame -> ip = NULL ;
8018+ /* There is no local variable. */
8019+ frame -> lp = frame -> operand + 0 ;
79398020#if WASM_ENABLE_GC != 0
7940- frame -> frame_ref =
7941- (uint8 * )(frame -> lp
7942- + (function -> ret_cell_num > 2 ? function -> ret_cell_num : 2 ));
8021+ frame -> frame_ref =
8022+ (uint8 * )(frame -> lp + (function -> ret_cell_num > 2
8023+ ? function -> ret_cell_num
8024+ : 2 ));
79438025#endif
7944- frame -> ret_offset = 0 ;
8026+ frame -> ret_offset = 0 ;
79458027
7946- if ((uint8 * )(outs_area -> operand + function -> const_cell_num + argc )
7947- > exec_env -> wasm_stack .top_boundary ) {
7948- wasm_set_exception ((WASMModuleInstance * )exec_env -> module_inst ,
7949- "wasm operand stack overflow" );
7950- return ;
7951- }
8028+ if ((uint8 * )(outs_area -> operand + function -> const_cell_num + argc )
8029+ > exec_env -> wasm_stack .top_boundary ) {
8030+ wasm_set_exception ((WASMModuleInstance * )exec_env -> module_inst ,
8031+ "wasm operand stack overflow" );
8032+ return ;
8033+ }
79528034
7953- if (argc > 0 )
7954- word_copy (outs_area -> operand + function -> const_cell_num , argv , argc );
8035+ if (argc > 0 )
8036+ word_copy (outs_area -> operand + function -> const_cell_num , argv ,
8037+ argc );
79558038
7956- wasm_exec_env_set_cur_frame (exec_env , frame );
8039+ wasm_exec_env_set_cur_frame (exec_env , frame );
8040+ }
79578041
79588042#if defined(os_writegsbase )
79598043 {
@@ -7980,9 +8064,24 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
79808064 }
79818065 }
79828066 else {
7983- wasm_interp_call_func_bytecode (module_inst , exec_env , function , frame );
8067+ wasm_interp_call_func_bytecode (module_inst , exec_env , function ,
8068+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
8069+ resume_metering ? suspended_frame
8070+ : frame
8071+ #else
8072+ frame
8073+ #endif
8074+ );
79848075 }
79858076
8077+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
8078+ if (is_instruction_metering_exception (module_inst )) {
8079+ exec_env -> metering_suspended = true;
8080+ exec_env -> metering_suspend_frame = wasm_exec_env_get_cur_frame (exec_env );
8081+ return ;
8082+ }
8083+ #endif
8084+
79868085 /* Output the return value to the caller */
79878086 if (!wasm_copy_exception (module_inst , NULL )) {
79888087 for (i = 0 ; i < function -> ret_cell_num ; i ++ )
@@ -7996,8 +8095,14 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
79968095#endif
79978096 }
79988097
7999- wasm_exec_env_set_cur_frame (exec_env , prev_frame );
8000- FREE_FRAME (exec_env , frame );
8098+ if (alloc_frame ) {
8099+ wasm_exec_env_set_cur_frame (exec_env , prev_frame );
8100+ FREE_FRAME (exec_env , frame );
8101+ }
8102+
8103+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
8104+ clear_metering_suspend_state (exec_env );
8105+ #endif
80018106#if WASM_ENABLE_OPCODE_COUNTER != 0
80028107 wasm_interp_dump_op_count ();
80038108#endif
0 commit comments