Skip to content

Commit 15d1919

Browse files
authored
Enhance GC const initializer expression to support nested struct/array new (#3447)
Only support interpreter now, and fix some issues found in wasm loader. This PR fixes issue #3410 and #3411.
1 parent 403f472 commit 15d1919

3 files changed

Lines changed: 307 additions & 108 deletions

File tree

core/iwasm/interpreter/wasm.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,13 @@ typedef union WASMValue {
250250
#endif /* end of WASM_VALUE_DEFINED */
251251

252252
typedef struct WASMStructNewInitValues {
253-
uint8 type_idx;
253+
uint32 type_idx;
254254
uint32 count;
255255
WASMValue fields[1];
256256
} WASMStructNewInitValues;
257257

258258
typedef struct WASMArrayNewInitValues {
259-
uint8 type_idx;
259+
uint32 type_idx;
260260
uint32 length;
261261
WASMValue elem_data[1];
262262
} WASMArrayNewInitValues;

core/iwasm/interpreter/wasm_loader.c

Lines changed: 116 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,8 @@ push_const_expr_stack(ConstExprContext *ctx, uint8 flag, uint8 type,
501501
error_buf, error_buf_size))) {
502502
goto fail;
503503
}
504+
bh_memcpy_s(ctx->stack, (ctx->size + 4) * (uint32)sizeof(InitValue),
505+
ctx->data, ctx->size * (uint32)sizeof(InitValue));
504506
}
505507
ctx->size += 4;
506508
}
@@ -523,6 +525,71 @@ push_const_expr_stack(ConstExprContext *ctx, uint8 flag, uint8 type,
523525
return false;
524526
}
525527

528+
#if WASM_ENABLE_GC != 0
529+
static void
530+
destroy_init_expr_data_recursive(WASMModule *module, void *data)
531+
{
532+
WASMStructNewInitValues *struct_init_values =
533+
(WASMStructNewInitValues *)data;
534+
WASMArrayNewInitValues *array_init_values = (WASMArrayNewInitValues *)data;
535+
WASMType *wasm_type;
536+
uint32 i;
537+
538+
if (!data)
539+
return;
540+
541+
wasm_type = module->types[struct_init_values->type_idx];
542+
543+
/* The data can only be type of `WASMStructNewInitValues *`
544+
or `WASMArrayNewInitValues *` */
545+
bh_assert(wasm_type->type_flag == WASM_TYPE_STRUCT
546+
|| wasm_type->type_flag == WASM_TYPE_ARRAY);
547+
548+
if (wasm_type->type_flag == WASM_TYPE_STRUCT) {
549+
WASMStructType *struct_type = (WASMStructType *)wasm_type;
550+
WASMRefTypeMap *ref_type_map = struct_type->ref_type_maps;
551+
WASMRefType *ref_type;
552+
uint8 field_type;
553+
554+
for (i = 0; i < struct_init_values->count; i++) {
555+
field_type = struct_type->fields[i].field_type;
556+
if (wasm_is_type_multi_byte_type(field_type))
557+
ref_type = ref_type_map->ref_type;
558+
else
559+
ref_type = NULL;
560+
if (wasm_reftype_is_subtype_of(field_type, ref_type,
561+
REF_TYPE_STRUCTREF, NULL,
562+
module->types, module->type_count)
563+
|| wasm_reftype_is_subtype_of(
564+
field_type, ref_type, REF_TYPE_ARRAYREF, NULL,
565+
module->types, module->type_count)) {
566+
destroy_init_expr_data_recursive(
567+
module, struct_init_values->fields[i].data);
568+
}
569+
}
570+
}
571+
else if (wasm_type->type_flag == WASM_TYPE_ARRAY) {
572+
WASMArrayType *array_type = (WASMArrayType *)wasm_type;
573+
WASMRefType *elem_ref_type = array_type->elem_ref_type;
574+
uint8 elem_type = array_type->elem_type;
575+
576+
for (i = 0; i < array_init_values->length; i++) {
577+
if (wasm_reftype_is_subtype_of(elem_type, elem_ref_type,
578+
REF_TYPE_STRUCTREF, NULL,
579+
module->types, module->type_count)
580+
|| wasm_reftype_is_subtype_of(
581+
elem_type, elem_ref_type, REF_TYPE_ARRAYREF, NULL,
582+
module->types, module->type_count)) {
583+
destroy_init_expr_data_recursive(
584+
module, array_init_values->elem_data[i].data);
585+
}
586+
}
587+
}
588+
589+
wasm_runtime_free(data);
590+
}
591+
#endif
592+
526593
static bool
527594
pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type,
528595
#if WASM_ENABLE_GC != 0
@@ -554,17 +621,6 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type,
554621
" but got other");
555622
goto fail;
556623
}
557-
558-
if ((ctx->sp != 0) && (cur_value->flag == WASM_OP_GC_PREFIX)
559-
&& (cur_value->gc_opcode != WASM_OP_REF_I31)) {
560-
/* To reduce complexity, we don't allow initialize struct fields/array
561-
* element with references, so struct/array must be at the bottom of the
562-
* init value stack */
563-
set_error_buf(
564-
error_buf, error_buf_size,
565-
"struct or array as field is not supported in constant expr");
566-
goto fail;
567-
}
568624
#endif
569625

