Răsfoiți Sursa

Fix GC AOT issues (#2640)

Wenyong Huang 2 ani în urmă
părinte
comite
3a31e517a4

+ 3 - 1
.github/workflows/compilation_on_android_ubuntu.yml

@@ -507,7 +507,9 @@ jobs:
             test_option: $MULTI_MODULES_TEST_OPTIONS
           - running_mode: "multi-tier-jit"
             test_option: $SIMD_TEST_OPTIONS
-          # jit don't support GC
+          # aot and jit don't support GC
+          - running_mode: "aot"
+            test_option: $GC_TEST_OPTIONS
           - running_mode: "jit"
             test_option: $GC_TEST_OPTIONS
           - running_mode: "multi-tier-jit"

+ 4 - 0
core/iwasm/common/wasm_runtime_common.c

@@ -2492,6 +2492,10 @@ static const char *exception_msgs[] = {
     "out of bounds table access",     /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */
     "wasm operand stack overflow",    /* EXCE_OPERAND_STACK_OVERFLOW */
     "failed to compile fast jit function", /* EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */
+    "null GC object",                 /* EXCE_NULL_GC_REF */
+    "failed to cast GC object",       /* EXCE_TYPE_NONCASTABLE */
+    "GC array index out of bounds",   /* EXCE_ARRAY_OOB */
+    "failed to create GC object",     /* EXCE_FAILED_TO_CREATE_GC_OBJ */
     "",                               /* EXCE_ALREADY_THROWN */
 };
 /* clang-format on */

+ 145 - 20
core/iwasm/compilation/aot_compiler.c

@@ -109,7 +109,7 @@ read_leb(const uint8 *buf, const uint8 *buf_end, uint32 *p_offset,
     } while (0)
 
 /**
- * Since Wamrc uses a full feature Wasm loader,
+ * Since wamrc uses a full feature Wasm loader,
  * add a post-validator here to run checks according
  * to options, like enable_tail_call, enable_ref_types,
  * and so on.
@@ -117,7 +117,7 @@ read_leb(const uint8 *buf, const uint8 *buf_end, uint32 *p_offset,
 static bool
 aot_validate_wasm(AOTCompContext *comp_ctx)
 {
-    if (!comp_ctx->enable_ref_types) {
+    if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
         /* Doesn't support multiple tables unless enabling reference type */
         if (comp_ctx->comp_data->import_table_count
                 + comp_ctx->comp_data->table_count
@@ -196,6 +196,18 @@ store_value(AOTCompContext *comp_ctx, LLVMValueRef value, uint8 value_type,
         case VALUE_TYPE_V128:
             value_ptr_type = V128_PTR_TYPE;
             break;
+#if WASM_ENABLE_GC != 0
+        case REF_TYPE_STRUCTREF:
+        case REF_TYPE_ARRAYREF:
+        case REF_TYPE_I31REF:
+        case REF_TYPE_EQREF:
+        case REF_TYPE_ANYREF:
+        case REF_TYPE_HT_NULLABLE:
+        case REF_TYPE_HT_NON_NULLABLE:
+        case VALUE_TYPE_GC_REF:
+            value_ptr_type = GC_REF_PTR_TYPE;
+            break;
+#endif
         default:
             bh_assert(0);
             break;
@@ -235,8 +247,6 @@ aot_gen_commit_values(AOTCompFrame *frame)
 
         switch (p->type) {
             case VALUE_TYPE_I32:
-            case VALUE_TYPE_FUNCREF:
-            case VALUE_TYPE_EXTERNREF:
                 if (!store_value(comp_ctx, p->value, VALUE_TYPE_I32,
                                  func_ctx->cur_frame,
                                  offset_of_local(comp_ctx, n)))
@@ -282,6 +292,45 @@ aot_gen_commit_values(AOTCompFrame *frame)
                                  offset_of_local(comp_ctx, n)))
                     return false;
                 break;
+            case VALUE_TYPE_FUNCREF:
+            case VALUE_TYPE_EXTERNREF:
+                if (comp_ctx->enable_ref_types) {
+                    if (!store_value(comp_ctx, p->value, VALUE_TYPE_I32,
+                                     func_ctx->cur_frame,
+                                     offset_of_local(comp_ctx, n)))
+                        return false;
+                }
+#if WASM_ENABLE_GC != 0
+                else if (comp_ctx->enable_gc) {
+                    if (comp_ctx->pointer_size == sizeof(uint64))
+                        (++p)->dirty = 0;
+                    if (!store_value(comp_ctx, p->value, VALUE_TYPE_GC_REF,
+                                     func_ctx->cur_frame,
+                                     offset_of_local(comp_ctx, n)))
+                        return false;
+                }
+#endif
+                else {
+                    bh_assert(0);
+                }
+                break;
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case VALUE_TYPE_GC_REF:
+                if (comp_ctx->pointer_size == sizeof(uint64))
+                    (++p)->dirty = 0;
+                if (!store_value(comp_ctx, p->value, VALUE_TYPE_GC_REF,
+                                 func_ctx->cur_frame,
+                                 offset_of_local(comp_ctx, n)))
+                    return false;
+                break;
+#endif
             default:
                 bh_assert(0);
                 break;
@@ -491,9 +540,38 @@ init_comp_frame(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                 break;
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_EXTERNREF:
-                set_local_ref(comp_ctx->aot_frame, n, local_value, local_type);
-                n++;
+            {
+                if (comp_ctx->enable_ref_types) {
+                    set_local_ref(comp_ctx->aot_frame, n, local_value,
+                                  local_type);
+                    n++;
+                }
+#if WASM_ENABLE_GC != 0
+                else if (comp_ctx->enable_gc) {
+                    set_local_gc_ref(comp_ctx->aot_frame, n, local_value,
+                                     VALUE_TYPE_GC_REF);
+                    n += comp_ctx->pointer_size / sizeof(uint32);
+                }
+#endif
+                else {
+                    bh_assert(0);
+                }
+                break;
+            }
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+                bh_assert(comp_ctx->enable_gc);
+                set_local_gc_ref(comp_ctx->aot_frame, n, local_value,
+                                 VALUE_TYPE_GC_REF);
+                n += comp_ctx->pointer_size / sizeof(uint32);
                 break;
+#endif
             default:
                 bh_assert(0);
                 break;
@@ -528,9 +606,37 @@ init_comp_frame(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
                 break;
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_EXTERNREF:
-                set_local_ref(comp_ctx->aot_frame, n, I32_ZERO, local_type);
-                n++;
+            {
+                if (comp_ctx->enable_ref_types) {
+                    set_local_ref(comp_ctx->aot_frame, n, I32_ZERO, local_type);
+                    n++;
+                }
+#if WASM_ENABLE_GC != 0
+                else if (comp_ctx->enable_gc) {
+                    set_local_gc_ref(comp_ctx->aot_frame, n, GC_REF_NULL,
+                                     VALUE_TYPE_GC_REF);
+                    n += comp_ctx->pointer_size / sizeof(uint32);
+                }
+#endif
+                else {
+                    bh_assert(0);
+                }
                 break;
+            }
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+                bh_assert(comp_ctx->enable_gc);
+                set_local_gc_ref(comp_ctx->aot_frame, n, GC_REF_NULL,
+                                 VALUE_TYPE_GC_REF);
+                n += comp_ctx->pointer_size / sizeof(uint32);
+                break;
+#endif
             default:
                 bh_assert(0);
                 break;
@@ -605,7 +711,14 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                     || value_type == VALUE_TYPE_V128
                     || value_type == VALUE_TYPE_VOID
                     || value_type == VALUE_TYPE_FUNCREF
-                    || value_type == VALUE_TYPE_EXTERNREF) {
+                    || value_type == VALUE_TYPE_EXTERNREF
+                    || value_type == REF_TYPE_STRUCTREF
+                    || value_type == REF_TYPE_ARRAYREF
+                    || value_type == REF_TYPE_I31REF
+                    || value_type == REF_TYPE_EQREF
+                    || value_type == REF_TYPE_ANYREF
+                    || value_type == REF_TYPE_HT_NULLABLE
+                    || value_type == REF_TYPE_HT_NON_NULLABLE) {
                     param_count = 0;
                     param_types = NULL;
                     if (value_type == VALUE_TYPE_VOID) {
@@ -851,8 +964,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
                         comp_ctx, func_ctx,
                         (type_idx != VALUE_TYPE_I64)
                             && (type_idx != VALUE_TYPE_F64)
-#if WASM_ENABLE_GC != 0 && UINTPTR_MAX == UINT64_MAX
+#if WASM_ENABLE_GC != 0
                             && !(comp_ctx->enable_gc
+                                 && comp_ctx->pointer_size == sizeof(uint64)
                                  && wasm_is_type_reftype(type_idx))
 #endif
                             ))
@@ -1118,18 +1232,28 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
 
                     case WASM_OP_REF_TEST:
                     case WASM_OP_REF_TEST_NULLABLE:
+                    {
+                        int32 heap_type;
+
+                        read_leb_int32(frame_ip, frame_ip_end, heap_type);
+                        if (!aot_compile_op_ref_test(
+                                comp_ctx, func_ctx, heap_type,
+                                opcode == WASM_OP_REF_TEST_NULLABLE ? true
+                                                                    : false))
+                            return false;
+                        break;
+                    }
+
                     case WASM_OP_REF_CAST:
                     case WASM_OP_REF_CAST_NULLABLE:
                     {
                         int32 heap_type;
 
                         read_leb_int32(frame_ip, frame_ip_end, heap_type);
-                        if (!aot_compile_op_ref_test(
+                        if (!aot_compile_op_ref_cast(
                                 comp_ctx, func_ctx, heap_type,
-                                opcode == WASM_OP_REF_TEST_NULLABLE
-                                    || opcode == WASM_OP_REF_CAST_NULLABLE,
-                                opcode == WASM_OP_REF_CAST
-                                    || opcode == WASM_OP_REF_CAST_NULLABLE))
+                                opcode == WASM_OP_REF_CAST_NULLABLE ? true
+                                                                    : false))
                             return false;
                         break;
                     }
@@ -3237,22 +3361,23 @@ unsupport_simd:
 #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");
+                       "try removing --disable-ref-types option "
+                       "or adding --enable-gc option");
     return false;
 #endif
 
 #if WASM_ENABLE_GC != 0
 unsupport_gc:
-    aot_set_last_error("garbage collection instruction was found, "
-                       "try adding --enable-gc");
+    aot_set_last_error("GC instruction was found, "
+                       "try adding --enable-gc option");
     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");
+        "reference type or gc instruction was found, try removing "
+        "--disable-ref-types option or adding --enable-gc option");
     return false;
 #endif
 

+ 51 - 20
core/iwasm/compilation/aot_compiler.h

@@ -222,6 +222,19 @@ push_ref(AOTCompFrame *frame, AOTValue *aot_value)
     push_32bit(frame, aot_value);
 }
 
