aot_emit_table.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_emit_table.h"
  6. #include "aot_emit_exception.h"
  7. #include "../aot/aot_runtime.h"
  8. uint64
  9. get_tbl_inst_offset(const AOTCompContext *comp_ctx,
  10. const AOTFuncContext *func_ctx, uint32 tbl_idx)
  11. {
  12. uint64 offset = 0, i = 0;
  13. AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables;
  14. AOTTable *tbls = comp_ctx->comp_data->tables;
  15. offset =
  16. offsetof(AOTModuleInstance, global_table_data.bytes)
  17. + (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance)
  18. + comp_ctx->comp_data->global_data_size;
  19. while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
  20. offset += offsetof(AOTTableInstance, elems);
  21. /* avoid loading from current AOTTableInstance */
  22. offset +=
  23. sizeof(uint32)
  24. * aot_get_imp_tbl_data_slots(imp_tbls + i, comp_ctx->is_jit_mode);
  25. ++i;
  26. }
  27. if (i == tbl_idx) {
  28. return offset;
  29. }
  30. tbl_idx -= comp_ctx->comp_data->import_table_count;
  31. i -= comp_ctx->comp_data->import_table_count;
  32. while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
  33. offset += offsetof(AOTTableInstance, elems);
  34. /* avoid loading from current AOTTableInstance */
  35. offset += sizeof(uint32)
  36. * aot_get_tbl_data_slots(tbls + i, comp_ctx->is_jit_mode);
  37. ++i;
  38. }
  39. return offset;
  40. }
  41. #if WASM_ENABLE_REF_TYPES != 0
  42. LLVMValueRef
  43. aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  44. uint32 tbl_idx)
  45. {
  46. LLVMValueRef offset, tbl_inst;
  47. if (!(offset =
  48. I64_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)))) {
  49. HANDLE_FAILURE("LLVMConstInt");
  50. goto fail;
  51. }
  52. if (!(tbl_inst = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  53. func_ctx->aot_inst, &offset, 1,
  54. "tbl_inst"))) {
  55. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  56. goto fail;
  57. }
  58. return tbl_inst;
  59. fail:
  60. return NULL;
  61. }
  62. bool
  63. aot_compile_op_elem_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  64. uint32 tbl_seg_idx)
  65. {
  66. LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
  67. LLVMValueRef param_values[2], ret_value, func, value;
  68. /* void aot_drop_table_seg(AOTModuleInstance *, uint32 ) */
  69. param_types[0] = INT8_PTR_TYPE;
  70. param_types[1] = I32_TYPE;
  71. ret_type = VOID_TYPE;
  72. if (comp_ctx->is_jit_mode)
  73. GET_AOT_FUNCTION(llvm_jit_drop_table_seg, 2);
  74. else
  75. GET_AOT_FUNCTION(aot_drop_table_seg, 2);
  76. param_values[0] = func_ctx->aot_inst;
  77. if (!(param_values[1] = I32_CONST(tbl_seg_idx))) {
  78. HANDLE_FAILURE("LLVMConstInt");
  79. goto fail;
  80. }
  81. /* "" means return void */
  82. if (!(ret_value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
  83. param_values, 2, ""))) {
  84. HANDLE_FAILURE("LLVMBuildCall");
  85. goto fail;
  86. }
  87. return true;
  88. fail:
  89. return false;
  90. }
  91. static bool
  92. aot_check_table_access(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  93. uint32 tbl_idx, LLVMValueRef elem_idx)
  94. {
  95. LLVMValueRef offset, tbl_sz, cmp_elem_idx;
  96. LLVMBasicBlockRef check_elem_idx_succ;
  97. /* get the cur size of the table instance */
  98. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  99. + offsetof(AOTTableInstance, cur_size)))) {
  100. HANDLE_FAILURE("LLVMConstInt");
  101. goto fail;
  102. }
  103. if (!(tbl_sz = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  104. func_ctx->aot_inst, &offset, 1,
  105. "cur_size_i8p"))) {
  106. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  107. goto fail;
  108. }
  109. if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
  110. "cur_siuze_i32p"))) {
  111. HANDLE_FAILURE("LLVMBuildBitCast");
  112. goto fail;
  113. }
  114. if (!(tbl_sz = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, tbl_sz,
  115. "cur_size"))) {
  116. HANDLE_FAILURE("LLVMBuildLoad");
  117. goto fail;
  118. }
  119. /* Check if (uint32)elem index >= table size */
  120. if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
  121. tbl_sz, "cmp_elem_idx"))) {
  122. aot_set_last_error("llvm build icmp failed.");
  123. goto fail;
  124. }
  125. /* Throw exception if elem index >= table size */
  126. if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
  127. comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
  128. aot_set_last_error("llvm add basic block failed.");
  129. goto fail;
  130. }
  131. LLVMMoveBasicBlockAfter(check_elem_idx_succ,
  132. LLVMGetInsertBlock(comp_ctx->builder));
  133. if (!(aot_emit_exception(comp_ctx, func_ctx,
  134. EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true,
  135. cmp_elem_idx, check_elem_idx_succ)))
  136. goto fail;
  137. return true;
  138. fail:
  139. return false;
  140. }
  141. bool
  142. aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  143. uint32 tbl_idx)
  144. {
  145. LLVMValueRef elem_idx, offset, table_elem, func_idx;
  146. POP_I32(elem_idx);
  147. if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
  148. goto fail;
  149. }
  150. /* load data as i32* */
  151. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  152. + offsetof(AOTTableInstance, elems)))) {
  153. HANDLE_FAILURE("LLVMConstInt");
  154. goto fail;
  155. }
  156. if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  157. func_ctx->aot_inst, &offset, 1,
  158. "table_elem_i8p"))) {
  159. aot_set_last_error("llvm build add failed.");
  160. goto fail;
  161. }
  162. if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
  163. INT32_PTR_TYPE, "table_elem_i32p"))) {
  164. HANDLE_FAILURE("LLVMBuildBitCast");
  165. goto fail;
  166. }
  167. /* Load function index */
  168. if (!(table_elem =
  169. LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
  170. &elem_idx, 1, "table_elem"))) {
  171. HANDLE_FAILURE("LLVMBuildNUWAdd");
  172. goto fail;
  173. }
  174. if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, table_elem,
  175. "func_idx"))) {
  176. HANDLE_FAILURE("LLVMBuildLoad");
  177. goto fail;
  178. }
  179. PUSH_I32(func_idx);
  180. return true;
  181. fail:
  182. return false;
  183. }
  184. bool
  185. aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  186. uint32 tbl_idx)
  187. {
  188. LLVMValueRef val, elem_idx, offset, table_elem;
  189. POP_I32(val);
  190. POP_I32(elem_idx);
  191. if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
  192. goto fail;
  193. }
  194. /* load data as i32* */
  195. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  196. + offsetof(AOTTableInstance, elems)))) {
  197. HANDLE_FAILURE("LLVMConstInt");
  198. goto fail;
  199. }
  200. if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  201. func_ctx->aot_inst, &offset, 1,
  202. "table_elem_i8p"))) {
  203. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  204. goto fail;
  205. }
  206. if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
  207. INT32_PTR_TYPE, "table_elem_i32p"))) {
  208. HANDLE_FAILURE("LLVMBuildBitCast");
  209. goto fail;
  210. }
  211. /* Load function index */
  212. if (!(table_elem =
  213. LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
  214. &elem_idx, 1, "table_elem"))) {
  215. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  216. goto fail;
  217. }
  218. if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
  219. HANDLE_FAILURE("LLVMBuildStore");
  220. goto fail;
  221. }
  222. return true;
  223. fail:
  224. return false;
  225. }
  226. bool
  227. aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  228. uint32 tbl_idx, uint32 tbl_seg_idx)
  229. {
  230. LLVMValueRef func, param_values[6], value;
  231. LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
  232. param_types[0] = INT8_PTR_TYPE;
  233. param_types[1] = I32_TYPE;
  234. param_types[2] = I32_TYPE;
  235. param_types[3] = I32_TYPE;
  236. param_types[4] = I32_TYPE;
  237. param_types[5] = I32_TYPE;
  238. ret_type = VOID_TYPE;
  239. if (comp_ctx->is_jit_mode)
  240. GET_AOT_FUNCTION(llvm_jit_table_init, 6);
  241. else
  242. GET_AOT_FUNCTION(aot_table_init, 6);
  243. param_values[0] = func_ctx->aot_inst;
  244. if (!(param_values[1] = I32_CONST(tbl_idx))) {
  245. HANDLE_FAILURE("LLVMConstInt");
  246. goto fail;
  247. }
  248. if (!(param_values[2] = I32_CONST(tbl_seg_idx))) {
  249. HANDLE_FAILURE("LLVMConstInt");
  250. goto fail;
  251. }
  252. /* n */
  253. POP_I32(param_values[3]);
  254. /* s */
  255. POP_I32(param_values[4]);
  256. /* d */
  257. POP_I32(param_values[5]);
  258. /* "" means return void */
  259. if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
  260. ""))) {
  261. HANDLE_FAILURE("LLVMBuildCall");
  262. goto fail;
  263. }
  264. return true;
  265. fail:
  266. return false;
  267. }
  268. bool
  269. aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  270. uint32 src_tbl_idx, uint32 dst_tbl_idx)
  271. {
  272. LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
  273. LLVMValueRef func, param_values[6], value;
  274. param_types[0] = INT8_PTR_TYPE;
  275. param_types[1] = I32_TYPE;
  276. param_types[2] = I32_TYPE;
  277. param_types[3] = I32_TYPE;
  278. param_types[4] = I32_TYPE;
  279. param_types[5] = I32_TYPE;
  280. ret_type = VOID_TYPE;
  281. if (comp_ctx->is_jit_mode)
  282. GET_AOT_FUNCTION(llvm_jit_table_copy, 6);
  283. else
  284. GET_AOT_FUNCTION(aot_table_copy, 6);
  285. param_values[0] = func_ctx->aot_inst;
  286. if (!(param_values[1] = I32_CONST(src_tbl_idx))) {
  287. HANDLE_FAILURE("LLVMConstInt");
  288. goto fail;
  289. }
  290. if (!(param_values[2] = I32_CONST(dst_tbl_idx))) {
  291. HANDLE_FAILURE("LLVMConstInt");
  292. goto fail;
  293. }
  294. /* n */
  295. POP_I32(param_values[3]);
  296. /* s */
  297. POP_I32(param_values[4]);
  298. /* d */
  299. POP_I32(param_values[5]);
  300. /* "" means return void */
  301. if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
  302. ""))) {
  303. HANDLE_FAILURE("LLVMBuildCall");
  304. goto fail;
  305. }
  306. return true;
  307. fail:
  308. return false;
  309. }
  310. bool
  311. aot_compile_op_table_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  312. uint32 tbl_idx)
  313. {
  314. LLVMValueRef offset, tbl_sz;
  315. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  316. + offsetof(AOTTableInstance, cur_size)))) {
  317. HANDLE_FAILURE("LLVMConstInt");
  318. goto fail;
  319. }
  320. if (!(tbl_sz = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  321. func_ctx->aot_inst, &offset, 1,
  322. "tbl_sz_ptr_i8"))) {
  323. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  324. goto fail;
  325. }
  326. if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
  327. "tbl_sz_ptr"))) {
  328. HANDLE_FAILURE("LLVMBuildBitCast");
  329. goto fail;
  330. }
  331. if (!(tbl_sz =
  332. LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, tbl_sz, "tbl_sz"))) {
  333. HANDLE_FAILURE("LLVMBuildLoad");
  334. goto fail;
  335. }
  336. PUSH_I32(tbl_sz);
  337. return true;
  338. fail:
  339. return false;
  340. }
  341. bool
  342. aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  343. uint32 tbl_idx)
  344. {
  345. LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
  346. LLVMValueRef func, param_values[4], ret, value;
  347. param_types[0] = INT8_PTR_TYPE;
  348. param_types[1] = I32_TYPE;
  349. param_types[2] = I32_TYPE;
  350. param_types[3] = I32_TYPE;
  351. ret_type = I32_TYPE;
  352. if (comp_ctx->is_jit_mode)
  353. GET_AOT_FUNCTION(llvm_jit_table_grow, 4);
  354. else
  355. GET_AOT_FUNCTION(aot_table_grow, 4);
  356. param_values[0] = func_ctx->aot_inst;
  357. if (!(param_values[1] = I32_CONST(tbl_idx))) {
  358. HANDLE_FAILURE("LLVMConstInt");
  359. goto fail;
  360. }
  361. /* n */
  362. POP_I32(param_values[2]);
  363. /* v */
  364. POP_I32(param_values[3]);
  365. if (!(ret = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
  366. 4, "table_grow"))) {
  367. HANDLE_FAILURE("LLVMBuildCall");
  368. goto fail;
  369. }
  370. PUSH_I32(ret);
  371. return true;
  372. fail:
  373. return false;
  374. }
  375. bool
  376. aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  377. uint32 tbl_idx)
  378. {
  379. LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
  380. LLVMValueRef func, param_values[5], value;
  381. param_types[0] = INT8_PTR_TYPE;
  382. param_types[1] = I32_TYPE;
  383. param_types[2] = I32_TYPE;
  384. param_types[3] = I32_TYPE;
  385. param_types[4] = I32_TYPE;
  386. ret_type = VOID_TYPE;
  387. if (comp_ctx->is_jit_mode)
  388. GET_AOT_FUNCTION(llvm_jit_table_fill, 5);
  389. else
  390. GET_AOT_FUNCTION(aot_table_fill, 5);
  391. param_values[0] = func_ctx->aot_inst;
  392. if (!(param_values[1] = I32_CONST(tbl_idx))) {
  393. HANDLE_FAILURE("LLVMConstInt");
  394. goto fail;
  395. }
  396. /* n */
  397. POP_I32(param_values[2]);
  398. /* v */
  399. POP_I32(param_values[3]);
  400. /* i */
  401. POP_I32(param_values[4]);
  402. /* "" means return void */
  403. if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5,
  404. ""))) {
  405. HANDLE_FAILURE("LLVMBuildCall");
  406. goto fail;
  407. }
  408. return true;
  409. fail:
  410. return false;
  411. }
  412. #endif /* WASM_ENABLE_REF_TYPES != 0 */