Quellcode durchsuchen

Refactor the LLVM IR translation of the existing opcodes for GC AOT (#2376)

Refactor the LLVM IR translation of below opcodes:
  CALL_INDIRECT, SELECT_T, TABLE_GET, TABLE_SET,
  REF_NULL, REF_IS_NULL, REF_FUNC,
  TABLE_INIT, TABLE_GROW, TABLE_FILL,
  GET_LOCAL, SET_LOCAL, TEE_LOCAL

And refactor aot_drop_table_seg and add aot_create_func_obj.
TianlongLiang vor 2 Jahren
Ursprung
Commit
7d86111a53

+ 72 - 2
core/iwasm/aot/aot_runtime.c

@@ -2450,7 +2450,7 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
 #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \
                  || (WASM_ENABLE_MEMORY_TRACING != 0) */
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
 void
 aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx)
 {
@@ -2467,6 +2467,12 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
     AOTTableInstance *tbl_inst;
     AOTTableInitData *tbl_seg;
     const AOTModule *module = (AOTModule *)module_inst->module;
+#if WASM_ENABLE_GC != 0
+    table_elem_type_t *table_elems;
+    uintptr_t *func_indexes;
+    void *func_obj;
+    uint32 i;
+#endif
 
     tbl_inst = module_inst->tables[tbl_idx];
     bh_assert(tbl_inst);
@@ -2494,11 +2500,31 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
         return;
     }
 
+#if WASM_ENABLE_GC != 0
+    table_elems = tbl_inst->elems + dst_offset;
+    func_indexes = tbl_seg->func_indexes + src_offset;
+
+    for (i = 0; i < length; i++) {
+        /* UINT32_MAX indicates that it is a null ref */
+        if (func_indexes[i] != UINT32_MAX) {
+            if (!(func_obj = aot_create_func_obj(module_inst, func_indexes[i],
+                                                 true, NULL, 0))) {
+                aot_set_exception_with_id(module_inst, EXCE_NULL_GC_REF);
+                return;
+            }
+            table_elems[i] = func_obj;
+        }
+        else {
+            table_elems[i] = NULL_REF;
+        }
+    }
+#else
     bh_memcpy_s((uint8 *)tbl_inst + offsetof(AOTTableInstance, elems)
                     + dst_offset * sizeof(table_elem_type_t),
                 (tbl_inst->cur_size - dst_offset) * sizeof(table_elem_type_t),
                 tbl_seg->func_indexes + src_offset,
                 length * sizeof(table_elem_type_t));
+#endif
 }
 
 void
@@ -2587,7 +2613,7 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx,
     tbl_inst->cur_size = entry_count;
     return orig_tbl_sz;
 }
-#endif /* WASM_ENABLE_REF_TYPES != 0 */
+#endif /* WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */
 
 #if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
 #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
@@ -3352,3 +3378,47 @@ aot_dump_pgo_prof_data_to_buf(AOTModuleInstance *module_inst, char *buf,
     return total_size;
 }
 #endif /* end of WASM_ENABLE_STATIC_PGO != 0 */
+
+#if WASM_ENABLE_GC != 0
+
+void *
+aot_create_func_obj(AOTModuleInstance *module_inst, uint32 func_idx,
+                    bool throw_exce, char *error_buf, uint32 error_buf_size)
+{
+    AOTModule *module = (AOTModule *)module_inst->module;
+    WASMRttTypeRef rtt_type;
+    WASMFuncObjectRef func_obj;
+    AOTFuncType *func_type;
+    uint32 type_idx;
+
+    if (throw_exce) {
+        error_buf = module_inst->cur_exception;
+        error_buf_size = sizeof(module_inst->cur_exception);
+    }
+
+    if (func_idx >= module->import_func_count + module->func_count) {
+        set_error_buf_v(error_buf, error_buf_size, "unknown function %d",
+                        func_idx);
+        return NULL;
+    }
+
+    type_idx = module_inst->func_type_indexes[func_idx];
+    func_type = (AOTFuncType *)module->types[type_idx];
+
+    if (!(rtt_type = wasm_rtt_type_new((AOTType *)func_type, type_idx,
+                                       module->rtt_types, module->type_count,
+                                       &module->rtt_type_lock))) {
+        set_error_buf(error_buf, error_buf_size, "create rtt object failed");
+        return NULL;
+    }
+
+    if (!(func_obj = wasm_func_obj_new_internal(module_inst->e->gc_heap_handle,
+                                                rtt_type, func_idx))) {
+        set_error_buf(error_buf, error_buf_size, "create func object failed");
+        return NULL;
+    }
+
+    return func_obj;
+}
+
+#endif /* end of WASM_ENABLE_GC != 0 */

+ 14 - 1
core/iwasm/aot/aot_runtime.h

@@ -282,6 +282,12 @@ typedef struct AOTModule {
     WASIArguments wasi_args;
     bool import_wasi_api;
 #endif
+#if WASM_ENABLE_GC != 0
+    /* Ref types hash set */
+    HashMap *ref_type_set;
+    struct WASMRttType **rtt_types;
+    korp_mutex rtt_type_lock;
+#endif
 #if WASM_ENABLE_DEBUG_AOT != 0
     void *elf_hdr;
     uint32 elf_size;
@@ -603,7 +609,7 @@ void
 aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
                                     WASMModuleInstMemConsumption *mem_conspn);
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
 void
 aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx);
 
@@ -687,6 +693,13 @@ void
 aot_exchange_uint64(uint8 *p_data);
 #endif /* end of WASM_ENABLE_STATIC_PGO != 0 */
 
