From 7d05dbc9885fc875b6b5e59c693f0763b016694c Mon Sep 17 00:00:00 2001 From: TianlongLiang <111852609+TianlongLiang@users.noreply.github.com> Date: Mon, 7 Jul 2025 13:34:02 +0800 Subject: [PATCH] Support extended constant expressions (#4432) * implement extended const expr (#4318) * add a toggle to enable extended const on wamrc (#4412) --- .../compilation_on_android_ubuntu.yml | 3 + .github/workflows/compilation_on_macos.yml | 1 + .github/workflows/compilation_on_sgx.yml | 1 + .github/workflows/nightly_run.yml | 3 + build-scripts/config_common.cmake | 14 +- core/config.h | 4 + core/iwasm/aot/aot_loader.c | 127 +++-- core/iwasm/aot/aot_runtime.c | 318 +++++++---- core/iwasm/common/wasm_loader_common.c | 15 + core/iwasm/common/wasm_loader_common.h | 5 + core/iwasm/compilation/aot_emit_aot_file.c | 83 ++- core/iwasm/compilation/aot_llvm.c | 3 + core/iwasm/compilation/aot_llvm.h | 3 + core/iwasm/fast-jit/fe/jit_emit_table.c | 3 +- core/iwasm/include/aot_comp_option.h | 1 + core/iwasm/interpreter/wasm.h | 40 +- core/iwasm/interpreter/wasm_interp_classic.c | 10 +- core/iwasm/interpreter/wasm_interp_fast.c | 10 +- core/iwasm/interpreter/wasm_loader.c | 365 ++++++++++--- core/iwasm/interpreter/wasm_mini_loader.c | 250 +++++++-- core/iwasm/interpreter/wasm_runtime.c | 287 ++++++---- doc/build_wamr.md | 4 + .../wamr-test-suites/spec-test-script/all.py | 16 + .../spec-test-script/extended_const.patch | 506 ++++++++++++++++++ .../spec-test-script/runtest.py | 8 + tests/wamr-test-suites/test_wamr.sh | 28 +- wamr-compiler/CMakeLists.txt | 1 + wamr-compiler/main.c | 4 + 28 files changed, 1734 insertions(+), 379 deletions(-) create mode 100644 tests/wamr-test-suites/spec-test-script/extended_const.patch diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 0fbb09e7d..828773ae0 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -69,6 +69,7 @@ env: GC_TEST_OPTIONS: "-s spec -G -b -P" MEMORY64_TEST_OPTIONS: "-s spec -W -b -P" MULTI_MEMORY_TEST_OPTIONS: "-s spec -E -b -P" + EXTENDED_CONST_EXPR_TEST_OPTIONS: "-s spec -N -b -P" permissions: contents: read @@ -164,6 +165,7 @@ jobs: "-DWAMR_BUILD_MEMORY64=1", "-DWAMR_BUILD_MULTI_MEMORY=1", "-DWAMR_BUILD_SHARED=1", + "-DWAMR_BUILD_EXTENDED_CONST_EXPR=1", ] os: [ubuntu-22.04] platform: [android, linux] @@ -609,6 +611,7 @@ jobs: $GC_TEST_OPTIONS, $MEMORY64_TEST_OPTIONS, $MULTI_MEMORY_TEST_OPTIONS, + $EXTENDED_CONST_EXPR_TEST_OPTIONS, ] include: - os: ubuntu-22.04 diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index 44c7973f1..462e273bf 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.github/workflows/compilation_on_macos.yml @@ -142,6 +142,7 @@ jobs: "-DWAMR_BUILD_SIMD=1", "-DWAMR_BUILD_TAIL_CALL=1", "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_EXTENDED_CONST_EXPR=1", ] os: [macos-13] platform: [darwin] diff --git a/.github/workflows/compilation_on_sgx.yml b/.github/workflows/compilation_on_sgx.yml index 541f7a284..ec27fd8ba 100644 --- a/.github/workflows/compilation_on_sgx.yml +++ b/.github/workflows/compilation_on_sgx.yml @@ -100,6 +100,7 @@ jobs: "-DWAMR_BUILD_MULTI_MODULE=1", "-DWAMR_BUILD_PERF_PROFILING=1", "-DWAMR_BUILD_REF_TYPES=1", + "-DWAMR_BUILD_EXTENDED_CONST_EXPR=1", # doesn't support "-DWAMR_BUILD_SIMD=0", "-DWAMR_BUILD_TAIL_CALL=1", diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index 1ae405f60..b2bd04d1d 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -37,6 +37,7 @@ env: MULTI_TIER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" # For Spec Test DEFAULT_TEST_OPTIONS: "-s spec -b -P" + EXTENDED_CONST_EXPR_TEST_OPTIONS: "-s spec -b -P -N" MULTI_MODULES_TEST_OPTIONS: "-s spec -b -P -M" SIMD_TEST_OPTIONS: "-s spec -b -P -S" THREADS_TEST_OPTIONS: "-s spec -b -P -p" @@ -128,6 +129,7 @@ jobs: "-DWAMR_BUILD_MEMORY64=1", "-DWAMR_BUILD_MULTI_MEMORY=1", "-DWAMR_BUILD_SHARED=1", + "-DWAMR_BUILD_EXTENDED_CONST_EXPR=1", ] os: [ubuntu-22.04] platform: [android, linux] @@ -588,6 +590,7 @@ jobs: $DEFAULT_TEST_OPTIONS, $MULTI_MODULES_TEST_OPTIONS, $SIMD_TEST_OPTIONS, + $EXTENDED_CONST_EXPR_TEST_OPTIONS, $THREADS_TEST_OPTIONS, $WASI_TEST_OPTIONS, ] diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index ca9360a63..8cdce4a01 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -211,6 +211,10 @@ if (NOT DEFINED WAMR_BUILD_TAIL_CALL) set (WAMR_BUILD_TAIL_CALL 0) endif () +if (NOT DEFINED WAMR_BUILD_EXTENDED_CONST_EXPR) + set (WAMR_BUILD_EXTENDED_CONST_EXPR 0) +endif () + ######################################## # Compilation options to marco ######################################## @@ -673,7 +677,13 @@ if (WAMR_BUILD_INSTRUCTION_METERING EQUAL 1) message (" Instruction metering enabled") add_definitions (-DWASM_ENABLE_INSTRUCTION_METERING=1) endif () - +if (WAMR_BUILD_EXTENDED_CONST_EXPR EQUAL 1) + message (" Extended constant expression enabled") + add_definitions(-DWASM_ENABLE_EXTENDED_CONST_EXPR=1) +else() + message (" Extended constant expression disabled") + add_definitions(-DWASM_ENABLE_EXTENDED_CONST_EXPR=0) +endif () ######################################## # Show Phase4 Wasm proposals status. ######################################## @@ -687,6 +697,7 @@ message ( " \"WebAssembly C and C++ API\"\n" " Configurable. 0 is OFF. 1 is ON:\n" " \"Bulk Memory Operation\" via WAMR_BUILD_BULK_MEMORY: ${WAMR_BUILD_BULK_MEMORY}\n" +" \"Extended Constant Expressions\" via WAMR_BUILD_EXTENDED_CONST_EXPR: ${WAMR_BUILD_EXTENDED_CONST_EXPR}\n" " \"Fixed-width SIMD\" via WAMR_BUILD_SIMD: ${WAMR_BUILD_SIMD}\n" " \"Garbage collection\" via WAMR_BUILD_GC: ${WAMR_BUILD_GC}\n" " \"Legacy Exception handling\" via WAMR_BUILD_EXCE_HANDLING: ${WAMR_BUILD_EXCE_HANDLING}\n" @@ -701,7 +712,6 @@ message ( " \"Branch Hinting\"\n" " \"Custom Annotation Syntax in the Text Format\"\n" " \"Exception handling\"\n" -" \"Extended Constant Expressions\"\n" " \"Import/Export of Mutable Globals\"\n" " \"JS String Builtins\"\n" " \"Relaxed SIMD\"\n" diff --git a/core/config.h b/core/config.h index c43a1bfe4..38af3b029 100644 --- a/core/config.h +++ b/core/config.h @@ -720,4 +720,8 @@ unless used elsewhere */ #define WASM_ENABLE_INSTRUCTION_METERING 0 #endif +#ifndef WASM_ENABLE_EXTENDED_CONST_EXPR +#define WASM_ENABLE_EXTENDED_CONST_EXPR 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 9d1129b8d..358ec5d1d 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -968,6 +968,35 @@ fail: return false; } +#if WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0 +static void +destroy_init_expr(InitializerExpression *expr) +{ +#if WASM_ENABLE_GC != 0 + if (expr->init_expr_type == INIT_EXPR_TYPE_STRUCT_NEW + || expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW + || expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) { + wasm_runtime_free(expr->u.unary.v.data); + } +#endif + +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + // free left expr and right expr for binary oprand + if (!is_expr_binary_op(expr->init_expr_type)) { + return; + } + if (expr->u.binary.l_expr) { + destroy_init_expr_recursive(expr->u.binary.l_expr); + } + if (expr->u.binary.r_expr) { + destroy_init_expr_recursive(expr->u.binary.r_expr); + } + expr->u.binary.l_expr = expr->u.binary.r_expr = NULL; +#endif +} +#endif /* end of WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0 \ + */ + static void destroy_import_memories(AOTImportMemory *import_memories) { @@ -993,6 +1022,10 @@ destroy_mem_init_data_list(AOTModule *module, AOTMemInitData **data_list, /* If the module owns the binary data, free the bytes buffer */ if (module->is_binary_freeable && data_list[i]->bytes) wasm_runtime_free(data_list[i]->bytes); + +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(&data_list[i]->offset); +#endif /* Free the data segment structure itself */ wasm_runtime_free(data_list[i]); } @@ -1043,11 +1076,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end, uint32 byte_count; uint32 is_passive; uint32 memory_index; - InitializerExpression init_value; + InitializerExpression offset_expr; read_uint32(buf, buf_end, is_passive); read_uint32(buf, buf_end, memory_index); - if (!load_init_expr(&buf, buf_end, module, &init_value, error_buf, + if (!load_init_expr(&buf, buf_end, module, &offset_expr, error_buf, error_buf_size)) { return false; } @@ -1062,8 +1095,7 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end, data_list[i]->is_passive = (bool)is_passive; data_list[i]->memory_index = memory_index; #endif - data_list[i]->offset.init_expr_type = init_value.init_expr_type; - data_list[i]->offset.u = init_value.u; + data_list[i]->offset = offset_expr; data_list[i]->byte_count = byte_count; data_list[i]->bytes = NULL; /* If the module owns the binary data, clone the bytes buffer */ @@ -1148,18 +1180,6 @@ fail: return false; } -#if WASM_ENABLE_GC != 0 -static void -destroy_init_expr(InitializerExpression *expr) -{ - if (expr->init_expr_type == INIT_EXPR_TYPE_STRUCT_NEW - || expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW - || expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) { - wasm_runtime_free(expr->u.data); - } -} -#endif /* end of WASM_ENABLE_GC != 0 */ - static void destroy_import_tables(AOTImportTable *import_tables) { @@ -1183,6 +1203,9 @@ destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count) for (j = 0; j < data_list[i]->value_count; j++) { destroy_init_expr(&data_list[i]->init_values[j]); } +#endif +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(&data_list[i]->offset); #endif wasm_runtime_free(data_list[i]); } @@ -1208,34 +1231,34 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, break; case INIT_EXPR_TYPE_I32_CONST: case INIT_EXPR_TYPE_F32_CONST: - read_uint32(buf, buf_end, expr->u.i32); + read_uint32(buf, buf_end, expr->u.unary.v.i32); break; case INIT_EXPR_TYPE_I64_CONST: case INIT_EXPR_TYPE_F64_CONST: - read_uint64(buf, buf_end, expr->u.i64); + read_uint64(buf, buf_end, expr->u.unary.v.i64); break; case INIT_EXPR_TYPE_V128_CONST: - i64x2 = (uint64 *)expr->u.v128.i64x2; + i64x2 = (uint64 *)expr->u.unary.v.v128.i64x2; CHECK_BUF(buf, buf_end, sizeof(uint64) * 2); wasm_runtime_read_v128(buf, &i64x2[0], &i64x2[1]); buf += sizeof(uint64) * 2; break; case INIT_EXPR_TYPE_GET_GLOBAL: - read_uint32(buf, buf_end, expr->u.global_index); + read_uint32(buf, buf_end, expr->u.unary.v.global_index); break; /* INIT_EXPR_TYPE_FUNCREF_CONST can be used when both reference types and GC are disabled */ case INIT_EXPR_TYPE_FUNCREF_CONST: - read_uint32(buf, buf_end, expr->u.ref_index); + read_uint32(buf, buf_end, expr->u.unary.v.ref_index); break; #if WASM_ENABLE_GC != 0 || WASM_ENABLE_REF_TYPES != 0 case INIT_EXPR_TYPE_REFNULL_CONST: - read_uint32(buf, buf_end, expr->u.ref_index); + read_uint32(buf, buf_end, expr->u.unary.v.ref_index); break; #endif /* end of WASM_ENABLE_GC != 0 || WASM_ENABLE_REF_TYPES != 0 */ #if WASM_ENABLE_GC != 0 case INIT_EXPR_TYPE_I31_NEW: - read_uint32(buf, buf_end, expr->u.i32); + read_uint32(buf, buf_end, expr->u.unary.v.i32); break; case INIT_EXPR_TYPE_STRUCT_NEW: { @@ -1256,7 +1279,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, free_if_fail = true; init_values->count = field_count; init_values->type_idx = type_idx; - expr->u.data = init_values; + expr->u.unary.v.data = init_values; if (type_idx >= module->type_count) { set_error_buf(error_buf, error_buf_size, @@ -1294,7 +1317,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, break; } case INIT_EXPR_TYPE_STRUCT_NEW_DEFAULT: - read_uint32(buf, buf_end, expr->u.type_index); + read_uint32(buf, buf_end, expr->u.unary.v.type_index); break; case INIT_EXPR_TYPE_ARRAY_NEW: case INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT: @@ -1317,8 +1340,8 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, } if (init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) { - expr->u.array_new_default.type_index = type_idx; - expr->u.array_new_default.length = length; + expr->u.unary.v.array_new_default.type_index = type_idx; + expr->u.unary.v.array_new_default.length = length; } else { uint32 i, elem_size, elem_data_count; @@ -1329,7 +1352,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, return false; } free_if_fail = true; - expr->u.data = init_values; + expr->u.unary.v.data = init_values; init_values->type_idx = type_idx; init_values->length = length; @@ -1357,6 +1380,34 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, break; } #endif /* end of WASM_ENABLE_GC != 0 */ +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: + { + expr->u.binary.l_expr = expr->u.binary.r_expr = NULL; + if (!(expr->u.binary.l_expr = + loader_malloc(sizeof(InitializerExpression), error_buf, + error_buf_size))) { + goto fail; + } + if (!load_init_expr(&buf, buf_end, module, expr->u.binary.l_expr, + error_buf, error_buf_size)) + goto fail; + if (!(expr->u.binary.r_expr = + loader_malloc(sizeof(InitializerExpression), error_buf, + error_buf_size))) { + goto fail; + } + if (!load_init_expr(&buf, buf_end, module, expr->u.binary.r_expr, + error_buf, error_buf_size)) + goto fail; + break; + } +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */ default: set_error_buf(error_buf, error_buf_size, "invalid init expr type."); return false; @@ -1369,10 +1420,13 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, fail: #if WASM_ENABLE_GC != 0 if (free_if_fail) { - wasm_runtime_free(expr->u.data); + wasm_runtime_free(expr->u.unary.v.data); } #else (void)free_if_fail; +#endif +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(expr); #endif return false; } @@ -1535,14 +1589,16 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, /* Create each table data segment */ for (i = 0; i < module->table_init_data_count; i++) { uint32 mode, elem_type; - uint32 table_index, init_expr_type, value_count; - uint64 init_expr_value, size1; + uint32 table_index, value_count; + uint64 size1; + InitializerExpression offset_expr; read_uint32(buf, buf_end, mode); read_uint32(buf, buf_end, elem_type); read_uint32(buf, buf_end, table_index); - read_uint32(buf, buf_end, init_expr_type); - read_uint64(buf, buf_end, init_expr_value); + if (!load_init_expr(&buf, buf_end, module, &offset_expr, error_buf, + error_buf_size)) + return false; #if WASM_ENABLE_GC != 0 if (wasm_is_type_multi_byte_type(elem_type)) { uint16 ref_type, nullable; @@ -1588,8 +1644,7 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end, } } #endif - data_list[i]->offset.init_expr_type = (uint8)init_expr_type; - data_list[i]->offset.u.i64 = (int64)init_expr_value; + data_list[i]->offset = offset_expr; data_list[i]->value_count = value_count; for (j = 0; j < data_list[i]->value_count; j++) { if (!load_init_expr(&buf, buf_end, module, @@ -4500,7 +4555,7 @@ aot_unload(AOTModule *module) destroy_import_globals(module->import_globals); if (module->globals) { -#if WASM_ENABLE_GC != 0 +#if WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0 uint32 i; for (i = 0; i < module->global_count; i++) { destroy_init_expr(&module->globals[i].init_expr); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 9f9c6ab43..d2621fb2f 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -289,18 +289,21 @@ assign_table_init_value(AOTModuleInstance *module_inst, AOTModule *module, switch (flag) { case INIT_EXPR_TYPE_GET_GLOBAL: { - if (!check_global_init_expr(module, init_expr->u.global_index, + if (!check_global_init_expr(module, + init_expr->u.unary.v.global_index, error_buf, error_buf_size)) { return false; } - if (init_expr->u.global_index < module->import_global_count) { + if (init_expr->u.unary.v.global_index + < module->import_global_count) { PUT_REF_TO_ADDR( - addr, module->import_globals[init_expr->u.global_index] - .global_data_linked.gc_obj); + addr, + module->import_globals[init_expr->u.unary.v.global_index] + .global_data_linked.gc_obj); } else { - uint32 global_idx = - init_expr->u.global_index - module->import_global_count; + uint32 global_idx = init_expr->u.unary.v.global_index + - module->import_global_count; return assign_table_init_value( module_inst, module, &module->globals[global_idx].init_expr, addr, error_buf, error_buf_size); @@ -316,7 +319,7 @@ assign_table_init_value(AOTModuleInstance *module_inst, AOTModule *module, case INIT_EXPR_TYPE_FUNCREF_CONST: { WASMFuncObjectRef func_obj = NULL; - uint32 func_idx = init_expr->u.u32; + uint32 func_idx = init_expr->u.unary.v.u32; if (func_idx != UINT32_MAX) { if (!(func_obj = @@ -331,7 +334,8 @@ assign_table_init_value(AOTModuleInstance *module_inst, AOTModule *module, } case INIT_EXPR_TYPE_I31_NEW: { - WASMI31ObjectRef i31_obj = wasm_i31_obj_new(init_expr->u.i32); + WASMI31ObjectRef i31_obj = + wasm_i31_obj_new(init_expr->u.unary.v.i32); PUT_REF_TO_ADDR(addr, i31_obj); break; } @@ -345,11 +349,12 @@ assign_table_init_value(AOTModuleInstance *module_inst, AOTModule *module, uint32 type_idx; if (flag == INIT_EXPR_TYPE_STRUCT_NEW) { - init_values = (WASMStructNewInitValues *)init_expr->u.data; + init_values = + (WASMStructNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; } else { - type_idx = init_expr->u.type_index; + type_idx = init_expr->u.unary.v.type_index; } struct_type = (WASMStructType *)module->types[type_idx]; @@ -398,12 +403,13 @@ assign_table_init_value(AOTModuleInstance *module_inst, AOTModule *module, uint32 type_idx, len; if (flag == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) { - type_idx = init_expr->u.array_new_default.type_index; - len = init_expr->u.array_new_default.length; + type_idx = init_expr->u.unary.v.array_new_default.type_index; + len = init_expr->u.unary.v.array_new_default.length; arr_init_val = &empty_val; } else { - init_values = (WASMArrayNewInitValues *)init_expr->u.data; + init_values = + (WASMArrayNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; len = init_values->length; @@ -454,6 +460,90 @@ assign_table_init_value(AOTModuleInstance *module_inst, AOTModule *module, } #endif /* end of WASM_ENABLE_GC != 0 */ +static bool +get_init_value_recursive(AOTModuleInstance *module_inst, AOTModule *module, + InitializerExpression *expr, WASMValue *value, + char *error_buf, uint32 error_buf_size) +{ + uint8 flag = expr->init_expr_type; + switch (flag) { + case INIT_EXPR_TYPE_GET_GLOBAL: + { + if (!check_global_init_expr(module, expr->u.unary.v.global_index, + error_buf, error_buf_size)) { + return false; + } +#if WASM_ENABLE_GC == 0 + *value = module->import_globals[expr->u.unary.v.global_index] + .global_data_linked; +#else + if (expr->u.unary.v.global_index < module->import_global_count) { + *value = module->import_globals[expr->u.unary.v.global_index] + .global_data_linked; + } + else { + *value = module + ->globals[expr->u.unary.v.global_index + - module->import_global_count] + .init_expr.u.unary.v; + } +#endif + break; + } + case INIT_EXPR_TYPE_I32_CONST: + case INIT_EXPR_TYPE_I64_CONST: + { + *value = expr->u.unary.v; + break; + } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: + { + WASMValue l_value, r_value; + if (!get_init_value_recursive(module_inst, module, + expr->u.binary.l_expr, &l_value, + error_buf, error_buf_size)) { + return false; + } + if (!get_init_value_recursive(module_inst, module, + expr->u.binary.r_expr, &r_value, + error_buf, error_buf_size)) { + return false; + } + + if (flag == INIT_EXPR_TYPE_I32_ADD) { + value->i32 = l_value.i32 + r_value.i32; + } + else if (flag == INIT_EXPR_TYPE_I32_SUB) { + value->i32 = l_value.i32 - r_value.i32; + } + else if (flag == INIT_EXPR_TYPE_I32_MUL) { + value->i32 = l_value.i32 * r_value.i32; + } + else if (flag == INIT_EXPR_TYPE_I64_ADD) { + value->i64 = l_value.i64 + r_value.i64; + } + else if (flag == INIT_EXPR_TYPE_I64_SUB) { + value->i64 = l_value.i64 - r_value.i64; + } + else if (flag == INIT_EXPR_TYPE_I64_MUL) { + value->i64 = l_value.i64 * r_value.i64; + } + break; + } +#endif + default: + return false; + } + + return true; +} + static bool global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, char *error_buf, uint32 error_buf_size) @@ -482,30 +572,24 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, flag = init_expr->init_expr_type; switch (flag) { case INIT_EXPR_TYPE_GET_GLOBAL: + case INIT_EXPR_TYPE_I32_CONST: + case INIT_EXPR_TYPE_I64_CONST: +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: +#endif { - if (!check_global_init_expr(module, init_expr->u.global_index, - error_buf, error_buf_size)) { + WASMValue value; + if (!get_init_value_recursive(module_inst, module, init_expr, + &value, error_buf, + error_buf_size)) { return false; } -#if WASM_ENABLE_GC == 0 - init_global_data( - p, global->type.val_type, - &module->import_globals[init_expr->u.global_index] - .global_data_linked); -#else - if (init_expr->u.global_index < module->import_global_count) { - init_global_data( - p, global->type.val_type, - &module->import_globals[init_expr->u.global_index] - .global_data_linked); - } - else { - uint32 global_idx = - init_expr->u.global_index - module->import_global_count; - init_global_data(p, global->type.val_type, - &module->globals[global_idx].init_expr.u); - } -#endif + init_global_data(p, global->type.val_type, &value); break; } #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 @@ -526,7 +610,7 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, case INIT_EXPR_TYPE_FUNCREF_CONST: { WASMFuncObjectRef func_obj = NULL; - uint32 func_idx = init_expr->u.u32; + uint32 func_idx = init_expr->u.unary.v.ref_index; if (func_idx != UINT32_MAX) { if (!(func_obj = @@ -541,7 +625,8 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, } case INIT_EXPR_TYPE_I31_NEW: { - WASMI31ObjectRef i31_obj = wasm_i31_obj_new(init_expr->u.i32); + WASMI31ObjectRef i31_obj = + wasm_i31_obj_new(init_expr->u.unary.v.i32); PUT_REF_TO_ADDR(p, i31_obj); break; } @@ -555,11 +640,12 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint32 type_idx; if (flag == INIT_EXPR_TYPE_STRUCT_NEW) { - init_values = (WASMStructNewInitValues *)init_expr->u.data; + init_values = + (WASMStructNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; } else { - type_idx = init_expr->u.type_index; + type_idx = init_expr->u.unary.v.type_index; } struct_type = (WASMStructType *)module->types[type_idx]; @@ -609,12 +695,14 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint32 type_idx, len; if (flag == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) { - type_idx = init_expr->u.array_new_default.type_index; - len = init_expr->u.array_new_default.length; + type_idx = + init_expr->u.unary.v.array_new_default.type_index; + len = init_expr->u.unary.v.array_new_default.length; arr_init_val = &empty_val; } else { - init_values = (WASMArrayNewInitValues *)init_expr->u.data; + init_values = + (WASMArrayNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; len = init_values->length; @@ -660,7 +748,8 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #endif /* end of WASM_ENABLE_GC != 0 */ default: { - init_global_data(p, global->type.val_type, &init_expr->u); + init_global_data(p, global->type.val_type, + &init_expr->u.unary.v); break; } } @@ -681,6 +770,7 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint64 total_size; AOTTableInitData *table_seg; AOTTableInstance *tbl_inst = first_tbl_inst; + uint8 offset_flag; total_size = (uint64)sizeof(AOTTableInstance *) * module_inst->table_count; if (total_size > 0 @@ -753,28 +843,25 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, tbl_inst = module_inst->tables[table_seg->table_index]; bh_assert(tbl_inst); + offset_flag = table_seg->offset.init_expr_type; + #if WASM_ENABLE_REF_TYPES != 0 - bh_assert( - table_seg->offset.init_expr_type - == (tbl_inst->is_table64 ? INIT_EXPR_TYPE_I64_CONST - : INIT_EXPR_TYPE_I32_CONST) - || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL - || table_seg->offset.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST - || table_seg->offset.init_expr_type - == INIT_EXPR_TYPE_REFNULL_CONST); + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || offset_flag == INIT_EXPR_TYPE_FUNCREF_CONST + || offset_flag == INIT_EXPR_TYPE_REFNULL_CONST + || (tbl_inst->is_table64 ? is_valid_i64_offset(offset_flag) + : is_valid_i32_offset(offset_flag))); #else - bh_assert(table_seg->offset.init_expr_type - == (tbl_inst->is_table64 ? INIT_EXPR_TYPE_I64_CONST - : INIT_EXPR_TYPE_I32_CONST) - || table_seg->offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL); + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || (tbl_inst->is_table64 ? is_valid_i64_offset(offset_flag) + : is_valid_i32_offset(offset_flag))); #endif /* Resolve table data base offset */ /* TODO: The table64 current implementation assumes table max size * UINT32_MAX, so the offset conversion here is safe */ - if (table_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - global_index = table_seg->offset.u.global_index; + if (offset_flag == INIT_EXPR_TYPE_GET_GLOBAL) { + global_index = table_seg->offset.u.unary.v.global_index; if (!check_global_init_expr(module, global_index, error_buf, error_buf_size)) { @@ -792,8 +879,15 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, base_offset = *(uint32 *)(module_inst->global_data + global_data_offset); } - else - base_offset = (uint32)table_seg->offset.u.i32; + else { + WASMValue offset_value; + if (!get_init_value_recursive(module_inst, module, + &table_seg->offset, &offset_value, + error_buf, error_buf_size)) { + return false; + } + base_offset = (uint32)offset_value.i32; + } /* Copy table data */ /* base_offset only since length might negative */ @@ -828,7 +922,7 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #if WASM_ENABLE_GC == 0 for (j = 0; j < length; j++) { tbl_inst->elems[base_offset + j] = - table_seg->init_values[j].u.ref_index; + table_seg->init_values[j].u.unary.v.ref_index; } #endif } @@ -1128,6 +1222,7 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, AOTMemInitData *data_seg; uint64 total_size; mem_offset_t base_offset; + uint8 offset_flag; module_inst->memory_count = memory_count; total_size = sizeof(AOTMemoryInstance *) * (uint64)memory_count; @@ -1166,15 +1261,15 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, initialized */ continue; - bh_assert(data_seg->offset.init_expr_type - == (memory_inst->is_memory64 ? INIT_EXPR_TYPE_I64_CONST - : INIT_EXPR_TYPE_I32_CONST) - || data_seg->offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL); + offset_flag = data_seg->offset.init_expr_type; + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || (memory_inst->is_memory64 + ? is_valid_i64_offset(offset_flag) + : is_valid_i32_offset(offset_flag))); /* Resolve memory data base offset */ - if (data_seg->offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - global_index = data_seg->offset.u.global_index; + if (offset_flag == INIT_EXPR_TYPE_GET_GLOBAL) { + global_index = data_seg->offset.u.unary.v.global_index; if (!check_global_init_expr(module, global_index, error_buf, error_buf_size)) { @@ -1202,14 +1297,20 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, } } else { + WASMValue offset_value; + if (!get_init_value_recursive(module_inst, module, + &data_seg->offset, &offset_value, + error_buf, error_buf_size)) { + return false; + } #if WASM_ENABLE_MEMORY64 != 0 if (memory_inst->is_memory64) { - base_offset = data_seg->offset.u.i64; + base_offset = offset_value.i64; } else #endif { - base_offset = data_seg->offset.u.u32; + base_offset = offset_value.u32; } } @@ -2055,6 +2156,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, uint8 tbl_elem_type; uint32 tbl_init_size, tbl_max_size, j; WASMRefType *tbl_elem_ref_type; + WASMValue offset_value; bh_assert(table_init_data); @@ -2086,69 +2188,73 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, if (!wasm_elem_is_active(table_init_data->mode)) { continue; } - - bh_assert(table_init_data->offset.init_expr_type - == INIT_EXPR_TYPE_I32_CONST - || table_init_data->offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL - || table_init_data->offset.init_expr_type - == INIT_EXPR_TYPE_FUNCREF_CONST - || table_init_data->offset.init_expr_type - == INIT_EXPR_TYPE_REFNULL_CONST); + uint8 offset_flag = table_init_data->offset.init_expr_type; + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || offset_flag == INIT_EXPR_TYPE_FUNCREF_CONST + || offset_flag == INIT_EXPR_TYPE_REFNULL_CONST + || offset_flag == INIT_EXPR_TYPE_I32_CONST + || offset_flag == INIT_EXPR_TYPE_I32_ADD + || offset_flag == INIT_EXPR_TYPE_I32_SUB + || offset_flag == INIT_EXPR_TYPE_I32_MUL); /* init vec(funcidx) or vec(expr) */ - if (table_init_data->offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL) { + if (offset_flag == INIT_EXPR_TYPE_GET_GLOBAL) { uint32 data_offset; - if (!check_global_init_expr(module, - table_init_data->offset.u.global_index, - error_buf, error_buf_size)) { + if (!check_global_init_expr( + module, table_init_data->offset.u.unary.v.global_index, + error_buf, error_buf_size)) { goto fail; } - if (table_init_data->offset.u.global_index + if (table_init_data->offset.u.unary.v.global_index < module->import_global_count) { - data_offset = - module - ->import_globals[table_init_data->offset.u.global_index] - .data_offset; + data_offset = module + ->import_globals[table_init_data->offset.u + .unary.v.global_index] + .data_offset; } else { data_offset = module - ->globals[table_init_data->offset.u.global_index + ->globals[table_init_data->offset.u.unary.v.global_index - module->import_global_count] .data_offset; } - - table_init_data->offset.u.i32 = + offset_value.i32 = *(uint32 *)(module_inst->global_data + data_offset); } + else { + if (!get_init_value_recursive( + module_inst, module, &table_init_data->offset, + &offset_value, error_buf, error_buf_size)) { + goto fail; + } + } /* check offset since length might negative */ - if ((uint32)table_init_data->offset.u.i32 > table->cur_size) { - LOG_DEBUG("base_offset(%d) > table->cur_size(%d)", - table_init_data->offset.u.i32, table->cur_size); + if ((uint32)offset_value.i32 > table->cur_size) { + LOG_DEBUG("base_offset(%d) > table->cur_size(%d)", offset_value.i32, + table->cur_size); set_error_buf(error_buf, error_buf_size, "out of bounds table access"); goto fail; } - if ((uint32)table_init_data->offset.u.i32 + table_init_data->value_count + if ((uint32)offset_value.i32 + table_init_data->value_count > table->cur_size) { LOG_DEBUG("base_offset(%d) + length(%d) > table->cur_size(%d)", - table_init_data->offset.u.i32, - table_init_data->value_count, table->cur_size); + offset_value.i32, table_init_data->value_count, + table->cur_size); set_error_buf(error_buf, error_buf_size, "out of bounds table access"); goto fail; } for (j = 0; j < module->table_init_data_list[i]->value_count; j++) { - if (!assign_table_init_value( - module_inst, module, &table_init_data->init_values[j], - table_data + table_init_data->offset.u.i32 + j, error_buf, - error_buf_size)) { + if (!assign_table_init_value(module_inst, module, + &table_init_data->init_values[j], + table_data + offset_value.i32 + j, + error_buf, error_buf_size)) { goto fail; } } @@ -3741,10 +3847,10 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx, for (i = 0; i < length; i++) { #if WASM_ENABLE_GC != 0 /* UINT32_MAX indicates that it is a null ref */ - if (init_values[i].u.ref_index != UINT32_MAX) { - if (!(func_obj = aot_create_func_obj(module_inst, - init_values[i].u.ref_index, - true, NULL, 0))) { + if (init_values[i].u.unary.v.ref_index != UINT32_MAX) { + if (!(func_obj = aot_create_func_obj( + module_inst, init_values[i].u.unary.v.ref_index, true, + NULL, 0))) { aot_set_exception_with_id(module_inst, EXCE_NULL_FUNC_OBJ); return; } @@ -3754,7 +3860,7 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx, table_elems[i] = NULL_REF; } #else - table_elems[i] = init_values[i].u.ref_index; + table_elems[i] = init_values[i].u.unary.v.ref_index; #endif } } diff --git a/core/iwasm/common/wasm_loader_common.c b/core/iwasm/common/wasm_loader_common.c index dc8009205..4243e9198 100644 --- a/core/iwasm/common/wasm_loader_common.c +++ b/core/iwasm/common/wasm_loader_common.c @@ -225,3 +225,18 @@ read_leb(uint8 **p_buf, const uint8 *buf_end, uint32 maxbits, bool sign, return false; } } + +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 +void +destroy_init_expr_recursive(InitializerExpression *expr) +{ + if (expr == NULL) { + return; + } + if (is_expr_binary_op(expr->init_expr_type)) { + destroy_init_expr_recursive(expr->u.binary.l_expr); + destroy_init_expr_recursive(expr->u.binary.r_expr); + } + wasm_runtime_free(expr); +} +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */ diff --git a/core/iwasm/common/wasm_loader_common.h b/core/iwasm/common/wasm_loader_common.h index 81174fb26..d5394bf99 100644 --- a/core/iwasm/common/wasm_loader_common.h +++ b/core/iwasm/common/wasm_loader_common.h @@ -50,6 +50,11 @@ void wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size, const char *string, bool is_aot); +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 +void +destroy_init_expr_recursive(InitializerExpression *expr); +#endif + #ifdef __cplusplus } #endif diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 7d0654b78..db1c04d88 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -216,7 +216,7 @@ get_init_expr_size(const AOTCompContext *comp_ctx, const AOTCompData *comp_data, #if WASM_ENABLE_GC != 0 WASMModule *module = comp_data->wasm_module; #endif - + bh_assert(expr != NULL); /* + init value size */ switch (expr->init_expr_type) { case INIT_EXPR_NONE: @@ -248,7 +248,7 @@ get_init_expr_size(const AOTCompContext *comp_ctx, const AOTCompData *comp_data, { uint32 i; WASMStructNewInitValues *struct_new_init_values = - (WASMStructNewInitValues *)expr->u.data; + (WASMStructNewInitValues *)expr->u.unary.v.data; /* type_index + field_count + fields */ size += sizeof(uint32) + sizeof(uint32); @@ -285,7 +285,7 @@ get_init_expr_size(const AOTCompContext *comp_ctx, const AOTCompData *comp_data, case INIT_EXPR_TYPE_ARRAY_NEW_FIXED: { WASMArrayNewInitValues *array_new_init_values = - (WASMArrayNewInitValues *)expr->u.data; + (WASMArrayNewInitValues *)expr->u.unary.v.data; WASMArrayType *array_type = NULL; uint32 value_count; @@ -308,6 +308,21 @@ get_init_expr_size(const AOTCompContext *comp_ctx, const AOTCompData *comp_data, break; } #endif /* end of WASM_ENABLE_GC != 0 */ +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: + { + size += + get_init_expr_size(comp_ctx, comp_data, expr->u.binary.l_expr); + size += + get_init_expr_size(comp_ctx, comp_data, expr->u.binary.r_expr); + break; + } +#endif default: bh_assert(0); } @@ -324,15 +339,16 @@ get_table_init_data_size(AOTCompContext *comp_ctx, /* * mode (4 bytes), elem_type (4 bytes) * - * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8 - * bytes) + * table_index(4 bytes) */ - size = (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32) - + sizeof(uint64)) + size = (uint32)(sizeof(uint32) * 2 + sizeof(uint32)) /* Size of WasmRefType - inner padding (ref type + nullable + heap_type) */ + 8; + size += get_init_expr_size(comp_ctx, comp_ctx->comp_data, + &table_init_data->offset); + /* + value count/func index count (4 bytes) + init_values */ size += sizeof(uint32); for (i = 0; i < table_init_data->value_count; i++) { @@ -1811,6 +1827,10 @@ static bool aot_emit_init_expr(uint8 *buf, uint8 *buf_end, uint32 *p_offset, AOTCompContext *comp_ctx, InitializerExpression *expr) { + if (expr == NULL) { + aot_set_last_error("invalid init expr."); + return false; + } uint32 offset = *p_offset; #if WASM_ENABLE_GC != 0 WASMModule *module = comp_ctx->comp_data->wasm_module; @@ -1824,31 +1844,31 @@ aot_emit_init_expr(uint8 *buf, uint8 *buf_end, uint32 *p_offset, break; case INIT_EXPR_TYPE_I32_CONST: case INIT_EXPR_TYPE_F32_CONST: - EMIT_U32(expr->u.i32); + EMIT_U32(expr->u.unary.v.i32); break; case INIT_EXPR_TYPE_I64_CONST: case INIT_EXPR_TYPE_F64_CONST: - EMIT_U64(expr->u.i64); + EMIT_U64(expr->u.unary.v.i64); break; case INIT_EXPR_TYPE_V128_CONST: - EMIT_V128(expr->u.v128); + EMIT_V128(expr->u.unary.v.v128); break; case INIT_EXPR_TYPE_GET_GLOBAL: - EMIT_U32(expr->u.global_index); + EMIT_U32(expr->u.unary.v.global_index); break; case INIT_EXPR_TYPE_FUNCREF_CONST: case INIT_EXPR_TYPE_REFNULL_CONST: - EMIT_U32(expr->u.ref_index); + EMIT_U32(expr->u.unary.v.ref_index); break; #if WASM_ENABLE_GC != 0 case INIT_EXPR_TYPE_I31_NEW: - EMIT_U32(expr->u.i32); + EMIT_U32(expr->u.unary.v.i32); break; case INIT_EXPR_TYPE_STRUCT_NEW: { uint32 i; WASMStructNewInitValues *init_values = - (WASMStructNewInitValues *)expr->u.data; + (WASMStructNewInitValues *)expr->u.unary.v.data; WASMStructType *struct_type = NULL; EMIT_U32(init_values->type_idx); @@ -1879,7 +1899,7 @@ aot_emit_init_expr(uint8 *buf, uint8 *buf_end, uint32 *p_offset, break; } case INIT_EXPR_TYPE_STRUCT_NEW_DEFAULT: - EMIT_U32(expr->u.type_index); + EMIT_U32(expr->u.unary.v.type_index); break; case INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT: { @@ -1889,11 +1909,11 @@ aot_emit_init_expr(uint8 *buf, uint8 *buf_end, uint32 *p_offset, < module->type_count); array_type = (WASMArrayType *) - module->types[expr->u.array_new_default.type_index]; + module->types[expr->u.unary.v.array_new_default.type_index]; EMIT_U32(array_type->elem_type); - EMIT_U32(expr->u.array_new_default.type_index); - EMIT_U32(expr->u.array_new_default.length); + EMIT_U32(expr->u.unary.v.array_new_default.type_index); + EMIT_U32(expr->u.unary.v.array_new_default.length); break; } case INIT_EXPR_TYPE_ARRAY_NEW: @@ -1901,7 +1921,7 @@ aot_emit_init_expr(uint8 *buf, uint8 *buf_end, uint32 *p_offset, { uint32 value_count, i, field_size; WASMArrayNewInitValues *init_values = - (WASMArrayNewInitValues *)expr->u.data; + (WASMArrayNewInitValues *)expr->u.unary.v.data; WASMArrayType *array_type = NULL; bh_assert(init_values->type_idx < module->type_count); @@ -1933,6 +1953,25 @@ aot_emit_init_expr(uint8 *buf, uint8 *buf_end, uint32 *p_offset, break; } #endif /* end of WASM_ENABLE_GC != 0 */ +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: + if (comp_ctx->enable_extended_const) { + if (!aot_emit_init_expr(buf, buf_end, &offset, comp_ctx, + expr->u.binary.l_expr)) { + return false; + } + if (!aot_emit_init_expr(buf, buf_end, &offset, comp_ctx, + expr->u.binary.r_expr)) { + return false; + } + } + break; +#endif default: aot_set_last_error("invalid init expr type."); return false; @@ -2034,8 +2073,10 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset, EMIT_U32(init_datas[i]->mode); EMIT_U32(init_datas[i]->elem_type); EMIT_U32(init_datas[i]->table_index); - EMIT_U32(init_datas[i]->offset.init_expr_type); - EMIT_U64(init_datas[i]->offset.u.i64); + if (!aot_emit_init_expr(buf, buf_end, &offset, comp_ctx, + &init_datas[i]->offset)) + return false; + #if WASM_ENABLE_GC != 0 if (comp_ctx->enable_gc && init_datas[i]->elem_ref_type) { EMIT_U16(init_datas[i]->elem_ref_type->ref_ht_common.ref_type); diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index a71e147a2..5190a39d4 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -2787,6 +2787,9 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) if (option->enable_shared_chain) comp_ctx->enable_shared_chain = true; + if (option->enable_extended_const) + comp_ctx->enable_extended_const = true; + comp_ctx->opt_level = option->opt_level; comp_ctx->size_level = option->size_level; diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index b4228c67a..9f62f6616 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -461,6 +461,9 @@ typedef struct AOTCompContext { /* Enable LLVM PGO (Profile-Guided Optimization) */ bool enable_llvm_pgo; + /* Enable extended constant expression */ + bool enable_extended_const; + /* Treat unknown import function as wasm-c-api import function and allow to directly invoke it from AOT/JIT code */ bool quick_invoke_c_api_import; diff --git a/core/iwasm/fast-jit/fe/jit_emit_table.c b/core/iwasm/fast-jit/fe/jit_emit_table.c index 6da5b820f..efdf5cf14 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_table.c +++ b/core/iwasm/fast-jit/fe/jit_emit_table.c @@ -121,7 +121,8 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 seg_idx, + dst_offset * sizeof(table_elem_type_t)); init_values = tbl_seg_init_values + src_offset; for (i = 0; i < len; i++) { - addr[i] = (table_elem_type_t)(uintptr_t)init_values[+i].u.ref_index; + addr[i] = + (table_elem_type_t)(uintptr_t)init_values[+i].u.unary.v.ref_index; } return 0; diff --git a/core/iwasm/include/aot_comp_option.h b/core/iwasm/include/aot_comp_option.h index e12f3f6fc..069ceab31 100644 --- a/core/iwasm/include/aot_comp_option.h +++ b/core/iwasm/include/aot_comp_option.h @@ -68,6 +68,7 @@ typedef struct AOTCompOption { bool enable_ref_types; bool enable_gc; bool enable_aux_stack_check; + bool enable_extended_const; AOTStackFrameType aux_stack_frame_type; AOTCallStackFeatures call_stack_features; bool enable_perf_profiling; diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index ddc0b15b4..0dd73958e 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -135,6 +135,12 @@ typedef void *table_elem_type_t; #define INIT_EXPR_TYPE_F64_CONST 0x44 #define INIT_EXPR_TYPE_V128_CONST 0xFD #define INIT_EXPR_TYPE_GET_GLOBAL 0x23 +#define INIT_EXPR_TYPE_I32_ADD 0x6A +#define INIT_EXPR_TYPE_I32_SUB 0x6B +#define INIT_EXPR_TYPE_I32_MUL 0x6C +#define INIT_EXPR_TYPE_I64_ADD 0x7C +#define INIT_EXPR_TYPE_I64_SUB 0x7D +#define INIT_EXPR_TYPE_I64_MUL 0x7E #define INIT_EXPR_TYPE_REFNULL_CONST 0xD0 #define INIT_EXPR_TYPE_FUNCREF_CONST 0xD2 #define INIT_EXPR_TYPE_STRUCT_NEW 0xD3 @@ -277,9 +283,41 @@ typedef struct InitializerExpression { /* type of INIT_EXPR_TYPE_XXX, which is an instruction of constant expression */ uint8 init_expr_type; - WASMValue u; + union { + struct { + WASMValue v; + } unary; + struct { + struct InitializerExpression *l_expr; + struct InitializerExpression *r_expr; + } binary; + } u; } InitializerExpression; +static inline bool +is_expr_binary_op(uint8 flag) +{ + return flag == INIT_EXPR_TYPE_I32_ADD || flag == INIT_EXPR_TYPE_I32_SUB + || flag == INIT_EXPR_TYPE_I32_MUL || flag == INIT_EXPR_TYPE_I64_ADD + || flag == INIT_EXPR_TYPE_I64_SUB || flag == INIT_EXPR_TYPE_I64_MUL; +} + +/* check if table or data offset is valid for i32 offset */ +static inline bool +is_valid_i32_offset(uint8 flag) +{ + return flag == INIT_EXPR_TYPE_I32_CONST || flag == INIT_EXPR_TYPE_I32_ADD + || flag == INIT_EXPR_TYPE_I32_SUB || flag == INIT_EXPR_TYPE_I32_MUL; +} + +/* check if table or data offset is valid for i64 offset */ +static inline bool +is_valid_i64_offset(uint8 flag) +{ + return flag == INIT_EXPR_TYPE_I64_CONST || flag == INIT_EXPR_TYPE_I64_ADD + || flag == INIT_EXPR_TYPE_I64_SUB || flag == INIT_EXPR_TYPE_I64_MUL; +} + #if WASM_ENABLE_GC != 0 /** * Reference type of (ref null ht) or (ref ht), diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index dbbc7af01..edc473f2c 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -5958,12 +5958,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, || init_values[i].init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST); #if WASM_ENABLE_GC == 0 - table_elems[i] = - (table_elem_type_t)init_values[i].u.ref_index; + table_elems[i] = (table_elem_type_t)init_values[i] + .u.unary.v.ref_index; #else - if (init_values[i].u.ref_index != UINT32_MAX) { + if (init_values[i].u.unary.v.ref_index + != UINT32_MAX) { if (!(func_obj = wasm_create_func_obj( - module, init_values[i].u.ref_index, + module, + init_values[i].u.unary.v.ref_index, true, NULL, 0))) { goto got_exception; } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 4c7b246d5..4e99c679d 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -5350,12 +5350,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, || init_values[i].init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST); #if WASM_ENABLE_GC == 0 - table_elems[i] = - (table_elem_type_t)init_values[i].u.ref_index; + table_elems[i] = (table_elem_type_t)init_values[i] + .u.unary.v.ref_index; #else - if (init_values[i].u.ref_index != UINT32_MAX) { + if (init_values[i].u.unary.v.ref_index + != UINT32_MAX) { if (!(func_obj = wasm_create_func_obj( - module, init_values[i].u.ref_index, + module, + init_values[i].u.unary.v.ref_index, true, NULL, 0))) { goto got_exception; } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 5dd9f0520..12e68c06e 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -453,6 +453,9 @@ typedef struct InitValue { WASMRefType ref_type; #endif WASMValue value; +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression *expr; +#endif } InitValue; typedef struct ConstExprContext { @@ -477,7 +480,11 @@ push_const_expr_stack(ConstExprContext *ctx, uint8 flag, uint8 type, #if WASM_ENABLE_GC != 0 WASMRefType *ref_type, uint8 gc_opcode, #endif - WASMValue *value, char *error_buf, uint32 error_buf_size) + WASMValue *value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression *expr, +#endif + char *error_buf, uint32 error_buf_size) { InitValue *cur_value; @@ -503,6 +510,10 @@ push_const_expr_stack(ConstExprContext *ctx, uint8 flag, uint8 type, cur_value->flag = flag; cur_value->value = *value; +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + cur_value->expr = expr; +#endif + #if WASM_ENABLE_GC != 0 cur_value->gc_opcode = gc_opcode; if (wasm_is_type_multi_byte_type(type)) { @@ -587,7 +598,11 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, #if WASM_ENABLE_GC != 0 WASMRefType *ref_type, uint8 *p_gc_opcode, #endif - WASMValue *p_value, char *error_buf, uint32 error_buf_size) + WASMValue *p_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression **p_expr, +#endif + char *error_buf, uint32 error_buf_size) { InitValue *cur_value; @@ -623,7 +638,10 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, if (p_gc_opcode) *p_gc_opcode = cur_value->gc_opcode; #endif - +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + if (p_expr) + *p_expr = cur_value->expr; +#endif return true; #if WASM_ENABLE_GC != 0 @@ -639,7 +657,7 @@ fail: } static void -destroy_const_expr_stack(ConstExprContext *ctx) +destroy_const_expr_stack(ConstExprContext *ctx, bool free_exprs) { #if WASM_ENABLE_GC != 0 uint32 i; @@ -654,24 +672,62 @@ destroy_const_expr_stack(ConstExprContext *ctx) } } #endif +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + if (free_exprs) { + for (uint32 j = 0; j < ctx->sp; j++) { + if (is_expr_binary_op(ctx->stack[j].expr->init_expr_type)) { + destroy_init_expr_recursive(ctx->stack[j].expr); + ctx->stack[j].expr = NULL; + } + } + } +#endif if (ctx->stack != ctx->data) { wasm_runtime_free(ctx->stack); } } -#if WASM_ENABLE_GC != 0 +#if WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0 static void destroy_init_expr(WASMModule *module, InitializerExpression *expr) { +#if WASM_ENABLE_GC != 0 if (expr->init_expr_type == INIT_EXPR_TYPE_STRUCT_NEW || expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW || expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) { - destroy_init_expr_data_recursive(module, expr->u.data); + destroy_init_expr_data_recursive(module, expr->u.unary.v.data); } -} -#endif /* end of WASM_ENABLE_GC != 0 */ +#endif +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + // free left expr and right exprs for binary oprand + if (!is_expr_binary_op(expr->init_expr_type)) { + return; + } + if (expr->u.binary.l_expr) { + destroy_init_expr_recursive(expr->u.binary.l_expr); + } + if (expr->u.binary.r_expr) { + destroy_init_expr_recursive(expr->u.binary.r_expr); + } + expr->u.binary.l_expr = expr->u.binary.r_expr = NULL; +#endif +} +#endif + +/* for init expr + * (data (i32.add (i32.const 0) (i32.sub (i32.const 1) (i32.const 2)))), + * the binary format is + * 0x11: 41 00 ; i32.const 0 + * 0x13: 41 01 ; i32.const 1 + * 0x15: 41 02 ; i32.const 2 + * 0x17: 6b ; i32.sub + * 0x18: 6a ; i32.add + * for traversal: read opcodes and push them onto the stack. When encountering + * a binary opcode, pop two values from the stack which become the left and + * right child nodes of this binary operation node. + */ static bool load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, InitializerExpression *init_expr, uint8 type, void *ref_type, @@ -687,6 +743,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, uint8 opcode; WASMRefType cur_ref_type = { 0 }; #endif +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression *cur_expr = NULL; +#endif init_const_expr_stack(&const_expr_ctx, module); @@ -699,24 +758,32 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, case INIT_EXPR_TYPE_I32_CONST: read_leb_int32(p, p_end, cur_value.i32); - if (!push_const_expr_stack( - &const_expr_ctx, flag, VALUE_TYPE_I32, + if (!push_const_expr_stack(&const_expr_ctx, flag, + VALUE_TYPE_I32, #if WASM_ENABLE_GC != 0 - NULL, 0, + NULL, 0, #endif - &cur_value, error_buf, error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; break; /* i64.const */ case INIT_EXPR_TYPE_I64_CONST: read_leb_int64(p, p_end, cur_value.i64); - if (!push_const_expr_stack( - &const_expr_ctx, flag, VALUE_TYPE_I64, + if (!push_const_expr_stack(&const_expr_ctx, flag, + VALUE_TYPE_I64, #if WASM_ENABLE_GC != 0 - NULL, 0, + NULL, 0, #endif - &cur_value, error_buf, error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; break; /* f32.const */ @@ -726,12 +793,16 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, for (i = 0; i < sizeof(float32); i++) *p_float++ = *p++; - if (!push_const_expr_stack( - &const_expr_ctx, flag, VALUE_TYPE_F32, + if (!push_const_expr_stack(&const_expr_ctx, flag, + VALUE_TYPE_F32, #if WASM_ENABLE_GC != 0 - NULL, 0, + NULL, 0, #endif - &cur_value, error_buf, error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; break; /* f64.const */ @@ -741,12 +812,16 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, for (i = 0; i < sizeof(float64); i++) *p_float++ = *p++; - if (!push_const_expr_stack( - &const_expr_ctx, flag, VALUE_TYPE_F64, + if (!push_const_expr_stack(&const_expr_ctx, flag, + VALUE_TYPE_F64, #if WASM_ENABLE_GC != 0 - NULL, 0, + NULL, 0, #endif - &cur_value, error_buf, error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; break; #if WASM_ENABLE_SIMD != 0 @@ -767,12 +842,16 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, cur_value.v128.i64x2[0] = high; cur_value.v128.i64x2[1] = low; - if (!push_const_expr_stack( - &const_expr_ctx, flag, VALUE_TYPE_V128, + if (!push_const_expr_stack(&const_expr_ctx, flag, + VALUE_TYPE_V128, #if WASM_ENABLE_GC != 0 - NULL, 0, + NULL, 0, #endif - &cur_value, error_buf, error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; #if WASM_ENABLE_WAMR_COMPILER != 0 /* If any init_expr is v128.const, mark SIMD used */ @@ -783,7 +862,92 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, #endif /* end of (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) || \ (WASM_ENABLE_FAST_INTERP != 0) */ #endif /* end of WASM_ENABLE_SIMD */ +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: + { + InitializerExpression *l_expr, *r_expr; + WASMValue l_value, r_value; + uint8 l_flag, r_flag; + uint8 value_type; + + if (flag == INIT_EXPR_TYPE_I32_ADD + || flag == INIT_EXPR_TYPE_I32_SUB + || flag == INIT_EXPR_TYPE_I32_MUL) { + value_type = VALUE_TYPE_I32; + } + else { + value_type = VALUE_TYPE_I64; + } + + /* If right flag indicates a binary operation, right expr will + * be popped from stack. Otherwise, allocate a new expr for + * right expr. Same for left expr. + */ + if (!(pop_const_expr_stack(&const_expr_ctx, &r_flag, value_type, +#if WASM_ENABLE_GC != 0 + NULL, NULL, +#endif + &r_value, &r_expr, error_buf, + error_buf_size))) { + goto fail; + } + if (!is_expr_binary_op(r_flag)) { + if (!(r_expr = loader_malloc(sizeof(InitializerExpression), + error_buf, error_buf_size))) { + goto fail; + } + r_expr->init_expr_type = r_flag; + r_expr->u.unary.v = r_value; + } + + if (!(pop_const_expr_stack(&const_expr_ctx, &l_flag, value_type, +#if WASM_ENABLE_GC != 0 + NULL, NULL, +#endif + &l_value, &l_expr, error_buf, + error_buf_size))) { + destroy_init_expr_recursive(r_expr); + goto fail; + } + if (!is_expr_binary_op(l_flag)) { + if (!(l_expr = loader_malloc(sizeof(InitializerExpression), + error_buf, error_buf_size))) { + destroy_init_expr_recursive(r_expr); + goto fail; + } + l_expr->init_expr_type = l_flag; + l_expr->u.unary.v = l_value; + } + + if (!(cur_expr = loader_malloc(sizeof(InitializerExpression), + error_buf, error_buf_size))) { + destroy_init_expr_recursive(l_expr); + destroy_init_expr_recursive(r_expr); + goto fail; + } + cur_expr->init_expr_type = flag; + cur_expr->u.binary.l_expr = l_expr; + cur_expr->u.binary.r_expr = r_expr; + + if (!push_const_expr_stack(&const_expr_ctx, flag, value_type, +#if WASM_ENABLE_GC != 0 + NULL, 0, +#endif + &cur_value, cur_expr, error_buf, + error_buf_size)) { + destroy_init_expr_recursive(cur_expr); + goto fail; + } + + break; + } +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR */ #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 /* ref.func */ case INIT_EXPR_TYPE_FUNCREF_CONST: @@ -799,6 +963,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_GC == 0 if (!push_const_expr_stack(&const_expr_ctx, flag, VALUE_TYPE_FUNCREF, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) goto fail; #else @@ -816,8 +983,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, false, type_idx); if (!push_const_expr_stack(&const_expr_ctx, flag, cur_ref_type.ref_type, &cur_ref_type, - 0, &cur_value, error_buf, - error_buf_size)) + 0, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; #endif #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -837,8 +1007,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, cur_value.ref_index = NULL_REF; if (!push_const_expr_stack(&const_expr_ctx, flag, type1, - &cur_value, error_buf, - error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; #else int32 heap_type; @@ -861,13 +1034,19 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack(&const_expr_ctx, flag, cur_ref_type.ref_type, &cur_ref_type, 0, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) goto fail; } else { if (!push_const_expr_stack(&const_expr_ctx, flag, type1, - NULL, 0, &cur_value, error_buf, - error_buf_size)) + NULL, 0, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; } #endif @@ -956,8 +1135,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_GC != 0 &cur_ref_type, 0, #endif - &cur_value, error_buf, - error_buf_size)) + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) goto fail; break; @@ -1020,6 +1202,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, &const_expr_ctx, NULL, field_type, field_ref_type, NULL, &struct_init_values->fields[field_idx], +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { destroy_init_expr_data_recursive( module, struct_init_values); @@ -1033,6 +1218,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack( &const_expr_ctx, flag, cur_ref_type.ref_type, &cur_ref_type, (uint8)opcode1, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { destroy_init_expr_data_recursive( module, struct_init_values); @@ -1064,6 +1252,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack( &const_expr_ctx, flag, cur_ref_type.ref_type, &cur_ref_type, (uint8)opcode1, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { goto fail; } @@ -1112,8 +1303,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!pop_const_expr_stack( &const_expr_ctx, NULL, VALUE_TYPE_I32, - NULL, NULL, &len_val, error_buf, - error_buf_size)) { + NULL, NULL, &len_val, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) { goto fail; } @@ -1132,6 +1326,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, &const_expr_ctx, NULL, elem_type, elem_ref_type, NULL, &array_init_values->elem_data[0], +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { destroy_init_expr_data_recursive( module, array_init_values); @@ -1164,6 +1361,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, elem_ref_type, NULL, &array_init_values ->elem_data[i - 1], +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { destroy_init_expr_data_recursive( module, array_init_values); @@ -1180,10 +1380,13 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, uint32 len; /* POP(i32) */ - if (!pop_const_expr_stack(&const_expr_ctx, NULL, - VALUE_TYPE_I32, NULL, - NULL, &len_val, error_buf, - error_buf_size)) { + if (!pop_const_expr_stack( + &const_expr_ctx, NULL, VALUE_TYPE_I32, NULL, + NULL, &len_val, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) { goto fail; } len = len_val.i32; @@ -1197,6 +1400,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack( &const_expr_ctx, flag, cur_ref_type.ref_type, &cur_ref_type, (uint8)opcode1, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { if (array_init_values) { destroy_init_expr_data_recursive( @@ -1223,9 +1429,13 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, case WASM_OP_REF_I31: { /* POP(i32) */ - if (!pop_const_expr_stack( - &const_expr_ctx, NULL, VALUE_TYPE_I32, NULL, - NULL, &cur_value, error_buf, error_buf_size)) { + if (!pop_const_expr_stack(&const_expr_ctx, NULL, + VALUE_TYPE_I32, NULL, NULL, + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) { goto fail; } @@ -1234,6 +1444,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack( &const_expr_ctx, flag, cur_ref_type.ref_type, &cur_ref_type, (uint8)opcode1, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { goto fail; } @@ -1268,7 +1481,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, #if WASM_ENABLE_GC != 0 ref_type, &opcode, #endif - &cur_value, error_buf, error_buf_size)) { + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + &cur_expr, +#endif + error_buf, error_buf_size)) { goto fail; } @@ -1278,8 +1495,21 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, goto fail; } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + if (cur_expr != NULL) { + bh_memcpy_s(init_expr, sizeof(InitializerExpression), cur_expr, + sizeof(InitializerExpression)); + wasm_runtime_free(cur_expr); + } + else { + init_expr->init_expr_type = flag; + init_expr->u.unary.v = cur_value; + } + +#else init_expr->init_expr_type = flag; - init_expr->u = cur_value; + init_expr->u.unary.v = cur_value; +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */ #if WASM_ENABLE_GC != 0 if (init_expr->init_expr_type == WASM_OP_GC_PREFIX) { @@ -1310,11 +1540,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, #endif /* end of WASM_ENABLE_GC != 0 */ *p_buf = p; - destroy_const_expr_stack(&const_expr_ctx); + destroy_const_expr_stack(&const_expr_ctx, false); return true; fail: - destroy_const_expr_stack(&const_expr_ctx); + destroy_const_expr_stack(&const_expr_ctx, true); return false; } @@ -4072,9 +4302,9 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, if (global->init_expr.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { uint8 global_type; WASMRefType *global_ref_type; - uint32 global_idx = global->init_expr.u.global_index; + uint32 global_idx = global->init_expr.u.unary.v.global_index; - if (global->init_expr.u.global_index + if (global->init_expr.u.unary.v.global_index >= module->import_global_count + i) { set_error_buf(error_buf, error_buf_size, "unknown global"); return false; @@ -4471,7 +4701,7 @@ load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end, } init_expr->init_expr_type = INIT_EXPR_TYPE_FUNCREF_CONST; - init_expr->u.ref_index = function_index; + init_expr->u.unary.v.ref_index = function_index; } *p_buf = p; @@ -4744,7 +4974,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, #if WASM_ENABLE_MEMORY64 != 0 if (table_elem_idx_type == VALUE_TYPE_I64 - && table_segment->base_offset.u.u64 > UINT32_MAX) { + && table_segment->base_offset.u.unary.v.u64 > UINT32_MAX) { set_error_buf(error_buf, error_buf_size, "In table64, table base offset can't be " "larger than UINT32_MAX"); @@ -4904,6 +5134,9 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, if (!(dataseg = module->data_segments[i] = loader_malloc( sizeof(WASMDataSeg), error_buf, error_buf_size))) { +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(module, &init_expr); +#endif return false; } @@ -6031,7 +6264,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { aux_heap_base_global = global; - aux_heap_base = (uint64)(uint32)global->init_expr.u.i32; + aux_heap_base = + (uint64)(uint32)global->init_expr.u.unary.v.i32; aux_heap_base_global_index = export->index; LOG_VERBOSE("Found aux __heap_base global, value: %" PRIu64, aux_heap_base); @@ -6052,7 +6286,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { aux_data_end_global = global; - aux_data_end = (uint64)(uint32)global->init_expr.u.i32; + aux_data_end = + (uint64)(uint32)global->init_expr.u.unary.v.i32; aux_data_end_global_index = export->index; LOG_VERBOSE("Found aux __data_end global, value: %" PRIu64, aux_data_end); @@ -6093,10 +6328,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->type.val_type == VALUE_TYPE_I32 && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST - && (uint64)(uint32)global->init_expr.u.i32 + && (uint64)(uint32)global->init_expr.u.unary.v.i32 <= aux_heap_base) { aux_stack_top_global = global; - aux_stack_top = (uint64)(uint32)global->init_expr.u.i32; + aux_stack_top = + (uint64)(uint32)global->init_expr.u.unary.v.i32; module->aux_stack_top_global_index = module->import_global_count + global_index; module->aux_stack_bottom = aux_stack_top; @@ -6947,7 +7183,7 @@ wasm_loader_unload(WASMModule *module) wasm_runtime_free(module->memories); if (module->globals) { -#if WASM_ENABLE_GC != 0 +#if WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0 for (i = 0; i < module->global_count; i++) { destroy_init_expr(module, &module->globals[i].init_expr); } @@ -6980,6 +7216,9 @@ wasm_loader_unload(WASMModule *module) #endif wasm_runtime_free(module->table_segments[i].init_values); } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(module, &module->table_segments[i].base_offset); +#endif } wasm_runtime_free(module->table_segments); } @@ -6989,6 +7228,10 @@ wasm_loader_unload(WASMModule *module) if (module->data_segments[i]) { if (module->data_segments[i]->is_data_cloned) wasm_runtime_free(module->data_segments[i]->data); +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(module, + &(module->data_segments[i]->base_offset)); +#endif wasm_runtime_free(module->data_segments[i]); } } @@ -13260,7 +13503,8 @@ re_scan: == VALUE_TYPE_FUNCREF && module->globals[i].init_expr.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST - && module->globals[i].init_expr.u.u32 == func_idx) { + && module->globals[i].init_expr.u.unary.v.u32 + == func_idx) { func_declared = true; break; } @@ -13289,7 +13533,8 @@ re_scan: #endif ) { for (j = 0; j < table_seg->value_count; j++) { - if (table_seg->init_values[j].u.ref_index + if (table_seg->init_values[j] + .u.unary.v.ref_index == func_idx) { func_declared = true; break; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 7ff1078c3..771538a14 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -261,6 +261,9 @@ typedef struct InitValue { uint8 type; uint8 flag; WASMValue value; +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression *expr; +#endif } InitValue; typedef struct ConstExprContext { @@ -282,7 +285,11 @@ init_const_expr_stack(ConstExprContext *ctx, WASMModule *module) static bool push_const_expr_stack(ConstExprContext *ctx, uint8 flag, uint8 type, - WASMValue *value, char *error_buf, uint32 error_buf_size) + WASMValue *value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression *expr, +#endif + char *error_buf, uint32 error_buf_size) { InitValue *cur_value; @@ -305,6 +312,9 @@ push_const_expr_stack(ConstExprContext *ctx, uint8 flag, uint8 type, cur_value->type = type; cur_value->flag = flag; cur_value->value = *value; +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + cur_value->expr = expr; +#endif return true; fail: @@ -313,7 +323,11 @@ fail: static bool pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, - WASMValue *p_value, char *error_buf, uint32 error_buf_size) + WASMValue *p_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression **p_expr, +#endif + char *error_buf, uint32 error_buf_size) { InitValue *cur_value; @@ -331,18 +345,50 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type, *p_flag = cur_value->flag; if (p_value) *p_value = cur_value->value; +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + if (p_expr) + *p_expr = cur_value->expr; +#endif return true; } static void -destroy_const_expr_stack(ConstExprContext *ctx) +destroy_const_expr_stack(ConstExprContext *ctx, bool free_exprs) { +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + if (free_exprs) { + for (uint32 j = 0; j < ctx->sp; j++) { + if (is_expr_binary_op(ctx->stack[j].expr->init_expr_type)) { + destroy_init_expr_recursive(ctx->stack[j].expr); + ctx->stack[j].expr = NULL; + } + } + } +#endif if (ctx->stack != ctx->data) { wasm_runtime_free(ctx->stack); } } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 +static void +destroy_init_expr(InitializerExpression *expr) +{ + // free left expr and right exprs for binary oprand + if (is_expr_binary_op(expr->init_expr_type)) { + return; + } + if (expr->u.binary.l_expr) { + destroy_init_expr_recursive(expr->u.binary.l_expr); + } + if (expr->u.binary.r_expr) { + destroy_init_expr_recursive(expr->u.binary.r_expr); + } + expr->u.binary.l_expr = expr->u.binary.r_expr = NULL; +} +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */ + static bool load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, InitializerExpression *init_expr, uint8 type, char *error_buf, @@ -353,6 +399,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, uint32 i; ConstExprContext const_expr_ctx = { 0 }; WASMValue cur_value = { 0 }; +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + InitializerExpression *cur_expr = NULL; +#endif init_const_expr_stack(&const_expr_ctx, module); @@ -367,8 +416,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack(&const_expr_ctx, flag, VALUE_TYPE_I32, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } break; /* i64.const */ @@ -377,8 +429,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack(&const_expr_ctx, flag, VALUE_TYPE_I64, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } break; /* f32.const */ @@ -390,8 +445,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack(&const_expr_ctx, flag, VALUE_TYPE_F32, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } break; /* f64.const */ @@ -403,8 +461,11 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, if (!push_const_expr_stack(&const_expr_ctx, flag, VALUE_TYPE_F64, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } break; @@ -417,13 +478,16 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, cur_value.ref_index = func_idx; if (!check_function_index(module, func_idx, error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } if (!push_const_expr_stack(&const_expr_ctx, flag, VALUE_TYPE_FUNCREF, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } break; } @@ -438,9 +502,12 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, cur_value.ref_index = UINT32_MAX; if (!push_const_expr_stack(&const_expr_ctx, flag, type1, - &cur_value, error_buf, - error_buf_size)) { - bh_assert(0); + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) { + goto fail; } break; } @@ -471,15 +538,93 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, } if (!push_const_expr_stack(&const_expr_ctx, flag, global_type, - &cur_value, error_buf, - error_buf_size)) - bh_assert(0); + &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + NULL, +#endif + error_buf, error_buf_size)) + goto fail; break; } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_MUL: + { + InitializerExpression *l_expr, *r_expr; + WASMValue l_value, r_value; + uint8 l_flag, r_flag; + uint8 value_type; + + if (flag == INIT_EXPR_TYPE_I32_ADD + || flag == INIT_EXPR_TYPE_I32_SUB + || flag == INIT_EXPR_TYPE_I32_MUL) { + value_type = VALUE_TYPE_I32; + } + else { + value_type = VALUE_TYPE_I64; + } + + /* If right flag indicates a binary operation, right expr will + * be popped from stack. Otherwise, allocate a new expr for + * right expr. Same for left expr. + */ + if (!(pop_const_expr_stack(&const_expr_ctx, &r_flag, value_type, + &r_value, &r_expr, error_buf, + error_buf_size))) { + goto fail; + } + if (!is_expr_binary_op(r_flag)) { + if (!(r_expr = loader_malloc(sizeof(InitializerExpression), + error_buf, error_buf_size))) { + goto fail; + } + r_expr->init_expr_type = r_flag; + r_expr->u.unary.v = r_value; + } + + if (!(pop_const_expr_stack(&const_expr_ctx, &l_flag, value_type, + &l_value, &l_expr, error_buf, + error_buf_size))) { + destroy_init_expr_recursive(r_expr); + goto fail; + } + if (!is_expr_binary_op(l_flag)) { + if (!(l_expr = loader_malloc(sizeof(InitializerExpression), + error_buf, error_buf_size))) { + destroy_init_expr_recursive(r_expr); + goto fail; + } + l_expr->init_expr_type = l_flag; + l_expr->u.unary.v = l_value; + } + + if (!(cur_expr = loader_malloc(sizeof(InitializerExpression), + error_buf, error_buf_size))) { + destroy_init_expr_recursive(l_expr); + destroy_init_expr_recursive(r_expr); + goto fail; + } + cur_expr->init_expr_type = flag; + cur_expr->u.binary.l_expr = l_expr; + cur_expr->u.binary.r_expr = r_expr; + + if (!push_const_expr_stack(&const_expr_ctx, flag, value_type, + &cur_value, cur_expr, error_buf, + error_buf_size)) { + destroy_init_expr_recursive(cur_expr); + goto fail; + } + break; + } +#endif default: { - bh_assert(0); + goto fail; } } @@ -489,18 +634,42 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end, /* There should be only one value left on the init value stack */ if (!pop_const_expr_stack(&const_expr_ctx, &flag, type, &cur_value, +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + &cur_expr, +#endif error_buf, error_buf_size)) { - bh_assert(0); + goto fail; } - bh_assert(const_expr_ctx.sp == 0); + if (const_expr_ctx.sp != 0) { + set_error_buf(error_buf, error_buf_size, + "type mismatch: illegal constant opcode sequence"); + goto fail; + } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + if (cur_expr != NULL) { + bh_memcpy_s(init_expr, sizeof(InitializerExpression), cur_expr, + sizeof(InitializerExpression)); + wasm_runtime_free(cur_expr); + } + else { + init_expr->init_expr_type = flag; + init_expr->u.unary.v = cur_value; + } + +#else init_expr->init_expr_type = flag; - init_expr->u = cur_value; + init_expr->u.unary.v = cur_value; +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */ *p_buf = p; - destroy_const_expr_stack(&const_expr_ctx); + destroy_const_expr_stack(&const_expr_ctx, false); return true; + +fail: + destroy_const_expr_stack(&const_expr_ctx, true); + return false; } static bool @@ -1385,13 +1554,14 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, * global.get instructions are * only allowed to refer to imported globals. */ - uint32 target_global_index = global->init_expr.u.global_index; + uint32 target_global_index = + global->init_expr.u.unary.v.global_index; bh_assert(target_global_index < module->import_global_count); (void)target_global_index; } else if (INIT_EXPR_TYPE_FUNCREF_CONST == global->init_expr.init_expr_type) { - bh_assert(global->init_expr.u.ref_index + bh_assert(global->init_expr.u.unary.v.ref_index < module->import_function_count + module->function_count); } @@ -1575,7 +1745,7 @@ load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end, } init_expr->init_expr_type = INIT_EXPR_TYPE_FUNCREF_CONST; - init_expr->u.ref_index = function_index; + init_expr->u.unary.v.ref_index = function_index; } *p_buf = p; @@ -1890,6 +2060,9 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, if (!(dataseg = module->data_segments[i] = loader_malloc( sizeof(WASMDataSeg), error_buf, error_buf_size))) { +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(&init_expr); +#endif return false; } @@ -2778,7 +2951,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { aux_heap_base_global = global; - aux_heap_base = (uint64)(uint32)global->init_expr.u.i32; + aux_heap_base = + (uint64)(uint32)global->init_expr.u.unary.v.i32; aux_heap_base_global_index = export->index; LOG_VERBOSE("Found aux __heap_base global, value: %" PRIu64, aux_heap_base); @@ -2798,7 +2972,8 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST) { aux_data_end_global = global; - aux_data_end = (uint64)(uint32)global->init_expr.u.i32; + aux_data_end = + (uint64)(uint32)global->init_expr.u.unary.v.i32; aux_data_end_global_index = export->index; LOG_VERBOSE("Found aux __data_end global, value: %" PRIu64, aux_data_end); @@ -2838,10 +3013,11 @@ load_from_sections(WASMModule *module, WASMSection *sections, && global->type.val_type == VALUE_TYPE_I32 && global->init_expr.init_expr_type == INIT_EXPR_TYPE_I32_CONST - && (uint64)(uint32)global->init_expr.u.i32 + && (uint64)(uint32)global->init_expr.u.unary.v.i32 <= aux_heap_base) { aux_stack_top_global = global; - aux_stack_top = (uint64)(uint32)global->init_expr.u.i32; + aux_stack_top = + (uint64)(uint32)global->init_expr.u.unary.v.i32; module->aux_stack_top_global_index = module->import_global_count + global_index; module->aux_stack_bottom = aux_stack_top; @@ -3448,8 +3624,14 @@ wasm_loader_unload(WASMModule *module) if (module->memories) wasm_runtime_free(module->memories); - if (module->globals) + if (module->globals) { +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + for (i = 0; i < module->global_count; i++) { + destroy_init_expr(&module->globals[i].init_expr); + } +#endif wasm_runtime_free(module->globals); + } if (module->exports) wasm_runtime_free(module->exports); @@ -3458,6 +3640,9 @@ wasm_loader_unload(WASMModule *module) for (i = 0; i < module->table_seg_count; i++) { if (module->table_segments[i].init_values) wasm_runtime_free(module->table_segments[i].init_values); +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(&module->table_segments[i].base_offset); +#endif } wasm_runtime_free(module->table_segments); } @@ -3467,6 +3652,9 @@ wasm_loader_unload(WASMModule *module) if (module->data_segments[i]) { if (module->data_segments[i]->is_data_cloned) wasm_runtime_free(module->data_segments[i]->data); +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + destroy_init_expr(&module->data_segments[i]->base_offset); +#endif wasm_runtime_free(module->data_segments[i]); } } @@ -7320,7 +7508,8 @@ re_scan: == VALUE_TYPE_FUNCREF && module->globals[i].init_expr.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST - && module->globals[i].init_expr.u.u32 == func_idx) { + && module->globals[i].init_expr.u.unary.v.ref_index + == func_idx) { func_declared = true; break; } @@ -7334,7 +7523,8 @@ re_scan: i++, table_seg++) { if (table_seg->elem_type == VALUE_TYPE_FUNCREF) { for (j = 0; j < table_seg->value_count; j++) { - if (table_seg->init_values[j].u.ref_index + if (table_seg->init_values[j] + .u.unary.v.ref_index == func_idx) { func_declared = true; break; diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 8e38a0778..b4aa483d7 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1165,6 +1165,81 @@ instantiate_array_global_recursive(WASMModule *module, } #endif +static bool +get_init_value_recursive(WASMModule *module, InitializerExpression *expr, + WASMGlobalInstance *globals, WASMValue *value, + char *error_buf, uint32 error_buf_size) +{ + uint8 flag = expr->init_expr_type; + switch (flag) { + case INIT_EXPR_TYPE_GET_GLOBAL: + { + if (!check_global_init_expr(module, expr->u.unary.v.global_index, + error_buf, error_buf_size)) { + goto fail; + } + + *value = globals[expr->u.unary.v.global_index].initial_value; + break; + } + case INIT_EXPR_TYPE_I32_CONST: + case INIT_EXPR_TYPE_I64_CONST: + { + *value = expr->u.unary.v; + break; + } +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: + { + WASMValue l_value, r_value; + if (!expr->u.binary.l_expr || !expr->u.binary.r_expr) { + goto fail; + } + if (!get_init_value_recursive(module, expr->u.binary.l_expr, + globals, &l_value, error_buf, + error_buf_size)) { + goto fail; + } + if (!get_init_value_recursive(module, expr->u.binary.r_expr, + globals, &r_value, error_buf, + error_buf_size)) { + goto fail; + } + + if (flag == INIT_EXPR_TYPE_I32_ADD) { + value->i32 = l_value.i32 + r_value.i32; + } + else if (flag == INIT_EXPR_TYPE_I32_SUB) { + value->i32 = l_value.i32 - r_value.i32; + } + else if (flag == INIT_EXPR_TYPE_I32_MUL) { + value->i32 = l_value.i32 * r_value.i32; + } + else if (flag == INIT_EXPR_TYPE_I64_ADD) { + value->i64 = l_value.i64 + r_value.i64; + } + else if (flag == INIT_EXPR_TYPE_I64_SUB) { + value->i64 = l_value.i64 - r_value.i64; + } + else if (flag == INIT_EXPR_TYPE_I64_MUL) { + value->i64 = l_value.i64 * r_value.i64; + } + break; + } +#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */ + default: + goto fail; + } + return true; +fail: + return false; +} + /** * Instantiate globals in a module. */ @@ -1209,7 +1284,7 @@ globals_instantiate(WASMModule *module, WASMModuleInstance *module_inst, /* The linked global instance has been initialized, we just need to copy the value. */ global->initial_value = - global_import->import_global_linked->init_expr.u; + global_import->import_global_linked->init_expr.u.unary.v; } else #endif @@ -1245,17 +1320,23 @@ globals_instantiate(WASMModule *module, WASMModuleInstance *module_inst, #endif switch (flag) { + case INIT_EXPR_TYPE_I32_CONST: + case INIT_EXPR_TYPE_I64_CONST: case INIT_EXPR_TYPE_GET_GLOBAL: +#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0 + case INIT_EXPR_TYPE_I32_ADD: + case INIT_EXPR_TYPE_I32_SUB: + case INIT_EXPR_TYPE_I32_MUL: + case INIT_EXPR_TYPE_I64_ADD: + case INIT_EXPR_TYPE_I64_SUB: + case INIT_EXPR_TYPE_I64_MUL: +#endif { - if (!check_global_init_expr(module, init_expr->u.global_index, - error_buf, error_buf_size)) { + if (!get_init_value_recursive(module, init_expr, globals, + &global->initial_value, error_buf, + error_buf_size)) { goto fail; } - - bh_memcpy_s( - &(global->initial_value), sizeof(WASMValue), - &(globals[init_expr->u.global_index].initial_value), - sizeof(globals[init_expr->u.global_index].initial_value)); break; } #if WASM_ENABLE_GC != 0 @@ -1267,11 +1348,12 @@ globals_instantiate(WASMModule *module, WASMModuleInstance *module_inst, uint32 type_idx; if (flag == INIT_EXPR_TYPE_STRUCT_NEW) { - init_values = (WASMStructNewInitValues *)init_expr->u.data; + init_values = + (WASMStructNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; } else { - type_idx = init_expr->u.type_index; + type_idx = init_expr->u.unary.v.type_index; } struct_obj = instantiate_struct_global_recursive( @@ -1294,12 +1376,14 @@ globals_instantiate(WASMModule *module, WASMModuleInstance *module_inst, uint32 type_idx, len; if (flag == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) { - type_idx = init_expr->u.array_new_default.type_index; - len = init_expr->u.array_new_default.length; + type_idx = + init_expr->u.unary.v.array_new_default.type_index; + len = init_expr->u.unary.v.array_new_default.length; array_init_value = &empty_value; } else { - init_values = (WASMArrayNewInitValues *)init_expr->u.data; + init_values = + (WASMArrayNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; len = init_values->length; @@ -1318,13 +1402,12 @@ globals_instantiate(WASMModule *module, WASMModuleInstance *module_inst, case INIT_EXPR_TYPE_I31_NEW: { global->initial_value.gc_obj = - (wasm_obj_t)wasm_i31_obj_new(init_expr->u.i32); + (wasm_obj_t)wasm_i31_obj_new(init_expr->u.unary.v.i32); break; } #endif /* end of WASM_ENABLE_GC != 0 */ default: - bh_memcpy_s(&(global->initial_value), sizeof(WASMValue), - &(init_expr->u), sizeof(init_expr->u)); + global->initial_value = init_expr->u.unary.v; break; } @@ -2698,6 +2781,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, uint8 *memory_data = NULL; uint64 memory_size = 0; WASMDataSeg *data_seg = module->data_segments[i]; + WASMValue offset_value; #if WASM_ENABLE_BULK_MEMORY != 0 if (data_seg->is_passive) @@ -2717,54 +2801,37 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, (uint64)memory->num_bytes_per_page * memory->cur_page_count; bh_assert(memory_data || memory_size == 0); - bh_assert(data_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL - || data_seg->base_offset.init_expr_type - == (memory->is_memory64 ? INIT_EXPR_TYPE_I64_CONST - : INIT_EXPR_TYPE_I32_CONST)); + uint8 offset_flag = data_seg->base_offset.init_expr_type; + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || (memory->is_memory64 ? is_valid_i64_offset(offset_flag) + : is_valid_i32_offset(offset_flag))); - if (data_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - if (!check_global_init_expr(module, - data_seg->base_offset.u.global_index, - error_buf, error_buf_size)) { - goto fail; - } + if (!get_init_value_recursive(module, &data_seg->base_offset, globals, + &offset_value, error_buf, + error_buf_size)) { + goto fail; + } + if (offset_flag == INIT_EXPR_TYPE_GET_GLOBAL) { if (!globals - || globals[data_seg->base_offset.u.global_index].type + || globals[data_seg->base_offset.u.unary.v.global_index].type != (memory->is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32)) { set_error_buf(error_buf, error_buf_size, "data segment does not fit"); goto fail; } - -#if WASM_ENABLE_MEMORY64 != 0 - if (memory->is_memory64) { - base_offset = - (uint64)globals[data_seg->base_offset.u.global_index] - .initial_value.i64; - } - else -#endif - { - base_offset = - (uint32)globals[data_seg->base_offset.u.global_index] - .initial_value.i32; - } - } - else { -#if WASM_ENABLE_MEMORY64 != 0 - if (memory->is_memory64) { - base_offset = (uint64)data_seg->base_offset.u.i64; - } - else -#endif - { - base_offset = (uint32)data_seg->base_offset.u.i32; - } } +#if WASM_ENABLE_MEMORY64 != 0 + if (memory->is_memory64) { + base_offset = (uint64)offset_value.i64; + } + else +#endif + { + base_offset = (uint32)offset_value.i32; + } /* check offset */ if (base_offset > memory_size) { #if WASM_ENABLE_MEMORY64 != 0 @@ -2842,36 +2909,39 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, || table->init_expr.init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST); if (table->init_expr.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { - if (!check_global_init_expr(module, table->init_expr.u.global_index, + if (!check_global_init_expr(module, + table->init_expr.u.unary.v.global_index, error_buf, error_buf_size)) { goto fail; } - table->init_expr.u.gc_obj = - globals[table->init_expr.u.global_index].initial_value.gc_obj; + table->init_expr.u.unary.v.gc_obj = + globals[table->init_expr.u.unary.v.global_index] + .initial_value.gc_obj; } else if (table->init_expr.init_expr_type == INIT_EXPR_TYPE_FUNCREF_CONST) { - uint32 func_idx = table->init_expr.u.ref_index; + uint32 func_idx = table->init_expr.u.unary.v.ref_index; if (func_idx != UINT32_MAX) { - if (!(table->init_expr.u.gc_obj = + if (!(table->init_expr.u.unary.v.gc_obj = wasm_create_func_obj(module_inst, func_idx, false, error_buf, error_buf_size))) goto fail; } else { - table->init_expr.u.gc_obj = NULL_REF; + table->init_expr.u.unary.v.gc_obj = NULL_REF; } } else if (table->init_expr.init_expr_type == INIT_EXPR_TYPE_REFNULL_CONST) { - table->init_expr.u.gc_obj = NULL_REF; + table->init_expr.u.unary.v.gc_obj = NULL_REF; } LOG_DEBUG("Init table [%d] elements from [%d] to [%d] as: %p", i, 0, - table_inst->cur_size, (void *)table->init_expr.u.gc_obj); + table_inst->cur_size, + (void *)table->init_expr.u.unary.v.gc_obj); for (j = 0; j < table_inst->cur_size; j++) { - *(table_data + j) = table->init_expr.u.gc_obj; + *(table_data + j) = table->init_expr.u.unary.v.gc_obj; } } #endif /* end of WASM_ENABLE_GC != 0 */ @@ -2883,6 +2953,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, /* has check it in loader */ WASMTableInstance *table = module_inst->tables[table_seg->table_index]; table_elem_type_t *table_data; + WASMValue offset_value; uint32 j; #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 uint8 tbl_elem_type; @@ -2941,48 +3012,37 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, continue; #endif + uint8 offset_flag = table_seg->base_offset.init_expr_type; #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 - bh_assert(table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_I32_CONST - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_FUNCREF_CONST - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_REFNULL_CONST); + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || offset_flag == INIT_EXPR_TYPE_FUNCREF_CONST + || offset_flag == INIT_EXPR_TYPE_REFNULL_CONST + || is_valid_i32_offset(offset_flag)); #else - bh_assert(table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_I32_CONST - || table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL); + bh_assert(offset_flag == INIT_EXPR_TYPE_GET_GLOBAL + || is_valid_i32_offset(offset_flag)); #endif - /* init vec(funcidx) or vec(expr) */ - if (table_seg->base_offset.init_expr_type - == INIT_EXPR_TYPE_GET_GLOBAL) { - if (!check_global_init_expr(module, - table_seg->base_offset.u.global_index, - error_buf, error_buf_size)) { - goto fail; - } + if (!get_init_value_recursive(module, &table_seg->base_offset, globals, + &offset_value, error_buf, + error_buf_size)) { + goto fail; + } + if (offset_flag == INIT_EXPR_TYPE_GET_GLOBAL) { if (!globals - || globals[table_seg->base_offset.u.global_index].type + || globals[table_seg->base_offset.u.unary.v.global_index].type != VALUE_TYPE_I32) { set_error_buf(error_buf, error_buf_size, "type mismatch: elements segment does not fit"); goto fail; } - - table_seg->base_offset.u.i32 = - globals[table_seg->base_offset.u.global_index] - .initial_value.i32; } /* check offset since length might negative */ - if ((uint32)table_seg->base_offset.u.i32 > table->cur_size) { - LOG_DEBUG("base_offset(%d) > table->cur_size(%d)", - table_seg->base_offset.u.i32, table->cur_size); + if ((uint32)offset_value.i32 > table->cur_size) { + LOG_DEBUG("base_offset(%d) > table->cur_size(%d)", offset_value.i32, + table->cur_size); #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 set_error_buf(error_buf, error_buf_size, "out of bounds table access"); @@ -2995,9 +3055,9 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, /* check offset + length(could be zero) */ length = table_seg->value_count; - if ((uint32)table_seg->base_offset.u.i32 + length > table->cur_size) { + if ((uint32)offset_value.i32 + length > table->cur_size) { LOG_DEBUG("base_offset(%d) + length(%d)> table->cur_size(%d)", - table_seg->base_offset.u.i32, length, table->cur_size); + offset_value.i32, length, table->cur_size); #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 set_error_buf(error_buf, error_buf_size, "out of bounds table access"); @@ -3027,10 +3087,10 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, case INIT_EXPR_TYPE_FUNCREF_CONST: { #if WASM_ENABLE_GC == 0 - ref = (void *)(uintptr_t)init_expr->u.ref_index; + ref = (void *)(uintptr_t)init_expr->u.unary.v.ref_index; #else WASMFuncObjectRef func_obj; - uint32 func_idx = init_expr->u.ref_index; + uint32 func_idx = init_expr->u.unary.v.ref_index; /* UINT32_MAX indicates that it is a null reference */ if (func_idx != UINT32_MAX) { if (!(func_obj = wasm_create_func_obj( @@ -3049,14 +3109,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, #if WASM_ENABLE_GC != 0 case INIT_EXPR_TYPE_GET_GLOBAL: { - if (!check_global_init_expr(module, - init_expr->u.global_index, - error_buf, error_buf_size)) { + if (!check_global_init_expr( + module, init_expr->u.unary.v.global_index, + error_buf, error_buf_size)) { goto fail; } - ref = - globals[init_expr->u.global_index].initial_value.gc_obj; + ref = globals[init_expr->u.unary.v.global_index] + .initial_value.gc_obj; break; } case INIT_EXPR_TYPE_STRUCT_NEW: @@ -3069,12 +3129,12 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, uint32 type_idx; if (flag == INIT_EXPR_TYPE_STRUCT_NEW) { - init_values = - (WASMStructNewInitValues *)init_expr->u.data; + init_values = (WASMStructNewInitValues *) + init_expr->u.unary.v.data; type_idx = init_values->type_idx; } else { - type_idx = init_expr->u.type_index; + type_idx = init_expr->u.unary.v.type_index; } struct_type = (WASMStructType *)module->types[type_idx]; @@ -3125,13 +3185,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, uint32 type_idx, len; if (flag == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) { - type_idx = init_expr->u.array_new_default.type_index; - len = init_expr->u.array_new_default.length; + type_idx = + init_expr->u.unary.v.array_new_default.type_index; + len = init_expr->u.unary.v.array_new_default.length; arr_init_val = &empty_val; } else { init_values = - (WASMArrayNewInitValues *)init_expr->u.data; + (WASMArrayNewInitValues *)init_expr->u.unary.v.data; type_idx = init_values->type_idx; len = init_values->length; @@ -3177,14 +3238,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, } case INIT_EXPR_TYPE_I31_NEW: { - ref = (wasm_obj_t)wasm_i31_obj_new(init_expr->u.i32); + ref = + (wasm_obj_t)wasm_i31_obj_new(init_expr->u.unary.v.i32); break; } #endif /* end of WASM_ENABLE_GC != 0 */ } - *(table_data + table_seg->base_offset.u.i32 + j) = - (table_elem_type_t)ref; + *(table_data + offset_value.i32 + j) = (table_elem_type_t)ref; } } @@ -4706,10 +4767,10 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx, for (i = 0; i < length; i++) { #if WASM_ENABLE_GC != 0 /* UINT32_MAX indicates that it is a null ref */ - if (init_values[i].u.ref_index != UINT32_MAX) { - if (!(func_obj = wasm_create_func_obj(module_inst, - init_values[i].u.ref_index, - true, NULL, 0))) { + if (init_values[i].u.unary.v.ref_index != UINT32_MAX) { + if (!(func_obj = wasm_create_func_obj( + module_inst, init_values[i].u.unary.v.ref_index, true, + NULL, 0))) { wasm_set_exception(module_inst, "null function reference"); return; } @@ -4719,7 +4780,7 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx, table_elems[i] = NULL_REF; } #else - table_elems[i] = init_values[i].u.ref_index; + table_elems[i] = init_values[i].u.unary.v.ref_index; #endif } } diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 12d901679..78e0711ec 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -293,6 +293,10 @@ Currently we only profile the memory consumption of module, module_instance and - **WAMR_BUILD_AOT_INTRINSICS**=1/0, enable the AOT intrinsic functions, default to enable if not set. These functions can be called from the AOT code when `--disable-llvm-intrinsics` flag or `--enable-builtin-intrinsics=` flag is used by wamrc to generate the AOT file. > Note: See [Tuning the XIP intrinsic functions](./xip.md#tuning-the-xip-intrinsic-functions) for more details. +### **Enable extended constant expression** +- **WAMR_BUILD_EXTENDED_CONST_EXPR**=1/0, default to disable if not set. +> Note: See [Extended Constant Expressions](https://github.com/WebAssembly/extended-const/blob/main/proposals/extended-const/Overview.md) for more details. + ### **Configurable memory access boundary check** - **WAMR_CONFIGURABLE_BOUNDS_CHECKS**=1/0, default to disable if not set > Note: If it is enabled, allow to run `iwasm --disable-bounds-checks` to disable the memory access boundary checks for interpreter mode. diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 2c4725e89..970127d0b 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -172,6 +172,7 @@ def test_case( clean_up_flag=True, verbose_flag=True, gc_flag=False, + extended_const_flag=False, memory64_flag=False, multi_memory_flag=False, qemu_flag=False, @@ -229,6 +230,9 @@ def test_case( if gc_flag: CMD.append("--gc") + if extended_const_flag: + CMD.append("--extended-const") + if memory64_flag: CMD.append("--memory64") @@ -304,6 +308,7 @@ def test_suite( clean_up_flag=True, verbose_flag=True, gc_flag=False, + extended_const_flag=False, memory64_flag=False, multi_memory_flag=False, parl_flag=False, @@ -385,6 +390,7 @@ def test_suite( clean_up_flag, verbose_flag, gc_flag, + extended_const_flag, memory64_flag, multi_memory_flag, qemu_flag, @@ -428,6 +434,7 @@ def test_suite( clean_up_flag, verbose_flag, gc_flag, + extended_const_flag, memory64_flag, multi_memory_flag, qemu_flag, @@ -561,6 +568,13 @@ def main(): dest="gc_flag", help="Running with GC feature", ) + parser.add_argument( + "--enable-extended-const", + action="store_true", + default=False, + dest="extended_const_flag", + help="Running with extended const expression feature", + ) parser.add_argument( "--memory64", action="store_true", @@ -619,6 +633,7 @@ def main(): options.clean_up_flag, options.verbose_flag, options.gc_flag, + options.extended_const_flag, options.memory64_flag, options.multi_memory_flag, options.parl_flag, @@ -648,6 +663,7 @@ def main(): options.clean_up_flag, options.verbose_flag, options.gc_flag, + options.extended_const_flag, options.memory64_flag, options.multi_memory_flag, options.qemu_flag, diff --git a/tests/wamr-test-suites/spec-test-script/extended_const.patch b/tests/wamr-test-suites/spec-test-script/extended_const.patch new file mode 100644 index 000000000..f09427c29 --- /dev/null +++ b/tests/wamr-test-suites/spec-test-script/extended_const.patch @@ -0,0 +1,506 @@ +diff --git a/test/core/elem.wast b/test/core/elem.wast +index 92dab52..3954bca 100644 +--- a/test/core/elem.wast ++++ b/test/core/elem.wast +@@ -571,6 +571,7 @@ + + ;; Element sections across multiple modules change the same table + ++(; + (module $module1 + (type $out-i32 (func (result i32))) + (table (export "shared-table") 10 funcref) +@@ -620,7 +621,7 @@ + (assert_return (invoke $module1 "call-7") (i32.const 67)) + (assert_return (invoke $module1 "call-8") (i32.const 69)) + (assert_return (invoke $module1 "call-9") (i32.const 70)) +- ++;) + ;; Element segments must match element type of table + + (assert_invalid +@@ -659,24 +660,30 @@ + (func (export "set") (param $i i32) (param $x externref) + (table.set $t (local.get $i) (local.get $x)))) + +-(register "exporter" $m) ++;; (register "exporter" $m) + +-(assert_return (invoke $m "get" (i32.const 0)) (ref.null extern)) +-(assert_return (invoke $m "get" (i32.const 1)) (ref.null extern)) ++;; (assert_return (invoke $m "get" (i32.const 0)) (ref.null extern)) ++;; (assert_return (invoke $m "get" (i32.const 1)) (ref.null extern)) ++(assert_return (invoke "get" (i32.const 0)) (ref.null extern)) ++(assert_return (invoke "get" (i32.const 1)) (ref.null extern)) + +-(assert_return (invoke $m "set" (i32.const 0) (ref.extern 42))) +-(assert_return (invoke $m "set" (i32.const 1) (ref.extern 137))) +- +-(assert_return (invoke $m "get" (i32.const 0)) (ref.extern 42)) +-(assert_return (invoke $m "get" (i32.const 1)) (ref.extern 137)) ++;; (assert_return (invoke $m "set" (i32.const 0) (ref.extern 42))) ++;; (assert_return (invoke $m "set" (i32.const 1) (ref.extern 137))) ++(assert_return (invoke "set" (i32.const 0) (ref.extern 42))) ++(assert_return (invoke "set" (i32.const 1) (ref.extern 137))) + ++;; (assert_return (invoke $m "get" (i32.const 0)) (ref.extern 42)) ++;; (assert_return (invoke $m "get" (i32.const 1)) (ref.extern 137)) ++(assert_return (invoke "get" (i32.const 0)) (ref.extern 42)) ++(assert_return (invoke "get" (i32.const 1)) (ref.extern 137)) ++(; + (module + (import "exporter" "table" (table $t 2 externref)) + (elem (i32.const 0) externref (ref.null extern))) + + (assert_return (invoke $m "get" (i32.const 0)) (ref.null extern)) + (assert_return (invoke $m "get" (i32.const 1)) (ref.extern 137)) +- ++;) + ;; Initializing a table with imported funcref global + + (module $module4 +@@ -686,6 +693,7 @@ + (global (export "f") funcref (ref.func 0)) + ) + ++(; + (register "module4" $module4) + + (module +@@ -699,6 +707,7 @@ + ) + + (assert_return (invoke "call_imported_elem") (i32.const 42)) ++;) + + ;; Extended contant expressions + +diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast +index adb5cb7..6396013 100644 +--- a/test/core/ref_func.wast ++++ b/test/core/ref_func.wast +@@ -4,7 +4,7 @@ + (register "M") + + (module +- (func $f (import "M" "f") (param i32) (result i32)) ++ (func $f (param $x i32) (result i32) (local.get $x)) + (func $g (param $x i32) (result i32) + (i32.add (local.get $x) (i32.const 1)) + ) +diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast +index 380e84e..59230cf 100644 +--- a/test/core/table_copy.wast ++++ b/test/core/table_copy.wast +@@ -14,11 +14,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -106,11 +106,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -198,11 +198,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -290,11 +290,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -382,11 +382,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -474,11 +474,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -566,11 +566,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -658,11 +658,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -750,11 +750,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -842,11 +842,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -934,11 +934,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1026,11 +1026,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1118,11 +1118,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1210,11 +1210,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1302,11 +1302,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1394,11 +1394,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1486,11 +1486,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -1578,11 +1578,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +diff --git a/test/core/table_init.wast b/test/core/table_init.wast +index 0b2d26f..3c595e5 100644 +--- a/test/core/table_init.wast ++++ b/test/core/table_init.wast +@@ -14,11 +14,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -72,11 +72,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -130,11 +130,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) +@@ -196,11 +196,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -254,11 +254,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) +@@ -312,11 +312,11 @@ + + (module + (type (func (result i32))) ;; type #0 +- (import "a" "ef0" (func (result i32))) ;; index 0 +- (import "a" "ef1" (func (result i32))) +- (import "a" "ef2" (func (result i32))) +- (import "a" "ef3" (func (result i32))) +- (import "a" "ef4" (func (result i32))) ;; index 4 ++ (func (result i32) (i32.const 0)) ;; index 0 ++ (func (result i32) (i32.const 1)) ++ (func (result i32) (i32.const 2)) ++ (func (result i32) (i32.const 3)) ++ (func (result i32) (i32.const 4)) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index 158d759ed..fa9f5eb7d 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -336,6 +336,9 @@ parser.add_argument('--multi-thread', default=False, action='store_true', parser.add_argument('--gc', default=False, action='store_true', help='Test with GC') +parser.add_argument('--extended-const', action='store_true', + help='Enable extended const expression feature') + parser.add_argument('--memory64', default=False, action='store_true', help='Test with Memory64') @@ -1112,6 +1115,8 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): cmd = [opts.wast2wasm, "--enable-memory64", "--no-check", wast_tempfile, "-o", wasm_tempfile ] elif opts.multi_memory: cmd = [opts.wast2wasm, "--enable-multi-memory", "--no-check", wast_tempfile, "-o", wasm_tempfile ] + elif opts.extended_const: + cmd = [opts.wast2wasm, "--enable-extended-const", "--no-check", wast_tempfile, "-o", wasm_tempfile ] else: # `--enable-multi-memory` for a case in memory.wast but doesn't require runtime support cmd = [opts.wast2wasm, "--enable-multi-memory", "--enable-threads", "--no-check", @@ -1155,6 +1160,9 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = ' cmd.append("--enable-gc") cmd.append("--enable-tail-call") + if opts.extended_const: + cmd.append("--enable-extended-const") + if output == 'object': cmd.append("--format=object") elif output == 'ir': diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index f248c7cbb..6f498653f 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -41,6 +41,7 @@ function help() echo "-j set the platform to test" echo "-T set sanitizer to use in tests(ubsan|tsan|asan|posan)" echo "-A use the specified wamrc command instead of building it" + echo "-N enable extended const expression feature" echo "-r [requirement name] [N [N ...]] specify a requirement name followed by one or more" echo " subrequirement IDs, if no subrequirement is specificed," echo " it will run all subrequirements. When this optin is used," @@ -59,6 +60,7 @@ ENABLE_MULTI_THREAD=0 COLLECT_CODE_COVERAGE=0 ENABLE_SIMD=0 ENABLE_GC=0 +ENABLE_EXTENDED_CONST_EXPR=0 ENABLE_MEMORY64=0 ENABLE_MULTI_MEMORY=0 ENABLE_XIP=0 @@ -87,7 +89,7 @@ REQUIREMENT_NAME="" # Initialize an empty array for subrequirement IDs SUBREQUIREMENT_IDS=() -while getopts ":s:cabgvt:m:MCpSXexwWEPGQF:j:T:r:A:" opt +while getopts ":s:cabgvt:m:MCpSXexwWEPGQF:j:T:r:A:N" opt do OPT_PARSED="TRUE" case $opt in @@ -191,6 +193,10 @@ do echo "enable GC feature" ENABLE_GC=1 ;; + N) + echo "enable extended const expression feature" + ENABLE_EXTENDED_CONST_EXPR=1 + ;; P) PARALLELISM=1 ;; @@ -485,6 +491,17 @@ function spec_test() # (func $f (param (ref null $t)) (result funcref) (local.get 0)) # compile_reference_interpreter + elif [[ ${ENABLE_EXTENDED_CONST_EXPR} == 1 ]]; then + echo "checkout spec for extended const expression proposal" + + git clone -b main --single-branch https://github.com/WebAssembly/extended-const.git spec + pushd spec + + # Jan 14, 2025. README.md: Add note that this proposal is done (#20) + git reset --hard 8d4f6aa2b00a8e7c0174410028625c6a176db8a1 + # ignore import table cases + git apply --ignore-whitespace ../../spec-test-script/extended_const.patch || exit 1 + elif [[ ${ENABLE_MEMORY64} == 1 ]]; then echo "checkout spec for memory64 proposal" @@ -587,6 +604,10 @@ function spec_test() ARGS_FOR_SPEC_TEST+="--gc " fi + if [[ ${ENABLE_EXTENDED_CONST_EXPR} == 1 ]]; then + ARGS_FOR_SPEC_TEST+="--enable-extended-const " + fi + if [[ 1 == ${ENABLE_MEMORY64} ]]; then ARGS_FOR_SPEC_TEST+="--memory64 " fi @@ -832,6 +853,7 @@ function build_wamrc() && cmake .. \ -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE} \ -DWAMR_BUILD_SHRUNK_MEMORY=0 \ + -DWAMR_BUILD_EXTENDED_CONST_EXPR=${ENABLE_EXTENDED_CONST_EXPR} \ && make -j 4 } @@ -1023,6 +1045,10 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_TAIL_CALL=1" fi + if [[ ${ENABLE_EXTENDED_CONST_EXPR} == 1 ]]; then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_EXTENDED_CONST_EXPR=1" + fi + if [[ ${ENABLE_DEBUG_VERSION} == 1 ]]; then EXTRA_COMPILE_FLAGS+=" -DCMAKE_BUILD_TYPE=Debug" fi diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index 68648b84b..8ee61cab4 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -53,6 +53,7 @@ add_definitions(-DWASM_ENABLE_PERF_PROFILING=1) add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1) add_definitions(-DWASM_ENABLE_MODULE_INST_CONTEXT=1) add_definitions(-DWASM_ENABLE_MEMORY64=1) +add_definitions(-DWASM_ENABLE_EXTENDED_CONST_EXPR=1) add_definitions(-DWASM_ENABLE_GC=1) diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 8f029f79b..62b0dfb90 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -423,6 +423,7 @@ main(int argc, char *argv[]) option.enable_bulk_memory = true; option.enable_ref_types = true; option.enable_gc = false; + option.enable_extended_const = false; aot_call_stack_features_init_default(&option.call_stack_features); /* Process options */ @@ -536,6 +537,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--disable-aux-stack-check")) { option.enable_aux_stack_check = false; } + else if (!strcmp(argv[0], "--enable-extended-const")) { + option.enable_extended_const = true; + } else if (!strcmp(argv[0], "--enable-dump-call-stack")) { option.aux_stack_frame_type = AOT_STACK_FRAME_TYPE_STANDARD; }