Implement Multi-tier JIT (#1774)
Implement 2-level Multi-tier JIT engine: tier-up from Fast JIT to LLVM JIT to get quick cold startup by Fast JIT and better performance by gradually switching to LLVM JIT when the LLVM JIT functions are compiled by the backend threads. Refer to: https://github.com/bytecodealliance/wasm-micro-runtime/issues/1302
This commit is contained in:
@ -3947,28 +3947,48 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
|
||||
#if WASM_ENABLE_FAST_JIT != 0
|
||||
static void
|
||||
fast_jit_call_func_bytecode(WASMExecEnv *exec_env,
|
||||
fast_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
WASMExecEnv *exec_env,
|
||||
WASMFunctionInstance *function,
|
||||
WASMInterpFrame *frame)
|
||||
{
|
||||
JitGlobals *jit_globals = jit_compiler_get_jit_globals();
|
||||
JitInterpSwitchInfo info;
|
||||
WASMModule *module = module_inst->module;
|
||||
WASMType *func_type = function->u.func->func_type;
|
||||
uint8 type = func_type->result_count
|
||||
? func_type->types[func_type->param_count]
|
||||
: VALUE_TYPE_VOID;
|
||||
uint32 func_idx = (uint32)(function - module_inst->e->functions);
|
||||
uint32 func_idx_non_import = func_idx - module->import_function_count;
|
||||
int32 action;
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
if (type == VALUE_TYPE_EXTERNREF || type == VALUE_TYPE_FUNCREF)
|
||||
type = VALUE_TYPE_I32;
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_LAZY_JIT != 0
|
||||
if (!jit_compiler_compile(module, func_idx)) {
|
||||
wasm_set_exception(module_inst, "failed to compile fast jit function");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bh_assert(jit_compiler_is_compiled(module, func_idx));
|
||||
|
||||
/* Switch to jitted code to call the jit function */
|
||||
info.out.ret.last_return_type = type;
|
||||
info.frame = frame;
|
||||
frame->jitted_return_addr =
|
||||
(uint8 *)jit_globals->return_to_interp_from_jitted;
|
||||
jit_interp_switch_to_jitted(exec_env, &info,
|
||||
function->u.func->fast_jit_jitted_code);
|
||||
action = jit_interp_switch_to_jitted(
|
||||
exec_env, &info, func_idx,
|
||||
module_inst->fast_jit_func_ptrs[func_idx_non_import]);
|
||||
bh_assert(action == JIT_INTERP_ACTION_NORMAL
|
||||
|| (action == JIT_INTERP_ACTION_THROWN
|
||||
&& wasm_runtime_get_exception(exec_env->module_inst)));
|
||||
|
||||
/* Get the return values form info.out.ret */
|
||||
if (func_type->result_count) {
|
||||
switch (type) {
|
||||
case VALUE_TYPE_I32:
|
||||
@ -3992,8 +4012,10 @@ fast_jit_call_func_bytecode(WASMExecEnv *exec_env,
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void)action;
|
||||
(void)func_idx;
|
||||
}
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_FAST_JIT != 0 */
|
||||
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
static bool
|
||||
@ -4023,11 +4045,13 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
WASMType *func_type = function->u.func->func_type;
|
||||
uint32 result_count = func_type->result_count;
|
||||
uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0;
|
||||
uint32 func_idx = (uint32)(function - module_inst->e->functions);
|
||||
bool ret;
|
||||
|
||||
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
|
||||
if (!llvm_jit_alloc_frame(exec_env, function - module_inst->e->functions)) {
|
||||
wasm_set_exception(module_inst, "wasm operand stack overflow");
|
||||
/* wasm operand stack overflow has been thrown,
|
||||
no need to throw again */
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@ -4069,8 +4093,8 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
}
|
||||
|
||||
ret = wasm_runtime_invoke_native(
|
||||
exec_env, function->u.func->llvm_jit_func_ptr, func_type, NULL,
|
||||
NULL, argv1, argc, argv);
|
||||
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
|
||||
argv1, argc, argv);
|
||||
|
||||
if (!ret || wasm_get_exception(module_inst)) {
|
||||
if (clear_wasi_proc_exit_exception(module_inst))
|
||||
@ -4120,8 +4144,8 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
}
|
||||
else {
|
||||
ret = wasm_runtime_invoke_native(
|
||||
exec_env, function->u.func->llvm_jit_func_ptr, func_type, NULL,
|
||||
NULL, argv, argc, argv);
|
||||
exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL,
|
||||
argv, argc, argv);
|
||||
|
||||
if (clear_wasi_proc_exit_exception(module_inst))
|
||||
ret = true;
|
||||
@ -4129,7 +4153,7 @@ llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst,
|
||||
return ret && !wasm_get_exception(module_inst) ? true : false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_JIT != 0 */
|
||||
|
||||
void
|
||||
wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
@ -4202,18 +4226,63 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
#if WASM_ENABLE_LAZY_JIT != 0
|
||||
|
||||
/* Fast JIT to LLVM JIT tier-up is enabled */
|
||||
#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0
|
||||
/* Fast JIT and LLVM JIT are both enabled, call llvm jit function
|
||||
if it is compiled, else call fast jit function */
|
||||
uint32 func_idx = (uint32)(function - module_inst->e->functions);
|
||||
if (module_inst->module->func_ptrs_compiled
|
||||
[func_idx - module_inst->module->import_function_count]) {
|
||||
llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
|
||||
argv);
|
||||
/* For llvm jit, the results have been stored in argv,
|
||||
no need to copy them from stack frame again */
|
||||
copy_argv_from_frame = false;
|
||||
}
|
||||
else {
|
||||
fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
}
|
||||
#elif WASM_ENABLE_JIT != 0
|
||||
/* Only LLVM JIT is enabled */
|
||||
llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
|
||||
argv);
|
||||
/* For llvm jit, the results have been stored in argv,
|
||||
no need to copy them from stack frame again */
|
||||
copy_argv_from_frame = false;
|
||||
#elif WASM_ENABLE_FAST_JIT != 0
|
||||
fast_jit_call_func_bytecode(exec_env, function, frame);
|
||||
/* Only Fast JIT is enabled */
|
||||
fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
#else
|
||||
/* Both Fast JIT and LLVM JIT are disabled */
|
||||
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
#endif
|
||||
|
||||
#else /* else of WASM_ENABLE_LAZY_JIT != 0 */
|
||||
|
||||
/* Fast JIT to LLVM JIT tier-up is enabled */
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
/* LLVM JIT is enabled */
|
||||
llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc,
|
||||
argv);
|
||||
/* For llvm jit, the results have been stored in argv,
|
||||
no need to copy them from stack frame again */
|
||||
copy_argv_from_frame = false;
|
||||
#elif WASM_ENABLE_FAST_JIT != 0
|
||||
/* Fast JIT is enabled */
|
||||
fast_jit_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
#else
|
||||
/* Both Fast JIT and LLVM JIT are disabled */
|
||||
wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame);
|
||||
#endif
|
||||
|
||||
#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */
|
||||
|
||||
(void)wasm_interp_call_func_bytecode;
|
||||
#if WASM_ENABLE_FAST_JIT != 0
|
||||
(void)fast_jit_call_func_bytecode;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Output the return value to the caller */
|
||||
|
||||
Reference in New Issue
Block a user