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

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