570626
if (p_flag)
@@ -584,7 +640,7 @@ pop_const_expr_stack(ConstExprContext *ctx, uint8 *p_flag, uint8 type,
584640
&& (cur_value->gc_opcode == WASM_OP_STRUCT_NEW
585641
|| cur_value->gc_opcode == WASM_OP_ARRAY_NEW
586642
|| cur_value->gc_opcode == WASM_OP_ARRAY_NEW_FIXED)) {
587-
wasm_runtime_free(cur_value->value.data);
643+
destroy_init_expr_data_recursive(ctx->module, cur_value->value.data);
588644
}
589645
return false;
590646
#endif
@@ -601,7 +657,8 @@ destroy_const_expr_stack(ConstExprContext *ctx)
601657
&& (ctx->stack[i].gc_opcode == WASM_OP_STRUCT_NEW
602658
|| ctx->stack[i].gc_opcode == WASM_OP_ARRAY_NEW
603659
|| ctx->stack[i].gc_opcode == WASM_OP_ARRAY_NEW_FIXED)) {
604-
wasm_runtime_free(ctx->stack[i].value.data);
660+
destroy_init_expr_data_recursive(ctx->module,
661+
ctx->stack[i].value.data);
605662
}
606663
}
607664
#endif
@@ -613,12 +670,12 @@ destroy_const_expr_stack(ConstExprContext *ctx)
613670

614671
#if WASM_ENABLE_GC != 0
615672
static void
616-
destroy_init_expr(InitializerExpression *expr)
673+
destroy_init_expr(WASMModule *module, InitializerExpression *expr)
617674
{
618675
if (expr->init_expr_type == INIT_EXPR_TYPE_STRUCT_NEW
619676
|| expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW
620677
|| expr->init_expr_type == INIT_EXPR_TYPE_ARRAY_NEW_FIXED) {
621-
wasm_runtime_free(expr->u.data);
678+
destroy_init_expr_data_recursive(module, expr->u.data);
622679
}
623680
}
624681
#endif /* end of WASM_ENABLE_GC != 0 */
@@ -941,6 +998,7 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
941998
error_buf, error_buf_size))) {
942999
goto fail;
9431000
}
1001+
struct_init_values->type_idx = type_idx;
9441002
struct_init_values->count = field_count;
9451003

9461004
for (i = field_count; i > 0; i--) {
@@ -963,7 +1021,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
9631021
field_ref_type, NULL,
9641022
&struct_init_values->fields[field_idx],
9651023
error_buf, error_buf_size)) {
966-
wasm_runtime_free(struct_init_values);
1024+
destroy_init_expr_data_recursive(
1025+
module, struct_init_values);
9671026
goto fail;
9681027
}
9691028
}
@@ -975,7 +1034,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
9751034
&const_expr_ctx, flag, cur_ref_type.ref_type,
9761035
&cur_ref_type, (uint8)opcode1, &cur_value,
9771036
error_buf, error_buf_size)) {
978-
wasm_runtime_free(struct_init_values);
1037+
destroy_init_expr_data_recursive(
1038+
module, struct_init_values);
9791039
goto fail;
9801040
}
9811041
break;
@@ -1059,7 +1119,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
10591119
&const_expr_ctx, NULL, VALUE_TYPE_I32,
10601120
NULL, NULL, &len_val, error_buf,
10611121
error_buf_size)) {
1062-
wasm_runtime_free(array_init_values);
1122+
destroy_init_expr_data_recursive(
1123+
module, array_init_values);
10631124
goto fail;
10641125
}
10651126
array_init_values->length = len_val.i32;
@@ -1069,7 +1130,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
10691130
elem_ref_type, NULL,
10701131
&array_init_values->elem_data[0],
10711132
error_buf, error_buf_size)) {
1072-
wasm_runtime_free(array_init_values);
1133+
destroy_init_expr_data_recursive(
1134+
module, array_init_values);
10731135
goto fail;
10741136
}
10751137

