From 2f45f12cd7da73dca74f6e43da34b5aa133b1f59 Mon Sep 17 00:00:00 2001 From: Su Yihan Date: Mon, 23 Oct 2023 12:45:37 +0800 Subject: [PATCH] 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 Co-authored-by: Xu Jun --- build-scripts/config_common.cmake | 8 + build-scripts/runtime_lib.cmake | 4 + core/config.h | 4 + core/iwasm/common/gc/gc_common.c | 28 +- core/iwasm/common/gc/gc_object.c | 290 +++++++ core/iwasm/common/gc/gc_object.h | 70 ++ core/iwasm/common/gc/gc_type.c | 65 +- core/iwasm/common/gc/gc_type.h | 27 +- core/iwasm/common/gc/iwasm_gc.cmake | 17 +- .../iwasm/common/gc/stringref/string_object.h | 113 +++ core/iwasm/common/wasm_application.c | 15 + core/iwasm/common/wasm_native.c | 4 + core/iwasm/common/wasm_runtime_common.c | 54 ++ core/iwasm/include/gc_export.h | 5 + core/iwasm/interpreter/wasm.h | 74 +- core/iwasm/interpreter/wasm_interp_classic.c | 731 ++++++++++++++++++ core/iwasm/interpreter/wasm_interp_fast.c | 726 +++++++++++++++++ core/iwasm/interpreter/wasm_loader.c | 378 ++++++++- core/iwasm/interpreter/wasm_opcode.h | 50 ++ 19 files changed, 2647 insertions(+), 16 deletions(-) create mode 100644 core/iwasm/common/gc/stringref/string_object.h diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index e0c1cfb93..4c8e0b3fa 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -335,6 +335,14 @@ if (WAMR_BUILD_GC_BINARYEN EQUAL 1) add_definitions (-DWASM_ENABLE_GC_BINARYEN=1) message (" GC binaryen compatible mode on") 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 WAMR_BUILD_DUMP_CALL_STACK EQUAL 1 OR WAMR_BUILD_GC EQUAL 1 OR WAMR_BUILD_GC_BINARYEN EQUAL 1) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index b7fc0e21c..a47995944 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -78,6 +78,10 @@ if (WAMR_BUILD_AOT EQUAL 1) include (${IWASM_DIR}/aot/iwasm_aot.cmake) endif () +if (WAMR_BUILD_STRINGREF EQUAL 1) + set (WAMR_BUILD_GC 1) +endif () + if (WAMR_BUILD_GC_BINARYEN EQUAL 1) set (WAMR_BUILD_GC 1) endif () diff --git a/core/config.h b/core/config.h index 5e5cd2068..020e27855 100644 --- a/core/config.h +++ b/core/config.h @@ -467,6 +467,10 @@ #define WASM_ENABLE_GC_BINARYEN 0 #endif +#ifndef WASM_ENABLE_STRINGREF +#define WASM_ENABLE_STRINGREF 0 +#endif + #ifndef GC_REFTYPE_MAP_SIZE_DEFAULT #define GC_REFTYPE_MAP_SIZE_DEFAULT 64 #endif diff --git a/core/iwasm/common/gc/gc_common.c b/core/iwasm/common/gc/gc_common.c index 9c3964584..71d5c90fc 100644 --- a/core/iwasm/common/gc/gc_common.c +++ b/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; 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))) { return false; } if (value_type == VALUE_TYPE_HT_NULLABLE_REF || value_type == VALUE_TYPE_HT_NON_NULLABLE_REF) { 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; } } @@ -35,9 +46,20 @@ wasm_ref_type_normalize(wasm_ref_type_t *ref_type) ref_type->nullable = false; } 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 = +#if WASM_ENABLE_STRINGREF != 0 + (uint8)(REF_TYPE_STRINGVIEWITER + heap_type + - HEAP_TYPE_STRINGVIEWITER); +#else (uint8)(REF_TYPE_NULLREF + heap_type - HEAP_TYPE_NONE); +#endif ref_type->nullable = false; ref_type->heap_type = 0; } diff --git a/core/iwasm/common/gc/gc_object.c b/core/iwasm/common/gc/gc_object.c index 655a28441..84521b587 100644 --- a/core/iwasm/common/gc/gc_object.c +++ b/core/iwasm/common/gc/gc_object.c @@ -12,6 +12,9 @@ #if WASM_ENABLE_AOT != 0 #include "../aot/aot_runtime.h" #endif +#if WASM_ENABLE_STRINGREF != 0 +#include "string_object.h" +#endif WASMRttTypeRef 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); case HEAP_TYPE_ARRAY: 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_NOFUNC: case HEAP_TYPE_NOEXTERN: @@ -698,6 +709,18 @@ wasm_object_get_ref_list(WASMObjectRef obj, bool *p_is_compact_mode, *p_ref_list = NULL; 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) { /* function object */ *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); 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 */ diff --git a/core/iwasm/common/gc/gc_object.h b/core/iwasm/common/gc/gc_object.h index 74ebc21f6..970fc6500 100644 --- a/core/iwasm/common/gc/gc_object.h +++ b/core/iwasm/common/gc/gc_object.h @@ -102,6 +102,28 @@ typedef struct WASMFuncObject { uint32 func_idx_bound; } 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; 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_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 } /* end of extern "C" */ #endif diff --git a/core/iwasm/common/gc/gc_type.c b/core/iwasm/common/gc/gc_type.c index 0101f01d9..37285d14d 100644 --- a/core/iwasm/common/gc/gc_type.c +++ b/core/iwasm/common/gc/gc_type.c @@ -616,7 +616,12 @@ wasm_reftype_size(uint8 type) return 4; else if (type == VALUE_TYPE_I64 || type == VALUE_TYPE_F64) 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) +#endif return sizeof(uintptr_t); else if (type == PACKED_TYPE_I8) return 1; @@ -745,13 +750,26 @@ wasm_is_reftype_supers_of_extern(uint8 type) 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 wasm_is_reftype_supers_of_none(uint8 type, const WASMRefType *ref_type, const WASMTypePtr *types, uint32 type_count) { if (type == REF_TYPE_NULLREF || type == REF_TYPE_I31REF || 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; 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) { 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) { if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) { /* 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 == WASM_TYPE_FUNC) 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 return false; } @@ -1019,6 +1068,20 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1, /* (ref func) <: [funcref] */ 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) { /* (ref none) */ /* TODO */ diff --git a/core/iwasm/common/gc/gc_type.h b/core/iwasm/common/gc/gc_type.h index c42c3a170..574fad0eb 100644 --- a/core/iwasm/common/gc/gc_type.h +++ b/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 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 : 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 && 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_I31)) + && ref_heap_type->heap_type <= (int32)HEAP_TYPE_I31) +#endif + ) ? true : 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; } +#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 */ bool wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1, diff --git a/core/iwasm/common/gc/iwasm_gc.cmake b/core/iwasm/common/gc/iwasm_gc.cmake index 8454eb42d..cf3f80428 100644 --- a/core/iwasm/common/gc/iwasm_gc.cmake +++ b/core/iwasm/common/gc/iwasm_gc.cmake @@ -11,7 +11,22 @@ endif () 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}) +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 () diff --git a/core/iwasm/common/gc/stringref/string_object.h b/core/iwasm/common/gc/stringref/string_object.h new file mode 100644 index 000000000..19b050fff --- /dev/null +++ b/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_ */ diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 52030f632..57be67528 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -15,6 +15,9 @@ #endif #if WASM_ENABLE_GC != 0 #include "gc/gc_object.h" +#if WASM_ENABLE_STRINGREF != 0 +#include "string_object.h" +#endif #endif static void @@ -718,6 +721,18 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, } else if (wasm_obj_is_func_obj(gc_obj)) 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)) { WASMObjectRef obj = wasm_externref_obj_to_internal_obj( (WASMExternrefObjectRef)gc_obj); diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 6a6b707a6..8ff388e42 100644 --- a/core/iwasm/common/wasm_native.c +++ b/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 ('r' == signature #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) +#endif #else && type == VALUE_TYPE_EXTERNREF #endif diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 93cba39ea..7d5f4dd0c 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/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_ARRAYREF: 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, 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_ARRAYREF: 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, sizeof(uintptr_t)); @@ -3734,6 +3746,12 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, case REF_TYPE_STRUCTREF: case REF_TYPE_ARRAYREF: 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 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 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_ARRAYREF: 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 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 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_ARRAYREF: 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 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 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_ARRAYREF: 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 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 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_ARRAYREF: 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 #if WASM_ENABLE_GC == 0 && WASM_ENABLE_REF_TYPES != 0 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_ARRAYREF: 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 if (n_ints < MAX_REG_INTS) 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_ARRAYREF: 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 PUT_I64_TO_ADDR(argv_ret, invokeNative_Int64(func_ptr, argv1, n_stacks)); diff --git a/core/iwasm/include/gc_export.h b/core/iwasm/include/gc_export.h index 1498ad677..f9d6ba03a 100644 --- a/core/iwasm/include/gc_export.h +++ b/core/iwasm/include/gc_export.h @@ -34,6 +34,10 @@ typedef enum wasm_value_type_enum { VALUE_TYPE_STRUCTREF = 0x67, VALUE_TYPE_ARRAYREF = 0x66, VALUE_TYPE_NULLREF = 0x65, + VALUE_TYPE_STRINGREF = 0X64, + VALUE_TYPE_STRINGVIEWWTF8 = 0x63, + VALUE_TYPE_STRINGVIEWWTF16 = 0x62, + VALUE_TYPE_STRINGVIEWITER = 0x61 } wasm_value_type_enum; 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 WASMArrayObject *wasm_array_obj_t; typedef struct WASMFuncObject *wasm_func_obj_t; +typedef struct WASMStringrefObject *wasm_stringref_obj_t; typedef uintptr_t wasm_i31_obj_t; typedef void (*wasm_obj_finalizer_t)(const wasm_obj_t obj, void *data); diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index e50163bd9..21056199e 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -44,6 +44,10 @@ extern "C" { #define REF_TYPE_STRUCTREF 0x67 #define REF_TYPE_ARRAYREF 0x66 #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 */ #define HEAP_TYPE_FUNC (-0x10) @@ -56,6 +60,10 @@ extern "C" { #define HEAP_TYPE_STRUCT (-0x19) #define HEAP_TYPE_ARRAY (-0x1A) #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 */ #define DEFINED_TYPE_FUNC 0x60 @@ -71,7 +79,7 @@ extern "C" { * Used by loader to represent any type of i32/i64/f32/f64/v128 * and ref types, including funcref, externref, anyref, eqref, * (ref null $ht), (ref $ht), i31ref, structref, arrayref, - * nullfuncref, nullexternref and nullref + * nullfuncref, nullexternref, nullref and stringref */ #define VALUE_TYPE_ANY 0x42 /** @@ -132,6 +140,9 @@ typedef void *table_elem_type_t; #if WASM_ENABLE_BULK_MEMORY != 0 #define SECTION_TYPE_DATACOUNT 12 #endif +#if WASM_ENABLE_STRINGREF != 0 +#define SECTION_TYPE_STRINGREF 14 +#endif #define SUB_SECTION_TYPE_MODULE 0 #define SUB_SECTION_TYPE_FUNC 1 @@ -156,6 +167,13 @@ typedef void *table_elem_type_t; #define WASM_TYPE_STRUCT 1 #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 WASMFunction WASMFunction; typedef struct WASMGlobal WASMGlobal; @@ -353,6 +371,36 @@ typedef struct WASMArrayType { described with one byte */ WASMRefType *elem_ref_type; } 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 */ typedef struct WASMTable { @@ -680,6 +728,12 @@ struct WASMModule { #if WASM_ENABLE_BULK_MEMORY != 0 /* data count read from datacount section */ uint32 data_seg_count1; +#endif +#if WASM_ENABLE_GC != 0 +#if WASM_ENABLE_STRINGREF != 0 + uint32 stringref_count; + char **string_consts; +#endif #endif uint32 import_function_count; @@ -760,6 +814,15 @@ struct WASMModule { HashMap *ref_type_set; struct WASMRttType **rtt_types; 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 #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) return sizeof(int64) * 2; #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); else if (value_type == VALUE_TYPE_FUNCREF || value_type == VALUE_TYPE_EXTERNREF) diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index bdfda745f..a97948a1e 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -13,6 +13,9 @@ #if WASM_ENABLE_GC != 0 #include "../common/gc/gc_object.h" #include "mem_alloc.h" +#if WASM_ENABLE_STRINGREF != 0 +#include "string_object.h" +#endif #endif #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" @@ -1391,6 +1394,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMFuncObjectRef func_obj; WASMI31ObjectRef i31_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 #if WASM_ENABLE_DEBUG_INTERP != 0 @@ -2672,6 +2682,727 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, 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: { wasm_set_exception(module, "unsupported opcode"); diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 3bb8a6f2c..9f3cd84b2 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -13,6 +13,9 @@ #if WASM_ENABLE_GC != 0 #include "../common/gc/gc_object.h" #include "mem_alloc.h" +#if WASM_ENABLE_STRINGREF != 0 +#include "string_object.h" +#endif #endif #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" @@ -1477,6 +1480,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMI31ObjectRef i31_obj; WASMExternrefObjectRef externref_obj; 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 #if WASM_ENABLE_LABELS_AS_VALUES != 0 @@ -2608,6 +2618,722 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, 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: { wasm_set_exception(module, "unsupported opcode"); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 2b9005d28..6c8c47bad 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/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)) return false; *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 { /* type which can be represented by one byte */ @@ -3702,6 +3710,60 @@ fail: 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 static bool 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)) return false; 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 default: set_error_buf(error_buf, error_buf_size, "invalid section id"); @@ -4927,6 +4999,11 @@ static uint8 section_ids[] = { SECTION_TYPE_FUNC, SECTION_TYPE_TABLE, SECTION_TYPE_MEMORY, +#if WASM_ENABLE_GC != 0 +#if WASM_ENABLE_STRINGREF != 0 + SECTION_TYPE_STRINGREF, +#endif +#endif SECTION_TYPE_GLOBAL, SECTION_TYPE_EXPORT, 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 (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); } +#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 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: 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: return false; } @@ -8042,6 +8188,7 @@ fail: #define POP_V128() TEMPLATE_POP(V128) #define POP_FUNCREF() TEMPLATE_POP(FUNCREF) #define POP_EXTERNREF() TEMPLATE_POP(EXTERNREF) +#define POP_STRINGREF() TEMPLATE_POP(STRINGREF) #if WASM_ENABLE_FAST_INTERP != 0 @@ -8277,7 +8424,7 @@ fail: wasm_reftype_struct_size(_ref_type)); \ } \ } while (0) -#endif +#endif /* end of WASM_ENABLE_GC == 0 */ #define GET_LOCAL_INDEX_TYPE_AND_OFFSET() \ do { \ @@ -11756,7 +11903,12 @@ re_scan: } else { 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, "unknown type"); goto fail; @@ -11774,10 +11926,15 @@ re_scan: bool nullable = (opcode1 == WASM_OP_REF_CAST_NULLABLE) ? true : false; - wasm_set_refheaptype_typeidx( - &wasm_ref_type.ref_ht_typeidx, nullable, - heap_type); - PUSH_REF(wasm_ref_type.ref_type); + 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; } @@ -11998,6 +12155,215 @@ re_scan: 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: set_error_buf_v(error_buf, error_buf_size, "%s %02x %02x", "unsupported opcode", diff --git a/core/iwasm/interpreter/wasm_opcode.h b/core/iwasm/interpreter/wasm_opcode.h index 8a94de81a..723aebd96 100644 --- a/core/iwasm/interpreter/wasm_opcode.h +++ b/core/iwasm/interpreter/wasm_opcode.h @@ -337,6 +337,56 @@ typedef enum WASMGCEXTOpcode { WASM_OP_EXTERN_INTERNALIZE = 0x70, /* extern.internalize */ 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; typedef enum WASMMiscEXTOpcode {