Support extended constant expressions (#4432)

* implement extended const expr (#4318)
* add a toggle to enable extended const on wamrc (#4412)
This commit is contained in:
TianlongLiang
2025-07-07 13:34:02 +08:00
committed by GitHub
parent be33a40ba7
commit 7d05dbc988
28 changed files with 1734 additions and 379 deletions

View File

@ -968,6 +968,35 @@ fail:
return false;
}
#if WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0
static void
destroy_init_expr(InitializerExpression *expr)
{
#if WASM_ENABLE_GC != 0
if (expr->init_expr_type == INIT_EXPR_TYPE_STRUCT_NEW
|| expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW
|| expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) {
wasm_runtime_free(expr->u.unary.v.data);
}
#endif
#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0
// free left expr and right expr for binary oprand
if (!is_expr_binary_op(expr->init_expr_type)) {
return;
}
if (expr->u.binary.l_expr) {
destroy_init_expr_recursive(expr->u.binary.l_expr);
}
if (expr->u.binary.r_expr) {
destroy_init_expr_recursive(expr->u.binary.r_expr);
}
expr->u.binary.l_expr = expr->u.binary.r_expr = NULL;
#endif
}
#endif /* end of WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0 \
*/
static void
destroy_import_memories(AOTImportMemory *import_memories)
{
@ -993,6 +1022,10 @@ destroy_mem_init_data_list(AOTModule *module, AOTMemInitData **data_list,
/* If the module owns the binary data, free the bytes buffer */
if (module->is_binary_freeable && data_list[i]->bytes)
wasm_runtime_free(data_list[i]->bytes);
#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0
destroy_init_expr(&data_list[i]->offset);
#endif
/* Free the data segment structure itself */
wasm_runtime_free(data_list[i]);
}
@ -1043,11 +1076,11 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
uint32 byte_count;
uint32 is_passive;
uint32 memory_index;
InitializerExpression init_value;
InitializerExpression offset_expr;
read_uint32(buf, buf_end, is_passive);
read_uint32(buf, buf_end, memory_index);
if (!load_init_expr(&buf, buf_end, module, &init_value, error_buf,
if (!load_init_expr(&buf, buf_end, module, &offset_expr, error_buf,
error_buf_size)) {
return false;
}
@ -1062,8 +1095,7 @@ load_mem_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
data_list[i]->is_passive = (bool)is_passive;
data_list[i]->memory_index = memory_index;
#endif
data_list[i]->offset.init_expr_type = init_value.init_expr_type;
data_list[i]->offset.u = init_value.u;
data_list[i]->offset = offset_expr;
data_list[i]->byte_count = byte_count;
data_list[i]->bytes = NULL;
/* If the module owns the binary data, clone the bytes buffer */
@ -1148,18 +1180,6 @@ fail:
return false;
}
#if WASM_ENABLE_GC != 0
static void
destroy_init_expr(InitializerExpression *expr)
{
if (expr->init_expr_type == INIT_EXPR_TYPE_STRUCT_NEW
|| expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW
|| expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) {
wasm_runtime_free(expr->u.data);
}
}
#endif /* end of WASM_ENABLE_GC != 0 */
static void
destroy_import_tables(AOTImportTable *import_tables)
{
@ -1183,6 +1203,9 @@ destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count)
for (j = 0; j < data_list[i]->value_count; j++) {
destroy_init_expr(&data_list[i]->init_values[j]);
}
#endif
#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0
destroy_init_expr(&data_list[i]->offset);
#endif
wasm_runtime_free(data_list[i]);
}
@ -1208,34 +1231,34 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
break;
case INIT_EXPR_TYPE_I32_CONST:
case INIT_EXPR_TYPE_F32_CONST:
read_uint32(buf, buf_end, expr->u.i32);
read_uint32(buf, buf_end, expr->u.unary.v.i32);
break;
case INIT_EXPR_TYPE_I64_CONST:
case INIT_EXPR_TYPE_F64_CONST:
read_uint64(buf, buf_end, expr->u.i64);
read_uint64(buf, buf_end, expr->u.unary.v.i64);
break;
case INIT_EXPR_TYPE_V128_CONST:
i64x2 = (uint64 *)expr->u.v128.i64x2;
i64x2 = (uint64 *)expr->u.unary.v.v128.i64x2;
CHECK_BUF(buf, buf_end, sizeof(uint64) * 2);
wasm_runtime_read_v128(buf, &i64x2[0], &i64x2[1]);
buf += sizeof(uint64) * 2;
break;
case INIT_EXPR_TYPE_GET_GLOBAL:
read_uint32(buf, buf_end, expr->u.global_index);
read_uint32(buf, buf_end, expr->u.unary.v.global_index);
break;
/* INIT_EXPR_TYPE_FUNCREF_CONST can be used when
both reference types and GC are disabled */
case INIT_EXPR_TYPE_FUNCREF_CONST:
read_uint32(buf, buf_end, expr->u.ref_index);
read_uint32(buf, buf_end, expr->u.unary.v.ref_index);
break;
#if WASM_ENABLE_GC != 0 || WASM_ENABLE_REF_TYPES != 0
case INIT_EXPR_TYPE_REFNULL_CONST:
read_uint32(buf, buf_end, expr->u.ref_index);
read_uint32(buf, buf_end, expr->u.unary.v.ref_index);
break;
#endif /* end of WASM_ENABLE_GC != 0 || WASM_ENABLE_REF_TYPES != 0 */
#if WASM_ENABLE_GC != 0
case INIT_EXPR_TYPE_I31_NEW:
read_uint32(buf, buf_end, expr->u.i32);
read_uint32(buf, buf_end, expr->u.unary.v.i32);
break;
case INIT_EXPR_TYPE_STRUCT_NEW:
{
@ -1256,7 +1279,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
free_if_fail = true;
init_values->count = field_count;
init_values->type_idx = type_idx;
expr->u.data = init_values;
expr->u.unary.v.data = init_values;
if (type_idx >= module->type_count) {
set_error_buf(error_buf, error_buf_size,
@ -1294,7 +1317,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
break;
}
case INIT_EXPR_TYPE_STRUCT_NEW_DEFAULT:
read_uint32(buf, buf_end, expr->u.type_index);
read_uint32(buf, buf_end, expr->u.unary.v.type_index);
break;
case INIT_EXPR_TYPE_ARRAY_NEW:
case INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT:
@ -1317,8 +1340,8 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
}
if (init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_DEFAULT) {
expr->u.array_new_default.type_index = type_idx;
expr->u.array_new_default.length = length;
expr->u.unary.v.array_new_default.type_index = type_idx;
expr->u.unary.v.array_new_default.length = length;
}
else {
uint32 i, elem_size, elem_data_count;
@ -1329,7 +1352,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
return false;
}
free_if_fail = true;
expr->u.data = init_values;
expr->u.unary.v.data = init_values;
init_values->type_idx = type_idx;
init_values->length = length;
@ -1357,6 +1380,34 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
break;
}
#endif /* end of WASM_ENABLE_GC != 0 */
#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0
case INIT_EXPR_TYPE_I32_ADD:
case INIT_EXPR_TYPE_I32_SUB:
case INIT_EXPR_TYPE_I32_MUL:
case INIT_EXPR_TYPE_I64_ADD:
case INIT_EXPR_TYPE_I64_SUB:
case INIT_EXPR_TYPE_I64_MUL:
{
expr->u.binary.l_expr = expr->u.binary.r_expr = NULL;
if (!(expr->u.binary.l_expr =
loader_malloc(sizeof(InitializerExpression), error_buf,
error_buf_size))) {
goto fail;
}
if (!load_init_expr(&buf, buf_end, module, expr->u.binary.l_expr,
error_buf, error_buf_size))
goto fail;
if (!(expr->u.binary.r_expr =
loader_malloc(sizeof(InitializerExpression), error_buf,
error_buf_size))) {
goto fail;
}
if (!load_init_expr(&buf, buf_end, module, expr->u.binary.r_expr,
error_buf, error_buf_size))
goto fail;
break;
}
#endif /* end of WASM_ENABLE_EXTENDED_CONST_EXPR != 0 */
default:
set_error_buf(error_buf, error_buf_size, "invalid init expr type.");
return false;
@ -1369,10 +1420,13 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
fail:
#if WASM_ENABLE_GC != 0
if (free_if_fail) {
wasm_runtime_free(expr->u.data);
wasm_runtime_free(expr->u.unary.v.data);
}
#else
(void)free_if_fail;
#endif
#if WASM_ENABLE_EXTENDED_CONST_EXPR != 0
destroy_init_expr(expr);
#endif
return false;
}
@ -1535,14 +1589,16 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
/* Create each table data segment */
for (i = 0; i < module->table_init_data_count; i++) {
uint32 mode, elem_type;
uint32 table_index, init_expr_type, value_count;
uint64 init_expr_value, size1;
uint32 table_index, value_count;
uint64 size1;
InitializerExpression offset_expr;
read_uint32(buf, buf_end, mode);
read_uint32(buf, buf_end, elem_type);
read_uint32(buf, buf_end, table_index);
read_uint32(buf, buf_end, init_expr_type);
read_uint64(buf, buf_end, init_expr_value);
if (!load_init_expr(&buf, buf_end, module, &offset_expr, error_buf,
error_buf_size))
return false;
#if WASM_ENABLE_GC != 0
if (wasm_is_type_multi_byte_type(elem_type)) {
uint16 ref_type, nullable;
@ -1588,8 +1644,7 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
}
}
#endif
data_list[i]->offset.init_expr_type = (uint8)init_expr_type;
data_list[i]->offset.u.i64 = (int64)init_expr_value;
data_list[i]->offset = offset_expr;
data_list[i]->value_count = value_count;
for (j = 0; j < data_list[i]->value_count; j++) {
if (!load_init_expr(&buf, buf_end, module,
@ -4500,7 +4555,7 @@ aot_unload(AOTModule *module)
destroy_import_globals(module->import_globals);
if (module->globals) {
#if WASM_ENABLE_GC != 0
#if WASM_ENABLE_GC != 0 || WASM_ENABLE_EXTENDED_CONST_EXPR != 0
uint32 i;
for (i = 0; i < module->global_count; i++) {
destroy_init_expr(&module->globals[i].init_expr);