Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add instruction metering #4122

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ca78c66
feat: add instruction metering support with execution limit
AlixANNERAUD Mar 2, 2025
8c262ba
fix: formatting
AlixANNERAUD Mar 2, 2025
799cad6
fix: format
AlixANNERAUD Mar 2, 2025
0dd7fe2
feat: initialize instruction execution limit in exec_env
AlixANNERAUD Mar 2, 2025
422c8fb
fix: remove unnecessary backslash in macro definition
AlixANNERAUD Mar 2, 2025
161c945
fix
AlixANNERAUD Mar 2, 2025
5d34365
fix: correct function declaration for wasm_runtime_set_instruction_co…
AlixANNERAUD Mar 2, 2025
41bbcb7
fix: format function declaration for wasm_runtime_set_bounds_checks
AlixANNERAUD Mar 2, 2025
a7d90eb
fix: format HANDLE_OP_END macro for better readability
AlixANNERAUD Mar 2, 2025
ad6ba3d
fix: update preprocessor directive for WASM_INSTRUCTION_METERING check
AlixANNERAUD Mar 2, 2025
76392b5
fix: handle null exec_env in instruction metering checks
AlixANNERAUD Mar 2, 2025
e4ceb6b
fix: move instructions_to_execute field in WASMExecEnv (overwriten be…
AlixANNERAUD Mar 2, 2025
70af781
fix: improve instruction limit checks and enhance readability of HAND…
AlixANNERAUD Mar 17, 2025
0df05af
fix: simplify instruction limit checks for better readability
AlixANNERAUD Mar 17, 2025
56526e9
fix: streamline HANDLE_OP macro definitions for improved readability
AlixANNERAUD Mar 17, 2025
76c1448
fix: correct module parameter in instruction limit exception handling
AlixANNERAUD Mar 18, 2025
446c52b
fix: improve formatting of CHECK_INSTRUCTION_LIMIT macro for better r…
AlixANNERAUD Mar 18, 2025
e1b0411
fix: remove unnecessary else clause in instruction limit checks for i…
AlixANNERAUD Mar 18, 2025
cb5975e
fix: update instruction limit checks to use else if for improved clarity
AlixANNERAUD Mar 18, 2025
53c54b9
fix: update instruction metering configuration for consistency and cl…
AlixANNERAUD Mar 21, 2025
44486c8
docs: add instruction metering section to build_wamr documentation
AlixANNERAUD Mar 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,10 @@ if (WAMR_BUILD_AOT_VALIDATOR EQUAL 1)
message (" AOT validator enabled")
add_definitions (-DWASM_ENABLE_AOT_VALIDATOR=1)
endif ()
if (WAMR_BUILD_INSTRUCTION_METERING EQUAL 1)
message (" Instruction metering enabled")
add_definitions (-DWASM_ENABLE_INSTRUCTION_METERING=1)
endif ()

########################################
# Show Phase4 Wasm proposals status.
Expand Down
4 changes: 4 additions & 0 deletions core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,4 +710,8 @@
#define WASM_ENABLE_AOT_VALIDATOR 0
#endif

#ifndef WASM_ENABLE_INSTRUCTION_METERING
#define WASM_ENABLE_INSTRUCTION_METERING 0
#endif

#endif /* end of _CONFIG_H_ */
4 changes: 4 additions & 0 deletions core/iwasm/common/wasm_exec_env.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
#endif

#if WASM_ENABLE_INSTRUCTION_METERING != 0
exec_env->instructions_to_execute = -1;
#endif

return exec_env;

#ifdef OS_ENABLE_HW_BOUND_CHECK
Expand Down
5 changes: 5 additions & 0 deletions core/iwasm/common/wasm_exec_env.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ typedef struct WASMExecEnv {
uint8 *bottom;
} wasm_stack;

#if WASM_ENABLE_INSTRUCTION_METERING != 0
/* instructions to execute */
int instructions_to_execute;
#endif

#if WASM_ENABLE_FAST_JIT != 0
/**
* Cache for
Expand Down
9 changes: 9 additions & 0 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2285,6 +2285,15 @@ wasm_runtime_access_exce_check_guard_page()
}
#endif

#if WASM_ENABLE_INSTRUCTION_METERING != 0
void
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
int instructions_to_execute)
{
exec_env->instructions_to_execute = instructions_to_execute;
}
#endif

WASMFuncType *
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
uint32 module_type)
Expand Down
10 changes: 9 additions & 1 deletion core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,9 +672,17 @@ WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
uint8 *native_stack_boundary);

#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
#if WASM_ENABLE_INSTRUCTION_METERING != 0
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
int instructions_to_execute);
#endif

#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN
void
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
bool enable);

Expand Down
14 changes: 14 additions & 0 deletions core/iwasm/include/wasm_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,20 @@ WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
uint8_t *native_stack_boundary);

/**
* Set the instruction count limit to the execution environment.
* By default the instruction count limit is -1, which means no limit.
* However, if the instruction count limit is set to a positive value,
* the execution will be terminated when the instruction count reaches
* the limit.
*
* @param exec_env the execution environment
* @param instruction_count the instruction count limit
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_instruction_count_limit(wasm_exec_env_t exec_env,
int instruction_count);

/**
* Dump runtime memory consumption, including:
* Exec env memory consumption
Expand Down
30 changes: 28 additions & 2 deletions core/iwasm/interpreter/wasm_interp_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1516,10 +1516,13 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
} \
os_mutex_unlock(&exec_env->wait_lock); \
} \
CHECK_INSTRUCTION_LIMIT(); \
goto *handle_table[*frame_ip++]; \
} while (0)
#else
#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
#define HANDLE_OP_END() \
CHECK_INSTRUCTION_LIMIT(); \
FETCH_OPCODE_AND_DISPATCH()
#endif

#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
Expand All @@ -1542,9 +1545,12 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
} \
os_mutex_unlock(&exec_env->wait_lock); \
} \
CHECK_INSTRUCTION_LIMIT(); \
continue;
#else
#define HANDLE_OP_END() continue
#define HANDLE_OP_END() \
CHECK_INSTRUCTION_LIMIT(); \
continue;
#endif

#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
Expand All @@ -1562,6 +1568,18 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
#endif
}

#if WASM_ENABLE_INSTRUCTION_METERING != 0
#define CHECK_INSTRUCTION_LIMIT() \
if (instructions_left == 0) { \
wasm_set_exception(module, "instruction limit exceeded"); \
goto got_exception; \
} \
else if (instructions_left > 0) \
instructions_left--;
#else
#define CHECK_INSTRUCTION_LIMIT() (void)0
#endif

static void
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
WASMExecEnv *exec_env,
Expand Down Expand Up @@ -1605,6 +1623,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 local_idx, local_offset, global_idx;
uint8 local_type, *global_addr;
uint32 cache_index, type_index, param_cell_num, cell_num;

#if WASM_ENABLE_INSTRUCTION_METERING != 0
int instructions_left = -1;
if (exec_env) {
instructions_left = exec_env->instructions_to_execute;
}
#endif

#if WASM_ENABLE_EXCE_HANDLING != 0
int32_t exception_tag_index;
#endif
Expand Down
23 changes: 23 additions & 0 deletions core/iwasm/interpreter/wasm_interp_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ typedef float64 CellType_F64;
goto unaligned_atomic; \
} while (0)

#if WASM_ENABLE_INSTRUCTION_METERING != 0
#define CHECK_INSTRUCTION_LIMIT() \
if (instructions_left == 0) { \
wasm_set_exception(module, "instruction limit exceeded"); \
goto got_exception; \
} \
else if (instructions_left > 0) \
instructions_left--;

#else
#define CHECK_INSTRUCTION_LIMIT() (void)0
#endif

static inline uint32
rotl32(uint32 n, uint32 c)
{
Expand Down Expand Up @@ -1412,6 +1425,7 @@ wasm_interp_dump_op_count()
do { \
const void *p_label_addr = *(void **)frame_ip; \
frame_ip += sizeof(void *); \
CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#else
Expand All @@ -1423,6 +1437,7 @@ wasm_interp_dump_op_count()
/* int32 relative offset was emitted in 64-bit target */ \
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
frame_ip += sizeof(int32); \
CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#else
Expand All @@ -1433,6 +1448,7 @@ wasm_interp_dump_op_count()
/* uint32 label address was emitted in 32-bit target */ \
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
frame_ip += sizeof(int32); \
CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#endif
Expand Down Expand Up @@ -1509,6 +1525,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 *maddr = NULL;
uint32 local_idx, local_offset, global_idx;
uint8 opcode = 0, local_type, *global_addr;

#if WASM_ENABLE_INSTRUCTION_METERING != 0
int instructions_left = -1;
if (exec_env) {
instructions_left = exec_env->instructions_to_execute;
}
#endif
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
Expand Down
4 changes: 4 additions & 0 deletions doc/build_wamr.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ And the wasm app can calls below APIs to allocate/free memory from/to the shared
- **WAMR_BUILD_SHRUNK_MEMORY**=1/0, default to enable if not set
> Note: When enabled, this feature will reduce memory usage by decreasing the size of the linear memory, particularly when the `memory.grow` opcode is not used and memory usage is somewhat predictable.

## **Instruction metering**
- **WAMR_BUILD_INSTRUCTION_METERING**=1/0, default to disable if not set
> Note: Enabling this feature allows limiting the number of instructions a wasm module instance can execute. Use the `wasm_runtime_set_instruction_count_limit(...)` API before calling `wasm_runtime_call_*(...)` APIs to enforce this limit.

## **Combination of configurations:**

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