diff options
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r-- | Userland/Libraries/LibJS/AST.h | 85 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 401 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/CodeGenerationError.h | 25 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.cpp | 44 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.h | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp | 6 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp | 6 |
7 files changed, 355 insertions, 219 deletions
diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 684ff58106..fda6fe1e06 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -16,6 +16,7 @@ #include <AK/String.h> #include <AK/Variant.h> #include <AK/Vector.h> +#include <LibJS/Bytecode/CodeGenerationError.h> #include <LibJS/Forward.h> #include <LibJS/Heap/Handle.h> #include <LibJS/Runtime/Completion.h> @@ -47,7 +48,7 @@ class ASTNode : public RefCounted<ASTNode> { public: virtual ~ASTNode() { } virtual Completion execute(Interpreter&, GlobalObject&) const = 0; - virtual void generate_bytecode(Bytecode::Generator&) const; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const; virtual void dump(int indent) const; SourceRange const& source_range() const { return m_source_range; } @@ -151,7 +152,7 @@ public: { } Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; }; class ErrorStatement final : public Statement { @@ -173,7 +174,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; Expression const& expression() const { return m_expression; }; @@ -227,7 +228,7 @@ public: NonnullRefPtrVector<Statement> const& children() const { return m_children; } virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; Completion evaluate_statements(Interpreter& interpreter, GlobalObject& global_object) const; @@ -665,7 +666,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; virtual ThrowCompletionOr<void> for_each_bound_name(ThrowCompletionOrVoidCallback<FlyString const&>&& callback) const override; @@ -692,7 +693,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; bool has_name() const { return !name().is_empty(); } @@ -726,7 +727,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: RefPtr<Expression> m_argument; @@ -743,7 +744,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_argument; @@ -761,7 +762,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: RefPtr<Expression> m_argument; @@ -783,7 +784,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_predicate; @@ -806,7 +807,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_test; @@ -828,7 +829,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_test; @@ -874,7 +875,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Completion loop_evaluation(Interpreter&, GlobalObject&, Vector<FlyString> const&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: RefPtr<ASTNode> m_init; @@ -988,7 +989,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: BinaryOp m_op; @@ -1014,7 +1015,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: LogicalOp m_op; @@ -1043,7 +1044,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: UnaryOp m_op; @@ -1061,7 +1062,7 @@ public: virtual void dump(int indent) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtrVector<Expression> m_expressions; @@ -1085,7 +1086,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: bool m_value { false }; @@ -1101,7 +1102,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: Value m_value; @@ -1117,7 +1118,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: String m_value; @@ -1134,7 +1135,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; StringView value() const { return m_value; } bool is_use_strict_directive() const { return m_is_use_strict_directive; }; @@ -1155,7 +1156,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; }; class RegExpLiteral final : public Literal { @@ -1172,7 +1173,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; regex::Parser::Result const& parsed_regex() const { return m_parsed_regex; } String const& parsed_pattern() const { return m_parsed_pattern; } @@ -1202,7 +1203,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual ThrowCompletionOr<Reference> to_reference(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: virtual bool is_identifier() const override { return true; } @@ -1397,7 +1398,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; virtual ThrowCompletionOr<void> for_each_bound_name(ThrowCompletionOrVoidCallback<FlyString const&>&& callback) const override; @@ -1436,7 +1437,7 @@ public: } virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; }; class CallExpression : public Expression { @@ -1455,7 +1456,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; Expression const& callee() const { return m_callee; } @@ -1541,7 +1542,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: AssignmentOp m_op; @@ -1566,7 +1567,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: virtual bool is_update_expression() const override { return true; } @@ -1628,7 +1629,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; NonnullRefPtrVector<VariableDeclarator> const& declarations() const { return m_declarations; } @@ -1694,7 +1695,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; Optional<SourceRange> const& invalid_property_range() const { return m_first_invalid_property_range; } @@ -1717,7 +1718,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: virtual bool is_array_expression() const override { return true; } @@ -1742,7 +1743,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; NonnullRefPtrVector<Expression> const& expressions() const { return m_expressions; } NonnullRefPtrVector<Expression> const& raw_strings() const { return m_raw_strings; } @@ -1763,7 +1764,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> const m_tag; @@ -1783,7 +1784,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; virtual ThrowCompletionOr<Reference> to_reference(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; bool is_computed() const { return m_computed; } Expression const& object() const { return *m_object; } @@ -1900,7 +1901,7 @@ public: virtual void dump(int indent) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_test; @@ -1951,7 +1952,7 @@ public: virtual void dump(int indent) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<BlockStatement> m_block; @@ -1971,7 +1972,7 @@ public: virtual void dump(int indent) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: NonnullRefPtr<Expression> m_argument; @@ -2004,7 +2005,7 @@ public: virtual void dump(int indent) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; Completion execute_impl(Interpreter&, GlobalObject&) const; void add_case(NonnullRefPtr<SwitchCase> switch_case) { m_cases.append(move(switch_case)); } @@ -2025,7 +2026,7 @@ public: virtual Completion execute(Interpreter&, GlobalObject&) const override; FlyString const& target_label() const { return m_target_label; } - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; private: FlyString m_target_label; @@ -2040,7 +2041,7 @@ public: } virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; FlyString const& target_label() const { return m_target_label; } @@ -2056,7 +2057,7 @@ public: } virtual Completion execute(Interpreter&, GlobalObject&) const override; - virtual void generate_bytecode(Bytecode::Generator&) const override; + virtual Bytecode::CodeGenerationErrorOr<void> generate_bytecode(Bytecode::Generator&) const override; }; class SyntheticReferenceExpression final : public Expression { diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 5cb0bfa22b..15aadf65fe 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -18,13 +18,15 @@ namespace JS { -void ASTNode::generate_bytecode(Bytecode::Generator&) const +Bytecode::CodeGenerationErrorOr<void> ASTNode::generate_bytecode(Bytecode::Generator&) const { - dbgln("Missing generate_bytecode() in {}", class_name()); - TODO(); + return Bytecode::CodeGenerationError { + this, + "Missing generate_bytecode()"sv, + }; } -void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ScopeNode::generate_bytecode(Bytecode::Generator& generator) const { // FIXME: This is an ad-hoc fix but should be done as the spec says in // {Global, Block, Function, Eval}DeclarationInstantiation. @@ -44,28 +46,31 @@ void ScopeNode::generate_bytecode(Bytecode::Generator& generator) const // FIXME: Register lexical and variable scope declarations for (auto& child : children()) { - child.generate_bytecode(generator); + TRY(child.generate_bytecode(generator)); if (generator.is_current_block_terminated()) break; } + + return {}; } -void EmptyStatement::generate_bytecode(Bytecode::Generator&) const +Bytecode::CodeGenerationErrorOr<void> EmptyStatement::generate_bytecode(Bytecode::Generator&) const { + return {}; } -void ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const { - m_expression->generate_bytecode(generator); + return m_expression->generate_bytecode(generator); } -void BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const { - m_lhs->generate_bytecode(generator); + TRY(m_lhs->generate_bytecode(generator)); auto lhs_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(lhs_reg); - m_rhs->generate_bytecode(generator); + TRY(m_rhs->generate_bytecode(generator)); switch (m_op) { case BinaryOp::Addition: @@ -137,11 +142,12 @@ void BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const default: VERIFY_NOT_REACHED(); } + return {}; } -void LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const { - m_lhs->generate_bytecode(generator); + TRY(m_lhs->generate_bytecode(generator)); // lhs // jump op (true) end (false) rhs @@ -173,18 +179,19 @@ void LogicalExpression::generate_bytecode(Bytecode::Generator& generator) const } generator.switch_to_basic_block(rhs_block); - m_rhs->generate_bytecode(generator); + TRY(m_rhs->generate_bytecode(generator)); generator.emit<Bytecode::Op::Jump>().set_targets( Bytecode::Label { end_block }, {}); generator.switch_to_basic_block(end_block); + return {}; } -void UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const { - m_lhs->generate_bytecode(generator); + TRY(m_lhs->generate_bytecode(generator)); switch (m_op) { case UnaryOp::BitwiseNot: @@ -206,59 +213,70 @@ void UnaryExpression::generate_bytecode(Bytecode::Generator& generator) const generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); break; default: - TODO(); + return Bytecode::CodeGenerationError { + this, + "Unimplemented operation"sv, + }; } + + return {}; } -void NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::LoadImmediate>(m_value); + return {}; } -void BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> BooleanLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::LoadImmediate>(Value(m_value)); + return {}; } -void NullLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> NullLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::LoadImmediate>(js_null()); + return {}; } -void BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::NewBigInt>(Crypto::SignedBigInteger::from_base(10, m_value.substring(0, m_value.length() - 1))); + return {}; } -void StringLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> StringLiteral::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::NewString>(generator.intern_string(m_value)); + return {}; } -void RegExpLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> RegExpLiteral::generate_bytecode(Bytecode::Generator& generator) const { auto source_index = generator.intern_string(m_pattern); auto flags_index = generator.intern_string(m_flags); generator.emit<Bytecode::Op::NewRegExp>(source_index, flags_index); + return {}; } -void Identifier::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> Identifier::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::GetVariable>(generator.intern_identifier(m_string)); + return {}; } -void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const { // FIXME: Implement this for BindingPatterns too. auto& lhs = m_lhs.get<NonnullRefPtr<Expression>>(); if (m_op == AssignmentOp::Assignment) { - m_rhs->generate_bytecode(generator); - generator.emit_store_to_reference(lhs); - return; + TRY(m_rhs->generate_bytecode(generator)); + return generator.emit_store_to_reference(lhs); } - generator.emit_load_from_reference(lhs); + TRY(generator.emit_load_from_reference(lhs)); Bytecode::BasicBlock* rhs_block_ptr { nullptr }; Bytecode::BasicBlock* end_block_ptr { nullptr }; @@ -294,7 +312,7 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con // if the logical assignment condition fails. auto lhs_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(lhs_reg); - m_rhs->generate_bytecode(generator); + TRY(m_rhs->generate_bytecode(generator)); switch (m_op) { case AssignmentOp::AdditionAssignment: @@ -338,10 +356,13 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con case AssignmentOp::NullishAssignment: break; // These are handled above. default: - TODO(); + return Bytecode::CodeGenerationError { + this, + "Unimplemented operation"sv, + }; } - generator.emit_store_to_reference(lhs); + TRY(generator.emit_store_to_reference(lhs)); if (end_block_ptr) { generator.emit<Bytecode::Op::Jump>().set_targets( @@ -350,9 +371,11 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con generator.switch_to_basic_block(*end_block_ptr); } + + return {}; } -void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> WhileStatement::generate_bytecode(Bytecode::Generator& generator) const { // test // jump if_false (true) end (false) body @@ -374,7 +397,7 @@ void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const {}); generator.switch_to_basic_block(test_block); - m_test->generate_bytecode(generator); + TRY(m_test->generate_bytecode(generator)); generator.emit<Bytecode::Op::JumpConditional>().set_targets( Bytecode::Label { body_block }, Bytecode::Label { end_block }); @@ -382,7 +405,7 @@ void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(body_block); generator.begin_continuable_scope(Bytecode::Label { test_block }); generator.begin_breakable_scope(Bytecode::Label { end_block }); - m_body->generate_bytecode(generator); + TRY(m_body->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) { generator.emit<Bytecode::Op::Jump>().set_targets( Bytecode::Label { test_block }, @@ -392,9 +415,11 @@ void WhileStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(end_block); generator.emit<Bytecode::Op::Load>(result_reg); } + + return {}; } -void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const { // jump always (true) body // test @@ -417,7 +442,7 @@ void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const {}); generator.switch_to_basic_block(test_block); - m_test->generate_bytecode(generator); + TRY(m_test->generate_bytecode(generator)); generator.emit<Bytecode::Op::JumpConditional>().set_targets( Bytecode::Label { body_block }, Bytecode::Label { end_block }); @@ -425,7 +450,7 @@ void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(body_block); generator.begin_continuable_scope(Bytecode::Label { test_block }); generator.begin_breakable_scope(Bytecode::Label { end_block }); - m_body->generate_bytecode(generator); + TRY(m_body->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) { generator.emit<Bytecode::Op::Jump>().set_targets( Bytecode::Label { test_block }, @@ -435,9 +460,11 @@ void DoWhileStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(end_block); generator.emit<Bytecode::Op::Load>(result_reg); } + + return {}; } -void ForStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ForStatement::generate_bytecode(Bytecode::Generator& generator) const { // init // jump always (true) test @@ -459,7 +486,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const auto& end_block = generator.make_block(); if (m_init) - m_init->generate_bytecode(generator); + TRY(m_init->generate_bytecode(generator)); body_block_ptr = &generator.make_block(); @@ -483,7 +510,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const if (m_test) { generator.switch_to_basic_block(*test_block_ptr); - m_test->generate_bytecode(generator); + TRY(m_test->generate_bytecode(generator)); generator.emit<Bytecode::Op::JumpConditional>().set_targets( Bytecode::Label { *body_block_ptr }, Bytecode::Label { end_block }); @@ -492,7 +519,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const 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 }); - m_body->generate_bytecode(generator); + TRY(m_body->generate_bytecode(generator)); generator.end_continuable_scope(); if (!generator.is_current_block_terminated()) { @@ -502,7 +529,7 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const {}); generator.switch_to_basic_block(*update_block_ptr); - m_update->generate_bytecode(generator); + TRY(m_update->generate_bytecode(generator)); } generator.emit<Bytecode::Op::Jump>().set_targets( @@ -513,50 +540,58 @@ void ForStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(end_block); generator.emit<Bytecode::Op::Load>(result_reg); } + + return {}; } -void ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::NewObject>(); if (m_properties.is_empty()) - return; + return {}; auto object_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(object_reg); for (auto& property : m_properties) { if (property.type() != ObjectProperty::Type::KeyValue) - TODO(); + return Bytecode::CodeGenerationError { + this, + "Unimplemented property kind"sv, + }; if (is<StringLiteral>(property.key())) { auto& string_literal = static_cast<StringLiteral const&>(property.key()); Bytecode::IdentifierTableIndex key_name = generator.intern_identifier(string_literal.value()); - property.value().generate_bytecode(generator); + TRY(property.value().generate_bytecode(generator)); generator.emit<Bytecode::Op::PutById>(object_reg, key_name); } else { - property.key().generate_bytecode(generator); + TRY(property.key().generate_bytecode(generator)); auto property_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(property_reg); - property.value().generate_bytecode(generator); + TRY(property.value().generate_bytecode(generator)); generator.emit<Bytecode::Op::PutByValue>(object_reg, property_reg); } } generator.emit<Bytecode::Op::Load>(object_reg); + return {}; } -void ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const { Vector<Bytecode::Register> element_regs; for (auto& element : m_elements) { if (element) { - element->generate_bytecode(generator); + TRY(element->generate_bytecode(generator)); if (is<SpreadExpression>(*element)) { - TODO(); - continue; + return Bytecode::CodeGenerationError { + this, + "Unimplemented element kind: SpreadExpression"sv, + }; } } else { generator.emit<Bytecode::Op::LoadImmediate>(Value {}); @@ -566,25 +601,28 @@ void ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const element_regs.append(element_reg); } generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(element_regs.size(), element_regs); + return {}; } -void MemberExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> MemberExpression::generate_bytecode(Bytecode::Generator& generator) const { - generator.emit_load_from_reference(*this); + return generator.emit_load_from_reference(*this); } -void FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const +Bytecode::CodeGenerationErrorOr<void> FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const { + return {}; } -void FunctionExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> FunctionExpression::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::NewFunction>(*this); + return {}; } -static void generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Register const& value_reg); +static Bytecode::CodeGenerationErrorOr<void> generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode, Bytecode::Register const& value_reg); -static void generate_object_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Register const& value_reg) +static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Register const& value_reg) { Vector<Bytecode::Register> excluded_property_names; auto has_rest = false; @@ -601,9 +639,9 @@ static void generate_object_binding_pattern_bytecode(Bytecode::Generator& genera auto interned_identifier = generator.intern_identifier(identifier); generator.emit_with_extra_register_slots<Bytecode::Op::CopyObjectExcludingProperties>(excluded_property_names.size(), value_reg, excluded_property_names); - generator.emit<Bytecode::Op::SetVariable>(interned_identifier); + generator.emit<Bytecode::Op::SetVariable>(interned_identifier, initialization_mode); - return; + return {}; } Bytecode::StringTableIndex name_index; @@ -623,7 +661,7 @@ static void generate_object_binding_pattern_bytecode(Bytecode::Generator& genera generator.emit<Bytecode::Op::GetById>(generator.intern_identifier(identifier)); } else { auto expression = name.get<NonnullRefPtr<Expression>>(); - expression->generate_bytecode(generator); + TRY(expression->generate_bytecode(generator)); if (has_rest) { auto excluded_name_reg = generator.allocate_register(); @@ -643,7 +681,7 @@ static void generate_object_binding_pattern_bytecode(Bytecode::Generator& genera Bytecode::Label { if_not_undefined_block }); generator.switch_to_basic_block(if_undefined_block); - initializer->generate_bytecode(generator); + TRY(initializer->generate_bytecode(generator)); generator.emit<Bytecode::Op::Jump>().set_targets( Bytecode::Label { if_not_undefined_block }, {}); @@ -655,23 +693,27 @@ static void generate_object_binding_pattern_bytecode(Bytecode::Generator& genera auto& binding_pattern = *alias.get<NonnullRefPtr<BindingPattern>>(); auto nested_value_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(nested_value_reg); - generate_binding_pattern_bytecode(generator, binding_pattern, nested_value_reg); + TRY(generate_binding_pattern_bytecode(generator, binding_pattern, initialization_mode, nested_value_reg)); } else if (alias.has<Empty>()) { if (name.has<NonnullRefPtr<Expression>>()) { // This needs some sort of SetVariableByValue opcode, as it's a runtime binding - TODO(); + return Bytecode::CodeGenerationError { + name.get<NonnullRefPtr<Expression>>().ptr(), + "Unimplemented name/alias pair: Empty/Expression"sv, + }; } auto& identifier = alias.get<NonnullRefPtr<Identifier>>()->string(); - generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier)); + generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier), initialization_mode); } else { auto& identifier = alias.get<NonnullRefPtr<Identifier>>()->string(); - generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier)); + generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(identifier), initialization_mode); } } + return {}; } -static void generate_array_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Register const& value_reg) +static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Register const& value_reg) { /* * Consider the following destructuring assignment: @@ -705,22 +747,27 @@ static void generate_array_binding_pattern_bytecode(Bytecode::Generator& generat auto temp_iterator_result_reg = generator.allocate_register(); auto assign_accumulator_to_alias = [&](auto& alias) { - alias.visit( - [&](Empty) { + return alias.visit( + [&](Empty) -> Bytecode::CodeGenerationErrorOr<void> { // This element is an elision + return {}; }, - [&](NonnullRefPtr<Identifier> const& identifier) { + [&](NonnullRefPtr<Identifier> const& identifier) -> Bytecode::CodeGenerationErrorOr<void> { auto interned_index = generator.intern_identifier(identifier->string()); - generator.emit<Bytecode::Op::SetVariable>(interned_index); + generator.emit<Bytecode::Op::SetVariable>(interned_index, initialization_mode); + return {}; }, - [&](NonnullRefPtr<BindingPattern> const& pattern) { + [&](NonnullRefPtr<BindingPattern> const& pattern) -> Bytecode::CodeGenerationErrorOr<void> { // Store the accumulator value in a permanent register auto target_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(target_reg); - generate_binding_pattern_bytecode(generator, pattern, target_reg); + return generate_binding_pattern_bytecode(generator, pattern, initialization_mode, target_reg); }, - [&](NonnullRefPtr<MemberExpression> const&) { - TODO(); + [&](NonnullRefPtr<MemberExpression> const& expr) -> Bytecode::CodeGenerationErrorOr<void> { + return Bytecode::CodeGenerationError { + expr.ptr(), + "Unimplemented alias mode: MemberExpression"sv, + }; }); }; @@ -758,9 +805,7 @@ static void generate_array_binding_pattern_bytecode(Bytecode::Generator& generat generator.switch_to_basic_block(continuation_block); } - assign_accumulator_to_alias(alias); - - return; + return assign_accumulator_to_alias(alias); } // In the first iteration of the loop, a few things are true which can save @@ -818,41 +863,48 @@ static void generate_array_binding_pattern_bytecode(Bytecode::Generator& generat // pattern if necessary. generator.switch_to_basic_block(create_binding_block); - assign_accumulator_to_alias(alias); + TRY(assign_accumulator_to_alias(alias)); first = false; } + + return {}; } -static void generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Register const& value_reg) +static Bytecode::CodeGenerationErrorOr<void> generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Register const& value_reg) { - if (pattern.kind == BindingPattern::Kind::Object) { - generate_object_binding_pattern_bytecode(generator, pattern, value_reg); - } else { - generate_array_binding_pattern_bytecode(generator, pattern, value_reg); - } -}; + if (pattern.kind == BindingPattern::Kind::Object) + return generate_object_binding_pattern_bytecode(generator, pattern, initialization_mode, value_reg); + + return generate_array_binding_pattern_bytecode(generator, pattern, initialization_mode, value_reg); +} -void VariableDeclaration::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> VariableDeclaration::generate_bytecode(Bytecode::Generator& generator) const { for (auto& declarator : m_declarations) { if (declarator.init()) - declarator.init()->generate_bytecode(generator); + TRY(declarator.init()->generate_bytecode(generator)); else generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); - declarator.target().visit( - [&](NonnullRefPtr<Identifier> const& id) { - generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(id->string())); + + auto initialization_mode = is_lexical_declaration() ? Bytecode::Op::SetVariable::InitializationMode::Initialize : Bytecode::Op::SetVariable::InitializationMode::Set; + + TRY(declarator.target().visit( + [&](NonnullRefPtr<Identifier> const& id) -> Bytecode::CodeGenerationErrorOr<void> { + generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(id->string()), initialization_mode); + return {}; }, - [&](NonnullRefPtr<BindingPattern> const& pattern) { + [&](NonnullRefPtr<BindingPattern> const& pattern) -> Bytecode::CodeGenerationErrorOr<void> { auto value_register = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(value_register); - generate_binding_pattern_bytecode(generator, pattern, value_register); - }); + return generate_binding_pattern_bytecode(generator, pattern, initialization_mode, value_register); + })); } + + return {}; } -void CallExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode::Generator& generator) const { auto callee_reg = generator.allocate_register(); auto this_reg = generator.allocate_register(); @@ -860,35 +912,41 @@ void CallExpression::generate_bytecode(Bytecode::Generator& generator) const generator.emit<Bytecode::Op::Store>(this_reg); if (is<NewExpression>(this)) { - m_callee->generate_bytecode(generator); + TRY(m_callee->generate_bytecode(generator)); generator.emit<Bytecode::Op::Store>(callee_reg); } else if (is<SuperExpression>(*m_callee)) { - TODO(); + return Bytecode::CodeGenerationError { + this, + "Unimplemented callee kind: SuperExpression"sv, + }; } else if (is<MemberExpression>(*m_callee)) { auto& member_expression = static_cast<const MemberExpression&>(*m_callee); if (is<SuperExpression>(member_expression.object())) { - TODO(); + return Bytecode::CodeGenerationError { + this, + "Unimplemented callee kind: MemberExpression on SuperExpression"sv, + }; + } + + TRY(member_expression.object().generate_bytecode(generator)); + generator.emit<Bytecode::Op::Store>(this_reg); + if (member_expression.is_computed()) { + TRY(member_expression.property().generate_bytecode(generator)); + generator.emit<Bytecode::Op::GetByValue>(this_reg); } else { - member_expression.object().generate_bytecode(generator); - generator.emit<Bytecode::Op::Store>(this_reg); - if (member_expression.is_computed()) { - member_expression.property().generate_bytecode(generator); - generator.emit<Bytecode::Op::GetByValue>(this_reg); - } else { - auto identifier_table_ref = generator.intern_identifier(verify_cast<Identifier>(member_expression.property()).string()); - generator.emit<Bytecode::Op::GetById>(identifier_table_ref); - } - generator.emit<Bytecode::Op::Store>(callee_reg); + auto identifier_table_ref = generator.intern_identifier(verify_cast<Identifier>(member_expression.property()).string()); + generator.emit<Bytecode::Op::GetById>(identifier_table_ref); } + generator.emit<Bytecode::Op::Store>(callee_reg); } else { // FIXME: this = global object in sloppy mode. - m_callee->generate_bytecode(generator); + TRY(m_callee->generate_bytecode(generator)); generator.emit<Bytecode::Op::Store>(callee_reg); } Vector<Bytecode::Register> argument_registers; for (auto& arg : m_arguments) { - arg.value->generate_bytecode(generator); + TRY(arg.value->generate_bytecode(generator)); auto arg_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(arg_reg); argument_registers.append(arg_reg); @@ -902,35 +960,43 @@ void CallExpression::generate_bytecode(Bytecode::Generator& generator) const } generator.emit_with_extra_register_slots<Bytecode::Op::Call>(argument_registers.size(), call_type, callee_reg, this_reg, argument_registers); + return {}; } -void ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ReturnStatement::generate_bytecode(Bytecode::Generator& generator) const { if (m_argument) - m_argument->generate_bytecode(generator); + TRY(m_argument->generate_bytecode(generator)); if (generator.is_in_generator_or_async_function()) generator.emit<Bytecode::Op::Yield>(nullptr); else generator.emit<Bytecode::Op::Return>(); + + return {}; } -void YieldExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> YieldExpression::generate_bytecode(Bytecode::Generator& generator) const { VERIFY(generator.is_in_generator_function()); - if (m_is_yield_from) - TODO(); + if (m_is_yield_from) { + return Bytecode::CodeGenerationError { + this, + "Unimplemented form: `yield*`"sv, + }; + } if (m_argument) - m_argument->generate_bytecode(generator); + TRY(m_argument->generate_bytecode(generator)); auto& continuation_block = generator.make_block(); generator.emit<Bytecode::Op::Yield>(Bytecode::Label { continuation_block }); generator.switch_to_basic_block(continuation_block); + return {}; } -void IfStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> IfStatement::generate_bytecode(Bytecode::Generator& generator) const { // test // jump if_true (true) true (false) false @@ -943,7 +1009,7 @@ void IfStatement::generate_bytecode(Bytecode::Generator& generator) const auto& true_block = generator.make_block(); auto& false_block = generator.make_block(); - m_predicate->generate_bytecode(generator); + TRY(m_predicate->generate_bytecode(generator)); generator.emit<Bytecode::Op::JumpConditional>().set_targets( Bytecode::Label { true_block }, Bytecode::Label { false_block }); @@ -952,7 +1018,7 @@ void IfStatement::generate_bytecode(Bytecode::Generator& generator) const generator.switch_to_basic_block(true_block); generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); - m_consequent->generate_bytecode(generator); + TRY(m_consequent->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) true_block_jump = &generator.emit<Bytecode::Op::Jump>(); @@ -961,7 +1027,7 @@ void IfStatement::generate_bytecode(Bytecode::Generator& generator) const generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); if (m_alternate) - m_alternate->generate_bytecode(generator); + TRY(m_alternate->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) generator.emit<Bytecode::Op::Jump>().set_targets(Bytecode::Label { end_block }, {}); @@ -969,20 +1035,23 @@ void IfStatement::generate_bytecode(Bytecode::Generator& generator) const true_block_jump->set_targets(Bytecode::Label { end_block }, {}); generator.switch_to_basic_block(end_block); + return {}; } -void ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ContinueStatement::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::Jump>().set_targets( generator.nearest_continuable_scope(), {}); + return {}; } -void DebuggerStatement::generate_bytecode(Bytecode::Generator&) const +Bytecode::CodeGenerationErrorOr<void> DebuggerStatement::generate_bytecode(Bytecode::Generator&) const { + return {}; } -void ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) const { // test // jump if_true (true) true (false) false @@ -996,38 +1065,41 @@ void ConditionalExpression::generate_bytecode(Bytecode::Generator& generator) co auto& false_block = generator.make_block(); auto& end_block = generator.make_block(); - m_test->generate_bytecode(generator); + TRY(m_test->generate_bytecode(generator)); generator.emit<Bytecode::Op::JumpConditional>().set_targets( Bytecode::Label { true_block }, Bytecode::Label { false_block }); generator.switch_to_basic_block(true_block); - m_consequent->generate_bytecode(generator); + TRY(m_consequent->generate_bytecode(generator)); generator.emit<Bytecode::Op::Jump>().set_targets( Bytecode::Label { end_block }, {}); generator.switch_to_basic_block(false_block); - m_alternate->generate_bytecode(generator); + TRY(m_alternate->generate_bytecode(generator)); generator.emit<Bytecode::Op::Jump>().set_targets( Bytecode::Label { end_block }, {}); generator.switch_to_basic_block(end_block); + return {}; } -void SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> SequenceExpression::generate_bytecode(Bytecode::Generator& generator) const { for (auto& expression : m_expressions) - expression.generate_bytecode(generator); + TRY(expression.generate_bytecode(generator)); + + return {}; } -void TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const { auto string_reg = generator.allocate_register(); for (size_t i = 0; i < m_expressions.size(); i++) { - m_expressions[i].generate_bytecode(generator); + TRY(m_expressions[i].generate_bytecode(generator)); if (i == 0) { generator.emit<Bytecode::Op::Store>(string_reg); } else { @@ -1036,11 +1108,12 @@ void TemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const } generator.emit<Bytecode::Op::Load>(string_reg); + return {}; } -void TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) const { - m_tag->generate_bytecode(generator); + TRY(m_tag->generate_bytecode(generator)); auto tag_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(tag_reg); @@ -1050,7 +1123,7 @@ void TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) co if (i % 2 != 0) continue; - expressions[i].generate_bytecode(generator); + TRY(expressions[i].generate_bytecode(generator)); auto string_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(string_reg); string_regs.append(string_reg); @@ -1066,7 +1139,7 @@ void TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) co if (i % 2 == 0) continue; - expressions[i].generate_bytecode(generator); + TRY(expressions[i].generate_bytecode(generator)); auto string_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(string_reg); argument_regs.append(string_reg); @@ -1074,7 +1147,7 @@ void TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) co Vector<Bytecode::Register> raw_string_regs; for (auto& raw_string : m_template_literal->raw_strings()) { - raw_string.generate_bytecode(generator); + TRY(raw_string.generate_bytecode(generator)); auto raw_string_reg = generator.allocate_register(); generator.emit<Bytecode::Op::Store>(raw_string_reg); raw_string_regs.append(raw_string_reg); @@ -1092,11 +1165,12 @@ void TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator) co generator.emit<Bytecode::Op::Store>(this_reg); generator.emit_with_extra_register_slots<Bytecode::Op::Call>(argument_regs.size(), Bytecode::Op::Call::CallType::Call, tag_reg, this_reg, move(argument_regs)); + return {}; } -void UpdateExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> UpdateExpression::generate_bytecode(Bytecode::Generator& generator) const { - generator.emit_load_from_reference(*m_argument); + TRY(generator.emit_load_from_reference(*m_argument)); Optional<Bytecode::Register> previous_value_for_postfix_reg; if (!m_prefixed) { @@ -1109,26 +1183,29 @@ void UpdateExpression::generate_bytecode(Bytecode::Generator& generator) const else generator.emit<Bytecode::Op::Decrement>(); - generator.emit_store_to_reference(*m_argument); + TRY(generator.emit_store_to_reference(*m_argument)); if (!m_prefixed) generator.emit<Bytecode::Op::Load>(*previous_value_for_postfix_reg); + return {}; } -void ThrowStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ThrowStatement::generate_bytecode(Bytecode::Generator& generator) const { - m_argument->generate_bytecode(generator); + TRY(m_argument->generate_bytecode(generator)); generator.emit<Bytecode::Op::Throw>(); + return {}; } -void BreakStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> BreakStatement::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::Jump>().set_targets( generator.nearest_breakable_scope(), {}); + return {}; } -void TryStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> TryStatement::generate_bytecode(Bytecode::Generator& generator) const { auto& saved_block = generator.current_block(); @@ -1140,7 +1217,7 @@ void TryStatement::generate_bytecode(Bytecode::Generator& generator) const if (m_finalizer) { auto& finalizer_block = generator.make_block(); generator.switch_to_basic_block(finalizer_block); - m_finalizer->generate_bytecode(generator); + TRY(m_finalizer->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) { next_block = &generator.make_block(); auto next_target = Bytecode::Label { *next_block }; @@ -1152,19 +1229,23 @@ void TryStatement::generate_bytecode(Bytecode::Generator& generator) const if (m_handler) { auto& handler_block = generator.make_block(); generator.switch_to_basic_block(handler_block); - m_handler->parameter().visit( - [&](FlyString const& parameter) { + TRY(m_handler->parameter().visit( + [&](FlyString const& parameter) -> Bytecode::CodeGenerationErrorOr<void> { if (!parameter.is_empty()) { // FIXME: We need a separate DeclarativeEnvironment here generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(parameter)); } + return {}; }, - [&](NonnullRefPtr<BindingPattern> const&) { + [&](NonnullRefPtr<BindingPattern> const&) -> Bytecode::CodeGenerationErrorOr<void> { // FIXME: Implement this path when the above DeclarativeEnvironment issue is dealt with. - TODO(); - }); + return Bytecode::CodeGenerationError { + this, + "Unimplemented catch argument: BindingPattern"sv, + }; + })); - m_handler->body().generate_bytecode(generator); + TRY(m_handler->body().generate_bytecode(generator)); handler_target = Bytecode::Label { handler_block }; if (!generator.is_current_block_terminated()) { if (m_finalizer) { @@ -1184,7 +1265,7 @@ void TryStatement::generate_bytecode(Bytecode::Generator& generator) const generator.emit<Bytecode::Op::EnterUnwindContext>(Bytecode::Label { target_block }, handler_target, finalizer_target); generator.switch_to_basic_block(target_block); - m_block->generate_bytecode(generator); + TRY(m_block->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) { if (m_finalizer) { generator.emit<Bytecode::Op::Jump>(finalizer_target); @@ -1196,12 +1277,13 @@ void TryStatement::generate_bytecode(Bytecode::Generator& generator) const } generator.switch_to_basic_block(next_block ? *next_block : saved_block); + return {}; } -void SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const { auto discriminant_reg = generator.allocate_register(); - m_discriminant->generate_bytecode(generator); + TRY(m_discriminant->generate_bytecode(generator)); generator.emit<Bytecode::Op::Store>(discriminant_reg); Vector<Bytecode::BasicBlock&> case_blocks; Bytecode::BasicBlock* default_block { nullptr }; @@ -1211,7 +1293,7 @@ void SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const auto& case_block = generator.make_block(); if (switch_case.test()) { generator.switch_to_basic_block(*next_test_block); - switch_case.test()->generate_bytecode(generator); + TRY(switch_case.test()->generate_bytecode(generator)); generator.emit<Bytecode::Op::StrictlyEquals>(discriminant_reg); next_test_block = &generator.make_block(); generator.emit<Bytecode::Op::JumpConditional>().set_targets(Bytecode::Label { case_block }, Bytecode::Label { *next_test_block }); @@ -1236,7 +1318,7 @@ void SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const generator.emit<Bytecode::Op::LoadImmediate>(js_undefined()); for (auto& statement : switch_case.children()) { - statement.generate_bytecode(generator); + TRY(statement.generate_bytecode(generator)); } if (!generator.is_current_block_terminated()) { auto next_block = current_block; @@ -1252,6 +1334,7 @@ void SwitchStatement::generate_bytecode(Bytecode::Generator& generator) const generator.end_breakable_scope(); generator.switch_to_basic_block(end_block); + return {}; } void ClassDeclaration::generate_bytecode(Bytecode::Generator& generator) const @@ -1260,21 +1343,23 @@ void ClassDeclaration::generate_bytecode(Bytecode::Generator& generator) const generator.emit<Bytecode::Op::SetVariable>(generator.intern_identifier(m_class_expression.ptr()->name())); } -void ThisExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> ThisExpression::generate_bytecode(Bytecode::Generator& generator) const { generator.emit<Bytecode::Op::ResolveThisBinding>(); + return {}; } -void AwaitExpression::generate_bytecode(Bytecode::Generator& generator) const +Bytecode::CodeGenerationErrorOr<void> AwaitExpression::generate_bytecode(Bytecode::Generator& generator) const { VERIFY(generator.is_in_async_function()); // Transform `await expr` to `yield expr` - m_argument->generate_bytecode(generator); + TRY(m_argument->generate_bytecode(generator)); auto& continuation_block = generator.make_block(); generator.emit<Bytecode::Op::Yield>(Bytecode::Label { continuation_block }); generator.switch_to_basic_block(continuation_block); + return {}; } } diff --git a/Userland/Libraries/LibJS/Bytecode/CodeGenerationError.h b/Userland/Libraries/LibJS/Bytecode/CodeGenerationError.h new file mode 100644 index 0000000000..e0404b1b26 --- /dev/null +++ b/Userland/Libraries/LibJS/Bytecode/CodeGenerationError.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Error.h> +#include <AK/StringView.h> +#include <LibJS/Forward.h> + +namespace JS::Bytecode { + +struct CodeGenerationError { + ASTNode const* failing_node { nullptr }; + StringView reason_literal; + + String to_string(); +}; + +template<typename T> +using CodeGenerationErrorOr = ErrorOr<T, CodeGenerationError>; + +} diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index da1d837a4e..f515bd5f13 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -23,7 +23,7 @@ Generator::~Generator() { } -NonnullOwnPtr<Executable> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind) +CodeGenerationErrorOr<NonnullOwnPtr<Executable>> Generator::generate(ASTNode const& node, FunctionKind enclosing_function_kind) { Generator generator; generator.switch_to_basic_block(generator.make_block()); @@ -34,7 +34,7 @@ NonnullOwnPtr<Executable> Generator::generate(ASTNode const& node, FunctionKind generator.emit<Bytecode::Op::Yield>(Label { start_block }); generator.switch_to_basic_block(start_block); } - node.generate_bytecode(generator); + TRY(node.generate_bytecode(generator)); if (generator.is_in_generator_or_async_function()) { // Terminate all unterminated blocks with yield return for (auto& block : generator.m_root_basic_blocks) { @@ -99,38 +99,43 @@ void Generator::end_breakable_scope() m_breakable_scopes.take_last(); } -void Generator::emit_load_from_reference(JS::ASTNode const& node) +CodeGenerationErrorOr<void> Generator::emit_load_from_reference(JS::ASTNode const& node) { if (is<Identifier>(node)) { auto& identifier = static_cast<Identifier const&>(node); emit<Bytecode::Op::GetVariable>(intern_identifier(identifier.string())); - return; + return {}; } if (is<MemberExpression>(node)) { auto& expression = static_cast<MemberExpression const&>(node); - expression.object().generate_bytecode(*this); + TRY(expression.object().generate_bytecode(*this)); auto object_reg = allocate_register(); emit<Bytecode::Op::Store>(object_reg); if (expression.is_computed()) { - expression.property().generate_bytecode(*this); + TRY(expression.property().generate_bytecode(*this)); emit<Bytecode::Op::GetByValue>(object_reg); - } else { + } else if (expression.property().is_identifier()) { auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string()); emit<Bytecode::Op::GetById>(identifier_table_ref); + } else { + return CodeGenerationError { + &expression, + "Unimplemented non-computed member expression"sv + }; } - return; + return {}; } VERIFY_NOT_REACHED(); } -void Generator::emit_store_to_reference(JS::ASTNode const& node) +CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const& node) { if (is<Identifier>(node)) { auto& identifier = static_cast<Identifier const&>(node); emit<Bytecode::Op::SetVariable>(intern_identifier(identifier.string())); - return; + return {}; } if (is<MemberExpression>(node)) { // NOTE: The value is in the accumulator, so we have to store that away first. @@ -138,25 +143,36 @@ void Generator::emit_store_to_reference(JS::ASTNode const& node) emit<Bytecode::Op::Store>(value_reg); auto& expression = static_cast<MemberExpression const&>(node); - expression.object().generate_bytecode(*this); + TRY(expression.object().generate_bytecode(*this)); auto object_reg = allocate_register(); emit<Bytecode::Op::Store>(object_reg); if (expression.is_computed()) { - expression.property().generate_bytecode(*this); + TRY(expression.property().generate_bytecode(*this)); auto property_reg = allocate_register(); emit<Bytecode::Op::Store>(property_reg); emit<Bytecode::Op::Load>(value_reg); emit<Bytecode::Op::PutByValue>(object_reg, property_reg); - } else { + } else if (expression.property().is_identifier()) { emit<Bytecode::Op::Load>(value_reg); auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(expression.property()).string()); emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref); + } else { + return CodeGenerationError { + &expression, + "Unimplemented non-computed member expression"sv + }; } - return; + return {}; } + 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 1f5c542771..f12e4d5243 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -10,6 +10,7 @@ #include <AK/OwnPtr.h> #include <AK/SinglyLinkedList.h> #include <LibJS/Bytecode/BasicBlock.h> +#include <LibJS/Bytecode/CodeGenerationError.h> #include <LibJS/Bytecode/Executable.h> #include <LibJS/Bytecode/IdentifierTable.h> #include <LibJS/Bytecode/Label.h> @@ -23,7 +24,7 @@ namespace JS::Bytecode { class Generator { public: - static NonnullOwnPtr<Executable> generate(ASTNode const&, FunctionKind = FunctionKind::Normal); + static CodeGenerationErrorOr<NonnullOwnPtr<Executable>> generate(ASTNode const&, FunctionKind = FunctionKind::Normal); Register allocate_register(); @@ -71,8 +72,8 @@ public: return *static_cast<OpType*>(slot); } - void emit_load_from_reference(JS::ASTNode const&); - void emit_store_to_reference(JS::ASTNode const&); + CodeGenerationErrorOr<void> emit_load_from_reference(JS::ASTNode const&); + CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&); void begin_continuable_scope(Label continue_target); void end_continuable_scope(); diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index ee0c708c23..7edf0769a7 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -579,7 +579,11 @@ ThrowCompletionOr<Value> perform_eval(Value x, GlobalObject& caller_realm, Calle Optional<Value> eval_result; if (auto* bytecode_interpreter = Bytecode::Interpreter::current()) { - auto executable = JS::Bytecode::Generator::generate(program); + auto executable_result = JS::Bytecode::Generator::generate(program); + if (executable_result.is_error()) + return vm.throw_completion<InternalError>(bytecode_interpreter->global_object(), ErrorType::NotImplemented, executable_result.error().to_string()); + + auto executable = executable_result.release_value(); executable->name = "eval"sv; if (JS::Bytecode::g_dump_bytecode) executable->dump(); diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index ab60930f2a..65e29633a0 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -767,7 +767,11 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body() // FIXME: pass something to evaluate default arguments with TRY(function_declaration_instantiation(nullptr)); if (!m_bytecode_executable) { - m_bytecode_executable = Bytecode::Generator::generate(m_ecmascript_code, m_kind); + auto executable_result = JS::Bytecode::Generator::generate(m_ecmascript_code, m_kind); + if (executable_result.is_error()) + return vm.throw_completion<InternalError>(bytecode_interpreter->global_object(), ErrorType::NotImplemented, executable_result.error().to_string()); + + m_bytecode_executable = executable_result.release_value(); m_bytecode_executable->name = m_name; auto& passes = JS::Bytecode::Interpreter::optimization_pipeline(); passes.perform(*m_bytecode_executable); |