diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 0304bd09..3efb190e 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1382,6 +1382,12 @@ load_table_list(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, for (i = 0; i < module->table_count; i++, table++) { read_uint8(buf, buf_end, table->table_type.elem_type); read_uint8(buf, buf_end, table->table_type.flags); + + if (!wasm_table_check_flags(table->table_type.flags, error_buf, + error_buf_size, true)) { + return false; + } + read_uint8(buf, buf_end, table->table_type.possible_grow); #if WASM_ENABLE_GC != 0 if (wasm_is_type_multi_byte_type(table->table_type.elem_type)) { diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index eb88fa6c..ebef5441 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -737,18 +737,24 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #if WASM_ENABLE_REF_TYPES != 0 bh_assert( - table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + 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); #else - bh_assert(table_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST + 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); #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; diff --git a/core/iwasm/common/wasm_loader_common.c b/core/iwasm/common/wasm_loader_common.c index 6dd31be2..97ea5efd 100644 --- a/core/iwasm/common/wasm_loader_common.c +++ b/core/iwasm/common/wasm_loader_common.c @@ -19,6 +19,37 @@ wasm_loader_set_error_buf(char *error_buf, uint32 error_buf_size, } } +#if WASM_ENABLE_MEMORY64 != 0 +bool +check_memory64_flags_consistency(WASMModule *module, char *error_buf, + uint32 error_buf_size, bool is_aot) +{ + uint32 i; + bool wasm64_flag, all_wasm64 = true, none_wasm64 = true; + + for (i = 0; i < module->import_memory_count; ++i) { + wasm64_flag = + module->import_memories[i].u.memory.mem_type.flags & MEMORY64_FLAG; + all_wasm64 &= wasm64_flag; + none_wasm64 &= !wasm64_flag; + } + + for (i = 0; i < module->memory_count; ++i) { + wasm64_flag = module->memories[i].flags & MEMORY64_FLAG; + all_wasm64 &= wasm64_flag; + none_wasm64 &= !wasm64_flag; + } + + if (!(all_wasm64 || none_wasm64)) { + wasm_loader_set_error_buf( + error_buf, error_buf_size, + "inconsistent limits wasm64 flags for memory sections", is_aot); + return false; + } + return true; +} +#endif + bool wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, uint32 error_buf_size, bool is_aot) @@ -60,6 +91,37 @@ wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, return true; } +bool +wasm_table_check_flags(const uint8 table_flag, char *error_buf, + uint32 error_buf_size, bool is_aot) +{ + /* Check whether certain features indicated by mem_flag are enabled in + * runtime */ + if (table_flag > MAX_TABLE_SIZE_FLAG) { + if (table_flag & SHARED_TABLE_FLAG) { + wasm_loader_set_error_buf(error_buf, error_buf_size, + "tables cannot be shared", is_aot); + } +#if WASM_ENABLE_MEMORY64 == 0 + if (table_flag & TABLE64_FLAG) { + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags(table64 flag was " + "found, please enable memory64)", + is_aot); + return false; + } +#endif + } + + if (table_flag > MAX_TABLE_SIZE_FLAG + TABLE64_FLAG) { + wasm_loader_set_error_buf(error_buf, error_buf_size, + "invalid limits flags", is_aot); + return false; + } + + return true; +} + /* * compare with a bigger type set in `wasm_value_type_size_internal()`, * this function will only cover global value type, function's param diff --git a/core/iwasm/common/wasm_loader_common.h b/core/iwasm/common/wasm_loader_common.h index d574110b..81174fb2 100644 --- a/core/iwasm/common/wasm_loader_common.h +++ b/core/iwasm/common/wasm_loader_common.h @@ -13,10 +13,22 @@ extern "C" { #endif +#if WASM_ENABLE_MEMORY64 != 0 +/* check consistency of memory64 flags across all memories, + * they must be either all wasm64 or all wasm32 */ +bool +check_memory64_flags_consistency(WASMModule *module, char *error_buf, + uint32 error_buf_size, bool is_aot); +#endif + bool wasm_memory_check_flags(const uint8 mem_flag, char *error_buf, uint32 error_buf_size, bool is_aot); +bool +wasm_table_check_flags(const uint8 table_flag, char *error_buf, + uint32 error_buf_size, bool is_aot); + bool is_valid_value_type(uint8 value_tpye); diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index e5600497..07734b3b 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -146,9 +146,20 @@ aot_validate_wasm(AOTCompContext *comp_ctx) } #if WASM_ENABLE_MEMORY64 != 0 - if (comp_ctx->pointer_size < sizeof(uint64) && IS_MEMORY64) { - aot_set_last_error("Compiling wasm64 to 32bit platform is not allowed"); - return false; + if (comp_ctx->pointer_size < sizeof(uint64)) { + if (IS_MEMORY64) { + aot_set_last_error("Compiling wasm64(contains i64 memory section) " + "to 32bit platform is not allowed"); + return false; + } + + for (uint32 i = 0; i < comp_ctx->comp_data->table_count; ++i) { + if (IS_TABLE64(i)) { + aot_set_last_error("Compiling wasm64(contains i64 table " + "section) to 32bit platform is not allowed"); + return false; + } + } } #endif diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index 895d2416..06d8e42b 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -532,8 +532,13 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) #define IS_MEMORY64 (comp_ctx->comp_data->memories[0].flags & MEMORY64_FLAG) #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) \ (IS_MEMORY64 ? VAL_IF_ENABLED : VAL_IF_DISABLED) +#define IS_TABLE64(i) \ + (comp_ctx->comp_data->tables[i].table_type.flags & TABLE64_FLAG) +#define TABLE64_COND_VALUE(i, VAL_IF_ENABLED, VAL_IF_DISABLED) \ + (IS_TABLE64(i) ? VAL_IF_ENABLED : VAL_IF_DISABLED) #else #define MEMORY64_COND_VALUE(VAL_IF_ENABLED, VAL_IF_DISABLED) (VAL_IF_DISABLED) +#define TABLE64_COND_VALUE(i, VAL_IF_ENABLED, VAL_IF_DISABLED) (VAL_IF_DISABLED) #endif #define POP_I32(v) POP(v, VALUE_TYPE_I32) @@ -548,6 +553,9 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) POP(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32)) #define POP_PAGE_COUNT(v) \ POP(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define POP_TBL_ELEM_IDX(v) \ + POP(v, TABLE64_COND_VALUE(tbl_idx, VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define POP_TBL_ELEM_LEN(v) POP_TBL_ELEM_IDX(v) #define POP_COND(llvm_value) \ do { \ @@ -613,6 +621,9 @@ set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type) #define PUSH_GC_REF(v) PUSH(v, VALUE_TYPE_GC_REF) #define PUSH_PAGE_COUNT(v) \ PUSH(v, MEMORY64_COND_VALUE(VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define PUSH_TBL_ELEM_IDX(v) \ + PUSH(v, TABLE64_COND_VALUE(tbl_idx, VALUE_TYPE_I64, VALUE_TYPE_I32)) +#define PUSH_TBL_ELEM_LEN(v) PUSH_TBL_ELEM_IDX(v) #define SET_CONST(v) \ do { \ diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index 85a9239a..167acc62 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -2089,6 +2089,9 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef ext_ret_offset, ext_ret_ptr, ext_ret, res; LLVMValueRef *param_values = NULL, *value_rets = NULL; LLVMValueRef *result_phis = NULL, value_ret, import_func_count; +#if WASM_ENABLE_MEMORY64 != 0 + LLVMValueRef u32_max, u32_cmp_result; +#endif LLVMTypeRef *param_types = NULL, ret_type; LLVMTypeRef llvm_func_type, llvm_func_ptr_type; LLVMTypeRef ext_ret_ptr_type; @@ -2153,7 +2156,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, func_param_count = func_type->param_count; func_result_count = func_type->result_count; - POP_I32(elem_idx); + POP_TBL_ELEM_IDX(elem_idx); /* get the cur size of the table instance */ if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx) @@ -2182,6 +2185,27 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } +#if WASM_ENABLE_MEMORY64 != 0 + /* Check if elem index >= UINT32_MAX */ + if (IS_TABLE64(tbl_idx)) { + if (!(u32_max = I64_CONST(UINT32_MAX))) { + aot_set_last_error("llvm build const failed"); + goto fail; + } + if (!(u32_cmp_result = + LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx, + u32_max, "cmp_elem_idx_u32_max"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + if (!(elem_idx = LLVMBuildTrunc(comp_ctx->builder, elem_idx, I32_TYPE, + "elem_idx_i32"))) { + aot_set_last_error("llvm build trunc failed."); + goto fail; + } + } +#endif + /* Check if (uint32)elem index >= table size */ if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx, table_size_const, "cmp_elem_idx"))) { @@ -2189,7 +2213,19 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - /* Throw exception if elem index >= table size */ +#if WASM_ENABLE_MEMORY64 != 0 + if (IS_TABLE64(tbl_idx)) { + if (!(cmp_elem_idx = + LLVMBuildOr(comp_ctx->builder, cmp_elem_idx, u32_cmp_result, + "larger_than_u32_max_or_cur_size"))) { + aot_set_last_error("llvm build or failed."); + goto fail; + } + } +#endif + + /* Throw exception if elem index >= table size or elem index >= UINT32_MAX + */ if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext( comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) { aot_set_last_error("llvm add basic block failed."); diff --git a/core/iwasm/compilation/aot_emit_table.c b/core/iwasm/compilation/aot_emit_table.c index f968bacd..d65d2f41 100644 --- a/core/iwasm/compilation/aot_emit_table.c +++ b/core/iwasm/compilation/aot_emit_table.c @@ -10,6 +10,72 @@ #include "aot_emit_gc.h" #endif +static bool +zero_extend_u64(AOTCompContext *comp_ctx, LLVMValueRef *value, const char *name) +{ + if (comp_ctx->pointer_size == sizeof(uint64)) { + /* zero extend to uint64 if the target is 64-bit */ + *value = LLVMBuildZExt(comp_ctx->builder, *value, I64_TYPE, name); + if (!*value) { + aot_set_last_error("llvm build zero extend failed."); + return false; + } + } + return true; +} + +/* check whether a table64 elem idx is greater than UINT32_MAX, if so, throw + * exception, otherwise trunc it to uint32 */ +static bool +check_tbl_elem_idx_and_trunc(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef *elem_idx, uint32 tbl_idx) +{ + LLVMValueRef u32_max, u32_cmp_result; + LLVMBasicBlockRef check_elem_idx_succ; + +#if WASM_ENABLE_MEMORY64 != 0 + if (!IS_TABLE64(tbl_idx)) { + return true; + } + + /* Check if elem index >= UINT32_MAX */ + if (!(u32_max = I64_CONST(UINT32_MAX))) { + aot_set_last_error("llvm build const failed"); + goto fail; + } + if (!(u32_cmp_result = + LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, *elem_idx, u32_max, + "cmp_elem_idx_u32_max"))) { + aot_set_last_error("llvm build icmp failed."); + goto fail; + } + if (!(*elem_idx = LLVMBuildTrunc(comp_ctx->builder, *elem_idx, I32_TYPE, + "elem_idx_i32"))) { + aot_set_last_error("llvm build trunc failed."); + goto fail; + } + + /* Throw exception if elem index >= UINT32_MAX*/ + if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) { + aot_set_last_error("llvm add basic block failed."); + goto fail; + } + + LLVMMoveBasicBlockAfter(check_elem_idx_succ, + LLVMGetInsertBlock(comp_ctx->builder)); + + if (!(aot_emit_exception(comp_ctx, func_ctx, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true, + u32_cmp_result, check_elem_idx_succ))) + goto fail; +#endif + + return true; +fail: + return false; +} + uint64 get_tbl_inst_offset(const AOTCompContext *comp_ctx, const AOTFuncContext *func_ctx, uint32 tbl_idx) @@ -158,6 +224,10 @@ aot_check_table_access(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, &elem_idx, tbl_idx)) { + goto fail; + } + /* Check if (uint32)elem index >= table size */ if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx, tbl_sz, "cmp_elem_idx"))) { @@ -192,7 +262,7 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef elem_idx, offset, func_idx; LLVMValueRef table_elem_base, table_elem_addr, table_elem; - POP_I32(elem_idx); + POP_TBL_ELEM_IDX(elem_idx); if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) { goto fail; @@ -289,7 +359,7 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } - POP_I32(elem_idx); + POP_TBL_ELEM_IDX(elem_idx); if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) { goto fail; @@ -388,7 +458,11 @@ aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* s */ POP_I32(param_values[4]); /* d */ - POP_I32(param_values[5]); + POP_TBL_ELEM_IDX(param_values[5]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[5], + tbl_idx)) { + goto fail; + } /* "" means return void */ if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6, @@ -408,6 +482,7 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type; LLVMValueRef func, param_values[6], value; + uint32 tbl_idx; param_types[0] = INT8_PTR_TYPE; param_types[1] = I32_TYPE; @@ -434,12 +509,34 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } + /* In table64, the length should be i32 type if any one of src/dst table + * is i32 type, set the table index to the lesser-or-equal table when + * popping length n */ + if (!(comp_ctx->comp_data->tables[src_tbl_idx].table_type.flags + & TABLE64_FLAG)) + tbl_idx = src_tbl_idx; + else + tbl_idx = dst_tbl_idx; /* n */ - POP_I32(param_values[3]); + POP_TBL_ELEM_LEN(param_values[3]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[3], + tbl_idx)) { + goto fail; + } /* s */ - POP_I32(param_values[4]); + tbl_idx = src_tbl_idx; + POP_TBL_ELEM_IDX(param_values[4]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[4], + tbl_idx)) { + goto fail; + } /* d */ - POP_I32(param_values[5]); + tbl_idx = dst_tbl_idx; + POP_TBL_ELEM_IDX(param_values[5]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[5], + tbl_idx)) { + goto fail; + } /* "" means return void */ if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6, @@ -484,7 +581,14 @@ aot_compile_op_table_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - PUSH_I32(tbl_sz); +#if WASM_ENABLE_MEMORY64 != 0 + if (IS_TABLE64(tbl_idx)) { + if (!zero_extend_u64(comp_ctx, &tbl_sz, "length64")) { + goto fail; + } + } +#endif + PUSH_TBL_ELEM_IDX(tbl_sz); return true; fail: @@ -517,7 +621,11 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* n */ - POP_I32(param_values[2]); + POP_TBL_ELEM_LEN(param_values[2]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[2], + tbl_idx)) { + goto fail; + } /* v */ if (comp_ctx->enable_gc) { @@ -545,7 +653,14 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } - PUSH_I32(ret); +#if WASM_ENABLE_MEMORY64 != 0 + if (IS_TABLE64(tbl_idx)) { + if (!zero_extend_u64(comp_ctx, &ret, "table_size64")) { + goto fail; + } + } +#endif + PUSH_TBL_ELEM_LEN(ret); return true; fail: @@ -579,7 +694,11 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* n */ - POP_I32(param_values[2]); + POP_TBL_ELEM_LEN(param_values[2]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[2], + tbl_idx)) { + goto fail; + } /* v */ if (comp_ctx->enable_gc) { @@ -601,7 +720,11 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } /* i */ - POP_I32(param_values[4]); + POP_TBL_ELEM_IDX(param_values[4]); + if (!check_tbl_elem_idx_and_trunc(comp_ctx, func_ctx, ¶m_values[4], + tbl_idx)) { + goto fail; + } /* "" means return void */ if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5, diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 83597401..6023b070 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -93,6 +93,10 @@ extern "C" { #define MAX_PAGE_COUNT_FLAG 0x01 #define SHARED_MEMORY_FLAG 0x02 #define MEMORY64_FLAG 0x04 +#define MAX_TABLE_SIZE_FLAG 0x01 +/* the shared flag for table is not actual used now */ +#define SHARED_TABLE_FLAG 0x02 +#define TABLE64_FLAG 0x04 /** * In the multi-memory proposal, the memarg in loads and stores are @@ -494,6 +498,7 @@ typedef struct WASMTableType { * 0: no max size and not shared * 1: has max size * 2: shared + * 4: table64 */ uint8 flags; bool possible_grow; @@ -520,6 +525,7 @@ typedef uint64 mem_offset_t; typedef uint32 mem_offset_t; #define PR_MEM_OFFSET PRIu32 #endif +typedef mem_offset_t tbl_elem_idx_t; typedef struct WASMMemory { uint32 flags; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 67f8c2d4..faa97f35 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -511,9 +511,9 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) #endif #if WASM_ENABLE_MEMORY64 != 0 -#define PUSH_MEM_OFFSET(value) \ +#define COND_PUSH_TEMPLATE(cond, value) \ do { \ - if (is_memory64) { \ + if (cond) { \ PUT_I64_TO_ADDR(frame_sp, value); \ frame_sp += 2; \ } \ @@ -521,8 +521,11 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) *(int32 *)frame_sp++ = (int32)(value); \ } \ } while (0) +#define PUSH_MEM_OFFSET(value) COND_PUSH_TEMPLATE(is_memory64, value) +#define PUSH_TBL_ELEM_IDX(value) COND_PUSH_TEMPLATE(is_table64, value) #else #define PUSH_MEM_OFFSET(value) PUSH_I32(value) +#define PUSH_TBL_ELEM_IDX(value) PUSH_I32(value) #endif #define PUSH_PAGE_COUNT(value) PUSH_MEM_OFFSET(value) @@ -558,8 +561,10 @@ wasm_interp_get_frame_ref(WASMInterpFrame *frame) #if WASM_ENABLE_MEMORY64 != 0 #define POP_MEM_OFFSET() (is_memory64 ? POP_I64() : POP_I32()) +#define POP_TBL_ELEM_IDX() (is_table64 ? POP_I64() : POP_I32()) #else #define POP_MEM_OFFSET() POP_I32() +#define POP_TBL_ELEM_IDX() POP_I32() #endif #define POP_PAGE_COUNT() POP_MEM_OFFSET() @@ -1562,7 +1567,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 opcode; uint32 i, depth, cond, count, fidx, tidx, lidx, frame_size = 0; uint32 all_cell_num = 0; - int32 val; + tbl_elem_idx_t val; uint8 *else_addr, *end_addr, *maddr = NULL; uint32 local_idx, local_offset, global_idx; uint8 local_type, *global_addr; @@ -1602,6 +1607,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ bool is_memory64 = false; + bool is_table64 = false; if (memory) is_memory64 = memory->is_memory64; #endif @@ -2315,7 +2321,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /** * type check. compiler will make sure all like - * (call_indirect (type $x) (i32.const 1)) + * (call_indirect (type $x) (it.const 1)) * the function type has to be defined in the module also * no matter it is used or not */ @@ -2334,9 +2340,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* clang-format on */ tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - val = POP_I32(); - if ((uint32)val >= tbl_inst->cur_size) { + val = POP_TBL_ELEM_IDX(); + if (val >= tbl_inst->cur_size) { wasm_set_exception(module, "undefined element"); goto got_exception; } @@ -2482,15 +2491,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_TABLE_GET) { - uint32 tbl_idx, elem_idx; + uint32 tbl_idx; + tbl_elem_idx_t elem_idx; WASMTableInstance *tbl_inst; read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - elem_idx = POP_I32(); + elem_idx = POP_TBL_ELEM_IDX(); if (elem_idx >= tbl_inst->cur_size) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -2507,20 +2520,24 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_TABLE_SET) { WASMTableInstance *tbl_inst; - uint32 tbl_idx, elem_idx; + uint32 tbl_idx; + tbl_elem_idx_t elem_idx; table_elem_type_t elem_val; read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif #if WASM_ENABLE_GC == 0 elem_val = POP_I32(); #else elem_val = POP_REF(); #endif - elem_idx = POP_I32(); + elem_idx = POP_TBL_ELEM_IDX(); if (elem_idx >= tbl_inst->cur_size) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -4616,13 +4633,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_MEMORY_GROW) { - uint32 mem_idx, delta, prev_page_count; + uint32 mem_idx, prev_page_count; + mem_offset_t delta; read_leb_memidx(frame_ip, frame_ip_end, mem_idx); prev_page_count = memory->cur_page_count; - delta = (uint32)POP_PAGE_COUNT(); + delta = POP_PAGE_COUNT(); - if (!wasm_enlarge_memory_with_idx(module, delta, mem_idx)) { + if ( +#if WASM_ENABLE_MEMORY64 != 0 + delta > UINT32_MAX || +#endif + !wasm_enlarge_memory_with_idx(module, (uint32)delta, + mem_idx)) { /* failed to memory.grow, return -1 */ PUSH_PAGE_COUNT(-1); } @@ -5778,8 +5801,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 case WASM_OP_TABLE_INIT: { - uint32 tbl_idx, elem_idx; - uint32 n, s, d; + uint32 tbl_idx; + tbl_elem_idx_t elem_idx, d; + uint32 n, s; WASMTableInstance *tbl_inst; table_elem_type_t *table_elems; InitializerExpression *tbl_seg_init_values = NULL, @@ -5793,10 +5817,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tbl_idx < module->module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif n = (uint32)POP_I32(); s = (uint32)POP_I32(); - d = (uint32)POP_I32(); + d = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); if (!bh_bitmap_get_bit(module->e->common.elem_dropped, elem_idx)) { @@ -5809,8 +5836,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, .value_count; } - if (offset_len_out_of_bounds(s, n, tbl_seg_len) - || offset_len_out_of_bounds(d, n, + /* TODO: memory64 current implementation of table64 + * still assumes the max table size UINT32_MAX + */ + if ( +#if WASM_ENABLE_MEMORY64 != 0 + d > UINT32_MAX || +#endif + offset_len_out_of_bounds(s, n, tbl_seg_len) + || offset_len_out_of_bounds((uint32)d, n, tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); @@ -5864,7 +5898,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_COPY: { uint32 src_tbl_idx, dst_tbl_idx; - uint32 n, s, d; + tbl_elem_idx_t n, s, d; WASMTableInstance *src_tbl_inst, *dst_tbl_inst; read_leb_uint32(frame_ip, frame_ip_end, dst_tbl_idx); @@ -5877,14 +5911,29 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, src_tbl_inst = wasm_get_table_inst(module, src_tbl_idx); - n = (uint32)POP_I32(); - s = (uint32)POP_I32(); - d = (uint32)POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = src_tbl_inst->is_table64 + && dst_tbl_inst->is_table64; +#endif + n = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = src_tbl_inst->is_table64; +#endif + s = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = dst_tbl_inst->is_table64; +#endif + d = (tbl_elem_idx_t)POP_TBL_ELEM_IDX(); - if (offset_len_out_of_bounds(d, n, + if ( +#if WASM_ENABLE_MEMORY64 != 0 + n > UINT32_MAX || s > UINT32_MAX || d > UINT32_MAX + || +#endif + offset_len_out_of_bounds((uint32)d, (uint32)n, dst_tbl_inst->cur_size) || offset_len_out_of_bounds( - s, n, src_tbl_inst->cur_size)) { + (uint32)s, (uint32)n, src_tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; @@ -5907,28 +5956,37 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, case WASM_OP_TABLE_GROW: { WASMTableInstance *tbl_inst; - uint32 tbl_idx, n, orig_tbl_sz; + uint32 tbl_idx, orig_tbl_sz; + tbl_elem_idx_t n; table_elem_type_t init_val; read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif orig_tbl_sz = tbl_inst->cur_size; - n = POP_I32(); + n = POP_TBL_ELEM_IDX(); #if WASM_ENABLE_GC == 0 init_val = POP_I32(); #else init_val = POP_REF(); #endif - if (!wasm_enlarge_table(module, tbl_idx, n, init_val)) { - PUSH_I32(-1); + if ( +#if WASM_ENABLE_MEMORY64 != 0 + n > UINT32_MAX || +#endif + !wasm_enlarge_table(module, tbl_idx, (uint32)n, + init_val)) { + PUSH_TBL_ELEM_IDX(-1); } else { - PUSH_I32(orig_tbl_sz); + PUSH_TBL_ELEM_IDX(orig_tbl_sz); } break; } @@ -5941,13 +5999,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - PUSH_I32(tbl_inst->cur_size); + PUSH_TBL_ELEM_IDX(tbl_inst->cur_size); break; } case WASM_OP_TABLE_FILL: { - uint32 tbl_idx, n; + uint32 tbl_idx; + tbl_elem_idx_t n, elem_idx; WASMTableInstance *tbl_inst; table_elem_type_t fill_val; @@ -5955,24 +6017,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_assert(tbl_idx < module->table_count); tbl_inst = wasm_get_table_inst(module, tbl_idx); +#if WASM_ENABLE_MEMORY64 != 0 + is_table64 = tbl_inst->is_table64; +#endif - n = POP_I32(); + n = POP_TBL_ELEM_IDX(); #if WASM_ENABLE_GC == 0 fill_val = POP_I32(); #else fill_val = POP_REF(); #endif - i = POP_I32(); + elem_idx = POP_TBL_ELEM_IDX(); - if (offset_len_out_of_bounds(i, n, + if ( +#if WASM_ENABLE_MEMORY64 != 0 + n > UINT32_MAX || elem_idx > UINT32_MAX || +#endif + offset_len_out_of_bounds((uint32)elem_idx, + (uint32)n, tbl_inst->cur_size)) { wasm_set_exception(module, "out of bounds table access"); goto got_exception; } - for (; n != 0; i++, n--) { - tbl_inst->elems[i] = fill_val; + for (; n != 0; elem_idx++, n--) { + tbl_inst->elems[elem_idx] = fill_val; } break; } diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index ff3501e3..e6b797f9 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -51,6 +51,18 @@ has_module_memory64(WASMModule *module) return false; } + +static bool +is_table_64bit(WASMModule *module, uint32 table_idx) +{ + if (table_idx < module->import_table_count) + return !!(module->import_tables[table_idx].u.table.table_type.flags + & TABLE64_FLAG); + else + return !!(module->tables[table_idx].table_type.flags & TABLE64_FLAG); + + return false; +} #endif static void @@ -2201,10 +2213,14 @@ fail: } static void -adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) +adjust_table_max_size(bool is_table64, uint32 init_size, uint32 max_size_flag, + uint32 *max_size) { uint32 default_max_size; + /* TODO: current still use UINT32_MAX as upper limit for table size to keep + * ABI unchanged */ + (void)is_table64; if (UINT32_MAX / 2 > init_size) default_max_size = init_size * 2; else @@ -2499,9 +2515,9 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, const char *table_name, WASMTableImport *table, char *error_buf, uint32 error_buf_size) { - const uint8 *p = *p_buf, *p_end = buf_end; - uint32 declare_elem_type = 0, declare_max_size_flag = 0, - declare_init_size = 0, declare_max_size = 0; + const uint8 *p = *p_buf, *p_end = buf_end, *p_org; + uint32 declare_elem_type = 0, table_flag = 0, declare_init_size = 0, + declare_max_size = 0; #if WASM_ENABLE_MULTI_MODULE != 0 WASMModule *sub_module = NULL; WASMTable *linked_table = NULL; @@ -2510,6 +2526,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, WASMRefType ref_type; bool need_ref_type_map; #endif + bool is_table64 = false; #if WASM_ENABLE_GC == 0 CHECK_BUF(p, p_end, 1); @@ -2548,23 +2565,29 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, #endif #endif /* end of WASM_ENABLE_GC == 0 */ - read_leb_uint32(p, p_end, declare_max_size_flag); - if (declare_max_size_flag > 1) { - set_error_buf(error_buf, error_buf_size, "integer too large"); + p_org = p; + read_leb_uint32(p, p_end, table_flag); + is_table64 = table_flag & TABLE64_FLAG; + if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long(import table)"); + set_error_buf(error_buf, error_buf_size, "invalid limits flags"); + return false; + } + + if (!wasm_table_check_flags(table_flag, error_buf, error_buf_size, false)) { return false; } read_leb_uint32(p, p_end, declare_init_size); - - if (declare_max_size_flag) { + if (table_flag & MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, declare_max_size); if (!check_table_max_size(declare_init_size, declare_max_size, error_buf, error_buf_size)) return false; } - adjust_table_max_size(declare_init_size, declare_max_size_flag, - &declare_max_size); + adjust_table_max_size(is_table64, declare_init_size, + table_flag & MAX_TABLE_SIZE_FLAG, &declare_max_size); *p_buf = p; @@ -2582,7 +2605,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, declare_elem_type = linked_table->table_type.elem_type; declare_init_size = linked_table->table_type.init_size; declare_max_size = linked_table->table_type.max_size; - declare_max_size_flag = linked_table->table_type.flags; + table_flag = linked_table->table_type.flags; table->import_table_linked = linked_table; table->import_module = sub_module; } @@ -2591,12 +2614,17 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, #endif /* WASM_ENABLE_MULTI_MODULE != 0 */ /* (table (export "table") 10 20 funcref) */ + /* (table (export "table64") 10 20 funcref) */ /* we need this section working in wamrc */ if (!strcmp("spectest", sub_module_name)) { const uint32 spectest_table_init_size = 10; const uint32 spectest_table_max_size = 20; - if (strcmp("table", table_name)) { + if (strcmp("table", table_name) +#if WASM_ENABLE_MEMORY64 != 0 + && strcmp("table64", table_name) +#endif + ) { set_error_buf(error_buf, error_buf_size, "incompatible import type or unknown import"); return false; @@ -2616,7 +2644,7 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, /* now we believe all declaration are ok */ table->table_type.elem_type = declare_elem_type; table->table_type.init_size = declare_init_size; - table->table_type.flags = declare_max_size_flag; + table->table_type.flags = table_flag; table->table_type.max_size = declare_max_size; #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -2709,7 +2737,7 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, read_leb_uint32(p, p_end, mem_flag); is_memory64 = mem_flag & MEMORY64_FLAG; if (p - p_org > 1) { - LOG_VERBOSE("integer representation too long"); + LOG_VERBOSE("integer representation too long(import memory)"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } @@ -3024,6 +3052,7 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, WASMRefType ref_type; bool need_ref_type_map; #endif + bool is_table64 = false; #if WASM_ENABLE_GC == 0 CHECK_BUF(p, p_end, 1); @@ -3061,34 +3090,20 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, p_org = p; read_leb_uint32(p, p_end, table->table_type.flags); -#if WASM_ENABLE_SHARED_MEMORY == 0 - if (p - p_org > 1) { - set_error_buf(error_buf, error_buf_size, - "integer representation too long"); - return false; - } - if (table->table_type.flags > 1) { - set_error_buf(error_buf, error_buf_size, "integer too large"); - return false; - } -#else + is_table64 = table->table_type.flags & TABLE64_FLAG; if (p - p_org > 1) { + LOG_VERBOSE("integer representation too long(table)"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } - if (table->table_type.flags == 2) { - set_error_buf(error_buf, error_buf_size, "tables cannot be shared"); + + if (!wasm_table_check_flags(table->table_type.flags, error_buf, + error_buf_size, false)) { return false; } - if (table->table_type.flags > 1) { - set_error_buf(error_buf, error_buf_size, "invalid limits flags"); - return false; - } -#endif read_leb_uint32(p, p_end, table->table_type.init_size); - - if (table->table_type.flags) { + if (table->table_type.flags & MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, table->table_type.max_size); if (!check_table_max_size(table->table_type.init_size, table->table_type.max_size, error_buf, @@ -3096,7 +3111,8 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, return false; } - adjust_table_max_size(table->table_type.init_size, table->table_type.flags, + adjust_table_max_size(is_table64, table->table_type.init_size, + table->table_type.flags & MAX_TABLE_SIZE_FLAG, &table->table_type.max_size); #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -3128,7 +3144,7 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, read_leb_uint32(p, p_end, memory->flags); is_memory64 = memory->flags & MEMORY64_FLAG; if (p - p_org > 1) { - LOG_VERBOSE("integer representation too long"); + LOG_VERBOSE("integer representation too long(memory)"); set_error_buf(error_buf, error_buf_size, "invalid limits flags"); return false; } @@ -4402,6 +4418,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; + uint8 table_elem_idx_type; uint32 table_segment_count, i; uint64 total_size; WASMTableSeg *table_segment; @@ -4424,6 +4441,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, "invalid elements segment kind"); return false; } + table_elem_idx_type = VALUE_TYPE_I32; #if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 read_leb_uint32(p, p_end, table_segment->mode); @@ -4459,9 +4477,17 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, if (!check_table_index(module, table_segment->table_index, error_buf, error_buf_size)) return false; - if (!load_init_expr( - module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, NULL, error_buf, error_buf_size)) + +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + if (!load_init_expr(module, &p, p_end, + &table_segment->base_offset, + table_elem_idx_type, NULL, error_buf, + error_buf_size)) return false; if (table_segment->mode == 0) { @@ -4509,9 +4535,16 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; - if (!load_init_expr( - module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, NULL, error_buf, error_buf_size)) +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + if (!load_init_expr(module, &p, p_end, + &table_segment->base_offset, + table_elem_idx_type, NULL, error_buf, + error_buf_size)) return false; if (!load_elem_type(module, &p, p_end, &table_segment->elem_type, @@ -4563,7 +4596,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, "unknown element segment kind"); return false; } -#else /* else of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ +#else /* else of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ /* * like: 00 41 05 0b 04 00 01 00 01 * for: (elem 0 (offset (i32.const 5)) $f1 $f2 $f1 $f2) @@ -4572,8 +4605,14 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr(module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, NULL, error_buf, + table_elem_idx_type, NULL, error_buf, error_buf_size)) return false; if (!load_func_index_vec(&p, p_end, module, table_segment, @@ -4588,6 +4627,16 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, return false; #endif /* end of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */ +#if WASM_ENABLE_MEMORY64 != 0 + if (table_elem_idx_type == VALUE_TYPE_I64 + && table_segment->base_offset.u.u64 > UINT32_MAX) { + set_error_buf(error_buf, error_buf_size, + "In table64, table base offset can't be " + "larger than UINT32_MAX"); + return false; + } +#endif + #if WASM_ENABLE_WAMR_COMPILER != 0 if (table_segment->elem_type == VALUE_TYPE_EXTERNREF) module->is_ref_types_used = true; @@ -6110,6 +6159,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif } +#if WASM_ENABLE_MEMORY64 != 0 + if (!check_memory64_flags_consistency(module, error_buf, error_buf_size, + false)) + return false; +#endif + calculate_global_data_offset(module); #if WASM_ENABLE_FAST_JIT != 0 @@ -9608,6 +9663,7 @@ fail: #define POP_REF(Type) TEMPLATE_POP_REF(Type) #define PUSH_MEM_OFFSET() TEMPLATE_PUSH_REF(mem_offset_type) #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() +#define PUSH_TBL_ELEM_IDX() TEMPLATE_PUSH_REF(table_elem_idx_type) #define POP_I32() TEMPLATE_POP(I32) #define POP_F32() TEMPLATE_POP(F32) @@ -9618,6 +9674,7 @@ fail: #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF) #define POP_STRINGREF() TEMPLATE_POP(STRINGREF) #define POP_MEM_OFFSET() TEMPLATE_POP_REF(mem_offset_type) +#define POP_TBL_ELEM_IDX() TEMPLATE_POP_REF(table_elem_idx_type) #if WASM_ENABLE_FAST_INTERP != 0 @@ -10803,7 +10860,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type, + table_elem_idx_type; BlockType func_block_type; uint16 *local_offsets, local_offset; uint32 type_idx, func_idx, local_idx, global_idx, table_idx; @@ -10838,6 +10896,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; #else mem_offset_type = VALUE_TYPE_I32; + table_elem_idx_type = VALUE_TYPE_I32; #endif uint32 memidx; @@ -11997,8 +12056,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif /* skip elem idx */ - POP_I32(); + POP_TBL_ELEM_IDX(); if (type_idx >= module->type_count) { set_error_buf(error_buf, error_buf_size, "unknown type"); @@ -12375,8 +12439,8 @@ re_scan: break; } - /* table.get x. tables[x]. [i32] -> [t] */ - /* table.set x. tables[x]. [i32 t] -> [] */ + /* table.get x. tables[x]. [it] -> [t] */ + /* table.set x. tables[x]. [it t] -> [] */ case WASM_OP_TABLE_GET: case WASM_OP_TABLE_SET: { @@ -12407,8 +12471,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (opcode == WASM_OP_TABLE_GET) { - POP_I32(); + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 PUSH_OFFSET_TYPE(decl_ref_type); #endif @@ -12419,7 +12488,7 @@ re_scan: POP_OFFSET_TYPE(decl_ref_type); #endif POP_TYPE(decl_ref_type); - POP_I32(); + POP_TBL_ELEM_IDX(); } #if WASM_ENABLE_WAMR_COMPILER != 0 @@ -14702,7 +14771,12 @@ re_scan: #endif POP_I32(); POP_I32(); - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; @@ -14727,7 +14801,8 @@ re_scan: } case WASM_OP_TABLE_COPY: { - uint8 src_type, dst_type; + uint8 src_type, dst_type, src_tbl_idx_type, + dst_tbl_idx_type, min_tbl_idx_type; #if WASM_ENABLE_GC != 0 WASMRefType *src_ref_type = NULL, *dst_ref_type = NULL; #endif @@ -14773,9 +14848,31 @@ re_scan: emit_uint32(loader_ctx, dst_tbl_idx); emit_uint32(loader_ctx, src_tbl_idx); #endif - POP_I32(); - POP_I32(); - POP_I32(); + +#if WASM_ENABLE_MEMORY64 != 0 + src_tbl_idx_type = is_table_64bit(module, src_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + dst_tbl_idx_type = is_table_64bit(module, dst_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + min_tbl_idx_type = + (src_tbl_idx_type == VALUE_TYPE_I32 + || dst_tbl_idx_type == VALUE_TYPE_I32) + ? VALUE_TYPE_I32 + : VALUE_TYPE_I64; +#else + src_tbl_idx_type = VALUE_TYPE_I32; + dst_tbl_idx_type = VALUE_TYPE_I32; + min_tbl_idx_type = VALUE_TYPE_I32; +#endif + + table_elem_idx_type = min_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = src_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = dst_tbl_idx_type; + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; @@ -14795,7 +14892,12 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - PUSH_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + PUSH_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; @@ -14844,15 +14946,20 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 POP_OFFSET_TYPE(decl_type); #endif POP_TYPE(decl_type); if (opcode1 == WASM_OP_TABLE_GROW) - PUSH_I32(); + PUSH_TBL_ELEM_IDX(); else - POP_I32(); + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_WAMR_COMPILER != 0 module->is_ref_types_used = true; diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 968eaf00..0c29ef3c 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -33,12 +33,25 @@ has_module_memory64(WASMModule *module) /* TODO: multi-memories for now assuming the memory idx type is consistent * across multi-memories */ if (module->import_memory_count > 0) - return !!(module->import_memories[0].u.mem_type.flags & MEMORY64_FLAG); + return !!(module->import_memories[0].u.memory.mem_type.flags + & MEMORY64_FLAG); else if (module->memory_count > 0) return !!(module->memories[0].flags & MEMORY64_FLAG); return false; } + +static bool +is_table_64bit(WASMModule *module, uint32 table_idx) +{ + if (table_idx < module->import_table_count) + return !!(module->import_tables[table_idx].u.table.table_type.flags + & TABLE64_FLAG); + else + return !!(module->tables[table_idx].table_type.flags & TABLE64_FLAG); + + return false; +} #endif static void @@ -577,11 +590,15 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, } static void -adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) +adjust_table_max_size(bool is_table64, uint32 init_size, uint32 max_size_flag, + uint32 *max_size) { uint32 default_max_size = init_size * 2 > WASM_TABLE_MAX_SIZE ? init_size * 2 : WASM_TABLE_MAX_SIZE; + /* TODO: current still use UINT32_MAX as upper limit for table size to keep + * ABI unchanged */ + (void)is_table64; if (max_size_flag) { /* module defines the table limitation */ @@ -642,8 +659,8 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, char *error_buf, uint32 error_buf_size) { const uint8 *p = *p_buf, *p_end = buf_end; - uint32 declare_elem_type = 0, declare_max_size_flag = 0, - declare_init_size = 0, declare_max_size = 0; + uint32 declare_elem_type = 0, table_flag = 0, declare_init_size = 0, + declare_max_size = 0; CHECK_BUF(p, p_end, 1); /* 0x70 or 0x6F */ @@ -654,24 +671,29 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, #endif ); - read_leb_uint32(p, p_end, declare_max_size_flag); + read_leb_uint32(p, p_end, table_flag); + + if (!wasm_table_check_flags(table_flag, error_buf, error_buf_size, false)) { + return false; + } + read_leb_uint32(p, p_end, declare_init_size); - if (declare_max_size_flag & 1) { + if (table_flag & MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, declare_max_size); bh_assert(table->table_type.init_size <= table->table_type.max_size); } - adjust_table_max_size(declare_init_size, declare_max_size_flag, - &declare_max_size); + adjust_table_max_size(table_flag & TABLE64_FLAG, declare_init_size, + table_flag & MAX_TABLE_SIZE_FLAG, &declare_max_size); *p_buf = p; - bh_assert( - !((declare_max_size_flag & 1) && declare_init_size > declare_max_size)); + bh_assert(!((table_flag & MAX_TABLE_SIZE_FLAG) + && declare_init_size > declare_max_size)); /* now we believe all declaration are ok */ table->table_type.elem_type = declare_elem_type; table->table_type.init_size = declare_init_size; - table->table_type.flags = declare_max_size_flag; + table->table_type.flags = table_flag; table->table_type.max_size = declare_max_size; return true; } @@ -789,16 +811,22 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table, p_org = p; read_leb_uint32(p, p_end, table->table_type.flags); bh_assert(p - p_org <= 1); - bh_assert(table->table_type.flags <= 1); (void)p_org; + if (!wasm_table_check_flags(table->table_type.flags, error_buf, + error_buf_size, false)) { + return false; + } + read_leb_uint32(p, p_end, table->table_type.init_size); - if (table->table_type.flags == 1) { + if (table->table_type.flags == MAX_TABLE_SIZE_FLAG) { read_leb_uint32(p, p_end, table->table_type.max_size); bh_assert(table->table_type.init_size <= table->table_type.max_size); } - adjust_table_max_size(table->table_type.init_size, table->table_type.flags, + adjust_table_max_size(table->table_type.flags & TABLE64_FLAG, + table->table_type.init_size, + table->table_type.flags & MAX_TABLE_SIZE_FLAG, &table->table_type.max_size); *p_buf = p; @@ -1575,6 +1603,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, uint32 error_buf_size) { const uint8 *p = buf, *p_end = buf_end; + uint8 table_elem_idx_type; uint32 table_segment_count, i, table_index, function_count; uint64 total_size; WASMTableSeg *table_segment; @@ -1592,6 +1621,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, table_segment = module->table_segments; for (i = 0; i < table_segment_count; i++, table_segment++) { bh_assert(p < p_end); + table_elem_idx_type = VALUE_TYPE_I32; #if WASM_ENABLE_REF_TYPES != 0 read_leb_uint32(p, p_end, table_segment->mode); @@ -1608,9 +1638,15 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr( module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, error_buf, error_buf_size)) + table_elem_idx_type, error_buf, error_buf_size)) return false; if (table_segment->mode == 0) { @@ -1646,9 +1682,15 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr( module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, error_buf, error_buf_size)) + table_elem_idx_type, error_buf, error_buf_size)) return false; if (!load_elem_type(&p, p_end, &table_segment->elem_type, table_segment->mode == 2 ? true : false, @@ -1691,13 +1733,29 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, &table_segment->table_index, error_buf, error_buf_size)) return false; +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = + is_table_64bit(module, table_segment->table_index) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (!load_init_expr(module, &p, p_end, &table_segment->base_offset, - VALUE_TYPE_I32, error_buf, error_buf_size)) + table_elem_idx_type, error_buf, error_buf_size)) return false; if (!load_func_index_vec(&p, p_end, module, table_segment, error_buf, error_buf_size)) return false; #endif /* WASM_ENABLE_REF_TYPES != 0 */ + +#if WASM_ENABLE_MEMORY64 != 0 + if (table_elem_idx_type == VALUE_TYPE_I64 + && table_segment->base_offset.u.u64 > UINT32_MAX) { + set_error_buf(error_buf, error_buf_size, + "In table64, table base offset can't be " + "larger than UINT32_MAX"); + return false; + } +#endif } } @@ -1781,8 +1839,8 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end, /* This memory_flag is from memory instead of data segment */ uint8 memory_flag; if (module->import_memory_count > 0) { - memory_flag = - module->import_memories[mem_index].u.mem_type.flags; + memory_flag = module->import_memories[mem_index] + .u.memory.mem_type.flags; } else { memory_flag = @@ -2948,6 +3006,12 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } +#if WASM_ENABLE_MEMORY64 != 0 + if (!check_memory64_flags_consistency(module, error_buf, error_buf_size, + false)) + return false; +#endif + calculate_global_data_offset(module); #if WASM_ENABLE_FAST_JIT != 0 @@ -5214,6 +5278,13 @@ fail: } while (0) #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() +#define PUSH_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_MEM_OFFSET() \ do { \ if (!wasm_loader_pop_frame_ref_offset(loader_ctx, mem_offset_type, \ @@ -5221,6 +5292,13 @@ fail: goto fail; \ } while (0) +#define POP_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref_offset( \ @@ -5284,6 +5362,13 @@ fail: #define PUSH_PAGE_COUNT() PUSH_MEM_OFFSET() +#define PUSH_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_push_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_I32() \ do { \ if (!(wasm_loader_pop_frame_ref(loader_ctx, VALUE_TYPE_I32, error_buf, \ @@ -5326,6 +5411,13 @@ fail: goto fail; \ } while (0) +#define POP_TBL_ELEM_IDX() \ + do { \ + if (!(wasm_loader_pop_frame_ref(loader_ctx, table_elem_idx_type, \ + error_buf, error_buf_size))) \ + goto fail; \ + } while (0) + #define POP_AND_PUSH(type_pop, type_push) \ do { \ if (!(wasm_loader_push_pop_frame_ref(loader_ctx, 1, type_push, \ @@ -5945,7 +6037,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, { uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org; uint32 param_count, local_count, global_count; - uint8 *param_types, *local_types, local_type, global_type, mem_offset_type; + uint8 *param_types, *local_types, local_type, global_type, mem_offset_type, + table_elem_idx_type; BlockType func_block_type; uint16 *local_offsets, local_offset; uint32 count, local_idx, global_idx, u32, align, i, memidx; @@ -5976,6 +6069,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, mem_offset_type = is_memory64 ? VALUE_TYPE_I64 : VALUE_TYPE_I32; #else mem_offset_type = VALUE_TYPE_I32; + table_elem_idx_type = VALUE_TYPE_I32; #endif global_count = module->import_global_count + module->global_count; @@ -6588,8 +6682,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif /* skip elem idx */ - POP_I32(); + POP_TBL_ELEM_IDX(); bh_assert(type_idx < module->type_count); @@ -6865,8 +6964,8 @@ re_scan: break; } - /* table.get x. tables[x]. [i32] -> [t] */ - /* table.set x. tables[x]. [i32 t] -> [] */ + /* table.get x. tables[x]. [it] -> [t] */ + /* table.set x. tables[x]. [it t] -> [] */ case WASM_OP_TABLE_GET: case WASM_OP_TABLE_SET: { @@ -6882,8 +6981,13 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif if (opcode == WASM_OP_TABLE_GET) { - POP_I32(); + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 PUSH_OFFSET_TYPE(decl_ref_type); #endif @@ -6894,7 +6998,7 @@ re_scan: POP_OFFSET_TYPE(decl_ref_type); #endif POP_TYPE(decl_ref_type); - POP_I32(); + POP_TBL_ELEM_IDX(); } break; } @@ -7819,7 +7923,12 @@ re_scan: #endif POP_I32(); POP_I32(); - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); break; } case WASM_OP_ELEM_DROP: @@ -7838,7 +7947,8 @@ re_scan: case WASM_OP_TABLE_COPY: { uint8 src_ref_type, dst_ref_type; - uint32 src_tbl_idx, dst_tbl_idx; + uint32 src_tbl_idx, dst_tbl_idx, src_tbl_idx_type, + dst_tbl_idx_type, min_tbl_idx_type; read_leb_uint32(p, p_end, src_tbl_idx); if (!get_table_elem_type(module, src_tbl_idx, @@ -7862,9 +7972,31 @@ re_scan: emit_uint32(loader_ctx, src_tbl_idx); emit_uint32(loader_ctx, dst_tbl_idx); #endif - POP_I32(); - POP_I32(); - POP_I32(); + +#if WASM_ENABLE_MEMORY64 != 0 + src_tbl_idx_type = is_table_64bit(module, src_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + dst_tbl_idx_type = is_table_64bit(module, dst_tbl_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; + min_tbl_idx_type = + (src_tbl_idx_type == VALUE_TYPE_I32 + || dst_tbl_idx_type == VALUE_TYPE_I32) + ? VALUE_TYPE_I32 + : VALUE_TYPE_I64; +#else + src_tbl_idx_type = VALUE_TYPE_I32; + dst_tbl_idx_type = VALUE_TYPE_I32; + min_tbl_idx_type = VALUE_TYPE_I32; +#endif + + table_elem_idx_type = min_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = src_tbl_idx_type; + POP_TBL_ELEM_IDX(); + table_elem_idx_type = dst_tbl_idx_type; + POP_TBL_ELEM_IDX(); break; } case WASM_OP_TABLE_SIZE: @@ -7882,7 +8014,12 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - PUSH_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + PUSH_TBL_ELEM_IDX(); break; } case WASM_OP_TABLE_GROW: @@ -7914,15 +8051,20 @@ re_scan: emit_uint32(loader_ctx, table_idx); #endif - POP_I32(); +#if WASM_ENABLE_MEMORY64 != 0 + table_elem_idx_type = is_table_64bit(module, table_idx) + ? VALUE_TYPE_I64 + : VALUE_TYPE_I32; +#endif + POP_TBL_ELEM_IDX(); #if WASM_ENABLE_FAST_INTERP != 0 POP_OFFSET_TYPE(decl_ref_type); #endif POP_TYPE(decl_ref_type); if (opcode1 == WASM_OP_TABLE_GROW) - PUSH_I32(); + PUSH_TBL_ELEM_IDX(); else - POP_I32(); + PUSH_TBL_ELEM_IDX(); break; } #endif /* WASM_ENABLE_REF_TYPES */ diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 90299df9..06ac2daf 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -678,6 +678,8 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, uninitialized elements */ #endif + table->is_table64 = import->u.table.table_type.flags & TABLE64_FLAG; + #if WASM_ENABLE_MULTI_MODULE != 0 *table_linked = table_inst_linked; if (table_inst_linked != NULL) { @@ -736,6 +738,7 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, /* For GC, all elements have already been set to NULL_REF (0) as uninitialized elements */ #endif + table->is_table64 = module->tables[i].table_type.flags & TABLE64_FLAG; table->elem_type = module->tables[i].table_type.elem_type; #if WASM_ENABLE_GC != 0 table->elem_ref_type.elem_ref_type = diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index e46b63cd..c5d09cb6 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -157,7 +157,8 @@ struct WASMMemoryInstance { struct WASMTableInstance { /* The element type */ uint8 elem_type; - uint8 __padding__[7]; + uint8 is_table64; + uint8 __padding__[6]; union { #if WASM_ENABLE_GC != 0 WASMRefType *elem_ref_type; diff --git a/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch b/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch index 5e7afd9d..afd0536d 100644 --- a/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch +++ b/tests/wamr-test-suites/spec-test-script/memory64_ignore_cases.patch @@ -1,5 +1,5 @@ diff --git a/test/core/address.wast b/test/core/address.wast -index 8e52030..de0d0cb 100644 +index 8e52030e..de0d0cb9 100644 --- a/test/core/address.wast +++ b/test/core/address.wast @@ -210,7 +210,7 @@ @@ -12,7 +12,7 @@ index 8e52030..de0d0cb 100644 "(memory 1)" "(func (drop (i32.load offset=4294967296 (i32.const 0))))" diff --git a/test/core/binary.wast b/test/core/binary.wast -index 4090b2c..18f66b4 100644 +index 4090b2cd..18f66b42 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -206,7 +206,7 @@ @@ -70,7 +70,7 @@ index 4090b2c..18f66b4 100644 ;; Start section (module binary diff --git a/test/core/data.wast b/test/core/data.wast -index 4f339be..0b5b3e6 100644 +index 4f339bed..0b5b3e6b 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -306,9 +306,10 @@ @@ -124,7 +124,7 @@ index 4f339be..0b5b3e6 100644 ;; Invalid offsets diff --git a/test/core/elem.wast b/test/core/elem.wast -index 575ecef..dd1106c 100644 +index 575ecef8..dd1106c7 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -562,6 +562,7 @@ @@ -151,7 +151,7 @@ index 575ecef..dd1106c 100644 (assert_return (invoke $module1 "call-9") (i32.const 70)) +;) diff --git a/test/core/global.wast b/test/core/global.wast -index e40a305..8f8f25b 100644 +index e40a305f..8f8f25bb 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -328,10 +328,12 @@ @@ -168,7 +168,7 @@ index e40a305..8f8f25b 100644 (assert_invalid (module (global (import "test" "global-i32") i32) (global i32 (global.get 0) (global.get 0))) diff --git a/test/core/if.wast b/test/core/if.wast -index 2ea45f6..b6dd504 100644 +index 2ea45f6f..b6dd5044 100644 --- a/test/core/if.wast +++ b/test/core/if.wast @@ -527,11 +527,12 @@ @@ -199,7 +199,7 @@ index 2ea45f6..b6dd504 100644 (assert_malformed (module quote diff --git a/test/core/imports.wast b/test/core/imports.wast -index 69f76a0..a3844c6 100644 +index 69f76a0b..a3844c65 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -572,6 +572,7 @@ @@ -219,7 +219,7 @@ index 69f76a0..a3844c6 100644 ;; Syntax errors diff --git a/test/core/linking.wast b/test/core/linking.wast -index 994e0f4..d0bfb5f 100644 +index 994e0f49..d0bfb5f6 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -64,6 +64,7 @@ @@ -376,7 +376,7 @@ index 994e0f4..d0bfb5f 100644 (assert_return (invoke $Ms "get table[0]") (i32.const 0xdead)) +;) diff --git a/test/core/memory.wast b/test/core/memory.wast -index 1dd5b84..497b69f 100644 +index 1dd5b845..497b69fc 100644 --- a/test/core/memory.wast +++ b/test/core/memory.wast @@ -76,17 +76,17 @@ @@ -404,7 +404,7 @@ index 1dd5b84..497b69f 100644 (module diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast -index adb5cb7..590f626 100644 +index adb5cb78..590f6262 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -4,7 +4,8 @@ @@ -417,8 +417,65 @@ index adb5cb7..590f626 100644 (func $g (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 1)) ) +diff --git a/test/core/table.wast b/test/core/table.wast +index 1b6afe9b..45dd1145 100644 +--- a/test/core/table.wast ++++ b/test/core/table.wast +@@ -8,16 +8,20 @@ + (module (table 0 65536 funcref)) + (module (table 0 0xffff_ffff funcref)) + ++(; TODO: wabt not unsupported gc yet + (module (table 1 (ref null func))) + (module (table 1 (ref null extern))) + (module (table 1 (ref null $t)) (type $t (func))) ++;) + + (module (table 0 funcref) (table 0 funcref)) + (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) + ++(; TODO: wabt not unsupported gc yet + (module (table 0 funcref (ref.null func))) + (module (table 1 funcref (ref.null func))) + (module (table 1 (ref null func) (ref.null func))) ++;) + + (assert_invalid (module (elem (i32.const 0))) "unknown table") + (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") +@@ -31,6 +35,7 @@ + "size minimum must not be greater than maximum" + ) + ++(; TODO: wabt not unsupported gc yet + (assert_invalid + (module quote "(table 0x1_0000_0000 funcref)") + "table size must be at most 2^32-1" +@@ -43,6 +48,7 @@ + (module quote "(table 0 0x1_0000_0000 funcref)") + "table size must be at most 2^32-1" + ) ++;) + + ;; Same as above but with i64 index types + +@@ -71,6 +77,7 @@ + (assert_invalid (module (elem (i32.const 0))) "unknown table") + (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") + ++(; TODO: wabt not unsupported gc yet + (assert_invalid + (module (table 1 (ref null func) (i32.const 0))) + "type mismatch" +@@ -159,6 +166,7 @@ + ) + "type mismatch" + ) ++;) + + + ;; Duplicate table identifiers diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast -index 380e84e..f37e745 100644 +index 613fc529..abeca22c 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -14,11 +14,12 @@ @@ -728,8 +785,46 @@ index 380e84e..f37e745 100644 (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_grow.wast b/test/core/table_grow.wast +index e0872d78..6a84f239 100644 +--- a/test/core/table_grow.wast ++++ b/test/core/table_grow.wast +@@ -147,19 +147,20 @@ + ) + (register "grown-table" $Tgt) + (assert_return (invoke $Tgt "grow") (i32.const 1)) ;; now size is 2 +-(module $Tgit1 +- ;; imported table limits should match, because external table size is 2 now +- (table (export "table") (import "grown-table" "table") 2 funcref) +- (func (export "grow") (result i32) (table.grow (ref.null func) (i32.const 1))) +-) +-(register "grown-imported-table" $Tgit1) +-(assert_return (invoke $Tgit1 "grow") (i32.const 2)) ;; now size is 3 +-(module $Tgit2 +- ;; imported table limits should match, because external table size is 3 now +- (import "grown-imported-table" "table" (table 3 funcref)) +- (func (export "size") (result i32) (table.size)) +-) +-(assert_return (invoke $Tgit2 "size") (i32.const 3)) ++;; TODO: No dynnamic linking yet ++;; (module $Tgit1 ++;; ;; imported table limits should match, because external table size is 2 now ++;; (table (export "table") (import "grown-table" "table") 2 funcref) ++;; (func (export "grow") (result i32) (table.grow (ref.null func) (i32.const 1))) ++;; ) ++;; (register "grown-imported-table" $Tgit1) ++;; (assert_return (invoke $Tgit1 "grow") (i32.const 2)) ;; now size is 3 ++;; (module $Tgit2 ++;; ;; imported table limits should match, because external table size is 3 now ++;; (import "grown-imported-table" "table" (table 3 funcref)) ++;; (func (export "size") (result i32) (table.size)) ++;; ) ++;; (assert_return (invoke $Tgit2 "size") (i32.const 3)) + + + ;; Type errors diff --git a/test/core/table_init.wast b/test/core/table_init.wast -index 0b2d26f..bdab6a0 100644 +index 5c3679ab..76782794 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -14,11 +14,12 @@ @@ -749,8 +844,8 @@ index 0b2d26f..bdab6a0 100644 + (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 +73,12 @@ + (table $t2 i64 30 30 funcref) +@@ -73,11 +74,12 @@ (module (type (func (result i32))) ;; type #0 @@ -767,8 +862,8 @@ index 0b2d26f..bdab6a0 100644 + (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 +132,12 @@ + (table $t2 i64 30 30 funcref) +@@ -132,11 +134,12 @@ (module (type (func (result i32))) ;; type #0 @@ -785,8 +880,8 @@ index 0b2d26f..bdab6a0 100644 + (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 +199,12 @@ + (table $t2 i64 30 30 funcref) +@@ -199,11 +202,12 @@ (module (type (func (result i32))) ;; type #0 @@ -803,8 +898,8 @@ index 0b2d26f..bdab6a0 100644 + (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 +258,12 @@ + (table $t2 i64 30 30 funcref) +@@ -258,11 +262,12 @@ (module (type (func (result i32))) ;; type #0 @@ -821,8 +916,8 @@ index 0b2d26f..bdab6a0 100644 + (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 +317,12 @@ + (table $t2 i64 30 30 funcref) +@@ -317,11 +322,12 @@ (module (type (func (result i32))) ;; type #0 @@ -839,9 +934,63 @@ index 0b2d26f..bdab6a0 100644 + (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) + (table $t2 i64 30 30 funcref) +@@ -384,11 +390,12 @@ + + (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 ++ ;; aot mode does not support module linking ++ (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) + (table $t2 i64 30 30 funcref) +@@ -443,11 +450,12 @@ + + (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 ++ ;; aot mode does not support module linking ++ (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) + (table $t2 i64 30 30 funcref) +@@ -502,11 +510,12 @@ + + (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 ++ ;; aot mode does not support module linking ++ (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) + (table $t2 i64 30 30 funcref) diff --git a/test/core/unreached-valid.wast b/test/core/unreached-valid.wast -index b7ebabf..4f2abfb 100644 +index b7ebabfd..4f2abfbf 100644 --- a/test/core/unreached-valid.wast +++ b/test/core/unreached-valid.wast @@ -46,6 +46,7 @@ diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 87e15686..4893bb65 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -375,7 +375,7 @@ function sightglass_test() function setup_wabt() { - WABT_VERSION=1.0.34 + WABT_VERSION=1.0.36 if [ ${WABT_BINARY_RELEASE} == "YES" ]; then echo "download a binary release and install" local WAT2WASM=${WORK_DIR}/wabt/out/gcc/Release/wat2wasm @@ -384,7 +384,7 @@ function setup_wabt() cosmopolitan) ;; linux) - WABT_PLATFORM=ubuntu + WABT_PLATFORM=ubuntu-20.04 ;; darwin) WABT_PLATFORM=macos-12 @@ -502,6 +502,8 @@ function spec_test() # Reset to commit: "Merge remote-tracking branch 'upstream/main' into merge2" git reset --hard 48e69f394869c55b7bbe14ac963c09f4605490b6 git checkout 044d0d2e77bdcbe891f7e0b9dd2ac01d56435f0b -- test/core/elem.wast test/core/data.wast + # Patch table64 extension + git checkout 940398cd4823522a9b36bec4984be4b153dedb81 -- test/core/call_indirect.wast test/core/table.wast test/core/table_copy.wast test/core/table_copy_mixed.wast test/core/table_fill.wast test/core/table_get.wast test/core/table_grow.wast test/core/table_init.wast test/core/table_set.wast test/core/table_size.wast git apply ../../spec-test-script/memory64_ignore_cases.patch || exit 1 elif [[ ${ENABLE_MULTI_MEMORY} == 1 ]]; then echo "checkout spec for multi memory proposal"