Support table64 extension in classic-interp and AOT running modes (#3811)

Add table64 extension(in Memory64 proposal) support in classic-interp
and AOT running modes, currently still use uint32 to represent table's
initial and maximum size to keep AOT ABI unchanged.
This commit is contained in:
TianlongLiang
2024-10-11 21:14:56 +08:00
committed by GitHub
parent 2b5e2d9c2c
commit 36d438051e
16 changed files with 922 additions and 175 deletions

View File

@ -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)) {

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 { \

View File

@ -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.");

View File

@ -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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_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, &param_values[4],
tbl_idx)) {
goto fail;
}
/* "" means return void */
if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5,

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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 */

View File

@ -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 =

View File

@ -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;