From e521d9991dbb1dc1b1fd01471c2df817b2af2df2 Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Fri, 24 Jun 2022 03:30:03 +0800 Subject: [PATCH] Implement GC opcode fund.bind --- core/iwasm/common/gc/gc_object.c | 36 ++-- core/iwasm/common/gc/gc_object.h | 38 +++- core/iwasm/common/gc/gc_type.c | 29 +++ core/iwasm/common/gc/gc_type.h | 10 + core/iwasm/interpreter/wasm.h | 2 - core/iwasm/interpreter/wasm_interp_classic.c | 149 ++++++++++++++- core/iwasm/interpreter/wasm_interp_fast.c | 185 ++++++++++++++++++- core/iwasm/interpreter/wasm_loader.c | 144 +++++++++++++-- core/iwasm/interpreter/wasm_runtime.c | 38 ++-- core/iwasm/interpreter/wasm_runtime.h | 4 +- 10 files changed, 562 insertions(+), 73 deletions(-) diff --git a/core/iwasm/common/gc/gc_object.c b/core/iwasm/common/gc/gc_object.c index c4f01e544..cf16852d9 100644 --- a/core/iwasm/common/gc/gc_object.c +++ b/core/iwasm/common/gc/gc_object.c @@ -289,36 +289,41 @@ wasm_array_obj_get_elem(WASMArrayObjectRef array_obj, uint32 elem_idx, } WASMFuncObjectRef -wasm_func_obj_new(void *heap_handle, WASMRttObjectRef rtt_obj, uint32 func_idx) +wasm_func_obj_new(void *heap_handle, WASMRttObjectRef rtt_obj, + uint32 func_idx_bound, uint32 param_count_bound) { WASMFuncObjectRef func_obj; - WASMFuncType *func_type; uint64 total_size; bh_assert(rtt_obj->type_flag == WASM_TYPE_FUNC); - func_type = (WASMFuncType *)rtt_obj->defined_type; - - total_size = - offsetof(WASMFuncObject, param_data) + func_type->total_param_size; + total_size = offsetof(WASMFuncObject, params_bound) + + (uint64)sizeof(WASMValue) * param_count_bound; if (!(func_obj = gc_obj_malloc(heap_handle, total_size))) { return NULL; } func_obj->header = (WASMObjectHeader)rtt_obj; - func_obj->func_idx = func_idx; + func_obj->func_idx_bound = func_idx_bound; + func_obj->param_count_bound = param_count_bound; return func_obj; } void -wasm_func_obj_set_param(WASMFuncObjectRef func_obj, uint32 param_idx, - WASMValue *value) -{} +wasm_func_obj_set_param_bound(WASMFuncObjectRef func_obj, uint32 param_idx, + WASMValue *value) +{ + bh_assert(param_idx < func_obj->param_count_bound); + bh_memcpy_s(func_obj->params_bound + param_idx, sizeof(WASMValue), value, + sizeof(WASMValue)); +} WASMValue * -wasm_func_obj_get_param(const WASMFuncObjectRef func_obj, uint32 param_idx) +wasm_func_obj_get_param_bound(const WASMFuncObjectRef func_obj, + uint32 param_idx) { - return NULL; + bh_assert(param_idx < func_obj->param_count_bound); + return func_obj->params_bound + param_idx; } WASMExternrefObjectRef @@ -386,14 +391,17 @@ wasm_object_get_ref_list(WASMObjectRef obj, bool *p_is_compact_mode, rtt_obj = (WASMRttObjectRef)wasm_object_header(obj); - if ((obj->header & WASM_OBJ_EXTERNREF_OBJ_FLAG) - || rtt_obj->defined_type->type_flag == WASM_TYPE_FUNC) { + if (obj->header & WASM_OBJ_EXTERNREF_OBJ_FLAG) { /* externref object or function object */ *p_is_compact_mode = false; *p_ref_num = 0; *p_ref_list = NULL; return true; } + else if (rtt_obj->defined_type->type_flag == WASM_TYPE_FUNC) { + /* TODO */ + return false; + } else if (rtt_obj->defined_type->type_flag == WASM_TYPE_STRUCT) { /* struct object */ WASMStructType *type = (WASMStructType *)rtt_obj->defined_type; diff --git a/core/iwasm/common/gc/gc_object.h b/core/iwasm/common/gc/gc_object.h index e354b1809..c0e767c23 100644 --- a/core/iwasm/common/gc/gc_object.h +++ b/core/iwasm/common/gc/gc_object.h @@ -93,10 +93,11 @@ typedef struct WASMArrayObject { /* Representation of WASM function objects */ typedef struct WASMFuncObject { - /* must be pointer of WASMRttObject of array type */ + /* must be pointer of WASMRttObject of func type */ WASMObjectHeader header; - uint32 func_idx; - uint8 *param_data[1]; + uint32 func_idx_bound; + uint32 param_count_bound; + WASMValue params_bound[1]; } WASMFuncObject, *WASMFuncObjectRef; inline static WASMObjectHeader @@ -223,14 +224,37 @@ wasm_array_obj_elem_addr(const WASMArrayObjectRef array_obj, uint32 elem_idx) } WASMFuncObjectRef -wasm_func_obj_new(void *heap_handle, WASMRttObjectRef rtt_obj, uint32 func_idx); +wasm_func_obj_new(void *heap_handle, WASMRttObjectRef rtt_obj, + uint32 func_idx_bound, uint32 param_count_bound); void -wasm_func_obj_set_param(WASMFuncObjectRef func_obj, uint32 param_idx, - WASMValue *value); +wasm_func_obj_set_param_bound(WASMFuncObjectRef func_obj, uint32 param_idx, + WASMValue *value); WASMValue * -wasm_func_obj_get_param(const WASMFuncObjectRef func_obj, uint32 param_idx); +wasm_func_obj_get_param_bound(const WASMFuncObjectRef func_obj, + uint32 param_idx); + +inline static uint32 +wasm_func_obj_get_func_idx_bound(const WASMFuncObjectRef func_obj) +{ + return func_obj->func_idx_bound; +} + +inline static uint32 +wasm_func_obj_get_param_count_bound(const WASMFuncObjectRef func_obj) +{ + return func_obj->param_count_bound; +} + +inline static WASMFuncType * +wasm_func_obj_get_func_type(const WASMFuncObjectRef func_obj) +{ + WASMRttObjectRef rtt_obj = + (WASMRttObjectRef)wasm_object_header((WASMObjectRef)func_obj); + bh_assert(rtt_obj->type_flag == WASM_TYPE_FUNC); + return (WASMFuncType *)rtt_obj->defined_type; +} WASMExternrefObjectRef wasm_externref_obj_new(void *heap_handle, void *foreign_obj); diff --git a/core/iwasm/common/gc/gc_type.c b/core/iwasm/common/gc/gc_type.c index bc553d9d4..b121f0b2b 100644 --- a/core/iwasm/common/gc/gc_type.c +++ b/core/iwasm/common/gc/gc_type.c @@ -189,6 +189,35 @@ wasm_dump_array_type(const WASMArrayType *type) os_printf("\n"); } +bool +wasm_value_types_is_subtype_of(const uint8 *types1, + const WASMRefTypeMap *ref_type_maps1, + const uint8 *types2, + const WASMRefTypeMap *ref_type_maps2, + uint32 value_type_count, + const WASMTypePtr *types, uint32 type_count) +{ + uint32 i; + WASMRefType *ref_type1, *ref_type2; + + for (i = 0; i < value_type_count; i++) { + ref_type1 = ref_type2 = NULL; + if (wasm_is_type_multi_byte_type(types1[i])) { + ref_type1 = ref_type_maps1->ref_type; + ref_type_maps1++; + } + if (wasm_is_type_multi_byte_type(types2[i])) { + ref_type2 = ref_type_maps2->ref_type; + ref_type_maps2++; + } + if (!wasm_reftype_is_subtype_of(types1[i], ref_type1, types2[i], + ref_type2, types, type_count)) { + return false; + } + } + return true; +} + typedef struct TypeIdxNode { uint32 type_idx1; uint32 type_idx2; diff --git a/core/iwasm/common/gc/gc_type.h b/core/iwasm/common/gc/gc_type.h index d4198cb57..988041480 100644 --- a/core/iwasm/common/gc/gc_type.h +++ b/core/iwasm/common/gc/gc_type.h @@ -26,6 +26,16 @@ wasm_dump_array_type(const WASMArrayType *type); /* Operations of function type */ +/* Whether a group of value types is subtype of + another group of value types */ +bool +wasm_value_types_is_subtype_of(const uint8 *types1, + const WASMRefTypeMap *ref_type_maps1, + const uint8 *types2, + const WASMRefTypeMap *ref_type_maps2, + uint32 value_type_count, + const WASMTypePtr *types, uint32 type_count); + /* Whether two function types are equal */ bool wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2, diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index 6bc5da524..a233b698c 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -338,8 +338,6 @@ typedef struct WASMFuncType { uint16 ret_cell_num; #if WASM_ENABLE_GC != 0 - uint16 *param_offsets; - uint16 total_param_size; uint16 ref_type_map_count; WASMRefTypeMap *ref_type_maps; WASMRefTypeMap *result_ref_type_maps; diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index d61afb6cf..b4ca66916 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -1154,6 +1154,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_GC != 0 register uint8 *frame_ref = NULL; /* cache of frame->ref */ uint8 *frame_ref_tmp; + bool is_return_call_ref = false; #endif WASMBranchBlock *frame_csp = NULL; BlockAddr *cache_items; @@ -1518,7 +1519,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, wasm_set_exception(module, "uninitialized element"); goto got_exception; } - fidx = func_obj->func_idx; + fidx = wasm_func_obj_get_func_idx_bound(func_obj); #endif /* clang-format on */ @@ -1535,21 +1536,40 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* always call module own functions */ cur_func = module->functions + fidx; + /* clang-format off */ +#if WASM_ENABLE_GC == 0 if (cur_func->is_import_func) cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; +#else + cur_func_type = wasm_func_obj_get_func_type(func_obj); +#endif + /* clang-format on */ + if (!wasm_type_equal( (WASMType *)cur_type, (WASMType *)cur_func_type, module->module->types, module->module->type_count)) { wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } + + /* clang-format off */ +#if WASM_ENABLE_GC == 0 #if WASM_ENABLE_TAIL_CALL != 0 if (opcode == WASM_OP_RETURN_CALL_INDIRECT) goto call_func_from_return_call; #endif goto call_func_from_interp; +#else + is_return_call_ref = false; +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_RETURN_CALL_INDIRECT) + is_return_call_ref = true; +#endif + goto call_func_from_call_ref; +#endif + /* clang-format on */ } /* parametric instructions */ @@ -1700,7 +1720,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #else SYNC_ALL_TO_FRAME(); if (!(gc_obj = wasm_create_func_obj(module, func_idx, true, - NULL, 0))) { + NULL, true, NULL, 0))) { goto got_exception; } PUSH_REF(gc_obj); @@ -1721,8 +1741,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - cur_func = module->functions + func_obj->func_idx; - goto call_func_from_interp; + is_return_call_ref = false; + goto call_func_from_call_ref; } HANDLE_OP(WASM_OP_RETURN_CALL_REF) @@ -1736,11 +1756,71 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - cur_func = module->functions + func_obj->func_idx; - goto call_func_from_return_call; + is_return_call_ref = true; + goto call_func_from_call_ref; } HANDLE_OP(WASM_OP_FUNC_BIND) + { + WASMFuncObjectRef func_obj_old; + WASMFuncType *func_type_src, *func_type_dst; + WASMFunctionInstance *func_inst; + WASMValue *value_bound, value; + int32 param_count_bound, param_count_to_bind, func_idx_bound; + int32 j; + + read_leb_uint32(frame_ip, frame_ip_end, type_index); + func_type_dst = + (WASMFuncType *)module->module->types[type_index]; + + func_obj_old = POP_REF(); + if (!func_obj_old) { + wasm_set_exception(module, "null function object"); + goto got_exception; + } + + func_idx_bound = wasm_func_obj_get_func_idx_bound(func_obj_old); + func_inst = &module->functions[func_idx_bound]; + func_type_src = func_inst->is_import_func + ? func_inst->u.func_import->func_type + : func_inst->u.func->func_type; + + /* create func object */ + param_count_to_bind = + func_type_src->param_count - func_type_dst->param_count; + if (!(func_obj = + wasm_create_func_obj(module, func_idx_bound, false, + func_type_dst, true, NULL, 0))) { + goto got_exception; + } + + param_count_bound = + wasm_func_obj_get_param_count_bound(func_obj_old); + for (j = 0; j < (int32)param_count_bound; j++) { + value_bound = + wasm_func_obj_get_param_bound(func_obj_old, j); + wasm_func_obj_set_param_bound(func_obj, j, value_bound); + } + + /* pop bound arguments */ + for (j = param_count_to_bind - 1; j >= param_count_bound; j--) { + if (wasm_is_type_multi_byte_type(func_type_src->types[j])) { + value.gc_obj = POP_REF(); + } + else if (func_type_src->types[j] == VALUE_TYPE_I32 + || func_type_src->types[j] == VALUE_TYPE_F32) { + value.i32 = POP_I32(); + } + else { + value.i64 = POP_I64(); + } + wasm_func_obj_set_param_bound(func_obj, j, &value); + } + + PUSH_REF(func_obj); + HANDLE_OP_END(); + } + HANDLE_OP(WASM_OP_LET) { wasm_set_exception(module, "unsupported opcode"); @@ -4018,7 +4098,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (func_indexes[i] != UINT32_MAX) { if (!(func_obj = wasm_create_func_obj( module, func_indexes[i], true, NULL, - 0))) { + true, NULL, 0))) { goto got_exception; } table_elems[i] = func_obj; @@ -4592,7 +4672,56 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, FETCH_OPCODE_AND_DISPATCH(); #endif -#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 +#if WASM_ENABLE_GC != 0 + call_func_from_call_ref: + { + WASMInterpFrame *outs_area; + WASMFuncType *func_type, *cur_func_type; + WASMValue *value; + uint32 *outs_area_lp; + uint32 param_count_bound, j; + + cur_func = + module->functions + wasm_func_obj_get_func_idx_bound(func_obj); + cur_func_type = (cur_func->is_import_func) + ? cur_func->u.func_import->func_type + : cur_func->u.func->func_type; + + if (!is_return_call_ref) { + outs_area = wasm_exec_env_wasm_stack_top(exec_env); + outs_area_lp = outs_area->lp; + } + else { + outs_area_lp = frame->lp; + } + + param_count_bound = wasm_func_obj_get_param_count_bound(func_obj); + for (j = 0; j < param_count_bound; j++) { + value = wasm_func_obj_get_param_bound(func_obj, j); + cell_num = wasm_value_type_cell_num(cur_func_type->types[j]); + bh_memcpy_s(outs_area_lp, cell_num * 4, value, cell_num * 4); + outs_area_lp += cell_num; + } + + func_type = wasm_func_obj_get_func_type(func_obj); + if (func_type->param_cell_num > 0) { + POP(func_type->param_cell_num); + word_copy(outs_area_lp, frame_sp, func_type->param_cell_num); + } + + if (!is_return_call_ref) { + SYNC_ALL_TO_FRAME(); + prev_frame = frame; + } + else { + FREE_FRAME(exec_env, frame); + wasm_exec_env_set_cur_frame(exec_env, + (WASMRuntimeFrame *)prev_frame); + } + goto call_func_from_entry; + } +#endif +#if WASM_ENABLE_TAIL_CALL != 0 call_func_from_return_call: { POP(cur_func->param_cell_num); @@ -4608,11 +4737,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { /* Only do the copy when it's called from interpreter. */ WASMInterpFrame *outs_area = wasm_exec_env_wasm_stack_top(exec_env); - POP(cur_func->param_cell_num); - SYNC_ALL_TO_FRAME(); if (cur_func->param_cell_num > 0) { + POP(cur_func->param_cell_num); word_copy(outs_area->lp, frame_sp, cur_func->param_cell_num); } + SYNC_ALL_TO_FRAME(); prev_frame = frame; } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 16c796c5f..ff7a8856f 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -1188,6 +1188,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_GC != 0 register uint8 *frame_ref = NULL; /* cache of frame->ref */ int16 opnd_off; + bool is_return_call_ref = false; #endif uint8 *frame_ip_end = frame_ip + 1; uint32 cond, count, fidx, tidx, frame_size = 0; @@ -1403,7 +1404,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, wasm_set_exception(module, "uninitialized element"); goto got_exception; } - fidx = func_obj->func_idx; + fidx = wasm_func_obj_get_func_idx_bound(func_obj); #endif /* clang-format on */ @@ -1420,21 +1421,40 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* always call module own functions */ cur_func = module->functions + fidx; + /* clang-format off */ +#if WASM_ENABLE_GC == 0 if (cur_func->is_import_func) cur_func_type = cur_func->u.func_import->func_type; else cur_func_type = cur_func->u.func->func_type; +#else + cur_func_type = wasm_func_obj_get_func_type(func_obj); +#endif + /* clang-format on */ + if (!wasm_type_equal( (WASMType *)cur_type, (WASMType *)cur_func_type, module->module->types, module->module->type_count)) { wasm_set_exception(module, "indirect call type mismatch"); goto got_exception; } + + /* clang-format off */ +#if WASM_ENABLE_GC == 0 #if WASM_ENABLE_TAIL_CALL != 0 if (opcode == WASM_OP_RETURN_CALL_INDIRECT) goto call_func_from_return_call; #endif goto call_func_from_interp; +#else + is_return_call_ref = false; +#if WASM_ENABLE_TAIL_CALL != 0 + if (opcode == WASM_OP_RETURN_CALL_INDIRECT) + is_return_call_ref = true; +#endif + goto call_func_from_call_ref; +#endif + /* clang-format on */ } /* parametric instructions */ @@ -1582,7 +1602,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, PUSH_I32(func_idx); #else if (!(gc_obj = wasm_create_func_obj(module, func_idx, true, - NULL, 0))) { + NULL, true, NULL, 0))) { goto got_exception; } PUSH_REF(gc_obj); @@ -1603,8 +1623,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - cur_func = module->functions + func_obj->func_idx; - goto call_func_from_interp; + is_return_call_ref = false; + goto call_func_from_call_ref; } HANDLE_OP(WASM_OP_RETURN_CALL_REF) @@ -1618,11 +1638,70 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - cur_func = module->functions + func_obj->func_idx; - goto call_func_from_return_call; + is_return_call_ref = true; + goto call_func_from_call_ref; } HANDLE_OP(WASM_OP_FUNC_BIND) + { + WASMFuncObjectRef func_obj_old; + WASMFuncType *func_type_src, *func_type_dst; + WASMFunctionInstance *func_inst; + WASMValue *value_bound, value; + int32 param_count_bound, param_count_to_bind, func_idx_bound; + int32 j; + + type_idx = read_uint32(frame_ip); + func_type_dst = (WASMFuncType *)module->module->types[type_idx]; + + func_obj_old = POP_REF(); + if (!func_obj_old) { + wasm_set_exception(module, "null function object"); + goto got_exception; + } + + func_idx_bound = wasm_func_obj_get_func_idx_bound(func_obj_old); + func_inst = &module->functions[func_idx_bound]; + func_type_src = func_inst->is_import_func + ? func_inst->u.func_import->func_type + : func_inst->u.func->func_type; + + /* create func object */ + param_count_to_bind = + func_type_src->param_count - func_type_dst->param_count; + if (!(func_obj = + wasm_create_func_obj(module, func_idx_bound, false, + func_type_dst, true, NULL, 0))) { + goto got_exception; + } + + param_count_bound = + wasm_func_obj_get_param_count_bound(func_obj_old); + for (j = 0; j < (int32)param_count_bound; j++) { + value_bound = + wasm_func_obj_get_param_bound(func_obj_old, j); + wasm_func_obj_set_param_bound(func_obj, j, value_bound); + } + + /* pop bound arguments */ + for (j = param_count_to_bind - 1; j >= param_count_bound; j--) { + if (wasm_is_type_multi_byte_type(func_type_src->types[j])) { + value.gc_obj = POP_REF(); + } + else if (func_type_src->types[j] == VALUE_TYPE_I32 + || func_type_src->types[j] == VALUE_TYPE_F32) { + value.i32 = POP_I32(); + } + else { + value.i64 = POP_I64(); + } + wasm_func_obj_set_param_bound(func_obj, j, &value); + } + + PUSH_REF(func_obj); + HANDLE_OP_END(); + } + HANDLE_OP(WASM_OP_LET) { wasm_set_exception(module, "unsupported opcode"); @@ -2352,7 +2431,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, *(int32 *)global_addr = frame_lp[addr1]; else PUT_REF_TO_ADDR((uint32 *)global_addr, - GET_REF_FROM_ADDR(frame_lp + addr_ret)); + GET_REF_FROM_ADDR(frame_lp + addr1)); #endif /* clang-format on */ HANDLE_OP_END(); @@ -3906,7 +3985,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (func_indexes[i] != UINT32_MAX) { if (!(func_obj = wasm_create_func_obj( module, func_indexes[i], true, NULL, - 0))) { + true, NULL, 0))) { goto got_exception; } table_elems[i] = func_obj; @@ -4503,7 +4582,95 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, FETCH_OPCODE_AND_DISPATCH(); #endif -#if WASM_ENABLE_TAIL_CALL != 0 || WASM_ENABLE_GC != 0 +#if WASM_ENABLE_GC != 0 + call_func_from_call_ref: + { + WASMInterpFrame *outs_area; + WASMValue *value; + uint32 *lp_base = NULL, *lp = NULL; + uint32 *outs_area_lp; + uint32 param_count_bound, i; + + cur_func = + module->functions + wasm_func_obj_get_func_idx_bound(func_obj); + + /* Allocate temporary memory for local variables */ + if (cur_func->param_cell_num > 0 + && !(lp_base = lp = wasm_runtime_malloc( + cur_func->param_cell_num * (uint32)sizeof(uint32)))) { + wasm_set_exception(module, "allocate memory failed"); + goto got_exception; + } + + /* Copy bound parameters from function object */ + param_count_bound = wasm_func_obj_get_param_count_bound(func_obj); + for (i = 0; i < param_count_bound; i++) { + value = wasm_func_obj_get_param_bound(func_obj, i); + if (cur_func->param_types[i] == VALUE_TYPE_I64 + || cur_func->param_types[i] == VALUE_TYPE_F64) { + PUT_I64_TO_ADDR(lp, value->i64); + lp += 2; + } + else { + *lp++ = value->i32; + } + } + + /* Copy left parameters from stack */ + for (; i < cur_func->param_count; i++) { + if (cur_func->param_types[i] == VALUE_TYPE_I64 + || cur_func->param_types[i] == VALUE_TYPE_F64) { + PUT_I64_TO_ADDR( + lp, GET_OPERAND(uint64, I64, + 2 * (cur_func->param_count - i - 1))); + lp += 2; + } + else { + *lp++ = GET_OPERAND(uint32, I32, + (2 * (cur_func->param_count - i - 1))); + } + } + frame_ip += (cur_func->param_count - param_count_bound) * 2; + + if (!is_return_call_ref) + outs_area = wasm_exec_env_wasm_stack_top(exec_env); + else + outs_area = frame; + outs_area_lp = outs_area->operand + cur_func->const_cell_num; + + /* Copy local variables from temporary memory */ + if (lp - lp_base > 0) + word_copy(outs_area_lp, lp_base, lp - lp_base); + + if (lp_base) + wasm_runtime_free(lp_base); + + if (!is_return_call_ref) { + if (cur_func->ret_cell_num != 0) { + /* Get the first return value's offset. Since loader emit + * all return values' offset so we must skip remain return + * values' offsets. + */ + WASMFuncType *func_type; + if (cur_func->is_import_func) + func_type = cur_func->u.func_import->func_type; + else + func_type = cur_func->u.func->func_type; + frame->ret_offset = GET_OFFSET(); + frame_ip += 2 * (func_type->result_count - 1); + } + SYNC_ALL_TO_FRAME(); + prev_frame = frame; + } + else { + FREE_FRAME(exec_env, frame); + wasm_exec_env_set_cur_frame(exec_env, + (WASMRuntimeFrame *)prev_frame); + } + goto call_func_from_entry; + } +#endif +#if WASM_ENABLE_TAIL_CALL != 0 call_func_from_return_call: { uint32 *lp_base = NULL, *lp = NULL; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index e1c848b89..a4bf60dbf 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1053,8 +1053,7 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, uint32 param_count, result_count, i, j = 0; uint32 param_cell_num, ret_cell_num; uint32 ref_type_map_count = 0, result_ref_type_map_count = 0; - uint64 total_size, param_offset; - uint16 offset; + uint64 total_size; bool need_ref_type_map; WASMRefType ref_type; WASMFuncType *type = NULL; @@ -1094,8 +1093,6 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, total_size = offsetof(WASMFuncType, types) + sizeof(uint8) * (uint64)(param_count + result_count); - total_size = param_offset = align_uint(total_size, 4); - total_size += sizeof(uint16) * param_count; if (!(type = loader_malloc(total_size, error_buf, error_buf_size))) { return false; } @@ -1111,13 +1108,11 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, type->type_idx = type_idx; type->param_count = param_count; type->result_count = result_count; - type->param_offsets = (uint16 *)((uint8 *)type + (uint32)param_offset); type->ref_type_map_count = ref_type_map_count; type->result_ref_type_maps = type->ref_type_maps + ref_type_map_count - result_ref_type_map_count; type->ref_count = 1; - offset = offsetof(WASMFuncObject, param_data); 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)) { @@ -1132,10 +1127,7 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module, goto fail; } } - type->param_offsets[i] = offset; - offset += wasm_value_type_size(ref_type.ref_type); } - type->total_param_size = offset; read_leb_uint32(p, p_end, result_count); for (i = 0; i < result_count; i++) { @@ -5271,7 +5263,11 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, case WASM_OP_BR_ON_NULL: case WASM_OP_BR_ON_NON_NULL: break; + case WASM_OP_FUNC_BIND: + skip_leb_uint32(p, p_end); /* type index */ + break; + case WASM_OP_LET: set_error_buf_v(error_buf, error_buf_size, "unsupported opcode %02x", opcode); @@ -6076,16 +6072,19 @@ check_stack_push(WASMLoaderContext *ctx, uint8 type, char *error_buf, && ctx->frame_reftype_map >= ctx->frame_reftype_map_boundary) { /* Increase the frame reftype map stack */ bh_assert( - (uint32)(ctx->frame_reftype_map - ctx->frame_reftype_map_bottom) + (uint32)((ctx->frame_reftype_map - ctx->frame_reftype_map_bottom) + * sizeof(WASMRefTypeMap)) == ctx->frame_reftype_map_size); MEM_REALLOC(ctx->frame_reftype_map_bottom, ctx->frame_reftype_map_size, ctx->frame_reftype_map_size + (uint32)sizeof(WASMRefTypeMap) * 8); ctx->frame_reftype_map = - ctx->frame_reftype_map_bottom + ctx->frame_reftype_map_size; + ctx->frame_reftype_map_bottom + + ctx->frame_reftype_map_size / ((uint32)sizeof(WASMRefTypeMap)); ctx->frame_reftype_map_size += (uint32)sizeof(WASMRefTypeMap) * 8; ctx->frame_reftype_map_boundary = - ctx->frame_reftype_map_bottom + ctx->frame_reftype_map_size; + ctx->frame_reftype_map_bottom + + ctx->frame_reftype_map_size / ((uint32)sizeof(WASMRefTypeMap)); } #endif return true; @@ -6113,18 +6112,22 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf, if (ctx->frame_reftype_map >= ctx->frame_reftype_map_boundary) { /* Increase the frame reftype map stack */ - bh_assert( - (uint32)(ctx->frame_reftype_map - ctx->frame_reftype_map_bottom) - == ctx->frame_reftype_map_size); + bh_assert((uint32)((ctx->frame_reftype_map + - ctx->frame_reftype_map_bottom) + * sizeof(WASMRefTypeMap)) + == ctx->frame_reftype_map_size); MEM_REALLOC(ctx->frame_reftype_map_bottom, ctx->frame_reftype_map_size, ctx->frame_reftype_map_size + (uint32)sizeof(WASMRefTypeMap) * 8); - ctx->frame_reftype_map = - ctx->frame_reftype_map_bottom + ctx->frame_reftype_map_size; + ctx->frame_reftype_map = ctx->frame_reftype_map_bottom + + ctx->frame_reftype_map_size + / ((uint32)sizeof(WASMRefTypeMap)); ctx->frame_reftype_map_size += (uint32)sizeof(WASMRefTypeMap) * 8; ctx->frame_reftype_map_boundary = - ctx->frame_reftype_map_bottom + ctx->frame_reftype_map_size; + ctx->frame_reftype_map_bottom + + ctx->frame_reftype_map_size + / ((uint32)sizeof(WASMRefTypeMap)); } ctx->frame_reftype_map->index = ctx->stack_cell_num; @@ -10000,6 +10003,111 @@ re_scan: break; case WASM_OP_FUNC_BIND: + { + WASMFuncType *func_type_src, *func_type_dst; + WASMRefTypeMap *ref_type_map_src; + WASMRefType *ref_type_src; + uint32 type_idx_src, type_idx_dst, pop_count; + int32 j, idx; + uint8 type_src; + + /* Get the dest function type */ + read_leb_uint32(p, p_end, type_idx_dst); +#if WASM_ENABLE_FAST_INTERP != 0 + emit_uint32(loader_ctx, type_idx_dst); +#endif + if (!check_type_index(module, type_idx_dst, error_buf, + error_buf_size)) { + goto fail; + } + if (module->types[type_idx_dst]->type_flag != WASM_TYPE_FUNC) { + set_error_buf(error_buf, error_buf_size, + "unkown function type"); + goto fail; + } + func_type_dst = (WASMFuncType *)module->types[type_idx_dst]; + + /* Get the src function type */ + if (!wasm_loader_pop_nullable_typeidx(loader_ctx, &type_src, + &type_idx_src, error_buf, + error_buf_size)) { + goto fail; + } + if (!check_type_index(module, type_idx_src, error_buf, + error_buf_size)) { + goto fail; + } + if (module->types[type_idx_src]->type_flag != WASM_TYPE_FUNC) { + set_error_buf(error_buf, error_buf_size, + "unkown function type"); + goto fail; + } + + func_type_src = (WASMFuncType *)module->types[type_idx_src]; + + /* Check function types */ + if (func_type_src->param_count < func_type_dst->param_count + || func_type_src->result_count + != func_type_dst->result_count) { + set_error_buf(error_buf, error_buf_size, + "function type mismatch"); + goto fail; + } + + /* Calculate the begin ref_type_map of the non-pop arguments */ + ref_type_map_src = func_type_src->ref_type_maps; + pop_count = + func_type_src->param_count - func_type_dst->param_count; + for (i = 0; i < pop_count; i++) { + if (wasm_is_type_multi_byte_type(func_type_src->types[i])) { + ref_type_map_src++; + } + } + + /* Check the subtype relationship of parameter types + (contravariance) and the subtype relationship of + result types (covariance) */ + if (!wasm_value_types_is_subtype_of( + func_type_dst->types, func_type_dst->ref_type_maps, + func_type_src->types + pop_count, ref_type_map_src, + func_type_dst->param_count, module->types, + module->type_count) + || !wasm_value_types_is_subtype_of( + func_type_src->types + func_type_src->param_count, + func_type_src->result_ref_type_maps, + func_type_dst->types + func_type_dst->param_count, + func_type_dst->result_ref_type_maps, + func_type_dst->result_count, module->types, + module->type_count)) { + set_error_buf(error_buf, error_buf_size, + "function type mismatch"); + goto fail; + } + + /* Pop arguments */ + j = ref_type_map_src - func_type_src->ref_type_maps - 1; + for (idx = (int32)(pop_count - 1); idx >= 0; idx--) { + if (wasm_is_type_multi_byte_type( + func_type_src->types[idx])) { + ref_type_src = func_type_src->ref_type_maps[j].ref_type; + bh_memcpy_s(&wasm_ref_type, sizeof(WASMRefType), + ref_type_src, + wasm_reftype_struct_size(ref_type_src)); + j--; + } + POP_TYPE(func_type_src->types[idx]); +#if WASM_ENABLE_FAST_INTERP != 0 + POP_OFFSET_TYPE(func_type_src->types[idx]); +#endif + } + + /* PUSH (ref type_idx_dst) */ + wasm_set_refheaptype_typeidx(&wasm_ref_type.ref_ht_typeidx, + false, type_idx_dst); + PUSH_REF(wasm_ref_type.ref_type); + break; + } + case WASM_OP_LET: /* TODO */ set_error_buf_v(error_buf, error_buf_size, diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 7b0c6520b..9ba8eff38 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1166,12 +1166,15 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, #if WASM_ENABLE_GC != 0 void * wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx, - bool throw_exce, char *error_buf, uint32 error_buf_size) + bool use_same_func_type, + const WASMFuncType *func_type_to_bind, bool throw_exce, + char *error_buf, uint32 error_buf_size) { WASMRttObjectRef rtt_obj; WASMFuncObjectRef func_obj; WASMFunctionInstance *func_inst; - WASMType *func_type; + WASMFuncType *func_type; + uint32 param_count_bound = 0; if (throw_exce) { error_buf = module_inst->cur_exception; @@ -1185,18 +1188,27 @@ wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx, } func_inst = &module_inst->functions[func_idx]; - func_type = (WASMType *)(func_inst->is_import_func - ? func_inst->u.func_import->func_type - : func_inst->u.func->func_type); + func_type = func_inst->is_import_func ? func_inst->u.func_import->func_type + : func_inst->u.func->func_type; + + if (use_same_func_type) { + func_type_to_bind = func_type; + } + else { + bh_assert(func_type->param_count >= func_type_to_bind->param_count); + param_count_bound = + func_type->param_count - func_type_to_bind->param_count; + } if (!(rtt_obj = wasm_rtt_obj_new(module_inst->module->rtt_obj_set, NULL, - func_type, func_type->type_idx))) { + (WASMType *)func_type_to_bind, + func_type->type_idx))) { set_error_buf(error_buf, error_buf_size, "create rtt object failed"); return NULL; } if (!(func_obj = wasm_func_obj_new(module_inst->gc_heap_handle, rtt_obj, - func_idx))) { + func_idx, param_count_bound))) { set_error_buf(error_buf, error_buf_size, "create func object failed"); return NULL; } @@ -1472,7 +1484,8 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, if ((uint32)global->initial_value.i32 != UINT32_MAX) { if (!(func_obj = wasm_create_func_obj( module_inst, global->initial_value.i32, - false, error_buf, error_buf_size))) + true, NULL, false, error_buf, + error_buf_size))) goto fail; } STORE_PTR((void **)global_data, func_obj); @@ -1711,9 +1724,9 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, uint32 func_idx = table_seg->func_indexes[j]; /* UINT32_MAX indicates that it is an null reference */ if (func_idx != UINT32_MAX) { - if (!(func_obj = - wasm_create_func_obj(module_inst, func_idx, false, - error_buf, error_buf_size))) { + if (!(func_obj = wasm_create_func_obj( + module_inst, func_idx, true, NULL, false, error_buf, + error_buf_size))) { goto fail; } *((void **)table_data + table_seg->base_offset.u.i32 + j) = @@ -2533,7 +2546,8 @@ wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 tbl_elem_idx, #if WASM_ENABLE_GC == 0 func_idx = tbl_elem_val; #else - func_idx = ((WASMFuncObjectRef)tbl_elem_val)->func_idx; + func_idx = + wasm_func_obj_get_func_idx_bound((WASMFuncObjectRef)tbl_elem_val); #endif /** diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 6b67d9fb8..3359fe61b 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -433,7 +433,9 @@ wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx, #if WASM_ENABLE_GC != 0 void * wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx, - bool throw_exce, char *error_buf, uint32 error_buf_size); + bool use_same_func_type, + const WASMFuncType *func_type_to_bind, bool throw_exce, + char *error_buf, uint32 error_buf_size); bool wasm_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap);