Przeglądaj źródła

Support stringref proposal (#2651)

This PR implements the WebAssembly stringref proposal:
  https://github.com/WebAssembly/stringref

It adds cmake variable `WAMR_BUILD_STRINGREF` to build the feature,
which will enable GC automatically.

The stringref contains two parts:
- `part 1`: add new ref types in WasmGC, add opcode processing in loader and interpreter
- `part 2`: add a library for string representation/encoding/decoding and so on

To reduce the code size introduced to WAMR, this PR only includes `part 1`,
`part 2` can be provided by embedder, they may use their own implementation,
e.g., Wasmnizer-ts uses JSString from QuickJS to implement stringref:
https://github.com/intel/Wasmnizer-ts/blob/main/runtime-library/stringref/stringref_qjs.c

We will submit another PR of `part 2` and make it as a sample rather than WAMR core part.

Signed-off-by: Su Yihan <yihan.su@intel.com>
Co-authored-by: Xu Jun <jun1.xu@intel.com>
Su Yihan 2 lat temu
rodzic
commit
2f45f12cd7

+ 8 - 0
build-scripts/config_common.cmake

@@ -335,6 +335,14 @@ if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
   add_definitions (-DWASM_ENABLE_GC_BINARYEN=1)
   add_definitions (-DWASM_ENABLE_GC_BINARYEN=1)
   message ("     GC binaryen compatible mode on")
   message ("     GC binaryen compatible mode on")
 endif ()
 endif ()
+if (WAMR_BUILD_STRINGREF EQUAL 1)
+  message ("     Stringref enabled")
+  if (NOT DEFINED WAMR_STRINGREF_IMPL_SOURCE)
+    message ("       Using WAMR builtin implementation for stringref")
+  else ()
+    message ("       Using custom implementation for stringref")
+  endif()
+endif ()
 if (WAMR_BUILD_PERF_PROFILING EQUAL 1 OR
 if (WAMR_BUILD_PERF_PROFILING EQUAL 1 OR
     WAMR_BUILD_DUMP_CALL_STACK EQUAL 1 OR
     WAMR_BUILD_DUMP_CALL_STACK EQUAL 1 OR
     WAMR_BUILD_GC EQUAL 1 OR WAMR_BUILD_GC_BINARYEN EQUAL 1)
     WAMR_BUILD_GC EQUAL 1 OR WAMR_BUILD_GC_BINARYEN EQUAL 1)

+ 4 - 0
build-scripts/runtime_lib.cmake

@@ -78,6 +78,10 @@ if (WAMR_BUILD_AOT EQUAL 1)
     include (${IWASM_DIR}/aot/iwasm_aot.cmake)
     include (${IWASM_DIR}/aot/iwasm_aot.cmake)
 endif ()
 endif ()
 
 
+if (WAMR_BUILD_STRINGREF EQUAL 1)
+    set (WAMR_BUILD_GC 1)
+endif ()
+
 if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
 if (WAMR_BUILD_GC_BINARYEN EQUAL 1)
     set (WAMR_BUILD_GC 1)
     set (WAMR_BUILD_GC 1)
 endif ()
 endif ()

+ 4 - 0
core/config.h

@@ -467,6 +467,10 @@
 #define WASM_ENABLE_GC_BINARYEN 0
 #define WASM_ENABLE_GC_BINARYEN 0
 #endif
 #endif
 
 
+#ifndef WASM_ENABLE_STRINGREF
+#define WASM_ENABLE_STRINGREF 0
+#endif
+
 #ifndef GC_REFTYPE_MAP_SIZE_DEFAULT
 #ifndef GC_REFTYPE_MAP_SIZE_DEFAULT
 #define GC_REFTYPE_MAP_SIZE_DEFAULT 64
 #define GC_REFTYPE_MAP_SIZE_DEFAULT 64
 #endif
 #endif

+ 25 - 3
core/iwasm/common/gc/gc_common.c

@@ -19,14 +19,25 @@ wasm_ref_type_normalize(wasm_ref_type_t *ref_type)
     int32 heap_type = ref_type->heap_type;
     int32 heap_type = ref_type->heap_type;
 
 
     if (!((value_type >= VALUE_TYPE_I16 && value_type <= VALUE_TYPE_I32)
     if (!((value_type >= VALUE_TYPE_I16 && value_type <= VALUE_TYPE_I32)
-          || (value_type >= VALUE_TYPE_NULLREF
+          || (
+#if WASM_ENABLE_STRINGREF != 0
+              value_type >= VALUE_TYPE_STRINGVIEWITER
+#else
+              value_type >= VALUE_TYPE_NULLREF
+#endif
               && value_type <= VALUE_TYPE_FUNCREF))) {
               && value_type <= VALUE_TYPE_FUNCREF))) {
         return false;
         return false;
     }
     }
     if (value_type == VALUE_TYPE_HT_NULLABLE_REF
     if (value_type == VALUE_TYPE_HT_NULLABLE_REF
         || value_type == VALUE_TYPE_HT_NON_NULLABLE_REF) {
         || value_type == VALUE_TYPE_HT_NON_NULLABLE_REF) {
         if (heap_type < 0
         if (heap_type < 0
-            && (heap_type < HEAP_TYPE_NONE || heap_type > HEAP_TYPE_FUNC)) {
+#if WASM_ENABLE_STRINGREF != 0
+            && (heap_type < HEAP_TYPE_STRINGVIEWITER
+                || heap_type > HEAP_TYPE_FUNC)
+#else
+            && (heap_type < HEAP_TYPE_NONE || heap_type > HEAP_TYPE_FUNC)
+#endif
+        ) {
             return false;
             return false;
         }
         }
     }
     }
@@ -35,9 +46,20 @@ wasm_ref_type_normalize(wasm_ref_type_t *ref_type)
         ref_type->nullable = false;
         ref_type->nullable = false;
     }
     }
     else {
     else {
-        if (heap_type >= HEAP_TYPE_NONE && heap_type <= HEAP_TYPE_FUNC) {
+        if (
+#if WASM_ENABLE_STRINGREF != 0
+            heap_type >= HEAP_TYPE_STRINGVIEWITER && heap_type <= HEAP_TYPE_FUNC
+#else
+            heap_type >= HEAP_TYPE_NONE && heap_type <= HEAP_TYPE_FUNC
+#endif
+        ) {
             ref_type->value_type =
             ref_type->value_type =
+#if WASM_ENABLE_STRINGREF != 0
+                (uint8)(REF_TYPE_STRINGVIEWITER + heap_type
+                        - HEAP_TYPE_STRINGVIEWITER);
+#else
                 (uint8)(REF_TYPE_NULLREF + heap_type - HEAP_TYPE_NONE);
                 (uint8)(REF_TYPE_NULLREF + heap_type - HEAP_TYPE_NONE);
+#endif
             ref_type->nullable = false;
             ref_type->nullable = false;
             ref_type->heap_type = 0;
             ref_type->heap_type = 0;
         }
         }

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

@@ -12,6 +12,9 @@
 #if WASM_ENABLE_AOT != 0
 #if WASM_ENABLE_AOT != 0
 #include "../aot/aot_runtime.h"
 #include "../aot/aot_runtime.h"
 #endif
 #endif
+#if WASM_ENABLE_STRINGREF != 0
+#include "string_object.h"
+#endif
 
 
 WASMRttTypeRef
 WASMRttTypeRef
 wasm_rtt_type_new(WASMType *defined_type, uint32 defined_type_idx,
 wasm_rtt_type_new(WASMType *defined_type, uint32 defined_type_idx,
@@ -653,6 +656,14 @@ wasm_obj_is_type_of(WASMObjectRef obj, int32 heap_type)
             return wasm_obj_is_struct_obj(obj);
             return wasm_obj_is_struct_obj(obj);
         case HEAP_TYPE_ARRAY:
         case HEAP_TYPE_ARRAY:
             return wasm_obj_is_array_obj(obj);
             return wasm_obj_is_array_obj(obj);
+#if WASM_ENABLE_STRINGREF != 0
+        case HEAP_TYPE_STRINGREF:
+            return wasm_obj_is_stringref_obj(obj);
+        case HEAP_TYPE_STRINGVIEWWTF8:
+            return wasm_obj_is_stringview_wtf8_obj(obj);
+        case HEAP_TYPE_STRINGVIEWWTF16:
+            return wasm_obj_is_stringview_wtf16_obj(obj);
+#endif
         case HEAP_TYPE_NONE:
         case HEAP_TYPE_NONE:
         case HEAP_TYPE_NOFUNC:
         case HEAP_TYPE_NOFUNC:
         case HEAP_TYPE_NOEXTERN:
         case HEAP_TYPE_NOEXTERN:
@@ -698,6 +709,18 @@ wasm_object_get_ref_list(WASMObjectRef obj, bool *p_is_compact_mode,
         *p_ref_list = NULL;
         *p_ref_list = NULL;
         return true;
         return true;
     }
     }
+#if WASM_ENABLE_STRINGREF != 0
+    else if (rtt_type->type_flag == WASM_TYPE_STRINGREF
+             || rtt_type->type_flag == WASM_TYPE_STRINGVIEWWTF8
+             || rtt_type->type_flag == WASM_TYPE_STRINGVIEWWTF16
+             || rtt_type->type_flag == WASM_TYPE_STRINGVIEWITER) {
+        /* stringref/stringview_wtf8/stringview_wtf16/stringview_iter object */
+        *p_is_compact_mode = false;
+        *p_ref_num = 0;
+        *p_ref_list = NULL;
+        return true;
+    }
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
     else if (rtt_type->defined_type->type_flag == WASM_TYPE_FUNC) {
     else if (rtt_type->defined_type->type_flag == WASM_TYPE_FUNC) {
         /* function object */
         /* function object */
         *p_is_compact_mode = false;
         *p_is_compact_mode = false;
@@ -750,3 +773,270 @@ wasm_obj_unset_gc_finalizer(wasm_exec_env_t exec_env, void *obj)
     void *heap_handle = get_gc_heap_handle(exec_env);
     void *heap_handle = get_gc_heap_handle(exec_env);
     mem_allocator_unset_gc_finalizer(heap_handle, obj);
     mem_allocator_unset_gc_finalizer(heap_handle, obj);
 }
 }
+
+#if WASM_ENABLE_STRINGREF != 0
+WASMRttTypeRef
+wasm_stringref_rtt_type_new(uint16 type_flag, WASMRttType **rtt_types,
+                            korp_mutex *rtt_type_lock)
+{
+    WASMRttType *rtt_type;
+    uint32 index;
+
+    bh_assert(type_flag >= WASM_TYPE_STRINGREF
+              && type_flag <= WASM_TYPE_STRINGVIEWITER);
+
+    index = type_flag - WASM_TYPE_STRINGREF;
+
+    os_mutex_lock(rtt_type_lock);
+
+    if (rtt_types[index]) {
+        os_mutex_unlock(rtt_type_lock);
+        return rtt_types[index];
+    }
+
+    if ((rtt_type = wasm_runtime_malloc(sizeof(WASMRttType)))) {
+        memset(rtt_type, 0, sizeof(WASMRttType));
+        rtt_type->type_flag = type_flag;
+
+        rtt_types[index] = rtt_type;
+    }
+
+    os_mutex_unlock(rtt_type_lock);
+    return rtt_type;
+}
+
+static void
+wasm_stringref_obj_finalizer(WASMStringrefObjectRef stringref_obj, void *data)
+{
+    wasm_string_destroy(
+        (WASMString)wasm_stringref_obj_get_value(stringref_obj));
+}
+
+static void
+wasm_stringview_wtf8_obj_finalizer(WASMStringviewWTF8ObjectRef stringref_obj,
+                                   void *data)
+{
+    wasm_string_destroy(
+        (WASMString)wasm_stringview_wtf8_obj_get_value(stringref_obj));
+}
+
+static void
+wasm_stringview_wtf16_obj_finalizer(WASMStringviewWTF16ObjectRef stringref_obj,
+                                    void *data)
+{
+    wasm_string_destroy(
+        (WASMString)wasm_stringview_wtf16_obj_get_value(stringref_obj));
+}
+
+static void
+wasm_stringview_iter_obj_finalizer(WASMStringviewIterObjectRef stringref_obj,
+                                   void *data)
+{
+    wasm_string_destroy(
+        (WASMString)wasm_stringview_iter_obj_get_value(stringref_obj));
+}
+
+static WASMObjectRef
+stringref_obj_new(WASMExecEnv *exec_env, uint32 type, const void *str_obj,
+                  int32 pos)
+{
+    WASMObjectRef stringref_obj = NULL;
+    void *heap_handle = get_gc_heap_handle(exec_env);
+    WASMModuleInstanceCommon *module_inst =
+        wasm_runtime_get_module_inst(exec_env);
+    WASMRttTypeRef rtt_type = NULL;
+
+#if WASM_ENABLE_INTERP != 0
+    if (module_inst->module_type == Wasm_Module_Bytecode) {
+        WASMModule *module = ((WASMModuleInstance *)module_inst)->module;
+        rtt_type = wasm_stringref_rtt_type_new(type, module->stringref_rtts,
+                                               &module->rtt_type_lock);
+    }
+#endif
+#if WASM_ENABLE_AOT != 0
+    if (module_inst->module_type == Wasm_Module_AoT) {
+        AOTModule *module =
+            (AOTModule *)((AOTModuleInstance *)module_inst)->module;
+        /* TODO: implement stringref for AoT */
+        /*
+        rtt_type = aot_stringref_rtt_type_new(WASM_TYPE_STRINGREF,
+                                              module->stringref_rtts,
+                                              &module->rtt_type_lock);
+        */
+    }
+#endif
+
+    if (!rtt_type) {
+        return NULL;
+    }
+
+    if (type == WASM_TYPE_STRINGREF) {
+        if (!(stringref_obj =
+                  gc_obj_malloc(heap_handle, sizeof(WASMStringrefObject)))) {
+            return NULL;
+        }
+        ((WASMStringrefObjectRef)stringref_obj)->header =
+            (WASMObjectHeader)rtt_type;
+        ((WASMStringrefObjectRef)stringref_obj)->str_obj = str_obj;
+        wasm_obj_set_gc_finalizer(
+            exec_env, (wasm_obj_t)stringref_obj,
+            (wasm_obj_finalizer_t)wasm_stringref_obj_finalizer, NULL);
+    }
+    else if (type == WASM_TYPE_STRINGVIEWWTF8) {
+        if (!(stringref_obj = gc_obj_malloc(
+                  heap_handle, sizeof(WASMStringviewWTF8Object)))) {
+            return NULL;
+        }
+        ((WASMStringviewWTF8ObjectRef)stringref_obj)->header =
+            (WASMObjectHeader)rtt_type;
+        ((WASMStringviewWTF8ObjectRef)stringref_obj)->str_obj = str_obj;
+        wasm_obj_set_gc_finalizer(
+            exec_env, (wasm_obj_t)stringref_obj,
+            (wasm_obj_finalizer_t)wasm_stringview_wtf8_obj_finalizer, NULL);
+    }
+    else if (type == WASM_TYPE_STRINGVIEWWTF16) {
+        if (!(stringref_obj = gc_obj_malloc(
+                  heap_handle, sizeof(WASMStringviewWTF16Object)))) {
+            return NULL;
+        }
+        ((WASMStringviewWTF16ObjectRef)stringref_obj)->header =
+            (WASMObjectHeader)rtt_type;
+        ((WASMStringviewWTF16ObjectRef)stringref_obj)->str_obj = str_obj;
+        wasm_obj_set_gc_finalizer(
+            exec_env, (wasm_obj_t)stringref_obj,
+            (wasm_obj_finalizer_t)wasm_stringview_wtf16_obj_finalizer, NULL);
+    }
+    else if (type == WASM_TYPE_STRINGVIEWITER) {
+        if (!(stringref_obj = gc_obj_malloc(
+                  heap_handle, sizeof(WASMStringviewIterObject)))) {
+            return NULL;
+        }
+        ((WASMStringviewIterObjectRef)stringref_obj)->header =
+            (WASMObjectHeader)rtt_type;
+        ((WASMStringviewIterObjectRef)stringref_obj)->str_obj = str_obj;
+        ((WASMStringviewIterObjectRef)stringref_obj)->pos = pos;
+        wasm_obj_set_gc_finalizer(
+            exec_env, (wasm_obj_t)stringref_obj,
+            (wasm_obj_finalizer_t)wasm_stringview_iter_obj_finalizer, NULL);
+    }
+
+    return stringref_obj;
+}
+
+WASMStringrefObjectRef
+wasm_stringref_obj_new(WASMExecEnv *exec_env, const void *str_obj)
+{
+    WASMStringrefObjectRef stringref_obj;
+
+    stringref_obj = (WASMStringrefObjectRef)stringref_obj_new(
+        exec_env, WASM_TYPE_STRINGREF, str_obj, 0);
+
+    return stringref_obj;
+}
+
+WASMStringviewWTF8ObjectRef
+wasm_stringview_wtf8_obj_new(WASMExecEnv *exec_env, const void *str_obj)
+{
+    WASMStringviewWTF8ObjectRef stringview_wtf8_obj;
+
+    stringview_wtf8_obj = (WASMStringviewWTF8ObjectRef)stringref_obj_new(
+        exec_env, WASM_TYPE_STRINGVIEWWTF8, str_obj, 0);
+
+    return stringview_wtf8_obj;
+}
+
+WASMStringviewWTF16ObjectRef
+wasm_stringview_wtf16_obj_new(WASMExecEnv *exec_env, const void *str_obj)
+{
+    WASMStringviewWTF16ObjectRef stringview_wtf16_obj;
+
+    stringview_wtf16_obj = (WASMStringviewWTF16ObjectRef)stringref_obj_new(
+        exec_env, WASM_TYPE_STRINGVIEWWTF16, str_obj, 0);
+
+    return stringview_wtf16_obj;
+}
+
+WASMStringviewIterObjectRef
+wasm_stringview_iter_obj_new(WASMExecEnv *exec_env, const void *str_obj,
+                             int32 pos)
+{
+    WASMStringviewIterObjectRef stringview_iter_obj;
+
+    stringview_iter_obj = (WASMStringviewIterObjectRef)stringref_obj_new(
+        exec_env, WASM_TYPE_STRINGVIEWITER, str_obj, pos);
+
+    return stringview_iter_obj;
+}
+
+const void *
+wasm_stringref_obj_get_value(WASMStringrefObjectRef stringref_obj)
+{
+    return stringref_obj->str_obj;
+}
+
+const void *
+wasm_stringview_wtf8_obj_get_value(
+    WASMStringviewWTF8ObjectRef stringview_wtf8_obj)
+{
+    return stringview_wtf8_obj->str_obj;
+}
+
+const void *
+wasm_stringview_wtf16_obj_get_value(
+    WASMStringviewWTF16ObjectRef stringview_wtf16_obj)
+{
+    return stringview_wtf16_obj->str_obj;
+}
+
+const void *
+wasm_stringview_iter_obj_get_value(
+    WASMStringviewIterObjectRef stringview_iter_obj)
+{
+    return stringview_iter_obj->str_obj;
+}
+
+int32
+wasm_stringview_iter_obj_get_pos(
+    WASMStringviewIterObjectRef stringview_iter_obj)
+{
+    return stringview_iter_obj->pos;
+}
+
+void
+wasm_stringview_iter_obj_update_pos(
+    WASMStringviewIterObjectRef stringview_iter_obj, int32 pos)
+{
+    stringview_iter_obj->pos = pos;
+}
+
+#define WASM_OBJ_IS_STRINGREF_IMPL(flag)                \
+    WASMRttTypeRef rtt_type;                            \
+                                                        \
+    bh_assert(obj);                                     \
+                                                        \
+    if (wasm_obj_is_i31_externref_or_anyref_obj(obj))   \
+        return false;                                   \
+                                                        \
+    rtt_type = (WASMRttTypeRef)wasm_object_header(obj); \
+    return rtt_type->type_flag == flag ? true : false
+
+bool
+wasm_obj_is_stringref_obj(WASMObjectRef obj)
+{
+    WASM_OBJ_IS_STRINGREF_IMPL(WASM_TYPE_STRINGREF);
+}
+
+bool
+wasm_obj_is_stringview_wtf8_obj(WASMObjectRef obj)
+{
+    WASM_OBJ_IS_STRINGREF_IMPL(WASM_TYPE_STRINGVIEWWTF8);
+}
+
+bool
+wasm_obj_is_stringview_wtf16_obj(WASMObjectRef obj)
+{
+    WASM_OBJ_IS_STRINGREF_IMPL(WASM_TYPE_STRINGVIEWWTF16);
+}
+#undef WASM_OBJ_IS_STRINGREF_IMPL
+
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */

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

@@ -102,6 +102,28 @@ typedef struct WASMFuncObject {
     uint32 func_idx_bound;
     uint32 func_idx_bound;
 } WASMFuncObject, *WASMFuncObjectRef;
 } WASMFuncObject, *WASMFuncObjectRef;
 
 
+/* Representation of WASM stringref objects */
+typedef struct WASMStringrefObject {
+    WASMObjectHeader header;
+    const void *str_obj;
+} WASMStringrefObject, *WASMStringrefObjectRef;
+
+typedef struct WASMStringviewWTF8Object {
+    WASMObjectHeader header;
+    const void *str_obj;
+} WASMStringviewWTF8Object, *WASMStringviewWTF8ObjectRef;
+
+typedef struct WASMStringviewWTF16Object {
+    WASMObjectHeader header;
+    const void *str_obj;
+} WASMStringviewWTF16Object, *WASMStringviewWTF16ObjectRef;
+
+typedef struct WASMStringviewIterObject {
+    WASMObjectHeader header;
+    const void *str_obj;
+    int32 pos;
+} WASMStringviewIterObject, *WASMStringviewIterObjectRef;
+
 struct WASMExecEnv;
 struct WASMExecEnv;
 
 
 inline static WASMObjectHeader
 inline static WASMObjectHeader
@@ -284,6 +306,54 @@ wasm_object_get_ref_list(WASMObjectRef obj, bool *p_is_compact_mode,
                          uint32 *p_ref_num, uint16 **p_ref_list,
                          uint32 *p_ref_num, uint16 **p_ref_list,
                          uint32 *p_ref_start_offset);
                          uint32 *p_ref_start_offset);
 
 
+#if WASM_ENABLE_STRINGREF != 0
+WASMStringrefObjectRef
+wasm_stringref_obj_new(struct WASMExecEnv *exec_env, const void *str_obj);
+
+WASMStringviewWTF8ObjectRef
+wasm_stringview_wtf8_obj_new(struct WASMExecEnv *exec_env, const void *str_obj);
+
+WASMStringviewWTF16ObjectRef
+wasm_stringview_wtf16_obj_new(struct WASMExecEnv *exec_env,
+                              const void *str_obj);
+
+WASMStringviewIterObjectRef
+wasm_stringview_iter_obj_new(struct WASMExecEnv *exec_env, const void *str_obj,
+                             int32 pos);
+
+const void *
+wasm_stringref_obj_get_value(WASMStringrefObjectRef stringref_obj);
+
+const void *
+wasm_stringview_wtf8_obj_get_value(
+    WASMStringviewWTF8ObjectRef stringview_wtf8_obj);
+
+const void *
+wasm_stringview_wtf16_obj_get_value(
+    WASMStringviewWTF16ObjectRef stringview_wtf16_obj);
+
+const void *
+wasm_stringview_iter_obj_get_value(
+    WASMStringviewIterObjectRef stringview_iter_obj);
+
+int32
+wasm_stringview_iter_obj_get_pos(
+    WASMStringviewIterObjectRef stringview_iter_obj);
+
+void
+wasm_stringview_iter_obj_update_pos(
+    WASMStringviewIterObjectRef stringview_iter_obj, int32 pos);
+
+bool
+wasm_obj_is_stringref_obj(WASMObjectRef obj);
+
+bool
+wasm_obj_is_stringview_wtf8_obj(WASMObjectRef obj);
+
+bool
+wasm_obj_is_stringview_wtf16_obj(WASMObjectRef obj);
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 } /* end of extern "C" */
 } /* end of extern "C" */
 #endif
 #endif

