mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-11 12:11:14 +00:00
Implement JIT IR translation for opcode call_indirect (#1138)
This commit is contained in:
parent
87b259a40a
commit
dd966977a5
|
@ -7,43 +7,18 @@
|
|||
#include "jit_emit_exception.h"
|
||||
#include "../jit_frontend.h"
|
||||
#include "../jit_codegen.h"
|
||||
#include "../../interpreter/wasm_runtime.h"
|
||||
|
||||
extern bool
|
||||
jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||
WASMInterpFrame *prev_frame);
|
||||
|
||||
bool
|
||||
jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
|
||||
/* Prepare parameters for the function to call */
|
||||
static bool
|
||||
pre_call(JitCompContext *cc, const WASMType *func_type)
|
||||
{
|
||||
WASMModule *wasm_module = cc->cur_wasm_module;
|
||||
WASMFunctionImport *func_import;
|
||||
WASMFunction *func;
|
||||
WASMType *func_type;
|
||||
JitFrame *jit_frame = cc->jit_frame;
|
||||
JitReg value, result = 0, native_ret;
|
||||
JitReg func_ptrs, jitted_code = 0;
|
||||
JitInsn *insn;
|
||||
uint32 i, n, outs_off, jitted_func_idx;
|
||||
|
||||
if (func_idx >= wasm_module->import_function_count) {
|
||||
func_ptrs = get_func_ptrs_reg(jit_frame);
|
||||
jitted_code = jit_cc_new_reg_ptr(cc);
|
||||
/* jitted_code = func_ptrs[func_idx - import_function_count] */
|
||||
jitted_func_idx = func_idx - wasm_module->import_function_count;
|
||||
GEN_INSN(LDPTR, jitted_code, func_ptrs,
|
||||
NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx));
|
||||
}
|
||||
|
||||
if (func_idx < wasm_module->import_function_count) {
|
||||
func_import = &wasm_module->import_functions[func_idx].u.function;
|
||||
func_type = func_import->func_type;
|
||||
}
|
||||
else {
|
||||
func = wasm_module
|
||||
->functions[func_idx - wasm_module->import_function_count];
|
||||
func_type = func->func_type;
|
||||
}
|
||||
|
||||
JitReg value;
|
||||
uint32 i, outs_off;
|
||||
/* Prepare parameters for the function to call */
|
||||
outs_off =
|
||||
cc->total_frame_size + offsetof(WASMInterpFrame, lp)
|
||||
|
@ -77,13 +52,107 @@ jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
|
|||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit sp as the callee may use it to store the results */
|
||||
gen_commit_sp_ip(cc->jit_frame);
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Push results */
|
||||
static bool
|
||||
post_return(JitCompContext *cc, const WASMType *func_type)
|
||||
{
|
||||
uint32 i, n;
|
||||
JitReg value;
|
||||
|
||||
n = cc->jit_frame->sp - cc->jit_frame->lp;
|
||||
for (i = 0; i < func_type->result_count; i++) {
|
||||
switch (func_type->types[func_type->param_count + i]) {
|
||||
case VALUE_TYPE_I32:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
#endif
|
||||
value = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(LDI32, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_I32(value);
|
||||
n++;
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
value = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(LDI64, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_I64(value);
|
||||
n += 2;
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
value = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(LDF32, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_F32(value);
|
||||
n++;
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
value = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(LDF64, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_F64(value);
|
||||
n += 2;
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
|
||||
{
|
||||
WASMModule *wasm_module = cc->cur_wasm_module;
|
||||
WASMFunctionImport *func_import;
|
||||
WASMFunction *func;
|
||||
WASMType *func_type;
|
||||
JitFrame *jit_frame = cc->jit_frame;
|
||||
JitReg result = 0, native_ret;
|
||||
JitReg func_ptrs, jitted_code = 0;
|
||||
JitInsn *insn;
|
||||
uint32 jitted_func_idx;
|
||||
|
||||
if (func_idx >= wasm_module->import_function_count) {
|
||||
func_ptrs = get_func_ptrs_reg(jit_frame);
|
||||
jitted_code = jit_cc_new_reg_ptr(cc);
|
||||
/* jitted_code = func_ptrs[func_idx - import_function_count] */
|
||||
jitted_func_idx = func_idx - wasm_module->import_function_count;
|
||||
GEN_INSN(LDPTR, jitted_code, func_ptrs,
|
||||
NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx));
|
||||
}
|
||||
|
||||
if (func_idx < wasm_module->import_function_count) {
|
||||
func_import = &wasm_module->import_functions[func_idx].u.function;
|
||||
func_type = func_import->func_type;
|
||||
}
|
||||
else {
|
||||
func = wasm_module
|
||||
->functions[func_idx - wasm_module->import_function_count];
|
||||
func_type = func->func_type;
|
||||
}
|
||||
|
||||
if (!pre_call(cc, func_type)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (func_idx < wasm_module->import_function_count) {
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
||||
/* Set native_ret to x86::eax */
|
||||
|
@ -144,46 +213,8 @@ jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
|
|||
GEN_INSN(CALLBC, result, 0, jitted_code);
|
||||
}
|
||||
|
||||
/* Push results */
|
||||
n = cc->jit_frame->sp - cc->jit_frame->lp;
|
||||
for (i = 0; i < func_type->result_count; i++) {
|
||||
switch (func_type->types[func_type->param_count + i]) {
|
||||
case VALUE_TYPE_I32:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
#endif
|
||||
value = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(LDI32, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_I32(value);
|
||||
n++;
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
value = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(LDI64, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_I64(value);
|
||||
n += 2;
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
value = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(LDF32, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_F32(value);
|
||||
n++;
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
value = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(LDF64, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(n)));
|
||||
PUSH_F64(value);
|
||||
n += 2;
|
||||
break;
|
||||
default:
|
||||
bh_assert(0);
|
||||
break;
|
||||
}
|
||||
if (!post_return(cc, func_type)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Clear part of memory regs and table regs as their values
|
||||
|
@ -198,10 +229,145 @@ fail:
|
|||
return false;
|
||||
}
|
||||
|
||||
static JitReg
|
||||
pack_argv(JitCompContext *cc)
|
||||
{
|
||||
/* reuse the stack of the next frame*/
|
||||
uint32 stack_base;
|
||||
JitReg argv;
|
||||
|
||||
stack_base = cc->total_frame_size + offsetof(WASMInterpFrame, lp);
|
||||
argv = jit_cc_new_reg_ptr(cc);
|
||||
GEN_INSN(ADD, argv, cc->fp_reg, NEW_CONST(PTR, stack_base));
|
||||
return argv;
|
||||
}
|
||||
|
||||
static bool
|
||||
unpack_argv(JitCompContext *cc, const WASMType *func_type, JitReg argv)
|
||||
{
|
||||
/* argv to stack*/
|
||||
uint32 i, top_by_cell, offset_by_cell;
|
||||
JitReg value;
|
||||
|
||||
/* stack top */
|
||||
top_by_cell = cc->jit_frame->sp - cc->jit_frame->lp;
|
||||
offset_by_cell = 0;
|
||||
for (i = 0; i < func_type->result_count; i++) {
|
||||
switch (func_type->types[func_type->param_count + i]) {
|
||||
case VALUE_TYPE_I32:
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
case VALUE_TYPE_EXTERNREF:
|
||||
case VALUE_TYPE_FUNCREF:
|
||||
#endif
|
||||
{
|
||||
value = jit_cc_new_reg_I32(cc);
|
||||
GEN_INSN(LDI32, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
GEN_INSN(STI32, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(top_by_cell
|
||||
+ offset_by_cell)));
|
||||
offset_by_cell += 1;
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_I64:
|
||||
{
|
||||
value = jit_cc_new_reg_I64(cc);
|
||||
GEN_INSN(LDI64, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
GEN_INSN(STI64, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(top_by_cell
|
||||
+ offset_by_cell)));
|
||||
offset_by_cell += 2;
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_F32:
|
||||
{
|
||||
value = jit_cc_new_reg_F32(cc);
|
||||
GEN_INSN(LDF32, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
GEN_INSN(STF32, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(top_by_cell
|
||||
+ offset_by_cell)));
|
||||
offset_by_cell += 1;
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_F64:
|
||||
{
|
||||
value = jit_cc_new_reg_F64(cc);
|
||||
GEN_INSN(LDF64, value, argv, NEW_CONST(I32, offset_by_cell));
|
||||
GEN_INSN(STF64, value, cc->fp_reg,
|
||||
NEW_CONST(I32, offset_of_local(top_by_cell
|
||||
+ offset_by_cell)));
|
||||
offset_by_cell += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
bh_assert(0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
|
||||
uint32 tbl_idx)
|
||||
{
|
||||
JitReg element_indices, native_ret, argv;
|
||||
WASMType *func_type;
|
||||
JitInsn *insn;
|
||||
|
||||
POP_I32(element_indices);
|
||||
|
||||
func_type = cc->cur_wasm_module->types[type_idx];
|
||||
if (!pre_call(cc, func_type)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
argv = pack_argv(cc);
|
||||
|
||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
||||
/* Set native_ret to x86::eax */
|
||||
native_ret = jit_codegen_get_hreg_by_name("eax");
|
||||
#else
|
||||
native_ret = jit_cc_new_reg_I32(cc);
|
||||
#endif
|
||||
|
||||
insn = GEN_INSN(CALLNATIVE, native_ret,
|
||||
NEW_CONST(PTR, (uintptr_t)wasm_call_indirect), 5);
|
||||
if (!insn) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*(jit_insn_opndv(insn, 2)) = cc->exec_env_reg;
|
||||
*(jit_insn_opndv(insn, 3)) = NEW_CONST(I32, tbl_idx);
|
||||
*(jit_insn_opndv(insn, 4)) = element_indices;
|
||||
*(jit_insn_opndv(insn, 5)) = NEW_CONST(I32, func_type->param_count);
|
||||
*(jit_insn_opndv(insn, 6)) = argv;
|
||||
|
||||
/* Check whether there is exception thrown */
|
||||
GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0));
|
||||
if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, cc->cmp_reg,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unpack_argv(cc, func_type, argv)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!post_return(cc, func_type)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Clear part of memory regs and table regs as their values
|
||||
may be changed in the function call */
|
||||
clear_memory_regs(cc->jit_frame);
|
||||
clear_table_regs(cc->jit_frame);
|
||||
return true;
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user