+#if WASM_ENABLE_GC != 0
+void *
+aot_create_func_obj(AOTModuleInstance *module_inst, uint32 func_idx,
+                    bool throw_exce, char *error_buf, uint32 error_buf_size);
+
+#endif /* end of WASM_ENABLE_GC != 0 */
+
 #ifdef __cplusplus
 } /* end of extern "C" */
 #endif

+ 37 - 28
core/iwasm/compilation/aot_compiler.c

@@ -361,13 +361,10 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
 
-#if WASM_ENABLE_REF_TYPES != 0
-                if (comp_ctx->enable_ref_types) {
+                if (comp_ctx->enable_gc || comp_ctx->enable_ref_types) {
                     read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
                 }
-                else
-#endif
-                {
+                else {
                     frame_ip++;
                     tbl_idx = 0;
                 }
@@ -401,13 +398,10 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 }
 
                 read_leb_uint32(frame_ip, frame_ip_end, type_idx);
-#if WASM_ENABLE_REF_TYPES != 0
-                if (comp_ctx->enable_ref_types) {
+                if (comp_ctx->enable_gc || comp_ctx->enable_ref_types) {
                     read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
                 }
-                else
-#endif
-                {
+                else {
                     frame_ip++;
                     tbl_idx = 0;
                 }
@@ -441,13 +435,13 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                     return false;
                 break;
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
             case WASM_OP_SELECT_T:
             {
                 uint32 vec_len;
 
-                if (!comp_ctx->enable_ref_types) {
-                    goto unsupport_ref_types;
+                if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+                    goto unsupport_gc_and_ref_types;
                 }
 
                 read_leb_uint32(frame_ip, frame_ip_end, vec_len);
@@ -455,18 +449,25 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                 (void)vec_len;
 
                 type_idx = *frame_ip++;
-                if (!aot_compile_op_select(comp_ctx, func_ctx,
-                                           (type_idx != VALUE_TYPE_I64)
-                                               && (type_idx != VALUE_TYPE_F64)))
+                if (!aot_compile_op_select(
+                        comp_ctx, func_ctx,
+                        (type_idx != VALUE_TYPE_I64)
+                            && (type_idx != VALUE_TYPE_F64)
+#if WASM_ENABLE_GC != 0 && UINTPTR_MAX == UINT64_MAX
+                            && !(comp_ctx->enable_gc
+                                 && wasm_is_type_reftype(type_idx))
+#endif
+                            ))
                     return false;
+
                 break;
             }
             case WASM_OP_TABLE_GET:
             {
                 uint32 tbl_idx;
 
-                if (!comp_ctx->enable_ref_types) {
-                    goto unsupport_ref_types;
+                if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+                    goto unsupport_gc_and_ref_types;
                 }
 
                 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
@@ -478,8 +479,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
             {
                 uint32 tbl_idx;
 
-                if (!comp_ctx->enable_ref_types) {
-                    goto unsupport_ref_types;
+                if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+                    goto unsupport_gc_and_ref_types;
                 }
 
                 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx);
@@ -491,8 +492,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
             {
                 uint32 type;
 
-                if (!comp_ctx->enable_ref_types) {
-                    goto unsupport_ref_types;
+                if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+                    goto unsupport_gc_and_ref_types;
                 }
 
                 read_leb_uint32(frame_ip, frame_ip_end, type);
@@ -505,8 +506,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
             }
             case WASM_OP_REF_IS_NULL:
             {
-                if (!comp_ctx->enable_ref_types) {
-                    goto unsupport_ref_types;
+                if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+                    goto unsupport_gc_and_ref_types;
                 }
 
                 if (!aot_compile_op_ref_is_null(comp_ctx, func_ctx))
@@ -515,8 +516,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
             }
             case WASM_OP_REF_FUNC:
             {
-                if (!comp_ctx->enable_ref_types) {
-                    goto unsupport_ref_types;
+                if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+                    goto unsupport_gc_and_ref_types;
                 }
 
                 read_leb_uint32(frame_ip, frame_ip_end, func_idx);
@@ -1137,7 +1138,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                         break;
                     }
 #endif /* WASM_ENABLE_BULK_MEMORY */
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
                     case WASM_OP_TABLE_INIT:
                     {
                         uint32 tbl_idx, tbl_seg_idx;
@@ -1201,7 +1202,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                             return false;
                         break;
                     }
-#endif /* WASM_ENABLE_REF_TYPES */
+#endif /* WASM_ENABLE_REF_TYPES || WASM_ENABLE_GC */
                     default:
                         aot_set_last_error("unsupported opcode");
                         return false;
@@ -2589,6 +2590,14 @@ unsupport_ref_types:
     return false;
 #endif
 
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
+unsupport_gc_and_ref_types:
+    aot_set_last_error(
+        "reference type or garbage collection instruction was found, "
+        "try adding --enable-gc or removing --disable-ref-types option");
+    return false;
+#endif
+
 #if WASM_ENABLE_BULK_MEMORY != 0
 unsupport_bulk_memory:
     aot_set_last_error("bulk memory instruction was found, "

+ 22 - 1
core/iwasm/compilation/aot_compiler.h

@@ -163,7 +163,15 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
 #define POP_V128(v) POP(v, VALUE_TYPE_V128)
 #define POP_FUNCREF(v) POP(v, VALUE_TYPE_FUNCREF)
 #define POP_EXTERNREF(v) POP(v, VALUE_TYPE_EXTERNREF)
-
+#if WASM_ENABLE_GC != 0
+#define POP_REF(v) POP(v, VALUE_TYPE_GC_REF)
+#else
+#define POP_REF(v)                                                          \
+    do {                                                                    \
+        bh_assert(                                                          \
+            !"should not POP_REF when WASM_ENABLE_GC macro isn't enabled"); \
+    } while (0)
+#endif
 #define POP_COND(llvm_value)                                                   \
     do {                                                                       \
         AOTValue *aot_value;                                                   \
@@ -217,6 +225,15 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
 #define PUSH_COND(v) PUSH(v, VALUE_TYPE_I1)
 #define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF)
 #define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF)
+#if WASM_ENABLE_GC != 0
+#define PUSH_REF(v) PUSH(v, VALUE_TYPE_GC_REF)
+#else
+#define PUSH_REF(v)                                                          \
+    do {                                                                     \
+        bh_assert(                                                           \
+            !"should not PUSH_REF when WASM_ENABLE_GC macro isn't enabled"); \
+    } while (0)
+#endif
 
 #define TO_LLVM_TYPE(wasm_type) \
     wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
@@ -240,6 +257,8 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
 #define F64_PTR_TYPE comp_ctx->basic_types.float64_ptr_type
 #define FUNC_REF_TYPE comp_ctx->basic_types.funcref_type
 #define EXTERN_REF_TYPE comp_ctx->basic_types.externref_type
+#define GC_REF_TYPE comp_ctx->basic_types.gc_ref_type
+#define GC_REF_PTR_TYPE comp_ctx->basic_types.gc_ref_ptr_type
 
 #define INT8_PTR_TYPE_GS comp_ctx->basic_types.int8_ptr_type_gs
 #define INT16_PTR_TYPE_GS comp_ctx->basic_types.int16_ptr_type_gs
@@ -278,6 +297,8 @@ check_type_compatible(uint8 src_type, uint8 dst_type)
 #define I64_63 LLVM_CONST(i64_63)
 #define I64_64 LLVM_CONST(i64_64)
 #define REF_NULL I32_NEG_ONE
+#define GC_REF_NULL LLVM_CONST(gc_ref_null)
+#define I8_PTR_NULL LLVM_CONST(i8_ptr_null)
 
 #define V128_TYPE comp_ctx->basic_types.v128_type
 #define V128_PTR_TYPE comp_ctx->basic_types.v128_ptr_type

+ 154 - 49
core/iwasm/compilation/aot_emit_function.c

@@ -8,6 +8,9 @@
 #include "aot_emit_control.h"
 #include "aot_emit_table.h"
 #include "../aot/aot_runtime.h"
+#if WASM_ENABLE_GC != 0
+#include "aot_emit_gc.h"
+#endif
 
 #define ADD_BASIC_BLOCK(block, name)                                          \
     do {                                                                      \
@@ -1057,7 +1060,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     AOTFuncType *func_type;
     LLVMValueRef tbl_idx_value, elem_idx, table_elem, func_idx;
     LLVMValueRef ftype_idx_ptr, ftype_idx, ftype_idx_const;
-    LLVMValueRef cmp_elem_idx, cmp_func_idx, cmp_ftype_idx;
+    LLVMValueRef cmp_func_obj, cmp_elem_idx, cmp_func_idx, cmp_ftype_idx;
     LLVMValueRef func, func_ptr, table_size_const;
     LLVMValueRef ext_ret_offset, ext_ret_ptr, ext_ret, res;
     LLVMValueRef *param_values = NULL, *value_rets = NULL;
@@ -1065,7 +1068,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMTypeRef *param_types = NULL, ret_type;
     LLVMTypeRef llvm_func_type, llvm_func_ptr_type;
     LLVMTypeRef ext_ret_ptr_type;
-    LLVMBasicBlockRef check_elem_idx_succ, check_ftype_idx_succ;
+    LLVMBasicBlockRef check_func_obj_succ, check_elem_idx_succ,
+        check_ftype_idx_succ;
     LLVMBasicBlockRef check_func_idx_succ, block_return, block_curr;
     LLVMBasicBlockRef block_call_import, block_call_non_import;
     LLVMValueRef offset;
@@ -1164,53 +1168,129 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
-                                        INTPTR_PTR_TYPE, "table_elem_ptr"))) {
-        HANDLE_FAILURE("LLVMBuildBitCast");
-        goto fail;
-    }
-
     /* Load function index */
-    if (!(table_elem =
-              LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE, table_elem,
-                                    &elem_idx, 1, "table_elem"))) {
-        HANDLE_FAILURE("LLVMBuildNUWAdd");
-        goto fail;
-    }
+    if (comp_ctx->enable_gc) {
+        /* table elem is func_obj when gc is enabled */
+        if (!(table_elem =
+                  LLVMBuildBitCast(comp_ctx->builder, table_elem,
+                                   GC_REF_PTR_TYPE, "table_elem_ptr"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
 
-    if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, INTPTR_TYPE, table_elem,
-                                    "func_idx"))) {
-        aot_set_last_error("llvm build load failed.");
-        goto fail;
-    }
+        if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, GC_REF_TYPE,
+                                                 table_elem, &elem_idx, 1,
+                                                 "table_elem"))) {
+            HANDLE_FAILURE("LLVMBuildNUWAdd");
+            goto fail;
+        }
 
-    if (!(func_idx = LLVMBuildIntCast2(comp_ctx->builder, func_idx, I32_TYPE,
-                                       true, "func_idx_i32"))) {
-        aot_set_last_error("llvm build int cast failed.");
-        goto fail;
-    }
+        if (!(table_elem = LLVMBuildLoad2(comp_ctx->builder, GC_REF_TYPE,
+                                          table_elem, "func_idx"))) {
+            aot_set_last_error("llvm build load failed.");
+            goto fail;
+        }
 
-    /* Check if func_idx == -1 */
-    if (!(cmp_func_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, func_idx,
-                                       I32_NEG_ONE, "cmp_func_idx"))) {
-        aot_set_last_error("llvm build icmp failed.");
-        goto fail;
-    }
+        /* Check if func object is NULL */
+        if (!(cmp_func_obj = LLVMBuildIsNull(comp_ctx->builder, table_elem,
+                                             "cmp_func_obj"))) {
+            aot_set_last_error("llvm build isnull failed.");
+            goto fail;
+        }
 
