Assembler.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Vector.h>
  8. #include <LibJS/Bytecode/BasicBlock.h>
  9. namespace JS::JIT {
  10. struct Assembler {
  11. Assembler(Vector<u8>& output)
  12. : m_output(output)
  13. {
  14. }
  15. Vector<u8>& m_output;
  16. enum class Reg {
  17. RAX = 0,
  18. RCX = 1,
  19. RDX = 2,
  20. RBX = 3,
  21. RSP = 4,
  22. RBP = 5,
  23. RSI = 6,
  24. RDI = 7,
  25. R8 = 8,
  26. R9 = 9,
  27. R10 = 10,
  28. R11 = 11,
  29. R12 = 12,
  30. R13 = 13,
  31. R14 = 14,
  32. R15 = 15,
  33. };
  34. struct Operand {
  35. enum class Type {
  36. Reg,
  37. Imm8,
  38. Imm32,
  39. Imm64,
  40. Mem64BaseAndOffset,
  41. };
  42. Type type {};
  43. Reg reg {};
  44. u64 offset_or_immediate { 0 };
  45. static Operand Register(Reg reg)
  46. {
  47. Operand operand;
  48. operand.type = Type::Reg;
  49. operand.reg = reg;
  50. return operand;
  51. }
  52. static Operand Imm8(u8 imm8)
  53. {
  54. Operand operand;
  55. operand.type = Type::Imm8;
  56. operand.offset_or_immediate = imm8;
  57. return operand;
  58. }
  59. static Operand Imm32(u32 imm32)
  60. {
  61. Operand operand;
  62. operand.type = Type::Imm32;
  63. operand.offset_or_immediate = imm32;
  64. return operand;
  65. }
  66. static Operand Imm64(u64 imm64)
  67. {
  68. Operand operand;
  69. operand.type = Type::Imm64;
  70. operand.offset_or_immediate = imm64;
  71. return operand;
  72. }
  73. static Operand Mem64BaseAndOffset(Reg base, u64 offset)
  74. {
  75. Operand operand;
  76. operand.type = Type::Mem64BaseAndOffset;
  77. operand.reg = base;
  78. operand.offset_or_immediate = offset;
  79. return operand;
  80. }
  81. };
  82. static constexpr u8 encode_reg(Reg reg)
  83. {
  84. return to_underlying(reg) & 0x7;
  85. }
  86. void shift_right(Operand dst, Operand count)
  87. {
  88. VERIFY(dst.type == Operand::Type::Reg);
  89. VERIFY(count.type == Operand::Type::Imm8);
  90. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  91. emit8(0xc1);
  92. emit8(0xe8 | encode_reg(dst.reg));
  93. emit8(count.offset_or_immediate);
  94. }
  95. void mov(Operand dst, Operand src)
  96. {
  97. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg) {
  98. if (src.reg == dst.reg)
  99. return;
  100. emit8(0x48
  101. | ((to_underlying(src.reg) >= 8) ? 1 << 2 : 0)
  102. | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  103. emit8(0x89);
  104. emit8(0xc0 | (encode_reg(src.reg) << 3) | encode_reg(dst.reg));
  105. return;
  106. }
  107. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm64) {
  108. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  109. emit8(0xb8 | encode_reg(dst.reg));
  110. emit64(src.offset_or_immediate);
  111. return;
  112. }
  113. if (dst.type == Operand::Type::Mem64BaseAndOffset && src.type == Operand::Type::Reg) {
  114. emit8(0x48
  115. | ((to_underlying(src.reg) >= 8) ? 1 << 2 : 0)
  116. | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  117. emit8(0x89);
  118. emit8(0x80 | (encode_reg(src.reg) << 3) | encode_reg(dst.reg));
  119. emit32(dst.offset_or_immediate);
  120. return;
  121. }
  122. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Mem64BaseAndOffset) {
  123. emit8(0x48
  124. | ((to_underlying(dst.reg) >= 8) ? 1 << 2 : 0)
  125. | ((to_underlying(src.reg) >= 8) ? 1 << 0 : 0));
  126. emit8(0x8b);
  127. emit8(0x80 | (encode_reg(dst.reg) << 3) | encode_reg(src.reg));
  128. emit32(src.offset_or_immediate);
  129. return;
  130. }
  131. VERIFY_NOT_REACHED();
  132. }
  133. void emit8(u8 value)
  134. {
  135. m_output.append(value);
  136. }
  137. void emit32(u32 value)
  138. {
  139. m_output.append((value >> 0) & 0xff);
  140. m_output.append((value >> 8) & 0xff);
  141. m_output.append((value >> 16) & 0xff);
  142. m_output.append((value >> 24) & 0xff);
  143. }
  144. void emit64(u64 value)
  145. {
  146. m_output.append((value >> 0) & 0xff);
  147. m_output.append((value >> 8) & 0xff);
  148. m_output.append((value >> 16) & 0xff);
  149. m_output.append((value >> 24) & 0xff);
  150. m_output.append((value >> 32) & 0xff);
  151. m_output.append((value >> 40) & 0xff);
  152. m_output.append((value >> 48) & 0xff);
  153. m_output.append((value >> 56) & 0xff);
  154. }
  155. struct Label {
  156. size_t offset_of_label_in_instruction_stream { 0 };
  157. Vector<size_t> jump_slot_offsets_in_instruction_stream;
  158. void add_jump(size_t offset)
  159. {
  160. jump_slot_offsets_in_instruction_stream.append(offset);
  161. }
  162. void link(Assembler& assembler)
  163. {
  164. offset_of_label_in_instruction_stream = assembler.m_output.size();
  165. for (auto offset_in_instruction_stream : jump_slot_offsets_in_instruction_stream) {
  166. auto offset = offset_of_label_in_instruction_stream - offset_in_instruction_stream;
  167. auto jump_slot = offset_in_instruction_stream - 4;
  168. assembler.m_output[jump_slot + 0] = (offset >> 0) & 0xff;
  169. assembler.m_output[jump_slot + 1] = (offset >> 8) & 0xff;
  170. assembler.m_output[jump_slot + 2] = (offset >> 16) & 0xff;
  171. assembler.m_output[jump_slot + 3] = (offset >> 24) & 0xff;
  172. }
  173. }
  174. };
  175. [[nodiscard]] Label make_label()
  176. {
  177. return { .offset_of_label_in_instruction_stream = m_output.size() };
  178. }
  179. [[nodiscard]] Label jump()
  180. {
  181. // jmp target (RIP-relative 32-bit offset)
  182. emit8(0xe9);
  183. emit32(0xdeadbeef);
  184. auto label = make_label();
  185. label.add_jump(m_output.size());
  186. return label;
  187. }
  188. void jump(Label& label)
  189. {
  190. // jmp target (RIP-relative 32-bit offset)
  191. emit8(0xe9);
  192. emit32(0xdeadbeef);
  193. label.add_jump(m_output.size());
  194. }
  195. void jump(Operand op)
  196. {
  197. if (op.type == Operand::Type::Reg) {
  198. if (to_underlying(op.reg) >= 8)
  199. emit8(0x41);
  200. emit8(0xff);
  201. emit8(0xe0 | encode_reg(op.reg));
  202. } else {
  203. VERIFY_NOT_REACHED();
  204. }
  205. }
  206. void verify_not_reached()
  207. {
  208. // ud2
  209. emit8(0x0f);
  210. emit8(0x0b);
  211. }
  212. void jump(Bytecode::BasicBlock& target)
  213. {
  214. // jmp target (RIP-relative 32-bit offset)
  215. emit8(0xe9);
  216. target.jumps_to_here.append(m_output.size());
  217. emit32(0xdeadbeef);
  218. }
  219. void jump_conditional(Reg reg, Bytecode::BasicBlock& true_target, Bytecode::BasicBlock& false_target)
  220. {
  221. // if (reg & 1) is 0, jump to false_target, else jump to true_target
  222. // test reg, 1
  223. emit8(0x48 | ((to_underlying(reg) >= 8) ? 1 << 2 : 0));
  224. emit8(0xf7);
  225. emit8(0xc0 | encode_reg(reg));
  226. emit32(0x01);
  227. // jz false_target (RIP-relative 32-bit offset)
  228. emit8(0x0f);
  229. emit8(0x84);
  230. false_target.jumps_to_here.append(m_output.size());
  231. emit32(0xdeadbeef);
  232. // jmp true_target (RIP-relative 32-bit offset)
  233. jump(true_target);
  234. }
  235. void cmp(Operand lhs, Operand rhs)
  236. {
  237. if (lhs.type == Operand::Type::Reg && rhs.type == Operand::Type::Reg) {
  238. emit8(0x48
  239. | ((to_underlying(rhs.reg) >= 8) ? 1 << 2 : 0)
  240. | ((to_underlying(lhs.reg) >= 8) ? 1 << 0 : 0));
  241. emit8(0x39);
  242. emit8(0xc0 | (encode_reg(rhs.reg) << 3) | encode_reg(lhs.reg));
  243. } else if (lhs.type == Operand::Type::Reg && rhs.type == Operand::Type::Imm32) {
  244. emit8(0x48 | ((to_underlying(lhs.reg) >= 8) ? 1 << 0 : 0));
  245. emit8(0x81);
  246. emit8(0xf8 | encode_reg(lhs.reg));
  247. emit32(rhs.offset_or_immediate);
  248. } else {
  249. VERIFY_NOT_REACHED();
  250. }
  251. }
  252. void jump_if_equal(Operand lhs, Operand rhs, Label& label)
  253. {
  254. cmp(lhs, rhs);
  255. // je label (RIP-relative 32-bit offset)
  256. emit8(0x0f);
  257. emit8(0x84);
  258. emit32(0xdeadbeef);
  259. label.add_jump(m_output.size());
  260. }
  261. void jump_if_not_equal(Operand lhs, Operand rhs, Label& label)
  262. {
  263. cmp(lhs, rhs);
  264. // jne label (RIP-relative 32-bit offset)
  265. emit8(0x0f);
  266. emit8(0x85);
  267. emit32(0xdeadbeef);
  268. label.add_jump(m_output.size());
  269. }
  270. void jump_if_less_than(Operand lhs, Operand rhs, Label& label)
  271. {
  272. cmp(lhs, rhs);
  273. // jl label (RIP-relative 32-bit offset)
  274. emit8(0x0f);
  275. emit8(0x8c);
  276. emit32(0xdeadbeef);
  277. label.add_jump(m_output.size());
  278. }
  279. void sign_extend_32_to_64_bits(Reg reg)
  280. {
  281. // movsxd (reg as 64-bit), (reg as 32-bit)
  282. emit8(0x48 | ((to_underlying(reg) >= 8) ? 1 << 0 : 0));
  283. emit8(0x63);
  284. emit8(0xc0 | (encode_reg(reg) << 3) | encode_reg(reg));
  285. }
  286. void bitwise_and(Operand dst, Operand src)
  287. {
  288. // and dst,src
  289. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg) {
  290. emit8(0x48
  291. | ((to_underlying(src.reg) >= 8) ? 1 << 2 : 0)
  292. | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  293. emit8(0x21);
  294. emit8(0xc0 | (encode_reg(src.reg) << 3) | encode_reg(dst.reg));
  295. } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm32) {
  296. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  297. emit8(0x81);
  298. emit8(0xe0 | encode_reg(dst.reg));
  299. emit32(src.offset_or_immediate);
  300. } else {
  301. VERIFY_NOT_REACHED();
  302. }
  303. }
  304. void bitwise_or(Operand dst, Operand src)
  305. {
  306. // or dst,src
  307. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg) {
  308. emit8(0x48
  309. | ((to_underlying(src.reg) >= 8) ? 1 << 2 : 0)
  310. | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  311. emit8(0x09);
  312. emit8(0xc0 | (encode_reg(src.reg) << 3) | encode_reg(dst.reg));
  313. } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm32) {
  314. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  315. emit8(0x81);
  316. emit8(0xc8 | encode_reg(dst.reg));
  317. emit32(src.offset_or_immediate);
  318. } else {
  319. VERIFY_NOT_REACHED();
  320. }
  321. }
  322. void enter()
  323. {
  324. push_callee_saved_registers();
  325. push(Operand::Register(Reg::RBP));
  326. mov(Operand::Register(Reg::RBP), Operand::Register(Reg::RSP));
  327. sub(Operand::Register(Reg::RSP), Operand::Imm8(8));
  328. }
  329. void exit()
  330. {
  331. // leave
  332. emit8(0xc9);
  333. pop_callee_saved_registers();
  334. // ret
  335. emit8(0xc3);
  336. }
  337. void push_callee_saved_registers()
  338. {
  339. // FIXME: Don't push RBX twice :^)
  340. push(Operand::Register(Reg::RBX));
  341. push(Operand::Register(Reg::RBX));
  342. push(Operand::Register(Reg::R12));
  343. push(Operand::Register(Reg::R13));
  344. push(Operand::Register(Reg::R14));
  345. push(Operand::Register(Reg::R15));
  346. }
  347. void pop_callee_saved_registers()
  348. {
  349. pop(Operand::Register(Reg::R15));
  350. pop(Operand::Register(Reg::R14));
  351. pop(Operand::Register(Reg::R13));
  352. pop(Operand::Register(Reg::R12));
  353. // FIXME: Don't pop RBX twice :^)
  354. pop(Operand::Register(Reg::RBX));
  355. pop(Operand::Register(Reg::RBX));
  356. }
  357. void push(Operand op)
  358. {
  359. if (op.type == Operand::Type::Reg) {
  360. if (to_underlying(op.reg) >= 8)
  361. emit8(0x49);
  362. emit8(0x50 | encode_reg(op.reg));
  363. } else if (op.type == Operand::Type::Imm32) {
  364. emit8(0x68);
  365. emit32(op.offset_or_immediate);
  366. } else {
  367. VERIFY_NOT_REACHED();
  368. }
  369. }
  370. void pop(Operand op)
  371. {
  372. if (op.type == Operand::Type::Reg) {
  373. if (to_underlying(op.reg) >= 8)
  374. emit8(0x49);
  375. emit8(0x58 | encode_reg(op.reg));
  376. } else {
  377. VERIFY_NOT_REACHED();
  378. }
  379. }
  380. void add(Operand dst, Operand src)
  381. {
  382. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg) {
  383. emit8(0x48
  384. | ((to_underlying(dst.reg) >= 8) ? 1 << 2 : 0)
  385. | ((to_underlying(src.reg) >= 8) ? 1 << 0 : 0));
  386. emit8(0x01);
  387. emit8(0xc0 | (encode_reg(dst.reg) << 3) | encode_reg(src.reg));
  388. } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm32) {
  389. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  390. emit8(0x81);
  391. emit8(0xc0 | encode_reg(dst.reg));
  392. emit32(src.offset_or_immediate);
  393. } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm8) {
  394. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  395. emit8(0x83);
  396. emit8(0xc0 | encode_reg(dst.reg));
  397. emit8(src.offset_or_immediate);
  398. } else {
  399. VERIFY_NOT_REACHED();
  400. }
  401. }
  402. void sub(Operand dst, Operand src)
  403. {
  404. if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Reg) {
  405. emit8(0x48
  406. | ((to_underlying(dst.reg) >= 8) ? 1 << 2 : 0)
  407. | ((to_underlying(src.reg) >= 8) ? 1 << 0 : 0));
  408. emit8(0x29);
  409. emit8(0xc0 | (encode_reg(dst.reg) << 3) | encode_reg(src.reg));
  410. } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm32) {
  411. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  412. emit8(0x81);
  413. emit8(0xe8 | encode_reg(dst.reg));
  414. emit32(src.offset_or_immediate);
  415. } else if (dst.type == Operand::Type::Reg && src.type == Operand::Type::Imm8) {
  416. emit8(0x48 | ((to_underlying(dst.reg) >= 8) ? 1 << 0 : 0));
  417. emit8(0x83);
  418. emit8(0xe8 | encode_reg(dst.reg));
  419. emit8(src.offset_or_immediate);
  420. } else {
  421. VERIFY_NOT_REACHED();
  422. }
  423. }
  424. void native_call(void* callee)
  425. {
  426. // push caller-saved registers on the stack
  427. // (callee-saved registers: RBX, RSP, RBP, and R12–R15)
  428. push(Operand::Register(Reg::RCX));
  429. push(Operand::Register(Reg::RDX));
  430. push(Operand::Register(Reg::RSI));
  431. push(Operand::Register(Reg::RDI));
  432. push(Operand::Register(Reg::R8));
  433. push(Operand::Register(Reg::R9));
  434. push(Operand::Register(Reg::R10));
  435. push(Operand::Register(Reg::R11));
  436. // align the stack to 16-byte boundary
  437. sub(Operand::Register(Reg::RSP), Operand::Imm8(8));
  438. // load callee into RAX
  439. mov(Operand::Register(Reg::RAX), Operand::Imm64(bit_cast<u64>(callee)));
  440. // call RAX
  441. emit8(0xff);
  442. emit8(0xd0);
  443. // adjust stack pointer
  444. add(Operand::Register(Reg::RSP), Operand::Imm8(8));
  445. // restore caller-saved registers from the stack
  446. pop(Operand::Register(Reg::R11));
  447. pop(Operand::Register(Reg::R10));
  448. pop(Operand::Register(Reg::R9));
  449. pop(Operand::Register(Reg::R8));
  450. pop(Operand::Register(Reg::RDI));
  451. pop(Operand::Register(Reg::RSI));
  452. pop(Operand::Register(Reg::RDX));
  453. pop(Operand::Register(Reg::RCX));
  454. }
  455. void trap()
  456. {
  457. // int3
  458. emit8(0xcc);
  459. }
  460. };
  461. }