+ 64 - 1
core/iwasm/common/gc/gc_type.c

@@ -616,7 +616,12 @@ wasm_reftype_size(uint8 type)
         return 4;
         return 4;
     else if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)
     else if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64)
         return 8;
         return 8;
+#if WASM_ENABLE_STRINGREF != 0
+    else if (type >= (uint8)REF_TYPE_STRINGVIEWITER
+             && type <= (uint8)REF_TYPE_FUNCREF)
+#else
     else if (type >= (uint8)REF_TYPE_NULLREF && type <= (uint8)REF_TYPE_FUNCREF)
     else if (type >= (uint8)REF_TYPE_NULLREF && type <= (uint8)REF_TYPE_FUNCREF)
+#endif
         return sizeof(uintptr_t);
         return sizeof(uintptr_t);
     else if (type == PACKED_TYPE_I8)
     else if (type == PACKED_TYPE_I8)
         return 1;
         return 1;
@@ -745,13 +750,26 @@ wasm_is_reftype_supers_of_extern(uint8 type)
     return (type == REF_TYPE_EXTERNREF) ? true : false;
     return (type == REF_TYPE_EXTERNREF) ? true : false;
 }
 }
 
 
+#if WASM_ENABLE_STRINGREF != 0
+inline static bool
+wasm_is_reftype_supers_of_string(uint8 type)
+{
+    return (type == REF_TYPE_STRINGREF || type == REF_TYPE_ANYREF) ? true
+                                                                   : false;
+}
+#endif
+
 inline static bool
 inline static bool
 wasm_is_reftype_supers_of_none(uint8 type, const WASMRefType *ref_type,
 wasm_is_reftype_supers_of_none(uint8 type, const WASMRefType *ref_type,
                                const WASMTypePtr *types, uint32 type_count)
                                const WASMTypePtr *types, uint32 type_count)
 {
 {
     if (type == REF_TYPE_NULLREF || type == REF_TYPE_I31REF
     if (type == REF_TYPE_NULLREF || type == REF_TYPE_I31REF
         || type == REF_TYPE_STRUCTREF || type == REF_TYPE_ARRAYREF
         || type == REF_TYPE_STRUCTREF || type == REF_TYPE_ARRAYREF
-        || wasm_is_reftype_supers_of_eq(type))
+        || wasm_is_reftype_supers_of_eq(type)
+#if WASM_ENABLE_STRINGREF != 0
+        || type == REF_TYPE_STRINGREF
+#endif
+    )
         return true;
         return true;
 
 
     if (type == REF_TYPE_HT_NULLABLE && ref_type != NULL
     if (type == REF_TYPE_HT_NULLABLE && ref_type != NULL
@@ -875,6 +893,20 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
     else if (type1 == REF_TYPE_NULLEXTERNREF) {
     else if (type1 == REF_TYPE_NULLEXTERNREF) {
         return wasm_is_reftype_supers_of_noextern(type2);
         return wasm_is_reftype_supers_of_noextern(type2);
     }
     }
+#if WASM_ENABLE_STRINGREF != 0
+    else if (type1 == REF_TYPE_STRINGREF) {
+        return wasm_is_reftype_supers_of_string(type2);
+    }
+    else if (type1 == REF_TYPE_STRINGVIEWWTF8) {
+        return type2 == REF_TYPE_STRINGVIEWWTF8 ? true : false;
+    }
+    else if (type1 == REF_TYPE_STRINGVIEWWTF16) {
+        return type2 == REF_TYPE_STRINGVIEWWTF16 ? true : false;
+    }
+    else if (type1 == REF_TYPE_STRINGVIEWITER) {
+        return type2 == REF_TYPE_STRINGVIEWITER ? true : false;
+    }
+#endif
     else if (type1 == REF_TYPE_HT_NULLABLE) {
     else if (type1 == REF_TYPE_HT_NULLABLE) {
         if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) {
         if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) {
             /* reftype1 is (ref null $t) */
             /* reftype1 is (ref null $t) */
@@ -895,6 +927,23 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
             else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
             else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
                      == WASM_TYPE_FUNC)
                      == WASM_TYPE_FUNC)
                 return wasm_is_reftype_supers_of_func(type2);
                 return wasm_is_reftype_supers_of_func(type2);
+#if WASM_ENABLE_STRINGREF != 0
+            else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
+                     == WASM_TYPE_STRINGREF)
+                return wasm_is_reftype_supers_of_string(type2);
+            else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
+                     == WASM_TYPE_STRINGVIEWWTF8) {
+                return type2 == REF_TYPE_STRINGVIEWWTF8 ? true : false;
+            }
+            else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
+                     == WASM_TYPE_STRINGVIEWWTF16) {
+                return type2 == REF_TYPE_STRINGVIEWWTF16 ? true : false;
+            }
+            else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
+                     == WASM_TYPE_STRINGVIEWITER) {
+                return type2 == REF_TYPE_STRINGVIEWITER ? true : false;
+            }
+#endif
             else
             else
                 return false;
                 return false;
         }
         }
