jit_emit_control.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  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_control.h"
  6. #include "jit_emit_exception.h"
  7. #include "../jit_frontend.h"
  8. #include "../interpreter/wasm_loader.h"
  9. #define CREATE_BASIC_BLOCK(new_basic_block) \
  10. do { \
  11. bh_assert(!new_basic_block); \
  12. if (!(new_basic_block = jit_cc_new_basic_block(cc, 0))) { \
  13. jit_set_last_error(cc, "create basic block failed"); \
  14. goto fail; \
  15. } \
  16. } while (0)
  17. #define CURR_BASIC_BLOCK() cc->cur_basic_block
  18. #define BUILD_BR(target_block) \
  19. do { \
  20. if (!GEN_INSN(JMP, jit_basic_block_label(target_block))) { \
  21. jit_set_last_error(cc, "generate jmp insn failed"); \
  22. goto fail; \
  23. } \
  24. } while (0)
  25. #define BUILD_COND_BR(value_if, block_then, block_else) \
  26. do { \
  27. if (!GEN_INSN(CMP, cc->cmp_reg, value_if, NEW_CONST(cc, 0)) \
  28. || !GEN_INSN(BNE, cc->cmp_reg, jit_basic_block_label(block_then), \
  29. jit_basic_block_label(block_else))) { \
  30. jit_set_last_error(cc, "generate bne insn failed"); \
  31. goto fail; \
  32. } \
  33. } while (0)
  34. #define SET_BUILDER_POS(basic_block) \
  35. do { \
  36. cc->cur_basic_block = basic_block; \
  37. } while (0)
  38. #define SET_BB_BEGIN_BCIP(basic_block, bcip) \
  39. do { \
  40. *(jit_annl_begin_bcip(cc, jit_basic_block_label(basic_block))) = bcip; \
  41. } while (0)
  42. #define SET_BB_END_BCIP(basic_block, bcip) \
  43. do { \
  44. *(jit_annl_end_bcip(cc, jit_basic_block_label(basic_block))) = bcip; \
  45. } while (0)
  46. static JitBlock *
  47. get_target_block(JitCompContext *cc, uint32 br_depth)
  48. {
  49. uint32 i = br_depth;
  50. JitBlock *block = jit_block_stack_top(&cc->block_stack);
  51. while (i-- > 0 && block) {
  52. block = block->prev;
  53. }
  54. if (!block) {
  55. jit_set_last_error(cc, "WASM block stack underflow");
  56. return NULL;
  57. }
  58. return block;
  59. }
  60. static bool
  61. load_block_params(JitCompContext *cc, JitBlock *block)
  62. {
  63. JitFrame *jit_frame = cc->jit_frame;
  64. uint32 offset, i;
  65. JitReg value = 0;
  66. /* Clear jit frame's locals and stacks */
  67. clear_values(jit_frame);
  68. /* Restore jit frame's sp to block's sp begin */
  69. jit_frame->sp = block->frame_sp_begin;
  70. /* Load params to new block */
  71. offset = (uint32)(jit_frame->sp - jit_frame->lp);
  72. for (i = 0; i < block->param_count; i++) {
  73. switch (block->param_types[i]) {
  74. case VALUE_TYPE_I32:
  75. #if WASM_ENABLE_REF_TYPES != 0
  76. case VALUE_TYPE_EXTERNREF:
  77. case VALUE_TYPE_FUNCREF:
  78. #endif
  79. value = gen_load_i32(jit_frame, offset);
  80. offset++;
  81. break;
  82. case VALUE_TYPE_I64:
  83. value = gen_load_i64(jit_frame, offset);
  84. offset += 2;
  85. break;
  86. case VALUE_TYPE_F32:
  87. value = gen_load_f32(jit_frame, offset);
  88. offset++;
  89. break;
  90. case VALUE_TYPE_F64:
  91. value = gen_load_f64(jit_frame, offset);
  92. offset += 2;
  93. break;
  94. default:
  95. bh_assert(0);
  96. break;
  97. }
  98. PUSH(value, block->param_types[i]);
  99. }
  100. return true;
  101. fail:
  102. return false;
  103. }
  104. static bool
  105. load_block_results(JitCompContext *cc, JitBlock *block)
  106. {
  107. JitFrame *jit_frame = cc->jit_frame;
  108. uint32 offset, i;
  109. JitReg value = 0;
  110. /* Restore jit frame's sp to block's sp begin */
  111. jit_frame->sp = block->frame_sp_begin;
  112. /* Load results to new block */
  113. offset = (uint32)(jit_frame->sp - jit_frame->lp);
  114. for (i = 0; i < block->result_count; i++) {
  115. switch (block->result_types[i]) {
  116. case VALUE_TYPE_I32:
  117. #if WASM_ENABLE_REF_TYPES != 0
  118. case VALUE_TYPE_EXTERNREF:
  119. case VALUE_TYPE_FUNCREF:
  120. #endif
  121. value = gen_load_i32(jit_frame, offset);
  122. offset++;
  123. break;
  124. case VALUE_TYPE_I64:
  125. value = gen_load_i64(jit_frame, offset);
  126. offset += 2;
  127. break;
  128. case VALUE_TYPE_F32:
  129. value = gen_load_f32(jit_frame, offset);
  130. offset++;
  131. break;
  132. case VALUE_TYPE_F64:
  133. value = gen_load_f64(jit_frame, offset);
  134. offset += 2;
  135. break;
  136. default:
  137. bh_assert(0);
  138. break;
  139. }
  140. PUSH(value, block->result_types[i]);
  141. }
  142. return true;
  143. fail:
  144. return false;
  145. }
  146. static bool
  147. jit_reg_is_i32_const(JitCompContext *cc, JitReg reg, int32 val)
  148. {
  149. return (jit_reg_kind(reg) == JIT_REG_KIND_I32 && jit_reg_is_const(reg)
  150. && jit_cc_get_const_I32(cc, reg) == val)
  151. ? true
  152. : false;
  153. }
  154. /**
  155. * get the last two insns:
  156. * CMP cmp_reg, r0, r1
  157. * SELECTcc r2, cmp_reg, 1, 0
  158. */
  159. static void
  160. get_last_cmp_and_selectcc(JitCompContext *cc, JitReg cond, JitInsn **p_insn_cmp,
  161. JitInsn **p_insn_select)
  162. {
  163. JitInsn *insn = jit_basic_block_last_insn(cc->cur_basic_block);
  164. if (insn && insn->prev && insn->prev->opcode == JIT_OP_CMP
  165. && insn->opcode >= JIT_OP_SELECTEQ && insn->opcode <= JIT_OP_SELECTLEU
  166. && *jit_insn_opnd(insn, 0) == cond
  167. && jit_reg_is_i32_const(cc, *jit_insn_opnd(insn, 2), 1)
  168. && jit_reg_is_i32_const(cc, *jit_insn_opnd(insn, 3), 0)) {
  169. *p_insn_cmp = insn->prev;
  170. *p_insn_select = insn;
  171. }
  172. }
  173. static bool
  174. push_jit_block_to_stack_and_pass_params(JitCompContext *cc, JitBlock *block,
  175. JitBasicBlock *basic_block, JitReg cond,
  176. bool merge_cmp_and_if)
  177. {
  178. JitFrame *jit_frame = cc->jit_frame;
  179. JitValue *value_list_head = NULL, *value_list_end = NULL, *jit_value;
  180. JitInsn *insn;
  181. JitReg value;
  182. uint32 i, param_index, cell_num;
  183. if (cc->cur_basic_block == basic_block) {
  184. /* Reuse the current basic block and no need to commit values,
  185. we just move param values from current block's value stack to
  186. the new block's value stack */
  187. for (i = 0; i < block->param_count; i++) {
  188. jit_value = jit_value_stack_pop(
  189. &jit_block_stack_top(&cc->block_stack)->value_stack);
  190. if (!value_list_head) {
  191. value_list_head = value_list_end = jit_value;
  192. jit_value->prev = jit_value->next = NULL;
  193. }
  194. else {
  195. jit_value->prev = NULL;
  196. jit_value->next = value_list_head;
  197. value_list_head->prev = jit_value;
  198. value_list_head = jit_value;
  199. }
  200. }
  201. block->value_stack.value_list_head = value_list_head;
  202. block->value_stack.value_list_end = value_list_end;
  203. /* Save block's begin frame sp */
  204. cell_num = wasm_get_cell_num(block->param_types, block->param_count);
  205. block->frame_sp_begin = jit_frame->sp - cell_num;
  206. /* Push the new block to block stack */
  207. jit_block_stack_push(&cc->block_stack, block);
  208. /* Continue to translate current block */
  209. }
  210. else {
  211. JitInsn *insn_select = NULL, *insn_cmp = NULL;
  212. if (merge_cmp_and_if) {
  213. get_last_cmp_and_selectcc(cc, cond, &insn_cmp, &insn_select);
  214. }
  215. /* Commit register values to locals and stacks */
  216. gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp);
  217. /* Pop param values from current block's value stack */
  218. for (i = 0; i < block->param_count; i++) {
  219. param_index = block->param_count - 1 - i;
  220. POP(value, block->param_types[param_index]);
  221. }
  222. /* Clear frame values */
  223. clear_values(jit_frame);
  224. /* Save block's begin frame sp */
  225. block->frame_sp_begin = jit_frame->sp;
  226. /* Push the new block to block stack */
  227. jit_block_stack_push(&cc->block_stack, block);
  228. if (block->label_type == LABEL_TYPE_LOOP) {
  229. BUILD_BR(basic_block);
  230. }
  231. else {
  232. /* IF block with condition br insn */
  233. if (insn_select && insn_cmp) {
  234. /* Change `CMP + SELECTcc` into `CMP + Bcc` */
  235. if (!(insn = GEN_INSN(BEQ, cc->cmp_reg,
  236. jit_basic_block_label(basic_block), 0))) {
  237. jit_set_last_error(cc, "generate cond br failed");
  238. goto fail;
  239. }
  240. insn->opcode =
  241. JIT_OP_BEQ + (insn_select->opcode - JIT_OP_SELECTEQ);
  242. jit_insn_unlink(insn_select);
  243. jit_insn_delete(insn_select);
  244. }
  245. else {
  246. if (!GEN_INSN(CMP, cc->cmp_reg, cond, NEW_CONST(I32, 0))
  247. || !(insn =
  248. GEN_INSN(BNE, cc->cmp_reg,
  249. jit_basic_block_label(basic_block), 0))) {
  250. jit_set_last_error(cc, "generate cond br failed");
  251. goto fail;
  252. }
  253. }
  254. /* Don't create else basic block or end basic block now, just
  255. save its incoming BNE insn, and patch the insn's else label
  256. when the basic block is lazily created */
  257. if (block->wasm_code_else) {
  258. block->incoming_insn_for_else_bb = insn;
  259. }
  260. else {
  261. if (!jit_block_add_incoming_insn(block, insn, 2)) {
  262. jit_set_last_error(cc, "add incoming insn failed");
  263. goto fail;
  264. }
  265. }
  266. }
  267. /* Start to translate the block */
  268. SET_BUILDER_POS(basic_block);
  269. /* Push the block parameters */
  270. if (!load_block_params(cc, block)) {
  271. goto fail;
  272. }
  273. }
  274. return true;
  275. fail:
  276. return false;
  277. }
  278. static void
  279. copy_block_arities(JitCompContext *cc, JitReg dst_frame_sp, uint8 *dst_types,
  280. uint32 dst_type_count, JitReg *p_first_res_reg)
  281. {
  282. JitFrame *jit_frame;
  283. uint32 offset_src, offset_dst, i;
  284. JitReg value;
  285. jit_frame = cc->jit_frame;
  286. offset_src = (uint32)(jit_frame->sp - jit_frame->lp)
  287. - wasm_get_cell_num(dst_types, dst_type_count);
  288. offset_dst = 0;
  289. /* pop values from stack and store to dest frame */
  290. for (i = 0; i < dst_type_count; i++) {
  291. switch (dst_types[i]) {
  292. case VALUE_TYPE_I32:
  293. #if WASM_ENABLE_REF_TYPES != 0
  294. case VALUE_TYPE_EXTERNREF:
  295. case VALUE_TYPE_FUNCREF:
  296. #endif
  297. value = gen_load_i32(jit_frame, offset_src);
  298. if (i == 0 && p_first_res_reg)
  299. *p_first_res_reg = value;
  300. else
  301. GEN_INSN(STI32, value, dst_frame_sp,
  302. NEW_CONST(I32, offset_dst * 4));
  303. offset_src++;
  304. offset_dst++;
  305. break;
  306. case VALUE_TYPE_I64:
  307. value = gen_load_i64(jit_frame, offset_src);
  308. if (i == 0 && p_first_res_reg)
  309. *p_first_res_reg = value;
  310. else
  311. GEN_INSN(STI64, value, dst_frame_sp,
  312. NEW_CONST(I32, offset_dst * 4));
  313. offset_src += 2;
  314. offset_dst += 2;
  315. break;
  316. case VALUE_TYPE_F32:
  317. value = gen_load_f32(jit_frame, offset_src);
  318. if (i == 0 && p_first_res_reg)
  319. *p_first_res_reg = value;
  320. else
  321. GEN_INSN(STF32, value, dst_frame_sp,
  322. NEW_CONST(I32, offset_dst * 4));
  323. offset_src++;
  324. offset_dst++;
  325. break;
  326. case VALUE_TYPE_F64:
  327. value = gen_load_f64(jit_frame, offset_src);
  328. if (i == 0 && p_first_res_reg)
  329. *p_first_res_reg = value;
  330. else
  331. GEN_INSN(STF64, value, dst_frame_sp,
  332. NEW_CONST(I32, offset_dst * 4));
  333. offset_src += 2;
  334. offset_dst += 2;
  335. break;
  336. default:
  337. bh_assert(0);
  338. break;
  339. }
  340. }
  341. }
  342. static void
  343. handle_func_return(JitCompContext *cc, JitBlock *block)
  344. {
  345. JitReg prev_frame, prev_frame_sp;
  346. JitReg ret_reg = 0;
  347. prev_frame = jit_cc_new_reg_ptr(cc);
  348. prev_frame_sp = jit_cc_new_reg_ptr(cc);
  349. /* prev_frame = cur_frame->prev_frame */
  350. GEN_INSN(LDPTR, prev_frame, cc->fp_reg,
  351. NEW_CONST(I32, offsetof(WASMInterpFrame, prev_frame)));
  352. GEN_INSN(LDPTR, prev_frame_sp, prev_frame,
  353. NEW_CONST(I32, offsetof(WASMInterpFrame, sp)));
  354. if (block->result_count) {
  355. uint32 cell_num =
  356. wasm_get_cell_num(block->result_types, block->result_count);
  357. copy_block_arities(cc, prev_frame_sp, block->result_types,
  358. block->result_count, &ret_reg);
  359. /* prev_frame->sp += cell_num */
  360. GEN_INSN(ADD, prev_frame_sp, prev_frame_sp,
  361. NEW_CONST(PTR, cell_num * 4));
  362. GEN_INSN(STPTR, prev_frame_sp, prev_frame,
  363. NEW_CONST(I32, offsetof(WASMInterpFrame, sp)));
  364. }
  365. /* Free stack space of the current frame:
  366. exec_env->wasm_stack.s.top = cur_frame */
  367. GEN_INSN(STPTR, cc->fp_reg, cc->exec_env_reg,
  368. NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top)));
  369. /* Set the prev_frame as the current frame:
  370. exec_env->cur_frame = prev_frame */
  371. GEN_INSN(STPTR, prev_frame, cc->exec_env_reg,
  372. NEW_CONST(I32, offsetof(WASMExecEnv, cur_frame)));
  373. /* fp_reg = prev_frame */
  374. GEN_INSN(MOV, cc->fp_reg, prev_frame);
  375. /* return 0 */
  376. GEN_INSN(RETURNBC, NEW_CONST(I32, JIT_INTERP_ACTION_NORMAL), ret_reg, 0);
  377. }
  378. /**
  379. * is_block_polymorphic: whether current block's stack is in polymorphic state,
  380. * if the opcode is one of unreachable/br/br_table/return, stack is marked
  381. * to polymorphic state until the block's 'end' opcode is processed
  382. */
  383. static bool
  384. handle_op_end(JitCompContext *cc, uint8 **p_frame_ip, bool is_block_polymorphic)
  385. {
  386. JitFrame *jit_frame = cc->jit_frame;
  387. JitBlock *block, *block_prev;
  388. JitIncomingInsn *incoming_insn;
  389. JitInsn *insn;
  390. /* Check block stack */
  391. if (!(block = jit_block_stack_top(&cc->block_stack))) {
  392. jit_set_last_error(cc, "WASM block stack underflow");
  393. return false;
  394. }
  395. if (!block->incoming_insns_for_end_bb) {
  396. /* No other basic blocks jumping to this end, no need to
  397. create the end basic block, just continue to translate
  398. the following opcodes */
  399. if (block->label_type == LABEL_TYPE_FUNCTION) {
  400. handle_func_return(cc, block);
  401. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  402. clear_values(jit_frame);
  403. }
  404. else if (block->result_count > 0) {
  405. JitValue *value_list_head = NULL, *value_list_end = NULL;
  406. JitValue *jit_value;
  407. uint32 i;
  408. /* No need to change cc->jit_frame, just move result values
  409. from current block's value stack to previous block's
  410. value stack */
  411. block_prev = block->prev;
  412. for (i = 0; i < block->result_count; i++) {
  413. jit_value = jit_value_stack_pop(&block->value_stack);
  414. bh_assert(jit_value);
  415. if (!value_list_head) {
  416. value_list_head = value_list_end = jit_value;
  417. jit_value->prev = jit_value->next = NULL;
  418. }
  419. else {
  420. jit_value->prev = NULL;
  421. jit_value->next = value_list_head;
  422. value_list_head->prev = jit_value;
  423. value_list_head = jit_value;
  424. }
  425. }
  426. if (!block_prev->value_stack.value_list_head) {
  427. block_prev->value_stack.value_list_head = value_list_head;
  428. block_prev->value_stack.value_list_end = value_list_end;
  429. }
  430. else {
  431. /* Link to the end of previous block's value stack */
  432. block_prev->value_stack.value_list_end->next = value_list_head;
  433. value_list_head->prev = block_prev->value_stack.value_list_end;
  434. block_prev->value_stack.value_list_end = value_list_end;
  435. }
  436. }
  437. /* Pop block and destroy the block */
  438. block = jit_block_stack_pop(&cc->block_stack);
  439. jit_block_destroy(block);
  440. return true;
  441. }
  442. else {
  443. /* Commit register values to locals and stacks */
  444. gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp);
  445. /* Clear frame values */
  446. clear_values(jit_frame);
  447. /* Create the end basic block */
  448. CREATE_BASIC_BLOCK(block->basic_block_end);
  449. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  450. SET_BB_BEGIN_BCIP(block->basic_block_end, *p_frame_ip);
  451. /* No need to create 'JMP' insn if block is in stack polymorphic
  452. state, as previous br/br_table opcode has created 'JMP' insn
  453. to this end basic block */
  454. if (!is_block_polymorphic) {
  455. /* Jump to the end basic block */
  456. BUILD_BR(block->basic_block_end);
  457. }
  458. /* Patch the INSNs which jump to this basic block */
  459. incoming_insn = block->incoming_insns_for_end_bb;
  460. while (incoming_insn) {
  461. insn = incoming_insn->insn;
  462. bh_assert(
  463. insn->opcode == JIT_OP_JMP
  464. || (insn->opcode >= JIT_OP_BEQ && insn->opcode <= JIT_OP_BLEU)
  465. || insn->opcode == JIT_OP_LOOKUPSWITCH);
  466. if (insn->opcode == JIT_OP_JMP
  467. || (insn->opcode >= JIT_OP_BEQ
  468. && insn->opcode <= JIT_OP_BLEU)) {
  469. *(jit_insn_opnd(insn, incoming_insn->opnd_idx)) =
  470. jit_basic_block_label(block->basic_block_end);
  471. }
  472. else {
  473. /* Patch LOOKUPSWITCH INSN */
  474. JitOpndLookupSwitch *opnd = jit_insn_opndls(insn);
  475. if (incoming_insn->opnd_idx < opnd->match_pairs_num) {
  476. opnd->match_pairs[incoming_insn->opnd_idx].target =
  477. jit_basic_block_label(block->basic_block_end);
  478. }
  479. else {
  480. opnd->default_target =
  481. jit_basic_block_label(block->basic_block_end);
  482. }
  483. }
  484. incoming_insn = incoming_insn->next;
  485. }
  486. SET_BUILDER_POS(block->basic_block_end);
  487. /* Pop block and load block results */
  488. block = jit_block_stack_pop(&cc->block_stack);
  489. if (block->label_type == LABEL_TYPE_FUNCTION) {
  490. handle_func_return(cc, block);
  491. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  492. clear_values(jit_frame);
  493. }
  494. else {
  495. if (!load_block_results(cc, block)) {
  496. jit_block_destroy(block);
  497. goto fail;
  498. }
  499. }
  500. jit_block_destroy(block);
  501. return true;
  502. }
  503. return true;
  504. fail:
  505. return false;
  506. }
  507. /**
  508. * is_block_polymorphic: whether current block's stack is in polymorphic state,
  509. * if the opcode is one of unreachable/br/br_table/return, stack is marked
  510. * to polymorphic state until the block's 'end' opcode is processed
  511. */
  512. static bool
  513. handle_op_else(JitCompContext *cc, uint8 **p_frame_ip,
  514. bool is_block_polymorphic)
  515. {
  516. JitBlock *block = jit_block_stack_top(&cc->block_stack);
  517. JitFrame *jit_frame = cc->jit_frame;
  518. JitInsn *insn;
  519. /* Check block */
  520. if (!block) {
  521. jit_set_last_error(cc, "WASM block stack underflow");
  522. return false;
  523. }
  524. if (block->label_type != LABEL_TYPE_IF) {
  525. jit_set_last_error(cc, "Invalid WASM block type");
  526. return false;
  527. }
  528. if (!block->incoming_insn_for_else_bb) {
  529. /* The if branch is handled like OP_BLOCK (cond is const and != 0),
  530. just skip the else branch and handle OP_END */
  531. *p_frame_ip = block->wasm_code_end + 1;
  532. return handle_op_end(cc, p_frame_ip, false);
  533. }
  534. else {
  535. /* Has else branch and need to translate else branch */
  536. /* Commit register values to locals and stacks */
  537. gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp);
  538. /* Clear frame values */
  539. clear_values(jit_frame);
  540. /* No need to create 'JMP' insn if block is in stack polymorphic
  541. state, as previous br/br_table opcode has created 'JMP' insn
  542. to this end basic block */
  543. if (!is_block_polymorphic) {
  544. /* Jump to end basic block */
  545. if (!(insn = GEN_INSN(JMP, 0))) {
  546. jit_set_last_error(cc, "generate jmp insn failed");
  547. return false;
  548. }
  549. if (!jit_block_add_incoming_insn(block, insn, 0)) {
  550. jit_set_last_error(cc, "add incoming insn failed");
  551. return false;
  552. }
  553. }
  554. /* Clear value stack, restore param values and
  555. start to translate the else branch. */
  556. jit_value_stack_destroy(&block->value_stack);
  557. /* create else basic block */
  558. CREATE_BASIC_BLOCK(block->basic_block_else);
  559. SET_BB_END_BCIP(block->basic_block_entry, *p_frame_ip - 1);
  560. SET_BB_BEGIN_BCIP(block->basic_block_else, *p_frame_ip);
  561. /* Patch the insn which conditionly jumps to the else basic block */
  562. insn = block->incoming_insn_for_else_bb;
  563. *(jit_insn_opnd(insn, 2)) =
  564. jit_basic_block_label(block->basic_block_else);
  565. SET_BUILDER_POS(block->basic_block_else);
  566. /* Reload block parameters */
  567. if (!load_block_params(cc, block)) {
  568. return false;
  569. }
  570. return true;
  571. }
  572. return true;
  573. fail:
  574. return false;
  575. }
  576. static bool
  577. handle_next_reachable_block(JitCompContext *cc, uint8 **p_frame_ip)
  578. {
  579. JitBlock *block = jit_block_stack_top(&cc->block_stack);
  580. bh_assert(block);
  581. do {
  582. if (block->label_type == LABEL_TYPE_IF
  583. && block->incoming_insn_for_else_bb
  584. && *p_frame_ip <= block->wasm_code_else) {
  585. /* Else branch hasn't been translated,
  586. start to translate the else branch */
  587. *p_frame_ip = block->wasm_code_else + 1;
  588. /* Restore jit frame's sp to block's sp begin */
  589. cc->jit_frame->sp = block->frame_sp_begin;
  590. return handle_op_else(cc, p_frame_ip, true);
  591. }
  592. else if (block->incoming_insns_for_end_bb) {
  593. *p_frame_ip = block->wasm_code_end + 1;
  594. /* Restore jit frame's sp to block's sp end */
  595. cc->jit_frame->sp =
  596. block->frame_sp_begin
  597. + wasm_get_cell_num(block->result_types, block->result_count);
  598. return handle_op_end(cc, p_frame_ip, true);
  599. }
  600. else {
  601. *p_frame_ip = block->wasm_code_end + 1;
  602. jit_block_stack_pop(&cc->block_stack);
  603. jit_block_destroy(block);
  604. block = jit_block_stack_top(&cc->block_stack);
  605. }
  606. } while (block != NULL);
  607. return true;
  608. }
  609. bool
  610. jit_compile_op_block(JitCompContext *cc, uint8 **p_frame_ip,
  611. uint8 *frame_ip_end, uint32 label_type, uint32 param_count,
  612. uint8 *param_types, uint32 result_count,
  613. uint8 *result_types, bool merge_cmp_and_if)
  614. {
  615. BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE];
  616. JitBlock *block;
  617. JitReg value;
  618. uint8 *else_addr, *end_addr;
  619. /* Check block stack */
  620. if (!jit_block_stack_top(&cc->block_stack)) {
  621. jit_set_last_error(cc, "WASM block stack underflow");
  622. return false;
  623. }
  624. memset(block_addr_cache, 0, sizeof(block_addr_cache));
  625. /* Get block info */
  626. if (!(wasm_loader_find_block_addr(
  627. NULL, (BlockAddr *)block_addr_cache, *p_frame_ip, frame_ip_end,
  628. (uint8)label_type, &else_addr, &end_addr))) {
  629. jit_set_last_error(cc, "find block end addr failed");
  630. return false;
  631. }
  632. /* Allocate memory */
  633. if (!(block = jit_calloc(sizeof(JitBlock)))) {
  634. jit_set_last_error(cc, "allocate memory failed");
  635. return false;
  636. }
  637. if (param_count && !(block->param_types = jit_calloc(param_count))) {
  638. jit_set_last_error(cc, "allocate memory failed");
  639. goto fail;
  640. }
  641. if (result_count && !(block->result_types = jit_calloc(result_count))) {
  642. jit_set_last_error(cc, "allocate memory failed");
  643. goto fail;
  644. }
  645. /* Initialize block data */
  646. block->label_type = label_type;
  647. block->param_count = param_count;
  648. if (param_count) {
  649. bh_memcpy_s(block->param_types, param_count, param_types, param_count);
  650. }
  651. block->result_count = result_count;
  652. if (result_count) {
  653. bh_memcpy_s(block->result_types, result_count, result_types,
  654. result_count);
  655. }
  656. block->wasm_code_else = else_addr;
  657. block->wasm_code_end = end_addr;
  658. if (label_type == LABEL_TYPE_BLOCK) {
  659. /* Push the new jit block to block stack and continue to
  660. translate current basic block */
  661. if (!push_jit_block_to_stack_and_pass_params(
  662. cc, block, cc->cur_basic_block, 0, false))
  663. goto fail;
  664. }
  665. else if (label_type == LABEL_TYPE_LOOP) {
  666. CREATE_BASIC_BLOCK(block->basic_block_entry);
  667. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  668. SET_BB_BEGIN_BCIP(block->basic_block_entry, *p_frame_ip);
  669. /* Push the new jit block to block stack and continue to
  670. translate the new basic block */
  671. if (!push_jit_block_to_stack_and_pass_params(
  672. cc, block, block->basic_block_entry, 0, false))
  673. goto fail;
  674. }
  675. else if (label_type == LABEL_TYPE_IF) {
  676. POP_I32(value);
  677. if (!jit_reg_is_const_val(value)) {
  678. /* Compare value is not constant, create condition br IR */
  679. /* Create entry block */
  680. CREATE_BASIC_BLOCK(block->basic_block_entry);
  681. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  682. SET_BB_BEGIN_BCIP(block->basic_block_entry, *p_frame_ip);
  683. if (!push_jit_block_to_stack_and_pass_params(
  684. cc, block, block->basic_block_entry, value,
  685. merge_cmp_and_if))
  686. goto fail;
  687. }
  688. else {
  689. if (jit_cc_get_const_I32(cc, value) != 0) {
  690. /* Compare value is not 0, condition is true, else branch of
  691. BASIC_BLOCK if cannot be reached, we treat it same as
  692. LABEL_TYPE_BLOCK and start to translate if branch */
  693. if (!push_jit_block_to_stack_and_pass_params(
  694. cc, block, cc->cur_basic_block, 0, false))
  695. goto fail;
  696. }
  697. else {
  698. if (else_addr) {
  699. /* Compare value is not 0, condition is false, if branch of
  700. BASIC_BLOCK if cannot be reached, we treat it same as
  701. LABEL_TYPE_BLOCK and start to translate else branch */
  702. if (!push_jit_block_to_stack_and_pass_params(
  703. cc, block, cc->cur_basic_block, 0, false))
  704. goto fail;
  705. *p_frame_ip = else_addr + 1;
  706. }
  707. else {
  708. /* The whole if block cannot be reached, skip it */
  709. jit_block_destroy(block);
  710. *p_frame_ip = end_addr + 1;
  711. }
  712. }
  713. }
  714. }
  715. else {
  716. jit_set_last_error(cc, "Invalid block type");
  717. goto fail;
  718. }
  719. return true;
  720. fail:
  721. jit_block_destroy(block);
  722. return false;
  723. }
  724. bool
  725. jit_compile_op_else(JitCompContext *cc, uint8 **p_frame_ip)
  726. {
  727. return handle_op_else(cc, p_frame_ip, false);
  728. }
  729. bool
  730. jit_compile_op_end(JitCompContext *cc, uint8 **p_frame_ip)
  731. {
  732. return handle_op_end(cc, p_frame_ip, false);
  733. }
  734. /* Check whether need to copy arities when jumping from current block
  735. to the dest block */
  736. static bool
  737. check_copy_arities(const JitBlock *block_dst, JitFrame *jit_frame)
  738. {
  739. JitValueSlot *frame_sp_src = NULL;
  740. if (block_dst->label_type == LABEL_TYPE_LOOP) {
  741. frame_sp_src =
  742. jit_frame->sp
  743. - wasm_get_cell_num(block_dst->param_types, block_dst->param_count);
  744. /* There are parameters to copy and the src/dst addr are different */
  745. return (block_dst->param_count > 0
  746. && block_dst->frame_sp_begin != frame_sp_src)
  747. ? true
  748. : false;
  749. }
  750. else {
  751. frame_sp_src = jit_frame->sp
  752. - wasm_get_cell_num(block_dst->result_types,
  753. block_dst->result_count);
  754. /* There are results to copy and the src/dst addr are different */
  755. return (block_dst->result_count > 0
  756. && block_dst->frame_sp_begin != frame_sp_src)
  757. ? true
  758. : false;
  759. }
  760. }
  761. static bool
  762. handle_op_br(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip)
  763. {
  764. JitFrame *jit_frame;
  765. JitBlock *block_dst, *block;
  766. JitReg frame_sp_dst;
  767. JitInsn *insn;
  768. bool copy_arities;
  769. uint32 offset;
  770. /* Check block stack */
  771. if (!(block = jit_block_stack_top(&cc->block_stack))) {
  772. jit_set_last_error(cc, "WASM block stack underflow");
  773. return false;
  774. }
  775. if (!(block_dst = get_target_block(cc, br_depth))) {
  776. return false;
  777. }
  778. jit_frame = cc->jit_frame;
  779. /* Only opy parameters or results when their count > 0 and
  780. the src/dst addr are different */
  781. copy_arities = check_copy_arities(block_dst, jit_frame);
  782. if (copy_arities) {
  783. frame_sp_dst = jit_cc_new_reg_ptr(cc);
  784. offset = offsetof(WASMInterpFrame, lp)
  785. + (block_dst->frame_sp_begin - jit_frame->lp) * 4;
  786. GEN_INSN(ADD, frame_sp_dst, cc->fp_reg, NEW_CONST(PTR, offset));
  787. /* No need to commit results as they will be copied to dest block */
  788. gen_commit_values(jit_frame, jit_frame->lp, block->frame_sp_begin);
  789. }
  790. else {
  791. /* Commit all including results as they won't be copied */
  792. gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp);
  793. }
  794. if (block_dst->label_type == LABEL_TYPE_LOOP) {
  795. if (copy_arities) {
  796. /* Dest block is Loop block, copy loop parameters */
  797. copy_block_arities(cc, frame_sp_dst, block_dst->param_types,
  798. block_dst->param_count, NULL);
  799. }
  800. clear_values(jit_frame);
  801. /* Jump to the begin basic block */
  802. BUILD_BR(block_dst->basic_block_entry);
  803. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  804. }
  805. else {
  806. if (copy_arities) {
  807. /* Dest block is Block/If/Function block, copy block results */
  808. copy_block_arities(cc, frame_sp_dst, block_dst->result_types,
  809. block_dst->result_count, NULL);
  810. }
  811. clear_values(jit_frame);
  812. /* Jump to the end basic block */
  813. if (!(insn = GEN_INSN(JMP, 0))) {
  814. jit_set_last_error(cc, "generate jmp insn failed");
  815. goto fail;
  816. }
  817. if (!jit_block_add_incoming_insn(block_dst, insn, 0)) {
  818. jit_set_last_error(cc, "add incoming insn failed");
  819. goto fail;
  820. }
  821. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  822. }
  823. return true;
  824. fail:
  825. return false;
  826. }
  827. bool
  828. jit_compile_op_br(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip)
  829. {
  830. return handle_op_br(cc, br_depth, p_frame_ip)
  831. && handle_next_reachable_block(cc, p_frame_ip);
  832. }
  833. static JitFrame *
  834. jit_frame_clone(const JitFrame *jit_frame)
  835. {
  836. JitFrame *jit_frame_cloned;
  837. uint32 max_locals = jit_frame->max_locals;
  838. uint32 max_stacks = jit_frame->max_stacks;
  839. uint32 total_size;
  840. total_size = (uint32)(offsetof(JitFrame, lp)
  841. + sizeof(*jit_frame->lp) * (max_locals + max_stacks));
  842. jit_frame_cloned = jit_calloc(total_size);
  843. if (jit_frame_cloned) {
  844. bh_memcpy_s(jit_frame_cloned, total_size, jit_frame, total_size);
  845. jit_frame_cloned->sp =
  846. jit_frame_cloned->lp + (jit_frame->sp - jit_frame->lp);
  847. }
  848. return jit_frame_cloned;
  849. }
  850. static void
  851. jit_frame_copy(JitFrame *jit_frame_dst, const JitFrame *jit_frame_src)
  852. {
  853. uint32 max_locals = jit_frame_src->max_locals;
  854. uint32 max_stacks = jit_frame_src->max_stacks;
  855. uint32 total_size;
  856. total_size =
  857. (uint32)(offsetof(JitFrame, lp)
  858. + sizeof(*jit_frame_src->lp) * (max_locals + max_stacks));
  859. bh_memcpy_s(jit_frame_dst, total_size, jit_frame_src, total_size);
  860. jit_frame_dst->sp =
  861. jit_frame_dst->lp + (jit_frame_src->sp - jit_frame_src->lp);
  862. }
  863. bool
  864. jit_compile_op_br_if(JitCompContext *cc, uint32 br_depth,
  865. bool merge_cmp_and_br_if, uint8 **p_frame_ip)
  866. {
  867. JitFrame *jit_frame, *jit_frame_cloned;
  868. JitBlock *block_dst;
  869. JitReg cond;
  870. JitBasicBlock *cur_basic_block, *if_basic_block = NULL;
  871. JitInsn *insn, *insn_select = NULL, *insn_cmp = NULL;
  872. bool copy_arities;
  873. if (!(block_dst = get_target_block(cc, br_depth))) {
  874. return false;
  875. }
  876. /* append IF to current basic block */
  877. POP_I32(cond);
  878. if (merge_cmp_and_br_if) {
  879. get_last_cmp_and_selectcc(cc, cond, &insn_cmp, &insn_select);
  880. }
  881. jit_frame = cc->jit_frame;
  882. cur_basic_block = cc->cur_basic_block;
  883. gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp);
  884. if (!(insn_select && insn_cmp)) {
  885. if (!GEN_INSN(CMP, cc->cmp_reg, cond, NEW_CONST(I32, 0))) {
  886. jit_set_last_error(cc, "generate cmp insn failed");
  887. goto fail;
  888. }
  889. }
  890. /* Only opy parameters or results when their count > 0 and
  891. the src/dst addr are different */
  892. copy_arities = check_copy_arities(block_dst, jit_frame);
  893. if (!copy_arities) {
  894. if (block_dst->label_type == LABEL_TYPE_LOOP) {
  895. if (!(insn = GEN_INSN(
  896. BNE, cc->cmp_reg,
  897. jit_basic_block_label(block_dst->basic_block_entry),
  898. 0))) {
  899. jit_set_last_error(cc, "generate bne insn failed");
  900. goto fail;
  901. }
  902. }
  903. else {
  904. if (!(insn = GEN_INSN(BNE, cc->cmp_reg, 0, 0))) {
  905. jit_set_last_error(cc, "generate bne insn failed");
  906. goto fail;
  907. }
  908. if (!jit_block_add_incoming_insn(block_dst, insn, 1)) {
  909. jit_set_last_error(cc, "add incoming insn failed");
  910. goto fail;
  911. }
  912. }
  913. if (insn_select && insn_cmp) {
  914. /* Change `CMP + SELECTcc` into `CMP + Bcc` */
  915. insn->opcode = JIT_OP_BEQ + (insn_select->opcode - JIT_OP_SELECTEQ);
  916. jit_insn_unlink(insn_select);
  917. jit_insn_delete(insn_select);
  918. }
  919. return true;
  920. }
  921. CREATE_BASIC_BLOCK(if_basic_block);
  922. if (!(insn = GEN_INSN(BNE, cc->cmp_reg,
  923. jit_basic_block_label(if_basic_block), 0))) {
  924. jit_set_last_error(cc, "generate bne insn failed");
  925. goto fail;
  926. }
  927. if (insn_select && insn_cmp) {
  928. /* Change `CMP + SELECTcc` into `CMP + Bcc` */
  929. insn->opcode = JIT_OP_BEQ + (insn_select->opcode - JIT_OP_SELECTEQ);
  930. jit_insn_unlink(insn_select);
  931. jit_insn_delete(insn_select);
  932. }
  933. SET_BUILDER_POS(if_basic_block);
  934. SET_BB_BEGIN_BCIP(if_basic_block, *p_frame_ip - 1);
  935. /* Clone current jit frame to a new jit fame */
  936. if (!(jit_frame_cloned = jit_frame_clone(jit_frame))) {
  937. jit_set_last_error(cc, "allocate memory failed");
  938. goto fail;
  939. }
  940. /* Clear current jit frame so that the registers
  941. in the new basic block will be loaded again */
  942. clear_values(jit_frame);
  943. if (!handle_op_br(cc, br_depth, p_frame_ip)) {
  944. jit_free(jit_frame_cloned);
  945. goto fail;
  946. }
  947. /* Restore the jit frame so that the registers can
  948. be used again in current basic block */
  949. jit_frame_copy(jit_frame, jit_frame_cloned);
  950. jit_free(jit_frame_cloned);
  951. /* Continue processing opcodes after BR_IF */
  952. SET_BUILDER_POS(cur_basic_block);
  953. return true;
  954. fail:
  955. return false;
  956. }
  957. bool
  958. jit_compile_op_br_table(JitCompContext *cc, uint32 *br_depths, uint32 br_count,
  959. uint8 **p_frame_ip)
  960. {
  961. JitBasicBlock *cur_basic_block;
  962. JitReg value;
  963. JitInsn *insn;
  964. uint32 i = 0;
  965. JitOpndLookupSwitch *opnd = NULL;
  966. cur_basic_block = cc->cur_basic_block;
  967. POP_I32(value);
  968. /* append LOOKUPSWITCH to current basic block */
  969. gen_commit_values(cc->jit_frame, cc->jit_frame->lp, cc->jit_frame->sp);
  970. /* Clear frame values */
  971. clear_values(cc->jit_frame);
  972. SET_BB_END_BCIP(cur_basic_block, *p_frame_ip - 1);
  973. /* prepare basic blocks for br */
  974. insn = GEN_INSN(LOOKUPSWITCH, value, br_count);
  975. if (NULL == insn) {
  976. jit_set_last_error(cc, "generate insn LOOKUPSWITCH failed");
  977. goto fail;
  978. }
  979. for (i = 0, opnd = jit_insn_opndls(insn); i < br_count + 1; i++) {
  980. JitBasicBlock *basic_block = NULL;
  981. JitBlock *block_dst;
  982. bool copy_arities;
  983. if (!(block_dst = get_target_block(cc, br_depths[i]))) {
  984. goto fail;
  985. }
  986. /* Only opy parameters or results when their count > 0 and
  987. the src/dst addr are different */
  988. copy_arities = check_copy_arities(block_dst, cc->jit_frame);
  989. if (!copy_arities) {
  990. /* No need to create new basic block, direclty jump to
  991. the existing basic block when no need to copy arities */
  992. if (i == br_count) {
  993. if (block_dst->label_type == LABEL_TYPE_LOOP) {
  994. opnd->default_target =
  995. jit_basic_block_label(block_dst->basic_block_entry);
  996. }
  997. else {
  998. bh_assert(!block_dst->basic_block_end);
  999. if (!jit_block_add_incoming_insn(block_dst, insn, i)) {
  1000. jit_set_last_error(cc, "add incoming insn failed");
  1001. goto fail;
  1002. }
  1003. }
  1004. }
  1005. else {
  1006. opnd->match_pairs[i].value = i;
  1007. if (block_dst->label_type == LABEL_TYPE_LOOP) {
  1008. opnd->match_pairs[i].target =
  1009. jit_basic_block_label(block_dst->basic_block_entry);
  1010. }
  1011. else {
  1012. bh_assert(!block_dst->basic_block_end);
  1013. if (!jit_block_add_incoming_insn(block_dst, insn, i)) {
  1014. jit_set_last_error(cc, "add incoming insn failed");
  1015. goto fail;
  1016. }
  1017. }
  1018. }
  1019. continue;
  1020. }
  1021. /* Create new basic block when need to copy arities */
  1022. CREATE_BASIC_BLOCK(basic_block);
  1023. SET_BB_BEGIN_BCIP(basic_block, *p_frame_ip - 1);
  1024. if (i == br_count) {
  1025. opnd->default_target = jit_basic_block_label(basic_block);
  1026. }
  1027. else {
  1028. opnd->match_pairs[i].value = i;
  1029. opnd->match_pairs[i].target = jit_basic_block_label(basic_block);
  1030. }
  1031. SET_BUILDER_POS(basic_block);
  1032. if (!handle_op_br(cc, br_depths[i], p_frame_ip))
  1033. goto fail;
  1034. }
  1035. /* Search next available block to handle */
  1036. return handle_next_reachable_block(cc, p_frame_ip);
  1037. fail:
  1038. return false;
  1039. }
  1040. bool
  1041. jit_compile_op_return(JitCompContext *cc, uint8 **p_frame_ip)
  1042. {
  1043. JitBlock *block_func = cc->block_stack.block_list_head;
  1044. bh_assert(block_func);
  1045. handle_func_return(cc, block_func);
  1046. SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1);
  1047. clear_values(cc->jit_frame);
  1048. return handle_next_reachable_block(cc, p_frame_ip);
  1049. }
  1050. bool
  1051. jit_compile_op_unreachable(JitCompContext *cc, uint8 **p_frame_ip)
  1052. {
  1053. if (!jit_emit_exception(cc, JIT_EXCE_UNREACHABLE, JIT_OP_JMP, 0, NULL))
  1054. return false;
  1055. return handle_next_reachable_block(cc, p_frame_ip);
  1056. }
  1057. bool
  1058. jit_handle_next_reachable_block(JitCompContext *cc, uint8 **p_frame_ip)
  1059. {
  1060. return handle_next_reachable_block(cc, p_frame_ip);
  1061. }