| diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c |
| index 943b46f..5853813 100644 |
| --- a/core/iwasm/common/wasm_runtime_common.c |
| +++ b/core/iwasm/common/wasm_runtime_common.c |
| @@ -6234,6 +6234,142 @@ fail: |
| || defined(BUILD_TARGET_RISCV64_LP64D) \ |
| || defined(BUILD_TARGET_RISCV64_LP64) */ |
| |
| +#if WASM_ENABLE_QUICK_NATIVE != 0 |
| + |
| +uint8 |
| +wasm_runtime_compute_quick_native_kind(const WASMFuncType *func_type, |
| + const char *signature) |
| +{ |
| + uint32 i, n_int = 0, n_fp = 0; |
| + |
| + /* any conversion marker in the signature needs the generic path */ |
| + if (signature) { |
| + const char *s = signature; |
| + for (; *s; s++) |
| + if (*s != '(' && *s != ')' && *s != 'i' && *s != 'I' && *s != 'f' |
| + && *s != 'F') |
| + return WASM_QUICK_NATIVE_NO; |
| + } |
| + |
| + if (func_type->result_count > 1) |
| + return WASM_QUICK_NATIVE_NO; |
| + |
| + for (i = 0; i < func_type->param_count; i++) { |
| + switch (func_type->types[i]) { |
| + case VALUE_TYPE_I32: |
| + case VALUE_TYPE_I64: |
| + if (++n_int > 4) |
| + return WASM_QUICK_NATIVE_NO; |
| + break; |
| + case VALUE_TYPE_F32: |
| + case VALUE_TYPE_F64: |
| + if (++n_fp > 8) |
| + return WASM_QUICK_NATIVE_NO; |
| + break; |
| + default: |
| + return WASM_QUICK_NATIVE_NO; |
| + } |
| + } |
| + |
| + if (func_type->result_count == 0) |
| + return WASM_QUICK_NATIVE_RET_VOID; |
| + switch (func_type->types[func_type->param_count]) { |
| + case VALUE_TYPE_I32: |
| + return WASM_QUICK_NATIVE_RET_I32; |
| + case VALUE_TYPE_I64: |
| + return WASM_QUICK_NATIVE_RET_I64; |
| + case VALUE_TYPE_F32: |
| + return WASM_QUICK_NATIVE_RET_F32; |
| + case VALUE_TYPE_F64: |
| + return WASM_QUICK_NATIVE_RET_F64; |
| + default: |
| + return WASM_QUICK_NATIVE_NO; |
| + } |
| +} |
| + |
| +/* the shared arg shape: callees read their int args from the int registers |
| + and float args from the float registers, extra registers are ignored */ |
| +typedef uint64 (*quick_native_i_t)(WASMExecEnv *, uint64, uint64, uint64, |
| + uint64, double, double, double, double, |
| + double, double, double, double); |
| +typedef float32 (*quick_native_f32_t)(WASMExecEnv *, uint64, uint64, uint64, |
| + uint64, double, double, double, double, |
| + double, double, double, double); |
| +typedef float64 (*quick_native_f64_t)(WASMExecEnv *, uint64, uint64, uint64, |
| + uint64, double, double, double, double, |
| + double, double, double, double); |
| + |
| +#define QUICK_NATIVE_ARGS \ |
| + exec_env, ints[0], ints[1], ints[2], ints[3], fps[0], fps[1], fps[2], \ |
| + fps[3], fps[4], fps[5], fps[6], fps[7] |
| + |
| +bool |
| +wasm_runtime_invoke_native_quick(WASMExecEnv *exec_env, void *func_ptr, |
| + const WASMFuncType *func_type, uint8 ret_kind, |
| + void *attachment, uint32 *argv, |
| + uint32 *argv_ret) |
| +{ |
| + WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); |
| + uint64 ints[4] = { 0 }; |
| + double fps[8] = { 0 }; |
| + union { |
| + uint64 u; |
| + double d; |
| + } fbits; |
| + uint32 n_int = 0, n_fp = 0, i; |
| + uint32 *p = argv; |
| + |
| + for (i = 0; i < func_type->param_count; i++) { |
| + switch (func_type->types[i]) { |
| + case VALUE_TYPE_I32: |
| + ints[n_int++] = *p++; |
| + break; |
| + case VALUE_TYPE_I64: |
| + ints[n_int++] = (uint64)GET_I64_FROM_ADDR(p); |
| + p += 2; |
| + break; |
| + case VALUE_TYPE_F32: |
| + /* f32 args travel as the low half of a double register */ |
| + fbits.u = *p++; |
| + fps[n_fp++] = fbits.d; |
| + break; |
| + default: /* VALUE_TYPE_F64 */ |
| + fbits.u = (uint64)GET_I64_FROM_ADDR(p); |
| + fps[n_fp++] = fbits.d; |
| + p += 2; |
| + break; |
| + } |
| + } |
| + |
| + exec_env->attachment = attachment; |
| + switch (ret_kind) { |
| + case WASM_QUICK_NATIVE_RET_VOID: |
| + ((quick_native_i_t)func_ptr)(QUICK_NATIVE_ARGS); |
| + break; |
| + case WASM_QUICK_NATIVE_RET_I32: |
| + argv_ret[0] = |
| + (uint32)((quick_native_i_t)func_ptr)(QUICK_NATIVE_ARGS); |
| + break; |
| + case WASM_QUICK_NATIVE_RET_I64: |
| + PUT_I64_TO_ADDR(argv_ret, (int64)((quick_native_i_t)func_ptr)( |
| + QUICK_NATIVE_ARGS)); |
| + break; |
| + case WASM_QUICK_NATIVE_RET_F32: |
| + *(float32 *)argv_ret = |
| + ((quick_native_f32_t)func_ptr)(QUICK_NATIVE_ARGS); |
| + break; |
| + default: /* WASM_QUICK_NATIVE_RET_F64 */ |
| + PUT_F64_TO_ADDR(argv_ret, |
| + ((quick_native_f64_t)func_ptr)(QUICK_NATIVE_ARGS)); |
| + break; |
| + } |
| + exec_env->attachment = NULL; |
| + |
| + return !wasm_runtime_copy_exception(module, NULL); |
| +} |
| + |
| +#endif /* end of WASM_ENABLE_QUICK_NATIVE */ |
| + |
| bool |
| wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index, |
| uint32 argc, uint32 argv[]) |
| diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h |
| index 324620b..285ac40 100644 |
| --- a/core/iwasm/common/wasm_runtime_common.h |
| +++ b/core/iwasm/common/wasm_runtime_common.h |
| @@ -1255,6 +1255,41 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, |
| void *attachment, uint32 *argv, uint32 argc, |
| uint32 *ret); |
| |
| +/* rive: direct host-call dispatch for simple signatures skips the generic |
| + arg classifier; relies on int and float args living in disjoint register |
| + files, which Windows x64 does not honor */ |
| +#ifndef WASM_ENABLE_QUICK_NATIVE |
| +#if !defined(_WIN32) && !defined(_WIN32_) \ |
| + && (defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_X86_64) \ |
| + || defined(BUILD_TARGET_AMD_64)) |
| +#define WASM_ENABLE_QUICK_NATIVE 1 |
| +#else |
| +#define WASM_ENABLE_QUICK_NATIVE 0 |
| +#endif |
| +#endif |
| + |
| +#if WASM_ENABLE_QUICK_NATIVE != 0 |
| +enum { |
| + WASM_QUICK_NATIVE_UNKNOWN = 0, |
| + WASM_QUICK_NATIVE_NO = 1, |
| + WASM_QUICK_NATIVE_RET_VOID = 2, |
| + WASM_QUICK_NATIVE_RET_I32 = 3, |
| + WASM_QUICK_NATIVE_RET_I64 = 4, |
| + WASM_QUICK_NATIVE_RET_F32 = 5, |
| + WASM_QUICK_NATIVE_RET_F64 = 6, |
| +}; |
| + |
| +uint8 |
| +wasm_runtime_compute_quick_native_kind(const WASMFuncType *func_type, |
| + const char *signature); |
| + |
| +bool |
| +wasm_runtime_invoke_native_quick(WASMExecEnv *exec_env, void *func_ptr, |
| + const WASMFuncType *func_type, uint8 ret_kind, |
| + void *attachment, uint32 *argv, |
| + uint32 *argv_ret); |
| +#endif |
| + |
| bool |
| wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, |
| const WASMFuncType *func_type, |
| diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h |
| index 0dd7395..380890c 100644 |
| --- a/core/iwasm/interpreter/wasm.h |
| +++ b/core/iwasm/interpreter/wasm.h |
| @@ -613,6 +613,8 @@ typedef struct WASMFunctionImport { |
| #endif |
| bool call_conv_raw; |
| bool call_conv_wasm_c_api; |
| + /* rive: lazily computed quick host-call kind, see wasm_runtime_common.h */ |
| + uint8 quick_call_kind; |
| #if WASM_ENABLE_MULTI_MODULE != 0 |
| WASMModule *import_module; |
| WASMFunction *import_func_linked; |
| diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c |
| index c2aebd3..ddaf564 100644 |
| --- a/core/iwasm/interpreter/wasm_interp_fast.c |
| +++ b/core/iwasm/interpreter/wasm_interp_fast.c |
| @@ -1375,10 +1375,24 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, |
| } |
| } |
| else if (!func_import->call_conv_raw) { |
| - ret = wasm_runtime_invoke_native( |
| - exec_env, native_func_pointer, func_import->func_type, |
| - func_import->signature, func_import->attachment, frame->lp, |
| - cur_func->param_cell_num, argv_ret); |
| +#if WASM_ENABLE_QUICK_NATIVE != 0 |
| + uint8 quick_kind = func_import->quick_call_kind; |
| + if (quick_kind == WASM_QUICK_NATIVE_UNKNOWN) { |
| + /* benign race: concurrent recompute stores the same value */ |
| + quick_kind = wasm_runtime_compute_quick_native_kind( |
| + func_import->func_type, func_import->signature); |
| + func_import->quick_call_kind = quick_kind; |
| + } |
| + if (quick_kind != WASM_QUICK_NATIVE_NO) |
| + ret = wasm_runtime_invoke_native_quick( |
| + exec_env, native_func_pointer, func_import->func_type, |
| + quick_kind, func_import->attachment, frame->lp, argv_ret); |
| + else |
| +#endif |
| + ret = wasm_runtime_invoke_native( |
| + exec_env, native_func_pointer, func_import->func_type, |
| + func_import->signature, func_import->attachment, frame->lp, |
| + cur_func->param_cell_num, argv_ret); |
| } |
| else { |
| ret = wasm_runtime_invoke_native_raw( |