Просмотр исходного кода

Support GC opcodes generated by binaryen (#2110)

- Add cmake variable `WAMR_BUILD_GC_BINARYEN`
- Implement GC opcode array.copy
- Fix bug in wasm_type_is_supers_of
- Fix loader load import global and wasm_loader_pop_frame_ref
- Support pass/return GC ref type params/result to/from native API
Xu Jun 2 лет назад
Родитель
Сommit
786cf6ae10

+ 4 - 0
build-scripts/config_common.cmake

@@ -294,6 +294,10 @@ if (WAMR_BUILD_GC EQUAL 1)
     message("      GC testing enabled")
   endif()
 endif ()
+if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
+  add_definitions (-DWASM_ENABLE_GC_BINARYEN=1)
+  message ("     GC binaryen compatible mode on")
+endif ()
 if (DEFINED WAMR_BH_VPRINTF)
   add_definitions (-DBH_VPRINTF=${WAMR_BH_VPRINTF})
 endif ()

+ 4 - 0
build-scripts/runtime_lib.cmake

@@ -78,6 +78,10 @@ if (WAMR_BUILD_AOT EQUAL 1)
     include (${IWASM_DIR}/aot/iwasm_aot.cmake)
 endif ()
 
+if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
+    set (WAMR_BUILD_GC 1)
+endif ()
+
 if (WAMR_BUILD_GC EQUAL 1)
     include (${IWASM_DIR}/common/gc/iwasm_gc.cmake)
     # Enable the dependent feature if GC is enabled

+ 5 - 0
core/config.h

@@ -444,6 +444,11 @@
 #define WASM_ENABLE_GC 0
 #endif
 
+/* GC binaryen compatible mode */
+#ifndef WASM_ENABLE_GC_BINARYEN
+#define WASM_ENABLE_GC_BINARYEN 0
+#endif
+
 #ifndef GC_REFTYPE_MAP_SIZE_DEFAULT
 #define GC_REFTYPE_MAP_SIZE_DEFAULT 64
 #endif

+ 26 - 0
core/iwasm/common/gc/gc_object.c

@@ -260,6 +260,17 @@ wasm_array_obj_get_elem(WASMArrayObjectRef array_obj, uint32 elem_idx,
     }
 }
 
+void
+wasm_array_obj_copy(WASMArrayObjectRef dst_obj, uint32 dst_idx,
+                    WASMArrayObjectRef src_obj, uint32 src_idx, uint32 len)
+{
+    uint8 *dst_data = wasm_array_obj_elem_addr(dst_obj, dst_idx);
+    uint8 *src_data = wasm_array_obj_elem_addr(src_obj, src_idx);
+    uint32 elem_size = 1 << wasm_array_obj_elem_size_log(dst_obj);
+
+    bh_memmove_s(dst_data, elem_size * len, src_data, elem_size * len);
+}
+
 WASMFuncObjectRef
 wasm_func_obj_new(void *heap_handle, WASMRttTypeRef rtt_type,
                   uint32 func_idx_bound)
@@ -311,6 +322,21 @@ wasm_externref_obj_new(WASMExecEnv *exec_env, void *heap_handle, void *host_obj)
     return externref_obj;
 }
 