@@ -1019,6 +1068,20 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
                     /* (ref func) <: [funcref] */
                     /* (ref func) <: [funcref] */
                     return wasm_is_reftype_supers_of_func(type2);
                     return wasm_is_reftype_supers_of_func(type2);
                 }
                 }
+#if WASM_ENABLE_STRINGREF != 0
+                else if (heap_type == HEAP_TYPE_STRINGREF) {
+                    return wasm_is_reftype_supers_of_string(type2);
+                }
+                else if (heap_type == HEAP_TYPE_STRINGVIEWWTF8) {
+                    return type2 == REF_TYPE_STRINGVIEWWTF8 ? true : false;
+                }
+                else if (heap_type == HEAP_TYPE_STRINGVIEWWTF16) {
+                    return type2 == REF_TYPE_STRINGVIEWWTF16 ? true : false;
+                }
+                else if (heap_type == HEAP_TYPE_STRINGVIEWITER) {
+                    return type2 == REF_TYPE_STRINGVIEWITER ? true : false;
+                }
+#endif
                 else if (heap_type == HEAP_TYPE_NONE) {
                 else if (heap_type == HEAP_TYPE_NONE) {
                     /* (ref none) */
                     /* (ref none) */
                     /* TODO */
                     /* TODO */

+ 25 - 2
core/iwasm/common/gc/gc_type.h

@@ -120,7 +120,13 @@ wasm_type_is_subtype_of(const WASMType *type1, const WASMType *type2,
 inline static bool
 inline static bool
 wasm_is_type_reftype(uint8 type)
 wasm_is_type_reftype(uint8 type)
 {
 {
-    return (type >= (uint8)REF_TYPE_NULLREF && type <= (uint8)REF_TYPE_FUNCREF)
+    return (
+#if WASM_ENABLE_STRINGREF != 0
+               type >= (uint8)REF_TYPE_STRINGVIEWITER
+#else
+               type >= (uint8)REF_TYPE_NULLREF
+#endif
+               && type <= (uint8)REF_TYPE_FUNCREF)
                ? true
                ? true
                : false;
                : false;
 }
 }
@@ -244,8 +250,14 @@ wasm_is_refheaptype_common(const RefHeapType_Common *ref_heap_type)
 {
 {
     return ((ref_heap_type->heap_type >= (int32)HEAP_TYPE_EQ
     return ((ref_heap_type->heap_type >= (int32)HEAP_TYPE_EQ
              && ref_heap_type->heap_type <= (int32)HEAP_TYPE_FUNC)
              && ref_heap_type->heap_type <= (int32)HEAP_TYPE_FUNC)
+#if WASM_ENABLE_STRINGREF != 0
+            || (ref_heap_type->heap_type >= (int32)HEAP_TYPE_STRINGVIEWITER
+                && ref_heap_type->heap_type <= (int32)HEAP_TYPE_I31)
+#else
             || (ref_heap_type->heap_type >= (int32)HEAP_TYPE_NONE
             || (ref_heap_type->heap_type >= (int32)HEAP_TYPE_NONE
-                && ref_heap_type->heap_type <= (int32)HEAP_TYPE_I31))
+                && ref_heap_type->heap_type <= (int32)HEAP_TYPE_I31)
+#endif
+                )
                ? true
                ? true
                : false;
                : false;
 }
 }
@@ -285,6 +297,17 @@ wasm_is_refheaptype_array(const RefHeapType_Common *ref_heap_type)
     return ref_heap_type->heap_type == (int32)HEAP_TYPE_ARRAY ? true : false;
     return ref_heap_type->heap_type == (int32)HEAP_TYPE_ARRAY ? true : false;
 }
 }
 
 
+#if WASM_ENABLE_STRINGREF != 0
+inline static bool
+wasm_is_refheaptype_stringrefs(const RefHeapType_Common *ref_heap_type)
+{
+    return ref_heap_type->heap_type <= (int32)HEAP_TYPE_STRINGREF
+                   && ref_heap_type->heap_type >= HEAP_TYPE_STRINGVIEWITER
+               ? true
+               : false;
+}
+#endif
+
 /* Whether two ref heap types are equal */
 /* Whether two ref heap types are equal */
 bool
 bool
 wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1,
 wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1,

+ 16 - 1
core/iwasm/common/gc/iwasm_gc.cmake

@@ -11,7 +11,22 @@ endif ()
 
 
 include_directories (${IWASM_GC_DIR})
 include_directories (${IWASM_GC_DIR})
 
 
-file (GLOB_RECURSE source_all ${IWASM_GC_DIR}/*.c)
+file (GLOB source_all ${IWASM_GC_DIR}/*.c)
 
 
 set (IWASM_GC_SOURCE ${source_all})
 set (IWASM_GC_SOURCE ${source_all})
 
 
+if (WAMR_BUILD_STRINGREF EQUAL 1)
+  set (IWASM_STRINGREF_DIR ${CMAKE_CURRENT_LIST_DIR}/stringref)
+
+  add_definitions (-DWASM_ENABLE_STRINGREF=1)
+
+  include_directories (${IWASM_STRINGREF_DIR})
+
+  if (NOT DEFINED WAMR_STRINGREF_IMPL_SOURCE)
+    message(FATAL_ERROR "stringref feature enabled, but WAMR_STRINGREF_IMPL_SOURCE not set" )
+  else ()
+    set (IWASM_STRINGREF_SOURCE ${WAMR_STRINGREF_IMPL_SOURCE})
+  endif ()
+
+  set (IWASM_GC_SOURCE ${IWASM_GC_SOURCE} ${IWASM_STRINGREF_SOURCE})
+endif ()

+ 113 - 0
core/iwasm/common/gc/stringref/string_object.h

@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _STRING_OBJECT_H_
+#define _STRING_OBJECT_H_
+
+#include "wasm.h"
+
+typedef enum EncodingFlag {
+    UTF8,
+    WTF8,
+    WTF16,
+    LOSSY_UTF8,
+} EncodingFlag;
+
+typedef enum StringViewType {
+    STRING_VIEW_WTF8,
+    STRING_VIEW_WTF16,
+    STRING_VIEW_ITER,
+} StringViewType;
+
+typedef enum ErrorCode {
+    Insufficient_Space = -3,
+    Encode_Fail = -2,
+    Isolated_Surrogate = -1,
+} ErrorCode;
+
+/******************* gc finalizer *****************/
+void
+wasm_string_destroy(WASMString str_obj);
+
+/******************* opcode functions *****************/
+
+/* string.const */
+WASMString
+wasm_string_new_const(const char *str);
+
+/* string.new_xx8/new_wtf16 */
+/* string.new_xx8_array */
+/* string.new_wtf16_array */
+WASMString
+wasm_string_new_with_encoding(void *addr, uint32 count, EncodingFlag flag);
+
+/* string.measure */
+int32
+wasm_string_measure(WASMString str_obj, EncodingFlag flag);
+
+/* stringview_wtf16.length */
+int32
+wasm_string_wtf16_get_length(WASMString str_obj);
+
+/* string.encode_xx8 */
+/* string.encode_wtf16 */
+/* stringview_wtf8.encode_xx */
+/* stringview_wtf16.encode */
+/* string.encode_xx8_array */
+/* string.encode_wtf16_array */
+int32
+wasm_string_encode(WASMString str_obj, uint32 pos, uint32 count, void *addr,
+                   uint32 *next_pos, EncodingFlag flag);
+
+/* string.concat */
+WASMString
+wasm_string_concat(WASMString str_obj1, WASMString str_obj2);
+
+/* string.eq */
+int32
+wasm_string_eq(WASMString str_obj1, WASMString str_obj2);
+
+/* string.is_usv_sequence */
+int32
+wasm_string_is_usv_sequence(WASMString str_obj);
+
+/* string.as_wtf8 */
+/* string.as_wtf16 */
+/* string.as_iter */
+WASMString
+wasm_string_create_view(WASMString str_obj, StringViewType type);
+
+/* stringview_wtf8.advance */
+/* stringview_iter.advance */
+int32
+wasm_string_advance(WASMString str_obj, uint32 pos, uint32 count,
+                    uint32 *target_pos);
+
+/* stringview_wtf8.slice */
+/* stringview_wtf16.slice */
+/* stringview_iter.slice */
+WASMString
+wasm_string_slice(WASMString str_obj, uint32 start, uint32 end,
+                  StringViewType type);
+
+/* stringview_wtf16.get_codeunit */
+int16
+wasm_string_get_wtf16_codeunit(WASMString str_obj, int32 pos);
+
+/* stringview_iter.next */
+uint32
+wasm_string_next_codepoint(WASMString str_obj, uint32 pos);
+
+/* stringview_iter.rewind */
+uint32
+wasm_string_rewind(WASMString str_obj, uint32 pos, uint32 count,
+                   uint32 *target_pos);
+
+/******************* application functions *****************/
+
+void
+wasm_string_dump(WASMString str_obj);
+
+#endif /* end of _STRING_OBJECT_H_ */

+ 15 - 0
core/iwasm/common/wasm_application.c

@@ -15,6 +15,9 @@
 #endif
 #endif
 #if WASM_ENABLE_GC != 0
 #if WASM_ENABLE_GC != 0
 #include "gc/gc_object.h"
 #include "gc/gc_object.h"
+#if WASM_ENABLE_STRINGREF != 0
+#include "string_object.h"
+#endif
 #endif
 #endif
 
 
 static void
 static void
@@ -718,6 +721,18 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
                     }
                     }
                     else if (wasm_obj_is_func_obj(gc_obj))
                     else if (wasm_obj_is_func_obj(gc_obj))
                         os_printf("ref.func");
                         os_printf("ref.func");
