mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-05-12 12:41:25 +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_emit_exception.h"
|
||||||
#include "../jit_frontend.h"
|
#include "../jit_frontend.h"
|
||||||
#include "../jit_codegen.h"
|
#include "../jit_codegen.h"
|
||||||
|
#include "../../interpreter/wasm_runtime.h"
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
|
||||||
WASMInterpFrame *prev_frame);
|
WASMInterpFrame *prev_frame);
|
||||||
|
|
||||||
bool
|
/* Prepare parameters for the function to call */
|
||||||
jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
|
static bool
|
||||||
|
pre_call(JitCompContext *cc, const WASMType *func_type)
|
||||||
{
|
{
|
||||||
WASMModule *wasm_module = cc->cur_wasm_module;
|
JitReg value;
|
||||||
WASMFunctionImport *func_import;
|
uint32 i, outs_off;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare parameters for the function to call */
|
/* Prepare parameters for the function to call */
|
||||||
outs_off =
|
outs_off =
|
||||||
cc->total_frame_size + offsetof(WASMInterpFrame, lp)
|
cc->total_frame_size + offsetof(WASMInterpFrame, lp)
|
||||||
|
@ -77,13 +52,107 @@ jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bh_assert(0);
|
bh_assert(0);
|
||||||
break;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Commit sp as the callee may use it to store the results */
|
/* Commit sp as the callee may use it to store the results */
|
||||||
gen_commit_sp_ip(cc->jit_frame);
|
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 (func_idx < wasm_module->import_function_count) {
|
||||||
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
|
||||||
/* Set native_ret to x86::eax */
|
/* 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);
|
GEN_INSN(CALLBC, result, 0, jitted_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push results */
|
if (!post_return(cc, func_type)) {
|
||||||
n = cc->jit_frame->sp - cc->jit_frame->lp;
|
goto fail;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear part of memory regs and table regs as their values
|
/* Clear part of memory regs and table regs as their values
|
||||||
|
@ -198,10 +229,145 @@ fail:
|
||||||
return false;
|
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
|
bool
|
||||||
jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
|
jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
|
||||||
uint32 tbl_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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user