diff options
-rw-r--r-- | Userland/Libraries/LibJS/AST.h | 9 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 155 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.cpp | 68 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.h | 16 |
4 files changed, 218 insertions, 30 deletions
diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 743cd5bacd..62f3ef1686 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -113,6 +113,8 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const; FlyString const& label() const { return m_label; } FlyString& label() { return m_label; } @@ -142,6 +144,7 @@ public: using Statement::Statement; virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const = 0; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const; private: virtual bool is_iteration_statement() const final { return true; } @@ -803,6 +806,7 @@ public: virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const override; private: NonnullRefPtr<Expression> m_test; @@ -825,6 +829,7 @@ public: virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const override; private: NonnullRefPtr<Expression> m_test; @@ -872,6 +877,7 @@ public: virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const override; private: RefPtr<ASTNode> m_init; @@ -896,6 +902,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const override; virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; @@ -921,6 +928,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const override; virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; @@ -2002,6 +2010,7 @@ public: virtual void dump(int indent) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const; Completion execute_impl(Interpreter&, GlobalObject&) const; void add_case(NonnullRefPtr<SwitchCase> switch_case) { m_cases.append(move(switch_case)); } diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index f35c25bfa8..8e4e322b60 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -618,8 +618,81 @@ Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(By return {}; } +// 14.13.3 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-labelled-statements-runtime-semantics-evaluation +// LabelledStatement : LabelIdentifier : LabelledItem +Bytecode::CodeGenerationErrorOr<void> LabelledStatement::generate_bytecode(Bytecode::Generator& generator) const +{ + // Return ? LabelledEvaluation of this LabelledStatement with argument « ». + return generate_labelled_evaluation(generator, {}); +} + +// 14.13.4 Runtime Semantics: LabelledEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-labelledevaluation +// LabelledStatement : LabelIdentifier : LabelledItem +Bytecode::CodeGenerationErrorOr<void> LabelledStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ + // Convert the m_labelled_item NNRP to a reference early so we don't have to do it every single time we want to use it. + auto const& labelled_item = *m_labelled_item; + + // 1. Let label be the StringValue of LabelIdentifier. + // NOTE: Not necessary, this is m_label. + + // 2. Let newLabelSet be the list-concatenation of labelSet and « label ». + // FIXME: Avoid copy here. + auto new_label_set = label_set; + new_label_set.append(m_label); + + // 3. Let stmtResult be LabelledEvaluation of LabelledItem with argument newLabelSet. + // NOTE: stmtResult will be in the accumulator after running the generated bytecode. + if (is<IterationStatement>(labelled_item)) { + auto const& iteration_statement = static_cast<IterationStatement const&>(labelled_item); + TRY(iteration_statement.generate_labelled_evaluation(generator, new_label_set)); + } else if (is<SwitchStatement>(labelled_item)) { + auto const& switch_statement = static_cast<SwitchStatement const&>(labelled_item); + TRY(switch_statement.generate_labelled_evaluation(generator, new_label_set)); + } else if (is<LabelledStatement>(labelled_item)) { + auto const& labelled_statement = static_cast<LabelledStatement const&>(labelled_item); + TRY(labelled_statement.generate_labelled_evaluation(generator, new_label_set)); + } else { + auto& labelled_break_block = generator.make_block(); + + // NOTE: We do not need a continuable scope as `continue;` is not allowed outside of iteration statements, throwing a SyntaxError in the parser. + generator.begin_breakable_scope(Bytecode::Label { labelled_break_block }, new_label_set); + TRY(labelled_item.generate_bytecode(generator)); + generator.end_breakable_scope(); + + if (!generator.is_current_block_terminated()) { + generator.emit<Bytecode::Op::Jump>().set_targets( + Bytecode::Label { labelled_break_block }, + {}); + } + + generator.switch_to_basic_block(labelled_break_block); + } + + // 4. If stmtResult.[[Type]] is break and SameValue(stmtResult.[[Target]], label) is true, then + // a. Set stmtResult to NormalCompletion(stmtResult.[[Value]]). + // NOTE: These steps are performed by making labelled break jump straight to the appropriate break block, which preserves the statement result's value in the accumulator. + + // 5. Return Completion(stmtResult). + // NOTE: This is in the accumulator. + return {}; +} + +Bytecode::CodeGenerationErrorOr<void> IterationStatement::generate_labelled_evaluation(Bytecode::Generator&, Vector<FlyString> const&) const +{ + return Bytecode::CodeGenerationError { + this, + "Missing generate_labelled_evaluation()"sv, + }; +} + Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_bytecode(Bytecode::Generator& generator) const { + return generate_labelled_evaluation(generator, {}); +} + +Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ // test // jump if_false (true) end (false) body // body @@ -646,8 +719,8 @@ Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_bytecode(Bytecode Bytecode::Label { end_block }); generator.switch_to_basic_block(body_block); - generator.begin_continuable_scope(Bytecode::Label { test_block }); - generator.begin_breakable_scope(Bytecode::Label { end_block }); + generator.begin_continuable_scope(Bytecode::Label { test_block }, label_set); + generator.begin_breakable_scope(Bytecode::Label { end_block }, label_set); TRY(m_body->generate_bytecode(generator)); generator.end_breakable_scope(); generator.end_continuable_scope(); @@ -665,6 +738,11 @@ Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_bytecode(Bytecode Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const { + return generate_labelled_evaluation(generator, {}); +} + +Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ // jump always (true) body // test // jump if_false (true) end (false) body @@ -692,8 +770,8 @@ Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_bytecode(Byteco Bytecode::Label { end_block }); generator.switch_to_basic_block(body_block); - generator.begin_continuable_scope(Bytecode::Label { test_block }); - generator.begin_breakable_scope(Bytecode::Label { end_block }); + generator.begin_continuable_scope(Bytecode::Label { test_block }, label_set); + generator.begin_breakable_scope(Bytecode::Label { end_block }, label_set); TRY(m_body->generate_bytecode(generator)); generator.end_breakable_scope(); generator.end_continuable_scope(); @@ -711,6 +789,11 @@ Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_bytecode(Byteco Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_bytecode(Bytecode::Generator& generator) const { + return generate_labelled_evaluation(generator, {}); +} + +Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ // init // jump always (true) test // test @@ -732,6 +815,9 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_bytecode(Bytecode:: bool has_lexical_environment = false; + // The breakable scope needs to start here to unwind the potentially created lexical environment for the init bytecode. + generator.begin_breakable_scope(Bytecode::Label { end_block }, label_set); + if (m_init) { if (m_init->is_variable_declaration()) { auto& variable_declaration = verify_cast<VariableDeclaration>(*m_init); @@ -783,10 +869,8 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_bytecode(Bytecode:: } generator.switch_to_basic_block(*body_block_ptr); - generator.begin_continuable_scope(Bytecode::Label { *update_block_ptr }); - generator.begin_breakable_scope(Bytecode::Label { end_block }); + generator.begin_continuable_scope(Bytecode::Label { *update_block_ptr }, label_set); TRY(m_body->generate_bytecode(generator)); - generator.end_breakable_scope(); generator.end_continuable_scope(); if (!generator.is_current_block_terminated()) { @@ -810,6 +894,7 @@ Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_bytecode(Bytecode:: if (has_lexical_environment) generator.end_variable_scope(); + generator.end_breakable_scope(); return {}; } @@ -1345,9 +1430,17 @@ Bytecode::CodeGenerationErrorOr<void> IfStatement::generate_bytecode(Bytecode::G Bytecode::CodeGenerationErrorOr<void> ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const { - generator.perform_needed_unwinds<Bytecode::Op::Jump>(); + if (m_target_label.is_null()) { + generator.perform_needed_unwinds<Bytecode::Op::Jump>(); + generator.emit<Bytecode::Op::Jump>().set_targets( + generator.nearest_continuable_scope(), + {}); + return {}; + } + + auto target_to_jump_to = generator.perform_needed_unwinds_for_labelled_continue_and_return_target_block(m_target_label); generator.emit<Bytecode::Op::Jump>().set_targets( - generator.nearest_continuable_scope(), + target_to_jump_to, {}); return {}; } @@ -1524,9 +1617,17 @@ Bytecode::CodeGenerationErrorOr<void> ThrowStatement::generate_bytecode(Bytecode Bytecode::CodeGenerationErrorOr<void> BreakStatement::generate_bytecode(Bytecode::Generator& generator) const { - generator.perform_needed_unwinds<Bytecode::Op::Jump>(true); + if (m_target_label.is_null()) { + generator.perform_needed_unwinds<Bytecode::Op::Jump>(true); + generator.emit<Bytecode::Op::Jump>().set_targets( + generator.nearest_breakable_scope(), + {}); + return {}; + } + + auto target_to_jump_to = generator.perform_needed_unwinds_for_labelled_break_and_return_target_block(m_target_label); generator.emit<Bytecode::Op::Jump>().set_targets( - generator.nearest_breakable_scope(), + target_to_jump_to, {}); return {}; } @@ -1615,6 +1716,11 @@ Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode:: Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const { + return generate_labelled_evaluation(generator, {}); +} + +Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ auto discriminant_reg = generator.allocate_register(); TRY(m_discriminant->generate_bytecode(generator)); generator.emit<Bytecode::Op::Store>(discriminant_reg); @@ -1651,7 +1757,7 @@ Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_bytecode(Bytecod generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { end_block }, {}); } auto current_block = case_blocks.begin(); - generator.begin_breakable_scope(Bytecode::Label { end_block }); + generator.begin_breakable_scope(Bytecode::Label { end_block }, label_set); for (auto& switch_case : m_cases) { generator.switch_to_basic_block(*current_block); @@ -1858,7 +1964,7 @@ static Bytecode::CodeGenerationErrorOr<ForInOfHeadEvaluationResult> for_in_of_he } // 14.7.5.7 ForIn/OfBodyEvaluation ( lhs, stmt, iteratorRecord, iterationKind, lhsKind, labelSet [ , iteratorKind ] ), https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset -static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant<NonnullRefPtr<ASTNode>, NonnullRefPtr<BindingPattern>> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update) +static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant<NonnullRefPtr<ASTNode>, NonnullRefPtr<BindingPattern>> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector<FlyString> const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update) { auto iterator_register = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(iterator_register); @@ -1888,6 +1994,7 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode: // 6. Repeat, generator.emit<Bytecode::Op::Jump>(Bytecode::Label { loop_update }); generator.switch_to_basic_block(loop_update); + generator.begin_continuable_scope(Bytecode::Label { loop_update }, label_set); // a. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). generator.emit<Bytecode::Op::Load>(iterator_register); @@ -2042,31 +2149,39 @@ static Bytecode::CodeGenerationErrorOr<void> for_in_of_body_evaluation(Bytecode: return {}; } -// 14.7.5.5 Runtime Semantics: ForInOfLoopEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-forinofloopevaluation Bytecode::CodeGenerationErrorOr<void> ForInStatement::generate_bytecode(Bytecode::Generator& generator) const { + return generate_labelled_evaluation(generator, {}); +} + +// 14.7.5.5 Runtime Semantics: ForInOfLoopEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-forinofloopevaluation +Bytecode::CodeGenerationErrorOr<void> ForInStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ auto& loop_end = generator.make_block(); auto& loop_update = generator.make_block(); - generator.begin_breakable_scope(Bytecode::Label { loop_end }); - generator.begin_continuable_scope(Bytecode::Label { loop_update }); + generator.begin_breakable_scope(Bytecode::Label { loop_end }, label_set); auto head_result = TRY(for_in_of_head_evaluation(generator, IterationKind::Enumerate, m_lhs, m_rhs)); // Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over. - return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, loop_end, loop_update); + return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, label_set, loop_end, loop_update); } Bytecode::CodeGenerationErrorOr<void> ForOfStatement::generate_bytecode(Bytecode::Generator& generator) const { + return generate_labelled_evaluation(generator, {}); +} + +Bytecode::CodeGenerationErrorOr<void> ForOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector<FlyString> const& label_set) const +{ auto& loop_end = generator.make_block(); auto& loop_update = generator.make_block(); - generator.begin_breakable_scope(Bytecode::Label { loop_end }); - generator.begin_continuable_scope(Bytecode::Label { loop_update }); + generator.begin_breakable_scope(Bytecode::Label { loop_end }, label_set); auto head_result = TRY(for_in_of_head_evaluation(generator, IterationKind::Iterate, m_lhs, m_rhs)); // Now perform the rest of ForInOfLoopEvaluation, given that the accumulator holds the iterator we're supposed to iterate over. - return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, loop_end, loop_update); + return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, label_set, loop_end, loop_update); } // 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index 74dff1df70..3dc1799104 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -69,7 +69,7 @@ Register Generator::allocate_register() Label Generator::nearest_continuable_scope() const { - return m_continuable_scopes.last(); + return m_continuable_scopes.last().bytecode_target; } void Generator::begin_variable_scope(BindingMode mode, SurroundingScopeKind kind) @@ -99,9 +99,9 @@ void Generator::end_variable_scope() } } -void Generator::begin_continuable_scope(Label continue_target) +void Generator::begin_continuable_scope(Label continue_target, Vector<FlyString> const& language_label_set) { - m_continuable_scopes.append(continue_target); + m_continuable_scopes.append({ continue_target, language_label_set }); start_boundary(BlockBoundaryType::Continue); } @@ -110,13 +110,15 @@ void Generator::end_continuable_scope() m_continuable_scopes.take_last(); end_boundary(BlockBoundaryType::Continue); } + Label Generator::nearest_breakable_scope() const { - return m_breakable_scopes.last(); + return m_breakable_scopes.last().bytecode_target; } -void Generator::begin_breakable_scope(Label breakable_target) + +void Generator::begin_breakable_scope(Label breakable_target, Vector<FlyString> const& language_label_set) { - m_breakable_scopes.append(breakable_target); + m_breakable_scopes.append({ breakable_target, language_label_set }); start_boundary(BlockBoundaryType::Break); } @@ -246,6 +248,60 @@ CodeGenerationErrorOr<void> Generator::emit_delete_reference(JS::ASTNode const& return {}; } +Label Generator::perform_needed_unwinds_for_labelled_break_and_return_target_block(FlyString const& break_label) +{ + size_t current_boundary = m_boundaries.size(); + for (auto& breakable_scope : m_breakable_scopes.in_reverse()) { + for (; current_boundary > 0; --current_boundary) { + auto boundary = m_boundaries[current_boundary - 1]; + if (boundary == BlockBoundaryType::Unwind) { + emit<Bytecode::Op::LeaveUnwindContext>(); + } else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) { + emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Lexical); + } else if (boundary == BlockBoundaryType::LeaveVariableEnvironment) { + emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Var); + } else if (boundary == BlockBoundaryType::Break) { + // Make sure we don't process this boundary twice if the current breakable scope doesn't contain the target label. + --current_boundary; + break; + } + } + + if (breakable_scope.language_label_set.contains_slow(break_label)) + return breakable_scope.bytecode_target; + } + + // We must have a breakable scope available that contains the label, as this should be enforced by the parser. + VERIFY_NOT_REACHED(); +} + +Label Generator::perform_needed_unwinds_for_labelled_continue_and_return_target_block(FlyString const& continue_label) +{ + size_t current_boundary = m_boundaries.size(); + for (auto& continuable_scope : m_continuable_scopes.in_reverse()) { + for (; current_boundary > 0; --current_boundary) { + auto boundary = m_boundaries[current_boundary - 1]; + if (boundary == BlockBoundaryType::Unwind) { + emit<Bytecode::Op::LeaveUnwindContext>(); + } else if (boundary == BlockBoundaryType::LeaveLexicalEnvironment) { + emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Lexical); + } else if (boundary == BlockBoundaryType::LeaveVariableEnvironment) { + emit<Bytecode::Op::LeaveEnvironment>(Bytecode::Op::EnvironmentMode::Var); + } else if (boundary == BlockBoundaryType::Continue) { + // Make sure we don't process this boundary twice if the current continuable scope doesn't contain the target label. + --current_boundary; + break; + } + } + + if (continuable_scope.language_label_set.contains_slow(continue_label)) + return continuable_scope.bytecode_target; + } + + // We must have a continuable scope available that contains the label, as this should be enforced by the parser. + VERIFY_NOT_REACHED(); +} + String CodeGenerationError::to_string() { return String::formatted("CodeGenerationError in {}: {}", failing_node ? failing_node->class_name() : "<unknown node>", reason_literal); diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index f63f9e7b0f..6af3c9bfdb 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -81,9 +81,9 @@ public: CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&); CodeGenerationErrorOr<void> emit_delete_reference(JS::ASTNode const&); - void begin_continuable_scope(Label continue_target); + void begin_continuable_scope(Label continue_target, Vector<FlyString> const& language_label_set); void end_continuable_scope(); - void begin_breakable_scope(Label breakable_target); + void begin_breakable_scope(Label breakable_target, Vector<FlyString> const& language_label_set); void end_breakable_scope(); [[nodiscard]] Label nearest_continuable_scope() const; @@ -186,6 +186,9 @@ public: } } + Label perform_needed_unwinds_for_labelled_break_and_return_target_block(FlyString const& break_label); + Label perform_needed_unwinds_for_labelled_continue_and_return_target_block(FlyString const& continue_label); + void start_boundary(BlockBoundaryType type) { m_boundaries.append(type); } void end_boundary(BlockBoundaryType type) { @@ -200,6 +203,11 @@ private: void grow(size_t); void* next_slot(); + struct LabelableScope { + Label bytecode_target; + Vector<FlyString> language_label_set; + }; + BasicBlock* m_current_basic_block { nullptr }; NonnullOwnPtrVector<BasicBlock> m_root_basic_blocks; NonnullOwnPtr<StringTable> m_string_table; @@ -208,8 +216,8 @@ private: u32 m_next_register { 2 }; u32 m_next_block { 1 }; FunctionKind m_enclosing_function_kind { FunctionKind::Normal }; - Vector<Label> m_continuable_scopes; - Vector<Label> m_breakable_scopes; + Vector<LabelableScope> m_continuable_scopes; + Vector<LabelableScope> m_breakable_scopes; Vector<LexicalScope> m_variable_scopes; Vector<BlockBoundaryType> m_boundaries; }; |