+#if WASM_ENABLE_GC != 0
+static inline void
+push_gc_ref(AOTCompFrame *frame, AOTValue *aot_value)
+{
+    bh_assert(frame->comp_ctx->enable_gc);
+    bh_assert(aot_value->type == VALUE_TYPE_GC_REF);
+    if (frame->comp_ctx->pointer_size == sizeof(uint64))
+        push_64bit(frame, aot_value);
+    else
+        push_32bit(frame, aot_value);
+}
+#endif
+
 static inline void
 pop_i32(AOTCompFrame *frame)
 {
@@ -283,6 +296,20 @@ pop_ref(AOTCompFrame *frame)
     memset(frame->sp, 0, sizeof(*frame->sp) * 1);
 }
 
+#if WASM_ENABLE_GC != 0
+static inline void
+pop_gc_ref(AOTCompFrame *frame)
+{
+    uint32 i;
+    for (i = 0; i < frame->comp_ctx->pointer_size / sizeof(uint32); i++) {
+        bh_assert(frame->sp - frame->lp >= 1);
+        bh_assert((frame->sp - 1)->type == VALUE_TYPE_GC_REF);
+        frame->sp -= 1;
+        memset(frame->sp, 0, sizeof(*frame->sp) * 1);
+    }
+}
+#endif
+
 static inline void
 pop(AOTCompFrame *frame, uint32 n)
 {
@@ -349,6 +376,23 @@ set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
     frame->lp[n].dirty = 1;
 }
 
