Explorar o código

Implement AOT file emitting and loading for GC (#2366)

Huang Qi %!s(int64=2) %!d(string=hai) anos
pai
achega
067a86a774

+ 2 - 4
.github/workflows/compilation_on_android_ubuntu.yml

@@ -64,7 +64,7 @@ env:
   SIMD_TEST_OPTIONS: "-s spec -b -S -P"
   THREADS_TEST_OPTIONS: "-s spec -b -p -P"
   X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P"
-  WASI_TEST_OPTIONS: "-s wasi_certification -w"
+  WASI_TEST_OPTIONS: "-s wasi_certification -w -S"
   GC_TEST_OPTIONS: "-s spec -G -b -P"
 
 jobs:
@@ -473,9 +473,7 @@ jobs:
             test_option: $MULTI_MODULES_TEST_OPTIONS
           - running_mode: "multi-tier-jit"
             test_option: $SIMD_TEST_OPTIONS
-          # aot and jit don't support GC
-          - running_mode: "aot"
-            test_option: $GC_TEST_OPTIONS
+          # jit don't support GC
           - running_mode: "jit"
             test_option: $GC_TEST_OPTIONS
           - running_mode: "multi-tier-jit"

+ 2 - 1
.github/workflows/compilation_on_sgx.yml

@@ -48,7 +48,8 @@ concurrency:
   cancel-in-progress: true
 
 env:
-  AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
+  # ref types enabled in wamrc by default, so we need to enable it for iwasm in AOT mode
+  AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0 -DWAMR_BUILD_REF_TYPES=1"
   CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
   FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
   FAST_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=1"

+ 288 - 12
core/iwasm/aot/aot_loader.c

@@ -515,6 +515,21 @@ check_feature_flags(char *error_buf, uint32 error_buf_size,
     return true;
 }
 
+#if WASM_ENABLE_GC != 0
+static WASMRefType *
+reftype_set_insert(HashMap *ref_type_set, const WASMRefType *ref_type,
+                   char *error_buf, uint32 error_buf_size)
+{
+    WASMRefType *ret = wasm_reftype_set_insert(ref_type_set, ref_type);
+
+    if (!ret) {
+        set_error_buf(error_buf, error_buf_size,
+                      "insert ref type to hash set failed");
+    }
+    return ret;
+}
+#endif
+
 static bool
 load_target_info_section(const uint8 *buf, const uint8 *buf_end,
                          AOTModule *module, char *error_buf,
@@ -1067,6 +1082,9 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
 {
     const uint8 *buf = *p_buf;
     AOTTableInitData **data_list;
+#if WASM_ENABLE_GC != 0
+    WASMRefType reftype;
+#endif
     uint64 size;
     uint32 i;
 
@@ -1088,6 +1106,15 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
         read_uint32(buf, buf_end, table_index);
         read_uint32(buf, buf_end, init_expr_type);
         read_uint64(buf, buf_end, init_expr_value);
+#if WASM_ENABLE_GC != 0
+        read_uint32(buf, buf_end, reftype.ref_ht_common.ref_type);
+        read_uint16(buf, buf_end, reftype.ref_ht_common.heap_type);
+        read_uint16(buf, buf_end, reftype.ref_ht_common.nullable);
+#else
+        /* Skip 8 byte for ref type info */
+        buf += 8;
+#endif
+
         read_uint32(buf, buf_end, func_index_count);
 
         size1 = sizeof(uintptr_t) * (uint64)func_index_count;
@@ -1100,6 +1127,16 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
         data_list[i]->elem_type = elem_type;
         data_list[i]->is_dropped = false;
         data_list[i]->table_index = table_index;
+#if WASM_ENABLE_GC != 0
+        if (wasm_is_reftype_htref_nullable(reftype.ref_type)
+            || wasm_is_reftype_htref_non_nullable(reftype.ref_type)) {
+            if (!(data_list[i]->elem_ref_type =
+                      reftype_set_insert(module->ref_type_set, &reftype,
+                                         error_buf, error_buf_size))) {
+                goto fail;
+            }
+        }
+#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]->func_index_count = func_index_count;
@@ -1148,12 +1185,223 @@ static void
 destroy_types(AOTType **types, uint32 count)
 {
     uint32 i;
-    for (i = 0; i < count; i++)
-        if (types[i])
+    for (i = 0; i < count; i++) {
+
+        if (types[i]) {
+#if WASM_ENABLE_GC != 0
+            if (types[i]->type_flag == WASM_TYPE_FUNC) {
+                AOTFuncType *func_type = (AOTFuncType *)types[i];
+                if (func_type->ref_type_maps != NULL) {
+                    bh_assert(func_type->ref_type_map_count > 0);
+                    wasm_runtime_free(func_type->ref_type_maps);
+                }
+            }
+            else if (types[i]->type_flag == WASM_TYPE_STRUCT) {
+                AOTStructType *struct_type = (AOTStructType *)types[i];
+                if (struct_type->ref_type_maps != NULL) {
+                    bh_assert(func_type->ref_type_map_count > 0);
+                    wasm_runtime_free(struct_type->ref_type_maps);
+                }
+            }
+#endif
             wasm_runtime_free(types[i]);
+        }
+    }
     wasm_runtime_free(types);
 }
 
+#if WASM_ENABLE_GC != 0
+static bool
+load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
+           char *error_buf, uint32 error_buf_size)
+{
+    const uint8 *buf = *p_buf;
+    AOTType **types;
+    uint64 size;
+    uint32 i, j;
+    uint32 type_flag, param_cell_num, ret_cell_num;
+    uint16 param_count, result_count, ref_type_map_count;
+    bool is_sub_final;
+    uint32 parent_type_idx;
+
+    /* Allocate memory */
+    size = sizeof(AOTFuncType *) * (uint64)module->type_count;
+    if (!(types = loader_malloc(size, error_buf, error_buf_size))) {
+        return false;
+    }
+
+    module->types = types;
+
+    /* Create each type */
+    for (i = 0; i < module->type_count; i++) {
+
+        buf = align_ptr(buf, 4);
+
+        read_uint16(buf, buf_end, type_flag);
+        if (type_flag == WASM_TYPE_FUNC) {
+            AOTFuncType *func_type;
+            /* Read base type info */
+            read_uint16(buf, buf_end, is_sub_final);
+            read_uint32(buf, buf_end, parent_type_idx);
+
+            /* Read param count */
+            read_uint16(buf, buf_end, param_count);
+            /* Read result count */
+            read_uint16(buf, buf_end, result_count);
+            /* Read ref_type_map_count */
+            read_uint16(buf, buf_end, ref_type_map_count);
+
+            func_type =
+                loader_malloc(sizeof(AOTFuncType) + param_count + result_count,
+                              error_buf, error_buf_size);
+
+            if (!func_type) {
+                goto fail;
+            }
+
+            types[i] = (AOTType *)func_type;
+
+            func_type->base_type.type_flag = type_flag;
+            func_type->base_type.is_sub_final = is_sub_final;
+            func_type->base_type.parent_type_idx = parent_type_idx;
+            func_type->param_count = param_count;
+            func_type->result_count = result_count;
+
+            /* Read types of params */
+            read_byte_array(buf, buf_end, func_type->types,
+                            func_type->param_count + func_type->result_count);
+
+            func_type->ref_type_map_count = ref_type_map_count;
+
+            param_cell_num = wasm_get_cell_num(func_type->types, param_count);
+            ret_cell_num =
+                wasm_get_cell_num(func_type->types + param_count, result_count);
+            if (param_cell_num > UINT16_MAX || ret_cell_num > UINT16_MAX) {
+                set_error_buf(error_buf, error_buf_size,
+                              "param count or result count too large");
+                goto fail;
+            }
+
+            func_type->param_cell_num = param_cell_num;
+            func_type->ret_cell_num = ret_cell_num;
+
+            if (ref_type_map_count == 0) {
+                continue;
+            }
+
+            bh_assert(func_type->ref_type_map_count
+                      <= func_type->param_count + func_type->result_count);
+
+            if (!(func_type->ref_type_maps = loader_malloc(
+                      sizeof(WASMRefTypeMap) * func_type->ref_type_map_count,
+                      error_buf, error_buf_size))) {
+                goto fail;
+            }
+
+            for (j = 0; j < func_type->ref_type_map_count; j++) {
+                read_uint8(buf, buf_end,
+                           func_type->ref_type_maps[j]
+                               .ref_type->ref_ht_common.ref_type);
+                read_uint8(buf, buf_end,
+                           func_type->ref_type_maps[j]
+                               .ref_type->ref_ht_common.nullable);
+                read_uint32(buf, buf_end,
+                            func_type->ref_type_maps[j]
+                                .ref_type->ref_ht_common.heap_type);
+            }
+        }
+        else if (type_flag == WASM_TYPE_STRUCT) {
+            AOTStructType *struct_type;
+            uint16 field_count;
+            read_uint16(buf, buf_end, field_count);
+            struct_type =
+                loader_malloc(sizeof(AOTStructType)
+                                  + field_count * sizeof(WASMStructFieldType),
+                              error_buf, error_buf_size);
+            if (!struct_type) {
+                goto fail;
+            }
+
+            types[i] = (AOTType *)struct_type;
+
+            struct_type->base_type.type_flag = type_flag;
+            struct_type->field_count = field_count;
+
+            /* Read types of fields */
+            for (j = 0; j < field_count; j++) {
+                read_uint16(buf, buf_end, struct_type->fields[j].field_flags);
+                read_uint8(buf, buf_end, struct_type->fields[j].field_type);
+            }
+            /* Read ref_type_map_count */
+            read_uint16(buf, buf_end, struct_type->ref_type_map_count);
+
+            if (struct_type->ref_type_map_count == 0) {
+                continue;
+            }
+
+            bh_assert(struct_type->ref_type_map_count <= field_count);
+
+            if (!(struct_type->ref_type_maps = loader_malloc(
+                      sizeof(WASMRefTypeMap) * struct_type->ref_type_map_count,
+                      error_buf, error_buf_size))) {
+                goto fail;
+            }
+
+            for (j = 0; j < struct_type->ref_type_map_count; j++) {
+                read_uint16(buf, buf_end, struct_type->ref_type_maps[j].index);
+                read_uint8(buf, buf_end,
+                           struct_type->ref_type_maps[j]
+                               .ref_type->ref_ht_common.ref_type);
+                read_uint8(buf, buf_end,
+                           struct_type->ref_type_maps[j]
+                               .ref_type->ref_ht_common.nullable);
+                read_uint32(buf, buf_end,
+                            struct_type->ref_type_maps[j]
+                                .ref_type->ref_ht_common.heap_type);
+            }
+        }
+        else if (type_flag == WASM_TYPE_ARRAY) {
+            AOTArrayType *array_type;
+
+            array_type =
+                loader_malloc(sizeof(AOTArrayType), error_buf, error_buf_size);
+
+            if (!array_type) {
+                goto fail;
+            }
+
+            types[i] = (AOTType *)array_type;
+
+            array_type->base_type.type_flag = type_flag;
+            read_uint16(buf, buf_end, array_type->elem_flags);
+            read_uint8(buf, buf_end, array_type->elem_type);
+        }
+        else {
+            set_error_buf_v(error_buf, error_buf_size,
+                            "invalid type flag: %" PRIu32, type_flag);
+            goto fail;
+        }
+    }
+
+    if (module->type_count) {
+        if (!(module->rtt_types = loader_malloc((uint64)sizeof(WASMRttType *)
+                                                    * module->type_count,
+                                                error_buf, error_buf_size))) {
+            goto fail;
+        }
+    }
+
+    *p_buf = buf;
+    return true;
+
+fail:
+    /* Destroy all types */
+    destroy_types(types, module->type_count);
+    wasm_runtime_free(types);
+    module->types = NULL;
+    return false;
+}
+#else
 static bool
 load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
            char *error_buf, uint32 error_buf_size)
@@ -1173,18 +1421,18 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
 
     /* Create each function type */
     for (i = 0; i < module->type_count; i++) {
+        uint32 type_flag;
         uint32 param_count, result_count;
         uint32 param_cell_num, ret_cell_num;
         uint64 size1;
 
+        buf = align_ptr(buf, 4);
+        read_uint16(buf, buf_end, type_flag);
+        /* Dummy read to ignore the is_sub_final and parent_type_idx */
+        read_uint16(buf, buf_end, param_count);
         read_uint32(buf, buf_end, param_count);
-        read_uint32(buf, buf_end, result_count);
-
-        if (param_count > UINT16_MAX || result_count > UINT16_MAX) {
-            set_error_buf(error_buf, error_buf_size,
-                          "param count or result count too large");
-            return false;
-        }
+        read_uint16(buf, buf_end, param_count);
+        read_uint16(buf, buf_end, result_count);
 
         size1 = (uint64)param_count + (uint64)result_count;
         size = offsetof(AOTFuncType, types) + size1;
@@ -1214,10 +1462,11 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
 fail:
     return false;
 }
+#endif /* end of WASM_ENABLE_GC != 0 */
 
 static bool
-load_func_type_info(const uint8 **p_buf, const uint8 *buf_end,
-                    AOTModule *module, char *error_buf, uint32 error_buf_size)
+load_type_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
+               char *error_buf, uint32 error_buf_size)
 {
     const uint8 *buf = *p_buf;
 
@@ -1599,7 +1848,7 @@ load_init_data_section(const uint8 *buf, const uint8 *buf_end,
 
     if (!load_memory_info(&p, p_end, module, error_buf, error_buf_size)
         || !load_table_info(&p, p_end, module, error_buf, error_buf_size)
-        || !load_func_type_info(&p, p_end, module, error_buf, error_buf_size)
+        || !load_type_info(&p, p_end, module, error_buf, error_buf_size)
         || !load_import_global_info(&p, p_end, module, is_load_from_file_buf,
                                     error_buf, error_buf_size)
         || !load_global_info(&p, p_end, module, error_buf, error_buf_size)
@@ -2933,7 +3182,27 @@ create_module(char *error_buf, uint32 error_buf_size)
 
     module->module_type = Wasm_Module_AoT;
 
+#if WASM_ENABLE_GC != 0
+    if (!(module->ref_type_set =
+              wasm_reftype_set_create(GC_REFTYPE_MAP_SIZE_DEFAULT))) {
+        set_error_buf(error_buf, error_buf_size, "create reftype map failed");
+        goto fail1;
+    }
+
+    if (os_mutex_init(&module->rtt_type_lock)) {
+        set_error_buf(error_buf, error_buf_size, "init rtt type lock failed");
+        goto fail2;
+    }
+#endif
+
     return module;
+#if WASM_ENABLE_GC != 0
+fail2:
+    bh_hash_map_destroy(module->ref_type_set);
+fail1:
+#endif
+    wasm_runtime_free(module);
+    return NULL;
 }
 
 AOTModule *
@@ -3309,6 +3578,13 @@ aot_unload(AOTModule *module)
     wasm_runtime_destroy_custom_sections(module->custom_section_list);
 #endif
 
+#if WASM_ENABLE_GC != 0
+    if (module->ref_type_set) {
+        bh_hash_map_destroy(module->ref_type_set);
+    }
+    os_mutex_destroy(&module->rtt_type_lock);
+#endif
+
     wasm_runtime_free(module);
 }
 

+ 177 - 6
core/iwasm/aot/aot_runtime.c

@@ -95,6 +95,7 @@ check_global_init_expr(const AOTModule *module, uint32 global_index,
         return false;
     }
 
+#if WASM_ENABLE_GC == 0
     /**
      * Currently, constant expressions occurring as initializers of
      * globals are further constrained in that contained global.get
@@ -108,6 +109,19 @@ check_global_init_expr(const AOTModule *module, uint32 global_index,
                       "constant expression required");
         return false;
     }
+#else
+    if (global_index >= module->import_global_count + module->global_count) {
+        set_error_buf_v(error_buf, error_buf_size, "unknown global %u",
+                        global_index);
+        return false;
+    }
+    if (global_index < module->import_global_count
+        && module->import_globals[global_index].is_mutable) {
+        set_error_buf(error_buf, error_buf_size,
+                      "constant expression required");
+        return false;
+    }
+#endif
 
     return true;
 }
@@ -208,7 +222,7 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
     AOTTableInitData *table_seg;
     AOTTableInstance *tbl_inst = first_tbl_inst;
 
-    total_size = (uint64)sizeof(WASMTableInstance *) * module_inst->table_count;
+    total_size = (uint64)sizeof(AOTTableInstance *) * module_inst->table_count;
     if (total_size > 0
         && !(module_inst->tables =
                  runtime_malloc(total_size, error_buf, error_buf_size))) {
@@ -225,16 +239,32 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
             tbl_inst->cur_size = import_table->table_init_size;
             tbl_inst->max_size =
                 aot_get_imp_tbl_data_slots(import_table, false);
+#if WASM_ENABLE_GC != 0
+            tbl_inst->elem_type = module->tables[i].elem_type;
+            tbl_inst->elem_ref_type.elem_ref_type =
+                module->tables[i].elem_ref_type;
+#endif
         }
         else {
             AOTTable *table = module->tables + (i - module->import_table_count);
             tbl_inst->cur_size = table->table_init_size;
             tbl_inst->max_size = aot_get_tbl_data_slots(table, false);
+#if WASM_ENABLE_GC != 0
+            tbl_inst->elem_type = module->tables[i].elem_type;
+            tbl_inst->elem_ref_type.elem_ref_type =
+                module->tables[i].elem_ref_type;
+#endif
         }
 
-        /* Set all elements to -1 to mark them as uninitialized elements */
+        /* Set all elements to -1 or NULL_REF to mark them as uninitialized
+         * elements */
+#if WASM_ENABLE_GC == 0
         memset(tbl_inst->elems, 0xff,
                sizeof(table_elem_type_t) * tbl_inst->max_size);
+#else
+        memset(tbl_inst->elems, 0x00,
+               sizeof(table_elem_type_t) * tbl_inst->max_size);
+#endif
 
         module_inst->tables[i] = tbl_inst;
         tbl_inst = (AOTTableInstance *)((uint8 *)tbl_inst
@@ -247,7 +277,7 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
     for (i = 0; i < module->table_init_data_count; i++) {
         table_seg = module->table_init_data_list[i];
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
         if (!wasm_elem_is_active(table_seg->mode))
             continue;
 #endif
@@ -323,10 +353,12 @@ tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module,
          * Check function index in the current module inst for now.
          * will check the linked table inst owner in future
          */
+#if WASM_ENABLE_GC == 0
         bh_memcpy_s(
             tbl_inst->elems + base_offset,
             (tbl_inst->max_size - base_offset) * sizeof(table_elem_type_t),
             table_seg->func_indexes, length * sizeof(table_elem_type_t));
+#endif
     }
 
     return true;
@@ -1093,7 +1125,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
         (uint64)module->memory_count * sizeof(AOTMemoryInstance);
     uint64 total_size, table_size = 0;
     uint8 *p;
-    uint32 i, extra_info_offset;
+    uint32 i, j, extra_info_offset;
     const bool is_sub_inst = parent != NULL;
 
     /* Check heap size */
@@ -1210,6 +1242,133 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     }
 #endif
 
+#if WASM_ENABLE_GC != 0
+    if (!is_sub_inst) {
+        uint32 gc_heap_size = wasm_runtime_get_gc_heap_size_default();
+        AOTModuleInstanceExtra *extra =
+            (AOTModuleInstanceExtra *)module_inst->e;
+
+        if (gc_heap_size < GC_HEAP_SIZE_MIN)
+            gc_heap_size = GC_HEAP_SIZE_MIN;
+        if (gc_heap_size > GC_HEAP_SIZE_MAX)
+            gc_heap_size = GC_HEAP_SIZE_MAX;
+
+        extra->common.gc_heap_pool =
+            runtime_malloc(gc_heap_size, error_buf, error_buf_size);
+        if (!extra->common.gc_heap_pool)
+            goto fail;
+
+        extra->common.gc_heap_handle =
+            mem_allocator_create(extra->common.gc_heap_pool, gc_heap_size);
+        if (!extra->common.gc_heap_handle)
+            goto fail;
+    }
+#endif
+
+#if WASM_ENABLE_GC != 0
+    /* Initialize the table data with table init data */
+    for (i = 0;
+         module_inst->table_count > 0 && i < module->table_init_data_count;
+         i++) {
+
+        AOTTableInitData *table_init_data = module->table_init_data_list[i];
+        AOTTableInstance *table;
+        table_elem_type_t *table_data;
+        uint8 tbl_elem_type;
+        uint32 tbl_init_size, tbl_max_size;
+        WASMRefType *tbl_elem_ref_type;
+
+        bh_assert(table_init_data);
+
+        table = module_inst->tables[table_init_data->table_index];
+
+        bh_assert(table);
+
+        table_data = table->elems;
+
+        wasm_runtime_get_table_inst_elem_type(
+            (WASMModuleInstanceCommon *)module_inst, i, &tbl_elem_type,
+            &tbl_elem_ref_type, &tbl_init_size, &tbl_max_size);
+
+        if (!wasm_elem_is_declarative(table_init_data->mode)
+            && !wasm_reftype_is_subtype_of(
+                table_init_data->elem_type, table_init_data->elem_ref_type,
+                table->elem_type, table->elem_ref_type.elem_ref_type,
+                module->types, module->type_count)) {
+            set_error_buf(error_buf, error_buf_size,
+                          "elements segment does not fit");
+            goto fail;
+        }
+
+        (void)tbl_init_size;
+        (void)tbl_max_size;
+
+        table_data = table->elems;
+
+        bh_assert(table_data);
+
+        if (!wasm_elem_is_active(table_init_data->mode)) {
+            continue;
+        }
+
+        bh_assert(table_init_data->offset.init_expr_type
+                      == INIT_EXPR_TYPE_I32_CONST
+                  || table_init_data->offset.init_expr_type
+                         == INIT_EXPR_TYPE_GET_GLOBAL
+                  || table_init_data->offset.init_expr_type
+                         == INIT_EXPR_TYPE_FUNCREF_CONST
+                  || table_init_data->offset.init_expr_type
+                         == INIT_EXPR_TYPE_REFNULL_CONST);
+
+        /* init vec(funcidx) or vec(expr) */
+        if (table_init_data->offset.init_expr_type
+            == INIT_EXPR_TYPE_GET_GLOBAL) {
+            if (!check_global_init_expr(module,
+                                        table_init_data->offset.u.global_index,
+                                        error_buf, error_buf_size)) {
+                goto fail;
+            }
+        }
+
+        /* check offset since length might negative */
+        if ((uint32)table_init_data->offset.u.i32 > table->cur_size) {
+            LOG_DEBUG("base_offset(%d) > table->cur_size(%d)",
+                      table_init_data->offset.u.i32, table->cur_size);
+            set_error_buf(error_buf, error_buf_size,
+                          "out of bounds table access");
+            goto fail;
+        }
+
+        if ((uint32)table_init_data->offset.u.i32
+                + table_init_data->func_index_count
+            > table->cur_size) {
+            LOG_DEBUG("base_offset(%d) + length(%d) > table->cur_size(%d)",
+                      table_init_data->offset.u.i32,
+                      table_init_data->func_index_count, table->cur_size);
+            set_error_buf(error_buf, error_buf_size,
+                          "out of bounds table access");
+            goto fail;
+        }
+
+        for (j = 0; j < module->table_init_data_list[i]->func_index_count;
+             j++) {
+            WASMFuncObjectRef func_obj;
+            uint32 func_idx = table_init_data->func_indexes[j];
+            if (func_idx != UINT32_MAX) {
+                if (!(func_obj =
+                          aot_create_func_obj(module_inst, func_idx, false,
+                                              error_buf, error_buf_size))) {
+                    goto fail;
+                }
+                *(table_data + table_init_data->offset.u.i32 + j) = func_obj;
+            }
+            else {
+                *(table_data + table_init_data->offset.u.i32 + j) = NULL_REF;
+            }
+        }
+    }
+#endif
+
 #if WASM_ENABLE_DUMP_CALL_STACK != 0
     if (!(module_inst->frames =
               runtime_malloc(sizeof(Vector), error_buf, error_buf_size))) {
@@ -1279,6 +1438,17 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
         wasm_runtime_free(((AOTModuleInstanceExtra *)module_inst->e)
                               ->common.c_api_func_imports);
 
+#if WASM_ENABLE_GC != 0
+    if (!is_sub_inst) {
+        AOTModuleInstanceExtra *extra =
+            (AOTModuleInstanceExtra *)module_inst->e;
+        if (extra->common.gc_heap_handle)
+            mem_allocator_destroy(extra->common.gc_heap_handle);
+        if (extra->common.gc_heap_pool)
+            wasm_runtime_free(extra->common.gc_heap_pool);
+    }
+#endif
+
     if (!is_sub_inst) {
 #if WASM_ENABLE_LIBC_WASI != 0
         wasm_runtime_destroy_wasi((WASMModuleInstanceCommon *)module_inst);
@@ -3412,8 +3582,9 @@ aot_create_func_obj(AOTModuleInstance *module_inst, uint32 func_idx,
         return NULL;
     }
 
-    if (!(func_obj = wasm_func_obj_new_internal(module_inst->e->gc_heap_handle,
-                                                rtt_type, func_idx))) {
+    if (!(func_obj = wasm_func_obj_new_internal(
+              ((AOTModuleInstanceExtra *)module_inst->e)->common.gc_heap_handle,
+              rtt_type, func_idx))) {
         set_error_buf(error_buf, error_buf_size, "create func object failed");
         return NULL;
     }

+ 117 - 26
core/iwasm/common/gc/gc_common.c

@@ -61,7 +61,10 @@ wasm_get_defined_type_count(WASMModuleCommon *const module)
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+        type_count = aot_module->type_count;
+    }
 #endif
 
     return type_count;
@@ -81,7 +84,12 @@ wasm_get_defined_type(WASMModuleCommon *const module, uint32 index)
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        bh_assert(index < aot_module->type_count);
+        type = aot_module->types[index];
+    }
 #endif
 
     return type;
@@ -298,7 +306,12 @@ wasm_defined_type_is_subtype_of(WASMType *const def_type1,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        types = aot_module->types;
+        type_count = aot_module->type_count;
+    }
 #endif
 
     bh_assert(types);
@@ -365,7 +378,10 @@ wasm_ref_type_equal(const wasm_ref_type_t *ref_type1,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        types = ((AOTModule *)module)->types;
+        type_count = wasm_get_defined_type_count(module);
+    }
 #endif
 
     return wasm_reftype_equal(type1, (WASMRefType *)&ref_type1_norm, type2,
@@ -405,7 +421,10 @@ wasm_ref_type_is_subtype_of(const wasm_ref_type_t *ref_type1,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        types = ((AOTModule *)module)->types;
+        type_count = wasm_get_defined_type_count(module);
+    }
 #endif
 
     bh_assert(types);
@@ -437,7 +456,17 @@ wasm_struct_obj_new_with_typeidx(WASMExecEnv *exec_env, uint32 type_idx)
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module_inst->module_type == Wasm_Module_AoT) {
+        AOTModule *module =
+            (AOTModule *)((AOTModuleInstance *)module_inst)->module;
+
+        bh_assert(type_idx < module->type_count);
+        type = module->types[type_idx];
+        bh_assert(wasm_defined_type_is_struct_type(type));
+        rtt_type =
+            wasm_rtt_type_new(type, type_idx, module->rtt_types,
+                              module->type_count, &module->rtt_type_lock);
+    }
 #endif
 
     if (!rtt_type) {
@@ -478,7 +507,22 @@ wasm_struct_obj_new_with_type(WASMExecEnv *exec_env, WASMStructType *type)
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module_inst->module_type == Wasm_Module_AoT) {
+        AOTModule *module =
+            (AOTModule *)((AOTModuleInstance *)module_inst)->module;
+
+        type_count = module->type_count;
+
+        for (i = 0; i < type_count; i++) {
+            if (module->types[i] == (AOTType *)type) {
+                break;
+            }
+        }
+        bh_assert(i < type_count);
+        rtt_type =
+            wasm_rtt_type_new((AOTType *)type, i, module->rtt_types,
+                              module->type_count, &module->rtt_type_lock);
+    }
 #endif
 
     if (!rtt_type) {
@@ -510,7 +554,13 @@ wasm_array_obj_new_with_typeidx(WASMExecEnv *exec_env, uint32 type_idx,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        rtt_type = wasm_rtt_type_new(
+            defined_type, type_idx, aot_module->rtt_types,
+            aot_module->type_count, &aot_module->rtt_type_lock);
+    }
 #endif
 
     if (!rtt_type) {
@@ -547,7 +597,19 @@ wasm_array_obj_new_with_type(WASMExecEnv *exec_env, WASMArrayType *type,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        type_count = aot_module->type_count;
+        for (i = 0; i < type_count; i++) {
+            if (aot_module->types[i] == (AOTType *)type) {
+                break;
+            }
+        }
+        bh_assert(i < aot_module->type_count);
+
+        type_idx = i;
+    }
 #endif
 
     array_obj =
@@ -575,7 +637,13 @@ wasm_func_obj_new_with_typeidx(WASMExecEnv *exec_env, uint32 type_idx,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        rtt_type = wasm_rtt_type_new(
+            defined_type, type_idx, aot_module->rtt_types,
+            aot_module->type_count, &aot_module->rtt_type_lock);
+    }
 #endif
 
     if (!rtt_type) {
@@ -612,7 +680,19 @@ wasm_func_obj_new_with_type(WASMExecEnv *exec_env, WASMFuncType *type,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        type_count = aot_module->type_count;
+        for (i = 0; i < type_count; i++) {
+            if (aot_module->types[i] == (AOTType *)type) {
+                break;
+            }
+        }
+        bh_assert(i < aot_module->type_count);
+
+        type_idx = i;
+    }
 #endif
 
     func_obj =
@@ -641,8 +721,12 @@ wasm_runtime_call_func_ref(WASMExecEnv *exec_env,
 #endif
 #if WASM_ENABLE_AOT != 0
     if (exec_env->module_inst->module_type == Wasm_Module_AoT) {
-        /* TODO */
-        return false;
+        AOTModuleInstance *module_inst =
+            (AOTModuleInstance *)exec_env->module_inst;
+
+        bh_assert(func_idx < module_inst->module->import_function_count
+                                 + module_inst->module->function_count);
+        /* TODO: Implement call func ref for aot mode */
     }
 #endif
 
@@ -687,7 +771,12 @@ wasm_obj_is_instance_of_defined_type(WASMObjectRef obj, WASMType *defined_type,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        type_count = aot_module->type_count;
+        types = (WASMType **)aot_module->types;
+    }
 #endif
 
     for (type_idx = 0; type_idx < type_count; type_idx++) {
@@ -715,7 +804,11 @@ wasm_obj_is_instance_of_type_idx(WASMObjectRef obj, uint32 type_idx,
     }
 #endif
 #if WASM_ENABLE_AOT != 0
-    /* TODO */
+    if (module->module_type == Wasm_Module_AoT) {
+        AOTModule *aot_module = (AOTModule *)module;
+
+        types = (WASMType **)aot_module->types;
+    }
 #endif
 
     bh_assert(types);
@@ -813,15 +906,14 @@ wasm_runtime_set_gc_heap_handle(WASMModuleInstanceCommon *module_inst,
 {
 #if WASM_ENABLE_INTERP != 0
     if (module_inst->module_type == Wasm_Module_Bytecode)
-        ((WASMModuleInstance *)module_inst)->e->gc_heap_handle = gc_heap_handle;
+        ((WASMModuleInstance *)module_inst)->e->common.gc_heap_handle =
+            gc_heap_handle;
 #endif
 #if WASM_ENABLE_AOT != 0
     if (module_inst->module_type == Wasm_Module_AoT) {
-        /* TODO */
-        /*
-        ((AOTModuleInstance *)module_inst)->e->gc_heap_handle.ptr =
-        gc_heap_handle;
-        */
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+        e->common.gc_heap_handle = gc_heap_handle;
     }
 #endif
 }
@@ -831,14 +923,13 @@ wasm_runtime_get_gc_heap_handle(WASMModuleInstanceCommon *module_inst)
 {
 #if WASM_ENABLE_INTERP != 0
     if (module_inst->module_type == Wasm_Module_Bytecode)
-        return ((WASMModuleInstance *)module_inst)->e->gc_heap_handle;
+        return ((WASMModuleInstance *)module_inst)->e->common.gc_heap_handle;
 #endif
 #if WASM_ENABLE_AOT != 0
     if (module_inst->module_type == Wasm_Module_AoT) {
-        /* TODO */
-        /*
-        return ((AOTModuleInstance *)module_inst)->e->gc_heap_handle.ptr;
-        */
+        AOTModuleInstanceExtra *e =
+            (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e;
+        return e->common.gc_heap_handle;
     }
 #endif
     return NULL;

+ 5 - 2
core/iwasm/common/gc/gc_object.c

@@ -65,11 +65,14 @@ get_gc_heap_handle(WASMExecEnv *exec_env)
 
 #if WASM_ENABLE_INTERP != 0
     if (module_inst->module_type == Wasm_Module_Bytecode)
-        gc_heap_handle = ((WASMModuleInstance *)module_inst)->e->gc_heap_handle;
+        gc_heap_handle =
+            ((WASMModuleInstance *)module_inst)->e->common.gc_heap_handle;
 #endif
 #if WASM_ENABLE_AOT != 0
     if (module_inst->module_type == Wasm_Module_AoT)
-        gc_heap_handle = NULL; /* TODO */
+        gc_heap_handle =
+            ((AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e)
+                ->common.gc_heap_handle;
 #endif
 
     bh_assert(gc_heap_handle);

+ 1 - 1
core/iwasm/common/wasm_application.c

@@ -564,7 +564,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
     }
 
     wasm_runtime_set_exception(module_inst, NULL);
-#if !(WASM_ENABLE_REF_TYPES != 0 && WASM_ENABLE_GC == 0)
+#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0
     bh_assert(p == (int32)argc1);
 #endif
 

+ 5 - 4
core/iwasm/common/wasm_exec_env.c

@@ -151,7 +151,8 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
         exec_env->aux_stack_boundary.boundary =
             module->aux_stack_bottom - module->aux_stack_size;
 #if WASM_ENABLE_GC != 0
-        gc_heap_handle = ((WASMModuleInstance *)module_inst)->e->gc_heap_handle;
+        gc_heap_handle =
+            ((WASMModuleInstance *)module_inst)->e->common.gc_heap_pool;
 #endif
     }
 #endif
@@ -164,8 +165,9 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
         exec_env->aux_stack_boundary.boundary =
             module->aux_stack_bottom - module->aux_stack_size;
 #if WASM_ENABLE_GC != 0
-        /*gc_heap_handle = ((AOTModuleInstance
-         * *)module_inst)->e->gc_heap_handle;*/
+        gc_heap_handle =
+            ((AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e)
+                ->common.gc_heap_handle;
 #endif
     }
 #endif
@@ -181,7 +183,6 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst,
 #endif
 #else
 #if WASM_ENABLE_GC != 0
-    bh_assert(gc_heap_handle);
     mem_allocator_enable_gc_reclaim(gc_heap_handle, exec_env);
 #endif
 #endif /* end of WASM_ENABLE_THREAD_MGR */

+ 7 - 0
core/iwasm/compilation/aot.c

@@ -136,6 +136,9 @@ aot_create_table_init_data_list(const WASMModule *module)
                     sizeof(AOTInitExpr));
         data_list[i]->func_index_count =
             module->table_segments[i].function_count;
+#if WASM_ENABLE_GC != 0
+        data_list[i]->elem_ref_type = module->table_segments[i].elem_ref_type;
+#endif
         bh_memcpy_s(
             data_list[i]->func_indexes,
             sizeof(uintptr_t) * module->table_segments[i].function_count,
@@ -460,6 +463,10 @@ aot_create_comp_data(WASMModule *module, bool gc_enabled)
                     module->import_tables[i].u.table.init_size;
                 comp_data->tables[i].table_max_size =
                     module->import_tables[i].u.table.max_size;
+#if WASM_ENABLE_GC != 0
+                comp_data->tables[i].elem_ref_type =
+                    module->import_tables[i].u.table.elem_ref_type;
+#endif
                 comp_data->tables[i].possible_grow =
                     module->import_tables[i].u.table.possible_grow;
             }

+ 10 - 0
core/iwasm/compilation/aot.h

@@ -41,6 +41,10 @@ extern const char *aot_stack_sizes_section_name;
 typedef InitializerExpression AOTInitExpr;
 typedef WASMType AOTType;
 typedef WASMFuncType AOTFuncType;
+#if WASM_ENABLE_GC != 0
+typedef WASMStructType AOTStructType;
+typedef WASMArrayType AOTArrayType;
+#endif
 typedef WASMExport AOTExport;
 
 #if WASM_ENABLE_DEBUG_AOT != 0
@@ -134,6 +138,9 @@ typedef struct AOTTable {
     uint32 table_init_size;
     uint32 table_max_size;
     bool possible_grow;
+#if WASM_ENABLE_GC != 0
+    WASMRefType *elem_ref_type;
+#endif
 } AOTTable;
 
 /**
@@ -144,6 +151,9 @@ typedef struct AOTTableInitData {
     uint32 mode;
     /* funcref or externref, elemkind will be considered as funcref */
     uint32 elem_type;
+#if WASM_ENABLE_GC != 0
+    WASMRefType *elem_ref_type;
+#endif
     bool is_dropped;
     /* optional, only for active */
     uint32 table_index;

+ 3 - 3
core/iwasm/compilation/aot_compiler.c

@@ -1063,9 +1063,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 }
 #endif
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
                 if (WASM_OP_TABLE_INIT <= opcode && opcode <= WASM_OP_TABLE_FILL
-                    && !comp_ctx->enable_ref_types) {
+                    && (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc)) {
                     goto unsupport_ref_types;
                 }
 #endif
@@ -2583,7 +2583,7 @@ unsupport_simd:
     return false;
 #endif
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
 unsupport_ref_types:
     aot_set_last_error("reference type instruction was found, "
                        "try removing --disable-ref-types option");

+ 222 - 36
core/iwasm/compilation/aot_emit_aot_file.c

@@ -271,13 +271,16 @@ get_table_init_data_size(AOTCompContext *comp_ctx,
      * mode (4 bytes), elem_type (4 bytes), do not need is_dropped field
      *
      * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8
-     * bytes)
+     * bytes) + sizeof(WASMRefType)
      * + func index count (4 bytes) + func indexes
      */
     return (uint32)(sizeof(uint32) * 2 + sizeof(uint32) + sizeof(uint32)
                     + sizeof(uint64) + sizeof(uint32)
                     + comp_ctx->pointer_size
-                          * table_init_data->func_index_count);
+                          * table_init_data->func_index_count)
+           /* Size of WasmRefType - inner padding (ref type + nullable +
+              heap_type) */
+           + 8;
 }
 
 static uint32
@@ -294,8 +297,8 @@ get_table_init_data_list_size(AOTCompContext *comp_ctx,
      * |                     | U32 table_index
      * |                     | U32 offset.init_expr_type
      * |                     | U64 offset.u.i64
-     * |                     | U32 func_index_count
-     * |                     | U32/U64 [func_index_count]
+     * |                     | U32 func_index_count / elem_count
+     * |                     | UINTPTR [func_index_count] / [elem_count]
      * ------------------------------
      */
     AOTTableInitData **table_init_data = table_init_data_list;
@@ -376,33 +379,65 @@ get_table_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data)
                                            comp_data->table_init_data_count);
 }
 
+#if WASM_ENABLE_GC != 0
 static uint32
-get_func_type_size(AOTFuncType *func_type)
+get_func_type_size(AOTCompContext *comp_ctx, AOTFuncType *func_type)
+{
+    /* type flag + is_sub_final + parent_type_idx + param count + result count
+     * + types + ref_type_map_count */
+    if (comp_ctx->enable_gc) {
+        return sizeof(func_type->base_type.type_flag) + sizeof(uint16)
+               + sizeof(func_type->base_type.parent_type_idx)
+               + sizeof(func_type->param_count)
+               + sizeof(func_type->result_count) + func_type->param_count
+               + func_type->result_count
+               + sizeof(func_type->ref_type_map_count);
+    }
+    else {
+        /* type flag + is_sub_final + parent_type_idx + param count + result
+         * count + types */
+        return (uint32)sizeof(uint16) * 6 + func_type->param_count
+               + func_type->result_count;
+    }
+}
+#else
+static uint32
+get_func_type_size(AOTCompContext *comp_ctx, AOTFuncType *func_type)
 {
-    /* param count + result count + types */
-    return (uint32)sizeof(uint32) * 2 + func_type->param_count
+    /* type flags + parent type idx + is_sub_final + param count + result count
+     * + types */
+    return (uint32)sizeof(uint16) * 6 + func_type->param_count
            + func_type->result_count;
 }
+#endif
 
 static uint32
-get_types_size(AOTType **func_types, uint32 func_type_count)
+get_func_type_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data)
 {
-    AOTFuncType **func_type = (AOTFuncType **)func_types;
-    uint32 size = 0, i;
+    /* Initial size with size of type count */
+    uint32 size = 4;
+    uint32 i;
 
-    for (i = 0; i < func_type_count; i++, func_type++) {
-        size = align_uint(size, 4);
-        size += get_func_type_size(*func_type);
+#if WASM_ENABLE_GC != 0
+    if (comp_ctx->enable_gc) {
+        for (i = 0; i < comp_data->type_count; i++) {
+            size = align_uint(size, 4);
+            if (comp_data->types[i]->type_flag == WASM_TYPE_FUNC)
+                size += get_func_type_size(comp_ctx,
+                                           (AOTFuncType *)comp_data->types[i]);
+        }
+    }
+    else
+#endif
+    {
+        for (i = 0; i < comp_data->type_count; i++) {
+            size = align_uint(size, 4);
+            size += get_func_type_size(comp_ctx,
+                                       (AOTFuncType *)comp_data->types[i]);
+        }
     }
-    return size;
-}
 
-static uint32
-get_func_type_info_size(AOTCompData *comp_data)
-{
-    /* func type count + func type list */
-    return (uint32)sizeof(uint32)
-           + get_types_size(comp_data->types, comp_data->type_count);
+    return size;
 }
 
 static uint32
@@ -549,7 +584,7 @@ get_init_data_section_size(AOTCompContext *comp_ctx, AOTCompData *comp_data,
     size += get_table_info_size(comp_ctx, comp_data);
 
     size = align_uint(size, 4);
-    size += get_func_type_info_size(comp_data);
+    size += get_func_type_info_size(comp_ctx, comp_data);
 
     size = align_uint(size, 4);
     size += get_import_global_info_size(comp_ctx, comp_data);
@@ -1510,6 +1545,18 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
         EMIT_U32(init_datas[i]->table_index);
         EMIT_U32(init_datas[i]->offset.init_expr_type);
         EMIT_U64(init_datas[i]->offset.u.i64);
+#if WASM_ENABLE_GC != 0
+        if (init_datas[i]->elem_ref_type) {
+            EMIT_U16(init_datas[i]->elem_ref_type->ref_ht_common.ref_type);
+            EMIT_U16(init_datas[i]->elem_ref_type->ref_ht_common.nullable);
+            EMIT_U32(init_datas[i]->elem_ref_type->ref_ht_common.heap_type);
+        }
+        else {
+            EMIT_U32(0);
+            EMIT_U16(init_datas[i]->elem_type);
+            EMIT_U16(0);
+        }
+#endif
         EMIT_U32(init_datas[i]->func_index_count);
         for (j = 0; j < init_datas[i]->func_index_count; j++) {
 
@@ -1532,31 +1579,148 @@ aot_emit_table_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
     return true;
 }
 
+#if WASM_ENABLE_GC != 0
+static bool
+aot_emit_reftype_map(uint8 *buf, uint8 *buf_end, uint32 *p_offset, uint32 count,
+                     WASMRefTypeMap *refmap)
+{
+    uint32 offset = *p_offset, i;
+
+    for (i = 0; i < count; i++) {
+        EMIT_U16(refmap->index);
+        WASMRefType *ref_type = refmap->ref_type;
+
+        /* Note: WASMRefType is a union type */
+        EMIT_U8(ref_type->ref_ht_common.ref_type);
+        EMIT_U8(ref_type->ref_ht_common.nullable);
+        EMIT_U32(ref_type->ref_ht_common.heap_type);
+
+        refmap++;
+    }
+
+    *p_offset = offset;
+    return true;
+}
+#endif
+
 static bool
 aot_emit_type_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
-                   AOTCompData *comp_data, AOTObjectData *obj_data)
+                   AOTCompContext *comp_ctx, AOTCompData *comp_data,
+                   AOTObjectData *obj_data)
 {
     uint32 offset = *p_offset, i;
-    AOTFuncType **func_types = (AOTFuncType **)comp_data->types;
 
     *p_offset = offset = align_uint(offset, 4);
 
     EMIT_U32(comp_data->type_count);
 
-    for (i = 0; i < comp_data->type_count; i++) {
-        offset = align_uint(offset, 4);
-        EMIT_U32(func_types[i]->param_count);
-        EMIT_U32(func_types[i]->result_count);
-        EMIT_BUF(func_types[i]->types,
-                 func_types[i]->param_count + func_types[i]->result_count);
-    }
+#if WASM_ENABLE_GC != 0
+    if (comp_ctx->enable_gc) {
+        int32 idx;
+        AOTType **types = comp_data->types;
+        WASMRefTypeMap *ref_type_map;
 
-    if (offset - *p_offset != get_func_type_info_size(comp_data)) {
-        aot_set_last_error("emit function type info failed.");
-        return false;
+        for (i = 0; i < comp_data->type_count; i++) {
+            offset = align_uint(offset, 4);
+            EMIT_U16(types[i]->type_flag);
+            EMIT_U16(types[i]->is_sub_final);
+            EMIT_U32(types[i]->parent_type_idx);
+
+            /* Emit WASM_TYPE_FUNC */
+            if (types[i]->type_flag == WASM_TYPE_FUNC) {
+                AOTFuncType *func_type = (AOTFuncType *)types[i];
+                EMIT_U16(func_type->param_count);
+                EMIT_U16(func_type->result_count);
+                EMIT_U16(func_type->ref_type_map_count);
+                EMIT_BUF(func_type->types,
+                         func_type->param_count + func_type->result_count);
+
+                /* If no ref type used, then continue */
+                if (func_type->ref_type_map_count == 0) {
+                    continue;
+                }
+
+                ref_type_map = func_type->ref_type_maps;
+                for (int j = 0;
+                     j < func_type->param_count + func_type->result_count;
+                     j++) {
+                    WASMRefType *ref_type = ref_type_map->ref_type;
+
+                    bh_assert(j == ref_type_map->index);
+                    bh_assert(ref_type->ref_type == REF_TYPE_HT_NULLABLE
+                              || ref_type->ref_type
+                                     == REF_TYPE_HT_NON_NULLABLE);
+
+                    /* Note: WASMRefType is a union type */
+                    EMIT_U8(ref_type->ref_ht_common.ref_type);
+                    EMIT_U8(ref_type->ref_ht_common.nullable);
+                    EMIT_U32(ref_type->ref_ht_common.heap_type);
+
+                    ref_type_map++;
+                }
+                bh_assert(ref_type_map - func_type->ref_type_maps
+                          == func_type->ref_type_map_count);
+            }
+            /* Emit WASM_TYPE_STRUCT */
+            else if (types[i]->type_flag == WASM_TYPE_STRUCT) {
+                AOTStructType *struct_type = (AOTStructType *)types[i];
+                EMIT_U16(struct_type->field_count);
+                for (idx = 0; idx < struct_type->field_count; idx++) {
+                    EMIT_U16(struct_type->fields[idx].field_flags);
+                    EMIT_U8(struct_type->fields[idx].field_type);
+                }
+                EMIT_U16(struct_type->ref_type_map_count);
+                aot_emit_reftype_map(buf, buf_end, &offset,
+                                     struct_type->ref_type_map_count,
+                                     struct_type->ref_type_maps);
+            }
+            /* Emit WASM_TYPE_ARRAY */
+            else if (types[i]->type_flag == WASM_TYPE_ARRAY) {
+                AOTArrayType *array_type = (AOTArrayType *)types[i];
+                EMIT_U16(array_type->elem_flags);
+                EMIT_U8(array_type->elem_type);
+            }
+            else {
+                aot_set_last_error("invalid type flag.");
+                return false;
+            }
+        }
+
+        if (offset - *p_offset
+            != get_func_type_info_size(comp_ctx, comp_data)) {
+            aot_set_last_error("emit function type info failed.");
+            return false;
+        }
+
+        *p_offset = offset;
     }
+    else
+#endif
+    {
+        AOTFuncType **func_types = (AOTFuncType **)comp_data->types;
 
-    *p_offset = offset;
+        for (i = 0; i < comp_data->type_count; i++) {
+            offset = align_uint(offset, 4);
+            /* If GC enabled, only emit function type info */
+            EMIT_U16(WASM_TYPE_FUNC);
+            /* Emit dummy is_sub_final */
+            EMIT_U16(0);
+            /* Emit parent_type_index */
+            EMIT_U32(0);
+            EMIT_U16(func_types[i]->param_count);
+            EMIT_U16(func_types[i]->result_count);
+            EMIT_BUF(func_types[i]->types,
+                     func_types[i]->param_count + func_types[i]->result_count);
+        }
+
+        if (offset - *p_offset
+            != get_func_type_info_size(comp_ctx, comp_data)) {
+            aot_set_last_error("emit function type info failed.");
+            return false;
+        }
+
+        *p_offset = offset;
+    }
 
     return true;
 }
@@ -1727,7 +1891,8 @@ aot_emit_init_data_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
     if (!aot_emit_mem_info(buf, buf_end, &offset, comp_ctx, comp_data, obj_data)
         || !aot_emit_table_info(buf, buf_end, &offset, comp_ctx, comp_data,
                                 obj_data)
-        || !aot_emit_type_info(buf, buf_end, &offset, comp_data, obj_data)
+        || !aot_emit_type_info(buf, buf_end, &offset, comp_ctx, comp_data,
+                               obj_data)
         || !aot_emit_import_global_info(buf, buf_end, &offset, comp_ctx,
                                         comp_data, obj_data)
         || !aot_emit_global_info(buf, buf_end, &offset, comp_data, obj_data)
@@ -3566,6 +3731,27 @@ aot_obj_data_create(AOTCompContext *comp_ctx)
         goto fail;
     }
 
+    /* Create wasm feature flags form compile options */
+    obj_data->target_info.feature_flags = 0;
+    if (comp_ctx->enable_simd) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_SIMD_128BIT;
+    }
+    if (comp_ctx->enable_bulk_memory) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_BULK_MEMORY;
+    }
+    if (comp_ctx->enable_thread_mgr) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_THREADS;
+    }
+    if (comp_ctx->enable_ref_types) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_REF_TYPES;
+    }
+    if (comp_ctx->enable_tail_call) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_TAIL_CALL;
+    }
+    if (comp_ctx->enable_gc) {
+        obj_data->target_info.feature_flags |= WASM_FEATURE_GARBAGE_COLLECTION;
+    }
+
     bh_print_time("Begin to resolve object file info");
 
     /* resolve target info/text/relocations/functions */

