@@ -1558,6 +1558,25 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
15581558#define CHECK_INSTRUCTION_LIMIT () (void)0
15591559#endif
15601560
1561+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
1562+ static inline bool
1563+ is_instruction_metering_exception (WASMModuleInstance * module_inst )
1564+ {
1565+ const char * exception = wasm_get_exception (module_inst );
1566+ return exception && strstr (exception , "instruction limit exceeded" );
1567+ }
1568+
1569+ static inline void
1570+ clear_metering_suspend_state (WASMExecEnv * exec_env )
1571+ {
1572+ exec_env -> metering_suspended = false;
1573+ exec_env -> metering_suspend_frame = NULL ;
1574+ exec_env -> metering_suspend_function = NULL ;
1575+ exec_env -> metering_suspend_argc = 0 ;
1576+ exec_env -> metering_suspend_argv = NULL ;
1577+ }
1578+ #endif
1579+
15611580static void
15621581wasm_interp_call_func_bytecode (WASMModuleInstance * module ,
15631582 WASMExecEnv * exec_env ,
@@ -1671,6 +1690,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
16711690#undef HANDLE_OPCODE
16721691#endif
16731692
1693+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
1694+ if (prev_frame && prev_frame -> function == cur_func && prev_frame -> ip ) {
1695+ RECOVER_CONTEXT (prev_frame );
1696+ #if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0
1697+ is_return_call = false;
1698+ #endif
1699+ goto resume_func ;
1700+ }
1701+ #endif
1702+
16741703#if WASM_ENABLE_LABELS_AS_VALUES == 0
16751704 while (frame_ip < frame_ip_end ) {
16761705 opcode = * frame_ip ++ ;
@@ -6857,6 +6886,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
68576886
68586887 wasm_exec_env_set_cur_frame (exec_env , frame );
68596888 }
6889+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
6890+ resume_func :
6891+ #endif
68606892#if WASM_ENABLE_THREAD_MGR != 0
68616893 CHECK_SUSPEND_FLAGS ();
68626894#endif
@@ -7413,6 +7445,10 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
74137445 wasm_runtime_get_running_mode ((WASMModuleInstanceCommon * )module_inst );
74147446 /* Allocate sufficient cells for all kinds of return values. */
74157447 bool alloc_frame = true;
7448+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7449+ bool resume_metering = false;
7450+ WASMRuntimeFrame * suspended_frame = NULL ;
7451+ #endif
74167452
74177453 if (argc < function -> param_cell_num ) {
74187454 char buf [128 ];
@@ -7456,7 +7492,34 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
74567492#endif
74577493 }
74587494
7459- if (alloc_frame ) {
7495+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7496+ if (running_mode == Mode_Interp && exec_env -> metering_suspended ) {
7497+ suspended_frame = exec_env -> metering_suspend_frame ;
7498+ if (!suspended_frame || suspended_frame -> function != function ) {
7499+ wasm_set_exception (module_inst ,
7500+ "cannot call different function while metering "
7501+ "resume is pending" );
7502+ return ;
7503+ }
7504+ if (!suspended_frame -> prev_frame ) {
7505+ wasm_set_exception (module_inst ,
7506+ "invalid metering resume frame state" );
7507+ clear_metering_suspend_state (exec_env );
7508+ return ;
7509+ }
7510+
7511+ resume_metering = true;
7512+ frame = suspended_frame -> prev_frame ;
7513+ prev_frame = frame -> prev_frame ;
7514+ wasm_exec_env_set_cur_frame (exec_env , suspended_frame );
7515+ }
7516+ #endif
7517+
7518+ if (alloc_frame
7519+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7520+ && !resume_metering
7521+ #endif
7522+ ) {
74607523 unsigned all_cell_num =
74617524 function -> ret_cell_num > 2 ? function -> ret_cell_num : 2 ;
74627525 unsigned frame_size ;
@@ -7513,7 +7576,13 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
75137576 else {
75147577 if (running_mode == Mode_Interp ) {
75157578 wasm_interp_call_func_bytecode (module_inst , exec_env , function ,
7516- frame );
7579+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7580+ resume_metering ? suspended_frame
7581+ : frame
7582+ #else
7583+ frame
7584+ #endif
7585+ );
75177586 }
75187587#if WASM_ENABLE_FAST_JIT != 0
75197588 else if (running_mode == Mode_Fast_JIT ) {
@@ -7554,6 +7623,27 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
75547623#endif
75557624 }
75567625
7626+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7627+ if ((running_mode == Mode_Interp )
7628+ && is_instruction_metering_exception (module_inst )) {
7629+ exec_env -> metering_suspended = true;
7630+ exec_env -> metering_suspend_frame =
7631+ wasm_exec_env_get_cur_frame (exec_env );
7632+ if (exec_env -> metering_suspend_frame ) {
7633+ exec_env -> metering_suspend_function =
7634+ exec_env -> metering_suspend_frame -> function ;
7635+ exec_env -> metering_suspend_argc = argc ;
7636+ exec_env -> metering_suspend_argv = argv ;
7637+ }
7638+ else {
7639+ exec_env -> metering_suspend_function = NULL ;
7640+ exec_env -> metering_suspend_argc = 0 ;
7641+ exec_env -> metering_suspend_argv = NULL ;
7642+ }
7643+ return ;
7644+ }
7645+ #endif
7646+
75577647 /* Output the return value to the caller */
75587648 if (!wasm_copy_exception (module_inst , NULL )) {
75597649 if (alloc_frame ) {
@@ -7575,4 +7665,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
75757665 wasm_exec_env_set_cur_frame (exec_env , prev_frame );
75767666 FREE_FRAME (exec_env , frame );
75777667 }
7668+
7669+ #if WASM_ENABLE_INSTRUCTION_METERING != 0
7670+ clear_metering_suspend_state (exec_env );
7671+ #endif
75787672}
0 commit comments