-    /* Throw exception if func_idx == -1 */
-    if (!(check_func_idx_succ = LLVMAppendBasicBlockInContext(
-              comp_ctx->context, func_ctx->func, "check_func_idx_succ"))) {
-        aot_set_last_error("llvm add basic block failed.");
-        goto fail;
+        /* Throw exception if func object is NULL */
+        if (!(check_func_obj_succ = LLVMAppendBasicBlockInContext(
+                  comp_ctx->context, func_ctx->func, "check_func_obj_succ"))) {
+            aot_set_last_error("llvm add basic block failed.");
+            goto fail;
+        }
+
+        LLVMMoveBasicBlockAfter(check_func_obj_succ,
+                                LLVMGetInsertBlock(comp_ctx->builder));
+
+        if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNINITIALIZED_ELEMENT,
+                                 true, cmp_func_obj, check_func_obj_succ)))
+            goto fail;
+
+        /* Get the func idx bound of the WASMFuncObject, the offset may be
+         * different in 32-bit runtime and 64-bit runtime since WASMObjectHeader
+         * is uintptr_t. Use comp_ctx->pointer_size as the
+         * offsetof(WASMFuncObject, func_idx_bound)
+         */
+        if (!(offset = I32_CONST(comp_ctx->pointer_size))) {
+            HANDLE_FAILURE("LLVMConstInt");
+            goto fail;
+        }
+
+        if (!(func_idx = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
+                                               table_elem, &offset, 1,
+                                               "func_idx_bound_i8p"))) {
+            HANDLE_FAILURE("LLVMBuildGEP");
+            goto fail;
+        }
+
+        if (!(func_idx =
+                  LLVMBuildBitCast(comp_ctx->builder, func_idx, INT32_PTR_TYPE,
+                                   "func_idx_bound_i32p"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
+
+        if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, func_idx,
+                                        "func_idx_bound"))) {
+            HANDLE_FAILURE("LLVMBuildLoad");
+            goto fail;
+        }
     }