+WASMAnyrefObjectRef
+wasm_anyref_obj_new(WASMExecEnv *exec_env, void *heap_handle, void *host_obj)
+{
+    WASMAnyrefObjectRef anyref_obj;
+
+    if (!(anyref_obj = gc_obj_malloc(heap_handle, sizeof(WASMAnyrefObject)))) {
+        return NULL;
+    }
+
+    anyref_obj->header = WASM_OBJ_ANYREF_OBJ_FLAG;
+    anyref_obj->host_obj = host_obj;
+
+    return anyref_obj;
+}
+
 WASMObjectRef
 wasm_externref_obj_to_internal_obj(WASMExternrefObjectRef externref_obj)
 {

+ 8 - 0
core/iwasm/common/gc/gc_object.h

@@ -141,6 +141,10 @@ void
 wasm_array_obj_get_elem(WASMArrayObjectRef array_obj, uint32 elem_idx,
                         bool sign_extend, WASMValue *value);
 
+void
+wasm_array_obj_copy(WASMArrayObjectRef dst_obj, uint32 dst_idx,
+                    WASMArrayObjectRef src_obj, uint32 src_idx, uint32 len);
+
 /**
  * Return the logarithm of the size of array element.
  *
@@ -218,6 +222,10 @@ WASMExternrefObjectRef
 wasm_externref_obj_new(struct WASMExecEnv *exec_env, void *heap_handle,
                        void *host_obj);
 
+WASMAnyrefObjectRef
+wasm_anyref_obj_new(struct WASMExecEnv *exec_env, void *heap_handle,
+                    void *host_obj);
+
 /* Implementation of opcode extern.internalize */
 WASMObjectRef
 wasm_externref_obj_to_internal_obj(WASMExternrefObjectRef externref_obj);

+ 3 - 2
core/iwasm/common/gc/gc_type.c

@@ -793,7 +793,7 @@ wasm_is_reftype_supers_of_noextern(uint type)
 static bool
 wasm_type_is_supers_of(const WASMType *type1, const WASMType *type2)
 {
-    uint32 i;
+    uint32 i, inherit_depth_diff;
 
     if (type1 == type2)
         return true;
@@ -802,7 +802,8 @@ wasm_type_is_supers_of(const WASMType *type1, const WASMType *type2)
           && type1->inherit_depth < type2->inherit_depth))
         return false;
 
