Enhance GC subtyping checks (#3317)

Enhance the GC subtyping checks:
- Fix issues in the type equivalence check
- Enable the recursive type subtyping check
- Add a equivalence type flag in defined types of aot file, if there is an
  equivalence type before, just set it true and re-use the previous type
- Normalize the defined types for interpreter and AOT
- Enable spec test case type-equivalence.wast and type-subtyping.wast,
  and enable some commented cases
- Enable set WAMR_BUILD_SANITIZER from cmake variable
This commit is contained in:
Wenyong Huang 2024-04-18 12:32:01 +08:00 committed by GitHub
parent d39d2ba3ca
commit 68bd30c6f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 585 additions and 477 deletions

View File

@ -134,7 +134,9 @@ endif ()
# Sanitizers
set(WAMR_BUILD_SANITIZER $ENV{WAMR_BUILD_SANITIZER})
if (NOT DEFINED WAMR_BUILD_SANITIZER)
set(WAMR_BUILD_SANITIZER $ENV{WAMR_BUILD_SANITIZER})
endif ()
if (NOT DEFINED WAMR_BUILD_SANITIZER)
set(WAMR_BUILD_SANITIZER "")
@ -554,3 +556,6 @@ else ()
# Disable aot intrinsics for interp, fast-jit and llvm-jit
add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=0)
endif ()
if (NOT WAMR_BUILD_SANITIZER STREQUAL "")
message (" Sanitizer ${WAMR_BUILD_SANITIZER} enabled")
endif ()

View File