+    else {
+        if (!(table_elem =
+                  LLVMBuildBitCast(comp_ctx->builder, table_elem,
+                                   INTPTR_PTR_TYPE, "table_elem_ptr"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
 
-    LLVMMoveBasicBlockAfter(check_func_idx_succ,
-                            LLVMGetInsertBlock(comp_ctx->builder));
+        if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE,
+                                                 table_elem, &elem_idx, 1,
+                                                 "table_elem"))) {
+            HANDLE_FAILURE("LLVMBuildNUWAdd");
+            goto fail;
+        }
 
-    if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNINITIALIZED_ELEMENT,
-                             true, cmp_func_idx, check_func_idx_succ)))
-        goto fail;
+        if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, INTPTR_TYPE,
+                                        table_elem, "func_idx"))) {
+            aot_set_last_error("llvm build load failed.");
+            goto fail;
+        }
+
+        if (!(func_idx = LLVMBuildIntCast2(comp_ctx->builder, func_idx,
+                                           I32_TYPE, true, "func_idx_i32"))) {
+            aot_set_last_error("llvm build int cast failed.");
+            goto fail;
+        }
+
+        /* Check if func_idx == -1 */
+        if (!(cmp_func_idx =
+                  LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, func_idx,
+                                I32_NEG_ONE, "cmp_func_idx"))) {
+            aot_set_last_error("llvm build icmp failed.");
+            goto fail;
+        }
 