@@ -1100,7 +1162,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
11001162
&array_init_values
11011163
->elem_data[i - 1],
11021164
error_buf, error_buf_size)) {
1103-
wasm_runtime_free(array_init_values);
1165+
destroy_init_expr_data_recursive(
1166+
module, array_init_values);
11041167
goto fail;
11051168
}
11061169
}
@@ -1133,7 +1196,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
11331196
&cur_ref_type, (uint8)opcode1, &cur_value,
11341197
error_buf, error_buf_size)) {
11351198
if (array_init_values) {
1136-
wasm_runtime_free(array_init_values);
1199+
destroy_init_expr_data_recursive(
1200+
module, array_init_values);
11371201
}
11381202
goto fail;
11391203
}
@@ -6669,14 +6733,6 @@ wasm_loader_unload(WASMModule *module)
66696733
}
66706734
#endif
66716735

6672-
if (module->types) {
6673-
for (i = 0; i < module->type_count; i++) {
6674-
if (module->types[i])
6675-
destroy_wasm_type(module->types[i]);
6676-
}
6677-
wasm_runtime_free(module->types);
6678-
}
6679-
66806736
if (module->imports)
66816737
wasm_runtime_free(module->imports);
66826738

@@ -6718,7 +6774,7 @@ wasm_loader_unload(WASMModule *module)
67186774
if (module->tables) {
67196775
#if WASM_ENABLE_GC != 0
67206776
for (i = 0; i < module->table_count; i++) {
6721-
destroy_init_expr(&module->tables[i].init_expr);
6777+
destroy_init_expr(module, &module->tables[i].init_expr);
67226778
}
67236779
#endif
67246780
wasm_runtime_free(module->tables);
@@ -6730,7 +6786,7 @@ wasm_loader_unload(WASMModule *module)
67306786
if (module->globals) {
67316787
#if WASM_ENABLE_GC != 0
67326788
for (i = 0; i < module->global_count; i++) {
6733-
destroy_init_expr(&module->globals[i].init_expr);
6789+
destroy_init_expr(module, &module->globals[i].init_expr);
67346790
}
67356791
#endif
67366792
wasm_runtime_free(module->globals);
@@ -6756,7 +6812,7 @@ wasm_loader_unload(WASMModule *module)
67566812
uint32 j;
67576813
for (j = 0; j < module->table_segments[i].value_count; j++) {
67586814
destroy_init_expr(
6759-
&module->table_segments[i].init_values[j]);
6815+
module, &module->table_segments[i].init_values[j]);
67606816
}
67616817
#endif
67626818
wasm_runtime_free(module->table_segments[i].init_values);
@@ -6773,6 +6829,14 @@ wasm_loader_unload(WASMModule *module)
67736829
wasm_runtime_free(module->data_segments);
67746830
}
67756831

6832+
if (module->types) {
6833+
for (i = 0; i < module->type_count; i++) {
6834+
if (module->types[i])
6835+
destroy_wasm_type(module->types[i]);
6836+
}
6837+
wasm_runtime_free(module->types);
6838+
}
6839+
67766840
if (module->const_str_list) {
67776841
StringNode *node = module->const_str_list, *node_next;
67786842
while (node) {
@@ -11654,12 +11718,29 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
1165411718

1165511719
case WASM_OP_RETURN:
1165611720
{
11721+
WASMFuncType *func_type = func->func_type;
1165711722
int32 idx;
1165811723
uint8 ret_type;
11659-
for (idx = (int32)func->func_type->result_count - 1; idx >= 0;
11724+
11725+
#if WASM_ENABLE_GC != 0
11726+
uint32 j = func_type->ref_type_map_count - 1;
11727+
#endif
11728+
for (idx = (int32)func_type->result_count - 1; idx >= 0;
1166011729
idx--) {
11661-
ret_type = *(func->func_type->types
11662-
+ func->func_type->param_count + idx);
11730+
ret_type =
11731+
*(func_type->types + func_type->param_count + idx);
11732+
#if WASM_ENABLE_GC != 0
11733+
if (wasm_is_type_multi_byte_type(ret_type)) {
11734+
WASMRefType *ref_type =
11735+
func_type->ref_type_maps[j].ref_type;
11736+
bh_assert(func_type->ref_type_maps[j].index
11737+
== func_type->param_count + idx);
11738+
bh_memcpy_s(&wasm_ref_type, sizeof(WASMRefType),
11739+
ref_type,
11740+
wasm_reftype_struct_size(ref_type));
11741+
j--;
11742+
}
11743+
#endif
1166311744
#if WASM_ENABLE_FAST_INTERP != 0
1166411745
/* emit the offset after return opcode */
1166511746
POP_OFFSET_TYPE(ret_type);

0 commit comments

Comments
 (0)