@ -1525,30 +1525,42 @@ fail:
return false;
}
static void
destroy_type(AOTType *type)
{
#if WASM_ENABLE_GC != 0
if (type->ref_count > 1) {
/* The type is referenced by other types
of current aot module */
type->ref_count--;
return;
}
if (type->type_flag == WASM_TYPE_FUNC) {
AOTFuncType *func_type = (AOTFuncType *)type;
if (func_type->ref_type_maps != NULL) {
bh_assert(func_type->ref_type_map_count > 0);
wasm_runtime_free(func_type->ref_type_maps);
}
}
else if (type->type_flag == WASM_TYPE_STRUCT) {
AOTStructType *struct_type = (AOTStructType *)type;
if (struct_type->ref_type_maps != NULL) {
bh_assert(struct_type->ref_type_map_count > 0);
wasm_runtime_free(struct_type->ref_type_maps);
}
}
#endif
wasm_runtime_free(type);
}
static void
destroy_types(AOTType **types, uint32 count)
{
uint32 i;
for (i = 0; i < count; i++) {
if (types[i]) {
#if WASM_ENABLE_GC != 0
if (types[i]->type_flag == WASM_TYPE_FUNC) {
AOTFuncType *func_type = (AOTFuncType *)types[i];
if (func_type->ref_type_maps != NULL) {
bh_assert(func_type->ref_type_map_count > 0);
wasm_runtime_free(func_type->ref_type_maps);
}
}
else if (types[i]->type_flag == WASM_TYPE_STRUCT) {
AOTStructType *struct_type = (AOTStructType *)types[i];
if (struct_type->ref_type_maps != NULL) {
bh_assert(struct_type->ref_type_map_count > 0);
wasm_runtime_free(struct_type->ref_type_maps);
}
}
#endif
wasm_runtime_free(types[i]);
destroy_type(types[i]);
}
}
wasm_runtime_free(types);
@ -1556,14 +1568,17 @@ destroy_types(AOTType **types, uint32 count)
#if WASM_ENABLE_GC != 0
static void
init_base_type(AOTType *base_type, uint16 type_flag, bool is_sub_final,
uint32 parent_type_idx, uint16 rec_count, uint16 rec_idx)
init_base_type(AOTType *base_type, uint32 type_idx, uint16 type_flag,
bool is_sub_final, uint32 parent_type_idx, uint16 rec_count,
uint16 rec_idx)
{
base_type->type_flag = type_flag;
base_type->ref_count = 1;
base_type->is_sub_final = is_sub_final;
base_type->parent_type_idx = parent_type_idx;
base_type->rec_count = rec_count;
base_type->rec_idx = rec_idx;
base_type->rec_begin_type_idx = type_idx - rec_idx;
}
static bool
@ -1576,7 +1591,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
uint32 i, j;
uint32 type_flag, param_cell_num, ret_cell_num;
uint16 param_count, result_count, ref_type_map_count, rec_count, rec_idx;
bool is_sub_final;
bool is_equivalence_type, is_sub_final;
uint32 parent_type_idx;
WASMRefType ref_type;
@ -1590,12 +1605,31 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
/* Create each type */
for (i = 0; i < module->type_count; i++) {
buf = align_ptr(buf, 4);
/* Read base type info */
read_uint16(buf, buf_end, type_flag);
read_uint16(buf, buf_end, is_sub_final);
read_uint8(buf, buf_end, is_equivalence_type);
/* If there is an equivalence type, re-use it */
if (is_equivalence_type) {
uint8 u8;
/* padding */
read_uint8(buf, buf_end, u8);
(void)u8;
read_uint32(buf, buf_end, j);
if (module->types[j]->ref_count == UINT16_MAX) {
set_error_buf(error_buf, error_buf_size,
"wasm type's ref count too large");
goto fail;
}
module->types[j]->ref_count++;
module->types[i] = module->types[j];
continue;
}
read_uint8(buf, buf_end, is_sub_final);
read_uint32(buf, buf_end, parent_type_idx);
read_uint16(buf, buf_end, rec_count);
read_uint16(buf, buf_end, rec_idx);
@ -1620,7 +1654,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
types[i] = (AOTType *)func_type;
init_base_type((AOTType *)func_type, type_flag, is_sub_final,
init_base_type((AOTType *)func_type, i, type_flag, is_sub_final,
parent_type_idx, rec_count, rec_idx);
func_type->param_count = param_count;
func_type->result_count = result_count;
@ -1726,7 +1760,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
offset = (uint32)offsetof(WASMStructObject, field_data);
types[i] = (AOTType *)struct_type;
init_base_type((AOTType *)struct_type, type_flag, is_sub_final,
init_base_type((AOTType *)struct_type, i, type_flag, is_sub_final,
parent_type_idx, rec_count, rec_idx);
struct_type->field_count = field_count;
struct_type->ref_type_map_count = ref_type_map_count;
@ -1812,7 +1846,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
types[i] = (AOTType *)array_type;
init_base_type((AOTType *)array_type, type_flag, is_sub_final,
init_base_type((AOTType *)array_type, i, type_flag, is_sub_final,
parent_type_idx, rec_count, rec_idx);
read_uint16(buf, buf_end, array_type->elem_flags);
read_uint8(buf, buf_end, array_type->elem_type);
@ -1841,7 +1875,6 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
if (rec_count == 0) {
bh_assert(rec_idx == 0);
}
for (j = i - rec_idx; j <= i; j++) {
AOTType *cur_type = module->types[j];
parent_type_idx = cur_type->parent_type_idx;
@ -1850,6 +1883,11 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
module->types[j]->parent_type = parent_type;
module->types[j]->root_type = parent_type->root_type;
if (parent_type->inherit_depth == UINT16_MAX) {
set_error_buf(error_buf, error_buf_size,
"parent type's inherit depth too large");
goto fail;
}
module->types[j]->inherit_depth =
parent_type->inherit_depth + 1;
}
@ -1867,7 +1905,7 @@ load_types(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
AOTType *parent_type = module->types[parent_type_idx];
/* subtyping has been checked during compilation */
bh_assert(wasm_type_is_subtype_of(
module->types[j], parent_type, module->types, i));
module->types[j], parent_type, module->types, i + 1));
(void)parent_type;
}
}

View File

@ -143,6 +143,7 @@ typedef struct {
REG_SYM(aot_array_init_with_data), \
REG_SYM(aot_create_func_obj), \
REG_SYM(aot_obj_is_instance_of), \
REG_SYM(aot_func_type_is_super_of), \
REG_SYM(aot_rtt_type_new), \
REG_SYM(wasm_array_obj_copy), \
REG_SYM(wasm_array_obj_new), \

View File

@ -1721,6 +1721,7 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
bh_assert(table_init_data);
bh_assert(table_init_data->table_index < module_inst->table_count);
table = module_inst->tables[table_init_data->table_index];
bh_assert(table);
@ -1728,8 +1729,9 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
bh_assert(table_data);
wasm_runtime_get_table_inst_elem_type(
(WASMModuleInstanceCommon *)module_inst, i, &tbl_elem_type,
&tbl_elem_ref_type, &tbl_init_size, &tbl_max_size);
(WASMModuleInstanceCommon *)module_inst,
table_init_data->table_index, &tbl_elem_type, &tbl_elem_ref_type,
&tbl_init_size, &tbl_max_size);
if (!wasm_elem_is_declarative(table_init_data->mode)
&& !wasm_reftype_is_subtype_of(
@ -4487,6 +4489,22 @@ aot_obj_is_instance_of(AOTModuleInstance *module_inst, WASMObjectRef gc_obj,
return wasm_obj_is_instance_of(gc_obj, type_index, types, type_count);
}
bool
aot_func_type_is_super_of(AOTModuleInstance *module_inst, uint32 type_idx1,
uint32 type_idx2)
{
AOTModule *aot_module = (AOTModule *)module_inst->module;
AOTType **types = aot_module->types;
if (type_idx1 == type_idx2)
return true;
bh_assert(types[type_idx1]->type_flag == WASM_TYPE_FUNC);
bh_assert(types[type_idx2]->type_flag == WASM_TYPE_FUNC);
return wasm_func_type_is_super_of((WASMFuncType *)types[type_idx1],
(WASMFuncType *)types[type_idx2]);
}
WASMRttTypeRef
aot_rtt_type_new(AOTModuleInstance *module_inst, uint32 type_index)
{

View File

@ -752,6 +752,11 @@ bool
aot_obj_is_instance_of(AOTModuleInstance *module_inst, WASMObjectRef gc_obj,
uint32 type_index);
/* Whether func type1 is one of super types of func type2 */
bool
aot_func_type_is_super_of(AOTModuleInstance *module_inst, uint32 type_idx1,
uint32 type_idx2);
WASMRttTypeRef
aot_rtt_type_new(AOTModuleInstance *module_inst, uint32 type_index);

View File

@ -304,7 +304,12 @@ wasm_defined_type_equal(WASMType *const def_type1, WASMType *const def_type2,
}
#endif
#if WASM_ENABLE_AOT != 0
/* TODO */
if (module->module_type == Wasm_Module_AoT) {
AOTModule *aot_module = (AOTModule *)module;
types = aot_module->types;
type_count = aot_module->type_count;
}
#endif
bh_assert(types);

View File

@ -250,6 +250,51 @@ wasm_value_types_is_subtype_of(const uint8 *types1,
return true;
}
static bool
rec_ref_type_equal(const WASMRefType *ref_type1, const WASMRefType *ref_type2,
uint32 rec_begin_type_idx1, uint32 rec_begin_type_idx2,
uint32 rec_count, const WASMTypePtr *types,
uint32 type_count)
{
uint32 type_idx1, type_idx2;
if (!wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)
|| !wasm_is_refheaptype_typeidx(&ref_type2->ref_ht_common))
return ref_type1->ref_ht_common.heap_type
== ref_type2->ref_ht_common.heap_type
? true
: false;
/* Now both ref types are type of (ref type_idx) */
type_idx1 = ref_type1->ref_ht_typeidx.type_idx;
type_idx2 = ref_type2->ref_ht_typeidx.type_idx;
if (type_idx1 >= rec_begin_type_idx1
&& type_idx1 < rec_begin_type_idx1 + rec_count) {
/* The converted iso-recursive types should be the same */
bool ret = (type_idx2 >= rec_begin_type_idx2
&& type_idx2 < rec_begin_type_idx2 + rec_count
&& type_idx1 - rec_begin_type_idx1
== type_idx2 - rec_begin_type_idx2)
? true
: false;
return ret;
}
else if (type_idx2 >= rec_begin_type_idx2
&& type_idx2 < rec_begin_type_idx2 + rec_count) {
/* The converted iso-recursive types should be the same */
bool ret = (type_idx1 >= rec_begin_type_idx1
&& type_idx1 < rec_begin_type_idx1 + rec_count
&& type_idx1 - rec_begin_type_idx1
== type_idx2 - rec_begin_type_idx2)
? true
: false;
return ret;
}
return types[type_idx1] == types[type_idx2] ? true : false;
}
bool
wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2,
const WASMTypePtr *types, uint32 type_count)
@ -277,9 +322,11 @@ wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2,
ref_type1 = type1->ref_type_maps[j].ref_type;
ref_type2 = type2->ref_type_maps[j].ref_type;
if (!wasm_reftype_equal(ref_type1->ref_type, ref_type1,
ref_type2->ref_type, ref_type2, types,
type_count))
if (!rec_ref_type_equal(
ref_type1, ref_type2, type1->base_type.rec_begin_type_idx,
type2->base_type.rec_begin_type_idx,
type1->base_type.rec_count, types, type_count))
return false;
j++;
@ -316,9 +363,11 @@ wasm_struct_type_equal(const WASMStructType *type1, const WASMStructType *type2,
ref_type1 = type1->ref_type_maps[j].ref_type;
ref_type2 = type2->ref_type_maps[j].ref_type;
if (!wasm_reftype_equal(ref_type1->ref_type, ref_type1,
ref_type2->ref_type, ref_type2, types,
type_count))
if (!rec_ref_type_equal(
ref_type1, ref_type2, type1->base_type.rec_begin_type_idx,
type2->base_type.rec_begin_type_idx,
type1->base_type.rec_count, types, type_count))
return false;
j++;
@ -338,21 +387,67 @@ wasm_array_type_equal(const WASMArrayType *type1, const WASMArrayType *type2,
if (type1->elem_flags != type2->elem_flags)
return false;
return wasm_reftype_equal(type1->elem_type, type1->elem_ref_type,
type2->elem_type, type2->elem_ref_type, types,
type_count);
if (type1->elem_type != type2->elem_type)
return false;
if (!wasm_is_type_multi_byte_type(type1->elem_type))
return true;
return rec_ref_type_equal(type1->elem_ref_type, type2->elem_ref_type,
type1->base_type.rec_begin_type_idx,
type2->base_type.rec_begin_type_idx,
type1->base_type.rec_count, types, type_count);
}
bool
wasm_type_equal(const WASMType *type1, const WASMType *type2,
const WASMTypePtr *types, uint32 type_count)
{
uint32 rec_begin_type_idx1 = type1->rec_begin_type_idx;
uint32 rec_begin_type_idx2 = type2->rec_begin_type_idx;
uint32 parent_type_idx1, parent_type_idx2, rec_count;
if (type1 == type2)
return true;
if (type1->type_flag != type2->type_flag)
if (!(type1->type_flag == type2->type_flag
&& type1->is_sub_final == type2->is_sub_final
&& type1->rec_count == type2->rec_count
&& type1->rec_idx == type2->rec_idx))
return false;
rec_count = type1->rec_count;
parent_type_idx1 = type1->parent_type_idx;
parent_type_idx2 = type2->parent_type_idx;
if (parent_type_idx1 >= rec_begin_type_idx1
&& parent_type_idx1 < rec_begin_type_idx1 + rec_count) {
/* The converted iso-recursive types should be the same */
if (!(parent_type_idx2 >= rec_begin_type_idx2
&& parent_type_idx2 < rec_begin_type_idx2 + rec_count
&& parent_type_idx1 - rec_begin_type_idx1
== parent_type_idx2 - rec_begin_type_idx2)) {
return false;
}
}
else if (parent_type_idx2 >= rec_begin_type_idx2
&& parent_type_idx2 < rec_begin_type_idx2 + rec_count) {
/* The converted iso-recursive types should be the same */
if (!(parent_type_idx1 >= rec_begin_type_idx1
&& parent_type_idx1 < rec_begin_type_idx1 + rec_count
&& parent_type_idx1 - rec_begin_type_idx1
== parent_type_idx2 - rec_begin_type_idx2)) {
return false;
}
}
else if (type1->parent_type != type2->parent_type) {
/* The parent types should be same since they have been
normalized and equivalence types with different type
indexes are referring to a same WASMType */
return false;
}
if (wasm_type_is_func_type(type1))
return wasm_func_type_equal((WASMFuncType *)type1,
(WASMFuncType *)type2, types, type_count);
@ -653,12 +748,6 @@ wasm_reftype_struct_size(const WASMRefType *ref_type)
return (uint32)sizeof(RefHeapType_Common);
}
static bool
type_idx_equal(uint32 type_idx1, uint32 type_idx2)
{
return (type_idx1 == type_idx2) ? true : false;
}
bool
wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1,
const RefHeapType_Common *ref_heap_type2,
@ -673,8 +762,16 @@ wasm_refheaptype_equal(const RefHeapType_Common *ref_heap_type1,
if (ref_heap_type1->heap_type != ref_heap_type2->heap_type) {
if (wasm_is_refheaptype_typeidx(ref_heap_type1)
&& wasm_is_refheaptype_typeidx(ref_heap_type2)) {
return type_idx_equal(ref_heap_type1->heap_type,
ref_heap_type2->heap_type);
if (ref_heap_type1->heap_type == ref_heap_type2->heap_type)
return true;
else
/* the type_count may be 0 when called from reftype_equal */
return ((uint32)ref_heap_type1->heap_type < type_count
&& (uint32)ref_heap_type2->heap_type < type_count
&& types[ref_heap_type1->heap_type]
== types[ref_heap_type2->heap_type])
? true
: false;
}
return false;
}
@ -835,6 +932,13 @@ wasm_type_is_supers_of(const WASMType *type1, const WASMType *type2)
return false;
}
bool
wasm_func_type_is_super_of(const WASMFuncType *type1, const WASMFuncType *type2)
{
return wasm_type_is_supers_of((const WASMType *)type1,
(const WASMType *)type2);
}
bool
wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
uint8 type2, const WASMRefType *ref_type2,
@ -914,14 +1018,15 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
#endif
else if (type1 == REF_TYPE_HT_NULLABLE) {
if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) {
bh_assert((uint32)ref_type1->ref_ht_typeidx.type_idx < type_count);
/* reftype1 is (ref null $t) */
if (type2 == REF_TYPE_HT_NULLABLE && ref_type2 != NULL
&& wasm_is_refheaptype_typeidx(&ref_type2->ref_ht_common)) {
return type_idx_equal(ref_type1->ref_ht_typeidx.type_idx,
ref_type2->ref_ht_typeidx.type_idx)
|| wasm_type_is_supers_of(
types[ref_type2->ref_ht_typeidx.type_idx],
types[ref_type1->ref_ht_typeidx.type_idx]);
bh_assert((uint32)ref_type2->ref_ht_typeidx.type_idx
< type_count);
return wasm_type_is_supers_of(
types[ref_type2->ref_ht_typeidx.type_idx],
types[ref_type1->ref_ht_typeidx.type_idx]);
}
else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
== WASM_TYPE_STRUCT)
@ -963,16 +1068,17 @@ wasm_reftype_is_subtype_of(uint8 type1, const WASMRefType *ref_type1,
else if (type1 == REF_TYPE_HT_NON_NULLABLE) {
bh_assert(ref_type1);
if (wasm_is_refheaptype_typeidx(&ref_type1->ref_ht_common)) {
bh_assert((uint32)ref_type1->ref_ht_typeidx.type_idx < type_count);
/* reftype1 is (ref $t) */
if ((type2 == REF_TYPE_HT_NULLABLE
|| type2 == REF_TYPE_HT_NON_NULLABLE)
&& ref_type2 != NULL
&& wasm_is_refheaptype_typeidx(&ref_type2->ref_ht_common)) {
return type_idx_equal(ref_type1->ref_ht_typeidx.type_idx,
ref_type2->ref_ht_typeidx.type_idx)
|| wasm_type_is_supers_of(
types[ref_type2->ref_ht_typeidx.type_idx],
types[ref_type1->ref_ht_typeidx.type_idx]);
bh_assert((uint32)ref_type2->ref_ht_typeidx.type_idx
< type_count);
return wasm_type_is_supers_of(
types[ref_type2->ref_ht_typeidx.type_idx],
types[ref_type1->ref_ht_typeidx.type_idx]);
}
else if (types[ref_type1->ref_ht_typeidx.type_idx]->type_flag
== WASM_TYPE_STRUCT) {

View File

@ -47,6 +47,12 @@ wasm_func_type_is_subtype_of(const WASMFuncType *type1,
const WASMFuncType *type2,
const WASMTypePtr *types, uint32 type_count);
/* Whether func type1 is one of super types of func type2,
used for the func type check in call_indirect/call_ref opcodes */
bool
wasm_func_type_is_super_of(const WASMFuncType *type1,
const WASMFuncType *type2);
/* Whether func type1's result types are subtype of
func type2's result types */
bool

View File

@ -578,8 +578,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
is_anyref = true;
}
if (wasm_is_type_multi_byte_type(
type->types[type->param_count + i])) {
if (wasm_is_type_multi_byte_type(type->types[i])) {
WASMRefType *ref_type = ref_type_map->ref_type;
if (wasm_is_refheaptype_common(
&ref_type->ref_ht_common)) {

View File

@ -84,9 +84,9 @@ compare_type_with_signautre(uint8 type, const char signature)
if ('r' == signature
#if WASM_ENABLE_GC != 0
#if WASM_ENABLE_STRINGREF != 0
&& (type >= REF_TYPE_STRINGVIEWITER && type <= REF_TYPE_FUNCREF)
&& (type >= REF_TYPE_STRINGVIEWITER && type <= REF_TYPE_NULLFUNCREF)
#else
&& (type >= REF_TYPE_NULLREF && type <= REF_TYPE_FUNCREF)
&& (type >= REF_TYPE_HT_NULLABLE && type <= REF_TYPE_NULLFUNCREF)
#endif
#else
&& type == VALUE_TYPE_EXTERNREF

View File

@ -484,15 +484,15 @@ static uint32
get_func_type_size(AOTCompContext *comp_ctx, AOTFuncType *func_type)
{
#if WASM_ENABLE_GC != 0
/* type flag + is_sub_final + parent_type_idx + rec_count + rec_idx + param
* count + result count
* + ref_type_map_count + types + context of ref_type_map */
/* type flag + equivalence type flag + is_sub_final + parent_type_idx
+ rec_count + rec_idx + param count + result count
+ ref_type_map_count + types + context of ref_type_map */
if (comp_ctx->enable_gc) {
uint32 size = 0;
/* type flag */
size += sizeof(func_type->base_type.type_flag);
/* is_sub_final */
/* equivalence type flag + is_sub_final */
size += sizeof(uint16);
/* parent_type_idx */
size += sizeof(func_type->base_type.parent_type_idx);
@ -529,12 +529,12 @@ static uint32
get_struct_type_size(AOTCompContext *comp_ctx, AOTStructType *struct_type)
{
uint32 size = 0;
/* type flag + is_sub_final + parent_type_idx + rec_count + rec_idx + field
* count + fields */
/* type flag + equivalence type flag + is_sub_final + parent_type_idx
+ rec_count + rec_idx + field count + fields */
/* type flag */
size += sizeof(struct_type->base_type.type_flag);
/* is_sub_final */
/* equivalence type flag + is_sub_final */
size += sizeof(uint16);
/* parent_type_idx */
size += sizeof(struct_type->base_type.parent_type_idx);
@ -558,12 +558,12 @@ static uint32
get_array_type_size(AOTCompContext *comp_ctx, AOTArrayType *array_type)
{
uint32 size = 0;
/* type flag + is_sub_final + parent_type_idx + rec_count + rec_idx +
elem_flags + elem_type + elem_ref_type */
/* type flag + equivalence type flag + is_sub_final + parent_type_idx
+ rec_count + rec_idx + elem_flags + elem_type + elem_ref_type */
/* type flag */
size += sizeof(array_type->base_type.type_flag);
/* is_sub_final */
/* equivalence type flag + is_sub_final */
size += sizeof(uint16);
/* parent_type_idx (u32) */
size += sizeof(array_type->base_type.parent_type_idx);
@ -597,7 +597,22 @@ get_type_info_size(AOTCompContext *comp_ctx, AOTCompData *comp_data)
#if WASM_ENABLE_GC != 0
if (comp_ctx->enable_gc) {
for (i = 0; i < comp_data->type_count; i++) {
uint32 j;
size = align_uint(size, 4);
/* Emit simple info if there is an equivalence type */
for (j = 0; j < i; j++) {
if (comp_data->types[j] == comp_data->types[i]) {
/* type_flag (2 bytes) + equivalence type flag (1 byte)
+ padding (1 byte) + equivalence type index */
size += 8;
break;
}
}
if (j < i)
continue;
if (comp_data->types[i]->type_flag == WASM_TYPE_FUNC)
size += get_func_type_size(comp_ctx,
(AOTFuncType *)comp_data->types[i]);
@ -2093,13 +2108,32 @@ aot_emit_type_info(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
#if WASM_ENABLE_GC != 0
if (comp_ctx->enable_gc) {
int32 idx;
AOTType **types = comp_data->types;
int32 idx;
uint32 j;
for (i = 0; i < comp_data->type_count; i++) {
offset = align_uint(offset, 4);
/* Emit simple info if there is an equivalence type */
for (j = 0; j < i; j++) {
if (types[j] == types[i]) {
EMIT_U16(types[i]->type_flag);
/* equivalence type flag is true */
EMIT_U8(1);
EMIT_U8(0);
/* equivalence type index */
EMIT_U32(j);
break;
}
}
if (j < i)
continue;
EMIT_U16(types[i]->type_flag);
EMIT_U16(types[i]->is_sub_final);
/* equivalence type flag is false */
EMIT_U8(0);
EMIT_U8(types[i]->is_sub_final);
EMIT_U32(types[i]->parent_type_idx);
EMIT_U16(types[i]->rec_count);
@ -2593,7 +2627,7 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
if (comp_ctx->enable_gc) {
/* emit func_local_ref_flag arrays for both import and AOTed funcs */
AOTFuncType *func_type;
uint32 j, local_ref_flags_cell_num;
uint32 j, local_ref_flags_cell_num, paddings;
for (i = 0; i < comp_data->import_func_count; i++) {
func_type = comp_data->import_funcs[i].func_type;
@ -2603,6 +2637,8 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
local_ref_flags_cell_num += wasm_value_type_cell_num_internal(
func_type->types[j], comp_ctx->pointer_size);
}
paddings =
local_ref_flags_cell_num < 2 ? 2 - local_ref_flags_cell_num : 0;
local_ref_flags_cell_num =
local_ref_flags_cell_num > 2 ? local_ref_flags_cell_num : 2;
@ -2614,7 +2650,7 @@ aot_emit_func_section(uint8 *buf, uint8 *buf_end, uint32 *p_offset,
func_type->types[j]))
return false;
}
for (; j < 2; j++)
for (j = 0; j < paddings; j++)
EMIT_U8(0);
}

View File

@ -1826,6 +1826,52 @@ fail:
return ret;
}
#if WASM_ENABLE_GC != 0
static LLVMValueRef
call_aot_func_type_is_super_of_func(AOTCompContext *comp_ctx,
AOTFuncContext *func_ctx,
LLVMValueRef type_idx1,
LLVMValueRef type_idx2)
{
LLVMValueRef param_values[3], ret_value, value, func;
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
param_types[0] = comp_ctx->aot_inst_type;
param_types[1] = I32_TYPE;
param_types[2] = I32_TYPE;
ret_type = INT8_TYPE;
#if WASM_ENABLE_JIT != 0
if (comp_ctx->is_jit_mode)
GET_AOT_FUNCTION(llvm_jit_func_type_is_super_of, 3);
else
#endif
GET_AOT_FUNCTION(aot_func_type_is_super_of, 3);
param_values[0] = func_ctx->aot_inst;
param_values[1] = type_idx1;
param_values[2] = type_idx2;
if (!(ret_value =
LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
3, "call_aot_func_type_is_super_of"))) {
aot_set_last_error("llvm build call failed.");
return NULL;
}
if (!(ret_value = LLVMBuildICmp(comp_ctx->builder, LLVMIntEQ, ret_value,
I8_ZERO, "check_fail"))) {
aot_set_last_error("llvm build icmp failed.");
return NULL;
}
return ret_value;
fail:
return NULL;
}
#endif
static bool
call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
AOTFuncType *aot_func_type,
@ -2018,15 +2064,23 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return false;
}
/* Find the equivalent function type whose type index is the smallest:
the callee function's type index is also converted to the smallest
one in wasm loader, so we can just check whether the two type indexes
are equal (the type index of call_indirect opcode and callee func),
we don't need to check whether the whole function types are equal,
including param types and result types. */
type_idx =
wasm_get_smallest_type_idx((WASMTypePtr *)comp_ctx->comp_data->types,
comp_ctx->comp_data->type_count, type_idx);
if (!comp_ctx->enable_gc) {
/* Find the equivalent function type whose type index is the smallest:
the callee function's type index is also converted to the smallest
one in wasm loader, so we can just check whether the two type indexes
are equal (the type index of call_indirect opcode and callee func),
we don't need to check whether the whole function types are equal,
including param types and result types. */
type_idx = wasm_get_smallest_type_idx(
(WASMTypePtr *)comp_ctx->comp_data->types,
comp_ctx->comp_data->type_count, type_idx);
}
else {
/* Call aot_func_type_is_super_of to check whether the func type
provided in the bytecode is a super type of the func type of
the function to call */
}
ftype_idx_const = I32_CONST(type_idx);
CHECK_LLVM_CONST(ftype_idx_const);
@ -2254,11 +2308,23 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
goto fail;
}
/* Check if function type index not equal */
if (!(cmp_ftype_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, ftype_idx,
ftype_idx_const, "cmp_ftype_idx"))) {
aot_set_last_error("llvm build icmp failed.");
goto fail;
#if WASM_ENABLE_GC != 0
if (comp_ctx->enable_gc) {
if (!(cmp_ftype_idx = call_aot_func_type_is_super_of_func(
comp_ctx, func_ctx, ftype_idx_const, ftype_idx))) {
goto fail;
}
}
else
#endif
{
/* Check if function type index not equal */
if (!(cmp_ftype_idx =
LLVMBuildICmp(comp_ctx->builder, LLVMIntNE, ftype_idx,
ftype_idx_const, "cmp_ftype_idx"))) {
aot_set_last_error("llvm build icmp failed.");
goto fail;
}
}
/* Throw exception if ftype_idx != ftype_idx_const */

View File

@ -274,7 +274,7 @@ typedef struct InitializerExpression {
*/
typedef struct RefHeapType_TypeIdx {
/* ref_type is REF_TYPE_HT_NULLABLE or
REF_TYPE_HT_NON_NULLABLE, (0x6C or 0x6B) */
REF_TYPE_HT_NON_NULLABLE, (0x63 or 0x64) */
uint8 ref_type;
/* true if ref_type is REF_TYPE_HT_NULLABLE */
bool nullable;
@ -288,7 +288,7 @@ typedef struct RefHeapType_TypeIdx {
*/
typedef struct RefHeapType_Common {
/* ref_type is REF_TYPE_HT_NULLABLE or
REF_TYPE_HT_NON_NULLABLE (0x6C or 0x6B) */
REF_TYPE_HT_NON_NULLABLE (0x63 or 0x64) */
uint8 ref_type;
/* true if ref_type is REF_TYPE_HT_NULLABLE */
bool nullable;
@ -338,18 +338,24 @@ typedef struct WASMType {
uint16 type_flag;
bool is_sub_final;
/* How many types are referring to this type */
uint16 ref_count;
/* The inheritance depth */
uint32 inherit_depth;
uint16 inherit_depth;
/* The root type */
struct WASMType *root_type;
/* The parent type */
struct WASMType *parent_type;
uint32 parent_type_idx;
/* number of internal types in the current rec group, if the type is not in
* a recursive group, rec_count = 0 */
/* The number of internal types in the current rec group, and if
the type is not in a recursive group, rec_count is 1 since a
single type definition is reinterpreted as a short-hand for a
recursive group containing just one type */
uint16 rec_count;
uint16 rec_idx;
/* The index of the begin type of this group */
uint32 rec_begin_type_idx;
} WASMType, *WASMTypePtr;
#endif /* end of WASM_ENABLE_GC */
@ -375,9 +381,6 @@ typedef struct WASMFuncType {
uint16 ref_type_map_count;
WASMRefTypeMap *ref_type_maps;
WASMRefTypeMap *result_ref_type_maps;
/* minimal type index of the type equal to this type,
used in type equal check in call_indirect opcode */
uint32 min_type_idx_normalized;
#else
uint16 ref_count;
#endif

View File

@ -2212,6 +2212,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
WASMFuncType *cur_type, *cur_func_type;
WASMTableInstance *tbl_inst;
uint32 tbl_idx;
#if WASM_ENABLE_TAIL_CALL != 0
opcode = *(frame_ip - 1);
#endif
@ -2282,8 +2283,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception;
}
#else
if (cur_type->min_type_idx_normalized
!= cur_func_type->min_type_idx_normalized) {
if (!wasm_func_type_is_super_of(cur_type, cur_func_type)) {
wasm_set_exception(module, "indirect call type mismatch");
goto got_exception;
}

View File

@ -1736,8 +1736,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception;
}
#else
if (cur_type->min_type_idx_normalized
!= cur_func_type->min_type_idx_normalized) {
if (!wasm_func_type_is_super_of(cur_type, cur_func_type)) {
wasm_set_exception(module, "indirect call type mismatch");
goto got_exception;
}

View File

@ -394,10 +394,10 @@ memory_realloc(void *mem_old, uint32 size_old, uint32 size_new, char *error_buf,
#if WASM_ENABLE_GC != 0
static bool
check_type_index(const WASMModule *module, uint32 type_index, char *error_buf,
uint32 error_buf_size)
check_type_index(const WASMModule *module, uint32 type_count, uint32 type_index,
char *error_buf, uint32 error_buf_size)
{
if (type_index >= module->type_count) {
if (type_index >= type_count) {
set_error_buf_v(error_buf, error_buf_size, "unknown type %d",
type_index);
return false;
@ -409,7 +409,8 @@ static bool
check_array_type(const WASMModule *module, uint32 type_index, char *error_buf,
uint32 error_buf_size)
{
if (!check_type_index(module, type_index, error_buf, error_buf_size)) {
if (!check_type_index(module, module->type_count, type_index, error_buf,
error_buf_size)) {
return false;
}
if (module->types[type_index]->type_flag != WASM_TYPE_ARRAY) {
@ -775,8 +776,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
if (!is_byte_a_type(type1)) {
p--;
read_leb_uint32(p, p_end, type_idx);
if (!check_type_index(module, type_idx, error_buf,
error_buf_size))
if (!check_type_index(module, module->type_count, type_idx,
error_buf, error_buf_size))
goto fail;
wasm_set_refheaptype_typeidx(&cur_ref_type.ref_ht_typeidx,
@ -902,7 +903,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
uint32 field_count;
read_leb_uint32(p, p_end, type_idx);
if (!check_type_index(module, type_idx, error_buf,
if (!check_type_index(module, module->type_count,
type_idx, error_buf,
error_buf_size)) {
goto fail;
}
@ -966,7 +968,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
read_leb_uint32(p, p_end, cur_value.type_index);
type_idx = cur_value.type_index;
if (!check_type_index(module, type_idx, error_buf,
if (!check_type_index(module, module->type_count,
type_idx, error_buf,
error_buf_size)) {
goto fail;
}
@ -1001,7 +1004,8 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
read_leb_uint32(p, p_end, cur_value.type_index);
type_idx = cur_value.type_index;
if (!check_type_index(module, type_idx, error_buf,
if (!check_type_index(module, module->type_count,
type_idx, error_buf,
error_buf_size)) {
goto fail;
}
@ -1275,6 +1279,13 @@ destroy_array_type(WASMArrayType *type)
static void
destroy_wasm_type(WASMType *type)
{
if (type->ref_count > 1) {
/* The type is referenced by other types
of current wasm module */
type->ref_count--;
return;
}
if (type->type_flag == WASM_TYPE_FUNC)
destroy_func_type((WASMFuncType *)type);
else if (type->type_flag == WASM_TYPE_STRUCT)
@ -1289,8 +1300,9 @@ destroy_wasm_type(WASMType *type)
/* Resolve (ref null ht) or (ref ht) */
static bool
resolve_reftype_htref(const uint8 **p_buf, const uint8 *buf_end,
WASMModule *module, bool nullable, WASMRefType *ref_type,
char *error_buf, uint32 error_buf_size)
WASMModule *module, uint32 type_count, bool nullable,
WASMRefType *ref_type, char *error_buf,
uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end;
@ -1301,8 +1313,9 @@ resolve_reftype_htref(const uint8 **p_buf, const uint8 *buf_end,
if (wasm_is_refheaptype_typeidx(&ref_type->ref_ht_common)) {
/* heap type is (type i), i : typeidx, >= 0 */
if (!check_type_index(module, ref_type->ref_ht_typeidx.type_idx,
error_buf, error_buf_size)) {
if (!check_type_index(module, type_count,
ref_type->ref_ht_typeidx.type_idx, error_buf,
error_buf_size)) {
return false;
}
}
@ -1320,9 +1333,10 @@ fail:
static bool
resolve_value_type(const uint8 **p_buf, const uint8 *buf_end,
WASMModule *module, bool *p_need_ref_type_map,
WASMRefType *ref_type, bool allow_packed_type,
char *error_buf, uint32 error_buf_size)
WASMModule *module, uint32 type_count,
bool *p_need_ref_type_map, WASMRefType *ref_type,
bool allow_packed_type, char *error_buf,
uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end;
uint8 type;
@ -1334,8 +1348,8 @@ resolve_value_type(const uint8 **p_buf, const uint8 *buf_end,
if (wasm_is_reftype_htref_nullable(type)) {
/* (ref null ht) */
if (!resolve_reftype_htref(&p, p_end, module, true, ref_type, error_buf,
error_buf_size))
if (!resolve_reftype_htref(&p, p_end, module, type_count, true,
ref_type, error_buf, error_buf_size))
return false;
if (!wasm_is_refheaptype_common(&ref_type->ref_ht_common))
*p_need_ref_type_map = true;
@ -1351,8 +1365,8 @@ resolve_value_type(const uint8 **p_buf, const uint8 *buf_end,
}
else if (wasm_is_reftype_htref_non_nullable(type)) {
/* (ref ht) */
if (!resolve_reftype_htref(&p, p_end, module, false, ref_type,
error_buf, error_buf_size))
if (!resolve_reftype_htref(&p, p_end, module, type_count, false,
ref_type, error_buf, error_buf_size))
return false;
*p_need_ref_type_map = true;
#if WASM_ENABLE_STRINGREF != 0
@ -1401,7 +1415,8 @@ reftype_set_insert(HashMap *ref_type_set, const WASMRefType *ref_type,
static bool
resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
uint32 type_idx, char *error_buf, uint32 error_buf_size)
uint32 type_count, uint32 type_idx, char *error_buf,
uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
uint32 param_count, result_count, i, j = 0;
@ -1417,8 +1432,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
read_leb_uint32(p, p_end, param_count);
p_org = p;
for (i = 0; i < param_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
return false;
}
if (need_ref_type_map)
@ -1427,8 +1443,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
read_leb_uint32(p, p_end, result_count);
for (i = 0; i < result_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
return false;
}
if (need_ref_type_map) {
@ -1468,8 +1485,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
}
for (i = 0; i < param_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
goto fail;
}
type->types[i] = ref_type.ref_type;
@ -1485,8 +1503,9 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
read_leb_uint32(p, p_end, result_count);
for (i = 0; i < result_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
goto fail;
}
type->types[param_count + i] = ref_type.ref_type;
@ -1527,18 +1546,6 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
}
#endif
/* Calculate the minimal type index of the type equal to this type */
type->min_type_idx_normalized = type_idx;
for (i = 0; i < type_idx; i++) {
WASMFuncType *func_type = (WASMFuncType *)module->types[i];
if (func_type->base_type.type_flag == WASM_TYPE_FUNC
&& wasm_func_type_equal(type, func_type, module->types,
type_idx + 1)) {
type->min_type_idx_normalized = i;
break;
}
}
*p_buf = p;
module->types[type_idx] = (WASMType *)type;
@ -1552,8 +1559,8 @@ fail:
static bool
resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end,
WASMModule *module, uint32 type_idx, char *error_buf,
uint32 error_buf_size)
WASMModule *module, uint32 type_count, uint32 type_idx,
char *error_buf, uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
uint32 field_count, ref_type_map_count = 0, ref_field_count = 0;
@ -1569,8 +1576,9 @@ resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end,
read_leb_uint32(p, p_end, field_count);
p_org = p;
for (i = 0; i < field_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, true, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count,
&need_ref_type_map, &ref_type, true, error_buf,
error_buf_size)) {
return false;
}
if (need_ref_type_map)
@ -1617,8 +1625,9 @@ resolve_struct_type(const uint8 **p_buf, const uint8 *buf_end,
offset = (uint32)offsetof(WASMStructObject, field_data);
for (i = 0; i < field_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, true, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count,
&need_ref_type_map, &ref_type, true, error_buf,
error_buf_size)) {
goto fail;
}
type->fields[i].field_type = ref_type.ref_type;
@ -1671,8 +1680,8 @@ fail:
static bool
resolve_array_type(const uint8 **p_buf, const uint8 *buf_end,
WASMModule *module, uint32 type_idx, char *error_buf,
uint32 error_buf_size)
WASMModule *module, uint32 type_count, uint32 type_idx,
char *error_buf, uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end;
uint8 mutable;
@ -1680,8 +1689,8 @@ resolve_array_type(const uint8 **p_buf, const uint8 *buf_end,
WASMRefType ref_type;
WASMArrayType *type = NULL;
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, &ref_type,
true, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, type_count, &need_ref_type_map,
&ref_type, true, error_buf, error_buf_size)) {
return false;
}
@ -1730,7 +1739,8 @@ init_ref_type(WASMModule *module, WASMRefType *ref_type, bool nullable,
int32 heap_type, char *error_buf, uint32 error_buf_size)
{
if (heap_type >= 0) {
if (!check_type_index(module, heap_type, error_buf, error_buf_size)) {
if (!check_type_index(module, module->type_count, heap_type, error_buf,
error_buf_size)) {
return false;
}
wasm_set_refheaptype_typeidx(&ref_type->ref_ht_typeidx, nullable,
@ -2010,6 +2020,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
if (flag == DEFINED_TYPE_FUNC) {
if (!resolve_func_type(&p, buf_end, module,
processed_type_count + rec_count,
processed_type_count + j, error_buf,
error_buf_size)) {
return false;
@ -2017,6 +2028,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
}
else if (flag == DEFINED_TYPE_STRUCT) {
if (!resolve_struct_type(&p, buf_end, module,
processed_type_count + rec_count,
processed_type_count + j,
error_buf, error_buf_size)) {
return false;
@ -2024,6 +2036,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
}
else if (flag == DEFINED_TYPE_ARRAY) {
if (!resolve_array_type(&p, buf_end, module,
processed_type_count + rec_count,
processed_type_count + j, error_buf,
error_buf_size)) {
return false;
@ -2037,13 +2050,13 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
cur_type = module->types[processed_type_count + j];
cur_type->ref_count = 1;
cur_type->parent_type_idx = parent_type_idx;
cur_type->is_sub_final = is_sub_final;
if (rec_count > 1) {
cur_type->rec_count = rec_count;
cur_type->rec_idx = j;
}
cur_type->rec_count = rec_count;
cur_type->rec_idx = j;
cur_type->rec_begin_type_idx = processed_type_count;
}
/* resolve subtyping relationship in current rec group */
@ -2055,6 +2068,11 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
module->types[cur_type->parent_type_idx];
cur_type->parent_type = parent_type;
cur_type->root_type = parent_type->root_type;
if (parent_type->inherit_depth == UINT16_MAX) {
set_error_buf(error_buf, error_buf_size,
"parent type's inherit depth too large");
return false;
}
cur_type->inherit_depth = parent_type->inherit_depth + 1;
}
else {
@ -2080,6 +2098,49 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
}
}
/* If there is already an equivalence type or a group of equivalence
recursive types created, use it or them instead */
for (j = 0; j < processed_type_count;) {
WASMType *src_type = module->types[j];
WASMType *cur_type = module->types[processed_type_count];
uint32 k, src_rec_count;
src_rec_count = src_type->rec_count;
if (src_rec_count != rec_count) {
/* no type equivalence */
j += src_rec_count;
continue;
}
for (k = 0; k < rec_count; k++) {
src_type = module->types[j + k];
cur_type = module->types[processed_type_count + k];
if (!wasm_type_equal(src_type, cur_type, module->types,
module->type_count)) {
break;
}
}
if (k < rec_count) {
/* no type equivalence */
j += src_rec_count;
continue;
}
/* type equivalence */
for (k = 0; k < rec_count; k++) {
if (module->types[j + k]->ref_count == UINT16_MAX) {
set_error_buf(error_buf, error_buf_size,
"wasm type's ref count too large");
return false;
}
destroy_wasm_type(module->types[processed_type_count + k]);
module->types[processed_type_count + k] =
module->types[j + k];
module->types[j + k]->ref_count++;
}
break;
}
if (rec_count > 1) {
LOG_VERBOSE("Finished processing rec group [%d-%d]",
processed_type_count,
@ -2511,8 +2572,9 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
return false;
}
#else /* else of WASM_ENABLE_GC == 0 */
if (!resolve_value_type(&p, p_end, parent_module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, parent_module, parent_module->type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
return false;
}
if (wasm_is_reftype_htref_non_nullable(ref_type.ref_type)) {
@ -2947,8 +3009,9 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
declare_type = read_uint8(p);
declare_mutable = read_uint8(p);
#else
if (!resolve_value_type(&p, p_end, parent_module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, parent_module, parent_module->type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
return false;
}
declare_type = ref_type.ref_type;
@ -3050,8 +3113,9 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
return false;
}
#else /* else of WASM_ENABLE_GC == 0 */
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, &ref_type,
false, error_buf, error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, module->type_count,
&need_ref_type_map, &ref_type, false, error_buf,
error_buf_size)) {
return false;
}
table->elem_type = ref_type.ref_type;
@ -3536,7 +3600,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
type_index_org = type_index;
#endif
#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0)
#if (WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0) \
&& WASM_ENABLE_GC == 0
type_index = wasm_get_smallest_type_idx(
module->types, module->type_count, type_index);
#endif
@ -3577,8 +3642,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
#endif
#else
if (!resolve_value_type(&p_code, buf_code_end, module,
&need_ref_type_map, &ref_type, false,
error_buf, error_buf_size)) {
module->type_count, &need_ref_type_map,
&ref_type, false, error_buf,
error_buf_size)) {
return false;
}
local_count += sub_local_count;
@ -3664,8 +3730,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
}
#else
if (!resolve_value_type(&p_code, buf_code_end, module,
&need_ref_type_map, &ref_type, false,
error_buf, error_buf_size)) {
module->type_count, &need_ref_type_map,
&ref_type, false, error_buf,
error_buf_size)) {
return false;
}
if (need_ref_type_map) {
@ -3923,9 +3990,9 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
global->type = read_uint8(p);
mutable = read_uint8(p);
#else
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, false, error_buf,
error_buf_size)) {
if (!resolve_value_type(&p, p_end, module, module->type_count,
&need_ref_type_map, &ref_type, false,
error_buf, error_buf_size)) {
return false;
}
global->type = ref_type.ref_type;
@ -4231,8 +4298,8 @@ load_elem_type(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
#else
p--;
if (!resolve_value_type((const uint8 **)&p, p_end, module,
&need_ref_type_map, &elem_ref_type, false,
error_buf, error_buf_size)) {
module->type_count, &need_ref_type_map,
&elem_ref_type, false, error_buf, error_buf_size)) {
return false;
}
if (!wasm_is_type_reftype(elem_ref_type.ref_type)) {
@ -10827,7 +10894,8 @@ re_scan:
p_org = p;
p--;
if (!resolve_value_type((const uint8 **)&p, p_end,
module, &need_ref_type_map,
module, module->type_count,
&need_ref_type_map,
&wasm_ref_type, false,
error_buf, error_buf_size)) {
goto fail;
@ -11303,8 +11371,8 @@ re_scan:
bh_memcpy_s(loader_ctx->frame_offset, size,
block->param_frame_offsets, size);
loader_ctx->frame_offset += (size / sizeof(int16));
loader_ctx->dynamic_offset = block->start_dynamic_offset;
}
loader_ctx->dynamic_offset = block->start_dynamic_offset;
#endif
break;
@ -11598,6 +11666,15 @@ re_scan:
if (opcode == WASM_OP_CALL_REF
|| opcode == WASM_OP_RETURN_CALL_REF) {
read_leb_uint32(p, p_end, type_idx1);
if (!check_type_index(module, module->type_count, type_idx1,
error_buf, error_buf_size)) {
goto fail;
}
if (module->types[type_idx1]->type_flag != WASM_TYPE_FUNC) {
set_error_buf(error_buf, error_buf_size,
"unkown function type");
goto fail;
}
if (!wasm_loader_pop_nullable_typeidx(loader_ctx, &type,
&type_idx, error_buf,
error_buf_size)) {
@ -11606,8 +11683,8 @@ re_scan:
if (type == VALUE_TYPE_ANY) {
type_idx = type_idx1;
}
if (!check_type_index(module, type_idx, error_buf,
error_buf_size)) {
if (!check_type_index(module, module->type_count, type_idx,
error_buf, error_buf_size)) {
goto fail;
}
if (module->types[type_idx]->type_flag != WASM_TYPE_FUNC) {
@ -11615,7 +11692,9 @@ re_scan:
"unkown function type");
goto fail;
}
if (type_idx != type_idx1) {
if (!wasm_func_type_is_super_of(
(WASMFuncType *)module->types[type_idx1],
(WASMFuncType *)module->types[type_idx])) {
set_error_buf(error_buf, error_buf_size,
"function type mismatch");
goto fail;
@ -12055,8 +12134,9 @@ re_scan:
#else
p_org = p + 1;
if (!resolve_value_type((const uint8 **)&p, p_end, module,
&need_ref_type_map, &wasm_ref_type,
false, error_buf, error_buf_size)) {
module->type_count, &need_ref_type_map,
&wasm_ref_type, false, error_buf,
error_buf_size)) {
goto fail;
}
type = wasm_ref_type.ref_type;
@ -12223,8 +12303,8 @@ re_scan:
#else
read_leb_int32(p, p_end, heap_type);
if (heap_type >= 0) {
if (!check_type_index(module, heap_type, error_buf,
error_buf_size)) {
if (!check_type_index(module, module->type_count, heap_type,
error_buf, error_buf_size)) {
goto fail;
}
wasm_set_refheaptype_typeidx(&wasm_ref_type.ref_ht_typeidx,
@ -13288,7 +13368,8 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
emit_uint32(loader_ctx, type_idx);
#endif
if (!check_type_index(module, type_idx, error_buf,
if (!check_type_index(module, module->type_count,
type_idx, error_buf,
error_buf_size)) {
goto fail;
}
@ -13374,7 +13455,8 @@ re_scan:
#if WASM_ENABLE_FAST_INTERP != 0
emit_uint32(loader_ctx, type_idx);
#endif
if (!check_type_index(module, type_idx, error_buf,
if (!check_type_index(module, module->type_count,
type_idx, error_buf,
error_buf_size)) {
goto fail;
}
@ -13787,7 +13869,8 @@ re_scan:
emit_uint32(loader_ctx, (uint32)heap_type);
#endif
if (heap_type >= 0) {
if (!check_type_index(module, heap_type, error_buf,
if (!check_type_index(module, module->type_count,
heap_type, error_buf,
error_buf_size)) {
goto fail;
}

View File

@ -6226,8 +6226,8 @@ re_scan:
bh_memcpy_s(loader_ctx->frame_offset, size,
block->param_frame_offsets, size);
loader_ctx->frame_offset += (size / sizeof(int16));
loader_ctx->dynamic_offset = block->start_dynamic_offset;
}
loader_ctx->dynamic_offset = block->start_dynamic_offset;
#endif
break;

View File

@ -4404,6 +4404,22 @@ llvm_jit_obj_is_instance_of(WASMModuleInstance *module_inst,
return wasm_obj_is_instance_of(gc_obj, type_index, types, type_count);
}
bool
llvm_jit_func_type_is_super_of(WASMModuleInstance *module_inst,
uint32 type_idx1, uint32 type_idx2)
{
WASMModule *module = module_inst->module;
WASMType **types = module->types;
if (type_idx1 == type_idx2)
return true;
bh_assert(types[type_idx1]->type_flag == WASM_TYPE_FUNC);
bh_assert(types[type_idx2]->type_flag == WASM_TYPE_FUNC);
return wasm_func_type_is_super_of((WASMFuncType *)types[type_idx1],
(WASMFuncType *)types[type_idx2]);
}
WASMRttTypeRef
llvm_jit_rtt_type_new(WASMModuleInstance *module_inst, uint32 type_index)
{

View File

@ -811,6 +811,11 @@ bool
llvm_jit_obj_is_instance_of(WASMModuleInstance *module_inst,
WASMObjectRef gc_obj, uint32 type_index);
/* Whether func type1 is one of super types of func type2 */
bool
llvm_jit_func_type_is_super_of(WASMModuleInstance *module_inst,
uint32 type_idx1, uint32 type_idx2);
WASMRttTypeRef
llvm_jit_rtt_type_new(WASMModuleInstance *module_inst, uint32 type_index);

View File

@ -95,7 +95,7 @@ def ignore_the_case(
return True
if gc_flag:
if case_name in ["type-equivalence", "type-rec", "array_init_elem", "array_init_data"]:
if case_name in ["array_init_elem", "array_init_data"]:
return True
if sgx_flag:

View File

@ -9,78 +9,6 @@ index 335496f0..5b975028 100644
- "integer representation too long"
+ "invalid type flag" ;; In GC extension, the first byte in rectype define is just one byte, not LEB128 encoded.
)
diff --git a/test/core/binary.wast b/test/core/binary.wast
index 1661a1c6..84c716b9 100644
--- a/test/core/binary.wast
+++ b/test/core/binary.wast
@@ -1082,7 +1082,7 @@
)
;; 1 br_table target declared, 2 given
-(assert_malformed
+(;assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01" ;; type section
@@ -1132,3 +1132,4 @@
)
"unexpected content after last section"
)
+;)
diff --git a/test/core/data.wast b/test/core/data.wast
index a5c87fbb..6f948bae 100644
--- a/test/core/data.wast
+++ b/test/core/data.wast
@@ -306,9 +306,10 @@
"\02\01\41\00\0b" ;; active data segment 0 for memory 1
"\00" ;; empty vec(byte)
)
- "unknown memory 1"
+ "unknown memory"
)
+(; not supported by wat2wasm
;; Data segment with memory index 0 (no memory section)
(assert_invalid
(module binary
@@ -317,7 +318,7 @@
"\00\41\00\0b" ;; active data segment 0 for memory 0
"\00" ;; empty vec(byte)
)
- "unknown memory 0"
+ "unknown memory"
)
;; Data segment with memory index 1 (no memory section)
@@ -328,7 +329,7 @@
"\02\01\41\00\0b" ;; active data segment 0 for memory 1
"\00" ;; empty vec(byte)
)
- "unknown memory 1"
+ "unknown memory"
)
;; Data segment with memory index 1 and vec(byte) as above,
@@ -348,7 +349,7 @@
"\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f"
"\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d"
)
- "unknown memory 1"
+ "unknown memory"
)
;; Data segment with memory index 1 and specially crafted vec(byte) after.
@@ -368,8 +369,9 @@
"\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f"
"\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d"
)
- "unknown memory 1"
+ "unknown memory"
)
+;)
;; Invalid offsets
diff --git a/test/core/elem.wast b/test/core/elem.wast
index df1610f6..32c1d8b3 100644
--- a/test/core/elem.wast
@ -268,196 +196,11 @@ index 00000000..32650644
+ )
+ "unsupported initializer expression for table"
+)
diff --git a/test/core/gc/ref_test.wast b/test/core/gc/ref_test.wast
index 590b81b8..e0aa49ed 100644
--- a/test/core/gc/ref_test.wast
+++ b/test/core/gc/ref_test.wast
@@ -310,15 +310,16 @@
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 11)))))
(br_if $l (i32.eqz (ref.test (ref $t0) (table.get (i32.const 12)))))
- (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 1)))))
- (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 2)))))
+ ;; Must have explicit sub relationship
+ ;; (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 1)))))
+ ;; (br_if $l (i32.eqz (ref.test (ref $t1') (table.get (i32.const 2)))))
- (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 11)))))
- (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 12)))))
+ ;; (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 11)))))
+ ;; (br_if $l (i32.eqz (ref.test (ref $t1) (table.get (i32.const 12)))))
- (br_if $l (i32.eqz (ref.test (ref $t2') (table.get (i32.const 2)))))
+ ;; (br_if $l (i32.eqz (ref.test (ref $t2') (table.get (i32.const 2)))))
- (br_if $l (i32.eqz (ref.test (ref $t2) (table.get (i32.const 12)))))
+ ;; (br_if $l (i32.eqz (ref.test (ref $t2) (table.get (i32.const 12)))))
(return)
)
diff --git a/test/core/gc/type-subtyping.wast b/test/core/gc/type-subtyping.wast
index a9022fc3..4e22e91b 100644
index a9022fc3..4aa36e2a 100644
--- a/test/core/gc/type-subtyping.wast
+++ b/test/core/gc/type-subtyping.wast
@@ -112,6 +112,8 @@
)
)
+;; don't support recursive type equality and subtype check
+(;
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
@@ -135,6 +137,7 @@
(func $g (type $g2))
(global (ref $g1) (ref.func $g))
)
+;)
(assert_invalid
(module
@@ -156,6 +159,8 @@
(global (ref $f1) (ref.func $g))
)
+;; don't support recursive type equality and subtype check
+(;
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
@@ -201,6 +206,7 @@
(global (ref $g12) (ref.func $g12))
(global (ref $g22) (ref.func $g12))
)
+;)
(assert_invalid
(module
@@ -226,6 +232,8 @@
;; Runtime types
+;; don't support recursive type equality and subtype check
+(;
(module
(type $t0 (sub (func (result (ref null func)))))
(rec (type $t1 (sub $t0 (func (result (ref null $t1))))))
@@ -286,6 +294,7 @@
(assert_trap (invoke "fail4") "cast")
(assert_trap (invoke "fail5") "cast")
(assert_trap (invoke "fail6") "cast")
+;)
(module
(type $t1 (sub (func)))
@@ -316,7 +325,8 @@
(assert_trap (invoke "fail3") "cast")
(assert_trap (invoke "fail4") "cast")
-
+;; don't support recursive type equality and subtype check
+(;
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
(rec (type $f2 (sub (func))) (type (struct (field (ref $f2)))))
@@ -346,6 +356,7 @@
)
)
(assert_return (invoke "run") (i32.const 1))
+;)
(module
(rec (type $f1 (sub (func))) (type (struct (field (ref $f1)))))
@@ -370,6 +381,8 @@
)
(assert_return (invoke "run") (i32.const 1))
+;; don't support recursive type equality and subtype check
+(;
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
@@ -390,7 +403,6 @@
)
(assert_return (invoke "run") (i32.const 1) (i32.const 1))
-
(module
(rec (type $f11 (sub (func (result (ref func))))) (type $f12 (sub $f11 (func (result (ref $f11))))))
(rec (type $f21 (sub (func (result (ref func))))) (type $f22 (sub $f21 (func (result (ref $f21))))))
@@ -429,7 +441,9 @@
(i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1)
(i32.const 1) (i32.const 1) (i32.const 1) (i32.const 1)
)
+;)
+(; we use normalized function type index
(module
(rec (type $f11 (sub (func))) (type $f12 (sub $f11 (func))))
(rec (type $f21 (sub (func))) (type $f22 (sub $f11 (func))))
@@ -439,6 +453,7 @@
)
)
(assert_return (invoke "run") (i32.const 0))
+;)
(module
(rec (type $f01 (sub (func))) (type $f02 (sub $f01 (func))))
@@ -547,15 +562,15 @@
(func (import "M3" "g") (type $g1))
)
-(module
- (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
- (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
- (rec
- (type $g2 (sub $f2 (func)))
- (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
- )
- (func (export "g") (type $g2))
-)
+;; (module
+;; (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
+;; (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
+;; (rec
+;; (type $g2 (sub $f2 (func)))
+;; (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
+;; )
+;; (func (export "g") (type $g2))
+;; )
(register "M4")
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
@@ -597,17 +612,17 @@
(func (import "M6" "g") (type $f1))
)
-(module
- (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
- (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
- (rec
- (type $g2 (sub $f2 (func)))
- (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
- )
- (rec (type $h (sub $g2 (func))) (type (struct)))
- (func (export "h") (type $h))
-)
-(register "M7")
+;; (module
+;; (rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
+;; (rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
+;; (rec
+;; (type $g2 (sub $f2 (func)))
+;; (type (sub $s2 (struct (field (ref $f1) (ref $f2) (ref $f1) (ref $f2) (ref $g2)))))
+;; )
+;; (rec (type $h (sub $g2 (func))) (type (struct)))
+;; (func (export "h") (type $h))
+;; )
+;; (register "M7")
(module
(rec (type $f1 (sub (func))) (type $s1 (sub (struct (field (ref $f1))))))
(rec (type $f2 (sub (func))) (type $s2 (sub (struct (field (ref $f2))))))
@@ -740,7 +755,7 @@
@@ -740,7 +740,7 @@
"sub type"
)
@ -466,7 +209,7 @@ index a9022fc3..4e22e91b 100644
(module
(type $f0 (sub (func (param i32) (result i32))))
(type $s0 (sub $f0 (struct)))
@@ -764,7 +779,7 @@
@@ -764,7 +764,7 @@
"sub type"
)
@ -475,7 +218,7 @@ index a9022fc3..4e22e91b 100644
(module
(type $s0 (sub (struct)))
(type $f0 (sub $s0 (func (param i32) (result i32))))
@@ -772,7 +787,7 @@
@@ -772,7 +772,7 @@
"sub type"
)
@ -1262,29 +1005,3 @@ index 0b2d26f7..bdab6a01 100644
(table $t0 30 30 funcref)
(table $t1 30 30 funcref)
(elem (table $t1) (i32.const 2) func 3 1 4 1)
diff --git a/test/core/unreached-valid.wast b/test/core/unreached-valid.wast
index f3feb0f3..d8ef8743 100644
--- a/test/core/unreached-valid.wast
+++ b/test/core/unreached-valid.wast
@@ -60,7 +60,7 @@
;; Validation after unreachable
-(module
+(;module
(func (export "meet-bottom")
(block (result f64)
(block (result f32)
@@ -76,7 +76,6 @@
(assert_trap (invoke "meet-bottom") "unreachable")
-
;; Bottom heap type
(module
@@ -106,3 +105,4 @@
(unreachable)
)
)
+;)