+        /* Throw exception if func_idx == -1 */
+        if (!(check_func_idx_succ = LLVMAppendBasicBlockInContext(
+                  comp_ctx->context, func_ctx->func, "check_func_idx_succ"))) {
+            aot_set_last_error("llvm add basic block failed.");
+            goto fail;
+        }
+
+        LLVMMoveBasicBlockAfter(check_func_idx_succ,
+                                LLVMGetInsertBlock(comp_ctx->builder));
+
+        if (!(aot_emit_exception(comp_ctx, func_ctx, EXCE_UNINITIALIZED_ELEMENT,
+                                 true, cmp_func_idx, check_func_idx_succ)))
+            goto fail;
+    }
     /* Load function type index */
     if (!(ftype_idx_ptr = LLVMBuildInBoundsGEP2(
               comp_ctx->builder, I32_TYPE, func_ctx->func_type_indexes,
@@ -1557,7 +1637,10 @@ fail:
 bool
 aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
-    PUSH_I32(REF_NULL);
+    if (comp_ctx->enable_gc)
+        PUSH_REF(GC_REF_NULL);
+    else
+        PUSH_I32(REF_NULL);
 
     return true;
 fail:
@@ -1567,14 +1650,24 @@ fail:
 bool
 aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
-    LLVMValueRef lhs, res;
+    LLVMValueRef lhs = NULL, res;
 
-    POP_I32(lhs);
+    if (comp_ctx->enable_gc) {
+        POP_REF(lhs);
 
-    if (!(res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, lhs, REF_NULL,
-                              "cmp_w_null"))) {
-        HANDLE_FAILURE("LLVMBuildICmp");
-        goto fail;
+        if (!(res = LLVMBuildIsNull(comp_ctx->builder, lhs, "lhs is null"))) {
+            HANDLE_FAILURE("LLVMBuildIsNull");
+            goto fail;
+        }
+    }
+    else {
+        POP_I32(lhs);
+
+        if (!(res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, lhs, REF_NULL,
+                                  "cmp_w_null"))) {
+            HANDLE_FAILURE("LLVMBuildICmp");
+            goto fail;
+        }
     }
 
     if (!(res = LLVMBuildZExt(comp_ctx->builder, res, I32_TYPE, "r_i"))) {
@@ -1594,13 +1687,25 @@ aot_compile_op_ref_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                         uint32 func_idx)
 {
     LLVMValueRef ref_idx;
-
     if (!(ref_idx = I32_CONST(func_idx))) {
         HANDLE_FAILURE("LLVMConstInt");
         goto fail;
     }
+#if WASM_ENABLE_GC != 0
+    LLVMValueRef gc_obj;
+    if (comp_ctx->enable_gc) {
+        if (!aot_call_aot_create_func_obj(comp_ctx, func_ctx, ref_idx,
+                                          &gc_obj)) {
+            goto fail;
+        }
 
-    PUSH_I32(ref_idx);
+        PUSH_REF(gc_obj);
+    }
+    else
+#endif
+    {
+        PUSH_I32(ref_idx);
+    }
 
     return true;
 fail:

+ 107 - 0
core/iwasm/compilation/aot_emit_gc.c

@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "aot_emit_gc.h"
+
+#if WASM_ENABLE_GC != 0
+
+#define BUILD_ISNULL(ptr, res, name)                                  \
+    do {                                                              \
+        if (!(res = LLVMBuildIsNull(comp_ctx->builder, ptr, name))) { \
+            aot_set_last_error("llvm build isnull failed.");          \
+            goto fail;                                                \
+        }                                                             \
+    } while (0)
+
+#define BUILD_ISNOTNULL(ptr, res, name)                                  \
+    do {                                                                 \
+        if (!(res = LLVMBuildIsNotNull(comp_ctx->builder, ptr, name))) { \
+            aot_set_last_error("llvm build isnotnull failed.");          \
+            goto fail;                                                   \
+        }                                                                \
+    } while (0)
+
+#define BUILD_ICMP(op, left, right, res, name)                                \
+    do {                                                                      \
+        if (!(res =                                                           \
+                  LLVMBuildICmp(comp_ctx->builder, op, left, right, name))) { \
+            aot_set_last_error("llvm build icmp failed.");                    \
+            goto fail;                                                        \
+        }                                                                     \
+    } while (0)
+
+#define ADD_BASIC_BLOCK(block, name)                                          \
+    do {                                                                      \
+        if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context,        \
+                                                    func_ctx->func, name))) { \
+            aot_set_last_error("llvm add basic block failed.");               \
+            goto fail;                                                        \
+        }                                                                     \
+    } while (0)
+
+bool
+aot_call_aot_create_func_obj(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                             LLVMValueRef func_idx, LLVMValueRef *p_gc_obj)
+{
+    LLVMValueRef gc_obj, cmp_gc_obj, param_values[5], func, value;
+    LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
+    AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
+    LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
+    LLVMBasicBlockRef init_gc_obj_fail, init_gc_obj_succ;
+
+    param_types[0] = INT8_PTR_TYPE;
+    param_types[1] = I32_TYPE;
+    param_types[2] = INT8_TYPE;
+    param_types[3] = INT8_PTR_TYPE;
+    param_types[4] = I32_TYPE;
+    ret_type = GC_REF_TYPE;
+
+    if (comp_ctx->is_jit_mode)
+        GET_AOT_FUNCTION(llvm_jit_create_func_obj, 5);
+    else
+        GET_AOT_FUNCTION(aot_create_func_obj, 5);
+
+    /* Call function llvm_jit/aot_create_func_obj()  */
+    param_values[0] = func_ctx->aot_inst;
+    param_values[1] = func_idx;
+    param_values[2] = I8_CONST(1);
+    param_values[3] = I8_PTR_NULL;
+    param_values[4] = I32_ZERO;
+    if (!(gc_obj = LLVMBuildCall2(comp_ctx->builder, func_type, func,
+                                  param_values, 5, "call"))) {
+        aot_set_last_error("llvm build call failed.");
+        return false;
+    }
+
+    BUILD_ISNOTNULL(gc_obj, cmp_gc_obj, "gc_obj_not_null");
+
+    ADD_BASIC_BLOCK(init_gc_obj_fail, "init_gc_obj_fail");
+    ADD_BASIC_BLOCK(init_gc_obj_succ, "init_gc_obj_success");
+
+    LLVMMoveBasicBlockAfter(init_gc_obj_fail, block_curr);
+    LLVMMoveBasicBlockAfter(init_gc_obj_succ, block_curr);
+
+    if (!LLVMBuildCondBr(comp_ctx->builder, cmp_gc_obj, init_gc_obj_succ,
+                         init_gc_obj_fail)) {
+        aot_set_last_error("llvm build cond br failed.");
+        goto fail;
+    }
+
+    /* If init gc_obj failed, return this function
+       so the runtime can catch the exception */
+    LLVMPositionBuilderAtEnd(comp_ctx->builder, init_gc_obj_fail);
+    if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) {
+        goto fail;
+    }
+
+    LLVMPositionBuilderAtEnd(comp_ctx->builder, init_gc_obj_succ);
+    *p_gc_obj = gc_obj;
+
+    return true;
+fail:
+    return false;
+}
+
+#endif /* end of WASM_ENABLE_GC != 0 */

+ 28 - 0
core/iwasm/compilation/aot_emit_gc.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _AOT_EMIT_GC_H_
+#define _AOT_EMIT_GC_H_
+
+#include "aot_compiler.h"
+#include "aot_runtime.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if WASM_ENABLE_GC != 0
+
+bool
+aot_call_aot_create_func_obj(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                             LLVMValueRef func_idx, LLVMValueRef *p_gc_obj);
+
+#endif
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif /* end of _AOT_EMIT_GC_H_ */

+ 14 - 4
core/iwasm/compilation/aot_emit_parametric.c

@@ -44,17 +44,27 @@ pop_value_from_wasm_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     wasm_runtime_free(aot_value);
 
-    /* is_32: i32, f32, ref.func, ref.extern, v128 */
+    /* is_32: i32, f32, ref.func, ref.extern, v128, ref types if gc is
+     * enabled and system is 32-bit */
     if (is_32
         && !(type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
              || type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF
-             || type == VALUE_TYPE_V128)) {
+             || type == VALUE_TYPE_V128
+#if WASM_ENABLE_GC != 0 && UINTPTR_MAX != UINT64_MAX
+             || (comp_ctx->enable_gc && type == VALUE_TYPE_GC_REF)
+#endif
+                 )) {
         aot_set_last_error("invalid WASM stack data type.");
         return false;
     }
 
-    /* !is_32: i64, f64 */
-    if (!is_32 && !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)) {
+    /* !is_32: i64, f64, ref types if gc is enabled and system is 64-bit */
+    if (!is_32
+        && !(type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64
+#if WASM_ENABLE_GC != 0 && UINTPTR_MAX == UINT64_MAX
+             || (comp_ctx->enable_gc && type == VALUE_TYPE_GC_REF)
+#endif
+                 )) {
         aot_set_last_error("invalid WASM stack data type.");
         return false;
     }

+ 111 - 37
core/iwasm/compilation/aot_emit_table.c

@@ -6,6 +6,9 @@
 #include "aot_emit_table.h"
 #include "aot_emit_exception.h"
 #include "../aot/aot_runtime.h"
+#if WASM_ENABLE_GC != 0
+#include "aot_emit_gc.h"
+#endif
 
 uint64
 get_tbl_inst_offset(const AOTCompContext *comp_ctx,
@@ -46,7 +49,7 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx,
     return offset;
 }
 
-#if WASM_ENABLE_REF_TYPES != 0
+#if WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0
 
 LLVMValueRef
 aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
@@ -199,27 +202,39 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    /* Load function index */
-    if (!(table_elem =
-              LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE, table_elem,
-                                    &elem_idx, 1, "table_elem"))) {
-        HANDLE_FAILURE("LLVMBuildNUWAdd");
-        goto fail;
-    }
+    /* Load function object reference or function index */
+    if (comp_ctx->enable_gc) {
+        if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, GC_REF_TYPE,
+                                                 table_elem, &elem_idx, 1,
+                                                 "table_elem"))) {
+            HANDLE_FAILURE("LLVMBuildNUWAdd");
+            goto fail;
+        }
 
-    if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, INTPTR_TYPE, table_elem,
-                                    "func_idx"))) {
-        HANDLE_FAILURE("LLVMBuildLoad");
-        goto fail;
+        PUSH_REF(table_elem);
     }
+    else {
+        if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE,
+                                                 table_elem, &elem_idx, 1,
+                                                 "table_elem"))) {
+            HANDLE_FAILURE("LLVMBuildNUWAdd");
+            goto fail;
+        }
 
-    if (!(func_idx = LLVMBuildIntCast2(comp_ctx->builder, func_idx, I32_TYPE,
-                                       true, "func_idx_i32"))) {
-        HANDLE_FAILURE("LLVMBuildIntCast");
-        goto fail;
-    }
+        if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, INTPTR_TYPE,
+                                        table_elem, "func_idx"))) {
+            HANDLE_FAILURE("LLVMBuildLoad");
+            goto fail;
+        }
+
+        if (!(func_idx = LLVMBuildIntCast2(comp_ctx->builder, func_idx,
+                                           I32_TYPE, true, "func_idx_i32"))) {
+            HANDLE_FAILURE("LLVMBuildIntCast");
+            goto fail;
+        }
 
-    PUSH_I32(func_idx);
+        PUSH_I32(func_idx);
+    }
 
     return true;
 fail:
@@ -232,14 +247,18 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     LLVMValueRef val, elem_idx, offset, table_elem;
 
-    POP_I32(val);
+    if (comp_ctx->enable_gc)
+        POP_REF(val);
+    else
+        POP_I32(val);
+
     POP_I32(elem_idx);
 
     if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
         goto fail;
     }
 
