Implement GC opcode fund.bind

This commit is contained in:
Wenyong Huang 2022-06-24 03:30:03 +08:00
parent 85dfa9b906
commit e521d9991d
10 changed files with 562 additions and 73 deletions

View File

@ -289,36 +289,41 @@ wasm_array_obj_get_elem(WASMArrayObjectRef array_obj, uint32 elem_idx,
} }
WASMFuncObjectRef 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; WASMFuncObjectRef func_obj;
WASMFuncType *func_type;
uint64 total_size; uint64 total_size;
bh_assert(rtt_obj->type_flag == WASM_TYPE_FUNC); bh_assert(rtt_obj->type_flag == WASM_TYPE_FUNC);
func_type = (WASMFuncType *)rtt_obj->defined_type; total_size = offsetof(WASMFuncObject, params_bound)
+ (uint64)sizeof(WASMValue) * param_count_bound;
total_size =
offsetof(WASMFuncObject, param_data) + func_type->total_param_size;
if (!(func_obj = gc_obj_malloc(heap_handle, total_size))) { if (!(func_obj = gc_obj_malloc(heap_handle, total_size))) {
return NULL; return NULL;
} }
func_obj->header = (WASMObjectHeader)rtt_obj; 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; return func_obj;
} }
void void
wasm_func_obj_set_param(WASMFuncObjectRef func_obj, uint32 param_idx, wasm_func_obj_set_param_bound(WASMFuncObjectRef func_obj, uint32 param_idx,
WASMValue *value) 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 * 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 WASMExternrefObjectRef
@ -386,14 +391,17 @@ wasm_object_get_ref_list(WASMObjectRef obj, bool *p_is_compact_mode,
rtt_obj = (WASMRttObjectRef)wasm_object_header(obj); rtt_obj = (WASMRttObjectRef)wasm_object_header(obj);
if ((obj->header & WASM_OBJ_EXTERNREF_OBJ_FLAG) if (obj->header & WASM_OBJ_EXTERNREF_OBJ_FLAG) {
|| rtt_obj->defined_type->type_flag == WASM_TYPE_FUNC) {
/* externref object or function object */ /* externref object or function object */
*p_is_compact_mode = false; *p_is_compact_mode = false;
*p_ref_num = 0; *p_ref_num = 0;
*p_ref_list = NULL; *p_ref_list = NULL;
return true; 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) { else if (rtt_obj->defined_type->type_flag == WASM_TYPE_STRUCT) {
/* struct object */ /* struct object */
WASMStructType *type = (WASMStructType *)rtt_obj->defined_type; WASMStructType *type = (WASMStructType *)rtt_obj->defined_type;

View File

@ -93,10 +93,11 @@ typedef struct WASMArrayObject {
/* Representation of WASM function objects */ /* Representation of WASM function objects */
typedef struct WASMFuncObject { typedef struct WASMFuncObject {
/* must be pointer of WASMRttObject of array type */ /* must be pointer of WASMRttObject of func type */
WASMObjectHeader header; WASMObjectHeader header;
uint32 func_idx; uint32 func_idx_bound;
uint8 *param_data[1]; uint32 param_count_bound;
WASMValue params_bound[1];
} WASMFuncObject, *WASMFuncObjectRef; } WASMFuncObject, *WASMFuncObjectRef;
inline static WASMObjectHeader inline static WASMObjectHeader
@ -223,14 +224,37 @@ wasm_array_obj_elem_addr(const WASMArrayObjectRef array_obj, uint32 elem_idx)
} }
WASMFuncObjectRef 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 void
wasm_func_obj_set_param(WASMFuncObjectRef func_obj, uint32 param_idx, wasm_func_obj_set_param_bound(WASMFuncObjectRef func_obj, uint32 param_idx,
WASMValue *value); WASMValue *value);
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);
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 WASMExternrefObjectRef
wasm_externref_obj_new(void *heap_handle, void *foreign_obj); wasm_externref_obj_new(void *heap_handle, void *foreign_obj);

View File

@ -189,6 +189,35 @@ wasm_dump_array_type(const WASMArrayType *type)
os_printf("\n"); 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 { typedef struct TypeIdxNode {
uint32 type_idx1; uint32 type_idx1;
uint32 type_idx2; uint32 type_idx2;

View File

@ -26,6 +26,16 @@ wasm_dump_array_type(const WASMArrayType *type);
/* Operations of function 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 */ /* Whether two function types are equal */
bool bool
wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2, wasm_func_type_equal(const WASMFuncType *type1, const WASMFuncType *type2,

View File

@ -338,8 +338,6 @@ typedef struct WASMFuncType {
uint16 ret_cell_num; uint16 ret_cell_num;
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
uint16 *param_offsets;
uint16 total_param_size;
uint16 ref_type_map_count; uint16 ref_type_map_count;
WASMRefTypeMap *ref_type_maps; WASMRefTypeMap *ref_type_maps;
WASMRefTypeMap *result_ref_type_maps; WASMRefTypeMap *result_ref_type_maps;

View File

@ -1154,6 +1154,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
register uint8 *frame_ref = NULL; /* cache of frame->ref */ register uint8 *frame_ref = NULL; /* cache of frame->ref */
uint8 *frame_ref_tmp; uint8 *frame_ref_tmp;
bool is_return_call_ref = false;
#endif #endif
WASMBranchBlock *frame_csp = NULL; WASMBranchBlock *frame_csp = NULL;
BlockAddr *cache_items; BlockAddr *cache_items;
@ -1518,7 +1519,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
wasm_set_exception(module, "uninitialized element"); wasm_set_exception(module, "uninitialized element");
goto got_exception; goto got_exception;
} }
fidx = func_obj->func_idx; fidx = wasm_func_obj_get_func_idx_bound(func_obj);
#endif #endif
/* clang-format on */ /* clang-format on */
@ -1535,21 +1536,40 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
/* always call module own functions */ /* always call module own functions */
cur_func = module->functions + fidx; cur_func = module->functions + fidx;
/* clang-format off */
#if WASM_ENABLE_GC == 0
if (cur_func->is_import_func) if (cur_func->is_import_func)
cur_func_type = cur_func->u.func_import->func_type; cur_func_type = cur_func->u.func_import->func_type;
else else
cur_func_type = cur_func->u.func->func_type; 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( if (!wasm_type_equal(
(WASMType *)cur_type, (WASMType *)cur_func_type, (WASMType *)cur_type, (WASMType *)cur_func_type,
module->module->types, module->module->type_count)) { module->module->types, module->module->type_count)) {
wasm_set_exception(module, "indirect call type mismatch"); wasm_set_exception(module, "indirect call type mismatch");
goto got_exception; goto got_exception;
} }
/* clang-format off */
#if WASM_ENABLE_GC == 0
#if WASM_ENABLE_TAIL_CALL != 0 #if WASM_ENABLE_TAIL_CALL != 0
if (opcode == WASM_OP_RETURN_CALL_INDIRECT) if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
goto call_func_from_return_call; goto call_func_from_return_call;
#endif #endif
goto call_func_from_interp; 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 */ /* parametric instructions */
@ -1700,7 +1720,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#else #else
SYNC_ALL_TO_FRAME(); SYNC_ALL_TO_FRAME();
if (!(gc_obj = wasm_create_func_obj(module, func_idx, true, if (!(gc_obj = wasm_create_func_obj(module, func_idx, true,
NULL, 0))) { NULL, true, NULL, 0))) {
goto got_exception; goto got_exception;
} }
PUSH_REF(gc_obj); PUSH_REF(gc_obj);
@ -1721,8 +1741,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception; goto got_exception;
} }
cur_func = module->functions + func_obj->func_idx; is_return_call_ref = false;
goto call_func_from_interp; goto call_func_from_call_ref;
} }
HANDLE_OP(WASM_OP_RETURN_CALL_REF) HANDLE_OP(WASM_OP_RETURN_CALL_REF)
@ -1736,11 +1756,71 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception; goto got_exception;
} }
cur_func = module->functions + func_obj->func_idx; is_return_call_ref = true;
goto call_func_from_return_call; goto call_func_from_call_ref;
} }
HANDLE_OP(WASM_OP_FUNC_BIND) 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) HANDLE_OP(WASM_OP_LET)
{ {
wasm_set_exception(module, "unsupported opcode"); 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_indexes[i] != UINT32_MAX) {
if (!(func_obj = wasm_create_func_obj( if (!(func_obj = wasm_create_func_obj(
module, func_indexes[i], true, NULL, module, func_indexes[i], true, NULL,
0))) { true, NULL, 0))) {
goto got_exception; goto got_exception;
} }
table_elems[i] = func_obj; table_elems[i] = func_obj;
@ -4592,7 +4672,56 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
FETCH_OPCODE_AND_DISPATCH(); FETCH_OPCODE_AND_DISPATCH();
#endif #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: call_func_from_return_call:
{ {
POP(cur_func->param_cell_num); 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. */ /* Only do the copy when it's called from interpreter. */
WASMInterpFrame *outs_area = wasm_exec_env_wasm_stack_top(exec_env); 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) { 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); word_copy(outs_area->lp, frame_sp, cur_func->param_cell_num);
} }
SYNC_ALL_TO_FRAME();
prev_frame = frame; prev_frame = frame;
} }