+#if WASM_ENABLE_GC != 0
+static inline void
+set_local_gc_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
+{
+    bh_assert(frame->comp_ctx->enable_gc);
+    bh_assert(ref_type == VALUE_TYPE_GC_REF);
+    frame->lp[n].value = value;
+    frame->lp[n].type = ref_type;
+    frame->lp[n].dirty = 1;
+    if (frame->comp_ctx->pointer_size == sizeof(uint64)) {
+        frame->lp[n + 1].value = value;
+        frame->lp[n + 1].type = ref_type;
+        frame->lp[n + 1].dirty = 1;
+    }
+}
+#endif
+
 #define CHECK_STACK()                                          \
     do {                                                       \
         if (!func_ctx->block_stack.block_list_end) {           \
@@ -364,7 +408,7 @@ set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
 
 #if WASM_ENABLE_GC != 0
 
-#define GET_REF_FROM_STACK(llvm_value)                                        \
+#define GET_GC_REF_FROM_STACK(llvm_value)                                     \
     do {                                                                      \
         AOTValue *aot_value;                                                  \
         CHECK_STACK();                                                        \
@@ -423,15 +467,8 @@ set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_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_GC_REF(v) POP(v, VALUE_TYPE_GC_REF)
+
 #define POP_COND(llvm_value)                                                   \
     do {                                                                       \
         AOTValue *aot_value;                                                   \
@@ -486,18 +523,10 @@ set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_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 PUSH_GC_REF(v) PUSH(v, VALUE_TYPE_GC_REF)
 
 #define TO_LLVM_TYPE(wasm_type) \
-    wasm_type_to_llvm_type(&comp_ctx->basic_types, wasm_type)
+    wasm_type_to_llvm_type(comp_ctx, &comp_ctx->basic_types, wasm_type)
 
 #define I32_TYPE comp_ctx->basic_types.int32_type
 #define I64_TYPE comp_ctx->basic_types.int64_type
@@ -535,6 +564,8 @@ set_local_ref(AOTCompFrame *frame, int n, LLVMValueRef value, uint8 ref_type)
 #define I8_CONST(v) LLVMConstInt(INT8_TYPE, v, true)
 
 #define LLVM_CONST(name) (comp_ctx->llvm_consts.name)
+#define I1_ZERO LLVM_CONST(i1_zero)
+#define I1_ONE LLVM_CONST(i1_one)
 #define I8_ZERO LLVM_CONST(i8_zero)
 #define I32_ZERO LLVM_CONST(i32_zero)
 #define I64_ZERO LLVM_CONST(i64_zero)

+ 76 - 28
core/iwasm/compilation/aot_emit_aot_file.c

@@ -384,14 +384,28 @@ static uint32
 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 */
+     * + ref_type_map_count + types + context of ref_type_map */
     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);
+        uint32 size = 0;
+
+        /* type flag */
+        size += sizeof(func_type->base_type.type_flag);
+        /* is_sub_final */
+        size += sizeof(uint16);
+        /* parent_type_idx */
+        size += sizeof(func_type->base_type.parent_type_idx);
+        /* param count */
+        size += sizeof(func_type->param_count);
+        /* result count */
+        size += sizeof(func_type->result_count);
+        /* ref_type_map_count */
+        size += sizeof(func_type->ref_type_map_count);
+        /* param and result types */
+        size += func_type->param_count + func_type->result_count;
+        /* ref_type_map */
+        size += func_type->ref_type_map_count * 8;
+
+        return size;
     }
     else {
         /* type flag + is_sub_final + parent_type_idx + param count + result
@@ -400,6 +414,50 @@ get_func_type_size(AOTCompContext *comp_ctx, AOTFuncType *func_type)
                + func_type->result_count;
     }
 }
+
+static uint32
+get_struct_type_size(AOTCompContext *comp_ctx, AOTStructType *struct_type)
+{
+    uint32 size = 0;
+    /* type flag + is_sub_final + parent_type_idx + field count + fields */
+
+    /* type flag */
+    size += sizeof(struct_type->base_type.type_flag);
+    /* is_sub_final */
+    size += sizeof(uint16);
+    /* parent_type_idx */
+    size += sizeof(struct_type->base_type.parent_type_idx);
+    /* field count */
+    size += sizeof(struct_type->field_count);
+    /* field types */
+    size += struct_type->field_count * 3;
+    /* ref_type_map_count */
+    size += sizeof(struct_type->ref_type_map_count);
+    /* ref_type_map */
+    size += struct_type->ref_type_map_count * 8;
+    return size;
+}
+
+static uint32
+get_array_type_size(AOTCompContext *comp_ctx, AOTArrayType *array_type)
+{
+    uint32 size = 0;
+    /* type flag + is_sub_final + parent_type_idx + element type + length */
+
+    /* type flag */
+    size += sizeof(array_type->base_type.type_flag);
+    /* is_sub_final */
+    size += sizeof(uint16);
+    /* parent_type_idx */
+    size += sizeof(array_type->base_type.parent_type_idx);
+    /* elem flags */
+    size += sizeof(array_type->elem_flags);
+    /* elem type */
+    size += sizeof(array_type->elem_type);
+
+    return size;
+}
+
 #else
 static uint32
 get_func_type_size(AOTCompContext *comp_ctx, AOTFuncType *func_type)
@@ -425,6 +483,14 @@ get_func_type_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data)
             if (comp_data->types[i]->type_flag == WASM_TYPE_FUNC)
                 size += get_func_type_size(comp_ctx,
                                            (AOTFuncType *)comp_data->types[i]);
+            else if (comp_data->types[i]->type_flag == WASM_TYPE_STRUCT)
+                size += get_struct_type_size(
+                    comp_ctx, (AOTStructType *)comp_data->types[i]);
+            else if (comp_data->types[i]->type_flag == WASM_TYPE_ARRAY)
+                size += get_array_type_size(
+                    comp_ctx, (AOTArrayType *)comp_data->types[i]);
+            else
+                bh_assert(0);
         }
     }
     else
