Generator.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/OwnPtr.h>
  8. #include <AK/SinglyLinkedList.h>
  9. #include <LibJS/AST.h>
  10. #include <LibJS/Bytecode/BasicBlock.h>
  11. #include <LibJS/Bytecode/CodeGenerationError.h>
  12. #include <LibJS/Bytecode/Executable.h>
  13. #include <LibJS/Bytecode/IdentifierTable.h>
  14. #include <LibJS/Bytecode/Label.h>
  15. #include <LibJS/Bytecode/Op.h>
  16. #include <LibJS/Bytecode/Register.h>
  17. #include <LibJS/Bytecode/StringTable.h>
  18. #include <LibJS/Forward.h>
  19. #include <LibJS/Runtime/FunctionKind.h>
  20. #include <LibRegex/Regex.h>
  21. namespace JS::Bytecode {
  22. class Generator {
  23. public:
  24. enum class SurroundingScopeKind {
  25. Global,
  26. Function,
  27. Block,
  28. };
  29. static CodeGenerationErrorOr<NonnullOwnPtr<Executable>> generate(ASTNode const&, FunctionKind = FunctionKind::Normal);
  30. Register allocate_register();
  31. void ensure_enough_space(size_t size)
  32. {
  33. // Make sure there's always enough space for a single jump at the end.
  34. if (!m_current_basic_block->can_grow(size + sizeof(Op::Jump))) {
  35. auto& new_block = make_block();
  36. emit<Op::Jump>().set_targets(
  37. Label { new_block },
  38. {});
  39. switch_to_basic_block(new_block);
  40. }
  41. }
  42. class SourceLocationScope {
  43. public:
  44. SourceLocationScope(Generator&, ASTNode const& node);
  45. ~SourceLocationScope();
  46. private:
  47. Generator& m_generator;
  48. ASTNode const* m_previous_node { nullptr };
  49. };
  50. template<typename OpType, typename... Args>
  51. OpType& emit(Args&&... args)
  52. {
  53. VERIFY(!is_current_block_terminated());
  54. // If the block doesn't have enough space, switch to another block
  55. if constexpr (!OpType::IsTerminator)
  56. ensure_enough_space(sizeof(OpType));
  57. void* slot = next_slot();
  58. grow(sizeof(OpType));
  59. new (slot) OpType(forward<Args>(args)...);
  60. if constexpr (OpType::IsTerminator)
  61. m_current_basic_block->terminate({}, static_cast<Instruction const*>(slot));
  62. auto* op = static_cast<OpType*>(slot);
  63. op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
  64. return *op;
  65. }
  66. template<typename OpType, typename... Args>
  67. OpType& emit_with_extra_register_slots(size_t extra_register_slots, Args&&... args)
  68. {
  69. VERIFY(!is_current_block_terminated());
  70. size_t size_to_allocate = round_up_to_power_of_two(sizeof(OpType) + extra_register_slots * sizeof(Register), alignof(void*));
  71. // If the block doesn't have enough space, switch to another block
  72. if constexpr (!OpType::IsTerminator)
  73. ensure_enough_space(size_to_allocate);
  74. void* slot = next_slot();
  75. grow(size_to_allocate);
  76. new (slot) OpType(forward<Args>(args)...);
  77. if constexpr (OpType::IsTerminator)
  78. m_current_basic_block->terminate({}, static_cast<Instruction const*>(slot));
  79. auto* op = static_cast<OpType*>(slot);
  80. op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
  81. return *op;
  82. }
  83. CodeGenerationErrorOr<void> emit_load_from_reference(JS::ASTNode const&);
  84. CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&);
  85. CodeGenerationErrorOr<void> emit_delete_reference(JS::ASTNode const&);
  86. struct ReferenceRegisters {
  87. Register base; // [[Base]]
  88. Optional<Bytecode::Register> referenced_name; // [[ReferencedName]]
  89. Register this_value; // [[ThisValue]]
  90. };
  91. CodeGenerationErrorOr<ReferenceRegisters> emit_super_reference(MemberExpression const&);
  92. void emit_set_variable(JS::Identifier const& identifier, Bytecode::Op::SetVariable::InitializationMode initialization_mode = Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode mode = Bytecode::Op::EnvironmentMode::Lexical);
  93. void push_home_object(Register);
  94. void pop_home_object();
  95. void emit_new_function(JS::FunctionExpression const&, Optional<IdentifierTableIndex> lhs_name);
  96. CodeGenerationErrorOr<void> emit_named_evaluation_if_anonymous_function(Expression const&, Optional<IdentifierTableIndex> lhs_name);
  97. void begin_continuable_scope(Label continue_target, Vector<DeprecatedFlyString> const& language_label_set);
  98. void end_continuable_scope();
  99. void begin_breakable_scope(Label breakable_target, Vector<DeprecatedFlyString> const& language_label_set);
  100. void end_breakable_scope();
  101. [[nodiscard]] Label nearest_continuable_scope() const;
  102. [[nodiscard]] Label nearest_breakable_scope() const;
  103. void switch_to_basic_block(BasicBlock& block)
  104. {
  105. m_current_basic_block = &block;
  106. }
  107. [[nodiscard]] BasicBlock& current_block() { return *m_current_basic_block; }
  108. BasicBlock& make_block(DeprecatedString name = {})
  109. {
  110. if (name.is_empty())
  111. name = DeprecatedString::number(m_next_block++);
  112. m_root_basic_blocks.append(BasicBlock::create(name));
  113. return *m_root_basic_blocks.last();
  114. }
  115. bool is_current_block_terminated() const
  116. {
  117. return m_current_basic_block->is_terminated();
  118. }
  119. StringTableIndex intern_string(DeprecatedString string)
  120. {
  121. return m_string_table->insert(move(string));
  122. }
  123. RegexTableIndex intern_regex(ParsedRegex regex)
  124. {
  125. return m_regex_table->insert(move(regex));
  126. }
  127. IdentifierTableIndex intern_identifier(DeprecatedFlyString string)
  128. {
  129. return m_identifier_table->insert(move(string));
  130. }
  131. bool is_in_generator_or_async_function() const { return m_enclosing_function_kind == FunctionKind::Async || m_enclosing_function_kind == FunctionKind::Generator || m_enclosing_function_kind == FunctionKind::AsyncGenerator; }
  132. bool is_in_generator_function() const { return m_enclosing_function_kind == FunctionKind::Generator || m_enclosing_function_kind == FunctionKind::AsyncGenerator; }
  133. bool is_in_async_function() const { return m_enclosing_function_kind == FunctionKind::Async || m_enclosing_function_kind == FunctionKind::AsyncGenerator; }
  134. bool is_in_async_generator_function() const { return m_enclosing_function_kind == FunctionKind::AsyncGenerator; }
  135. enum class BindingMode {
  136. Lexical,
  137. Var,
  138. Global,
  139. };
  140. struct LexicalScope {
  141. SurroundingScopeKind kind;
  142. };
  143. void block_declaration_instantiation(ScopeNode const&);
  144. void begin_variable_scope();
  145. void end_variable_scope();
  146. enum class BlockBoundaryType {
  147. Break,
  148. Continue,
  149. Unwind,
  150. ReturnToFinally,
  151. LeaveLexicalEnvironment,
  152. };
  153. template<typename OpType>
  154. void perform_needed_unwinds()
  155. requires(OpType::IsTerminator && !IsSame<OpType, Op::Jump>)
  156. {
  157. for (size_t i = m_boundaries.size(); i > 0; --i) {
  158. auto boundary = m_boundaries[i - 1];
  159. using enum BlockBoundaryType;
  160. switch (boundary) {
  161. case Unwind:
  162. if constexpr (IsSame<OpType, Bytecode::Op::Throw>)
  163. return;
  164. emit<Bytecode::Op::LeaveUnwindContext>();
  165. break;
  166. case LeaveLexicalEnvironment:
  167. emit<Bytecode::Op::LeaveLexicalEnvironment>();
  168. break;
  169. case Break:
  170. case Continue:
  171. break;
  172. case ReturnToFinally:
  173. return;
  174. };
  175. }
  176. }
  177. void generate_break();
  178. void generate_break(DeprecatedFlyString const& break_label);
  179. void generate_continue();
  180. void generate_continue(DeprecatedFlyString const& continue_label);
  181. void start_boundary(BlockBoundaryType type) { m_boundaries.append(type); }
  182. void end_boundary(BlockBoundaryType type)
  183. {
  184. VERIFY(m_boundaries.last() == type);
  185. m_boundaries.take_last();
  186. }
  187. void emit_get_by_id(IdentifierTableIndex);
  188. void emit_get_by_id_with_this(IdentifierTableIndex, Register);
  189. [[nodiscard]] size_t next_global_variable_cache() { return m_next_global_variable_cache++; }
  190. private:
  191. enum class JumpType {
  192. Continue,
  193. Break,
  194. };
  195. void generate_scoped_jump(JumpType);
  196. void generate_labelled_jump(JumpType, DeprecatedFlyString const& label);
  197. Generator();
  198. ~Generator() = default;
  199. void grow(size_t);
  200. void* next_slot();
  201. struct LabelableScope {
  202. Label bytecode_target;
  203. Vector<DeprecatedFlyString> language_label_set;
  204. };
  205. BasicBlock* m_current_basic_block { nullptr };
  206. ASTNode const* m_current_ast_node { nullptr };
  207. Vector<NonnullOwnPtr<BasicBlock>> m_root_basic_blocks;
  208. NonnullOwnPtr<StringTable> m_string_table;
  209. NonnullOwnPtr<IdentifierTable> m_identifier_table;
  210. NonnullOwnPtr<RegexTable> m_regex_table;
  211. u32 m_next_register { 2 };
  212. u32 m_next_block { 1 };
  213. u32 m_next_property_lookup_cache { 0 };
  214. u32 m_next_global_variable_cache { 0 };
  215. FunctionKind m_enclosing_function_kind { FunctionKind::Normal };
  216. Vector<LabelableScope> m_continuable_scopes;
  217. Vector<LabelableScope> m_breakable_scopes;
  218. Vector<BlockBoundaryType> m_boundaries;
  219. Vector<Register> m_home_objects;
  220. };
  221. }