-    /* load data as i32* */
+    /* load data as gc_obj_ref* or i32* */
     if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
                              + offsetof(AOTTableInstance, elems)))) {
         HANDLE_FAILURE("LLVMConstInt");
@@ -253,18 +272,37 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
-                                        INTPTR_PTR_TYPE, "table_elem_i32p"))) {
-        HANDLE_FAILURE("LLVMBuildBitCast");
-        goto fail;
-    }
-
-    /* Load function index */
-    if (!(table_elem =
-              LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE, table_elem,
-                                    &elem_idx, 1, "table_elem"))) {
-        HANDLE_FAILURE("LLVMBuildInBoundsGEP");
-        goto fail;
+    if (comp_ctx->enable_gc) {
+        if (!(table_elem =
+                  LLVMBuildBitCast(comp_ctx->builder, table_elem,
+                                   GC_REF_PTR_TYPE, "table_elem_ptr"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
+
+        /* Load function object reference */
+        if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, GC_REF_TYPE,
+                                                 table_elem, &elem_idx, 1,
+                                                 "table_elem"))) {
+            HANDLE_FAILURE("LLVMBuildInBoundsGEP");
+            goto fail;
+        }
+    }
+    else {
+        if (!(table_elem =
+                  LLVMBuildBitCast(comp_ctx->builder, table_elem,
+                                   INTPTR_PTR_TYPE, "table_elem_i32p"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
+
+        /* Load function index */
+        if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE,
+                                                 table_elem, &elem_idx, 1,
+                                                 "table_elem"))) {
+            HANDLE_FAILURE("LLVMBuildInBoundsGEP");
+            goto fail;
+        }
     }
 
     if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
@@ -428,7 +466,7 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     param_types[0] = INT8_PTR_TYPE;
     param_types[1] = I32_TYPE;
     param_types[2] = I32_TYPE;
-    param_types[3] = I32_TYPE;
+    param_types[3] = INT8_PTR_TYPE;
     ret_type = I32_TYPE;
 
     if (comp_ctx->is_jit_mode)
@@ -446,7 +484,25 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* n */
     POP_I32(param_values[2]);
     /* v */
-    POP_I32(param_values[3]);
+
+    if (comp_ctx->enable_gc) {
+        POP_REF(param_values[3]);
+        if (!(param_values[3] =
+                  LLVMBuildBitCast(comp_ctx->builder, param_values[3],
+                                   INT8_PTR_TYPE, "table_elem_i8p"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
+    }
+    else {
+        POP_I32(param_values[3]);
+        if (!(param_values[3] =
+                  LLVMBuildIntToPtr(comp_ctx->builder, param_values[3],
+                                    INT8_PTR_TYPE, "table_elem_i8p"))) {
+            HANDLE_FAILURE("LLVMBuildIntToPtr");
+            goto fail;
+        }
+    }
 
     if (!(ret = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
                                4, "table_grow"))) {
@@ -471,7 +527,7 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     param_types[0] = INT8_PTR_TYPE;
     param_types[1] = I32_TYPE;
     param_types[2] = I32_TYPE;
-    param_types[3] = I32_TYPE;
+    param_types[3] = INT8_PTR_TYPE;
     param_types[4] = I32_TYPE;
     ret_type = VOID_TYPE;
 
@@ -490,7 +546,25 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* n */
     POP_I32(param_values[2]);
     /* v */
-    POP_I32(param_values[3]);
+
+    if (comp_ctx->enable_gc) {
+        POP_REF(param_values[3]);
+        if (!(param_values[3] =
+                  LLVMBuildBitCast(comp_ctx->builder, param_values[3],
+                                   INT8_PTR_TYPE, "table_elem_i8p"))) {
+            HANDLE_FAILURE("LLVMBuildBitCast");
+            goto fail;
+        }
+    }
+    else {
+        POP_I32(param_values[3]);
+        if (!(param_values[3] =
+                  LLVMBuildIntToPtr(comp_ctx->builder, param_values[3],
+                                    INT8_PTR_TYPE, "table_elem_i8p"))) {
+            HANDLE_FAILURE("LLVMBuildIntToPtr");
+            goto fail;
+        }
+    }
     /* i */
     POP_I32(param_values[4]);
 
@@ -506,4 +580,4 @@ fail:
     return false;
 }
 
-#endif /*  WASM_ENABLE_REF_TYPES != 0 */
+#endif /*  WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC !=0 */

+ 17 - 7
core/iwasm/compilation/aot_emit_variable.c

@@ -17,13 +17,23 @@
     } while (0)
 
 static uint8
-get_local_type(AOTFuncContext *func_ctx, uint32 local_idx)
+get_local_type(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+               uint32 local_idx)
 {
     AOTFunc *aot_func = func_ctx->aot_func;
     uint32 param_count = aot_func->func_type->param_count;
-    return local_idx < param_count
-               ? aot_func->func_type->types[local_idx]
-               : aot_func->local_types[local_idx - param_count];
+    uint8 local_type;
+
+    local_type = local_idx < param_count
+                     ? aot_func->func_type->types[local_idx]
+                     : aot_func->local_types[local_idx - param_count];
+
+#if WASM_ENABLE_GC != 0
+    if (comp_ctx->enable_gc && wasm_is_type_reftype(local_type))
+        local_type = VALUE_TYPE_GC_REF;
+#endif
+
+    return local_type;
 }
 
 bool
@@ -37,7 +47,7 @@ aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     CHECK_LOCAL(local_idx);
 
-    local_type = get_local_type(func_ctx, local_idx);
+    local_type = get_local_type(comp_ctx, func_ctx, local_idx);
 
     snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
     if (!(value = LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(local_type),
@@ -66,7 +76,7 @@ aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     CHECK_LOCAL(local_idx);
 
-    POP(value, get_local_type(func_ctx, local_idx));
+    POP(value, get_local_type(comp_ctx, func_ctx, local_idx));
 
     if (!LLVMBuildStore(comp_ctx->builder, value,
                         func_ctx->locals[local_idx])) {
@@ -90,7 +100,7 @@ aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     CHECK_LOCAL(local_idx);
 
-    type = get_local_type(func_ctx, local_idx);
+    type = get_local_type(comp_ctx, func_ctx, local_idx);
 
     POP(value, type);
 

+ 14 - 1
core/iwasm/compilation/aot_llvm.c

@@ -42,6 +42,8 @@ wasm_type_to_llvm_type(const AOTLLVMTypes *llvm_types, uint8 wasm_type)
             return llvm_types->i64x2_vec_type;
         case VALUE_TYPE_VOID:
             return llvm_types->void_type;
+        case VALUE_TYPE_GC_REF:
+            return llvm_types->gc_ref_type;
         default:
             break;
     }
@@ -1744,6 +1746,9 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context,
         basic_types->intptr_ptr_type = basic_types->int64_ptr_type;
     }
 
+    basic_types->gc_ref_type = LLVMPointerType(basic_types->void_type, 0);
+    basic_types->gc_ref_ptr_type = LLVMPointerType(basic_types->gc_ref_type, 0);
+
     return (basic_types->int8_ptr_type && basic_types->int8_pptr_type
             && basic_types->int16_ptr_type && basic_types->int32_ptr_type
             && basic_types->int64_ptr_type && basic_types->intptr_type
@@ -1753,7 +1758,8 @@ aot_set_llvm_basic_types(AOTLLVMTypes *basic_types, LLVMContextRef context,
             && basic_types->i64x2_vec_type && basic_types->f32x4_vec_type
             && basic_types->f64x2_vec_type && basic_types->i1x2_vec_type
             && basic_types->meta_data_type && basic_types->funcref_type
-            && basic_types->externref_type)
+            && basic_types->externref_type && basic_types->gc_ref_type
+            && basic_types->gc_ref_ptr_type)
                ? true
                : false;
 }
@@ -1843,6 +1849,13 @@ aot_create_llvm_consts(AOTLLVMConsts *consts, AOTCompContext *comp_ctx)
     CREATE_VEC_ZERO_MASK(2)
 #undef CREATE_VEC_ZERO_MASK
 
+    if (!(consts->gc_ref_null =
+              LLVMConstNull(comp_ctx->basic_types.gc_ref_type)))
+        return false;
+    if (!(consts->i8_ptr_null =
+              LLVMConstNull(comp_ctx->basic_types.int8_ptr_type)))
+        return false;
+
     return true;
 }
 

+ 4 - 0
core/iwasm/compilation/aot_llvm.h

@@ -231,6 +231,8 @@ typedef struct AOTLLVMTypes {
 
     LLVMTypeRef funcref_type;
     LLVMTypeRef externref_type;
+    LLVMTypeRef gc_ref_type;
+    LLVMTypeRef gc_ref_ptr_type;
 } AOTLLVMTypes;
 
 typedef struct AOTLLVMConsts {
@@ -280,6 +282,8 @@ typedef struct AOTLLVMConsts {
     LLVMValueRef i32x8_zero;
     LLVMValueRef i32x4_zero;
     LLVMValueRef i32x2_zero;
+    LLVMValueRef gc_ref_null;
+    LLVMValueRef i8_ptr_null;
 } AOTLLVMConsts;
 
 /**

+ 7 - 0
core/iwasm/interpreter/wasm.h

@@ -74,6 +74,13 @@ extern "C" {
  * nullfuncref, nullexternref and nullref
  */
 #define VALUE_TYPE_ANY 0x42
+/**
+ * Used by wamr compiler to represent object ref types,
+ * including func object ref, externref object ref,
+ * internal object ref, eq obect ref, i31 object ref,
+ * struct object ref, array obect ref
+ */
+#define VALUE_TYPE_GC_REF 0x43
 
 #define DEFAULT_NUM_BYTES_PER_PAGE 65536
 #define DEFAULT_MAX_PAGES 65536

+ 13 - 0
core/iwasm/interpreter/wasm_runtime.c

@@ -3777,6 +3777,19 @@ llvm_jit_free_frame(WASMExecEnv *exec_env)
 #endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 \
           || WASM_ENABLE_PERF_PROFILING != 0 */
 
+#if WASM_ENABLE_GC != 0
+void *
+llvm_jit_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx,
+                         bool throw_exce, char *error_buf,
+                         uint32 error_buf_size)
+{
+    bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
+
+    return wasm_create_func_obj(module_inst, func_idx, throw_exce, error_buf,
+                                error_buf_size);
+}
+#endif /* end of WASM_ENABLE_GC != 0 */
+
 #endif /* end of WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 */
 
 #if WASM_ENABLE_LIBC_WASI != 0 && WASM_ENABLE_MULTI_MODULE != 0

+ 9 - 0
core/iwasm/interpreter/wasm_runtime.h

@@ -68,6 +68,7 @@ typedef enum WASMExceptionID {
     EXCE_OPERAND_STACK_OVERFLOW,
     EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC,
     EXCE_ALREADY_THROWN,
+    EXCE_NULL_GC_REF,
     EXCE_NUM,
 } WASMExceptionID;
 
@@ -575,6 +576,7 @@ wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx,
 
 bool
 wasm_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap);
+
 #endif
 
 static inline WASMTableInstance *
@@ -692,6 +694,13 @@ llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index);
 void
 llvm_jit_free_frame(WASMExecEnv *exec_env);
 #endif
+
+#if WASM_ENABLE_GC != 0
+void *
+llvm_jit_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx,
+                         bool throw_exce, char *error_buf,
+                         uint32 error_buf_size);
+#endif
 #endif /* end of WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 */
 
 #if WASM_ENABLE_LIBC_WASI != 0 && WASM_ENABLE_MULTI_MODULE != 0