+ 11 - 11
core/iwasm/interpreter/wasm_runtime.c

@@ -1538,8 +1538,8 @@ wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx,
         return NULL;
     }
 
-    if (!(func_obj = wasm_func_obj_new_internal(module_inst->e->gc_heap_handle,
-                                                rtt_type, func_idx))) {
+    if (!(func_obj = wasm_func_obj_new_internal(
+              module_inst->e->common.gc_heap_handle, rtt_type, func_idx))) {
         set_error_buf(error_buf, error_buf_size, "create func object failed");
         return NULL;
     }
@@ -1906,14 +1906,14 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
         if (gc_heap_size > GC_HEAP_SIZE_MAX)
             gc_heap_size = GC_HEAP_SIZE_MAX;
 
-        module_inst->e->gc_heap_pool =
+        module_inst->e->common.gc_heap_pool =
             runtime_malloc(gc_heap_size, error_buf, error_buf_size);
-        if (!module_inst->e->gc_heap_pool)
+        if (!module_inst->e->common.gc_heap_pool)
             goto fail;
 
-        module_inst->e->gc_heap_handle =
-            mem_allocator_create(module_inst->e->gc_heap_pool, gc_heap_size);
-        if (!module_inst->e->gc_heap_handle)
+        module_inst->e->common.gc_heap_handle = mem_allocator_create(
+            module_inst->e->common.gc_heap_pool, gc_heap_size);
+        if (!module_inst->e->common.gc_heap_handle)
             goto fail;
     }
 #endif
