jit_emit_function.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "jit_emit_function.h"
  6. #include "jit_emit_exception.h"
  7. #include "../jit_frontend.h"
  8. #include "../jit_codegen.h"
  9. #include "../../interpreter/wasm_runtime.h"
  10. extern bool
  11. jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx,
  12. WASMInterpFrame *prev_frame);
  13. /* Prepare parameters for the function to call */
  14. static bool
  15. pre_call(JitCompContext *cc, const WASMType *func_type)
  16. {
  17. JitReg value;
  18. uint32 i, outs_off;
  19. /* Prepare parameters for the function to call */
  20. outs_off =
  21. cc->total_frame_size + offsetof(WASMInterpFrame, lp)
  22. + wasm_get_cell_num(func_type->types, func_type->param_count) * 4;
  23. for (i = 0; i < func_type->param_count; i++) {
  24. switch (func_type->types[func_type->param_count - 1 - i]) {
  25. case VALUE_TYPE_I32:
  26. #if WASM_ENABLE_REF_TYPES != 0
  27. case VALUE_TYPE_EXTERNREF:
  28. case VALUE_TYPE_FUNCREF:
  29. #endif
  30. POP_I32(value);
  31. outs_off -= 4;
  32. GEN_INSN(STI32, value, cc->fp_reg, NEW_CONST(I32, outs_off));
  33. break;
  34. case VALUE_TYPE_I64:
  35. POP_I64(value);
  36. outs_off -= 8;
  37. GEN_INSN(STI64, value, cc->fp_reg, NEW_CONST(I32, outs_off));
  38. break;
  39. case VALUE_TYPE_F32:
  40. POP_F32(value);
  41. outs_off -= 4;
  42. GEN_INSN(STF32, value, cc->fp_reg, NEW_CONST(I32, outs_off));
  43. break;
  44. case VALUE_TYPE_F64:
  45. POP_F64(value);
  46. outs_off -= 8;
  47. GEN_INSN(STF64, value, cc->fp_reg, NEW_CONST(I32, outs_off));
  48. break;
  49. default:
  50. bh_assert(0);
  51. goto fail;
  52. }
  53. }
  54. /* Commit sp as the callee may use it to store the results */
  55. gen_commit_sp_ip(cc->jit_frame);
  56. return true;
  57. fail:
  58. return false;
  59. }
  60. /* Push results */
  61. static bool
  62. post_return(JitCompContext *cc, const WASMType *func_type, JitReg first_res)
  63. {
  64. uint32 i, n;
  65. JitReg value;
  66. n = cc->jit_frame->sp - cc->jit_frame->lp;
  67. for (i = 0; i < func_type->result_count; i++) {
  68. switch (func_type->types[func_type->param_count + i]) {
  69. case VALUE_TYPE_I32:
  70. #if WASM_ENABLE_REF_TYPES != 0
  71. case VALUE_TYPE_EXTERNREF:
  72. case VALUE_TYPE_FUNCREF:
  73. #endif
  74. if (i == 0 && first_res) {
  75. bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I32);
  76. value = first_res;
  77. }
  78. else {
  79. value = jit_cc_new_reg_I32(cc);
  80. GEN_INSN(LDI32, value, cc->fp_reg,
  81. NEW_CONST(I32, offset_of_local(n)));
  82. }
  83. PUSH_I32(value);
  84. n++;
  85. break;
  86. case VALUE_TYPE_I64:
  87. if (i == 0 && first_res) {
  88. bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I64);
  89. value = first_res;
  90. }
  91. else {
  92. value = jit_cc_new_reg_I64(cc);
  93. GEN_INSN(LDI64, value, cc->fp_reg,
  94. NEW_CONST(I32, offset_of_local(n)));
  95. }
  96. PUSH_I64(value);
  97. n += 2;
  98. break;
  99. case VALUE_TYPE_F32:
  100. if (i == 0 && first_res) {
  101. bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F32);
  102. value = first_res;
  103. }
  104. else {
  105. value = jit_cc_new_reg_F32(cc);
  106. GEN_INSN(LDF32, value, cc->fp_reg,
  107. NEW_CONST(I32, offset_of_local(n)));
  108. }
  109. PUSH_F32(value);
  110. n++;
  111. break;
  112. case VALUE_TYPE_F64:
  113. if (i == 0 && first_res) {
  114. bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F64);
  115. value = first_res;
  116. }
  117. else {
  118. value = jit_cc_new_reg_F64(cc);
  119. GEN_INSN(LDF64, value, cc->fp_reg,
  120. NEW_CONST(I32, offset_of_local(n)));
  121. }
  122. PUSH_F64(value);
  123. n += 2;
  124. break;
  125. default:
  126. bh_assert(0);
  127. goto fail;
  128. }
  129. }
  130. /* Update the committed_sp as the callee has updated the frame sp */
  131. cc->jit_frame->committed_sp = cc->jit_frame->sp;
  132. return true;
  133. fail:
  134. return false;
  135. }
  136. bool
  137. jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call)
  138. {
  139. WASMModule *wasm_module = cc->cur_wasm_module;
  140. WASMFunctionImport *func_import;
  141. WASMFunction *func;
  142. WASMType *func_type;
  143. JitFrame *jit_frame = cc->jit_frame;
  144. JitReg native_ret;
  145. JitReg fast_jit_func_ptrs, jitted_code = 0;
  146. uint32 jitted_func_idx;
  147. if (func_idx >= wasm_module->import_function_count) {
  148. fast_jit_func_ptrs = get_fast_jit_func_ptrs_reg(jit_frame);
  149. jitted_code = jit_cc_new_reg_ptr(cc);
  150. /* jitted_code = func_ptrs[func_idx - import_function_count] */
  151. jitted_func_idx = func_idx - wasm_module->import_function_count;
  152. GEN_INSN(LDPTR, jitted_code, fast_jit_func_ptrs,
  153. NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx));
  154. }
  155. if (func_idx < wasm_module->import_function_count) {
  156. func_import = &wasm_module->import_functions[func_idx].u.function;
  157. func_type = func_import->func_type;
  158. }
  159. else {
  160. func = wasm_module
  161. ->functions[func_idx - wasm_module->import_function_count];
  162. func_type = func->func_type;
  163. }
  164. if (!pre_call(cc, func_type)) {
  165. goto fail;
  166. }
  167. if (func_idx < wasm_module->import_function_count) {
  168. JitReg arg_regs[3];
  169. native_ret = jit_cc_new_reg_I32(cc);
  170. arg_regs[0] = cc->exec_env_reg;
  171. arg_regs[1] = NEW_CONST(I32, func_idx);
  172. arg_regs[2] = cc->fp_reg;
  173. if (!jit_emit_callnative(cc, jit_invoke_native, native_ret, arg_regs,
  174. 3)) {
  175. return false;
  176. }
  177. /* Convert bool to uint32 */
  178. GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF));
  179. /* Check whether there is exception thrown */
  180. GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0));
  181. if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BEQ,
  182. cc->cmp_reg, NULL)) {
  183. return false;
  184. }
  185. if (!post_return(cc, func_type, 0)) {
  186. goto fail;
  187. }
  188. }
  189. else {
  190. JitReg res = 0;
  191. if (func_type->result_count > 0) {
  192. switch (func_type->types[func_type->param_count]) {
  193. case VALUE_TYPE_I32:
  194. #if WASM_ENABLE_REF_TYPES != 0
  195. case VALUE_TYPE_EXTERNREF:
  196. case VALUE_TYPE_FUNCREF:
  197. #endif
  198. res = jit_cc_new_reg_I32(cc);
  199. break;
  200. case VALUE_TYPE_I64:
  201. res = jit_cc_new_reg_I64(cc);
  202. break;
  203. case VALUE_TYPE_F32:
  204. res = jit_cc_new_reg_F32(cc);
  205. break;
  206. case VALUE_TYPE_F64:
  207. res = jit_cc_new_reg_F64(cc);
  208. break;
  209. default:
  210. bh_assert(0);
  211. goto fail;
  212. }
  213. }
  214. GEN_INSN(CALLBC, res, 0, jitted_code);
  215. if (!post_return(cc, func_type, res)) {
  216. goto fail;
  217. }
  218. }
  219. /* Clear part of memory regs and table regs as their values
  220. may be changed in the function call */
  221. if (cc->cur_wasm_module->possible_memory_grow)
  222. clear_memory_regs(jit_frame);
  223. clear_table_regs(jit_frame);
  224. /* Ignore tail call currently */
  225. (void)tail_call;
  226. return true;
  227. fail:
  228. return false;
  229. }
  230. static JitReg
  231. pack_argv(JitCompContext *cc)
  232. {
  233. /* reuse the stack of the next frame */
  234. uint32 stack_base;
  235. JitReg argv;
  236. stack_base = cc->total_frame_size + offsetof(WASMInterpFrame, lp);
  237. argv = jit_cc_new_reg_ptr(cc);
  238. GEN_INSN(ADD, argv, cc->fp_reg, NEW_CONST(PTR, stack_base));
  239. return argv;
  240. }
  241. static bool
  242. unpack_argv(JitCompContext *cc, const WASMType *func_type, JitReg argv)
  243. {
  244. uint32 i, offset_by_cell = 0;
  245. JitReg value;
  246. /* push results in argv to stack */
  247. for (i = 0; i < func_type->result_count; i++) {
  248. switch (func_type->types[func_type->param_count + i]) {
  249. case VALUE_TYPE_I32:
  250. #if WASM_ENABLE_REF_TYPES != 0
  251. case VALUE_TYPE_EXTERNREF:
  252. case VALUE_TYPE_FUNCREF:
  253. #endif
  254. {
  255. value = jit_cc_new_reg_I32(cc);
  256. GEN_INSN(LDI32, value, argv, NEW_CONST(I32, offset_by_cell));
  257. PUSH_I32(value);
  258. offset_by_cell += 4;
  259. break;
  260. }
  261. case VALUE_TYPE_I64:
  262. {
  263. value = jit_cc_new_reg_I64(cc);
  264. GEN_INSN(LDI64, value, argv, NEW_CONST(I32, offset_by_cell));
  265. PUSH_I64(value);
  266. offset_by_cell += 8;
  267. break;
  268. }
  269. case VALUE_TYPE_F32:
  270. {
  271. value = jit_cc_new_reg_F32(cc);
  272. GEN_INSN(LDF32, value, argv, NEW_CONST(I32, offset_by_cell));
  273. PUSH_F32(value);
  274. offset_by_cell += 4;
  275. break;
  276. }
  277. case VALUE_TYPE_F64:
  278. {
  279. value = jit_cc_new_reg_F64(cc);
  280. GEN_INSN(LDF64, value, argv, NEW_CONST(I32, offset_by_cell));
  281. PUSH_F64(value);
  282. offset_by_cell += 8;
  283. break;
  284. }
  285. default:
  286. {
  287. bh_assert(0);
  288. goto fail;
  289. }
  290. }
  291. }
  292. /* Update the committed_sp as the callee has updated the frame sp */
  293. cc->jit_frame->committed_sp = cc->jit_frame->sp;
  294. return true;
  295. fail:
  296. return false;
  297. }
  298. bool
  299. jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx,
  300. uint32 tbl_idx)
  301. {
  302. JitReg elem_idx, native_ret, argv, arg_regs[6];
  303. WASMType *func_type;
  304. POP_I32(elem_idx);
  305. func_type = cc->cur_wasm_module->types[type_idx];
  306. if (!pre_call(cc, func_type)) {
  307. goto fail;
  308. }
  309. argv = pack_argv(cc);
  310. native_ret = jit_cc_new_reg_I32(cc);
  311. arg_regs[0] = cc->exec_env_reg;
  312. arg_regs[1] = NEW_CONST(I32, tbl_idx);
  313. arg_regs[2] = elem_idx;
  314. arg_regs[3] = NEW_CONST(I32, type_idx);
  315. arg_regs[4] = NEW_CONST(I32, func_type->param_cell_num);
  316. arg_regs[5] = argv;
  317. if (!jit_emit_callnative(cc, jit_call_indirect, native_ret, arg_regs, 6)) {
  318. return false;
  319. }
  320. /* Convert bool to uint32 */
  321. GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF));
  322. /* Check whether there is exception thrown */
  323. GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0));
  324. if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BEQ,
  325. cc->cmp_reg, NULL)) {
  326. return false;
  327. }
  328. if (!unpack_argv(cc, func_type, argv)) {
  329. goto fail;
  330. }
  331. /* Clear part of memory regs and table regs as their values
  332. may be changed in the function call */
  333. if (cc->cur_wasm_module->possible_memory_grow)
  334. clear_memory_regs(cc->jit_frame);
  335. clear_table_regs(cc->jit_frame);
  336. return true;
  337. fail:
  338. return false;
  339. }
  340. #if WASM_ENABLE_REF_TYPES != 0
  341. bool
  342. jit_compile_op_ref_null(JitCompContext *cc, uint32 ref_type)
  343. {
  344. PUSH_I32(NEW_CONST(I32, NULL_REF));
  345. (void)ref_type;
  346. return true;
  347. fail:
  348. return false;
  349. }
  350. bool
  351. jit_compile_op_ref_is_null(JitCompContext *cc)
  352. {
  353. JitReg ref, res;
  354. POP_I32(ref);
  355. GEN_INSN(CMP, cc->cmp_reg, ref, NEW_CONST(I32, NULL_REF));
  356. res = jit_cc_new_reg_I32(cc);
  357. GEN_INSN(SELECTEQ, res, cc->cmp_reg, NEW_CONST(I32, 1), NEW_CONST(I32, 0));
  358. PUSH_I32(res);
  359. return true;
  360. fail:
  361. return false;
  362. }
  363. bool
  364. jit_compile_op_ref_func(JitCompContext *cc, uint32 func_idx)
  365. {
  366. PUSH_I32(NEW_CONST(I32, func_idx));
  367. return true;
  368. fail:
  369. return false;
  370. }
  371. #endif
  372. #if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
  373. bool
  374. jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res,
  375. JitReg *params, uint32 param_count)
  376. {
  377. JitInsn *insn;
  378. char *i64_arg_names[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" };
  379. char *f32_arg_names[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" };
  380. char *f64_arg_names[] = { "xmm0_f64", "xmm1_f64", "xmm2_f64",
  381. "xmm3_f64", "xmm4_f64", "xmm5_f64" };
  382. JitReg i64_arg_regs[6], f32_arg_regs[6], f64_arg_regs[6], res_hreg = 0;
  383. JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax");
  384. JitReg rax_hreg = jit_codegen_get_hreg_by_name("rax");
  385. JitReg xmm0_hreg = jit_codegen_get_hreg_by_name("xmm0");
  386. JitReg xmm0_f64_hreg = jit_codegen_get_hreg_by_name("xmm0_f64");
  387. uint32 i, i64_reg_idx, float_reg_idx;
  388. bh_assert(param_count <= 6);
  389. for (i = 0; i < 6; i++) {
  390. i64_arg_regs[i] = jit_codegen_get_hreg_by_name(i64_arg_names[i]);
  391. f32_arg_regs[i] = jit_codegen_get_hreg_by_name(f32_arg_names[i]);
  392. f64_arg_regs[i] = jit_codegen_get_hreg_by_name(f64_arg_names[i]);
  393. }
  394. i64_reg_idx = float_reg_idx = 0;
  395. for (i = 0; i < param_count; i++) {
  396. switch (jit_reg_kind(params[i])) {
  397. case JIT_REG_KIND_I32:
  398. GEN_INSN(I32TOI64, i64_arg_regs[i64_reg_idx++], params[i]);
  399. break;
  400. case JIT_REG_KIND_I64:
  401. GEN_INSN(MOV, i64_arg_regs[i64_reg_idx++], params[i]);
  402. break;
  403. case JIT_REG_KIND_F32:
  404. GEN_INSN(MOV, f32_arg_regs[float_reg_idx++], params[i]);
  405. break;
  406. case JIT_REG_KIND_F64:
  407. GEN_INSN(MOV, f64_arg_regs[float_reg_idx++], params[i]);
  408. break;
  409. default:
  410. bh_assert(0);
  411. return false;
  412. }
  413. }
  414. if (res) {
  415. switch (jit_reg_kind(res)) {
  416. case JIT_REG_KIND_I32:
  417. res_hreg = eax_hreg;
  418. break;
  419. case JIT_REG_KIND_I64:
  420. res_hreg = rax_hreg;
  421. break;
  422. case JIT_REG_KIND_F32:
  423. res_hreg = xmm0_hreg;
  424. break;
  425. case JIT_REG_KIND_F64:
  426. res_hreg = xmm0_f64_hreg;
  427. break;
  428. default:
  429. bh_assert(0);
  430. return false;
  431. }
  432. }
  433. insn = GEN_INSN(CALLNATIVE, res_hreg,
  434. NEW_CONST(PTR, (uintptr_t)native_func), param_count);
  435. if (!insn) {
  436. return false;
  437. }
  438. i64_reg_idx = float_reg_idx = 0;
  439. for (i = 0; i < param_count; i++) {
  440. switch (jit_reg_kind(params[i])) {
  441. case JIT_REG_KIND_I32:
  442. case JIT_REG_KIND_I64:
  443. *(jit_insn_opndv(insn, i + 2)) = i64_arg_regs[i64_reg_idx++];
  444. break;
  445. case JIT_REG_KIND_F32:
  446. *(jit_insn_opndv(insn, i + 2)) = f32_arg_regs[float_reg_idx++];
  447. break;
  448. case JIT_REG_KIND_F64:
  449. *(jit_insn_opndv(insn, i + 2)) = f64_arg_regs[float_reg_idx++];
  450. break;
  451. default:
  452. bh_assert(0);
  453. return false;
  454. }
  455. }
  456. if (res) {
  457. GEN_INSN(MOV, res, res_hreg);
  458. }
  459. return true;
  460. }
  461. #else
  462. bool
  463. jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res,
  464. JitReg *params, uint32 param_count)
  465. {
  466. JitInsn *insn;
  467. uint32 i;
  468. bh_assert(param_count <= 6);
  469. insn = GEN_INSN(CALLNATIVE, res, NEW_CONST(PTR, (uintptr_t)native_func),
  470. param_count);
  471. if (!insn)
  472. return false;
  473. for (i = 0; i < param_count; i++) {
  474. *(jit_insn_opndv(insn, i + 2)) = params[i];
  475. }
  476. return true;
  477. }
  478. #endif