View File

@ -1188,6 +1188,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
register uint8 *frame_ref = NULL; /* cache of frame->ref */ register uint8 *frame_ref = NULL; /* cache of frame->ref */
int16 opnd_off; int16 opnd_off;
bool is_return_call_ref = false;
#endif #endif
uint8 *frame_ip_end = frame_ip + 1; uint8 *frame_ip_end = frame_ip + 1;
uint32 cond, count, fidx, tidx, frame_size = 0; 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"); wasm_set_exception(module, "uninitialized element");
goto got_exception; goto got_exception;
} }
fidx = func_obj->func_idx; fidx = wasm_func_obj_get_func_idx_bound(func_obj);
#endif #endif
/* clang-format on */ /* clang-format on */
@ -1420,21 +1421,40 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
/* always call module own functions */ /* always call module own functions */
cur_func = module->functions + fidx; cur_func = module->functions + fidx;
/* clang-format off */
#if WASM_ENABLE_GC == 0
if (cur_func->is_import_func) if (cur_func->is_import_func)
cur_func_type = cur_func->u.func_import->func_type; cur_func_type = cur_func->u.func_import->func_type;
else else
cur_func_type = cur_func->u.func->func_type; 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( if (!wasm_type_equal(
(WASMType *)cur_type, (WASMType *)cur_func_type, (WASMType *)cur_type, (WASMType *)cur_func_type,
module->module->types, module->module->type_count)) { module->module->types, module->module->type_count)) {
wasm_set_exception(module, "indirect call type mismatch"); wasm_set_exception(module, "indirect call type mismatch");
goto got_exception; goto got_exception;
} }
/* clang-format off */
#if WASM_ENABLE_GC == 0
#if WASM_ENABLE_TAIL_CALL != 0 #if WASM_ENABLE_TAIL_CALL != 0
if (opcode == WASM_OP_RETURN_CALL_INDIRECT) if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
goto call_func_from_return_call; goto call_func_from_return_call;
#endif #endif
goto call_func_from_interp; 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 */ /* parametric instructions */
@ -1582,7 +1602,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
PUSH_I32(func_idx); PUSH_I32(func_idx);
#else #else
if (!(gc_obj = wasm_create_func_obj(module, func_idx, true, if (!(gc_obj = wasm_create_func_obj(module, func_idx, true,
NULL, 0))) { NULL, true, NULL, 0))) {
goto got_exception; goto got_exception;
} }
PUSH_REF(gc_obj); PUSH_REF(gc_obj);
@ -1603,8 +1623,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception; goto got_exception;
} }
cur_func = module->functions + func_obj->func_idx; is_return_call_ref = false;
goto call_func_from_interp; goto call_func_from_call_ref;
} }
HANDLE_OP(WASM_OP_RETURN_CALL_REF) HANDLE_OP(WASM_OP_RETURN_CALL_REF)
@ -1618,11 +1638,70 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception; goto got_exception;
} }
cur_func = module->functions + func_obj->func_idx; is_return_call_ref = true;
goto call_func_from_return_call; goto call_func_from_call_ref;
} }
HANDLE_OP(WASM_OP_FUNC_BIND) 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) HANDLE_OP(WASM_OP_LET)
{ {
wasm_set_exception(module, "unsupported opcode"); wasm_set_exception(module, "unsupported opcode");
@ -2352,7 +2431,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
*(int32 *)global_addr = frame_lp[addr1]; *(int32 *)global_addr = frame_lp[addr1];
else else
PUT_REF_TO_ADDR((uint32 *)global_addr, PUT_REF_TO_ADDR((uint32 *)global_addr,
GET_REF_FROM_ADDR(frame_lp + addr_ret)); GET_REF_FROM_ADDR(frame_lp + addr1));
#endif #endif
/* clang-format on */ /* clang-format on */
HANDLE_OP_END(); HANDLE_OP_END();
@ -3906,7 +3985,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
if (func_indexes[i] != UINT32_MAX) { if (func_indexes[i] != UINT32_MAX) {
if (!(func_obj = wasm_create_func_obj( if (!(func_obj = wasm_create_func_obj(
module, func_indexes[i], true, NULL, module, func_indexes[i], true, NULL,
0))) { true, NULL, 0))) {
goto got_exception; goto got_exception;
} }
table_elems[i] = func_obj; table_elems[i] = func_obj;
@ -4503,7 +4582,95 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
FETCH_OPCODE_AND_DISPATCH(); FETCH_OPCODE_AND_DISPATCH();
#endif #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: call_func_from_return_call:
{ {
uint32 *lp_base = NULL, *lp = NULL; uint32 *lp_base = NULL, *lp = NULL;

View File

@ -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_count, result_count, i, j = 0;
uint32 param_cell_num, ret_cell_num; uint32 param_cell_num, ret_cell_num;
uint32 ref_type_map_count = 0, result_ref_type_map_count = 0; uint32 ref_type_map_count = 0, result_ref_type_map_count = 0;
uint64 total_size, param_offset; uint64 total_size;
uint16 offset;
bool need_ref_type_map; bool need_ref_type_map;
WASMRefType ref_type; WASMRefType ref_type;
WASMFuncType *type = NULL; 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) total_size = offsetof(WASMFuncType, types)
+ sizeof(uint8) * (uint64)(param_count + result_count); + 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))) { if (!(type = loader_malloc(total_size, error_buf, error_buf_size))) {
return false; 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->type_idx = type_idx;
type->param_count = param_count; type->param_count = param_count;
type->result_count = result_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->ref_type_map_count = ref_type_map_count;
type->result_ref_type_maps = type->result_ref_type_maps =
type->ref_type_maps + ref_type_map_count - result_ref_type_map_count; type->ref_type_maps + ref_type_map_count - result_ref_type_map_count;
type->ref_count = 1; type->ref_count = 1;
offset = offsetof(WASMFuncObject, param_data);
for (i = 0; i < param_count; i++) { for (i = 0; i < param_count; i++) {
if (!resolve_value_type(&p, p_end, module, &need_ref_type_map, if (!resolve_value_type(&p, p_end, module, &need_ref_type_map,
&ref_type, false, error_buf, error_buf_size)) { &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; 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); read_leb_uint32(p, p_end, result_count);
for (i = 0; i < result_count; i++) { 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_NULL:
case WASM_OP_BR_ON_NON_NULL: case WASM_OP_BR_ON_NON_NULL:
break; break;
case WASM_OP_FUNC_BIND: case WASM_OP_FUNC_BIND:
skip_leb_uint32(p, p_end); /* type index */
break;
case WASM_OP_LET: case WASM_OP_LET:
set_error_buf_v(error_buf, error_buf_size, set_error_buf_v(error_buf, error_buf_size,
"unsupported opcode %02x", opcode); "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) { && ctx->frame_reftype_map >= ctx->frame_reftype_map_boundary) {
/* Increase the frame reftype map stack */ /* Increase the frame reftype map stack */
bh_assert( 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); == ctx->frame_reftype_map_size);
MEM_REALLOC(ctx->frame_reftype_map_bottom, ctx->frame_reftype_map_size, MEM_REALLOC(ctx->frame_reftype_map_bottom, ctx->frame_reftype_map_size,
ctx->frame_reftype_map_size ctx->frame_reftype_map_size
+ (uint32)sizeof(WASMRefTypeMap) * 8); + (uint32)sizeof(WASMRefTypeMap) * 8);
ctx->frame_reftype_map = 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_size += (uint32)sizeof(WASMRefTypeMap) * 8;
ctx->frame_reftype_map_boundary = 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 #endif
return true; 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) { if (ctx->frame_reftype_map >= ctx->frame_reftype_map_boundary) {
/* Increase the frame reftype map stack */ /* Increase the frame reftype map stack */
bh_assert( bh_assert((uint32)((ctx->frame_reftype_map
(uint32)(ctx->frame_reftype_map - ctx->frame_reftype_map_bottom) - ctx->frame_reftype_map_bottom)
== ctx->frame_reftype_map_size); * sizeof(WASMRefTypeMap))
== ctx->frame_reftype_map_size);
MEM_REALLOC(ctx->frame_reftype_map_bottom, MEM_REALLOC(ctx->frame_reftype_map_bottom,
ctx->frame_reftype_map_size, ctx->frame_reftype_map_size,
ctx->frame_reftype_map_size ctx->frame_reftype_map_size
+ (uint32)sizeof(WASMRefTypeMap) * 8); + (uint32)sizeof(WASMRefTypeMap) * 8);
ctx->frame_reftype_map = ctx->frame_reftype_map = ctx->frame_reftype_map_bottom
ctx->frame_reftype_map_bottom + ctx->frame_reftype_map_size; + ctx->frame_reftype_map_size
/ ((uint32)sizeof(WASMRefTypeMap));
ctx->frame_reftype_map_size += (uint32)sizeof(WASMRefTypeMap) * 8; ctx->frame_reftype_map_size += (uint32)sizeof(WASMRefTypeMap) * 8;
ctx->frame_reftype_map_boundary = 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; ctx->frame_reftype_map->index = ctx->stack_cell_num;
@ -10000,6 +10003,111 @@ re_scan:
break; break;
case WASM_OP_FUNC_BIND: 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: case WASM_OP_LET:
/* TODO */ /* TODO */
set_error_buf_v(error_buf, error_buf_size, set_error_buf_v(error_buf, error_buf_size,

View File

@ -1166,12 +1166,15 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
void * void *
wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx, 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; WASMRttObjectRef rtt_obj;
WASMFuncObjectRef func_obj; WASMFuncObjectRef func_obj;
WASMFunctionInstance *func_inst; WASMFunctionInstance *func_inst;
WASMType *func_type; WASMFuncType *func_type;
uint32 param_count_bound = 0;
if (throw_exce) { if (throw_exce) {
error_buf = module_inst->cur_exception; 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_inst = &module_inst->functions[func_idx];
func_type = (WASMType *)(func_inst->is_import_func func_type = func_inst->is_import_func ? func_inst->u.func_import->func_type
? func_inst->u.func_import->func_type : func_inst->u.func->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, 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"); set_error_buf(error_buf, error_buf_size, "create rtt object failed");
return NULL; return NULL;
} }
if (!(func_obj = wasm_func_obj_new(module_inst->gc_heap_handle, rtt_obj, 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"); set_error_buf(error_buf, error_buf_size, "create func object failed");
return NULL; 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 ((uint32)global->initial_value.i32 != UINT32_MAX) {
if (!(func_obj = wasm_create_func_obj( if (!(func_obj = wasm_create_func_obj(
module_inst, global->initial_value.i32, module_inst, global->initial_value.i32,
false, error_buf, error_buf_size))) true, NULL, false, error_buf,
error_buf_size)))
goto fail; goto fail;
} }
STORE_PTR((void **)global_data, func_obj); 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 func_idx = table_seg->func_indexes[j];
/* UINT32_MAX indicates that it is an null reference */ /* UINT32_MAX indicates that it is an null reference */
if (func_idx != UINT32_MAX) { if (func_idx != UINT32_MAX) {
if (!(func_obj = if (!(func_obj = wasm_create_func_obj(
wasm_create_func_obj(module_inst, func_idx, false, module_inst, func_idx, true, NULL, false, error_buf,
error_buf, error_buf_size))) { error_buf_size))) {
goto fail; goto fail;
} }
*((void **)table_data + table_seg->base_offset.u.i32 + j) = *((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 #if WASM_ENABLE_GC == 0
func_idx = tbl_elem_val; func_idx = tbl_elem_val;
#else #else
func_idx = ((WASMFuncObjectRef)tbl_elem_val)->func_idx; func_idx =
wasm_func_obj_get_func_idx_bound((WASMFuncObjectRef)tbl_elem_val);
#endif #endif
/** /**

View File

@ -433,7 +433,9 @@ wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx,
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
void * void *
wasm_create_func_obj(WASMModuleInstance *module_inst, uint32 func_idx, 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 bool
wasm_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap); wasm_traverse_gc_rootset(WASMExecEnv *exec_env, void *heap);