@@ -1625,7 +1691,6 @@ aot_emit_type_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
     if (comp_ctx->enable_gc) {
         int32 idx;
         AOTType **types = comp_data->types;
-        WASMRefTypeMap *ref_type_map;
 
         for (i = 0; i < comp_data->type_count; i++) {
             offset = align_uint(offset, 4);
@@ -1647,26 +1712,9 @@ aot_emit_type_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
                     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);
+                aot_emit_reftype_map(buf, buf_end, &offset,
+                                     func_type->ref_type_map_count,
+                                     func_type->ref_type_maps);
             }
             /* Emit WASM_TYPE_STRUCT */
             else if (types[i]->type_flag == WASM_TYPE_STRUCT) {

+ 2 - 2
core/iwasm/compilation/aot_emit_compare.c

@@ -236,8 +236,8 @@ aot_compile_op_ref_eq(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
     LLVMValueRef gc_obj1 = NULL, gc_obj2 = NULL, res;
 
-    POP_REF(gc_obj1);
-    POP_REF(gc_obj2);
+    POP_GC_REF(gc_obj1);
+    POP_GC_REF(gc_obj2);
 
     /* LLVM pointer values pointers are compared using LLVMBuildICmp */
     res = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, gc_obj1, gc_obj2,

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

@@ -1319,7 +1319,7 @@ aot_compile_op_br_on_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 {
     LLVMValueRef gc_obj, value_cmp;
 
-    GET_REF_FROM_STACK(gc_obj);
+    GET_GC_REF_FROM_STACK(gc_obj);
 
     if (!(value_cmp =
               LLVMBuildIsNull(comp_ctx->builder, gc_obj, "cmp gc obj"))) {
@@ -1340,7 +1340,7 @@ aot_compile_op_br_on_non_null(AOTCompContext *comp_ctx,
 {
     LLVMValueRef gc_obj, value_cmp;
 
-    GET_REF_FROM_STACK(gc_obj);
+    GET_GC_REF_FROM_STACK(gc_obj);
 
     if (!(value_cmp =
               LLVMBuildIsNotNull(comp_ctx->builder, gc_obj, "cmp gc obj"))) {
@@ -1363,7 +1363,7 @@ aot_compile_op_br_on_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMBasicBlockRef gc_obj_null, gc_obj_non_null, conditional_branching,
         phi_blocks[2];
 
-    GET_REF_FROM_STACK(gc_obj);
+    GET_GC_REF_FROM_STACK(gc_obj);
 
     /* Create if block */
     CREATE_BLOCK(gc_obj_null, "gc_obj_null");

+ 4 - 4
core/iwasm/compilation/aot_emit_function.c

@@ -1669,7 +1669,7 @@ bool
 aot_compile_op_ref_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 {
     if (comp_ctx->enable_gc)
-        PUSH_REF(GC_REF_NULL);
+        PUSH_GC_REF(GC_REF_NULL);
     else
         PUSH_I32(REF_NULL);
 
@@ -1684,7 +1684,7 @@ aot_compile_op_ref_is_null(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
     LLVMValueRef lhs = NULL, res;
 
     if (comp_ctx->enable_gc) {
-        POP_REF(lhs);
+        POP_GC_REF(lhs);
 
         if (!(res = LLVMBuildIsNull(comp_ctx->builder, lhs, "lhs is null"))) {
             HANDLE_FAILURE("LLVMBuildIsNull");
@@ -1730,7 +1730,7 @@ aot_compile_op_ref_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             goto fail;
         }
 
-        PUSH_REF(gc_obj);
+        PUSH_GC_REF(gc_obj);
     }
     else
 #endif
@@ -1778,7 +1778,7 @@ aot_compile_op_call_ref(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     func_result_count = func_type->result_count;
     param_cell_num = func_type->param_cell_num;
 
-    POP_REF(func_obj);
+    POP_GC_REF(func_obj);
 
     /* Check if func object is NULL */
     if (!(cmp_func_obj =

+ 187 - 127
core/iwasm/compilation/aot_emit_gc.c

@@ -241,7 +241,7 @@ aot_compile_op_ref_as_non_null(AOTCompContext *comp_ctx,
     LLVMValueRef gc_obj, cmp_gc_obj;
     LLVMBasicBlockRef check_gc_obj_succ;
 
-    GET_REF_FROM_STACK(gc_obj);
+    GET_GC_REF_FROM_STACK(gc_obj);
 
     /* Check if gc object is NULL */
     BUILD_ISNULL(gc_obj, cmp_gc_obj, "cmp_gc_obj");
@@ -443,7 +443,7 @@ struct_new_canon_init_fields(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         field_offset = fields[field_idx].field_offset;
 
         if (wasm_is_type_reftype(field_type)) {
-            POP_REF(field_value);
+            POP_GC_REF(field_value);
         }
         else if (field_type == VALUE_TYPE_I32 || field_type == VALUE_TYPE_F32
                  || field_type == PACKED_TYPE_I8
@@ -505,7 +505,7 @@ aot_compile_op_struct_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    PUSH_REF(struct_obj);
+    PUSH_GC_REF(struct_obj);
 
     return true;
 fail:
@@ -536,7 +536,7 @@ aot_compile_op_struct_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
     }
 
-    POP_REF(struct_obj);
+    POP_GC_REF(struct_obj);
 
     ADD_BASIC_BLOCK(check_struct_obj_succ, "check struct obj succ");
     MOVE_BLOCK_AFTER_CURR(check_struct_obj_succ);
@@ -551,7 +551,7 @@ aot_compile_op_struct_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
 
     if (wasm_is_type_reftype(field_type)) {
-        PUSH_REF(field_value);
+        PUSH_GC_REF(field_value);
     }
     else if (field_type == VALUE_TYPE_I32 || field_type == VALUE_TYPE_F32
              || field_type == PACKED_TYPE_I8 || field_type == PACKED_TYPE_I16) {
@@ -590,7 +590,7 @@ aot_compile_op_struct_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     if (wasm_is_type_reftype(field_type)) {
-        POP_REF(field_value);
+        POP_GC_REF(field_value);
     }
     else if (field_type == VALUE_TYPE_I32 || field_type == VALUE_TYPE_F32
              || field_type == PACKED_TYPE_I8 || field_type == PACKED_TYPE_I16) {
@@ -600,7 +600,7 @@ aot_compile_op_struct_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         POP_I64(field_value);
     }
 
-    POP_REF(struct_obj);
+    POP_GC_REF(struct_obj);
 
     ADD_BASIC_BLOCK(check_struct_obj_succ, "check struct obj succ");
     MOVE_BLOCK_AFTER_CURR(check_struct_obj_succ);
@@ -1028,7 +1028,7 @@ aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* For WASM_OP_ARRAY_NEW_CANON */
     if (!fixed_size && !init_with_default) {
         if (wasm_is_type_reftype(array_elem_type)) {
-            POP_REF(array_elem);
+            POP_GC_REF(array_elem);
         }
         else if (array_elem_type == VALUE_TYPE_I32
                  || array_elem_type == VALUE_TYPE_F32
@@ -1062,7 +1062,7 @@ aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     if (fixed_size) {
         for (i = 0; i < array_len; i++) {
             if (wasm_is_type_reftype(array_elem_type)) {
-                POP_REF(array_elem);
+                POP_GC_REF(array_elem);
             }
             else if (array_elem_type == VALUE_TYPE_I32
                      || array_elem_type == VALUE_TYPE_F32
@@ -1087,7 +1087,7 @@ aot_compile_op_array_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         }
     }
 
-    PUSH_REF(array_obj);
+    PUSH_GC_REF(array_obj);
 
     return true;
 fail:
@@ -1165,7 +1165,7 @@ aot_compile_op_array_new_data(AOTCompContext *comp_ctx,
             array_obj, elem_size, array_length))
         goto fail;
 
-    PUSH_REF(array_obj);
+    PUSH_GC_REF(array_obj);
 
     return true;
 fail:
@@ -1184,7 +1184,7 @@ aot_compile_op_array_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     uint8 array_elem_type = compile_time_array_type->elem_type;
 
     POP_I32(elem_idx);
-    POP_REF(array_obj);
+    POP_GC_REF(array_obj);
 
     ADD_BASIC_BLOCK(check_array_obj_succ, "check array obj succ");
     MOVE_BLOCK_AFTER_CURR(check_array_obj_succ);
@@ -1210,7 +1210,7 @@ aot_compile_op_array_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         goto fail;
 
     if (wasm_is_type_reftype(array_elem_type)) {
-        PUSH_REF(array_elem);
+        PUSH_GC_REF(array_elem);
     }
     else if (array_elem_type == VALUE_TYPE_I32
              || array_elem_type == VALUE_TYPE_F32
@@ -1240,7 +1240,7 @@ aot_compile_op_array_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     /* Get LLVM type based on array_elem_type */
     if (wasm_is_type_reftype(array_elem_type)) {
-        POP_REF(array_elem);
+        POP_GC_REF(array_elem);
     }
     else if (array_elem_type == VALUE_TYPE_I32
              || array_elem_type == VALUE_TYPE_F32
@@ -1253,7 +1253,7 @@ aot_compile_op_array_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     }
 
     POP_I32(elem_idx);
-    POP_REF(array_obj);
+    POP_GC_REF(array_obj);
 
     ADD_BASIC_BLOCK(check_array_obj_succ, "check array obj succ");
     MOVE_BLOCK_AFTER_CURR(check_array_obj_succ);
@@ -1336,9 +1336,9 @@ aot_compile_op_array_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
     POP_I32(len);
     POP_I32(src_offset);
-    POP_REF(src_obj);
+    POP_GC_REF(src_obj);
     POP_I32(dst_offset);
-    POP_REF(dst_obj);
+    POP_GC_REF(dst_obj);
 
     ADD_BASIC_BLOCK(check_objs_succ, "check array objs succ");
     MOVE_BLOCK_AFTER_CURR(check_objs_succ);
@@ -1423,7 +1423,7 @@ aot_compile_op_array_len(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
     LLVMValueRef array_obj, cmp, array_len;
     LLVMBasicBlockRef check_array_obj_succ;
 
-    POP_REF(array_obj);
+    POP_GC_REF(array_obj);
 
     ADD_BASIC_BLOCK(check_array_obj_succ, "check array obj succ");
     MOVE_BLOCK_AFTER_CURR(check_array_obj_succ);
@@ -1452,28 +1452,34 @@ aot_compile_op_i31_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
 
     /* Equivalent to wasm_i31_obj_new: ((i31_value << 1) | 1) */
     if (!(i31_obj = LLVMBuildShl(comp_ctx->builder, i31_val, I32_ONE,
-                                 "i31_value << 1"))) {
+                                 "i31_val_shl"))) {
         aot_set_last_error("llvm build shl failed.");
         goto fail;
     }
 
-    if (!(i31_obj = LLVMBuildOr(comp_ctx->builder, i31_obj, I32_ONE,
-                                "((i31_value << 1) | 1)"))) {
+    if (!(i31_obj =
+              LLVMBuildOr(comp_ctx->builder, i31_obj, I32_ONE, "i31_val_or"))) {
         aot_set_last_error("llvm build or failed.");
         goto fail;
     }
 
     /* if uintptr_t is 64 bits, extend i32 to i64, equivalent to:
-     * (WASMI31ObjectRef)((i31_value << 1) | 1)  */
+       (WASMI31ObjectRef)((i31_value << 1) | 1)  */
     if (comp_ctx->pointer_size == sizeof(uint64)) {
         if (!(i31_obj = LLVMBuildZExt(comp_ctx->builder, i31_obj, I64_TYPE,
-                                      "extend i32 to uintptr_t"))) {
+                                      "i31_val_zext"))) {
             aot_set_last_error("llvm build zext failed.");
             goto fail;
         }
     }
 
-    PUSH_REF(i31_obj);
+    if (!(i31_obj = LLVMBuildIntToPtr(comp_ctx->builder, i31_obj, GC_REF_TYPE,
+                                      "i31_obj"))) {
+        aot_set_last_error("llvm build bit cast failed.");
+        goto fail;
+    }
+
+    PUSH_GC_REF(i31_obj);
 
     return true;
 fail:
@@ -1488,7 +1494,7 @@ aot_compile_op_i31_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
         i31_sign_val;
     LLVMBasicBlockRef check_i31_obj_succ;
 
-    POP_REF(i31_obj);
+    POP_GC_REF(i31_obj);
 
     ADD_BASIC_BLOCK(check_i31_obj_succ, "check_i31_obj_succ");
     MOVE_BLOCK_AFTER_CURR(check_i31_obj_succ);
@@ -1548,83 +1554,125 @@ fail:
 
 bool
 aot_compile_op_ref_test(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        int32 heap_type, bool nullable, bool cast)
+                        int32 heap_type, bool nullable)
 {
-    LLVMValueRef gc_obj, cmp, castable;
-    LLVMBasicBlockRef gc_obj_null, gc_obj_non_null, end_block;
+    LLVMValueRef gc_obj, ref_test_phi, cmp, castable;
+    LLVMBasicBlockRef block_curr, block_obj_non_null, block_end;
 
-    GET_REF_FROM_STACK(gc_obj);
+    POP_GC_REF(gc_obj);
 
-    /* Create if block */
-    ADD_BASIC_BLOCK(gc_obj_null, "gc_obj_null");
-    MOVE_BLOCK_AFTER_CURR(gc_obj_null);
+    block_curr = CURR_BLOCK();
 
-    /* Create else block */
-    ADD_BASIC_BLOCK(gc_obj_non_null, "gc_obj_non_null");
-    MOVE_BLOCK_AFTER_CURR(gc_obj_non_null);
+    /* Create non-null object block */
+    ADD_BASIC_BLOCK(block_obj_non_null, "non_null_obj");
+    MOVE_BLOCK_AFTER_CURR(block_obj_non_null);
 
     /* Create end block */
-    ADD_BASIC_BLOCK(end_block, "end_block");
-    MOVE_BLOCK_AFTER_CURR(end_block);
+    ADD_BASIC_BLOCK(block_end, "ref_test_end");
+    MOVE_BLOCK_AFTER(block_end, block_obj_non_null);
+
+    /* Create ref test result phi */
+    SET_BUILDER_POS(block_end);
+    if (!(ref_test_phi =
+              LLVMBuildPhi(comp_ctx->builder, INT1_TYPE, "ref_test_res"))) {
+        aot_set_last_error("llvm build phi failed");
+        return false;
+    }
 
     /* Check if gc object is NULL */
+    SET_BUILDER_POS(block_curr);
     BUILD_ISNULL(gc_obj, cmp, "cmp_gc_obj");
-    BUILD_COND_BR(cmp, gc_obj_null, gc_obj_non_null);
+    BUILD_COND_BR(cmp, block_end, block_obj_non_null);
 
-    /* Move builder to gc_obj NULL block */
-    SET_BUILDER_POS(gc_obj_null);
-    if (!cast) {
-        /* For WASM_OP_REF_TEST and WASM_OP_REF_TEST_NULLABLE */
-        if (nullable)
-            PUSH_I32(I32_ONE);
-        else
-            PUSH_I32(I32_ZERO);
-    }
-    else {
-        /* For WASM_OP_REF_CAST, exception */
-        if (!nullable
-            && !aot_emit_exception(comp_ctx, func_ctx, EXCE_TYPE_NONCASTABLE,
-                                   false, NULL, NULL))
-            goto fail;
-        /* For WASM_OP_REF_CAST_NULLABLE, do nothing */
-    }
+    if (nullable)
+        LLVMAddIncoming(ref_test_phi, &I1_ZERO, &block_curr, 1);
+    else
+        LLVMAddIncoming(ref_test_phi, &I1_ONE, &block_curr, 1);
 
-    BUILD_BR(end_block);
+    /* Move builder to non-null object block */
+    SET_BUILDER_POS(block_obj_non_null);
 
-    /* Move builder to gc_obj not NULL block */
-    SET_BUILDER_POS(gc_obj_non_null);
     if (heap_type >= 0) {
         if (!aot_call_aot_obj_is_instance_of(comp_ctx, func_ctx, gc_obj,
                                              I32_CONST(heap_type), &castable))
-            goto fail;
+            return false;
     }
     else {
         if (!aot_call_wasm_obj_is_type_of(comp_ctx, func_ctx, gc_obj,
                                           I32_CONST(heap_type), &castable))
-            goto fail;
+            return false;
     }
 
-    if (!(castable = LLVMBuildZExt(comp_ctx->builder, castable, I32_TYPE,
-                                   "castable_i32"))) {
-        aot_set_last_error("llvm build zext failed.");
-        goto fail;
+    if (!(castable = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, castable,
+                                   I8_ZERO, "castable"))) {
+        aot_set_last_error("llvm build icmp failed.");
+        return false;
     }
 
-    if (!cast) {
-        /* For WASM_OP_REF_TEST and WASM_OP_REF_TEST_NULLABLE */
-        PUSH_I32(castable);
-        BUILD_BR(end_block);
+    BUILD_BR(block_end);
+    LLVMAddIncoming(ref_test_phi, &castable, &block_obj_non_null, 1);
+
+    SET_BUILDER_POS(block_end);
+    PUSH_COND(ref_test_phi);
+
+    return true;
+fail:
+    return false;
+}
+
+bool
+aot_compile_op_ref_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                        int32 heap_type, bool nullable)
+{
+    LLVMValueRef gc_obj, cmp, castable;
+    LLVMBasicBlockRef block_obj_non_null, block_end;
+
+    GET_GC_REF_FROM_STACK(gc_obj);
+
+    /* Create non null block */
+    ADD_BASIC_BLOCK(block_obj_non_null, "non_null_obj");
+    MOVE_BLOCK_AFTER_CURR(block_obj_non_null);
+
+    /* Create end block */
+    ADD_BASIC_BLOCK(block_end, "ref_cast_end");
+    MOVE_BLOCK_AFTER(block_end, block_obj_non_null);
+
+    BUILD_ISNULL(gc_obj, cmp, "obj_is_null");
+    if (nullable) {
+        BUILD_COND_BR(cmp, block_end, block_obj_non_null);
     }
     else {
-        /* For WASM_OP_REF_CAST and WASM_OP_REF_CAST_NULLABLE */
-        BUILD_ICMP(LLVMIntEQ, castable, I32_ZERO, cmp, "cmp_castable");
         if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_TYPE_NONCASTABLE, true,
-                                cmp, end_block))
-            goto fail;
+                                cmp, block_obj_non_null)) {
+            return false;
+        }
     }
 
-    /* Move builder to end block */
-    SET_BUILDER_POS(end_block);
+    SET_BUILDER_POS(block_obj_non_null);
+
+    if (heap_type >= 0) {
+        if (!aot_call_aot_obj_is_instance_of(comp_ctx, func_ctx, gc_obj,
+                                             I32_CONST(heap_type), &castable))
+            return false;
+    }
+    else {
+        if (!aot_call_wasm_obj_is_type_of(comp_ctx, func_ctx, gc_obj,
+                                          I32_CONST(heap_type), &castable))
+            return false;
+    }
+
+    if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, castable, I8_ZERO,
+                              "is_uncastable"))) {
+        aot_set_last_error("llvm build not failed");
+        return false;
+    }
+
+    if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_TYPE_NONCASTABLE, true,
+                            cmp, block_end)) {
+        return false;
+    }
+
+    SET_BUILDER_POS(block_end);
 
     return true;
 fail:
@@ -1664,42 +1712,47 @@ bool
 aot_compile_op_extern_internalize(AOTCompContext *comp_ctx,
                                   AOTFuncContext *func_ctx)
 {
-    LLVMValueRef externref_obj, gc_obj, cmp;
-    LLVMBasicBlockRef obj_null, obj_non_null, end_block;
+    LLVMValueRef externref_obj, gc_obj, cmp, internal_obj_phi;
+    LLVMBasicBlockRef block_curr, block_obj_non_null, block_end;
 
-    POP_REF(externref_obj);
+    POP_GC_REF(externref_obj);
 
-    /* Create if block */
-    ADD_BASIC_BLOCK(obj_null, "obj_null");
-    MOVE_BLOCK_AFTER_CURR(obj_null);
+    block_curr = CURR_BLOCK();
 
-    /* Create else block */
-    ADD_BASIC_BLOCK(obj_non_null, "obj_non_null");
-    MOVE_BLOCK_AFTER_CURR(obj_non_null);
+    /* Create non-null object block */
+    ADD_BASIC_BLOCK(block_obj_non_null, "non_null_obj");
+    MOVE_BLOCK_AFTER_CURR(block_obj_non_null);
 
     /* Create end block */
-    ADD_BASIC_BLOCK(end_block, "end_block");
-    MOVE_BLOCK_AFTER_CURR(end_block);
+    ADD_BASIC_BLOCK(block_end, "internalize_end");
+    MOVE_BLOCK_AFTER(block_end, block_obj_non_null);
+
+    /* Create internalized object phi */
+    SET_BUILDER_POS(block_end);
+    if (!(internal_obj_phi =
+              LLVMBuildPhi(comp_ctx->builder, GC_REF_TYPE, "internal_obj"))) {
+        aot_set_last_error("llvm build phi failed");
+        return false;
+    }
 
     /* Check if externref object is NULL */
+    SET_BUILDER_POS(block_curr);
     BUILD_ISNULL(externref_obj, cmp, "cmp_externref_obj");
-    BUILD_COND_BR(cmp, obj_null, obj_non_null);
-
-    /* Move builder to obj NULL block */
-    SET_BUILDER_POS(obj_null);
-    PUSH_REF(GC_REF_NULL);
-    BUILD_BR(end_block);
+    BUILD_COND_BR(cmp, block_end, block_obj_non_null);
+    LLVMAddIncoming(internal_obj_phi, &GC_REF_NULL, &block_curr, 1);
 
-    /* Move builder to obj not NULL block */
-    SET_BUILDER_POS(obj_non_null);
+    /* Move builder to non-null object block */
+    SET_BUILDER_POS(block_obj_non_null);
     if (!aot_call_wasm_externref_obj_to_internal_obj(comp_ctx, func_ctx,
-                                                     externref_obj, &gc_obj))
-        goto fail;
-    PUSH_REF(gc_obj);
-    BUILD_BR(end_block);
+                                                     externref_obj, &gc_obj)) {
+        return false;
+    }
+    BUILD_BR(block_end);
+    LLVMAddIncoming(internal_obj_phi, &gc_obj, &block_obj_non_null, 1);
 
     /* Move builder to end block */
-    SET_BUILDER_POS(end_block);
+    SET_BUILDER_POS(block_end);
+    PUSH_GC_REF(internal_obj_phi);
 
     return true;
 fail:
@@ -1719,7 +1772,7 @@ aot_call_wasm_internal_obj_to_external_obj(AOTCompContext *comp_ctx,
     param_types[1] = GC_REF_TYPE;
     ret_type = GC_REF_TYPE;
 
-    GET_AOT_FUNCTION(wasm_internal_obj_to_externref_obj, 1);
+    GET_AOT_FUNCTION(wasm_internal_obj_to_externref_obj, 2);
 
     /* Call function wasm_internal_obj_to_externref_obj() */
     param_values[0] = func_ctx->exec_env;
@@ -1741,48 +1794,55 @@ bool
 aot_compile_op_extern_externalize(AOTCompContext *comp_ctx,
                                   AOTFuncContext *func_ctx)
 {
-    LLVMValueRef gc_obj, externref_obj, cmp;
-    LLVMBasicBlockRef obj_null, obj_non_null, end_block, externalize_succ;
+    LLVMValueRef gc_obj, cmp, external_obj_phi, externref_obj;
+    LLVMBasicBlockRef block_curr, block_obj_non_null, block_end;
 
-    POP_REF(gc_obj);
+    POP_GC_REF(gc_obj);
 
-    /* Create if block */
-    ADD_BASIC_BLOCK(obj_null, "obj_null");
-    MOVE_BLOCK_AFTER_CURR(obj_null);
+    block_curr = CURR_BLOCK();
 
-    /* Create else block */
-    ADD_BASIC_BLOCK(obj_non_null, "obj_non_null");
-    MOVE_BLOCK_AFTER_CURR(obj_non_null);
-    ADD_BASIC_BLOCK(externalize_succ, "externalized_succ");
-    MOVE_BLOCK_AFTER(externalize_succ, obj_non_null);
+    /* Create non-null object block */
+    ADD_BASIC_BLOCK(block_obj_non_null, "non_null_obj");
+    MOVE_BLOCK_AFTER_CURR(block_obj_non_null);
 
     /* Create end block */
-    ADD_BASIC_BLOCK(end_block, "end_block");
-    MOVE_BLOCK_AFTER_CURR(end_block);
+    ADD_BASIC_BLOCK(block_end, "externalize_end");
+    MOVE_BLOCK_AFTER(block_end, block_obj_non_null);
+
+    /* Create externalized object phi */
+    SET_BUILDER_POS(block_end);
+    if (!(external_obj_phi =
+              LLVMBuildPhi(comp_ctx->builder, GC_REF_TYPE, "external_obj"))) {
+        aot_set_last_error("llvm build phi failed");
+        return false;
+    }
 
     /* Check if gc object is NULL */
+    SET_BUILDER_POS(block_curr);
     BUILD_ISNULL(gc_obj, cmp, "cmp_gc_obj");
-    BUILD_COND_BR(cmp, obj_null, obj_non_null);
+    BUILD_COND_BR(cmp, block_end, block_obj_non_null);
+    LLVMAddIncoming(external_obj_phi, &GC_REF_NULL, &block_curr, 1);
 
-    /* Move builder to obj NULL block */
-    SET_BUILDER_POS(obj_null);
-    PUSH_REF(GC_REF_NULL);
-    BUILD_BR(end_block);
+    /* Move builder to non-null object block */
+    SET_BUILDER_POS(block_obj_non_null);
 
-    /* Move builder to obj not NULL block */
-    SET_BUILDER_POS(obj_non_null);
     if (!aot_call_wasm_internal_obj_to_external_obj(comp_ctx, func_ctx, gc_obj,
-                                                    &externref_obj))
-        goto fail;
+                                                    &externref_obj)) {
+        return false;
+    }
+
+    /* Check whether failed to externalize */
     BUILD_ISNULL(externref_obj, cmp, "cmp_externref_obj");
-    if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_NULL_GC_REF, true, cmp,
-                            externalize_succ))
-        goto fail;
-    PUSH_REF(externref_obj);
-    BUILD_BR(end_block);
+    if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_FAILED_TO_CREATE_GC_OBJ,
+                            true, cmp, block_end)) {
+        return false;
+    }
+
+    LLVMAddIncoming(external_obj_phi, &externref_obj, &block_obj_non_null, 1);
 
     /* Move builder to end block */
-    SET_BUILDER_POS(end_block);
+    SET_BUILDER_POS(block_end);
+    PUSH_GC_REF(external_obj_phi);
 
     return true;
 fail:

+ 5 - 1
core/iwasm/compilation/aot_emit_gc.h

@@ -85,7 +85,11 @@ aot_compile_op_i31_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
 
 bool
 aot_compile_op_ref_test(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
-                        int32 heap_type, bool nullable, bool cast);
+                        int32 heap_type, bool nullable);
+
+bool
+aot_compile_op_ref_cast(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
+                        int32 heap_type, bool nullable);
 
 bool
 aot_compile_op_extern_internalize(AOTCompContext *comp_ctx,

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

@@ -45,24 +45,28 @@ 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, ref types if gc is
-     * enabled and system is 32-bit */
+     * enabled and target 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
-#if WASM_ENABLE_GC != 0 && UINTPTR_MAX != UINT64_MAX
-             || (comp_ctx->enable_gc && type == VALUE_TYPE_GC_REF)
+        && !(
+            type == VALUE_TYPE_I32 || type == VALUE_TYPE_F32
+            || type == VALUE_TYPE_V128
+            || (comp_ctx->enable_ref_types
+                && (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF))
+#if WASM_ENABLE_GC != 0
+            || (comp_ctx->enable_gc && comp_ctx->pointer_size == sizeof(uint32)
+                && type == VALUE_TYPE_GC_REF)
 #endif
-                 )) {
+                )) {
         aot_set_last_error("invalid WASM stack data type.");
         return false;
     }
 
-    /* !is_32: i64, f64, ref types if gc is enabled and system is 64-bit */
+    /* !is_32: i64, f64, ref types if gc is enabled and target 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)
+#if WASM_ENABLE_GC
+             || (comp_ctx->enable_gc && comp_ctx->pointer_size == sizeof(uint64)
+                 && type == VALUE_TYPE_GC_REF)
 #endif
                  )) {
         aot_set_last_error("invalid WASM stack data type.");

+ 4 - 4
core/iwasm/compilation/aot_emit_table.c

@@ -211,7 +211,7 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
             goto fail;
         }
 
-        PUSH_REF(table_elem);
+        PUSH_GC_REF(table_elem);
     }
     else {
         if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INTPTR_TYPE,
@@ -248,7 +248,7 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     LLVMValueRef val = NULL, elem_idx, offset, table_elem;
 
     if (comp_ctx->enable_gc)
-        POP_REF(val);
+        POP_GC_REF(val);
     else
         POP_I32(val);
 
@@ -486,7 +486,7 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* v */
 
     if (comp_ctx->enable_gc) {
-        POP_REF(param_values[3]);
+        POP_GC_REF(param_values[3]);
         if (!(param_values[3] =
                   LLVMBuildBitCast(comp_ctx->builder, param_values[3],
                                    INT8_PTR_TYPE, "table_elem_i8p"))) {
@@ -548,7 +548,7 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     /* v */
 
     if (comp_ctx->enable_gc) {
-        POP_REF(param_values[3]);
+        POP_GC_REF(param_values[3]);
         if (!(param_values[3] =
                   LLVMBuildBitCast(comp_ctx->builder, param_values[3],
                                    INT8_PTR_TYPE, "table_elem_i8p"))) {

+ 100 - 3
core/iwasm/compilation/aot_llvm.c

@@ -25,13 +25,20 @@ create_native_stack_top_min(const AOTCompContext *comp_ctx,
                             AOTFuncContext *func_ctx);
 
 LLVMTypeRef
-wasm_type_to_llvm_type(const AOTLLVMTypes *llvm_types, uint8 wasm_type)
+wasm_type_to_llvm_type(const AOTCompContext *comp_ctx,
+                       const AOTLLVMTypes *llvm_types, uint8 wasm_type)
 {
     switch (wasm_type) {
         case VALUE_TYPE_I32:
+            return llvm_types->int32_type;
         case VALUE_TYPE_FUNCREF:
         case VALUE_TYPE_EXTERNREF:
-            return llvm_types->int32_type;
+            if (comp_ctx->enable_ref_types)
+                return llvm_types->int32_type;
+            else {
+                bh_assert(comp_ctx->enable_gc);
+                return llvm_types->gc_ref_type;
+            }
         case VALUE_TYPE_I64:
             return llvm_types->int64_type;
         case VALUE_TYPE_F32:
@@ -42,11 +49,20 @@ 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 REF_TYPE_STRUCTREF:
+        case REF_TYPE_ARRAYREF:
+        case REF_TYPE_I31REF:
+        case REF_TYPE_EQREF:
+        case REF_TYPE_ANYREF:
+        case REF_TYPE_HT_NULLABLE:
+        case REF_TYPE_HT_NON_NULLABLE:
         case VALUE_TYPE_GC_REF:
+            bh_assert(comp_ctx->enable_gc);
             return llvm_types->gc_ref_type;
         default:
             break;
     }
+    bh_assert(0);
     return NULL;
 }
 
@@ -560,6 +576,47 @@ fail:
     return NULL;
 }
 
+static bool
+check_wasm_type(AOTCompContext *comp_ctx, uint8 type)
+{
+    if (type == VALUE_TYPE_FUNCREF || type == VALUE_TYPE_EXTERNREF) {
+        if (!comp_ctx->enable_ref_types && !comp_ctx->enable_gc) {
+            aot_set_last_error("funcref or externref type was found, "
+                               "try removing --disable-ref-types option "
+                               "or adding --enable-gc option.");
+            return false;
+        }
+        else
+            return true;
+    }
+    else if (type == REF_TYPE_STRUCTREF || type == REF_TYPE_ARRAYREF
+             || type == REF_TYPE_I31REF || type == REF_TYPE_EQREF
+             || type == REF_TYPE_ANYREF || type == REF_TYPE_HT_NULLABLE
+             || type == REF_TYPE_HT_NON_NULLABLE) {
+        if (!comp_ctx->enable_gc) {
+            aot_set_last_error("GC reference type was found, "
+                               "try adding --enable-gc option.");
+            return false;
+        }
+        else
+            return true;
+    }
+    else if (type == VALUE_TYPE_V128) {
+        if (!comp_ctx->enable_simd) {
+            aot_set_last_error("SIMD type was found, try removing "
+                               " --disable-simd option.");
+            return false;
+        }
+        return true;
+    }
+    else if (type != VALUE_TYPE_I32 && type != VALUE_TYPE_I64
+             && type != VALUE_TYPE_F32 && type != VALUE_TYPE_F64) {
+        bh_assert(0);
+    }
+
+    return true;
+}
+
 /**
  * Add LLVM function
  */
@@ -568,6 +625,8 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
                   const AOTFuncType *aot_func_type, uint32 func_index,
                   LLVMTypeRef *p_func_type, LLVMValueRef *p_precheck_func)
 {
+    WASMFunction *aot_func =
+        comp_ctx->comp_data->wasm_module->functions[func_index];
     LLVMValueRef func = NULL;
     LLVMTypeRef *param_types, ret_type, func_type;
     LLVMTypeRef func_type_wrapper;
@@ -578,6 +637,18 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module,
     uint32 i, j = 0, param_count = (uint64)aot_func_type->param_count;
     uint32 backend_thread_num, compile_thread_num;
 
+    /* Check function parameter types and result types */
+    for (i = 0; i < aot_func_type->param_count + aot_func_type->result_count;
+         i++) {
+        if (!check_wasm_type(comp_ctx, aot_func_type->types[i]))
+            return NULL;
+    }
+    /* Check function local types */
+    for (i = 0; i < aot_func->local_count; i++) {
+        if (!check_wasm_type(comp_ctx, aot_func->local_types[i]))
+            return NULL;
+    }
+
     /* exec env as first parameter */
     param_count++;
 
@@ -1016,8 +1087,22 @@ create_local_variables(const AOTCompData *comp_data,
                 break;
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_EXTERNREF:
-                local_value = REF_NULL;
+                if (!comp_ctx->enable_gc)
+                    local_value = REF_NULL;
+                else
+                    local_value = GC_REF_NULL;
                 break;
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+                local_value = GC_REF_NULL;
+                break;
+#endif
             default:
                 bh_assert(0);
                 break;
@@ -3123,6 +3208,12 @@ aot_value_stack_push(const AOTCompContext *comp_ctx, AOTValueStack *stack,
             case VALUE_TYPE_EXTERNREF:
                 push_ref(comp_ctx->aot_frame, value);
                 break;
+#if WASM_ENABLE_GC != 0
+            case VALUE_TYPE_GC_REF:
+                bh_assert(comp_ctx->enable_gc);
+                push_gc_ref(comp_ctx->aot_frame, value);
+                break;
+#endif
             default:
                 bh_assert(0);
                 break;
@@ -3171,6 +3262,12 @@ aot_value_stack_pop(const AOTCompContext *comp_ctx, AOTValueStack *stack)
             case VALUE_TYPE_EXTERNREF:
                 pop_ref(comp_ctx->aot_frame);
                 break;
+#if WASM_ENABLE_GC != 0
+            case VALUE_TYPE_GC_REF:
+                bh_assert(comp_ctx->enable_gc);
+                pop_gc_ref(comp_ctx->aot_frame);
+                break;
+#endif
             default:
                 bh_assert(0);
                 break;

+ 2 - 1
core/iwasm/compilation/aot_llvm.h

@@ -578,7 +578,8 @@ void
 aot_block_destroy(AOTCompContext *comp_ctx, AOTBlock *block);
 
 LLVMTypeRef
-wasm_type_to_llvm_type(const AOTLLVMTypes *llvm_types, uint8 wasm_type);
+wasm_type_to_llvm_type(const AOTCompContext *comp_ctx,
+                       const AOTLLVMTypes *llvm_types, uint8 wasm_type);
 
 bool
 aot_checked_addr_list_add(AOTFuncContext *func_ctx, uint32 local_idx,

+ 2 - 1
core/iwasm/interpreter/wasm_runtime.h

@@ -67,10 +67,11 @@ typedef enum WASMExceptionID {
     EXCE_OUT_OF_BOUNDS_TABLE_ACCESS,
     EXCE_OPERAND_STACK_OVERFLOW,
     EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC,
-    EXCE_ALREADY_THROWN,
     EXCE_NULL_GC_REF,
     EXCE_TYPE_NONCASTABLE,
     EXCE_ARRAY_OOB,
+    EXCE_FAILED_TO_CREATE_GC_OBJ,
+    EXCE_ALREADY_THROWN,
     EXCE_NUM,
 } WASMExceptionID;
 

+ 2 - 3
wamr-compiler/CMakeLists.txt

@@ -48,10 +48,9 @@ add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1)
 add_definitions(-DWASM_ENABLE_LIB_WASI_THREADS=1)
 add_definitions(-DWASM_ENABLE_MODULE_INST_CONTEXT=1)
 
+add_definitions(-DWASM_ENABLE_GC=1)
 if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
-  add_definitions (-DWASM_ENABLE_GC_BINARYEN=1)
-else ()
-  add_definitions (-DWASM_ENABLE_GC=1)
+  add_definitions(-DWASM_ENABLE_GC_BINARYEN=1)
 endif ()
 
 if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1)