-    for (i = 0; i < type2->inherit_depth - type1->inherit_depth; i++) {
+    inherit_depth_diff = type2->inherit_depth - type1->inherit_depth;
+    for (i = 0; i < inherit_depth_diff; i++) {
         type2 = type2->parent_type;
         if (type2 == type1)
             return true;

+ 7 - 1
core/iwasm/common/wasm_native.c

@@ -81,7 +81,13 @@ compare_type_with_signautre(uint8 type, const char signature)
     }
 
 #if WASM_ENABLE_REF_TYPES != 0
-    if ('r' == signature && type == VALUE_TYPE_EXTERNREF)
+    if ('r' == signature
+#if WASM_ENABLE_GC != 0
+        && (type >= REF_TYPE_NULLREF && type <= REF_TYPE_FUNCREF)
+#else
+        && type == VALUE_TYPE_EXTERNREF
+#endif
+    )
         return true;
 #endif
 

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

@@ -3647,6 +3647,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     for (i = 0; i < func_type->param_count; i++) {
         switch (func_type->types[i]) {
             case VALUE_TYPE_I32:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_EXTERNREF:
@@ -3791,6 +3805,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     for (i = 0; i < func_type->param_count; i++) {
         switch (func_type->types[i]) {
             case VALUE_TYPE_I32:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
 #endif
@@ -3996,6 +4024,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     else {
         switch (func_type->types[func_type->param_count]) {
             case VALUE_TYPE_I32:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
 #endif
@@ -4128,6 +4170,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     for (i = 0; i < func_type->param_count; i++) {
         switch (func_type->types[i]) {
             case VALUE_TYPE_I32:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
 #endif
@@ -4214,6 +4270,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
     else {
         switch (func_type->types[func_type->param_count]) {
             case VALUE_TYPE_I32:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
 #endif
@@ -4453,6 +4523,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
                 break;
             }
             case VALUE_TYPE_I64:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
                 if (n_ints < MAX_REG_INTS)
                     ints[n_ints++] = *(uint64 *)argv_src;
                 else
@@ -4542,6 +4626,20 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
                     (uint32)invokeNative_Int32(func_ptr, argv1, n_stacks);
                 break;
             case VALUE_TYPE_I64:
+#if WASM_ENABLE_GC != 0
+            case REF_TYPE_FUNCREF:
+            case REF_TYPE_EXTERNREF:
+            case REF_TYPE_ANYREF:
+            case REF_TYPE_EQREF:
+            case REF_TYPE_HT_NULLABLE:
+            case REF_TYPE_HT_NON_NULLABLE:
+            case REF_TYPE_I31REF:
+            case REF_TYPE_NULLFUNCREF:
+            case REF_TYPE_NULLEXTERNREF:
+            case REF_TYPE_STRUCTREF:
+            case REF_TYPE_ARRAYREF:
+            case REF_TYPE_NULLREF:
+#endif
                 PUT_I64_TO_ADDR(argv_ret,
                                 invokeNative_Int64(func_ptr, argv1, n_stacks));
                 break;

+ 40 - 0
core/iwasm/interpreter/wasm_interp_classic.c

@@ -2378,6 +2378,46 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                                 &array_elem);
                         HANDLE_OP_END();
                     }
+#if WASM_ENABLE_GC_BINARYEN != 0
+                    case WASM_OP_ARRAY_COPY:
+                    {
+                        uint32 dst_offset, src_offset, len, src_type_index;
+                        WASMArrayObjectRef src_obj, dst_obj;
+
+                        read_leb_uint32(frame_ip, frame_ip_end, type_index);
+                        read_leb_uint32(frame_ip, frame_ip_end, src_type_index);
+
+                        len = POP_I32();
+                        src_offset = POP_I32();
+                        src_obj = POP_REF();
+                        dst_offset = POP_I32();
+                        dst_obj = POP_REF();
+
+                        if (!src_obj || !dst_obj) {
+                            wasm_set_exception(module, "null array object");
+                            goto got_exception;
+                        }
+
+                        if (len > 0) {
+                            if ((dst_offset > UINT32_MAX - len)
+                                || (dst_offset + len
+                                    > wasm_array_obj_length(dst_obj))
+                                || (src_offset > UINT32_MAX - len)
+                                || (src_offset + len
+                                    > wasm_array_obj_length(src_obj))) {
+                                wasm_set_exception(module,
+                                                   "array index out of bounds");
+                                goto got_exception;
+                            }
+
+                            wasm_array_obj_copy(dst_obj, dst_offset, src_obj,
+                                                src_offset, len);
+                        }
+
+                        (void)src_type_index;
+                        HANDLE_OP_END();
+                    }
+#endif
                     case WASM_OP_ARRAY_LEN:
                     {
                         uint32 array_len;

+ 40 - 0
core/iwasm/interpreter/wasm_interp_fast.c

@@ -2211,6 +2211,46 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                                                 &array_elem);
                         HANDLE_OP_END();
                     }
+#if WASM_ENABLE_GC_BINARYEN != 0
+                    case WASM_OP_ARRAY_COPY:
+                    {
+                        uint32 dst_offset, src_offset, len, src_type_index;
+                        WASMArrayObjectRef src_obj, dst_obj;
+
+                        type_idx = read_uint32(frame_ip);
+                        src_type_index = read_uint32(frame_ip);
+
+                        len = POP_I32();
+                        src_offset = POP_I32();
+                        src_obj = POP_REF();
+                        dst_offset = POP_I32();
+                        dst_obj = POP_REF();
+
+                        if (!src_obj || !dst_obj) {
+                            wasm_set_exception(module, "null array object");
+                            goto got_exception;
+                        }
+
+                        if (len > 0) {
+                            if ((dst_offset > UINT32_MAX - len)
+                                || (dst_offset + len
+                                    > wasm_array_obj_length(dst_obj))
+                                || (src_offset > UINT32_MAX - len)
+                                || (src_offset + len
+                                    > wasm_array_obj_length(src_obj))) {
+                                wasm_set_exception(module,
+                                                   "array index out of bounds");
+                                goto got_exception;
+                            }
+
+                            wasm_array_obj_copy(dst_obj, dst_offset, src_obj,
+                                                src_offset, len);
+                        }
+
+                        (void)src_type_index;
+                        HANDLE_OP_END();
+                    }
+#endif
                     case WASM_OP_ARRAY_LEN:
                     {
                         uint32 array_len;

+ 123 - 25
core/iwasm/interpreter/wasm_loader.c

@@ -467,6 +467,21 @@ check_type_index(const WASMModule *module, uint32 type_index, char *error_buf,
     }
     return true;
 }
+
+static bool
+check_array_type(const WASMModule *module, uint32 type_index, char *error_buf,
+                 uint32 error_buf_size)
+{
+    if (!check_type_index(module, type_index, error_buf, error_buf_size)) {
+        return false;
+    }
+    if (module->types[type_index]->type_flag != WASM_TYPE_ARRAY) {
+        set_error_buf(error_buf, error_buf_size, "unkown array type");
+        return false;
+    }
+
+    return true;
+}
 #endif
 
 static bool
@@ -729,15 +744,10 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
                     read_leb_uint32(p, p_end, init_expr->u.type_index);
                     type_idx = init_expr->u.type_index;
 
-                    if (!check_type_index(module, type_idx, error_buf,
+                    if (!check_array_type(module, type_idx, error_buf,
                                           error_buf_size)) {
                         return false;
                     }
-                    if (module->types[type_idx]->type_flag != WASM_TYPE_ARRAY) {
-                        set_error_buf(error_buf, error_buf_size,
-                                      "unkown array type");
-                        return false;
-                    }
 
                     if (opcode1 == WASM_OP_ARRAY_NEW_CANON_FIXED) {
                         read_leb_uint32(p, p_end,
@@ -1378,7 +1388,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                 }
             }
         }
-#else  /* else of WASM_ENABLE_GC == 0 */
+#else /* else of WASM_ENABLE_GC == 0 */
         for (i = 0; i < type_count; i++) {
             uint32 super_type_count = 0, parent_type_idx = (uint32)-1;
             bool is_sub_final = true;
@@ -1415,6 +1425,11 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                 CHECK_BUF(p, p_end, 1);
                 flag = read_uint8(p);
             }
+#if WASM_ENABLE_GC_BINARYEN != 0
+            else {
+                is_sub_final = false;
+            }
+#endif
 
             if (flag == DEFINED_TYPE_FUNC) {
                 if (!resolve_func_type(&p, buf_end, module, i, error_buf,
@@ -2507,7 +2522,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
     WASMImport *import_functions = NULL, *import_tables = NULL;
     WASMImport *import_memories = NULL, *import_globals = NULL;
     char *sub_module_name, *field_name;
-    uint8 u8, kind;
+    uint8 u8, kind, global_type;
 
     read_leb_uint32(p, p_end, import_count);
 
@@ -2576,8 +2591,25 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     break;
 
                 case IMPORT_KIND_GLOBAL: /* import global */
+#if WASM_ENABLE_GC != 0
+                    /* valtype */
+                    CHECK_BUF(p, p_end, 1);
+                    global_type = read_uint8(p);
+                    if (wasm_is_type_multi_byte_type(global_type)) {
+                        int32 heap_type;
+                        read_leb_int32(p, p_end, heap_type);
+                        (void)heap_type;
+                    }
+
+                    /* mutability */
+                    CHECK_BUF(p, p_end, 1);
+                    p += 1;
+#else
                     CHECK_BUF(p, p_end, 2);
                     p += 2;
+#endif
+
+                    (void)global_type;
                     module->import_global_count++;
                     break;
 
@@ -6039,6 +6071,12 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
                     case WASM_OP_ARRAY_SET:
                         skip_leb_uint32(p, p_end); /* typeidx */
                         break;
+#if WASM_ENABLE_GC_BINARYEN != 0
+                    case WASM_OP_ARRAY_COPY:
+                        skip_leb_uint32(p, p_end); /* typeidx1 */
+                        skip_leb_uint32(p, p_end); /* typeidx2 */
+                        break;
+#endif
                     case WASM_OP_ARRAY_LEN:
                         break;
                     case WASM_OP_ARRAY_NEW_CANON_FIXED:
@@ -6835,7 +6873,7 @@ wasm_loader_pop_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf,
     ctx->frame_ref -= cell_num_to_pop;
     ctx->stack_cell_num -= cell_num_to_pop;
 #if WASM_ENABLE_GC != 0
-    if (wasm_is_type_multi_byte_type(type)) {
+    if (wasm_is_type_multi_byte_type(*ctx->frame_ref)) {
         ctx->frame_reftype_map--;
         ctx->reftype_map_num--;
     }
@@ -11461,16 +11499,10 @@ re_scan:
 #endif
                         }
 
-                        if (!check_type_index(module, type_idx, error_buf,
+                        if (!check_array_type(module, type_idx, error_buf,
                                               error_buf_size)) {
                             goto fail;
                         }
-                        if (module->types[type_idx]->type_flag
-                            != WASM_TYPE_ARRAY) {
-                            set_error_buf(error_buf, error_buf_size,
-                                          "unkown array type");
-                            goto fail;
-                        }
 
                         if (opcode1 != WASM_OP_ARRAY_NEW_CANON_FIXED) {
                             /* length */
@@ -11559,16 +11591,10 @@ re_scan:
 #if WASM_ENABLE_FAST_INTERP != 0
                         emit_uint32(loader_ctx, type_idx);
 #endif
-                        if (!check_type_index(module, type_idx, error_buf,
+                        if (!check_array_type(module, type_idx, error_buf,
                                               error_buf_size)) {
                             goto fail;
                         }
-                        if (module->types[type_idx]->type_flag
-                            != WASM_TYPE_ARRAY) {
-                            set_error_buf(error_buf, error_buf_size,
-                                          "unkown array type");
-                            goto fail;
-                        }
                         array_type = (WASMArrayType *)module->types[type_idx];
 
                         if (opcode1 == WASM_OP_ARRAY_SET
@@ -11620,6 +11646,71 @@ re_scan:
                         break;
                     }
 
+#if WASM_ENABLE_GC_BINARYEN != 0
+                    case WASM_OP_ARRAY_COPY:
+                    {
+                        uint32 src_type_idx;
+                        WASMRefType src_ref_type = { 0 };
+                        WASMRefType dst_ref_type = { 0 };
+                        WASMArrayType *array_type;
+                        /* typeidx1 */
+                        read_leb_uint32(p, p_end, type_idx);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, type_idx);
+#endif
+                        /* typeidx2 */
+                        read_leb_uint32(p, p_end, src_type_idx);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, src_type_idx);
+#endif
+                        if (!check_array_type(module, type_idx, error_buf,
+                                              error_buf_size)) {
+                            goto fail;
+                        }
+
+                        if (!check_array_type(module, src_type_idx, error_buf,
+                                              error_buf_size)) {
+                            goto fail;
+                        }
+
+                        POP_I32();
+                        POP_I32();
+                        /* POP array obj, (ref null $t) */
+                        wasm_set_refheaptype_typeidx(
+                            &wasm_ref_type.ref_ht_typeidx, true, src_type_idx);
+                        POP_REF(wasm_ref_type.ref_type);
+                        bh_memcpy_s(&src_ref_type, (uint32)sizeof(WASMRefType),
+                                    &wasm_ref_type,
+                                    wasm_reftype_struct_size(&wasm_ref_type));
+                        POP_I32();
+                        /* POP array obj, (ref null $t) */
+                        wasm_set_refheaptype_typeidx(
+                            &wasm_ref_type.ref_ht_typeidx, true, type_idx);
+                        POP_REF(wasm_ref_type.ref_type);
+                        bh_memcpy_s(&dst_ref_type, (uint32)sizeof(WASMRefType),
+                                    &wasm_ref_type,
+                                    wasm_reftype_struct_size(&wasm_ref_type));
+
+                        if (!wasm_reftype_is_subtype_of(
+                                src_ref_type.ref_type, &src_ref_type,
+                                dst_ref_type.ref_type, &dst_ref_type,
+                                module->types, module->type_count)) {
+                            set_error_buf(error_buf, error_buf_size,
+                                          "type mismatch");
+                            goto fail;
+                        }
+
+                        array_type = (WASMArrayType *)module->types[type_idx];
+                        if (!(array_type->elem_flags & 1)) {
+                            set_error_buf(error_buf, error_buf_size,
+                                          "array is immutable");
+                            goto fail;
+                        }
+
+                        break;
+                    }
+#endif
+
                     case WASM_OP_ARRAY_LEN:
                     {
                         POP_REF(REF_TYPE_ARRAYREF);
@@ -11678,8 +11769,15 @@ re_scan:
                         if (opcode1 == WASM_OP_REF_TEST
                             || opcode1 == WASM_OP_REF_TEST_NULLABLE)
                             PUSH_I32();
-                        else
-                            PUSH_REF(type);
+                        else {
+                            bool nullable =
+                                (opcode1 == WASM_OP_REF_CAST_NULLABLE) ? true
+                                                                       : false;
+                            wasm_set_refheaptype_typeidx(
+                                &wasm_ref_type.ref_ht_typeidx, nullable,
+                                heap_type);
+                            PUSH_REF(wasm_ref_type.ref_type);
+                        }
                         break;
                     }
 

+ 34 - 15
core/iwasm/interpreter/wasm_opcode.h

@@ -284,23 +284,42 @@ typedef enum WASMOpcode {
 } WASMOpcode;
 
 typedef enum WASMGCEXTOpcode {
+#if WASM_ENABLE_GC_BINARYEN != 0
+    WASM_OP_STRUCT_NEW_CANON = 0x07,         /* struct.new_canon */
+    WASM_OP_STRUCT_NEW_CANON_DEFAULT = 0x08, /* struct.new_canon_default */
+#else
     WASM_OP_STRUCT_NEW_CANON = 0x01,         /* struct.new_canon */
     WASM_OP_STRUCT_NEW_CANON_DEFAULT = 0x02, /* struct.new_canon_default */
-    WASM_OP_STRUCT_GET = 0x03,               /* struct.get */
-    WASM_OP_STRUCT_GET_S = 0x04,             /* struct.get_s */
-    WASM_OP_STRUCT_GET_U = 0x05,             /* struct.get_u */
-    WASM_OP_STRUCT_SET = 0x06,               /* struct.set */
-
-    WASM_OP_ARRAY_NEW_CANON = 0x11,         /* array.new_canon */
-    WASM_OP_ARRAY_NEW_CANON_DEFAULT = 0x12, /* array.new_canon_default */
-    WASM_OP_ARRAY_GET = 0x13,               /* array.get */
-    WASM_OP_ARRAY_GET_S = 0x14,             /* array.get_s */
-    WASM_OP_ARRAY_GET_U = 0x15,             /* array.get_u */
-    WASM_OP_ARRAY_SET = 0x16,               /* array.set */
-    WASM_OP_ARRAY_LEN = 0x17,               /* array.len */
-    WASM_OP_ARRAY_NEW_CANON_FIXED = 0x19,   /* array.new_canon_fixed */
-    WASM_OP_ARRAY_NEW_CANON_DATA = 0x1b,    /* array.new_canon_data */
-    WASM_OP_ARRAY_NEW_CANON_ELEM = 0x1c,    /* array.new_canon_elem */
+#endif
+    WASM_OP_STRUCT_GET = 0x03,   /* struct.get */
+    WASM_OP_STRUCT_GET_S = 0x04, /* struct.get_s */
+    WASM_OP_STRUCT_GET_U = 0x05, /* struct.get_u */
+    WASM_OP_STRUCT_SET = 0x06,   /* struct.set */
+
+#if WASM_ENABLE_GC_BINARYEN != 0
+    WASM_OP_ARRAY_NEW_CANON = 0x1b,         /* array.new_canon */
+    WASM_OP_ARRAY_NEW_CANON_DEFAULT = 0x1c, /* array.new_canon_default */
+#else
+    WASM_OP_ARRAY_NEW_CANON = 0x11,          /* array.new_canon */
+    WASM_OP_ARRAY_NEW_CANON_DEFAULT = 0x12,  /* array.new_canon_default */
+#endif
+    WASM_OP_ARRAY_GET = 0x13,   /* array.get */
+    WASM_OP_ARRAY_GET_S = 0x14, /* array.get_s */
+    WASM_OP_ARRAY_GET_U = 0x15, /* array.get_u */
+    WASM_OP_ARRAY_SET = 0x16,   /* array.set */
+
+#if WASM_ENABLE_GC_BINARYEN != 0
+    WASM_OP_ARRAY_COPY = 0x18,            /* array.copy */
+    WASM_OP_ARRAY_LEN = 0x19,             /* array.len */
+    WASM_OP_ARRAY_NEW_CANON_FIXED = 0x1a, /* array.new_canon_fixed */
+    WASM_OP_ARRAY_NEW_CANON_DATA = 0x1d,  /* array.new_canon_data */
+    WASM_OP_ARRAY_NEW_CANON_ELEM = 0x1f,  /* array.new_canon_elem */
+#else
+    WASM_OP_ARRAY_LEN = 0x17,                /* array.len */
+    WASM_OP_ARRAY_NEW_CANON_FIXED = 0x19,    /* array.new_canon_fixed */
+    WASM_OP_ARRAY_NEW_CANON_DATA = 0x1b,     /* array.new_canon_data */
+    WASM_OP_ARRAY_NEW_CANON_ELEM = 0x1c,     /* array.new_canon_elem */
+#endif
 
     WASM_OP_I31_NEW = 0x20,   /* i31.new */
     WASM_OP_I31_GET_S = 0x21, /* i31.get_s */