+#if WASM_ENABLE_STRINGREF != 0
+                    else if (wasm_obj_is_stringref_obj(gc_obj)
+                             || wasm_obj_is_stringview_wtf8_obj(gc_obj)) {
+                        wasm_string_dump(
+                            (WASMString)wasm_stringref_obj_get_value(gc_obj));
+                    }
+                    else if (wasm_obj_is_stringview_wtf16_obj(gc_obj)) {
+                        wasm_string_dump(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                gc_obj));
+                    }
+#endif
                     else if (wasm_obj_is_externref_obj(gc_obj)) {
                     else if (wasm_obj_is_externref_obj(gc_obj)) {
                         WASMObjectRef obj = wasm_externref_obj_to_internal_obj(
                         WASMObjectRef obj = wasm_externref_obj_to_internal_obj(
                             (WASMExternrefObjectRef)gc_obj);
                             (WASMExternrefObjectRef)gc_obj);

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

@@ -96,7 +96,11 @@ compare_type_with_signautre(uint8 type, const char signature)
 #if WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_REF_TYPES != 0
     if ('r' == signature
     if ('r' == signature
 #if WASM_ENABLE_GC != 0
 #if WASM_ENABLE_GC != 0
+#if WASM_ENABLE_STRINGREF != 0
+        && (type >= REF_TYPE_STRINGVIEWITER && type <= REF_TYPE_FUNCREF)
+#else
         && (type >= REF_TYPE_NULLREF && type <= REF_TYPE_FUNCREF)
         && (type >= REF_TYPE_NULLREF && type <= REF_TYPE_FUNCREF)
+#endif
 #else
 #else
         && type == VALUE_TYPE_EXTERNREF
         && type == VALUE_TYPE_EXTERNREF
 #endif
 #endif

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

@@ -3569,6 +3569,12 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
             {
             {
                 bh_memcpy_s(argv_dst, sizeof(uintptr_t), argv_src,
                 bh_memcpy_s(argv_dst, sizeof(uintptr_t), argv_src,
                             sizeof(uintptr_t));
                             sizeof(uintptr_t));
@@ -3632,6 +3638,12 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
             {
             {
                 bh_memcpy_s(argv_ret, sizeof(uintptr_t), argv1,
                 bh_memcpy_s(argv_ret, sizeof(uintptr_t), argv1,
                             sizeof(uintptr_t));
                             sizeof(uintptr_t));
@@ -3734,6 +3746,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_FUNCREF:
@@ -3892,6 +3910,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_FUNCREF:
@@ -4111,6 +4135,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_FUNCREF:
@@ -4257,6 +4287,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_FUNCREF:
@@ -4357,6 +4393,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0
             case VALUE_TYPE_FUNCREF:
             case VALUE_TYPE_FUNCREF:
@@ -4616,6 +4658,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
                 if (n_ints < MAX_REG_INTS)
                 if (n_ints < MAX_REG_INTS)
                     ints[n_ints++] = *(uint64 *)argv_src;
                     ints[n_ints++] = *(uint64 *)argv_src;
@@ -4719,6 +4767,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr,
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_STRUCTREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_ARRAYREF:
             case REF_TYPE_NULLREF:
             case REF_TYPE_NULLREF:
+#if WASM_ENABLE_STRINGREF != 0
+            case REF_TYPE_STRINGREF:
+            case REF_TYPE_STRINGVIEWWTF8:
+            case REF_TYPE_STRINGVIEWWTF16:
+            case REF_TYPE_STRINGVIEWITER:
+#endif
 #endif
 #endif
                 PUT_I64_TO_ADDR(argv_ret,
                 PUT_I64_TO_ADDR(argv_ret,
                                 invokeNative_Int64(func_ptr, argv1, n_stacks));
                                 invokeNative_Int64(func_ptr, argv1, n_stacks));

+ 5 - 0
core/iwasm/include/gc_export.h

@@ -34,6 +34,10 @@ typedef enum wasm_value_type_enum {
     VALUE_TYPE_STRUCTREF = 0x67,
     VALUE_TYPE_STRUCTREF = 0x67,
     VALUE_TYPE_ARRAYREF = 0x66,
     VALUE_TYPE_ARRAYREF = 0x66,
     VALUE_TYPE_NULLREF = 0x65,
     VALUE_TYPE_NULLREF = 0x65,
+    VALUE_TYPE_STRINGREF = 0X64,
+    VALUE_TYPE_STRINGVIEWWTF8 = 0x63,
+    VALUE_TYPE_STRINGVIEWWTF16 = 0x62,
+    VALUE_TYPE_STRINGVIEWITER = 0x61
 } wasm_value_type_enum;
 } wasm_value_type_enum;
 
 
 typedef int32_t wasm_heap_type_t;
 typedef int32_t wasm_heap_type_t;
@@ -133,6 +137,7 @@ typedef struct WASMAnyrefObject *wasm_anyref_obj_t;
 typedef struct WASMStructObject *wasm_struct_obj_t;
 typedef struct WASMStructObject *wasm_struct_obj_t;
 typedef struct WASMArrayObject *wasm_array_obj_t;
 typedef struct WASMArrayObject *wasm_array_obj_t;
 typedef struct WASMFuncObject *wasm_func_obj_t;
 typedef struct WASMFuncObject *wasm_func_obj_t;
+typedef struct WASMStringrefObject *wasm_stringref_obj_t;
 typedef uintptr_t wasm_i31_obj_t;
 typedef uintptr_t wasm_i31_obj_t;
 
 
 typedef void (*wasm_obj_finalizer_t)(const wasm_obj_t obj, void *data);
 typedef void (*wasm_obj_finalizer_t)(const wasm_obj_t obj, void *data);

+ 71 - 3
core/iwasm/interpreter/wasm.h

@@ -44,6 +44,10 @@ extern "C" {
 #define REF_TYPE_STRUCTREF 0x67
 #define REF_TYPE_STRUCTREF 0x67
 #define REF_TYPE_ARRAYREF 0x66
 #define REF_TYPE_ARRAYREF 0x66
 #define REF_TYPE_NULLREF 0x65
 #define REF_TYPE_NULLREF 0x65
+#define REF_TYPE_STRINGREF VALUE_TYPE_STRINGREF
+#define REF_TYPE_STRINGVIEWWTF8 VALUE_TYPE_STRINGVIEWWTF8
+#define REF_TYPE_STRINGVIEWWTF16 VALUE_TYPE_STRINGVIEWWTF16
+#define REF_TYPE_STRINGVIEWITER VALUE_TYPE_STRINGVIEWITER
 
 
 /* Heap Types */
 /* Heap Types */
 #define HEAP_TYPE_FUNC (-0x10)
 #define HEAP_TYPE_FUNC (-0x10)
@@ -56,6 +60,10 @@ extern "C" {
 #define HEAP_TYPE_STRUCT (-0x19)
 #define HEAP_TYPE_STRUCT (-0x19)
 #define HEAP_TYPE_ARRAY (-0x1A)
 #define HEAP_TYPE_ARRAY (-0x1A)
 #define HEAP_TYPE_NONE (-0x1B)
 #define HEAP_TYPE_NONE (-0x1B)
+#define HEAP_TYPE_STRINGREF (-0x1C)
+#define HEAP_TYPE_STRINGVIEWWTF8 (-0x1D)
+#define HEAP_TYPE_STRINGVIEWWTF16 (-0x1E)
+#define HEAP_TYPE_STRINGVIEWITER (-0x1F)
 
 
 /* Defined Types */
 /* Defined Types */
 #define DEFINED_TYPE_FUNC 0x60
 #define DEFINED_TYPE_FUNC 0x60
@@ -71,7 +79,7 @@ extern "C" {
  * Used by loader to represent any type of i32/i64/f32/f64/v128
  * Used by loader to represent any type of i32/i64/f32/f64/v128
  * and ref types, including funcref, externref, anyref, eqref,
  * and ref types, including funcref, externref, anyref, eqref,
  * (ref null $ht), (ref $ht), i31ref, structref, arrayref,
  * (ref null $ht), (ref $ht), i31ref, structref, arrayref,
- * nullfuncref, nullexternref and nullref
+ * nullfuncref, nullexternref, nullref and stringref
  */
  */
 #define VALUE_TYPE_ANY 0x42
 #define VALUE_TYPE_ANY 0x42
 /**
 /**
@@ -132,6 +140,9 @@ typedef void *table_elem_type_t;
 #if WASM_ENABLE_BULK_MEMORY != 0
 #if WASM_ENABLE_BULK_MEMORY != 0
 #define SECTION_TYPE_DATACOUNT 12
 #define SECTION_TYPE_DATACOUNT 12
 #endif
 #endif
+#if WASM_ENABLE_STRINGREF != 0
+#define SECTION_TYPE_STRINGREF 14
+#endif
 
 
 #define SUB_SECTION_TYPE_MODULE 0
 #define SUB_SECTION_TYPE_MODULE 0
 #define SUB_SECTION_TYPE_FUNC 1
 #define SUB_SECTION_TYPE_FUNC 1
@@ -156,6 +167,13 @@ typedef void *table_elem_type_t;
 #define WASM_TYPE_STRUCT 1
 #define WASM_TYPE_STRUCT 1
 #define WASM_TYPE_ARRAY 2
 #define WASM_TYPE_ARRAY 2
 
 
+#if WASM_ENABLE_STRINGREF != 0
+#define WASM_TYPE_STRINGREF 3
+#define WASM_TYPE_STRINGVIEWWTF8 4
+#define WASM_TYPE_STRINGVIEWWTF16 5
+#define WASM_TYPE_STRINGVIEWITER 6
+#endif
+
 typedef struct WASMModule WASMModule;
 typedef struct WASMModule WASMModule;
 typedef struct WASMFunction WASMFunction;
 typedef struct WASMFunction WASMFunction;
 typedef struct WASMGlobal WASMGlobal;
 typedef struct WASMGlobal WASMGlobal;
@@ -353,6 +371,36 @@ typedef struct WASMArrayType {
        described with one byte */
        described with one byte */
     WASMRefType *elem_ref_type;
     WASMRefType *elem_ref_type;
 } WASMArrayType;
 } WASMArrayType;
+
+#if WASM_ENABLE_STRINGREF != 0
+/* stringref representation, we define it as a void * pointer here, the
+ * stringref implementation can use any structure */
+/*
+    WasmGC heap
+    +-----------------------+
+    |                       |
+    |   stringref           |
+    |   +----------+        |             external string representation
+    |   | host_ptr |--------o------+----->+------------+
+    |   +----------+        |      |      |            |
+    |                       |      |      +------------+
+    |   stringview_wtf8/16  |      |
+    |   +----------+        |      |
+    |   | host_ptr |--------o------+
+    |   +----------+        |      |
+    |                       |      |
+    |   stringview_iter     |      |
+    |   +----------+        |      |
+    |   | host_ptr |--------o------+
+    |   +----------+        |
+    |   |   pos    |        |
+    |   +----------+        |
+    |                       |
+    +-----------------------+
+*/
+typedef void *WASMString;
+
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
 #endif /* end of WASM_ENABLE_GC != 0 */
 #endif /* end of WASM_ENABLE_GC != 0 */
 
 
 typedef struct WASMTable {
 typedef struct WASMTable {
@@ -680,6 +728,12 @@ struct WASMModule {
 #if WASM_ENABLE_BULK_MEMORY != 0
 #if WASM_ENABLE_BULK_MEMORY != 0
     /* data count read from datacount section */
     /* data count read from datacount section */
     uint32 data_seg_count1;
     uint32 data_seg_count1;
+#endif
+#if WASM_ENABLE_GC != 0
+#if WASM_ENABLE_STRINGREF != 0
+    uint32 stringref_count;
+    char **string_consts;
+#endif
 #endif
 #endif
 
 
     uint32 import_function_count;
     uint32 import_function_count;
@@ -760,6 +814,15 @@ struct WASMModule {
     HashMap *ref_type_set;
     HashMap *ref_type_set;
     struct WASMRttType **rtt_types;
     struct WASMRttType **rtt_types;
     korp_mutex rtt_type_lock;
     korp_mutex rtt_type_lock;
+#if WASM_ENABLE_STRINGREF != 0
+    /* special rtts for stringref types
+        - stringref
+        - stringview_wtf8
+        - stringview_wtf16
+        - stringview_iter
+     */
+    struct WASMRttType *stringref_rtts[4];
+#endif
 #endif
 #endif
 
 
 #if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0
 #if WASM_ENABLE_DEBUG_INTERP != 0 || WASM_ENABLE_DEBUG_AOT != 0
@@ -970,8 +1033,13 @@ wasm_value_type_size_ex(uint8 value_type, bool gc_enabled)
     else if (value_type == VALUE_TYPE_V128)
     else if (value_type == VALUE_TYPE_V128)
         return sizeof(int64) * 2;
         return sizeof(int64) * 2;
 #endif
 #endif
-    else if (value_type >= (uint8)REF_TYPE_NULLREF /* 0x65 */
-             && value_type <= (uint8)REF_TYPE_FUNCREF /* 0x70 */ && gc_enabled)
+    else if (
+#if WASM_ENABLE_STRINGREF != 0
+        value_type >= (uint8)REF_TYPE_STRINGVIEWITER /* 0x61 */
+#else
+        value_type >= (uint8)REF_TYPE_NULLREF /* 0x65 */
+#endif
+        && value_type <= (uint8)REF_TYPE_FUNCREF /* 0x70 */ && gc_enabled)
         return sizeof(uintptr_t);
         return sizeof(uintptr_t);
     else if (value_type == VALUE_TYPE_FUNCREF
     else if (value_type == VALUE_TYPE_FUNCREF
              || value_type == VALUE_TYPE_EXTERNREF)
              || value_type == VALUE_TYPE_EXTERNREF)

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

@@ -13,6 +13,9 @@
 #if WASM_ENABLE_GC != 0
 #if WASM_ENABLE_GC != 0
 #include "../common/gc/gc_object.h"
 #include "../common/gc/gc_object.h"
 #include "mem_alloc.h"
 #include "mem_alloc.h"
+#if WASM_ENABLE_STRINGREF != 0
+#include "string_object.h"
+#endif
 #endif
 #endif
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #include "../common/wasm_shared_memory.h"
 #include "../common/wasm_shared_memory.h"
@@ -1391,6 +1394,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     WASMFuncObjectRef func_obj;
     WASMFuncObjectRef func_obj;
     WASMI31ObjectRef i31_obj;
     WASMI31ObjectRef i31_obj;
     WASMExternrefObjectRef externref_obj;
     WASMExternrefObjectRef externref_obj;
+#if WASM_ENABLE_STRINGREF != 0
+    WASMString str_obj = NULL;
+    WASMStringrefObjectRef stringref_obj;
+    WASMStringviewWTF8ObjectRef stringview_wtf8_obj;
+    WASMStringviewWTF16ObjectRef stringview_wtf16_obj;
+    WASMStringviewIterObjectRef stringview_iter_obj;
+#endif
 #endif
 #endif
 
 
 #if WASM_ENABLE_DEBUG_INTERP != 0
 #if WASM_ENABLE_DEBUG_INTERP != 0
@@ -2672,6 +2682,727 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         HANDLE_OP_END();
                         HANDLE_OP_END();
                     }
                     }
 
 
+#if WASM_ENABLE_STRINGREF != 0
+                    case WASM_OP_STRING_NEW_UTF8:
+                    case WASM_OP_STRING_NEW_WTF16:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8:
+                    case WASM_OP_STRING_NEW_WTF8:
+                    {
+                        uint32 mem_idx, addr, bytes_length, offset = 0;
+                        EncodingFlag flag = WTF8;
+
+                        read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
+                        bytes_length = POP_I32();
+                        addr = POP_I32();
+
+                        CHECK_MEMORY_OVERFLOW(bytes_length);
+
+                        if (opcode == WASM_OP_STRING_NEW_WTF16) {
+                            flag = WTF16;
+                        }
+                        else if (opcode == WASM_OP_STRING_NEW_UTF8) {
+                            flag = UTF8;
+                        }
+                        else if (opcode == WASM_OP_STRING_NEW_LOSSY_UTF8) {
+                            flag = LOSSY_UTF8;
+                        }
+                        else if (opcode == WASM_OP_STRING_NEW_WTF8) {
+                            flag = WTF8;
+                        }
+
+                        str_obj = wasm_string_new_with_encoding(
+                            maddr, bytes_length, flag);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+
+                        (void)mem_idx;
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_CONST:
+                    {
+                        WASMModule *wasm_module = module->module;
+                        uint32 contents;
+
+                        read_leb_uint32(frame_ip, frame_ip_end, contents);
+
+                        str_obj = wasm_string_new_const(
+                            wasm_module->string_consts[contents]);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_MEASURE_UTF8:
+                    case WASM_OP_STRING_MEASURE_WTF8:
+                    case WASM_OP_STRING_MEASURE_WTF16:
+                    {
+                        int32 target_bytes_length;
+                        EncodingFlag flag = WTF8;
+
+                        stringref_obj = POP_REF();
+
+                        if (opcode == WASM_OP_STRING_MEASURE_WTF16) {
+                            flag = WTF16;
+                        }
+                        else if (opcode == WASM_OP_STRING_MEASURE_UTF8) {
+                            flag = UTF8;
+                        }
+                        else if (opcode == WASM_OP_STRING_MEASURE_WTF8) {
+                            flag = LOSSY_UTF8;
+                        }
+                        target_bytes_length = wasm_string_measure(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            flag);
+
+                        PUSH_I32(target_bytes_length);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_ENCODE_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF16:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF8:
+                    {
+                        uint32 mem_idx, addr;
+                        int32 target_bytes_length;
+                        WASMMemoryInstance *memory_inst;
+                        EncodingFlag flag = WTF8;
+
+                        read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
+                        addr = POP_I32();
+                        stringref_obj = POP_REF();
+
+                        str_obj = (WASMString)wasm_stringref_obj_get_value(
+                            stringref_obj);
+
+                        memory_inst = module->memories[mem_idx];
+                        maddr = memory_inst->memory_data + addr;
+
+                        if (opcode == WASM_OP_STRING_ENCODE_WTF16) {
+                            flag = WTF16;
+                            count = wasm_string_measure(str_obj, flag);
+                            target_bytes_length = wasm_string_encode(
+                                str_obj, 0, count, maddr, NULL, flag);
+                        }
+                        else {
+                            if (opcode == WASM_OP_STRING_ENCODE_UTF8) {
+                                flag = UTF8;
+                            }
+                            else if (opcode
+                                     == WASM_OP_STRING_ENCODE_LOSSY_UTF8) {
+                                flag = LOSSY_UTF8;
+                            }
+                            else if (opcode == WASM_OP_STRING_ENCODE_WTF8) {
+                                flag = WTF8;
+                            }
+                            count = wasm_string_measure(str_obj, flag);
+                            target_bytes_length = wasm_string_encode(
+                                str_obj, 0, count, maddr, NULL, flag);
+
+                            if (target_bytes_length == -1) {
+                                wasm_set_exception(
+                                    module, "isolated surrogate is seen");
+                                goto got_exception;
+                            }
+                        }
+                        if (target_bytes_length < 0) {
+                            wasm_set_exception(module,
+                                               "stringref encode failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(target_bytes_length);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_CONCAT:
+                    {
+                        WASMStringrefObjectRef stringref_obj1, stringref_obj2;
+
+                        stringref_obj2 = POP_REF();
+                        stringref_obj1 = POP_REF();
+
+                        str_obj = wasm_string_concat(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj1),
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj2));
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_EQ:
+                    {
+                        WASMStringrefObjectRef stringref_obj1, stringref_obj2;
+                        int32 is_eq;
+
+                        stringref_obj2 = POP_REF();
+                        stringref_obj1 = POP_REF();
+
+                        is_eq = wasm_string_eq(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj1),
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj2));
+
+                        PUSH_I32(is_eq);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_IS_USV_SEQUENCE:
+                    {
+                        int32 is_usv_sequence;
+
+                        stringref_obj = POP_REF();
+
+                        is_usv_sequence = wasm_string_is_usv_sequence(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj));
+
+                        PUSH_I32(is_usv_sequence);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_AS_WTF8:
+                    {
+                        stringref_obj = POP_REF();
+
+                        str_obj = wasm_string_create_view(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            STRING_VIEW_WTF8);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringview_wtf8_obj =
+                            wasm_stringview_wtf8_obj_new(exec_env, str_obj);
+                        if (!stringview_wtf8_obj) {
+                            wasm_set_exception(module,
+                                               "create stringview wtf8 failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringview_wtf8_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_ADVANCE:
+                    {
+                        uint32 next_pos, bytes, pos;
+
+                        bytes = POP_I32();
+                        pos = POP_I32();
+                        stringview_wtf8_obj = POP_REF();
+
+                        next_pos = wasm_string_advance(
+                            (WASMString)wasm_stringview_wtf8_obj_get_value(
+                                stringview_wtf8_obj),
+                            pos, bytes, NULL);
+
+                        PUSH_I32(next_pos);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8:
+                    {
+                        uint32 mem_idx, addr, pos, bytes, next_pos;
+                        int32 bytes_written;
+                        WASMMemoryInstance *memory_inst;
+                        EncodingFlag flag = WTF8;
+
+                        if (opcode == WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8) {
+                            flag = UTF8;
+                        }
+                        else if (opcode
+                                 == WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8) {
+                            flag = LOSSY_UTF8;
+                        }
+                        else if (opcode
+                                 == WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8) {
+                            flag = WTF8;
+                        }
+
+                        read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
+                        bytes = POP_I32();
+                        pos = POP_I32();
+                        addr = POP_I32();
+                        stringview_wtf8_obj = POP_REF();
+
+                        memory_inst = module->memories[mem_idx];
+                        maddr = memory_inst->memory_data + addr;
+
+                        bytes_written = wasm_string_encode(
+                            (WASMString)wasm_stringview_wtf8_obj_get_value(
+                                stringview_wtf8_obj),
+                            pos, bytes, maddr, &next_pos, flag);
+
+                        if (bytes_written < 0) {
+                            if (bytes_written == Isolated_Surrogate) {
+                                wasm_set_exception(
+                                    module, "isolated surrogate is seen");
+                            }
+                            else {
+                                wasm_set_exception(module, "encode failed");
+                            }
+
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(next_pos);
+                        PUSH_I32(bytes_written);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_SLICE:
+                    {
+                        uint32 start, end;
+
+                        end = POP_I32();
+                        start = POP_I32();
+                        stringview_wtf8_obj = POP_REF();
+
+                        str_obj = wasm_string_slice(
+                            (WASMString)wasm_stringview_wtf8_obj_get_value(
+                                stringview_wtf8_obj),
+                            start, end, STRING_VIEW_WTF8);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_AS_WTF16:
+                    {
+                        stringref_obj = POP_REF();
+
+                        str_obj = wasm_string_create_view(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            STRING_VIEW_WTF16);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringview_wtf16_obj =
+                            wasm_stringview_wtf16_obj_new(exec_env, str_obj);
+                        if (!stringview_wtf16_obj) {
+                            wasm_set_exception(
+                                module, "create stringview wtf16 failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringview_wtf16_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_LENGTH:
+                    {
+                        int32 code_units_length;
+
+                        stringview_wtf16_obj = POP_REF();
+
+                        code_units_length = wasm_string_wtf16_get_length(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj));
+
+                        PUSH_I32(code_units_length);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_GET_CODEUNIT:
+                    {
+                        int32 pos;
+                        uint32 code_unit;
+
+                        pos = POP_I32();
+                        stringview_wtf16_obj = POP_REF();
+
+                        code_unit = (uint32)wasm_string_get_wtf16_codeunit(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj),
+                            pos);
+
+                        PUSH_I32(code_unit);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_ENCODE:
+                    {
+                        uint32 mem_idx, addr, pos, len, offset = 0;
+                        int32 written_code_units = 0;
+
+                        read_leb_uint32(frame_ip, frame_ip_end, mem_idx);
+                        len = POP_I32();
+                        pos = POP_I32();
+                        addr = POP_I32();
+                        stringview_wtf16_obj = POP_REF();
+
+                        CHECK_MEMORY_OVERFLOW(len * sizeof(uint16));
+
+                        /* check 2-byte alignment */
+                        if (((uintptr_t)maddr & (((uintptr_t)1 << 2) - 1))
+                            != 0) {
+                            wasm_set_exception(module,
+                                               "unaligned memory access");
+                            goto got_exception;
+                        }
+
+                        written_code_units = wasm_string_encode(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj),
+                            pos, len, maddr, NULL, WTF16);
+                        if (written_code_units < 0) {
+                            wasm_set_exception(module, "encode failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(written_code_units);
+                        (void)mem_idx;
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_SLICE:
+                    {
+                        uint32 start, end;
+
+                        end = POP_I32();
+                        start = POP_I32();
+                        stringview_wtf16_obj = POP_REF();
+
+                        str_obj = wasm_string_slice(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj),
+                            start, end, STRING_VIEW_WTF16);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_AS_ITER:
+                    {
+                        stringref_obj = POP_REF();
+
+                        str_obj = wasm_string_create_view(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            STRING_VIEW_ITER);
+
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringview_iter_obj =
+                            wasm_stringview_iter_obj_new(exec_env, str_obj, 0);
+                        if (!stringview_iter_obj) {
+                            wasm_set_exception(module,
+                                               "create stringview iter failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringview_iter_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_NEXT:
+                    {
+                        uint32 code_point;
+
+                        stringview_iter_obj = POP_REF();
+
+                        code_point = wasm_string_next_codepoint(
+                            (WASMString)wasm_stringview_iter_obj_get_value(
+                                stringview_iter_obj),
+                            wasm_stringview_iter_obj_get_pos(
+                                stringview_iter_obj));
+
+                        PUSH_I32(code_point);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_ADVANCE:
+                    case WASM_OP_STRINGVIEW_ITER_REWIND:
+                    {
+                        uint32 code_points_count, code_points_consumed = 0,
+                                                  cur_pos, next_pos = 0;
+
+                        code_points_count = POP_I32();
+                        stringview_iter_obj = POP_REF();
+
+                        str_obj =
+                            (WASMString)wasm_stringview_iter_obj_get_value(
+                                stringview_iter_obj);
+                        cur_pos = wasm_stringview_iter_obj_get_pos(
+                            stringview_iter_obj);
+
+                        if (opcode == WASM_OP_STRINGVIEW_ITER_ADVANCE) {
+                            next_pos = wasm_string_advance(
+                                str_obj, cur_pos, code_points_count,
+                                &code_points_consumed);
+                        }
+                        else if (opcode == WASM_OP_STRINGVIEW_ITER_REWIND) {
+                            next_pos = wasm_string_rewind(
+                                str_obj, cur_pos, code_points_count,
+                                &code_points_consumed);
+                        }
+
+                        wasm_stringview_iter_obj_update_pos(stringview_iter_obj,
+                                                            next_pos);
+
+                        PUSH_I32(code_points_consumed);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_SLICE:
+                    {
+                        uint32 code_points_count, cur_pos;
+
+                        code_points_count = POP_I32();
+                        stringview_iter_obj = POP_REF();
+
+                        cur_pos = wasm_stringview_iter_obj_get_pos(
+                            stringview_iter_obj);
+
+                        str_obj = wasm_string_slice(
+                            (WASMString)wasm_stringview_iter_obj_get_value(
+                                stringview_iter_obj),
+                            cur_pos, code_points_count, STRING_VIEW_ITER);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_NEW_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF16_ARRAY:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF8_ARRAY:
+                    {
+                        uint32 start, end, array_len;
+                        EncodingFlag flag = WTF8;
+                        WASMArrayType *array_type;
+                        void *arr_start_addr;
+
+                        end = POP_I32();
+                        start = POP_I32();
+                        array_obj = POP_REF();
+
+                        array_type = (WASMArrayType *)wasm_obj_get_defined_type(
+                            (WASMObjectRef)array_obj);
+                        arr_start_addr =
+                            wasm_array_obj_elem_addr(array_obj, start);
+                        array_len = wasm_array_obj_length(array_obj);
+
+                        if (start > end || end > array_len) {
+                            wasm_set_exception(module,
+                                               "array index out of bounds");
+                            goto got_exception;
+                        }
+
+                        if (opcode == WASM_OP_STRING_NEW_WTF16_ARRAY) {
+                            if (array_type->elem_type != VALUE_TYPE_I16) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            flag = WTF16;
+                        }
+                        else {
+                            if (array_type->elem_type != VALUE_TYPE_I8) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            if (opcode == WASM_OP_STRING_NEW_UTF8_ARRAY) {
+                                flag = UTF8;
+                            }
+                            else if (opcode == WASM_OP_STRING_NEW_WTF8_ARRAY) {
+                                flag = WTF8;
+                            }
+                            else if (opcode
+                                     == WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY) {
+                                flag = LOSSY_UTF8;
+                            }
+                        }
+
+                        str_obj = wasm_string_new_with_encoding(
+                            arr_start_addr, (end - start), flag);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_ENCODE_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF16_ARRAY:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF8_ARRAY:
+                    {
+                        uint32 start, array_len;
+                        int32 bytes_written;
+                        EncodingFlag flag = WTF8;
+                        WASMArrayType *array_type;
+                        void *arr_start_addr;
+
+                        start = POP_I32();
+                        array_obj = POP_REF();
+                        stringref_obj = POP_REF();
+
+                        str_obj = (WASMString)wasm_stringref_obj_get_value(
+                            stringref_obj);
+
+                        array_type = (WASMArrayType *)wasm_obj_get_defined_type(
+                            (WASMObjectRef)array_obj);
+                        arr_start_addr =
+                            wasm_array_obj_elem_addr(array_obj, start);
+                        array_len = wasm_array_obj_length(array_obj);
+
+                        if (start > array_len) {
+                            wasm_set_exception(module,
+                                               "array index out of bounds");
+                            goto got_exception;
+                        }
+
+                        if (opcode == WASM_OP_STRING_ENCODE_WTF16_ARRAY) {
+                            if (array_type->elem_type != VALUE_TYPE_I16) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            flag = WTF16;
+                        }
+                        else {
+                            if (array_type->elem_type != VALUE_TYPE_I8) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            if (opcode == WASM_OP_STRING_ENCODE_UTF8_ARRAY) {
+                                flag = UTF8;
+                            }
+                            else if (opcode
+                                     == WASM_OP_STRING_ENCODE_WTF8_ARRAY) {
+                                flag = WTF8;
+                            }
+                            else if (
+                                opcode
+                                == WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY) {
+                                flag = LOSSY_UTF8;
+                            }
+                        }
+
+                        bytes_written =
+                            wasm_string_encode(str_obj, start, array_len,
+                                               arr_start_addr, NULL, flag);
+
+                        if (bytes_written < 0) {
+                            if (bytes_written == Isolated_Surrogate) {
+                                wasm_set_exception(
+                                    module, "isolated surrogate is seen");
+                            }
+                            else if (bytes_written == Insufficient_Space) {
+                                wasm_set_exception(
+                                    module, "array space is insufficient");
+                            }
+                            else {
+                                wasm_set_exception(module, "encode failed");
+                            }
+
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(bytes_written);
+                        HANDLE_OP_END();
+                    }
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
                     default:
                     default:
                     {
                     {
                         wasm_set_exception(module, "unsupported opcode");
                         wasm_set_exception(module, "unsupported opcode");

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

@@ -13,6 +13,9 @@
 #if WASM_ENABLE_GC != 0
 #if WASM_ENABLE_GC != 0
 #include "../common/gc/gc_object.h"
 #include "../common/gc/gc_object.h"
 #include "mem_alloc.h"
 #include "mem_alloc.h"
+#if WASM_ENABLE_STRINGREF != 0
+#include "string_object.h"
+#endif
 #endif
 #endif
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #if WASM_ENABLE_SHARED_MEMORY != 0
 #include "../common/wasm_shared_memory.h"
 #include "../common/wasm_shared_memory.h"
@@ -1477,6 +1480,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
     WASMI31ObjectRef i31_obj;
     WASMI31ObjectRef i31_obj;
     WASMExternrefObjectRef externref_obj;
     WASMExternrefObjectRef externref_obj;
     uint32 type_idx;
     uint32 type_idx;
+#if WASM_ENABLE_STRINGREF != 0
+    WASMString str_obj;
+    WASMStringrefObjectRef stringref_obj;
+    WASMStringviewWTF8ObjectRef stringview_wtf8_obj;
+    WASMStringviewWTF16ObjectRef stringview_wtf16_obj;
+    WASMStringviewIterObjectRef stringview_iter_obj;
+#endif
 #endif
 #endif
 
 
 #if WASM_ENABLE_LABELS_AS_VALUES != 0
 #if WASM_ENABLE_LABELS_AS_VALUES != 0
@@ -2608,6 +2618,722 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
                         HANDLE_OP_END();
                         HANDLE_OP_END();
                     }
                     }
 
 
+#if WASM_ENABLE_STRINGREF != 0
+                    case WASM_OP_STRING_NEW_UTF8:
+                    case WASM_OP_STRING_NEW_WTF16:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8:
+                    case WASM_OP_STRING_NEW_WTF8:
+                    {
+                        uint32 mem_idx, addr, bytes_length, offset = 0;
+                        EncodingFlag flag = WTF8;
+
+                        mem_idx = (uint32)read_uint32(frame_ip);
+                        bytes_length = POP_I32();
+                        addr = POP_I32();
+
+                        CHECK_MEMORY_OVERFLOW(bytes_length);
+
+                        if (opcode == WASM_OP_STRING_NEW_WTF16) {
+                            flag = WTF16;
+                        }
+                        else if (opcode == WASM_OP_STRING_NEW_UTF8) {
+                            flag = UTF8;
+                        }
+                        else if (opcode == WASM_OP_STRING_NEW_LOSSY_UTF8) {
+                            flag = LOSSY_UTF8;
+                        }
+                        else if (opcode == WASM_OP_STRING_NEW_WTF8) {
+                            flag = WTF8;
+                        }
+
+                        str_obj = wasm_string_new_with_encoding(
+                            maddr, bytes_length, flag);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+
+                        (void)mem_idx;
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_CONST:
+                    {
+                        WASMModule *wasm_module = module->module;
+                        uint32 contents;
+
+                        contents = (uint32)read_uint32(frame_ip);
+
+                        str_obj = wasm_string_new_const(
+                            wasm_module->string_consts[contents]);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_MEASURE_UTF8:
+                    case WASM_OP_STRING_MEASURE_WTF8:
+                    case WASM_OP_STRING_MEASURE_WTF16:
+                    {
+                        int32 target_bytes_length;
+                        EncodingFlag flag = WTF8;
+
+                        stringref_obj = POP_REF();
+
+                        if (opcode == WASM_OP_STRING_MEASURE_WTF16) {
+                            flag = WTF16;
+                        }
+                        else if (opcode == WASM_OP_STRING_MEASURE_UTF8) {
+                            flag = UTF8;
+                        }
+                        else if (opcode == WASM_OP_STRING_MEASURE_WTF8) {
+                            flag = LOSSY_UTF8;
+                        }
+                        target_bytes_length = wasm_string_measure(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            flag);
+
+                        PUSH_I32(target_bytes_length);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_ENCODE_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF16:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF8:
+                    {
+                        uint32 mem_idx, addr;
+                        int32 target_bytes_length;
+                        WASMMemoryInstance *memory_inst;
+                        EncodingFlag flag = WTF8;
+
+                        mem_idx = (uint32)read_uint32(frame_ip);
+                        addr = POP_I32();
+                        stringref_obj = POP_REF();
+
+                        str_obj = (WASMString)wasm_stringref_obj_get_value(
+                            stringref_obj);
+
+                        memory_inst = module->memories[mem_idx];
+                        maddr = memory_inst->memory_data + addr;
+
+                        if (opcode == WASM_OP_STRING_ENCODE_WTF16) {
+                            flag = WTF16;
+                            count = wasm_string_measure(str_obj, flag);
+                            target_bytes_length = wasm_string_encode(
+                                str_obj, 0, count, maddr, NULL, flag);
+                        }
+                        else {
+                            if (opcode == WASM_OP_STRING_ENCODE_UTF8) {
+                                flag = UTF8;
+                            }
+                            else if (opcode
+                                     == WASM_OP_STRING_ENCODE_LOSSY_UTF8) {
+                                flag = LOSSY_UTF8;
+                            }
+                            else if (opcode == WASM_OP_STRING_ENCODE_WTF8) {
+                                flag = WTF8;
+                            }
+                            count = wasm_string_measure(str_obj, flag);
+                            target_bytes_length = wasm_string_encode(
+                                str_obj, 0, count, maddr, NULL, flag);
+
+                            if (target_bytes_length == -1) {
+                                wasm_set_exception(
+                                    module, "isolated surrogate is seen");
+                                goto got_exception;
+                            }
+                        }
+                        if (target_bytes_length < 0) {
+                            wasm_set_exception(module,
+                                               "stringref encode failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(target_bytes_length);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_CONCAT:
+                    {
+                        WASMStringrefObjectRef stringref_obj1, stringref_obj2;
+
+                        stringref_obj2 = POP_REF();
+                        stringref_obj1 = POP_REF();
+
+                        str_obj = wasm_string_concat(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj1),
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj2));
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_EQ:
+                    {
+                        WASMStringrefObjectRef stringref_obj1, stringref_obj2;
+                        int32 is_eq;
+
+                        stringref_obj2 = POP_REF();
+                        stringref_obj1 = POP_REF();
+
+                        is_eq = wasm_string_eq(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj1),
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj2));
+
+                        PUSH_I32(is_eq);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_IS_USV_SEQUENCE:
+                    {
+                        int32 is_usv_sequence;
+
+                        stringref_obj = POP_REF();
+
+                        is_usv_sequence = wasm_string_is_usv_sequence(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj));
+
+                        PUSH_I32(is_usv_sequence);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_AS_WTF8:
+                    {
+                        stringref_obj = POP_REF();
+
+                        str_obj = wasm_string_create_view(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            STRING_VIEW_WTF8);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringview_wtf8_obj =
+                            wasm_stringview_wtf8_obj_new(exec_env, str_obj);
+                        if (!stringview_wtf8_obj) {
+                            wasm_set_exception(module,
+                                               "create stringview wtf8 failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringview_wtf8_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_ADVANCE:
+                    {
+                        uint32 next_pos, bytes, pos;
+
+                        bytes = POP_I32();
+                        pos = POP_I32();
+                        stringview_wtf8_obj = POP_REF();
+
+                        next_pos = wasm_string_advance(
+                            (WASMString)wasm_stringview_wtf8_obj_get_value(
+                                stringview_wtf8_obj),
+                            pos, bytes, NULL);
+
+                        PUSH_I32(next_pos);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8:
+                    {
+                        uint32 mem_idx, addr, pos, bytes, next_pos;
+                        int32 bytes_written;
+                        WASMMemoryInstance *memory_inst;
+                        EncodingFlag flag = WTF8;
+
+                        if (opcode == WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8) {
+                            flag = UTF8;
+                        }
+                        else if (opcode
+                                 == WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8) {
+                            flag = LOSSY_UTF8;
+                        }
+                        else if (opcode
+                                 == WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8) {
+                            flag = WTF8;
+                        }
+
+                        mem_idx = (uint32)read_uint32(frame_ip);
+                        bytes = POP_I32();
+                        pos = POP_I32();
+                        addr = POP_I32();
+                        stringview_wtf8_obj = POP_REF();
+
+                        memory_inst = module->memories[mem_idx];
+                        maddr = memory_inst->memory_data + addr;
+
+                        bytes_written = wasm_string_encode(
+                            (WASMString)wasm_stringview_wtf8_obj_get_value(
+                                stringview_wtf8_obj),
+                            pos, bytes, maddr, &next_pos, flag);
+
+                        if (bytes_written < 0) {
+                            if (bytes_written == Isolated_Surrogate) {
+                                wasm_set_exception(
+                                    module, "isolated surrogate is seen");
+                            }
+                            else {
+                                wasm_set_exception(module, "encode failed");
+                            }
+
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(next_pos);
+                        PUSH_I32(bytes_written);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_SLICE:
+                    {
+                        uint32 start, end;
+
+                        end = POP_I32();
+                        start = POP_I32();
+                        stringview_wtf8_obj = POP_REF();
+
+                        str_obj = wasm_string_slice(
+                            (WASMString)wasm_stringview_wtf8_obj_get_value(
+                                stringview_wtf8_obj),
+                            start, end, STRING_VIEW_WTF8);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_AS_WTF16:
+                    {
+                        stringref_obj = POP_REF();
+
+                        str_obj = wasm_string_create_view(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            STRING_VIEW_WTF16);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringview_wtf16_obj =
+                            wasm_stringview_wtf16_obj_new(exec_env, str_obj);
+                        if (!stringview_wtf16_obj) {
+                            wasm_set_exception(
+                                module, "create stringview wtf16 failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringview_wtf16_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_LENGTH:
+                    {
+                        int32 code_units_length;
+
+                        stringview_wtf16_obj = POP_REF();
+
+                        code_units_length = wasm_string_wtf16_get_length(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj));
+
+                        PUSH_I32(code_units_length);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_GET_CODEUNIT:
+                    {
+                        int32 pos;
+                        uint32 code_unit;
+
+                        pos = POP_I32();
+                        stringview_wtf16_obj = POP_REF();
+
+                        code_unit = (uint32)wasm_string_get_wtf16_codeunit(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj),
+                            pos);
+
+                        PUSH_I32(code_unit);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_ENCODE:
+                    {
+                        uint32 mem_idx, addr, pos, len, offset = 0;
+                        int32 written_code_units = 0;
+
+                        mem_idx = (uint32)read_uint32(frame_ip);
+                        len = POP_I32();
+                        pos = POP_I32();
+                        addr = POP_I32();
+                        stringview_wtf16_obj = POP_REF();
+
+                        CHECK_MEMORY_OVERFLOW(len * sizeof(uint16));
+
+                        /* check 2-byte alignment */
+                        if (((uintptr_t)maddr & (((uintptr_t)1 << 2) - 1))
+                            != 0) {
+                            wasm_set_exception(module,
+                                               "unaligned memory access");
+                            goto got_exception;
+                        }
+
+                        written_code_units = wasm_string_encode(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj),
+                            pos, len, maddr, NULL, WTF16);
+
+                        PUSH_I32(written_code_units);
+                        (void)mem_idx;
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_SLICE:
+                    {
+                        uint32 start, end;
+
+                        end = POP_I32();
+                        start = POP_I32();
+                        stringview_wtf16_obj = POP_REF();
+
+                        str_obj = wasm_string_slice(
+                            (WASMString)wasm_stringview_wtf16_obj_get_value(
+                                stringview_wtf16_obj),
+                            start, end, STRING_VIEW_WTF16);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_AS_ITER:
+                    {
+                        stringref_obj = POP_REF();
+
+                        str_obj = wasm_string_create_view(
+                            (WASMString)wasm_stringref_obj_get_value(
+                                stringref_obj),
+                            STRING_VIEW_ITER);
+
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringview_iter_obj =
+                            wasm_stringview_iter_obj_new(exec_env, str_obj, 0);
+                        if (!stringview_iter_obj) {
+                            wasm_set_exception(module,
+                                               "create stringview iter failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringview_iter_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_NEXT:
+                    {
+                        uint32 code_point;
+
+                        stringview_iter_obj = POP_REF();
+
+                        code_point = wasm_string_next_codepoint(
+                            (WASMString)wasm_stringview_iter_obj_get_value(
+                                stringview_iter_obj),
+                            wasm_stringview_iter_obj_get_pos(
+                                stringview_iter_obj));
+
+                        PUSH_I32(code_point);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_ADVANCE:
+                    case WASM_OP_STRINGVIEW_ITER_REWIND:
+                    {
+                        uint32 code_points_count, code_points_consumed = 0,
+                                                  cur_pos, next_pos = 0;
+
+                        code_points_count = POP_I32();
+                        stringview_iter_obj = POP_REF();
+
+                        str_obj =
+                            (WASMString)wasm_stringview_iter_obj_get_value(
+                                stringview_iter_obj);
+                        cur_pos = wasm_stringview_iter_obj_get_pos(
+                            stringview_iter_obj);
+
+                        if (opcode == WASM_OP_STRINGVIEW_ITER_ADVANCE) {
+                            next_pos = wasm_string_advance(
+                                str_obj, cur_pos, code_points_count,
+                                &code_points_consumed);
+                        }
+                        else if (opcode == WASM_OP_STRINGVIEW_ITER_REWIND) {
+                            next_pos = wasm_string_rewind(
+                                str_obj, cur_pos, code_points_count,
+                                &code_points_consumed);
+                        }
+
+                        wasm_stringview_iter_obj_update_pos(stringview_iter_obj,
+                                                            next_pos);
+
+                        PUSH_I32(code_points_consumed);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_SLICE:
+                    {
+                        uint32 code_points_count, cur_pos;
+
+                        code_points_count = POP_I32();
+                        stringview_iter_obj = POP_REF();
+
+                        cur_pos = wasm_stringview_iter_obj_get_pos(
+                            stringview_iter_obj);
+
+                        str_obj = wasm_string_slice(
+                            (WASMString)wasm_stringview_iter_obj_get_value(
+                                stringview_iter_obj),
+                            cur_pos, code_points_count, STRING_VIEW_ITER);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_NEW_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF16_ARRAY:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF8_ARRAY:
+                    {
+                        uint32 start, end, array_len;
+                        EncodingFlag flag = WTF8;
+                        WASMArrayType *array_type;
+                        void *arr_start_addr;
+
+                        end = POP_I32();
+                        start = POP_I32();
+                        array_obj = POP_REF();
+
+                        array_type = (WASMArrayType *)wasm_obj_get_defined_type(
+                            (WASMObjectRef)array_obj);
+                        arr_start_addr =
+                            wasm_array_obj_elem_addr(array_obj, start);
+                        array_len = wasm_array_obj_length(array_obj);
+
+                        if (start > end || end > array_len) {
+                            wasm_set_exception(module,
+                                               "array index out of bounds");
+                            goto got_exception;
+                        }
+
+                        if (opcode == WASM_OP_STRING_NEW_WTF16_ARRAY) {
+                            if (array_type->elem_type != VALUE_TYPE_I16) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            flag = WTF16;
+                        }
+                        else {
+                            if (array_type->elem_type != VALUE_TYPE_I8) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            if (opcode == WASM_OP_STRING_NEW_UTF8_ARRAY) {
+                                flag = UTF8;
+                            }
+                            else if (opcode == WASM_OP_STRING_NEW_WTF8_ARRAY) {
+                                flag = WTF8;
+                            }
+                            else if (opcode
+                                     == WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY) {
+                                flag = LOSSY_UTF8;
+                            }
+                        }
+
+                        str_obj = wasm_string_new_with_encoding(
+                            arr_start_addr, (end - start), flag);
+                        if (!str_obj) {
+                            wasm_set_exception(module,
+                                               "create string object failed");
+                            goto got_exception;
+                        }
+
+                        SYNC_ALL_TO_FRAME();
+                        stringref_obj =
+                            wasm_stringref_obj_new(exec_env, str_obj);
+                        if (!stringref_obj) {
+                            wasm_set_exception(module,
+                                               "create stringref failed");
+                            goto got_exception;
+                        }
+
+                        PUSH_REF(stringref_obj);
+                        HANDLE_OP_END();
+                    }
+                    case WASM_OP_STRING_ENCODE_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF16_ARRAY:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF8_ARRAY:
+                    {
+                        uint32 start, array_len;
+                        int32 bytes_written;
+                        EncodingFlag flag = WTF8;
+                        WASMArrayType *array_type;
+                        void *arr_start_addr;
+
+                        start = POP_I32();
+                        array_obj = POP_REF();
+                        stringref_obj = POP_REF();
+
+                        str_obj = (WASMString)wasm_stringref_obj_get_value(
+                            stringref_obj);
+
+                        array_type = (WASMArrayType *)wasm_obj_get_defined_type(
+                            (WASMObjectRef)array_obj);
+                        arr_start_addr =
+                            wasm_array_obj_elem_addr(array_obj, start);
+                        array_len = wasm_array_obj_length(array_obj);
+
+                        if (start > array_len) {
+                            wasm_set_exception(module,
+                                               "array index out of bounds");
+                            goto got_exception;
+                        }
+
+                        if (opcode == WASM_OP_STRING_ENCODE_WTF16_ARRAY) {
+                            if (array_type->elem_type != VALUE_TYPE_I16) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            flag = WTF16;
+                        }
+                        else {
+                            if (array_type->elem_type != VALUE_TYPE_I8) {
+                                wasm_set_exception(module,
+                                                   "array type mismatch");
+                                goto got_exception;
+                            }
+                            if (opcode == WASM_OP_STRING_ENCODE_UTF8_ARRAY) {
+                                flag = UTF8;
+                            }
+                            else if (opcode
+                                     == WASM_OP_STRING_ENCODE_WTF8_ARRAY) {
+                                flag = WTF8;
+                            }
+                            else if (
+                                opcode
+                                == WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY) {
+                                flag = LOSSY_UTF8;
+                            }
+                        }
+
+                        bytes_written = wasm_string_encode(
+                            str_obj, 0, array_len, arr_start_addr, NULL, flag);
+                        if (bytes_written < 0) {
+                            if (bytes_written == Isolated_Surrogate) {
+                                wasm_set_exception(
+                                    module, "isolated surrogate is seen");
+                            }
+                            else if (bytes_written == Insufficient_Space) {
+                                wasm_set_exception(
+                                    module, "array space is insufficient");
+                            }
+                            else {
+                                wasm_set_exception(module, "encode failed");
+                            }
+
+                            goto got_exception;
+                        }
+
+                        PUSH_I32(bytes_written);
+                        HANDLE_OP_END();
+                    }
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
+
                     default:
                     default:
                     {
                     {
                         wasm_set_exception(module, "unsupported opcode");
                         wasm_set_exception(module, "unsupported opcode");

+ 372 - 6
core/iwasm/interpreter/wasm_loader.c

@@ -925,6 +925,14 @@ resolve_value_type(const uint8 **p_buf, const uint8 *buf_end,
                                    error_buf, error_buf_size))
                                    error_buf, error_buf_size))
             return false;
             return false;
         *p_need_ref_type_map = true;
         *p_need_ref_type_map = true;
+#if WASM_ENABLE_STRINGREF != 0
+        /* covert (ref string) to stringref */
+        if (wasm_is_refheaptype_stringrefs(&ref_type->ref_ht_common)) {
+            ref_type->ref_type =
+                (uint8)((int32)0x80 + ref_type->ref_ht_common.heap_type);
+            *p_need_ref_type_map = false;
+        }
+#endif
     }
     }
     else {
     else {
         /* type which can be represented by one byte */
         /* type which can be represented by one byte */
@@ -3702,6 +3710,60 @@ fail:
     return false;
     return false;
 }
 }
 
 
+#if WASM_ENABLE_GC != 0
+#if WASM_ENABLE_STRINGREF != 0
+static bool
+load_stringref_section(const uint8 *buf, const uint8 *buf_end,
+                       WASMModule *module, bool is_load_from_file_buf,
+                       char *error_buf, uint32 error_buf_size)
+{
+    const uint8 *p = buf, *p_end = buf_end;
+    int32 deferred_count, immediate_count, string_length, i;
+    uint64 total_size;
+
+    read_leb_uint32(p, p_end, deferred_count);
+    read_leb_uint32(p, p_end, immediate_count);
+
+    /* proposal set deferred_count for future extension */
+    if (deferred_count != 0) {
+        goto fail;
+    }
+
+    if (immediate_count > 0) {
+        total_size = sizeof(char *) * (uint64)immediate_count;
+        if (!(module->string_consts =
+                  loader_malloc(total_size, error_buf, error_buf_size))) {
+            goto fail;
+        }
+        module->stringref_count = immediate_count;
+
+        for (i = 0; i < immediate_count; i++) {
+            read_leb_uint32(p, p_end, string_length);
+
+            CHECK_BUF(p, p_end, string_length);
+            if (!(module->string_consts[i] = const_str_list_insert(
+                      p, string_length, module, is_load_from_file_buf,
+                      error_buf, error_buf_size))) {
+                goto fail;
+            }
+            p += string_length;
+        }
+    }
+
+    if (p != p_end) {
+        set_error_buf(error_buf, error_buf_size, "section size mismatch");
+        goto fail;
+    }
+
+    LOG_VERBOSE("Load stringref section success.\n");
+    return true;
+
+fail:
+    return false;
+}
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
+#endif /* end of WASM_ENABLE_GC != 0 */
+
 #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
 #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
 static bool
 static bool
 handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
 handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
@@ -4469,6 +4531,16 @@ load_from_sections(WASMModule *module, WASMSection *sections,
                                             error_buf_size))
                                             error_buf_size))
                     return false;
                     return false;
                 break;
                 break;
+#endif
+#if WASM_ENABLE_GC != 0
+#if WASM_ENABLE_STRINGREF != 0
+            case SECTION_TYPE_STRINGREF:
+                if (!load_stringref_section(buf, buf_end, module,
+                                            is_load_from_file_buf, error_buf,
+                                            error_buf_size))
+                    return false;
+                break;
+#endif
 #endif
 #endif
             default:
             default:
                 set_error_buf(error_buf, error_buf_size, "invalid section id");
                 set_error_buf(error_buf, error_buf_size, "invalid section id");
@@ -4927,6 +4999,11 @@ static uint8 section_ids[] = {
     SECTION_TYPE_FUNC,
     SECTION_TYPE_FUNC,
     SECTION_TYPE_TABLE,
     SECTION_TYPE_TABLE,
     SECTION_TYPE_MEMORY,
     SECTION_TYPE_MEMORY,
+#if WASM_ENABLE_GC != 0
+#if WASM_ENABLE_STRINGREF != 0
+    SECTION_TYPE_STRINGREF,
+#endif
+#endif
     SECTION_TYPE_GLOBAL,
     SECTION_TYPE_GLOBAL,
     SECTION_TYPE_EXPORT,
     SECTION_TYPE_EXPORT,
     SECTION_TYPE_START,
     SECTION_TYPE_START,
@@ -5374,6 +5451,14 @@ wasm_loader_unload(WASMModule *module)
         }
         }
     }
     }
 
 
+#if WASM_ENABLE_GC != 0
+#if WASM_ENABLE_STRINGREF != 0
+    if (module->string_consts) {
+        wasm_runtime_free(module->string_consts);
+    }
+#endif
+#endif
+
 #if WASM_ENABLE_FAST_INTERP == 0
 #if WASM_ENABLE_FAST_INTERP == 0
     if (module->br_table_cache_list) {
     if (module->br_table_cache_list) {
         BrTableCache *node = bh_list_first_elem(module->br_table_cache_list);
         BrTableCache *node = bh_list_first_elem(module->br_table_cache_list);
@@ -5451,6 +5536,12 @@ wasm_loader_unload(WASMModule *module)
         }
         }
         wasm_runtime_free(module->rtt_types);
         wasm_runtime_free(module->rtt_types);
     }
     }
+#if WASM_ENABLE_STRINGREF != 0
+    for (i = 0; i < WASM_TYPE_STRINGVIEWITER - WASM_TYPE_STRINGREF + 1; i++) {
+        if (module->stringref_rtts[i])
+            wasm_runtime_free(module->stringref_rtts[i]);
+    }
+#endif
 #endif
 #endif
 
 
     wasm_runtime_free(module);
     wasm_runtime_free(module);
@@ -5954,6 +6045,61 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
                     case WASM_OP_EXTERN_EXTERNALIZE:
                     case WASM_OP_EXTERN_EXTERNALIZE:
                         break;
                         break;
 
 
+#if WASM_ENABLE_STRINGREF != 0
+                    case WASM_OP_STRING_NEW_UTF8:
+                    case WASM_OP_STRING_NEW_WTF16:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8:
+                    case WASM_OP_STRING_NEW_WTF8:
+                        skip_leb_uint32(p, p_end); /* memory index 0x00 */
+                        break;
+                    case WASM_OP_STRING_CONST:
+                        skip_leb_int32(p, p_end); /* contents */
+                        break;
+                    case WASM_OP_STRING_MEASURE_UTF8:
+                    case WASM_OP_STRING_MEASURE_WTF8:
+                    case WASM_OP_STRING_MEASURE_WTF16:
+                        break;
+                    case WASM_OP_STRING_ENCODE_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF16:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF8:
+                        skip_leb_uint32(p, p_end); /* memory index 0x00 */
+                        break;
+                    case WASM_OP_STRING_CONCAT:
+                    case WASM_OP_STRING_EQ:
+                    case WASM_OP_STRING_IS_USV_SEQUENCE:
+                    case WASM_OP_STRING_AS_WTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ADVANCE:
+                        break;
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8:
+                        skip_leb_uint32(p, p_end); /* memory index 0x00 */
+                        break;
+                    case WASM_OP_STRINGVIEW_WTF8_SLICE:
+                    case WASM_OP_STRING_AS_WTF16:
+                    case WASM_OP_STRINGVIEW_WTF16_LENGTH:
+                    case WASM_OP_STRINGVIEW_WTF16_GET_CODEUNIT:
+                        break;
+                    case WASM_OP_STRINGVIEW_WTF16_ENCODE:
+                        skip_leb_uint32(p, p_end); /* memory index 0x00 */
+                        break;
+                    case WASM_OP_STRINGVIEW_WTF16_SLICE:
+                    case WASM_OP_STRING_AS_ITER:
+                    case WASM_OP_STRINGVIEW_ITER_NEXT:
+                    case WASM_OP_STRINGVIEW_ITER_ADVANCE:
+                    case WASM_OP_STRINGVIEW_ITER_REWIND:
+                    case WASM_OP_STRINGVIEW_ITER_SLICE:
+                    case WASM_OP_STRING_NEW_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF16_ARRAY:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF16_ARRAY:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF8_ARRAY:
+                        break;
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
                     default:
                     default:
                         return false;
                         return false;
                 }
                 }
@@ -8042,6 +8188,7 @@ fail:
 #define POP_V128() TEMPLATE_POP(V128)
 #define POP_V128() TEMPLATE_POP(V128)
 #define POP_FUNCREF() TEMPLATE_POP(FUNCREF)
 #define POP_FUNCREF() TEMPLATE_POP(FUNCREF)
 #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF)
 #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF)
+#define POP_STRINGREF() TEMPLATE_POP(STRINGREF)
 
 
 #if WASM_ENABLE_FAST_INTERP != 0
 #if WASM_ENABLE_FAST_INTERP != 0
 
 
@@ -8277,7 +8424,7 @@ fail:
                         wasm_reftype_struct_size(_ref_type));                \
                         wasm_reftype_struct_size(_ref_type));                \
         }                                                                    \
         }                                                                    \
     } while (0)
     } while (0)
-#endif
+#endif /* end of WASM_ENABLE_GC == 0 */
 
 
 #define GET_LOCAL_INDEX_TYPE_AND_OFFSET()                              \
 #define GET_LOCAL_INDEX_TYPE_AND_OFFSET()                              \
     do {                                                               \
     do {                                                               \
@@ -11756,7 +11903,12 @@ re_scan:
                         }
                         }
                         else {
                         else {
                             if (heap_type > HEAP_TYPE_FUNC
                             if (heap_type > HEAP_TYPE_FUNC
-                                || heap_type < HEAP_TYPE_NONE) {
+#if WASM_ENABLE_STRINGREF != 0
+                                || heap_type < HEAP_TYPE_STRINGVIEWITER
+#else
+                                || heap_type < HEAP_TYPE_NONE
+#endif
+                            ) {
                                 set_error_buf(error_buf, error_buf_size,
                                 set_error_buf(error_buf, error_buf_size,
                                               "unknown type");
                                               "unknown type");
                                 goto fail;
                                 goto fail;
@@ -11774,10 +11926,15 @@ re_scan:
                             bool nullable =
                             bool nullable =
                                 (opcode1 == WASM_OP_REF_CAST_NULLABLE) ? true
                                 (opcode1 == WASM_OP_REF_CAST_NULLABLE) ? true
                                                                        : false;
                                                                        : false;
-                            wasm_set_refheaptype_typeidx(
-                                &wasm_ref_type.ref_ht_typeidx, nullable,
-                                heap_type);
-                            PUSH_REF(wasm_ref_type.ref_type);
+                            if (heap_type >= 0 || !nullable) {
+                                wasm_set_refheaptype_typeidx(
+                                    &wasm_ref_type.ref_ht_typeidx, nullable,
+                                    heap_type);
+                                PUSH_REF(wasm_ref_type.ref_type);
+                            }
+                            else {
+                                PUSH_REF((uint8)((int32)0x80 + heap_type));
+                            }
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -11998,6 +12155,215 @@ re_scan:
                         break;
                         break;
                     }
                     }
 
 
+#if WASM_ENABLE_STRINGREF != 0
+                    case WASM_OP_STRING_NEW_UTF8:
+                    case WASM_OP_STRING_NEW_WTF16:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8:
+                    case WASM_OP_STRING_NEW_WTF8:
+                    {
+                        uint32 memidx;
+
+                        read_leb_uint32(p, p_end, memidx);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, (uint32)memidx);
+#endif
+                        POP_I32();
+                        POP_I32();
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        (void)memidx;
+                        break;
+                    }
+                    case WASM_OP_STRING_CONST:
+                    {
+                        uint32 contents;
+
+                        read_leb_uint32(p, p_end, contents);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, (uint32)contents);
+#endif
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        (void)contents;
+                        break;
+                    }
+                    case WASM_OP_STRING_MEASURE_UTF8:
+                    case WASM_OP_STRING_MEASURE_WTF8:
+                    case WASM_OP_STRING_MEASURE_WTF16:
+                    {
+                        POP_STRINGREF();
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRING_ENCODE_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF16:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRING_ENCODE_WTF8:
+                    {
+                        uint32 memidx;
+
+                        read_leb_uint32(p, p_end, memidx);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, (uint32)memidx);
+#endif
+                        POP_I32();
+                        POP_STRINGREF();
+                        PUSH_I32();
+                        (void)memidx;
+                        break;
+                    }
+                    case WASM_OP_STRING_CONCAT:
+                    {
+                        POP_STRINGREF();
+                        POP_STRINGREF();
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        break;
+                    }
+                    case WASM_OP_STRING_EQ:
+                    {
+                        POP_STRINGREF();
+                        POP_STRINGREF();
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRING_IS_USV_SEQUENCE:
+                    {
+                        POP_STRINGREF();
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRING_AS_WTF8:
+                    {
+                        POP_STRINGREF();
+                        PUSH_REF(REF_TYPE_STRINGVIEWWTF8);
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_ADVANCE:
+                    {
+                        POP_I32();
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWWTF8);
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8:
+                    case WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8:
+                    {
+                        uint32 memidx;
+
+                        read_leb_uint32(p, p_end, memidx);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, (uint32)memidx);
+#endif
+                        POP_I32();
+                        POP_I32();
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWWTF8);
+                        PUSH_I32();
+                        PUSH_I32();
+                        (void)memidx;
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF8_SLICE:
+                    {
+                        POP_I32();
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWWTF8);
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        break;
+                    }
+                    case WASM_OP_STRING_AS_WTF16:
+                    {
+                        POP_STRINGREF();
+                        PUSH_REF(REF_TYPE_STRINGVIEWWTF16);
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_LENGTH:
+                    {
+                        POP_REF(REF_TYPE_STRINGVIEWWTF16);
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_GET_CODEUNIT:
+                    {
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWWTF16);
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_ENCODE:
+                    {
+                        uint32 memidx;
+
+                        read_leb_uint32(p, p_end, memidx);
+#if WASM_ENABLE_FAST_INTERP != 0
+                        emit_uint32(loader_ctx, (uint32)memidx);
+#endif
+                        POP_I32();
+                        POP_I32();
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWWTF16);
+                        PUSH_I32();
+                        (void)memidx;
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_WTF16_SLICE:
+                    {
+                        POP_I32();
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWWTF16);
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        break;
+                    }
+                    case WASM_OP_STRING_AS_ITER:
+                    {
+                        POP_STRINGREF();
+                        PUSH_REF(REF_TYPE_STRINGVIEWITER);
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_NEXT:
+                    {
+                        POP_REF(REF_TYPE_STRINGVIEWITER);
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_ADVANCE:
+                    case WASM_OP_STRINGVIEW_ITER_REWIND:
+                    {
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWITER);
+                        PUSH_I32();
+                        break;
+                    }
+                    case WASM_OP_STRINGVIEW_ITER_SLICE:
+                    {
+                        POP_I32();
+                        POP_REF(REF_TYPE_STRINGVIEWITER);
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        break;
+                    }
+                    case WASM_OP_STRING_NEW_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF16_ARRAY:
+                    case WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_NEW_WTF8_ARRAY:
+                    {
+                        POP_I32();
+                        POP_I32();
+                        POP_REF(REF_TYPE_ARRAYREF);
+                        PUSH_REF(REF_TYPE_STRINGREF);
+                        break;
+                    }
+                    case WASM_OP_STRING_ENCODE_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF16_ARRAY:
+                    case WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY:
+                    case WASM_OP_STRING_ENCODE_WTF8_ARRAY:
+                    {
+                        POP_I32();
+                        POP_REF(REF_TYPE_ARRAYREF);
+                        POP_STRINGREF();
+                        PUSH_I32();
+                        break;
+                    }
+#endif /* end of WASM_ENABLE_STRINGREF != 0 */
                     default:
                     default:
                         set_error_buf_v(error_buf, error_buf_size,
                         set_error_buf_v(error_buf, error_buf_size,
                                         "%s %02x %02x", "unsupported opcode",
                                         "%s %02x %02x", "unsupported opcode",

+ 50 - 0
core/iwasm/interpreter/wasm_opcode.h

@@ -337,6 +337,56 @@ typedef enum WASMGCEXTOpcode {
 
 
     WASM_OP_EXTERN_INTERNALIZE = 0x70, /* extern.internalize */
     WASM_OP_EXTERN_INTERNALIZE = 0x70, /* extern.internalize */
     WASM_OP_EXTERN_EXTERNALIZE = 0x71, /* extern.externalize */
     WASM_OP_EXTERN_EXTERNALIZE = 0x71, /* extern.externalize */
+
+    WASM_OP_STRING_NEW_UTF8 = 0x80,          /* string.new_utf8 */
+    WASM_OP_STRING_NEW_WTF16 = 0x81,         /* string.new_wtf16 */
+    WASM_OP_STRING_CONST = 0x82,             /* string.const */
+    WASM_OP_STRING_MEASURE_UTF8 = 0x83,      /* string.measure_utf8 */
+    WASM_OP_STRING_MEASURE_WTF8 = 0x84,      /* string.measure_wtf8 */
+    WASM_OP_STRING_MEASURE_WTF16 = 0x85,     /* string.measure_wtf16 */
+    WASM_OP_STRING_ENCODE_UTF8 = 0x86,       /* string.encode_utf8 */
+    WASM_OP_STRING_ENCODE_WTF16 = 0x87,      /* string.encode_wtf16 */
+    WASM_OP_STRING_CONCAT = 0x88,            /* string.concat */
+    WASM_OP_STRING_EQ = 0x89,                /* string.eq */
+    WASM_OP_STRING_IS_USV_SEQUENCE = 0x8a,   /* string.is_usv_sequence */
+    WASM_OP_STRING_NEW_LOSSY_UTF8 = 0x8b,    /* string.new_lossy_utf8 */
+    WASM_OP_STRING_NEW_WTF8 = 0x8c,          /* string.new_wtf8 */
+    WASM_OP_STRING_ENCODE_LOSSY_UTF8 = 0x8d, /* string.encode_lossy_utf8 */
+    WASM_OP_STRING_ENCODE_WTF8 = 0x8e,       /* string.encode_wtf8 */
+
+    WASM_OP_STRING_AS_WTF8 = 0x90,          /* string.as_wtf8 */
+    WASM_OP_STRINGVIEW_WTF8_ADVANCE = 0x91, /* stringview_wtf8.advance */
+    WASM_OP_STRINGVIEW_WTF8_ENCODE_UTF8 =
+        0x92,                             /* stringview_wtf8.encode_utf8 */
+    WASM_OP_STRINGVIEW_WTF8_SLICE = 0x93, /* stringview_wtf8.slice */
+    WASM_OP_STRINGVIEW_WTF8_ENCODE_LOSSY_UTF8 =
+        0x94, /* stringview_wtf8.encode_lossy_utf8 */
+    WASM_OP_STRINGVIEW_WTF8_ENCODE_WTF8 =
+        0x95, /* stringview_wtf8.encode_wtf8 */
+
+    WASM_OP_STRING_AS_WTF16 = 0x98,         /* string.as_wtf16 */
+    WASM_OP_STRINGVIEW_WTF16_LENGTH = 0x99, /* stringview_wtf16.length */
+    WASM_OP_STRINGVIEW_WTF16_GET_CODEUNIT =
+        0x9a,                               /* stringview_wtf16.get_codeunit */
+    WASM_OP_STRINGVIEW_WTF16_ENCODE = 0x9b, /* stringview_wtf16.encode */
+    WASM_OP_STRINGVIEW_WTF16_SLICE = 0x9c,  /* stringview_wtf16.slice */
+
+    WASM_OP_STRING_AS_ITER = 0xa0,          /* string.as_iter */
+    WASM_OP_STRINGVIEW_ITER_NEXT = 0xa1,    /* stringview_iter.next */
+    WASM_OP_STRINGVIEW_ITER_ADVANCE = 0xa2, /* stringview_iter.advance */
+    WASM_OP_STRINGVIEW_ITER_REWIND = 0xa3,  /* stringview_iter.rewind */
+    WASM_OP_STRINGVIEW_ITER_SLICE = 0xa4,   /* stringview_iter.slice */
+
+    WASM_OP_STRING_NEW_UTF8_ARRAY = 0xb0,     /* string.new_utf8_array */
+    WASM_OP_STRING_NEW_WTF16_ARRAY = 0xb1,    /* string.new_wtf16_array */
+    WASM_OP_STRING_ENCODE_UTF8_ARRAY = 0xb2,  /* string.encode_utf8_array */
+    WASM_OP_STRING_ENCODE_WTF16_ARRAY = 0xb3, /* string.encode_wtf16_array */
+    WASM_OP_STRING_NEW_LOSSY_UTF8_ARRAY =
+        0xb4,                             /* string.new_lossy_utf8_array */
+    WASM_OP_STRING_NEW_WTF8_ARRAY = 0xb5, /* string.new_wtf8_array */
+    WASM_OP_STRING_ENCODE_LOSSY_UTF8_ARRAY =
+        0xb6, /* string.encode_lossy_utf8_array */
+    WASM_OP_STRING_ENCODE_WTF8_ARRAY = 0xb7, /* string.encode_wtf8_array */
 } WASMGCEXTOpcode;
 } WASMGCEXTOpcode;
 
 
 typedef enum WASMMiscEXTOpcode {
 typedef enum WASMMiscEXTOpcode {