Generator.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*
  2. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #define FIXME_NEWBC (void)
  7. #include <AK/TemporaryChange.h>
  8. #include <LibJS/AST.h>
  9. #include <LibJS/Bytecode/BasicBlock.h>
  10. #include <LibJS/Bytecode/Generator.h>
  11. #include <LibJS/Bytecode/Instruction.h>
  12. #include <LibJS/Bytecode/Op.h>
  13. #include <LibJS/Bytecode/Register.h>
  14. #include <LibJS/Runtime/VM.h>
  15. namespace JS::Bytecode {
  16. Generator::Generator()
  17. : m_string_table(make<StringTable>())
  18. , m_identifier_table(make<IdentifierTable>())
  19. , m_regex_table(make<RegexTable>())
  20. {
  21. }
  22. CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::generate(VM& vm, ASTNode const& node, FunctionKind enclosing_function_kind)
  23. {
  24. Generator generator;
  25. generator.switch_to_basic_block(generator.make_block());
  26. SourceLocationScope scope(generator, node);
  27. generator.m_enclosing_function_kind = enclosing_function_kind;
  28. if (generator.is_in_generator_or_async_function()) {
  29. // Immediately yield with no value.
  30. auto& start_block = generator.make_block();
  31. generator.emit<Bytecode::Op::Yield>(Label { start_block });
  32. generator.switch_to_basic_block(start_block);
  33. // NOTE: This doesn't have to handle received throw/return completions, as GeneratorObject::resume_abrupt
  34. // will not enter the generator from the SuspendedStart state and immediately completes the generator.
  35. }
  36. FIXME_NEWBC TRY(node.generate_bytecode(generator));
  37. if (generator.is_in_generator_or_async_function()) {
  38. // Terminate all unterminated blocks with yield return
  39. for (auto& block : generator.m_root_basic_blocks) {
  40. if (block->is_terminated())
  41. continue;
  42. generator.switch_to_basic_block(*block);
  43. generator.emit<Bytecode::Op::LoadImmediate>(js_undefined());
  44. generator.emit<Bytecode::Op::Yield>(nullptr);
  45. }
  46. }
  47. bool is_strict_mode = false;
  48. if (is<Program>(node))
  49. is_strict_mode = static_cast<Program const&>(node).is_strict_mode();
  50. else if (is<FunctionBody>(node))
  51. is_strict_mode = static_cast<FunctionBody const&>(node).in_strict_mode();
  52. else if (is<FunctionDeclaration>(node))
  53. is_strict_mode = static_cast<FunctionDeclaration const&>(node).is_strict_mode();
  54. else if (is<FunctionExpression>(node))
  55. is_strict_mode = static_cast<FunctionExpression const&>(node).is_strict_mode();
  56. auto executable = vm.heap().allocate_without_realm<Executable>(
  57. move(generator.m_identifier_table),
  58. move(generator.m_string_table),
  59. move(generator.m_regex_table),
  60. move(generator.m_constants),
  61. node.source_code(),
  62. generator.m_next_property_lookup_cache,
  63. generator.m_next_global_variable_cache,
  64. generator.m_next_environment_variable_cache,
  65. generator.m_next_register,
  66. move(generator.m_root_basic_blocks),
  67. is_strict_mode);
  68. return executable;
  69. }
  70. void Generator::grow(size_t additional_size)
  71. {
  72. VERIFY(m_current_basic_block);
  73. m_current_basic_block->grow(additional_size);
  74. }
  75. Register Generator::allocate_register()
  76. {
  77. VERIFY(m_next_register != NumericLimits<u32>::max());
  78. return Register { m_next_register++ };
  79. }
  80. Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node)
  81. : m_generator(generator)
  82. , m_previous_node(m_generator.m_current_ast_node)
  83. {
  84. m_generator.m_current_ast_node = &node;
  85. }
  86. Generator::SourceLocationScope::~SourceLocationScope()
  87. {
  88. m_generator.m_current_ast_node = m_previous_node;
  89. }
  90. Generator::UnwindContext::UnwindContext(Generator& generator, Optional<Label> finalizer)
  91. : m_generator(generator)
  92. , m_finalizer(finalizer)
  93. , m_previous_context(m_generator.m_current_unwind_context)
  94. {
  95. m_generator.m_current_unwind_context = this;
  96. }
  97. Generator::UnwindContext::~UnwindContext()
  98. {
  99. VERIFY(m_generator.m_current_unwind_context == this);
  100. m_generator.m_current_unwind_context = m_previous_context;
  101. }
  102. Label Generator::nearest_continuable_scope() const
  103. {
  104. return m_continuable_scopes.last().bytecode_target;
  105. }
  106. void Generator::block_declaration_instantiation(ScopeNode const& scope_node)
  107. {
  108. start_boundary(BlockBoundaryType::LeaveLexicalEnvironment);
  109. emit<Bytecode::Op::BlockDeclarationInstantiation>(scope_node);
  110. }
  111. void Generator::begin_variable_scope()
  112. {
  113. start_boundary(BlockBoundaryType::LeaveLexicalEnvironment);
  114. emit<Bytecode::Op::CreateLexicalEnvironment>();
  115. }
  116. void Generator::end_variable_scope()
  117. {
  118. end_boundary(BlockBoundaryType::LeaveLexicalEnvironment);
  119. if (!m_current_basic_block->is_terminated()) {
  120. emit<Bytecode::Op::LeaveLexicalEnvironment>();
  121. }
  122. }
  123. void Generator::begin_continuable_scope(Label continue_target, Vector<DeprecatedFlyString> const& language_label_set)
  124. {
  125. m_continuable_scopes.append({ continue_target, language_label_set });
  126. start_boundary(BlockBoundaryType::Continue);
  127. }
  128. void Generator::end_continuable_scope()
  129. {
  130. m_continuable_scopes.take_last();
  131. end_boundary(BlockBoundaryType::Continue);
  132. }
  133. Label Generator::nearest_breakable_scope() const
  134. {
  135. return m_breakable_scopes.last().bytecode_target;
  136. }
  137. void Generator::begin_breakable_scope(Label breakable_target, Vector<DeprecatedFlyString> const& language_label_set)
  138. {
  139. m_breakable_scopes.append({ breakable_target, language_label_set });
  140. start_boundary(BlockBoundaryType::Break);
  141. }
  142. void Generator::end_breakable_scope()
  143. {
  144. m_breakable_scopes.take_last();
  145. end_boundary(BlockBoundaryType::Break);
  146. }
  147. CodeGenerationErrorOr<Generator::ReferenceRegisters> Generator::emit_super_reference(MemberExpression const& expression)
  148. {
  149. VERIFY(is<SuperExpression>(expression.object()));
  150. // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
  151. // 1. Let env be GetThisEnvironment().
  152. // 2. Let actualThis be ? env.GetThisBinding().
  153. auto actual_this_register = allocate_register();
  154. emit<Bytecode::Op::ResolveThisBinding>();
  155. emit<Bytecode::Op::Store>(actual_this_register);
  156. Optional<Bytecode::Register> computed_property_value_register;
  157. if (expression.is_computed()) {
  158. // SuperProperty : super [ Expression ]
  159. // 3. Let propertyNameReference be ? Evaluation of Expression.
  160. // 4. Let propertyNameValue be ? GetValue(propertyNameReference).
  161. FIXME_NEWBC TRY(expression.property().generate_bytecode(*this));
  162. computed_property_value_register = allocate_register();
  163. emit<Bytecode::Op::Store>(*computed_property_value_register);
  164. }
  165. // 5/7. Return ? MakeSuperPropertyReference(actualThis, propertyKey, strict).
  166. // https://tc39.es/ecma262/#sec-makesuperpropertyreference
  167. // 1. Let env be GetThisEnvironment().
  168. // 2. Assert: env.HasSuperBinding() is true.
  169. // 3. Let baseValue be ? env.GetSuperBase().
  170. auto super_base_register = allocate_register();
  171. emit<Bytecode::Op::ResolveSuperBase>();
  172. emit<Bytecode::Op::Store>(super_base_register);
  173. // 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
  174. return ReferenceRegisters {
  175. .base = super_base_register,
  176. .referenced_name = move(computed_property_value_register),
  177. .this_value = actual_this_register,
  178. };
  179. }
  180. CodeGenerationErrorOr<Optional<Generator::ReferenceRegisters>> Generator::emit_load_from_reference(JS::ASTNode const& node, CollectRegisters collect_registers)
  181. {
  182. if (is<Identifier>(node)) {
  183. auto& identifier = static_cast<Identifier const&>(node);
  184. FIXME_NEWBC TRY(identifier.generate_bytecode(*this));
  185. return Optional<ReferenceRegisters> {};
  186. }
  187. if (is<MemberExpression>(node)) {
  188. auto& expression = static_cast<MemberExpression const&>(node);
  189. // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
  190. if (is<SuperExpression>(expression.object())) {
  191. auto super_reference = TRY(emit_super_reference(expression));
  192. if (super_reference.referenced_name.has_value()) {
  193. // 5. Let propertyKey be ? ToPropertyKey(propertyNameValue).
  194. // FIXME: This does ToPropertyKey out of order, which is observable by Symbol.toPrimitive!
  195. emit<Bytecode::Op::Load>(*super_reference.referenced_name);
  196. emit<Bytecode::Op::GetByValueWithThis>(super_reference.base, super_reference.this_value);
  197. } else {
  198. // 3. Let propertyKey be StringValue of IdentifierName.
  199. auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
  200. emit_get_by_id_with_this(identifier_table_ref, super_reference.this_value);
  201. }
  202. return super_reference;
  203. } else {
  204. FIXME_NEWBC TRY(expression.object().generate_bytecode(*this));
  205. if (expression.is_computed()) {
  206. auto object_reg = allocate_register();
  207. emit<Bytecode::Op::Store>(object_reg);
  208. FIXME_NEWBC TRY(expression.property().generate_bytecode(*this));
  209. Optional<Register> property_reg {};
  210. if (collect_registers == CollectRegisters::Yes) {
  211. property_reg = allocate_register();
  212. emit<Bytecode::Op::Store>(property_reg.value());
  213. }
  214. emit<Bytecode::Op::GetByValue>(object_reg);
  215. if (collect_registers == CollectRegisters::Yes)
  216. return ReferenceRegisters {
  217. .base = object_reg,
  218. .referenced_name = property_reg.value(),
  219. .this_value = object_reg,
  220. };
  221. return Optional<ReferenceRegisters> {};
  222. } else if (expression.property().is_identifier()) {
  223. auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
  224. emit_get_by_id(identifier_table_ref);
  225. } else if (expression.property().is_private_identifier()) {
  226. auto identifier_table_ref = intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
  227. emit<Bytecode::Op::GetPrivateById>(identifier_table_ref);
  228. } else {
  229. return CodeGenerationError {
  230. &expression,
  231. "Unimplemented non-computed member expression"sv
  232. };
  233. }
  234. }
  235. return Optional<ReferenceRegisters> {};
  236. }
  237. return CodeGenerationError {
  238. &node,
  239. "Unimplemented/invalid node used a reference"sv
  240. };
  241. }
  242. CodeGenerationErrorOr<Optional<Operand>> Generator::emit_store_to_reference(JS::ASTNode const& node)
  243. {
  244. if (is<Identifier>(node)) {
  245. auto& identifier = static_cast<Identifier const&>(node);
  246. emit_set_variable(identifier);
  247. return Optional<Operand> {};
  248. }
  249. if (is<MemberExpression>(node)) {
  250. // NOTE: The value is in the accumulator, so we have to store that away first.
  251. auto value_reg = allocate_register();
  252. emit<Bytecode::Op::Store>(value_reg);
  253. auto& expression = static_cast<MemberExpression const&>(node);
  254. // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
  255. if (is<SuperExpression>(expression.object())) {
  256. auto super_reference = TRY(emit_super_reference(expression));
  257. emit<Bytecode::Op::Load>(value_reg);
  258. // 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
  259. if (super_reference.referenced_name.has_value()) {
  260. // 5. Let propertyKey be ? ToPropertyKey(propertyNameValue).
  261. // FIXME: This does ToPropertyKey out of order, which is observable by Symbol.toPrimitive!
  262. emit<Bytecode::Op::PutByValueWithThis>(super_reference.base, *super_reference.referenced_name, super_reference.this_value);
  263. } else {
  264. // 3. Let propertyKey be StringValue of IdentifierName.
  265. auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
  266. emit<Bytecode::Op::PutByIdWithThis>(super_reference.base, super_reference.this_value, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, next_property_lookup_cache());
  267. }
  268. } else {
  269. FIXME_NEWBC TRY(expression.object().generate_bytecode(*this));
  270. auto object_reg = allocate_register();
  271. emit<Bytecode::Op::Store>(object_reg);
  272. if (expression.is_computed()) {
  273. FIXME_NEWBC TRY(expression.property().generate_bytecode(*this));
  274. auto property_reg = allocate_register();
  275. emit<Bytecode::Op::Store>(property_reg);
  276. emit<Bytecode::Op::Load>(value_reg);
  277. emit<Bytecode::Op::PutByValue>(object_reg, property_reg);
  278. } else if (expression.property().is_identifier()) {
  279. emit<Bytecode::Op::Load>(value_reg);
  280. auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
  281. emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref, Bytecode::Op::PropertyKind::KeyValue, next_property_lookup_cache());
  282. } else if (expression.property().is_private_identifier()) {
  283. emit<Bytecode::Op::Load>(value_reg);
  284. auto identifier_table_ref = intern_identifier(verify_cast<PrivateIdentifier>(expression.property()).string());
  285. emit<Bytecode::Op::PutPrivateById>(object_reg, identifier_table_ref);
  286. } else {
  287. return CodeGenerationError {
  288. &expression,
  289. "Unimplemented non-computed member expression"sv
  290. };
  291. }
  292. }
  293. return Optional<Operand> {};
  294. }
  295. return CodeGenerationError {
  296. &node,
  297. "Unimplemented/invalid node used a reference"sv
  298. };
  299. }
  300. CodeGenerationErrorOr<Optional<Operand>> Generator::emit_store_to_reference(ReferenceRegisters const& reference_registers)
  301. {
  302. if (reference_registers.base == reference_registers.this_value)
  303. emit<Bytecode::Op::PutByValue>(reference_registers.base, reference_registers.referenced_name.value());
  304. else
  305. emit<Bytecode::Op::PutByValueWithThis>(reference_registers.base, reference_registers.referenced_name.value(), reference_registers.this_value);
  306. return Optional<Operand> {};
  307. }
  308. CodeGenerationErrorOr<Optional<Operand>> Generator::emit_delete_reference(JS::ASTNode const& node)
  309. {
  310. if (is<Identifier>(node)) {
  311. auto& identifier = static_cast<Identifier const&>(node);
  312. if (identifier.is_local())
  313. emit<Bytecode::Op::LoadImmediate>(Value(false));
  314. else
  315. emit<Bytecode::Op::DeleteVariable>(intern_identifier(identifier.string()));
  316. return Optional<Operand> {};
  317. }
  318. if (is<MemberExpression>(node)) {
  319. auto& expression = static_cast<MemberExpression const&>(node);
  320. // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
  321. if (is<SuperExpression>(expression.object())) {
  322. auto super_reference = TRY(emit_super_reference(expression));
  323. if (super_reference.referenced_name.has_value()) {
  324. emit<Bytecode::Op::DeleteByValueWithThis>(super_reference.this_value, *super_reference.referenced_name);
  325. } else {
  326. auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
  327. emit<Bytecode::Op::DeleteByIdWithThis>(super_reference.this_value, identifier_table_ref);
  328. }
  329. return Optional<Operand> {};
  330. }
  331. FIXME_NEWBC TRY(expression.object().generate_bytecode(*this));
  332. if (expression.is_computed()) {
  333. auto object_reg = allocate_register();
  334. emit<Bytecode::Op::Store>(object_reg);
  335. FIXME_NEWBC TRY(expression.property().generate_bytecode(*this));
  336. emit<Bytecode::Op::DeleteByValue>(object_reg);
  337. } else if (expression.property().is_identifier()) {
  338. auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string());
  339. emit<Bytecode::Op::DeleteById>(identifier_table_ref);
  340. } else {
  341. // NOTE: Trying to delete a private field generates a SyntaxError in the parser.
  342. return CodeGenerationError {
  343. &expression,
  344. "Unimplemented non-computed member expression"sv
  345. };
  346. }
  347. return Optional<Operand> {};
  348. }
  349. // Though this will have no deletion effect, we still have to evaluate the node as it can have side effects.
  350. // For example: delete a(); delete ++c.b; etc.
  351. // 13.5.1.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation
  352. // 1. Let ref be the result of evaluating UnaryExpression.
  353. // 2. ReturnIfAbrupt(ref).
  354. FIXME_NEWBC TRY(node.generate_bytecode(*this));
  355. // 3. If ref is not a Reference Record, return true.
  356. emit<Bytecode::Op::LoadImmediate>(Value(true));
  357. // NOTE: The rest of the steps are handled by Delete{Variable,ByValue,Id}.
  358. return Optional<Operand> {};
  359. }
  360. void Generator::emit_set_variable(JS::Identifier const& identifier, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Op::EnvironmentMode mode)
  361. {
  362. if (identifier.is_local()) {
  363. emit<Bytecode::Op::SetLocal>(identifier.local_variable_index());
  364. } else {
  365. emit<Bytecode::Op::SetVariable>(intern_identifier(identifier.string()), next_environment_variable_cache(), initialization_mode, mode);
  366. }
  367. }
  368. void Generator::generate_scoped_jump(JumpType type)
  369. {
  370. TemporaryChange temp { m_current_unwind_context, m_current_unwind_context };
  371. bool last_was_finally = false;
  372. for (size_t i = m_boundaries.size(); i > 0; --i) {
  373. auto boundary = m_boundaries[i - 1];
  374. using enum BlockBoundaryType;
  375. switch (boundary) {
  376. case Break:
  377. if (type == JumpType::Break) {
  378. emit<Op::Jump>(nearest_breakable_scope());
  379. return;
  380. }
  381. break;
  382. case Continue:
  383. if (type == JumpType::Continue) {
  384. emit<Op::Jump>(nearest_continuable_scope());
  385. return;
  386. }
  387. break;
  388. case Unwind:
  389. VERIFY(last_was_finally || !m_current_unwind_context->finalizer().has_value());
  390. if (!last_was_finally) {
  391. VERIFY(m_current_unwind_context && m_current_unwind_context->handler().has_value());
  392. emit<Bytecode::Op::LeaveUnwindContext>();
  393. m_current_unwind_context = m_current_unwind_context->previous();
  394. }
  395. last_was_finally = false;
  396. break;
  397. case LeaveLexicalEnvironment:
  398. emit<Bytecode::Op::LeaveLexicalEnvironment>();
  399. break;
  400. case ReturnToFinally: {
  401. VERIFY(m_current_unwind_context->finalizer().has_value());
  402. m_current_unwind_context = m_current_unwind_context->previous();
  403. auto jump_type_name = type == JumpType::Break ? "break"sv : "continue"sv;
  404. auto block_name = MUST(String::formatted("{}.{}", current_block().name(), jump_type_name));
  405. auto& block = make_block(block_name);
  406. emit<Op::ScheduleJump>(Label { block });
  407. switch_to_basic_block(block);
  408. last_was_finally = true;
  409. break;
  410. };
  411. }
  412. }
  413. VERIFY_NOT_REACHED();
  414. }
  415. void Generator::generate_labelled_jump(JumpType type, DeprecatedFlyString const& label)
  416. {
  417. TemporaryChange temp { m_current_unwind_context, m_current_unwind_context };
  418. size_t current_boundary = m_boundaries.size();
  419. bool last_was_finally = false;
  420. auto const& jumpable_scopes = type == JumpType::Continue ? m_continuable_scopes : m_breakable_scopes;
  421. for (auto const& jumpable_scope : jumpable_scopes.in_reverse()) {
  422. for (; current_boundary > 0; --current_boundary) {
  423. auto boundary = m_boundaries[current_boundary - 1];
  424. if (boundary == BlockBoundaryType::Unwind) {
  425. VERIFY(last_was_finally || !m_current_unwind_context->finalizer().has_value());
  426. if (!last_was_finally) {
  427. VERIFY(m_current_unwind_context && m_current_unwind_context->handler().has_value());
  428. emit<Bytecode::Op::LeaveUnwindContext>();
  429. m_current_unwind_context = m_current_unwind_context->previous();
  430. }
  431. last_was_finally = false;
  432. } else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) {
  433. emit<Bytecode::Op::LeaveLexicalEnvironment>();
  434. } else if (boundary == BlockBoundaryType::ReturnToFinally) {
  435. VERIFY(m_current_unwind_context->finalizer().has_value());
  436. m_current_unwind_context = m_current_unwind_context->previous();
  437. auto jump_type_name = type == JumpType::Break ? "break"sv : "continue"sv;
  438. auto block_name = MUST(String::formatted("{}.{}", current_block().name(), jump_type_name));
  439. auto& block = make_block(block_name);
  440. emit<Op::ScheduleJump>(Label { block });
  441. switch_to_basic_block(block);
  442. last_was_finally = true;
  443. } else if ((type == JumpType::Continue && boundary == BlockBoundaryType::Continue) || (type == JumpType::Break && boundary == BlockBoundaryType::Break)) {
  444. // Make sure we don't process this boundary twice if the current jumpable scope doesn't contain the target label.
  445. --current_boundary;
  446. break;
  447. }
  448. }
  449. if (jumpable_scope.language_label_set.contains_slow(label)) {
  450. emit<Op::Jump>(jumpable_scope.bytecode_target);
  451. return;
  452. }
  453. }
  454. // We must have a jumpable scope available that contains the label, as this should be enforced by the parser.
  455. VERIFY_NOT_REACHED();
  456. }
  457. void Generator::generate_break()
  458. {
  459. generate_scoped_jump(JumpType::Break);
  460. }
  461. void Generator::generate_break(DeprecatedFlyString const& break_label)
  462. {
  463. generate_labelled_jump(JumpType::Break, break_label);
  464. }
  465. void Generator::generate_continue()
  466. {
  467. generate_scoped_jump(JumpType::Continue);
  468. }
  469. void Generator::generate_continue(DeprecatedFlyString const& continue_label)
  470. {
  471. generate_labelled_jump(JumpType::Continue, continue_label);
  472. }
  473. void Generator::push_home_object(Register register_)
  474. {
  475. m_home_objects.append(register_);
  476. }
  477. void Generator::pop_home_object()
  478. {
  479. m_home_objects.take_last();
  480. }
  481. void Generator::emit_new_function(FunctionExpression const& function_node, Optional<IdentifierTableIndex> lhs_name)
  482. {
  483. if (m_home_objects.is_empty())
  484. emit<Op::NewFunction>(function_node, lhs_name);
  485. else
  486. emit<Op::NewFunction>(function_node, lhs_name, m_home_objects.last());
  487. }
  488. CodeGenerationErrorOr<void> Generator::emit_named_evaluation_if_anonymous_function(Expression const& expression, Optional<IdentifierTableIndex> lhs_name)
  489. {
  490. if (is<FunctionExpression>(expression)) {
  491. auto const& function_expression = static_cast<FunctionExpression const&>(expression);
  492. if (!function_expression.has_name()) {
  493. FIXME_NEWBC TRY(function_expression.generate_bytecode_with_lhs_name(*this, move(lhs_name)));
  494. return {};
  495. }
  496. }
  497. if (is<ClassExpression>(expression)) {
  498. auto const& class_expression = static_cast<ClassExpression const&>(expression);
  499. if (!class_expression.has_name()) {
  500. FIXME_NEWBC TRY(class_expression.generate_bytecode_with_lhs_name(*this, move(lhs_name)));
  501. return {};
  502. }
  503. }
  504. FIXME_NEWBC TRY(expression.generate_bytecode(*this));
  505. return {};
  506. }
  507. void Generator::emit_get_by_id(IdentifierTableIndex id)
  508. {
  509. emit<Op::GetById>(id, m_next_property_lookup_cache++);
  510. }
  511. void Generator::emit_get_by_id_with_this(IdentifierTableIndex id, Register this_reg)
  512. {
  513. emit<Op::GetByIdWithThis>(id, this_reg, m_next_property_lookup_cache++);
  514. }
  515. void Generator::emit_iterator_value()
  516. {
  517. emit_get_by_id(intern_identifier("value"sv));
  518. }
  519. void Generator::emit_iterator_complete()
  520. {
  521. emit_get_by_id(intern_identifier("done"sv));
  522. }
  523. }