Compiler.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/OwnPtr.h>
  7. #include <LibJS/Bytecode/Instruction.h>
  8. #include <LibJS/JIT/Compiler.h>
  9. #include <LibJS/Runtime/ValueInlines.h>
  10. #include <sys/mman.h>
  11. namespace JS::JIT {
  12. void Compiler::store_vm_register(Bytecode::Register dst, Assembler::Reg src)
  13. {
  14. m_assembler.mov(
  15. Assembler::Operand::Mem64BaseAndOffset(Assembler::Reg::RegisterArrayBase, dst.index() * sizeof(Value)),
  16. Assembler::Operand::Register(src));
  17. }
  18. void Compiler::load_vm_register(Assembler::Reg dst, Bytecode::Register src)
  19. {
  20. m_assembler.mov(
  21. Assembler::Operand::Register(dst),
  22. Assembler::Operand::Mem64BaseAndOffset(Assembler::Reg::RegisterArrayBase, src.index() * sizeof(Value)));
  23. }
  24. void Compiler::store_vm_local(size_t dst, Assembler::Reg src)
  25. {
  26. m_assembler.mov(
  27. Assembler::Operand::Mem64BaseAndOffset(Assembler::Reg::LocalsArrayBase, dst * sizeof(Value)),
  28. Assembler::Operand::Register(src));
  29. }
  30. void Compiler::load_vm_local(Assembler::Reg dst, size_t src)
  31. {
  32. m_assembler.mov(
  33. Assembler::Operand::Register(dst),
  34. Assembler::Operand::Mem64BaseAndOffset(Assembler::Reg::LocalsArrayBase, src * sizeof(Value)));
  35. }
  36. void Compiler::compile_load_immediate(Bytecode::Op::LoadImmediate const& op)
  37. {
  38. m_assembler.mov(
  39. Assembler::Operand::Register(Assembler::Reg::GPR0),
  40. Assembler::Operand::Imm64(op.value().encoded()));
  41. store_vm_register(Bytecode::Register::accumulator(), Assembler::Reg::GPR0);
  42. }
  43. void Compiler::compile_load(Bytecode::Op::Load const& op)
  44. {
  45. load_vm_register(Assembler::Reg::GPR0, op.src());
  46. store_vm_register(Bytecode::Register::accumulator(), Assembler::Reg::GPR0);
  47. }
  48. void Compiler::compile_store(Bytecode::Op::Store const& op)
  49. {
  50. load_vm_register(Assembler::Reg::GPR0, Bytecode::Register::accumulator());
  51. store_vm_register(op.dst(), Assembler::Reg::GPR0);
  52. }
  53. void Compiler::compile_get_local(Bytecode::Op::GetLocal const& op)
  54. {
  55. load_vm_local(Assembler::Reg::GPR0, op.index());
  56. store_vm_register(Bytecode::Register::accumulator(), Assembler::Reg::GPR0);
  57. }
  58. void Compiler::compile_set_local(Bytecode::Op::SetLocal const& op)
  59. {
  60. load_vm_register(Assembler::Reg::GPR0, Bytecode::Register::accumulator());
  61. store_vm_local(op.index(), Assembler::Reg::GPR0);
  62. }
  63. void Compiler::compile_jump(Bytecode::Op::Jump const& op)
  64. {
  65. m_assembler.jump(const_cast<Bytecode::BasicBlock&>(op.true_target()->block()));
  66. }
  67. static bool cxx_to_boolean(VM&, Value value)
  68. {
  69. return value.to_boolean();
  70. }
  71. void Compiler::compile_to_boolean(Assembler::Reg reg)
  72. {
  73. m_assembler.mov(
  74. Assembler::Operand::Register(Assembler::Reg::Arg1),
  75. Assembler::Operand::Register(reg));
  76. m_assembler.native_call((void*)cxx_to_boolean);
  77. m_assembler.mov(
  78. Assembler::Operand::Register(reg),
  79. Assembler::Operand::Register(Assembler::Reg::Ret));
  80. }
  81. void Compiler::compile_jump_conditional(Bytecode::Op::JumpConditional const& op)
  82. {
  83. load_vm_register(Assembler::Reg::GPR0, Bytecode::Register::accumulator());
  84. compile_to_boolean(Assembler::Reg::GPR0);
  85. m_assembler.jump_conditional(Assembler::Reg::GPR0,
  86. const_cast<Bytecode::BasicBlock&>(op.true_target()->block()),
  87. const_cast<Bytecode::BasicBlock&>(op.false_target()->block()));
  88. }
  89. [[maybe_unused]] static Value cxx_less_than(VM& vm, Value lhs, Value rhs)
  90. {
  91. // FIXME: Handle exceptions!
  92. return MUST(less_than(vm, lhs, rhs));
  93. }
  94. void Compiler::compile_less_than(Bytecode::Op::LessThan const& op)
  95. {
  96. load_vm_register(Assembler::Reg::Arg1, op.lhs());
  97. load_vm_register(Assembler::Reg::Arg2, Bytecode::Register::accumulator());
  98. m_assembler.native_call((void*)cxx_less_than);
  99. store_vm_register(Bytecode::Register::accumulator(), Assembler::Reg::Ret);
  100. }
  101. [[maybe_unused]] static Value cxx_increment(VM& vm, Value value)
  102. {
  103. // FIXME: Handle exceptions!
  104. auto old_value = MUST(value.to_numeric(vm));
  105. if (old_value.is_number())
  106. return Value(old_value.as_double() + 1);
  107. return BigInt::create(vm, old_value.as_bigint().big_integer().plus(Crypto::SignedBigInteger { 1 }));
  108. }
  109. void Compiler::compile_increment(Bytecode::Op::Increment const&)
  110. {
  111. load_vm_register(Assembler::Reg::Arg1, Bytecode::Register::accumulator());
  112. m_assembler.native_call((void*)cxx_increment);
  113. store_vm_register(Bytecode::Register::accumulator(), Assembler::Reg::Ret);
  114. }
  115. OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable const& bytecode_executable)
  116. {
  117. if (getenv("LIBJS_NO_JIT"))
  118. return nullptr;
  119. Compiler compiler;
  120. compiler.m_assembler.mov(
  121. Assembler::Operand::Register(Assembler::Reg::RegisterArrayBase),
  122. Assembler::Operand::Register(Assembler::Reg::Arg1));
  123. compiler.m_assembler.mov(
  124. Assembler::Operand::Register(Assembler::Reg::LocalsArrayBase),
  125. Assembler::Operand::Register(Assembler::Reg::Arg2));
  126. for (auto& block : bytecode_executable.basic_blocks) {
  127. block->offset = compiler.m_output.size();
  128. auto it = Bytecode::InstructionStreamIterator(block->instruction_stream());
  129. while (!it.at_end()) {
  130. auto const& op = *it;
  131. switch (op.type()) {
  132. case Bytecode::Instruction::Type::LoadImmediate:
  133. compiler.compile_load_immediate(static_cast<Bytecode::Op::LoadImmediate const&>(op));
  134. break;
  135. case Bytecode::Instruction::Type::Store:
  136. compiler.compile_store(static_cast<Bytecode::Op::Store const&>(op));
  137. break;
  138. case Bytecode::Instruction::Type::Load:
  139. compiler.compile_load(static_cast<Bytecode::Op::Load const&>(op));
  140. break;
  141. case Bytecode::Instruction::Type::GetLocal:
  142. compiler.compile_get_local(static_cast<Bytecode::Op::GetLocal const&>(op));
  143. break;
  144. case Bytecode::Instruction::Type::SetLocal:
  145. compiler.compile_set_local(static_cast<Bytecode::Op::SetLocal const&>(op));
  146. break;
  147. case Bytecode::Instruction::Type::Jump:
  148. compiler.compile_jump(static_cast<Bytecode::Op::Jump const&>(op));
  149. break;
  150. case Bytecode::Instruction::Type::JumpConditional:
  151. compiler.compile_jump_conditional(static_cast<Bytecode::Op::JumpConditional const&>(op));
  152. break;
  153. case Bytecode::Instruction::Type::LessThan:
  154. compiler.compile_less_than(static_cast<Bytecode::Op::LessThan const&>(op));
  155. break;
  156. case Bytecode::Instruction::Type::Increment:
  157. compiler.compile_increment(static_cast<Bytecode::Op::Increment const&>(op));
  158. break;
  159. default:
  160. dbgln("JIT compilation failed: {}", bytecode_executable.name);
  161. dbgln("Unsupported bytecode op: {}", op.to_deprecated_string(bytecode_executable));
  162. return nullptr;
  163. }
  164. ++it;
  165. }
  166. if (!block->is_terminated())
  167. compiler.m_assembler.exit();
  168. }
  169. // Patch up all the jumps
  170. for (auto& block : bytecode_executable.basic_blocks) {
  171. for (auto& jump : block->jumps_to_here) {
  172. auto offset = block->offset - jump - 4;
  173. compiler.m_output[jump + 0] = (offset >> 0) & 0xff;
  174. compiler.m_output[jump + 1] = (offset >> 8) & 0xff;
  175. compiler.m_output[jump + 2] = (offset >> 16) & 0xff;
  176. compiler.m_output[jump + 3] = (offset >> 24) & 0xff;
  177. }
  178. }
  179. write(STDOUT_FILENO, compiler.m_output.data(), compiler.m_output.size());
  180. auto* executable_memory = mmap(nullptr, compiler.m_output.size(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  181. if (executable_memory == MAP_FAILED) {
  182. perror("mmap");
  183. return nullptr;
  184. }
  185. memcpy(executable_memory, compiler.m_output.data(), compiler.m_output.size());
  186. mprotect(executable_memory, compiler.m_output.size(), PROT_READ | PROT_EXEC);
  187. return make<NativeExecutable>(executable_memory, compiler.m_output.size());
  188. }
  189. }