@@ -2504,10 +2504,10 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
 
 #if WASM_ENABLE_GC != 0
     if (!is_sub_inst) {
-        if (module_inst->e->gc_heap_handle)
-            mem_allocator_destroy(module_inst->e->gc_heap_handle);
-        if (module_inst->e->gc_heap_pool)
-            wasm_runtime_free(module_inst->e->gc_heap_pool);
+        if (module_inst->e->common.gc_heap_handle)
+            mem_allocator_destroy(module_inst->e->common.gc_heap_handle);
+        if (module_inst->e->common.gc_heap_pool)
+            wasm_runtime_free(module_inst->e->common.gc_heap_pool);
     }
 #endif
 

+ 7 - 7
core/iwasm/interpreter/wasm_runtime.h

@@ -239,6 +239,13 @@ typedef struct WASMModuleInstanceExtraCommon {
     /* Disable bounds checks or not */
     bool disable_bounds_checks;
 #endif
+
+#if WASM_ENABLE_GC != 0
+    /* The gc heap memory pool */
+    uint8 *gc_heap_pool;
+    /* The gc heap created */
+    void *gc_heap_handle;
+#endif
 } WASMModuleInstanceExtraCommon;
 
 /* Extra info of WASM module instance for interpreter/jit mode */
@@ -265,13 +272,6 @@ typedef struct WASMModuleInstanceExtra {
     WASMTableInstance **table_insts_linked;
 #endif
 
-#if WASM_ENABLE_GC != 0
-    /* The gc heap memory pool */
-    uint8 *gc_heap_pool;
-    /* The gc heap created */
-    void *gc_heap_handle;
-#endif
-
 #if WASM_ENABLE_MEMORY_PROFILING != 0
     uint32 max_aux_stack_used;
 #endif

+ 4 - 0
product-mini/platforms/linux-sgx/CMakeLists.txt

@@ -16,6 +16,10 @@ if (NOT DEFINED WAMR_BUILD_TARGET)
   if (CMAKE_SIZEOF_VOID_P EQUAL 8)
     # Build as X86_64 by default in 64-bit platform
     set (WAMR_BUILD_TARGET "X86_64")
+    if (NOT DEFINED WAMR_BUILD_SIMD)
+      # Enable SIMD by default in 64-bit platform
+      set (WAMR_BUILD_SIMD 1)
+    endif ()
   elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
     # Build as X86_32 by default in 32-bit platform
     set (WAMR_BUILD_TARGET "X86_32")

+ 6 - 0
product-mini/platforms/linux/CMakeLists.txt

@@ -24,11 +24,17 @@ set (CMAKE_CXX_STANDARD 17)
 if (NOT DEFINED WAMR_BUILD_TARGET)
   if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
     set (WAMR_BUILD_TARGET "AARCH64")
+    if (NOT DEFINED WAMR_BUILD_SIMD)
+      set (WAMR_BUILD_SIMD 1)
+    endif ()
   elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
     set (WAMR_BUILD_TARGET "RISCV64")
   elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
     # Build as X86_64 by default in 64-bit platform
     set (WAMR_BUILD_TARGET "X86_64")
+    if (NOT DEFINED WAMR_BUILD_SIMD)
+      set (WAMR_BUILD_SIMD 1)
+    endif ()
   elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
     # Build as X86_32 by default in 32-bit platform
     set (WAMR_BUILD_TARGET "X86_32")

+ 1 - 0
samples/file/src/CMakeLists.txt

@@ -51,6 +51,7 @@ set (WAMR_BUILD_INTERP 1)
 set (WAMR_BUILD_AOT 1)
 set (WAMR_BUILD_JIT 0)
 set (WAMR_BUILD_LIBC_BUILTIN 1)
+set (WAMR_BUILD_REF_TYPES 1)
 
 if (NOT MSVC)
   set (WAMR_BUILD_LIBC_WASI 1)

+ 17 - 1
samples/wasm-c-api/CMakeLists.txt

@@ -36,11 +36,17 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
 if (NOT DEFINED WAMR_BUILD_TARGET)
   if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
     set (WAMR_BUILD_TARGET "AARCH64")
+    if (NOT DEFINED WAMR_BUILD_SIMD)
+      set (WAMR_BUILD_SIMD 1)
+    endif ()
   elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
     set (WAMR_BUILD_TARGET "RISCV64")
   elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
     # Build as X86_64 by default in 64-bit platform
     set (WAMR_BUILD_TARGET "X86_64")
+    if (NOT DEFINED WAMR_BUILD_SIMD)
+      set (WAMR_BUILD_SIMD 1)
+    endif ()
   elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
     # Build as X86_32 by default in 32-bit platform
     set (WAMR_BUILD_TARGET "X86_32")
@@ -67,6 +73,11 @@ set(WAMR_BUILD_MULTI_MODULE 1)
 set(WAMR_BUILD_DUMP_CALL_STACK 1)
 set(WAMR_BUILD_REF_TYPES 1)
 
+# If not defined WAMR_BUILD_GC, set it to 0
+if(NOT DEFINED WAMRC_BUILD_WITH_GC)
+  set(WAMRC_BUILD_WITH_GC 0)
+endif()
+
 if(NOT DEFINED WAMR_BUILD_FAST_INTERP)
   set(WAMR_BUILD_FAST_INTERP 1)
 endif()
@@ -173,8 +184,13 @@ foreach(EX ${EXAMPLES})
 
   # generate .aot file
   if(${WAMR_BUILD_AOT} EQUAL 1)
+    if(${WAMRC_BUILD_WITH_GC} EQUAL 1)
+      set(WAMRC_GC_FLAGS "--enable-gc")
+    else()
+      set(WAMRC_GC_FLAGS "")
+    endif()
     add_custom_target(${EX}_AOT
-      COMMAND ${WAMRC} -o ${PROJECT_BINARY_DIR}/${EX}.aot
+      COMMAND ${WAMRC} ${WAMRC_GC_FLAGS} -o ${PROJECT_BINARY_DIR}/${EX}.aot
         ${PROJECT_BINARY_DIR}/${EX}.wasm
       DEPENDS ${EX}_WASM
       BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.aot

+ 3 - 0
tests/wamr-test-suites/spec-test-script/runtest.py

@@ -1010,6 +1010,9 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = '
     if opts.multi_thread:
         cmd.append("--enable-multi-thread")
 
+    if opts.gc:
+        cmd.append("--enable-gc")
+
     if output == 'object':
         cmd.append("--format=object")
     elif output == 'ir':