diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 1c7b74a3804..2e06c10ed1e 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,7 @@ public: // NOTE: This is here to stop ASAN complaining about mismatch between new/delete sizes in ASTNodeWithTailArray. void operator delete(void* ptr) { ::operator delete(ptr); } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const; virtual void dump(int indent) const; [[nodiscard]] SourceRange source_range() const; @@ -175,8 +176,8 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const; DeprecatedFlyString const& label() const { return m_label; } DeprecatedFlyString& label() { return m_label; } @@ -204,7 +205,7 @@ class IterationStatement : public Statement { public: using Statement::Statement; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const; private: virtual bool is_iteration_statement() const final { return true; } @@ -216,7 +217,7 @@ public: : Statement(move(source_range)) { } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; }; class ErrorStatement final : public Statement { @@ -236,7 +237,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; Expression const& expression() const { return m_expression; } @@ -299,7 +300,7 @@ public: Vector> const& children() const { return m_children; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; void add_var_scoped_declaration(NonnullRefPtr variables); void add_lexical_declaration(NonnullRefPtr variables); @@ -387,7 +388,7 @@ public: virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; bool has_bound_name(DeprecatedFlyString const& name) const; Vector const& entries() const { return m_entries; } @@ -484,7 +485,7 @@ public: virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; bool has_export(DeprecatedFlyString const& export_name) const; @@ -671,7 +672,7 @@ public: void set_is_global() { m_is_global = true; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: virtual bool is_identifier() const override { return true; } @@ -761,7 +762,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override; @@ -787,8 +788,8 @@ public: virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional lhs_name, Optional preferred_dst = {}) const; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional lhs_name, Optional preferred_dst = {}) const; bool has_name() const { return !name().is_empty(); } @@ -819,7 +820,7 @@ public: bool is_yield_from() const { return m_is_yield_from; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: RefPtr m_argument; @@ -835,7 +836,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_argument; @@ -852,7 +853,7 @@ public: Expression const* argument() const { return m_argument; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: RefPtr m_argument; @@ -873,7 +874,7 @@ public: Statement const* alternate() const { return m_alternate; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_predicate; @@ -894,8 +895,8 @@ public: Statement const& body() const { return *m_body; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_test; @@ -915,8 +916,8 @@ public: Statement const& body() const { return *m_body; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_test; @@ -936,7 +937,7 @@ public: Statement const& body() const { return *m_body; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_object; @@ -960,8 +961,8 @@ public: Statement const& body() const { return *m_body; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; private: RefPtr m_init; @@ -984,8 +985,8 @@ public: Expression const& rhs() const { return *m_rhs; } Statement const& body() const { return *m_body; } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; virtual void dump(int indent) const override; private: @@ -1008,8 +1009,8 @@ public: Expression const& rhs() const { return *m_rhs; } Statement const& body() const { return *m_body; } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; virtual void dump(int indent) const override; private: @@ -1028,8 +1029,8 @@ public: { } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const override; virtual void dump(int indent) const override; private: @@ -1074,7 +1075,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: BinaryOp m_op; @@ -1099,7 +1100,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: LogicalOp m_op; @@ -1127,7 +1128,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: UnaryOp m_op; @@ -1144,7 +1145,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: Vector> m_expressions; @@ -1170,7 +1171,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; virtual Value value() const override { return Value(m_value); } @@ -1187,7 +1188,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; virtual Value value() const override { return m_value; } @@ -1206,7 +1207,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: ByteString m_value; @@ -1221,7 +1222,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; ByteString const& value() const { return m_value; } @@ -1239,7 +1240,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; virtual Value value() const override { return js_null(); } }; @@ -1257,7 +1258,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; regex::Parser::Result const& parsed_regex() const { return m_parsed_regex; } ByteString const& parsed_pattern() const { return m_parsed_pattern; } @@ -1402,7 +1403,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; virtual bool is_super_expression() const override { return true; } }; @@ -1425,8 +1426,8 @@ public: RefPtr constructor() const { return m_constructor; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional lhs_name, Optional preferred_dst = {}) const; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional lhs_name, Optional preferred_dst = {}) const; bool has_name() const { return m_name; } @@ -1454,7 +1455,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; ThrowCompletionOr for_each_bound_identifier(ThrowCompletionOrVoidCallback&&) const override; @@ -1482,7 +1483,7 @@ public: } virtual void dump(int) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_expression; @@ -1498,7 +1499,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_target; @@ -1511,7 +1512,7 @@ public: { } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; }; struct CallExpressionArgument { @@ -1541,7 +1542,7 @@ public: static NonnullRefPtr create(SourceRange, NonnullRefPtr callee, ReadonlySpan arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens); virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; Expression const& callee() const { return m_callee; } @@ -1609,7 +1610,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: Vector const m_arguments; @@ -1654,7 +1655,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: AssignmentOp m_op; @@ -1678,7 +1679,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: virtual bool is_update_expression() const override { return true; } @@ -1738,7 +1739,7 @@ public: DeclarationKind declaration_kind() const { return m_declaration_kind; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; Vector> const& declarations() const { return m_declarations; } @@ -1824,7 +1825,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: virtual bool is_object_expression() const override { return true; } @@ -1843,7 +1844,7 @@ public: Vector> const& elements() const { return m_elements; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: virtual bool is_array_expression() const override { return true; } @@ -1867,7 +1868,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; Vector> const& expressions() const { return m_expressions; } Vector> const& raw_strings() const { return m_raw_strings; } @@ -1887,7 +1888,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr const m_tag; @@ -1905,7 +1906,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; bool is_computed() const { return m_computed; } Expression const& object() const { return *m_object; } @@ -1957,7 +1958,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; Expression const& base() const { return *m_base; } Vector const& references() const { return m_references; } @@ -1981,7 +1982,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: Type m_type; @@ -1997,7 +1998,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: virtual bool is_import_call() const override { return true; } @@ -2017,7 +2018,7 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_test; @@ -2066,7 +2067,7 @@ public: BlockStatement const* finalizer() const { return m_finalizer; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_block; @@ -2085,7 +2086,7 @@ public: Expression const& argument() const { return m_argument; } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: NonnullRefPtr m_argument; @@ -2116,8 +2117,8 @@ public: } virtual void dump(int indent) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; - virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_labelled_evaluation(Bytecode::Generator&, Vector const&, Optional preferred_dst = {}) const; void add_case(NonnullRefPtr switch_case) { m_cases.append(move(switch_case)); } @@ -2135,7 +2136,7 @@ public: } Optional const& target_label() const { return m_target_label; } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; private: Optional m_target_label; @@ -2149,7 +2150,7 @@ public: { } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; Optional const& target_label() const { return m_target_label; } @@ -2164,7 +2165,7 @@ public: { } - virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; + virtual Bytecode::CodeGenerationErrorOr> generate_bytecode(Bytecode::Generator&, Optional preferred_dst = {}) const override; }; class SyntheticReferenceExpression final : public Expression { diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 6d95b6940f7..175d7144967 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -19,14 +19,16 @@ namespace JS { -static Bytecode::Operand choose_dst(Bytecode::Generator& generator, Optional const& preferred_dst) +using namespace JS::Bytecode; + +static ScopedOperand choose_dst(Bytecode::Generator& generator, Optional const& preferred_dst) { if (preferred_dst.has_value()) return preferred_dst.value(); - return Bytecode::Operand(generator.allocate_register()); + return generator.allocate_register(); } -Bytecode::CodeGenerationErrorOr> ASTNode::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ASTNode::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const { return Bytecode::CodeGenerationError { this, @@ -34,7 +36,7 @@ Bytecode::CodeGenerationErrorOr> ASTNode::generate_b }; } -Bytecode::CodeGenerationErrorOr> ScopeNode::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ScopeNode::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); bool did_create_lexical_environment = false; @@ -50,7 +52,7 @@ Bytecode::CodeGenerationErrorOr> ScopeNode::generate // FunctionDeclarationInstantiation is handled by the C++ AO. } - Optional last_result; + Optional last_result; for (auto& child : children()) { auto result = TRY(child->generate_bytecode(generator)); if (result.has_value()) @@ -65,18 +67,18 @@ Bytecode::CodeGenerationErrorOr> ScopeNode::generate return last_result; } -Bytecode::CodeGenerationErrorOr> EmptyStatement::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> EmptyStatement::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const { - return Optional {}; + return Optional {}; } -Bytecode::CodeGenerationErrorOr> ExpressionStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ExpressionStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return m_expression->generate_bytecode(generator); } -Bytecode::CodeGenerationErrorOr> BinaryExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> BinaryExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (m_op == BinaryOp::In && is(*m_lhs)) { @@ -164,7 +166,7 @@ Bytecode::CodeGenerationErrorOr> BinaryExpression::g return dst; } -Bytecode::CodeGenerationErrorOr> LogicalExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> LogicalExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto dst = choose_dst(generator, preferred_dst); @@ -213,13 +215,13 @@ Bytecode::CodeGenerationErrorOr> LogicalExpression:: return dst; } -Bytecode::CodeGenerationErrorOr> UnaryExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> UnaryExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (m_op == UnaryOp::Delete) return generator.emit_delete_reference(m_lhs); - Optional src; + Optional src; // Typeof needs some special handling for when the LHS is an Identifier. Namely, it shouldn't throw on unresolvable references, but instead return "undefined". if (m_op != UnaryOp::Typeof) src = TRY(m_lhs->generate_bytecode(generator)).value(); @@ -261,25 +263,25 @@ Bytecode::CodeGenerationErrorOr> UnaryExpression::ge return dst; } -Bytecode::CodeGenerationErrorOr> NumericLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> NumericLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generator.add_constant(Value(m_value), Bytecode::Generator::DeduplicateConstant::No); } -Bytecode::CodeGenerationErrorOr> BooleanLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> BooleanLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generator.add_constant(Value(m_value)); } -Bytecode::CodeGenerationErrorOr> NullLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> NullLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generator.add_constant(js_null()); } -Bytecode::CodeGenerationErrorOr> BigIntLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> BigIntLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // 1. Return the NumericValue of NumericLiteral as defined in 12.8.3. @@ -296,13 +298,13 @@ Bytecode::CodeGenerationErrorOr> BigIntLiteral::gene return generator.add_constant(BigInt::create(generator.vm(), move(integer)), Bytecode::Generator::DeduplicateConstant::No); } -Bytecode::CodeGenerationErrorOr> StringLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> StringLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generator.add_constant(PrimitiveString::create(generator.vm(), m_value), Bytecode::Generator::DeduplicateConstant::No); } -Bytecode::CodeGenerationErrorOr> RegExpLiteral::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> RegExpLiteral::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto source_index = generator.intern_string(m_pattern); @@ -317,12 +319,12 @@ Bytecode::CodeGenerationErrorOr> RegExpLiteral::gene return dst; } -Bytecode::CodeGenerationErrorOr> Identifier::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> Identifier::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (is_local()) { - auto local = Bytecode::Operand(Bytecode::Operand::Type::Local, local_variable_index()); + auto local = generator.local(local_variable_index()); if (!generator.is_local_initialized(local_variable_index())) { generator.emit(local); } @@ -338,9 +340,9 @@ Bytecode::CodeGenerationErrorOr> Identifier::generat return dst; } -static Bytecode::CodeGenerationErrorOr> arguments_to_array_for_call(Bytecode::Generator& generator, ReadonlySpan arguments) +static Bytecode::CodeGenerationErrorOr> arguments_to_array_for_call(Bytecode::Generator& generator, ReadonlySpan arguments) { - auto dst = Bytecode::Operand(generator.allocate_register()); + auto dst = generator.allocate_register(); if (arguments.is_empty()) { generator.emit(dst); return dst; @@ -348,11 +350,13 @@ static Bytecode::CodeGenerationErrorOr> arguments_to auto first_spread = find_if(arguments.begin(), arguments.end(), [](auto el) { return el.is_spread; }); + Vector registers; Bytecode::Register args_start_reg { 0 }; for (auto it = arguments.begin(); it != first_spread; ++it) { - auto reg = generator.allocate_register(); + auto reg = generator.allocate_sequential_register(); + registers.append(reg); if (args_start_reg.index() == 0) - args_start_reg = reg; + args_start_reg = reg.operand().as_register(); } u32 i = 0; for (auto it = arguments.begin(); it != first_spread; ++it, ++i) { @@ -377,10 +381,10 @@ static Bytecode::CodeGenerationErrorOr> arguments_to return dst; } -Bytecode::CodeGenerationErrorOr> SuperCall::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> SuperCall::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); - Optional arguments; + Optional arguments; if (m_is_synthetic == IsPartOfSyntheticConstructor::Yes) { // NOTE: This is the case where we have a fake constructor(...args) { super(...args); } which // shouldn't call @@iterator of %Array.prototype%. @@ -398,21 +402,21 @@ Bytecode::CodeGenerationErrorOr> SuperCall::generate return dst; } -static Bytecode::CodeGenerationErrorOr generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode, Bytecode::Operand const& input_value, bool create_variables); +static Bytecode::CodeGenerationErrorOr generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode, ScopedOperand const& input_value, bool create_variables); -Bytecode::CodeGenerationErrorOr> AssignmentExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> AssignmentExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (m_op == AssignmentOp::Assignment) { // AssignmentExpression : LeftHandSideExpression = AssignmentExpression return m_lhs.visit( // 1. If LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral, then - [&](NonnullRefPtr const& lhs) -> Bytecode::CodeGenerationErrorOr> { + [&](NonnullRefPtr const& lhs) -> Bytecode::CodeGenerationErrorOr> { // a. Let lref be the result of evaluating LeftHandSideExpression. // b. ReturnIfAbrupt(lref). - Optional base; - Optional computed_property; - Optional this_value; + Optional base; + Optional computed_property; + Optional this_value; bool lhs_is_super_expression = false; @@ -435,7 +439,7 @@ Bytecode::CodeGenerationErrorOr> AssignmentExpressio if (expression.is_computed()) { auto property = TRY(expression.property().generate_bytecode(generator)).value(); - computed_property = Bytecode::Operand(generator.allocate_register()); + computed_property = generator.allocate_register(); generator.emit(*computed_property, property); // To be continued later with PutByValue. @@ -458,7 +462,7 @@ Bytecode::CodeGenerationErrorOr> AssignmentExpressio // 2. Assert: env.HasSuperBinding() is true. // 3. Let baseValue be ? env.GetSuperBase(). // 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }. - base = Bytecode::Operand(generator.allocate_register()); + base = generator.allocate_register(); generator.emit(*base); } } else if (is(*lhs)) { @@ -474,7 +478,7 @@ Bytecode::CodeGenerationErrorOr> AssignmentExpressio // d. Else, // i. Let rref be the result of evaluating AssignmentExpression. // ii. Let rval be ? GetValue(rref). - auto rval = TRY([&]() -> Bytecode::CodeGenerationErrorOr { + auto rval = TRY([&]() -> Bytecode::CodeGenerationErrorOr { if (lhs->is_identifier()) { return TRY(generator.emit_named_evaluation_if_anonymous_function(*m_rhs, generator.intern_identifier(static_cast(*lhs).string()))).value(); } else { @@ -521,7 +525,7 @@ Bytecode::CodeGenerationErrorOr> AssignmentExpressio return rval; }, // 2. Let assignmentPattern be the AssignmentPattern that is covered by LeftHandSideExpression. - [&](NonnullRefPtr const& pattern) -> Bytecode::CodeGenerationErrorOr> { + [&](NonnullRefPtr const& pattern) -> Bytecode::CodeGenerationErrorOr> { // 3. Let rref be the result of evaluating AssignmentExpression. // 4. Let rval be ? GetValue(rref). auto rval = TRY(m_rhs->generate_bytecode(generator)).value(); @@ -577,7 +581,7 @@ Bytecode::CodeGenerationErrorOr> AssignmentExpressio if (rhs_block_ptr) generator.switch_to_basic_block(*rhs_block_ptr); - auto rhs = TRY([&]() -> Bytecode::CodeGenerationErrorOr { + auto rhs = TRY([&]() -> Bytecode::CodeGenerationErrorOr { if (lhs_expression->is_identifier()) { return TRY(generator.emit_named_evaluation_if_anonymous_function(*m_rhs, generator.intern_identifier(static_cast(*lhs_expression).string()))).value(); } @@ -659,7 +663,7 @@ Bytecode::CodeGenerationErrorOr> AssignmentExpressio // 14.13.3 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-labelled-statements-runtime-semantics-evaluation // LabelledStatement : LabelIdentifier : LabelledItem -Bytecode::CodeGenerationErrorOr> LabelledStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> LabelledStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // Return ? LabelledEvaluation of this LabelledStatement with argument « ». @@ -668,7 +672,7 @@ Bytecode::CodeGenerationErrorOr> LabelledStatement:: // 14.13.4 Runtime Semantics: LabelledEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-labelledevaluation // LabelledStatement : LabelIdentifier : LabelledItem -Bytecode::CodeGenerationErrorOr> LabelledStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> LabelledStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // 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. @@ -683,7 +687,7 @@ Bytecode::CodeGenerationErrorOr> LabelledStatement:: new_label_set.append(m_label); // 3. Let stmtResult be LabelledEvaluation of LabelledItem with argument newLabelSet. - Optional stmt_result; + Optional stmt_result; if (is(labelled_item)) { auto const& iteration_statement = static_cast(labelled_item); stmt_result = TRY(iteration_statement.generate_labelled_evaluation(generator, new_label_set)); @@ -716,7 +720,7 @@ Bytecode::CodeGenerationErrorOr> LabelledStatement:: return stmt_result; } -Bytecode::CodeGenerationErrorOr> IterationStatement::generate_labelled_evaluation(Bytecode::Generator&, Vector const&, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> IterationStatement::generate_labelled_evaluation(Bytecode::Generator&, Vector const&, [[maybe_unused]] Optional preferred_dst) const { return Bytecode::CodeGenerationError { this, @@ -724,13 +728,13 @@ Bytecode::CodeGenerationErrorOr> IterationStatement: }; } -Bytecode::CodeGenerationErrorOr> WhileStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> WhileStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } -Bytecode::CodeGenerationErrorOr> WhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> WhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // test @@ -742,7 +746,7 @@ Bytecode::CodeGenerationErrorOr> WhileStatement::gen auto& body_block = generator.make_block(); auto& end_block = generator.make_block(); - auto result = Bytecode::Operand(generator.allocate_register()); + auto result = generator.allocate_register(); generator.emit(result, generator.add_constant(js_undefined())); generator.emit(Bytecode::Label { test_block }); @@ -771,13 +775,13 @@ Bytecode::CodeGenerationErrorOr> WhileStatement::gen return result; } -Bytecode::CodeGenerationErrorOr> DoWhileStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> DoWhileStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } -Bytecode::CodeGenerationErrorOr> DoWhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> DoWhileStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // jump always (true) body @@ -791,7 +795,7 @@ Bytecode::CodeGenerationErrorOr> DoWhileStatement::g auto& load_result_and_jump_to_end_block = generator.make_block(); auto& end_block = generator.make_block(); - auto completion_value = Bytecode::Operand(generator.allocate_register()); + auto completion_value = generator.allocate_register(); generator.emit(completion_value, generator.add_constant(js_undefined())); // jump to the body block @@ -824,13 +828,13 @@ Bytecode::CodeGenerationErrorOr> DoWhileStatement::g return completion_value; } -Bytecode::CodeGenerationErrorOr> ForStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } -Bytecode::CodeGenerationErrorOr> ForStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // init @@ -938,11 +942,11 @@ Bytecode::CodeGenerationErrorOr> ForStatement::gener return body_result; } -Bytecode::CodeGenerationErrorOr> ObjectExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ObjectExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); - auto object = Bytecode::Operand(generator.allocate_register()); + auto object = generator.allocate_register(); generator.emit(object); if (m_properties.is_empty()) @@ -974,7 +978,7 @@ Bytecode::CodeGenerationErrorOr> ObjectExpression::g auto& string_literal = static_cast(property->key()); Bytecode::IdentifierTableIndex key_name = generator.intern_identifier(string_literal.value()); - Optional value; + Optional value; if (property_kind == Bytecode::Op::PropertyKind::ProtoSetter) { value = TRY(property->value().generate_bytecode(generator)).value(); } else if (property_kind != Bytecode::Op::PropertyKind::Spread) { @@ -993,7 +997,7 @@ Bytecode::CodeGenerationErrorOr> ObjectExpression::g generator.emit(object, key_name, *value, property_kind, generator.next_property_lookup_cache()); } else { auto property_name = TRY(property->key().generate_bytecode(generator)).value(); - Optional value; + Optional value; if (property_kind != Bytecode::Op::PropertyKind::Spread) value = TRY(property->value().generate_bytecode(generator)).value(); else @@ -1007,7 +1011,7 @@ Bytecode::CodeGenerationErrorOr> ObjectExpression::g return object; } -Bytecode::CodeGenerationErrorOr> ArrayExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ArrayExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (m_elements.is_empty()) { @@ -1033,15 +1037,17 @@ Bytecode::CodeGenerationErrorOr> ArrayExpression::ge auto first_spread = find_if(m_elements.begin(), m_elements.end(), [](auto el) { return el && is(*el); }); - Bytecode::Register args_start_reg { 0 }; + Vector registers; + Optional args_start_reg; for (auto it = m_elements.begin(); it != first_spread; ++it) { - auto reg = generator.allocate_register(); - if (args_start_reg.index() == 0) - args_start_reg = reg; + auto reg = generator.allocate_sequential_register(); + registers.append(reg); + if (!args_start_reg.has_value()) + args_start_reg = reg.operand().as_register(); } u32 i = 0; for (auto it = m_elements.begin(); it != first_spread; ++it, ++i) { - Bytecode::Register reg { args_start_reg.index() + i }; + Bytecode::Register reg { args_start_reg->index() + i }; if (*it) { auto value = TRY((*it)->generate_bytecode(generator)).value(); generator.emit(Bytecode::Operand(reg), value); @@ -1050,8 +1056,8 @@ Bytecode::CodeGenerationErrorOr> ArrayExpression::ge auto dst = choose_dst(generator, preferred_dst); if (first_spread.index() != 0) { - auto reg = Bytecode::Register { args_start_reg.index() + static_cast(first_spread.index() - 1) }; - generator.emit_with_extra_operand_slots(2u, dst, AK::Array { Bytecode::Operand(args_start_reg), Bytecode::Operand(reg) }); + auto reg = Bytecode::Register { args_start_reg->index() + static_cast(first_spread.index() - 1) }; + generator.emit_with_extra_operand_slots(2u, dst, AK::Array { Bytecode::Operand(*args_start_reg), Bytecode::Operand(reg) }); } else { generator.emit(dst); } @@ -1070,26 +1076,26 @@ Bytecode::CodeGenerationErrorOr> ArrayExpression::ge return dst; } -Bytecode::CodeGenerationErrorOr> MemberExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> MemberExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto reference = TRY(generator.emit_load_from_reference(*this, preferred_dst)); return reference.loaded_value; } -Bytecode::CodeGenerationErrorOr> FunctionDeclaration::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> FunctionDeclaration::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { if (m_is_hoisted) { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto index = generator.intern_identifier(name()); - auto value = Bytecode::Operand(generator.allocate_register()); + auto value = generator.allocate_register(); generator.emit(value, index, generator.next_environment_variable_cache()); generator.emit(index, value, generator.next_environment_variable_cache(), Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode::Var); } - return Optional {}; + return Optional {}; } -Bytecode::CodeGenerationErrorOr> FunctionExpression::generate_bytecode_with_lhs_name(Bytecode::Generator& generator, Optional lhs_name, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> FunctionExpression::generate_bytecode_with_lhs_name(Bytecode::Generator& generator, Optional lhs_name, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); bool has_name = !name().is_empty(); @@ -1113,17 +1119,17 @@ Bytecode::CodeGenerationErrorOr> FunctionExpression: return new_function; } -Bytecode::CodeGenerationErrorOr> FunctionExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> FunctionExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_bytecode_with_lhs_name(generator, {}, preferred_dst); } -static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Operand const& object, bool create_variables) +static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, ScopedOperand const& object, bool create_variables) { generator.emit(object); - Vector excluded_property_names; + Vector excluded_property_names; auto has_rest = false; if (pattern.entries.size() > 0) has_rest = pattern.entries[pattern.entries.size() - 1].is_rest; @@ -1135,7 +1141,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt auto identifier = name.get>(); auto interned_identifier = generator.intern_identifier(identifier->string()); - auto copy = Bytecode::Operand(generator.allocate_register()); + auto copy = generator.allocate_register(); generator.emit_with_extra_operand_slots( excluded_property_names.size(), copy, object, excluded_property_names); if (create_variables) { @@ -1147,7 +1153,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt return {}; } if (alias.has>()) { - auto copy = Bytecode::Operand(generator.allocate_register()); + auto copy = generator.allocate_register(); generator.emit_with_extra_operand_slots( excluded_property_names.size(), copy, object, excluded_property_names); (void)TRY(generator.emit_store_to_reference(alias.get>(), object)); @@ -1156,7 +1162,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt VERIFY_NOT_REACHED(); } - auto value = Bytecode::Operand(generator.allocate_register()); + auto value = generator.allocate_register(); if (name.has>()) { auto const& identifier = name.get>()->string(); @@ -1169,7 +1175,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt auto property_name = TRY(expression->generate_bytecode(generator)).value(); if (has_rest) { - auto excluded_name = Bytecode::Operand(generator.allocate_register()); + auto excluded_name = generator.allocate_register(); excluded_property_names.append(excluded_name); generator.emit(excluded_name, property_name); } @@ -1187,7 +1193,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt Bytecode::Label { if_not_undefined_block }); generator.switch_to_basic_block(if_undefined_block); - Optional default_value; + Optional default_value; if (auto const* alias_identifier = alias.get_pointer>()) { default_value = TRY(generator.emit_named_evaluation_if_anonymous_function(*initializer, generator.intern_identifier((*alias_identifier)->string()))).value(); } else if (auto const* lhs = name.get_pointer>()) { @@ -1203,7 +1209,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt if (alias.has>()) { auto& binding_pattern = *alias.get>(); - auto nested_value = Bytecode::Operand(generator.allocate_register()); + auto nested_value = generator.allocate_register(); generator.emit(nested_value, value); TRY(generate_binding_pattern_bytecode(generator, binding_pattern, initialization_mode, nested_value, create_variables)); } else if (alias.has()) { @@ -1233,7 +1239,7 @@ static Bytecode::CodeGenerationErrorOr generate_object_binding_pattern_byt return {}; } -static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Operand const& input_array, bool create_variables, [[maybe_unused]] Optional preferred_dst = {}) +static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, ScopedOperand const& input_array, bool create_variables, [[maybe_unused]] Optional preferred_dst = {}) { /* * Consider the following destructuring assignment: @@ -1255,14 +1261,14 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte * unnecessary. */ - auto is_iterator_exhausted = Bytecode::Operand(generator.allocate_register()); + auto is_iterator_exhausted = generator.allocate_register(); generator.emit(is_iterator_exhausted, generator.add_constant(Value(false))); - auto iterator = Bytecode::Operand(generator.allocate_register()); + auto iterator = generator.allocate_register(); generator.emit(iterator, input_array); bool first = true; - auto assign_value_to_alias = [&](auto& alias, Bytecode::Operand value) { + auto assign_value_to_alias = [&](auto& alias, ScopedOperand value) { return alias.visit( [&](Empty) -> Bytecode::CodeGenerationErrorOr { // This element is an elision @@ -1284,7 +1290,7 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte }); }; - auto temp_iterator_result = Bytecode::Operand(generator.allocate_register()); + auto temp_iterator_result = generator.allocate_register(); for (auto& [name, alias, initializer, is_rest] : pattern.entries) { VERIFY(name.has()); @@ -1292,7 +1298,7 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte if (is_rest) { VERIFY(!initializer); - auto value = Bytecode::Operand(generator.allocate_register()); + auto value = generator.allocate_register(); if (first) { // The iterator has not been called, and is thus known to be not exhausted @@ -1307,7 +1313,7 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte Bytecode::Label { if_exhausted_block }, Bytecode::Label { if_not_exhausted_block }); - value = Bytecode::Operand(generator.allocate_register()); + value = generator.allocate_register(); generator.switch_to_basic_block(if_exhausted_block); generator.emit(value); @@ -1350,7 +1356,7 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte generator.switch_to_basic_block(no_bail_block); // Get the next value in the iterator - auto value = Bytecode::Operand { generator.allocate_register() }; + auto value = generator.allocate_register(); generator.emit_iterator_value(value, temp_iterator_result); auto& create_binding_block = generator.make_block(); @@ -1374,7 +1380,7 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte generator.switch_to_basic_block(value_is_undefined_block); - Optional default_value; + Optional default_value; if (auto const* alias_identifier = alias.get_pointer>()) { default_value = TRY(generator.emit_named_evaluation_if_anonymous_function(*initializer, generator.intern_identifier((*alias_identifier)->string()))).value(); } else if (auto const* name_identifier = name.get_pointer>()) { @@ -1409,7 +1415,7 @@ static Bytecode::CodeGenerationErrorOr generate_array_binding_pattern_byte return {}; } -static Bytecode::CodeGenerationErrorOr generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Operand const& input_value, bool create_variables) +static Bytecode::CodeGenerationErrorOr generate_binding_pattern_bytecode(Bytecode::Generator& generator, BindingPattern const& pattern, Bytecode::Op::SetVariable::InitializationMode initialization_mode, ScopedOperand const& input_value, bool create_variables) { if (pattern.kind == BindingPattern::Kind::Object) return generate_object_binding_pattern_bytecode(generator, pattern, initialization_mode, input_value, create_variables); @@ -1417,7 +1423,7 @@ static Bytecode::CodeGenerationErrorOr generate_binding_pattern_bytecode(B return generate_array_binding_pattern_bytecode(generator, pattern, initialization_mode, input_value, create_variables); } -static Bytecode::CodeGenerationErrorOr assign_value_to_variable_declarator(Bytecode::Generator& generator, VariableDeclarator const& declarator, VariableDeclaration const& declaration, Bytecode::Operand value) +static Bytecode::CodeGenerationErrorOr assign_value_to_variable_declarator(Bytecode::Generator& generator, VariableDeclarator const& declarator, VariableDeclaration const& declaration, ScopedOperand value) { auto initialization_mode = declaration.is_lexical_declaration() ? Bytecode::Op::SetVariable::InitializationMode::Initialize : Bytecode::Op::SetVariable::InitializationMode::Set; @@ -1431,7 +1437,7 @@ static Bytecode::CodeGenerationErrorOr assign_value_to_variable_declarator }); } -Bytecode::CodeGenerationErrorOr> VariableDeclaration::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> VariableDeclaration::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); @@ -1439,17 +1445,17 @@ Bytecode::CodeGenerationErrorOr> VariableDeclaration // NOTE: `var` declarations can have duplicates, but duplicate `let` or `const` bindings are a syntax error. // Because of this, we can sink `let` and `const` directly into the preferred_dst if available. // This is not safe for `var` since the preferred_dst may be used in the initializer. - Optional init_dst; + Optional init_dst; if (declaration_kind() != DeclarationKind::Var) { if (auto const* identifier = declarator->target().get_pointer>()) { if ((*identifier)->is_local()) { - init_dst = Bytecode::Operand(Bytecode::Operand::Type::Local, (*identifier)->local_variable_index()); + init_dst = generator.local((*identifier)->local_variable_index()); } } } if (declarator->init()) { - auto value = TRY([&]() -> Bytecode::CodeGenerationErrorOr { + auto value = TRY([&]() -> Bytecode::CodeGenerationErrorOr { if (auto const* lhs = declarator->target().get_pointer>()) { return TRY(generator.emit_named_evaluation_if_anonymous_function(*declarator->init(), generator.intern_identifier((*lhs)->string()), init_dst)).value(); } else { @@ -1471,12 +1477,12 @@ Bytecode::CodeGenerationErrorOr> VariableDeclaration } // NOTE: VariableDeclaration doesn't return a completion value. - return Optional {}; + return Optional {}; } struct BaseAndValue { - Bytecode::Operand base; - Bytecode::Operand value; + ScopedOperand base; + ScopedOperand value; }; static Bytecode::CodeGenerationErrorOr get_base_and_value_from_member_expression(Bytecode::Generator& generator, MemberExpression const& member_expression) @@ -1487,7 +1493,7 @@ static Bytecode::CodeGenerationErrorOr get_base_and_value_from_mem // 2. Let actualThis be ? env.GetThisBinding(). auto this_value = generator.get_this(); - Optional computed_property; + Optional computed_property; if (member_expression.is_computed()) { // SuperProperty : super [ Expression ] @@ -1502,10 +1508,10 @@ static Bytecode::CodeGenerationErrorOr get_base_and_value_from_mem // 1. Let env be GetThisEnvironment(). // 2. Assert: env.HasSuperBinding() is true. // 3. Let baseValue be ? env.GetSuperBase(). - auto super_base = Bytecode::Operand(generator.allocate_register()); + auto super_base = generator.allocate_register(); generator.emit(super_base); - auto value = Bytecode::Operand { generator.allocate_register() }; + auto value = generator.allocate_register(); // 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }. if (computed_property.has_value()) { @@ -1522,7 +1528,7 @@ static Bytecode::CodeGenerationErrorOr get_base_and_value_from_mem } auto base = TRY(member_expression.object().generate_bytecode(generator)).value(); - auto value = Bytecode::Operand { generator.allocate_register() }; + auto value = generator.allocate_register(); if (member_expression.is_computed()) { auto property = TRY(member_expression.property().generate_bytecode(generator)).value(); generator.emit(value, base, property); @@ -1539,15 +1545,15 @@ static Bytecode::CodeGenerationErrorOr get_base_and_value_from_mem return BaseAndValue { base, value }; } -static Bytecode::CodeGenerationErrorOr generate_optional_chain(Bytecode::Generator& generator, OptionalChain const& optional_chain, Bytecode::Operand current_value, Bytecode::Operand current_base, [[maybe_unused]] Optional preferred_dst = {}); +static Bytecode::CodeGenerationErrorOr generate_optional_chain(Bytecode::Generator& generator, OptionalChain const& optional_chain, ScopedOperand current_value, ScopedOperand current_base, [[maybe_unused]] Optional preferred_dst = {}); -Bytecode::CodeGenerationErrorOr> CallExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> CallExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); Optional builtin; - Optional original_callee; + Optional original_callee; auto this_value = generator.add_constant(js_undefined()); if (is(this)) { @@ -1560,8 +1566,8 @@ Bytecode::CodeGenerationErrorOr> CallExpression::gen builtin = Bytecode::get_builtin(member_expression); } else if (is(*m_callee)) { auto& optional_chain = static_cast(*m_callee); - original_callee = Bytecode::Operand(generator.allocate_register()); - this_value = Bytecode::Operand(generator.allocate_register()); + original_callee = generator.allocate_register(); + this_value = generator.allocate_register(); TRY(generate_optional_chain(generator, optional_chain, *original_callee, this_value)); } else if (is(*m_callee)) { // If the original_callee is an identifier, we may need to extract a `this` value. @@ -1571,16 +1577,16 @@ Bytecode::CodeGenerationErrorOr> CallExpression::gen // a `with` binding, so we can skip this. auto& identifier = static_cast(*m_callee); if (identifier.is_local()) { - auto local = Bytecode::Operand(Bytecode::Operand::Type::Local, identifier.local_variable_index()); - if (!generator.is_local_initialized(local.index())) { + auto local = generator.local(identifier.local_variable_index()); + if (!generator.is_local_initialized(local.operand().index())) { generator.emit(local); } original_callee = local; } else if (identifier.is_global()) { original_callee = m_callee->generate_bytecode(generator).value(); } else { - original_callee = Bytecode::Operand(generator.allocate_register()); - this_value = Bytecode::Operand(generator.allocate_register()); + original_callee = generator.allocate_register(); + this_value = generator.allocate_register(); generator.emit( *original_callee, this_value, @@ -1593,7 +1599,7 @@ Bytecode::CodeGenerationErrorOr> CallExpression::gen } // NOTE: We copy the callee to a new register to avoid overwriting it while evaluating arguments. - auto callee = Bytecode::Operand(generator.allocate_register()); + auto callee = generator.allocate_register(); generator.emit(callee, *original_callee); Bytecode::Op::CallType call_type; @@ -1616,10 +1622,10 @@ Bytecode::CodeGenerationErrorOr> CallExpression::gen auto arguments = TRY(arguments_to_array_for_call(generator, this->arguments())).value(); generator.emit(call_type, dst, callee, this_value, arguments, expression_string_index); } else { - Vector argument_operands; + Vector argument_operands; for (auto const& argument : arguments()) { auto argument_value = TRY(argument.value->generate_bytecode(generator)).value(); - auto temporary = Bytecode::Operand(generator.allocate_register()); + auto temporary = generator.allocate_register(); generator.emit(temporary, argument_value); argument_operands.append(temporary); } @@ -1637,21 +1643,21 @@ Bytecode::CodeGenerationErrorOr> CallExpression::gen return dst; } -static Bytecode::Operand generate_await( +static ScopedOperand generate_await( Bytecode::Generator& generator, - Bytecode::Operand argument, - Bytecode::Operand received_completion, - Bytecode::Operand received_completion_type, - Bytecode::Operand received_completion_value, + ScopedOperand argument, + ScopedOperand received_completion, + ScopedOperand received_completion_type, + ScopedOperand received_completion_value, Bytecode::IdentifierTableIndex type_identifier, Bytecode::IdentifierTableIndex value_identifier); // https://tc39.es/ecma262/#sec-return-statement-runtime-semantics-evaluation -Bytecode::CodeGenerationErrorOr> ReturnStatement::generate_bytecode(Bytecode::Generator& generator, Optional) const +Bytecode::CodeGenerationErrorOr> ReturnStatement::generate_bytecode(Bytecode::Generator& generator, Optional) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); - Optional return_value; + Optional return_value; if (m_argument) { // ReturnStatement : return Expression ; @@ -1666,9 +1672,9 @@ Bytecode::CodeGenerationErrorOr> ReturnStatement::ge // See: https://tc39.es/ecma262/#sec-asyncblockstart // c. Assert: If we return here, the async function either threw an exception or performed an implicit or explicit return; all awaiting is done. if (generator.is_in_async_function()) { - auto received_completion = Bytecode::Operand(generator.allocate_register()); - auto received_completion_type = Bytecode::Operand(generator.allocate_register()); - auto received_completion_value = Bytecode::Operand(generator.allocate_register()); + auto received_completion = generator.allocate_register(); + auto received_completion_type = generator.allocate_register(); + auto received_completion_value = generator.allocate_register(); auto type_identifier = generator.intern_identifier("type"); auto value_identifier = generator.intern_identifier("value"); @@ -1687,7 +1693,7 @@ Bytecode::CodeGenerationErrorOr> ReturnStatement::ge generator.emit(nullptr, *return_value); } else { generator.perform_needed_unwinds(); - generator.emit(return_value); + generator.emit(return_value.has_value() ? return_value->operand() : Optional {}); } return return_value; @@ -1695,9 +1701,9 @@ Bytecode::CodeGenerationErrorOr> ReturnStatement::ge static void get_received_completion_type_and_value( Bytecode::Generator& generator, - Bytecode::Operand received_completion, - Bytecode::Operand received_completion_type, - Bytecode::Operand received_completion_value, + ScopedOperand received_completion, + ScopedOperand received_completion_type, + ScopedOperand received_completion_value, Bytecode::IdentifierTableIndex type_identifier, Bytecode::IdentifierTableIndex value_identifier) { @@ -1712,10 +1718,10 @@ enum class AwaitBeforeYield { static void generate_yield(Bytecode::Generator& generator, Bytecode::Label continuation_label, - Bytecode::Operand argument, - Bytecode::Operand received_completion, - Bytecode::Operand received_completion_type, - Bytecode::Operand received_completion_value, + ScopedOperand argument, + ScopedOperand received_completion, + ScopedOperand received_completion_type, + ScopedOperand received_completion_value, Bytecode::IdentifierTableIndex type_identifier, Bytecode::IdentifierTableIndex value_identifier, AwaitBeforeYield await_before_yield) @@ -1732,13 +1738,13 @@ static void generate_yield(Bytecode::Generator& generator, generator.emit(Bytecode::Label { unwrap_yield_resumption_block }, argument); generator.switch_to_basic_block(unwrap_yield_resumption_block); - generator.emit(received_completion, Bytecode::Operand(Bytecode::Register(0))); + generator.emit(received_completion, generator.accumulator()); get_received_completion_type_and_value(generator, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier); // 27.6.3.7 AsyncGeneratorUnwrapYieldResumption ( resumptionValue ), https://tc39.es/ecma262/#sec-asyncgeneratorunwrapyieldresumption // 1. If resumptionValue.[[Type]] is not return, return ? resumptionValue. auto& resumption_value_type_is_return_block = generator.make_block(); - auto resumption_value_type_is_not_return_result = Bytecode::Operand(generator.allocate_register()); + auto resumption_value_type_is_not_return_result = generator.allocate_register(); generator.emit( resumption_value_type_is_not_return_result, received_completion_type, @@ -1755,7 +1761,7 @@ static void generate_yield(Bytecode::Generator& generator, // 3. If awaited.[[Type]] is throw, return ? awaited. auto& awaited_type_is_normal_block = generator.make_block(); - auto awaited_type_is_throw_result = Bytecode::Operand(generator.allocate_register()); + auto awaited_type_is_throw_result = generator.allocate_register(); generator.emit( awaited_type_is_throw_result, received_completion_type, @@ -1778,20 +1784,20 @@ static void generate_yield(Bytecode::Generator& generator, generator.emit(continuation_label); } -Bytecode::CodeGenerationErrorOr> YieldExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> YieldExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { // Note: We need to catch any scheduled exceptions and reschedule them on re-entry // as the act of yielding would otherwise clear them out // This only applies when we are in a finalizer bool is_in_finalizer = generator.is_in_finalizer(); - Optional saved_exception; + Optional saved_exception; Bytecode::Generator::SourceLocationScope scope(generator, *this); VERIFY(generator.is_in_generator_function()); - auto received_completion = Bytecode::Operand(generator.allocate_register()); - auto received_completion_type = Bytecode::Operand(generator.allocate_register()); - auto received_completion_value = Bytecode::Operand(generator.allocate_register()); + auto received_completion = generator.allocate_register(); + auto received_completion_type = generator.allocate_register(); + auto received_completion_value = generator.allocate_register(); auto type_identifier = generator.intern_identifier("type"); auto value_identifier = generator.intern_identifier("value"); @@ -1807,16 +1813,16 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge auto value = TRY(m_argument->generate_bytecode(generator)).value(); // 4. Let iteratorRecord be ? GetIterator(value, generatorKind). - auto iterator_record = Bytecode::Operand(generator.allocate_register()); + auto iterator_record = generator.allocate_register(); auto iterator_hint = generator.is_in_async_generator_function() ? IteratorHint::Async : IteratorHint::Sync; generator.emit(iterator_record, value, iterator_hint); // 5. Let iterator be iteratorRecord.[[Iterator]]. - auto iterator = Bytecode::Operand(generator.allocate_register()); + auto iterator = generator.allocate_register(); generator.emit(iterator, iterator_record); // Cache iteratorRecord.[[NextMethod]] for use in step 7.a.i. - auto next_method = Bytecode::Operand(generator.allocate_register()); + auto next_method = generator.allocate_register(); generator.emit(next_method, iterator_record); // 6. Let received be NormalCompletion(undefined). @@ -1837,7 +1843,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge auto& type_is_normal_block = generator.make_block(); auto& is_type_throw_block = generator.make_block(); - auto received_completion_type_register_is_normal = Bytecode::Operand(generator.allocate_register()); + auto received_completion_type_register_is_normal = generator.allocate_register(); generator.emit( received_completion_type_register_is_normal, received_completion_type, @@ -1850,9 +1856,9 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(type_is_normal_block); // i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »). - auto array = Bytecode::Operand(generator.allocate_register()); - generator.emit_with_extra_operand_slots(2u, array, AK::Array { received_completion_value, received_completion_value }); - auto inner_result = Bytecode::Operand(generator.allocate_register()); + auto array = generator.allocate_register(); + generator.emit_with_extra_operand_slots(2u, array, AK::Array { received_completion_value.operand(), received_completion_value.operand() }); + auto inner_result = generator.allocate_register(); generator.emit(Bytecode::Op::CallType::Call, inner_result, next_method, iterator, array); // ii. If generatorKind is async, set innerResult to ? Await(innerResult). @@ -1865,7 +1871,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.emit(inner_result); // iv. Let done be ? IteratorComplete(innerResult). - auto done = Bytecode::Operand(generator.allocate_register()); + auto done = generator.allocate_register(); generator.emit_iterator_complete(done, inner_result); // v. If done is true, then @@ -1879,7 +1885,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(type_is_normal_done_block); // 1. Return ? IteratorValue(innerResult). - auto return_value = Bytecode::Operand(generator.allocate_register()); + auto return_value = generator.allocate_register(); generator.emit_iterator_value(return_value, inner_result); generator.emit(Bytecode::Label { loop_end_block }); @@ -1891,7 +1897,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge { // FIXME: Yield currently only accepts a Value, not an object conforming to the IteratorResult interface, so we have to do an observable lookup of `value` here. // This only matters for non-async generators. - auto current_value = Bytecode::Operand(generator.allocate_register()); + auto current_value = generator.allocate_register(); generator.emit_iterator_value(current_value, inner_result); if (is_in_finalizer) { @@ -1915,10 +1921,10 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge auto& type_is_throw_block = generator.make_block(); auto& type_is_return_block = generator.make_block(); - auto received_completion_type_register_is_throw = Bytecode::Operand(generator.allocate_register()); + auto received_completion_type_register_is_throw = generator.allocate_register(); generator.emit( received_completion_type_register_is_throw, - Bytecode::Operand(received_completion_type), + received_completion_type, generator.add_constant(Value(to_underlying(Completion::Type::Throw)))); generator.emit( received_completion_type_register_is_throw, @@ -1928,7 +1934,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(type_is_throw_block); // i. Let throw be ? GetMethod(iterator, "throw"). - auto throw_method = Bytecode::Operand(generator.allocate_register()); + auto throw_method = generator.allocate_register(); generator.emit(throw_method, iterator, generator.intern_identifier("throw")); // ii. If throw is not undefined, then @@ -1942,8 +1948,8 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(throw_method_is_defined_block); // 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »). - auto received_value_array = Bytecode::Operand(generator.allocate_register()); - generator.emit_with_extra_operand_slots(2u, received_value_array, AK::Array { received_completion_value, received_completion_value }); + auto received_value_array = generator.allocate_register(); + generator.emit_with_extra_operand_slots(2u, received_value_array, AK::Array { received_completion_value.operand(), received_completion_value.operand() }); generator.emit(Bytecode::Op::CallType::Call, inner_result, throw_method, iterator, received_value_array); // 2. If generatorKind is async, set innerResult to ? Await(innerResult). @@ -1981,7 +1987,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge // FIXME: Yield currently only accepts a Value, not an object conforming to the IteratorResult interface, so we have to do an observable lookup of `value` here. // This only matters for non-async generators. - auto yield_value = Bytecode::Operand(generator.allocate_register()); + auto yield_value = generator.allocate_register(); generator.emit_iterator_value(yield_value, inner_result); generate_yield(generator, Bytecode::Label { continuation_block }, yield_value, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier, AwaitBeforeYield::No); } @@ -2003,7 +2009,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge // 5. NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation: iterator does not have a throw method. // 6. Throw a TypeError exception. - auto exception = Bytecode::Operand(generator.allocate_register()); + auto exception = generator.allocate_register(); generator.emit(exception, generator.intern_string(ErrorType::YieldFromIteratorMissingThrowMethod.message())); generator.perform_needed_unwinds(); generator.emit(exception); @@ -2013,7 +2019,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(type_is_return_block); // ii. Let return be ? GetMethod(iterator, "return"). - auto return_method = Bytecode::Operand(generator.allocate_register()); + auto return_method = generator.allocate_register(); generator.emit(return_method, iterator, generator.intern_identifier("return")); // iii. If return is undefined, then @@ -2039,9 +2045,9 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(return_is_defined_block); // iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »). - auto call_array = Bytecode::Operand(generator.allocate_register()); - generator.emit_with_extra_operand_slots(2, call_array, AK::Array { received_completion_value, received_completion_value }); - auto inner_return_result = Bytecode::Operand(generator.allocate_register()); + auto call_array = generator.allocate_register(); + generator.emit_with_extra_operand_slots(2, call_array, AK::Array { received_completion_value.operand(), received_completion_value.operand() }); + auto inner_return_result = generator.allocate_register(); generator.emit(Bytecode::Op::CallType::Call, inner_return_result, return_method, iterator, call_array); // v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult). @@ -2067,7 +2073,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge generator.switch_to_basic_block(type_is_return_done_block); // 1. Let value be ? IteratorValue(innerReturnResult). - auto inner_return_result_value = Bytecode::Operand(generator.allocate_register()); + auto inner_return_result_value = generator.allocate_register(); generator.emit_iterator_value(inner_return_result_value, inner_return_result); // 2. Return Completion Record { [[Type]]: return, [[Value]]: value, [[Target]]: empty }. @@ -2080,7 +2086,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge // x. Else, set received to Completion(GeneratorYield(innerReturnResult)). // FIXME: Yield currently only accepts a Value, not an object conforming to the IteratorResult interface, so we have to do an observable lookup of `value` here. // This only matters for non-async generators. - auto received = Bytecode::Operand(generator.allocate_register()); + auto received = generator.allocate_register(); generator.emit_iterator_value(received, inner_return_result); generate_yield(generator, Bytecode::Label { continuation_block }, received, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier, AwaitBeforeYield::No); @@ -2090,7 +2096,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge if (is_in_finalizer) generator.emit(Bytecode::Operand(Bytecode::Register::exception()), Bytecode::Operand(*saved_exception)); - generator.emit(received_completion, Bytecode::Operand(Bytecode::Register(0))); + generator.emit(received_completion, generator.accumulator()); get_received_completion_type_and_value(generator, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier); generator.emit(Bytecode::Label { loop_block }); @@ -2098,7 +2104,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge return return_value; } - Optional argument; + Optional argument; if (m_argument) argument = TRY(m_argument->generate_bytecode(generator)).value(); else @@ -2117,13 +2123,14 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge if (is_in_finalizer) generator.emit(Bytecode::Operand(Bytecode::Register::exception()), Bytecode::Operand(*saved_exception)); - generator.emit(received_completion, Bytecode::Operand(Bytecode::Register(0))); + generator.emit(received_completion, generator.accumulator()); + get_received_completion_type_and_value(generator, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier); auto& normal_completion_continuation_block = generator.make_block(); auto& throw_completion_continuation_block = generator.make_block(); - auto received_completion_type_is_normal = Bytecode::Operand(generator.allocate_register()); + auto received_completion_type_is_normal = generator.allocate_register(); generator.emit( received_completion_type_is_normal, received_completion_type, @@ -2137,7 +2144,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge auto& return_value_block = generator.make_block(); generator.switch_to_basic_block(throw_completion_continuation_block); - auto received_completion_type_is_throw = Bytecode::Operand(generator.allocate_register()); + auto received_completion_type_is_throw = generator.allocate_register(); generator.emit( received_completion_type_is_throw, received_completion_type, @@ -2161,7 +2168,7 @@ Bytecode::CodeGenerationErrorOr> YieldExpression::ge return received_completion_value; } -Bytecode::CodeGenerationErrorOr> IfStatement::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> IfStatement::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // test @@ -2195,7 +2202,7 @@ Bytecode::CodeGenerationErrorOr> IfStatement::genera generator.switch_to_basic_block(false_block); - Optional alternate; + Optional alternate; if (m_alternate) { alternate = TRY(m_alternate->generate_bytecode(generator, dst)); } @@ -2210,24 +2217,24 @@ Bytecode::CodeGenerationErrorOr> IfStatement::genera return dst; } -Bytecode::CodeGenerationErrorOr> ContinueStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ContinueStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (!m_target_label.has_value()) { generator.generate_continue(); - return Optional {}; + return Optional {}; } generator.generate_continue(m_target_label.value()); - return Optional {}; + return Optional {}; } -Bytecode::CodeGenerationErrorOr> DebuggerStatement::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> DebuggerStatement::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const { - return Optional {}; + return Optional {}; } -Bytecode::CodeGenerationErrorOr> ConditionalExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ConditionalExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // test @@ -2265,10 +2272,10 @@ Bytecode::CodeGenerationErrorOr> ConditionalExpressi return dst; } -Bytecode::CodeGenerationErrorOr> SequenceExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> SequenceExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); - Optional last_value; + Optional last_value; for (auto& expression : m_expressions) { last_value = TRY(expression->generate_bytecode(generator)); } @@ -2276,7 +2283,7 @@ Bytecode::CodeGenerationErrorOr> SequenceExpression: return last_value; } -Bytecode::CodeGenerationErrorOr> TemplateLiteral::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> TemplateLiteral::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); @@ -2294,7 +2301,7 @@ Bytecode::CodeGenerationErrorOr> TemplateLiteral::ge return dst; } -Bytecode::CodeGenerationErrorOr> TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> TaggedTemplateLiteral::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto tag = TRY(m_tag->generate_bytecode(generator)).value(); @@ -2307,12 +2314,12 @@ Bytecode::CodeGenerationErrorOr> TaggedTemplateLiter // * cache this somehow // * add a raw object accessor // * freeze array and raw member - Vector string_regs; + Vector string_regs; auto& expressions = m_template_literal->expressions(); for (size_t i = 0; i < expressions.size(); ++i) { if (i % 2 != 0) continue; - string_regs.append(Bytecode::Operand(generator.allocate_register())); + string_regs.append(generator.allocate_sequential_register()); } size_t reg_index = 0; @@ -2322,7 +2329,7 @@ Bytecode::CodeGenerationErrorOr> TaggedTemplateLiter // NOTE: If the string contains invalid escapes we get a null expression here, // which we then convert to the expected `undefined` TV. See // 12.9.6.1 Static Semantics: TV, https://tc39.es/ecma262/#sec-static-semantics-tv - auto string_reg = Bytecode::Operand(string_regs[reg_index++]); + auto string_reg = string_regs[reg_index++]; if (is(expressions[i])) { generator.emit(string_reg, generator.add_constant(js_undefined())); } else { @@ -2331,17 +2338,17 @@ Bytecode::CodeGenerationErrorOr> TaggedTemplateLiter } } - auto strings_array = Bytecode::Operand(generator.allocate_register()); + auto strings_array = generator.allocate_sequential_register(); if (string_regs.is_empty()) { generator.emit(strings_array); } else { - generator.emit_with_extra_operand_slots(2u, strings_array, AK::Array { string_regs.first(), string_regs.last() }); + generator.emit_with_extra_operand_slots(2u, strings_array, AK::Array { string_regs.first().operand(), string_regs.last().operand() }); } - Vector argument_regs; + Vector argument_regs; argument_regs.append(strings_array); for (size_t i = 1; i < expressions.size(); i += 2) - argument_regs.append(Bytecode::Operand(generator.allocate_register())); + argument_regs.append(generator.allocate_sequential_register()); for (size_t i = 1; i < expressions.size(); i += 2) { auto string_reg = argument_regs[1 + i / 2]; @@ -2349,9 +2356,9 @@ Bytecode::CodeGenerationErrorOr> TaggedTemplateLiter generator.emit(string_reg, string); } - Vector raw_string_regs; + Vector raw_string_regs; for ([[maybe_unused]] auto& raw_string : m_template_literal->raw_strings()) - string_regs.append(Bytecode::Operand(generator.allocate_register())); + string_regs.append(generator.allocate_sequential_register()); reg_index = 0; for (auto& raw_string : m_template_literal->raw_strings()) { @@ -2361,18 +2368,18 @@ Bytecode::CodeGenerationErrorOr> TaggedTemplateLiter raw_string_regs.append(raw_string_reg); } - auto raw_strings_array = Bytecode::Operand(generator.allocate_register()); + auto raw_strings_array = generator.allocate_register(); if (raw_string_regs.is_empty()) { generator.emit(raw_strings_array); } else { - generator.emit_with_extra_operand_slots(2u, raw_strings_array, AK::Array { raw_string_regs.first(), raw_string_regs.last() }); + generator.emit_with_extra_operand_slots(2u, raw_strings_array, AK::Array { raw_string_regs.first().operand(), raw_string_regs.last().operand() }); } generator.emit(strings_array, generator.intern_identifier("raw"), raw_strings_array, Bytecode::Op::PropertyKind::KeyValue, generator.next_property_lookup_cache()); - auto arguments = Bytecode::Operand(generator.allocate_register()); + auto arguments = generator.allocate_register(); if (!argument_regs.is_empty()) - generator.emit_with_extra_operand_slots(2, arguments, AK::Array { argument_regs.first(), argument_regs.last() }); + generator.emit_with_extra_operand_slots(2, arguments, AK::Array { argument_regs.first().operand(), argument_regs.last().operand() }); else generator.emit(arguments); @@ -2381,25 +2388,25 @@ Bytecode::CodeGenerationErrorOr> TaggedTemplateLiter return dst; } -Bytecode::CodeGenerationErrorOr> UpdateExpression::generate_bytecode(Bytecode::Generator& generator, Optional) const +Bytecode::CodeGenerationErrorOr> UpdateExpression::generate_bytecode(Bytecode::Generator& generator, Optional) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto reference = TRY(generator.emit_load_from_reference(*m_argument)); - Optional previous_value_for_postfix; + Optional previous_value_for_postfix; if (m_op == UpdateOp::Increment) { if (m_prefixed) { generator.emit(*reference.loaded_value); } else { - previous_value_for_postfix = Bytecode::Operand(generator.allocate_register()); + previous_value_for_postfix = generator.allocate_register(); generator.emit(*previous_value_for_postfix, *reference.loaded_value); } } else { if (m_prefixed) { generator.emit(*reference.loaded_value); } else { - previous_value_for_postfix = Bytecode::Operand(generator.allocate_register()); + previous_value_for_postfix = generator.allocate_register(); generator.emit(*previous_value_for_postfix, *reference.loaded_value); } } @@ -2414,16 +2421,16 @@ Bytecode::CodeGenerationErrorOr> UpdateExpression::g return *reference.loaded_value; } -Bytecode::CodeGenerationErrorOr> ThrowStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ThrowStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto argument = TRY(m_argument->generate_bytecode(generator)).value(); generator.perform_needed_unwinds(); generator.emit(argument); - return Optional {}; + return Optional {}; } -Bytecode::CodeGenerationErrorOr> BreakStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> BreakStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // FIXME: Handle finally blocks in a graceful manner @@ -2431,14 +2438,14 @@ Bytecode::CodeGenerationErrorOr> BreakStatement::gen // execution at the designated block if (!m_target_label.has_value()) { generator.generate_break(); - return Optional {}; + return Optional {}; } generator.generate_break(m_target_label.value()); - return Optional {}; + return Optional {}; } -Bytecode::CodeGenerationErrorOr> TryStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> TryStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto& saved_block = generator.current_block(); @@ -2449,7 +2456,7 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener Bytecode::BasicBlock* next_block { nullptr }; - Optional dst; + Optional dst; if (m_finalizer) { // FIXME: See notes in Op.h->ScheduleJump @@ -2475,7 +2482,7 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener auto& handler_block = generator.make_block(); generator.switch_to_basic_block(handler_block); - auto caught_value = Bytecode::Operand { generator.allocate_register() }; + auto caught_value = generator.allocate_register(); generator.emit(caught_value); if (!m_finalizer) { @@ -2506,7 +2513,7 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener auto handler_result = TRY(m_handler->body().generate_bytecode(generator)); if (handler_result.has_value() && !generator.is_current_block_terminated()) { - dst = Bytecode::Operand(generator.allocate_register()); + dst = generator.allocate_register(); generator.emit(*dst, *handler_result); } handler_target = Bytecode::Label { handler_block }; @@ -2550,7 +2557,7 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener auto block_result = TRY(m_block->generate_bytecode(generator)); if (!generator.is_current_block_terminated()) { if (block_result.has_value()) { - dst = Bytecode::Operand(generator.allocate_register()); + dst = generator.allocate_register(); generator.emit(*dst, *block_result); } @@ -2576,15 +2583,19 @@ Bytecode::CodeGenerationErrorOr> TryStatement::gener return dst; } -Bytecode::CodeGenerationErrorOr> SwitchStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> SwitchStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } -Bytecode::CodeGenerationErrorOr> SwitchStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> SwitchStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); + + auto dst = generator.allocate_register(); + generator.emit(dst, generator.add_constant(js_undefined())); + auto discriminant = TRY(m_discriminant->generate_bytecode(generator)).value(); Vector case_blocks; Bytecode::BasicBlock* entry_block_for_default { nullptr }; @@ -2602,7 +2613,7 @@ Bytecode::CodeGenerationErrorOr> SwitchStatement::ge if (switch_case->test()) { generator.switch_to_basic_block(*next_test_block); auto test_value = TRY(switch_case->test()->generate_bytecode(generator)).value(); - auto result = Bytecode::Operand(generator.allocate_register()); + auto result = generator.allocate_register(); generator.emit(result, test_value, discriminant); next_test_block = &generator.make_block(); generator.emit( @@ -2630,7 +2641,6 @@ Bytecode::CodeGenerationErrorOr> SwitchStatement::ge } auto current_block = case_blocks.begin(); generator.begin_breakable_scope(Bytecode::Label { end_block }, label_set); - auto dst = Bytecode::Operand(generator.allocate_register()); for (auto& switch_case : m_cases) { generator.switch_to_basic_block(*current_block); for (auto& statement : switch_case->children()) { @@ -2663,23 +2673,23 @@ Bytecode::CodeGenerationErrorOr> SwitchStatement::ge return dst; } -Bytecode::CodeGenerationErrorOr> SuperExpression::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> SuperExpression::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const { // The semantics for SuperExpression are handled in CallExpression and SuperCall. VERIFY_NOT_REACHED(); } -Bytecode::CodeGenerationErrorOr> ClassDeclaration::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ClassDeclaration::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto value = TRY(m_class_expression->generate_bytecode(generator)).value(); generator.emit_set_variable(*m_class_expression.ptr()->m_name, value, Bytecode::Op::SetVariable::InitializationMode::Initialize); // NOTE: ClassDeclaration does not produce a value. - return Optional {}; + return Optional {}; } // 15.7.14 Runtime Semantics: ClassDefinitionEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation -Bytecode::CodeGenerationErrorOr> ClassExpression::generate_bytecode_with_lhs_name(Bytecode::Generator& generator, Optional lhs_name, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ClassExpression::generate_bytecode_with_lhs_name(Bytecode::Generator& generator, Optional lhs_name, Optional preferred_dst) const { // NOTE: Step 2 is not a part of NewClass instruction because it is assumed to be done before super class expression evaluation generator.emit(); @@ -2690,41 +2700,41 @@ Bytecode::CodeGenerationErrorOr> ClassExpression::ge generator.emit(interned_index, Bytecode::Op::EnvironmentMode::Lexical, true); } - Optional super_class; + Optional super_class; if (m_super_class) super_class = TRY(m_super_class->generate_bytecode(generator)).value(); auto dst = choose_dst(generator, preferred_dst); - generator.emit(dst, super_class, *this, lhs_name); + generator.emit(dst, super_class.has_value() ? super_class->operand() : Optional {}, *this, lhs_name); return dst; } -Bytecode::CodeGenerationErrorOr> ClassExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ClassExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_bytecode_with_lhs_name(generator, {}, preferred_dst); } -Bytecode::CodeGenerationErrorOr> SpreadExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> SpreadExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { // NOTE: All users of this should handle the behaviour of this on their own, // assuming it returns an Array-like object return m_target->generate_bytecode(generator); } -Bytecode::CodeGenerationErrorOr> ThisExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ThisExpression::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generator.get_this(preferred_dst); } -static Bytecode::Operand generate_await( +static ScopedOperand generate_await( Bytecode::Generator& generator, - Bytecode::Operand argument, - Bytecode::Operand received_completion, - Bytecode::Operand received_completion_type, - Bytecode::Operand received_completion_value, + ScopedOperand argument, + ScopedOperand received_completion, + ScopedOperand received_completion_type, + ScopedOperand received_completion_value, Bytecode::IdentifierTableIndex type_identifier, Bytecode::IdentifierTableIndex value_identifier) { @@ -2737,13 +2747,13 @@ static Bytecode::Operand generate_await( // FIXME: It's really magical that we can just assume that the completion value is in register 0. // It ends up there because we "return" from the Await instruction above via the synthetic // generator function that actually drives async execution. - generator.emit(received_completion, Bytecode::Operand(Bytecode::Register(0))); + generator.emit(received_completion, generator.accumulator()); get_received_completion_type_and_value(generator, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier); auto& normal_completion_continuation_block = generator.make_block(); auto& throw_value_block = generator.make_block(); - auto received_completion_type_is_normal = Bytecode::Operand(generator.allocate_register()); + auto received_completion_type_is_normal = generator.allocate_register(); generator.emit( received_completion_type_is_normal, received_completion_type, @@ -2763,16 +2773,16 @@ static Bytecode::Operand generate_await( return received_completion_value; } -Bytecode::CodeGenerationErrorOr> AwaitExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> AwaitExpression::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto argument = TRY(m_argument->generate_bytecode(generator)).value(); - auto received_completion = Bytecode::Operand(generator.allocate_register()); - auto received_completion_type = Bytecode::Operand(generator.allocate_register()); - auto received_completion_value = Bytecode::Operand(generator.allocate_register()); + auto received_completion = generator.allocate_register(); + auto received_completion_type = generator.allocate_register(); + auto received_completion_value = generator.allocate_register(); - generator.emit(received_completion, Bytecode::Operand(Bytecode::Register(0))); + generator.emit(received_completion, generator.accumulator()); auto type_identifier = generator.intern_identifier("type"); auto value_identifier = generator.intern_identifier("value"); @@ -2780,7 +2790,7 @@ Bytecode::CodeGenerationErrorOr> AwaitExpression::ge return generate_await(generator, argument, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier); } -Bytecode::CodeGenerationErrorOr> WithStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> WithStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto object = TRY(m_object->generate_bytecode(generator)).value(); @@ -2816,7 +2826,7 @@ enum class IterationKind { struct ForInOfHeadEvaluationResult { bool is_destructuring { false }; LHSKind lhs_kind { LHSKind::Assignment }; - Optional iterator; + Optional iterator; }; static Bytecode::CodeGenerationErrorOr for_in_of_head_evaluation(Bytecode::Generator& generator, IterationKind iteration_kind, Variant, NonnullRefPtr> const& lhs, NonnullRefPtr const& rhs) { @@ -2889,7 +2899,7 @@ static Bytecode::CodeGenerationErrorOr for_in_of_he // 5. Let exprValue be ? GetValue(exprRef). // NOTE: No need to store this anywhere. - auto iterator = Bytecode::Operand(generator.allocate_register()); + auto iterator = generator.allocate_register(); // 6. If iterationKind is enumerate, then if (iteration_kind == IterationKind::Enumerate) { @@ -2929,7 +2939,7 @@ static Bytecode::CodeGenerationErrorOr 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> for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant, NonnullRefPtr> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update, IteratorHint iterator_kind = IteratorHint::Sync, [[maybe_unused]] Optional preferred_dst = {}) +static Bytecode::CodeGenerationErrorOr> for_in_of_body_evaluation(Bytecode::Generator& generator, ASTNode const& node, Variant, NonnullRefPtr> const& lhs, ASTNode const& body, ForInOfHeadEvaluationResult const& head_result, Vector const& label_set, Bytecode::BasicBlock& loop_end, Bytecode::BasicBlock& loop_update, IteratorHint iterator_kind = IteratorHint::Sync, [[maybe_unused]] Optional preferred_dst = {}) { // 1. If iteratorKind is not present, set iteratorKind to sync. @@ -2937,7 +2947,7 @@ static Bytecode::CodeGenerationErrorOr> for_in_of_bo bool has_lexical_binding = false; // 3. Let V be undefined. - auto completion_value = Bytecode::Operand(generator.allocate_register()); + auto completion_value = generator.allocate_register(); generator.emit(completion_value, generator.add_constant(js_undefined())); // 4. Let destructuring be IsDestructuring of lhs. @@ -2959,19 +2969,19 @@ static Bytecode::CodeGenerationErrorOr> for_in_of_bo generator.begin_continuable_scope(Bytecode::Label { loop_update }, label_set); // a. Let nextResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). - auto next_result = Bytecode::Operand(generator.allocate_register()); + auto next_result = generator.allocate_register(); generator.emit(next_result, *head_result.iterator); // b. If iteratorKind is async, set nextResult to ? Await(nextResult). if (iterator_kind == IteratorHint::Async) { - auto received_completion = Bytecode::Operand(generator.allocate_register()); - auto received_completion_type = Bytecode::Operand(generator.allocate_register()); - auto received_completion_value = Bytecode::Operand(generator.allocate_register()); + auto received_completion = generator.allocate_register(); + auto received_completion_type = generator.allocate_register(); + auto received_completion_value = generator.allocate_register(); auto type_identifier = generator.intern_identifier("type"); auto value_identifier = generator.intern_identifier("value"); - generator.emit(received_completion, Bytecode::Operand(Bytecode::Register(0))); + generator.emit(received_completion, generator.accumulator()); auto new_result = generate_await(generator, next_result, received_completion, received_completion_type, received_completion_value, type_identifier, value_identifier); generator.emit(next_result, new_result); } @@ -2980,7 +2990,7 @@ static Bytecode::CodeGenerationErrorOr> for_in_of_bo generator.emit(next_result); // d. Let done be ? IteratorComplete(nextResult). - auto done = Bytecode::Operand(generator.allocate_register()); + auto done = generator.allocate_register(); generator.emit_iterator_complete(done, next_result); // e. If done is true, return V. @@ -2992,7 +3002,7 @@ static Bytecode::CodeGenerationErrorOr> for_in_of_bo generator.switch_to_basic_block(loop_continue); // f. Let nextValue be ? IteratorValue(nextResult). - auto next_value = Bytecode::Operand(generator.allocate_register()); + auto next_value = generator.allocate_register(); generator.emit_iterator_value(next_value, next_result); // g. If lhsKind is either assignment or varBinding, then @@ -3151,14 +3161,14 @@ static Bytecode::CodeGenerationErrorOr> for_in_of_bo return completion_value; } -Bytecode::CodeGenerationErrorOr> ForInStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForInStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } // 14.7.5.5 Runtime Semantics: ForInOfLoopEvaluation, https://tc39.es/ecma262/#sec-runtime-semantics-forinofloopevaluation -Bytecode::CodeGenerationErrorOr> ForInStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForInStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { auto& loop_end = generator.make_block(); auto& loop_update = generator.make_block(); @@ -3168,13 +3178,13 @@ Bytecode::CodeGenerationErrorOr> ForInStatement::gen return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, label_set, loop_end, loop_update); } -Bytecode::CodeGenerationErrorOr> ForOfStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForOfStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } -Bytecode::CodeGenerationErrorOr> ForOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { auto& loop_end = generator.make_block(); auto& loop_update = generator.make_block(); @@ -3184,13 +3194,13 @@ Bytecode::CodeGenerationErrorOr> ForOfStatement::gen return for_in_of_body_evaluation(generator, *this, m_lhs, body(), head_result, label_set, loop_end, loop_update); } -Bytecode::CodeGenerationErrorOr> ForAwaitOfStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForAwaitOfStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); return generate_labelled_evaluation(generator, {}); } -Bytecode::CodeGenerationErrorOr> ForAwaitOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ForAwaitOfStatement::generate_labelled_evaluation(Bytecode::Generator& generator, Vector const& label_set, [[maybe_unused]] Optional preferred_dst) const { auto& loop_end = generator.make_block(); auto& loop_update = generator.make_block(); @@ -3201,7 +3211,7 @@ Bytecode::CodeGenerationErrorOr> ForAwaitOfStatement } // 13.3.12.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-meta-properties-runtime-semantics-evaluation -Bytecode::CodeGenerationErrorOr> MetaProperty::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> MetaProperty::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); // NewTarget : new . target @@ -3222,18 +3232,18 @@ Bytecode::CodeGenerationErrorOr> MetaProperty::gener VERIFY_NOT_REACHED(); } -Bytecode::CodeGenerationErrorOr> ClassFieldInitializerStatement::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ClassFieldInitializerStatement::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto value = TRY(generator.emit_named_evaluation_if_anonymous_function(*m_expression, generator.intern_identifier(m_class_field_identifier_name), preferred_dst)); generator.perform_needed_unwinds(); - generator.emit(value); + generator.emit(value.has_value() ? value->operand() : Optional {}); return value; } -static Bytecode::CodeGenerationErrorOr generate_optional_chain(Bytecode::Generator& generator, OptionalChain const& optional_chain, Bytecode::Operand current_value, Bytecode::Operand current_base, [[maybe_unused]] Optional preferred_dst) +static Bytecode::CodeGenerationErrorOr generate_optional_chain(Bytecode::Generator& generator, OptionalChain const& optional_chain, ScopedOperand current_value, ScopedOperand current_base, [[maybe_unused]] Optional preferred_dst) { - Optional new_current_value; + Optional new_current_value; if (is(optional_chain.base())) { auto& member_expression = static_cast(optional_chain.base()); auto base_and_value = TRY(get_base_and_value_from_member_expression(generator, member_expression)); @@ -3299,22 +3309,22 @@ static Bytecode::CodeGenerationErrorOr generate_optional_chain(Bytecode::G return {}; } -Bytecode::CodeGenerationErrorOr> OptionalChain::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> OptionalChain::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); - auto current_base = Bytecode::Operand(generator.allocate_register()); + auto current_base = generator.allocate_register(); auto current_value = choose_dst(generator, preferred_dst); generator.emit(current_base, generator.add_constant(js_undefined())); TRY(generate_optional_chain(generator, *this, current_value, current_base)); return current_value; } -Bytecode::CodeGenerationErrorOr> ImportCall::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ImportCall::generate_bytecode(Bytecode::Generator& generator, Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); auto specifier = TRY(m_specifier->generate_bytecode(generator)).value(); - Optional options; + Optional options; if (m_options) { options = TRY(m_options->generate_bytecode(generator)).value(); } else { @@ -3325,14 +3335,14 @@ Bytecode::CodeGenerationErrorOr> ImportCall::generat return dst; } -Bytecode::CodeGenerationErrorOr> ExportStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ExportStatement::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional preferred_dst) const { Bytecode::Generator::SourceLocationScope scope(generator, *this); if (!is_default_export()) { if (m_statement) { return m_statement->generate_bytecode(generator); } - return Optional {}; + return Optional {}; } VERIFY(m_statement); @@ -3366,9 +3376,9 @@ Bytecode::CodeGenerationErrorOr> ExportStatement::ge return value; } -Bytecode::CodeGenerationErrorOr> ImportStatement::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const +Bytecode::CodeGenerationErrorOr> ImportStatement::generate_bytecode(Bytecode::Generator&, [[maybe_unused]] Optional preferred_dst) const { - return Optional {}; + return Optional {}; } } diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index 5f13ab95c0c..0596da01df2 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -53,7 +53,7 @@ public: void add_source_map_entry(size_t bytecode_offset, SourceRecord const& source_record) { m_source_map.set(bytecode_offset, source_record); } auto const& this_() const { return m_this; } - void set_this(Operand operand) { m_this = operand; } + void set_this(ScopedOperand operand) { m_this = operand; } private: explicit BasicBlock(u32 index, String name); @@ -67,7 +67,7 @@ private: HashMap m_source_map; - Optional m_this; + Optional m_this; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index abe884f4759..a324ec97806 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -22,6 +22,7 @@ Generator::Generator(VM& vm) , m_identifier_table(make()) , m_regex_table(make()) , m_constants(vm.heap()) + , m_accumulator(*this, Operand(Register::accumulator())) { } @@ -208,6 +209,8 @@ CodeGenerationErrorOr> Generator::generate(VM& vm, ASTN executable->basic_block_start_offsets = move(basic_block_start_offsets); executable->source_map = move(source_map); + generator.m_finished = true; + return executable; } @@ -217,10 +220,28 @@ void Generator::grow(size_t additional_size) m_current_basic_block->grow(additional_size); } -Register Generator::allocate_register() +ScopedOperand Generator::allocate_sequential_register() { VERIFY(m_next_register != NumericLimits::max()); - return Register { m_next_register++ }; + return ScopedOperand { *this, Operand { Register { m_next_register++ } } }; +} + +ScopedOperand Generator::allocate_register() +{ + if (!m_free_registers.is_empty()) { + return ScopedOperand { *this, Operand { m_free_registers.take_last() } }; + } + return allocate_sequential_register(); +} + +void Generator::free_register(Register reg) +{ + m_free_registers.append(reg); +} + +ScopedOperand Generator::local(u32 local_index) +{ + return ScopedOperand { *this, Operand { Operand::Type::Local, static_cast(local_index) } }; } Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node) @@ -311,10 +332,10 @@ CodeGenerationErrorOr Generator::emit_super_refere // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation // 1. Let env be GetThisEnvironment(). // 2. Let actualThis be ? env.GetThisBinding(). - auto actual_this = Operand(allocate_register()); + auto actual_this = allocate_register(); emit(actual_this); - Optional computed_property_value; + Optional computed_property_value; if (expression.is_computed()) { // SuperProperty : super [ Expression ] @@ -329,7 +350,7 @@ CodeGenerationErrorOr Generator::emit_super_refere // 1. Let env be GetThisEnvironment(). // 2. Assert: env.HasSuperBinding() is true. // 3. Let baseValue be ? env.GetSuperBase(). - auto base_value = Operand(allocate_register()); + auto base_value = allocate_register(); emit(base_value); // 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }. @@ -340,7 +361,7 @@ CodeGenerationErrorOr Generator::emit_super_refere }; } -CodeGenerationErrorOr Generator::emit_load_from_reference(JS::ASTNode const& node, Optional preferred_dst) +CodeGenerationErrorOr Generator::emit_load_from_reference(JS::ASTNode const& node, Optional preferred_dst) { if (is(node)) { auto& identifier = static_cast(node); @@ -360,7 +381,7 @@ CodeGenerationErrorOr Generator::emit_load_from_re // https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation if (is(expression.object())) { auto super_reference = TRY(emit_super_reference(expression)); - auto dst = preferred_dst.has_value() ? preferred_dst.value() : Operand(allocate_register()); + auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register(); if (super_reference.referenced_name.has_value()) { // 5. Let propertyKey be ? ToPropertyKey(propertyNameValue). @@ -381,9 +402,9 @@ CodeGenerationErrorOr Generator::emit_load_from_re if (expression.is_computed()) { auto property = TRY(expression.property().generate_bytecode(*this)).value(); - auto saved_property = Operand(allocate_register()); + auto saved_property = allocate_register(); emit(saved_property, property); - auto dst = preferred_dst.has_value() ? preferred_dst.value() : Operand(allocate_register()); + auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register(); emit(dst, base, property, move(base_identifier)); return ReferenceOperands { .base = base, @@ -394,7 +415,7 @@ CodeGenerationErrorOr Generator::emit_load_from_re } if (expression.property().is_identifier()) { auto identifier_table_ref = intern_identifier(verify_cast(expression.property()).string()); - auto dst = preferred_dst.has_value() ? preferred_dst.value() : Operand(allocate_register()); + auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register(); emit_get_by_id(dst, base, identifier_table_ref, move(base_identifier)); return ReferenceOperands { .base = base, @@ -405,7 +426,7 @@ CodeGenerationErrorOr Generator::emit_load_from_re } if (expression.property().is_private_identifier()) { auto identifier_table_ref = intern_identifier(verify_cast(expression.property()).string()); - auto dst = preferred_dst.has_value() ? preferred_dst.value() : Operand(allocate_register()); + auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register(); emit(dst, base, identifier_table_ref); return ReferenceOperands { .base = base, @@ -420,7 +441,7 @@ CodeGenerationErrorOr Generator::emit_load_from_re }; } -CodeGenerationErrorOr Generator::emit_store_to_reference(JS::ASTNode const& node, Operand value) +CodeGenerationErrorOr Generator::emit_store_to_reference(JS::ASTNode const& node, ScopedOperand value) { if (is(node)) { auto& identifier = static_cast(node); @@ -473,7 +494,7 @@ CodeGenerationErrorOr Generator::emit_store_to_reference(JS::ASTNode const }; } -CodeGenerationErrorOr Generator::emit_store_to_reference(ReferenceOperands const& reference, Operand value) +CodeGenerationErrorOr Generator::emit_store_to_reference(ReferenceOperands const& reference, ScopedOperand value) { if (reference.referenced_private_identifier.has_value()) { emit(*reference.base, *reference.referenced_private_identifier, value); @@ -493,14 +514,14 @@ CodeGenerationErrorOr Generator::emit_store_to_reference(ReferenceOperands return {}; } -CodeGenerationErrorOr> Generator::emit_delete_reference(JS::ASTNode const& node) +CodeGenerationErrorOr> Generator::emit_delete_reference(JS::ASTNode const& node) { if (is(node)) { auto& identifier = static_cast(node); if (identifier.is_local()) { return add_constant(Value(false)); } - auto dst = Operand(allocate_register()); + auto dst = allocate_register(); emit(dst, intern_identifier(identifier.string())); return dst; } @@ -520,11 +541,11 @@ CodeGenerationErrorOr> Generator::emit_delete_reference(JS::AS emit(dst, *super_reference.base, *super_reference.this_value, identifier_table_ref); } - return Optional {}; + return Optional {}; } auto object = TRY(expression.object().generate_bytecode(*this)).value(); - auto dst = Operand(allocate_register()); + auto dst = allocate_register(); if (expression.is_computed()) { auto property = TRY(expression.property().generate_bytecode(*this)).value(); @@ -555,10 +576,10 @@ CodeGenerationErrorOr> Generator::emit_delete_reference(JS::AS return add_constant(Value(true)); } -void Generator::emit_set_variable(JS::Identifier const& identifier, Operand value, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Op::EnvironmentMode mode) +void Generator::emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::SetVariable::InitializationMode initialization_mode, Bytecode::Op::EnvironmentMode mode) { if (identifier.is_local()) { - if (value.is_local() && value.index() == identifier.local_variable_index()) { + if (value.operand().is_local() && value.operand().index() == identifier.local_variable_index()) { // Moving a local to itself is a no-op. return; } @@ -730,7 +751,7 @@ void Generator::generate_continue(DeprecatedFlyString const& continue_label) generate_labelled_jump(JumpType::Continue, continue_label); } -void Generator::push_home_object(Operand object) +void Generator::push_home_object(ScopedOperand object) { m_home_objects.append(object); } @@ -740,7 +761,7 @@ void Generator::pop_home_object() m_home_objects.take_last(); } -void Generator::emit_new_function(Operand dst, FunctionExpression const& function_node, Optional lhs_name) +void Generator::emit_new_function(ScopedOperand dst, FunctionExpression const& function_node, Optional lhs_name) { if (m_home_objects.is_empty()) { emit(dst, function_node, lhs_name); @@ -749,7 +770,7 @@ void Generator::emit_new_function(Operand dst, FunctionExpression const& functio } } -CodeGenerationErrorOr> Generator::emit_named_evaluation_if_anonymous_function(Expression const& expression, Optional lhs_name, Optional preferred_dst) +CodeGenerationErrorOr> Generator::emit_named_evaluation_if_anonymous_function(Expression const& expression, Optional lhs_name, Optional preferred_dst) { if (is(expression)) { auto const& function_expression = static_cast(expression); @@ -768,22 +789,22 @@ CodeGenerationErrorOr> Generator::emit_named_evaluation_if_ano return expression.generate_bytecode(*this, preferred_dst); } -void Generator::emit_get_by_id(Operand dst, Operand base, IdentifierTableIndex property_identifier, Optional base_identifier) +void Generator::emit_get_by_id(ScopedOperand dst, ScopedOperand base, IdentifierTableIndex property_identifier, Optional base_identifier) { emit(dst, base, property_identifier, move(base_identifier), m_next_property_lookup_cache++); } -void Generator::emit_get_by_id_with_this(Operand dst, Operand base, IdentifierTableIndex id, Operand this_value) +void Generator::emit_get_by_id_with_this(ScopedOperand dst, ScopedOperand base, IdentifierTableIndex id, ScopedOperand this_value) { emit(dst, base, id, this_value, m_next_property_lookup_cache++); } -void Generator::emit_iterator_value(Operand dst, Operand result) +void Generator::emit_iterator_value(ScopedOperand dst, ScopedOperand result) { emit_get_by_id(dst, result, intern_identifier("value"sv)); } -void Generator::emit_iterator_complete(Operand dst, Operand result) +void Generator::emit_iterator_complete(ScopedOperand dst, ScopedOperand result) { emit_get_by_id(dst, result, intern_identifier("done"sv)); } @@ -798,7 +819,7 @@ void Generator::set_local_initialized(u32 local_index) m_initialized_locals.set(local_index); } -Operand Generator::get_this(Optional preferred_dst) +ScopedOperand Generator::get_this(Optional preferred_dst) { if (m_current_basic_block->this_().has_value()) return m_current_basic_block->this_().value(); @@ -806,10 +827,15 @@ Operand Generator::get_this(Optional preferred_dst) m_current_basic_block->set_this(m_root_basic_blocks[0]->this_().value()); return m_root_basic_blocks[0]->this_().value(); } - auto dst = preferred_dst.has_value() ? preferred_dst.value() : Operand(allocate_register()); + auto dst = preferred_dst.has_value() ? preferred_dst.value() : allocate_register(); emit(dst); m_current_basic_block->set_this(dst); return dst; } +ScopedOperand Generator::accumulator() +{ + return m_accumulator; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 28eefc1c026..7da2e117f82 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -34,7 +34,13 @@ public: }; static CodeGenerationErrorOr> generate(VM&, ASTNode const&, ReadonlySpan parameters, FunctionKind = FunctionKind::Normal); - Register allocate_register(); + [[nodiscard]] ScopedOperand allocate_sequential_register(); + + [[nodiscard]] ScopedOperand allocate_register(); + [[nodiscard]] ScopedOperand local(u32 local_index); + [[nodiscard]] ScopedOperand accumulator(); + + void free_register(Register); void set_local_initialized(u32 local_index); [[nodiscard]] bool is_local_initialized(u32 local_index) const; @@ -112,28 +118,28 @@ public: } struct ReferenceOperands { - Optional base {}; // [[Base]] - Optional referenced_name {}; // [[ReferencedName]] as an operand + Optional base {}; // [[Base]] + Optional referenced_name {}; // [[ReferencedName]] as an operand Optional referenced_identifier {}; // [[ReferencedName]] as an identifier Optional referenced_private_identifier {}; // [[ReferencedName]] as a private identifier - Optional this_value {}; // [[ThisValue]] - Optional loaded_value {}; // Loaded value, if we've performed a load. + Optional this_value {}; // [[ThisValue]] + Optional loaded_value {}; // Loaded value, if we've performed a load. }; - CodeGenerationErrorOr emit_load_from_reference(JS::ASTNode const&, Optional preferred_dst = {}); - CodeGenerationErrorOr emit_store_to_reference(JS::ASTNode const&, Operand value); - CodeGenerationErrorOr emit_store_to_reference(ReferenceOperands const&, Operand value); - CodeGenerationErrorOr> emit_delete_reference(JS::ASTNode const&); + CodeGenerationErrorOr emit_load_from_reference(JS::ASTNode const&, Optional preferred_dst = {}); + CodeGenerationErrorOr emit_store_to_reference(JS::ASTNode const&, ScopedOperand value); + CodeGenerationErrorOr emit_store_to_reference(ReferenceOperands const&, ScopedOperand value); + CodeGenerationErrorOr> emit_delete_reference(JS::ASTNode const&); CodeGenerationErrorOr emit_super_reference(MemberExpression const&); - void emit_set_variable(JS::Identifier const& identifier, Operand value, Bytecode::Op::SetVariable::InitializationMode initialization_mode = Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode mode = Bytecode::Op::EnvironmentMode::Lexical); + void emit_set_variable(JS::Identifier const& identifier, ScopedOperand value, Bytecode::Op::SetVariable::InitializationMode initialization_mode = Bytecode::Op::SetVariable::InitializationMode::Set, Bytecode::Op::EnvironmentMode mode = Bytecode::Op::EnvironmentMode::Lexical); - void push_home_object(Operand); + void push_home_object(ScopedOperand); void pop_home_object(); - void emit_new_function(Operand dst, JS::FunctionExpression const&, Optional lhs_name); + void emit_new_function(ScopedOperand dst, JS::FunctionExpression const&, Optional lhs_name); - CodeGenerationErrorOr> emit_named_evaluation_if_anonymous_function(Expression const&, Optional lhs_name, Optional preferred_dst = {}); + CodeGenerationErrorOr> emit_named_evaluation_if_anonymous_function(Expression const&, Optional lhs_name, Optional preferred_dst = {}); void begin_continuable_scope(Label continue_target, Vector const& language_label_set); void end_continuable_scope(); @@ -257,14 +263,14 @@ public: m_boundaries.take_last(); } - [[nodiscard]] Operand get_this(Optional preferred_dst = {}); + [[nodiscard]] ScopedOperand get_this(Optional preferred_dst = {}); - void emit_get_by_id(Operand dst, Operand base, IdentifierTableIndex property_identifier, Optional base_identifier = {}); + void emit_get_by_id(ScopedOperand dst, ScopedOperand base, IdentifierTableIndex property_identifier, Optional base_identifier = {}); - void emit_get_by_id_with_this(Operand dst, Operand base, IdentifierTableIndex, Operand this_value); + void emit_get_by_id_with_this(ScopedOperand dst, ScopedOperand base, IdentifierTableIndex, ScopedOperand this_value); - void emit_iterator_value(Operand dst, Operand result); - void emit_iterator_complete(Operand dst, Operand result); + void emit_iterator_value(ScopedOperand dst, ScopedOperand result); + void emit_iterator_complete(ScopedOperand dst, ScopedOperand result); [[nodiscard]] size_t next_global_variable_cache() { return m_next_global_variable_cache++; } [[nodiscard]] size_t next_environment_variable_cache() { return m_next_environment_variable_cache++; } @@ -274,20 +280,22 @@ public: Yes, No, }; - [[nodiscard]] Operand add_constant(Value value, DeduplicateConstant deduplicate_constant = DeduplicateConstant::Yes) + [[nodiscard]] ScopedOperand add_constant(Value value, DeduplicateConstant deduplicate_constant = DeduplicateConstant::Yes) { if (deduplicate_constant == DeduplicateConstant::Yes) { for (size_t i = 0; i < m_constants.size(); ++i) { if (m_constants[i] == value) - return Operand(Operand::Type::Constant, i); + return ScopedOperand(*this, Operand(Operand::Type::Constant, i)); } } m_constants.append(value); - return Operand(Operand::Type::Constant, m_constants.size() - 1); + return ScopedOperand(*this, Operand(Operand::Type::Constant, m_constants.size() - 1)); } UnwindContext const* current_unwind_context() const { return m_current_unwind_context; } + [[nodiscard]] bool is_finished() const { return m_finished; } + private: VM& m_vm; @@ -318,6 +326,9 @@ private: NonnullOwnPtr m_regex_table; MarkedVector m_constants; + ScopedOperand m_accumulator; + Vector m_free_registers; + u32 m_next_register { Register::reserved_register_count }; u32 m_next_block { 1 }; u32 m_next_property_lookup_cache { 0 }; @@ -327,9 +338,11 @@ private: Vector m_continuable_scopes; Vector m_breakable_scopes; Vector m_boundaries; - Vector m_home_objects; + Vector m_home_objects; HashTable m_initialized_locals; + + bool m_finished { false }; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 42935f14649..671983d5545 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -211,7 +212,7 @@ class CopyObjectExcludingProperties final : public Instruction { public: static constexpr bool IsVariableLength = true; - CopyObjectExcludingProperties(Operand dst, Operand from_object, Vector const& excluded_names) + CopyObjectExcludingProperties(Operand dst, Operand from_object, Vector const& excluded_names) : Instruction(Type::CopyObjectExcludingProperties) , m_dst(dst) , m_from_object(from_object) @@ -1238,7 +1239,7 @@ class Call final : public Instruction { public: static constexpr bool IsVariableLength = true; - Call(CallType type, Operand dst, Operand callee, Operand this_value, ReadonlySpan arguments, Optional expression_string = {}, Optional builtin = {}) + Call(CallType type, Operand dst, Operand callee, Operand this_value, ReadonlySpan arguments, Optional expression_string = {}, Optional builtin = {}) : Instruction(Type::Call) , m_dst(dst) , m_callee(callee) diff --git a/Userland/Libraries/LibJS/Bytecode/Operand.h b/Userland/Libraries/LibJS/Bytecode/Operand.h index 560111af25d..89482af46c5 100644 --- a/Userland/Libraries/LibJS/Bytecode/Operand.h +++ b/Userland/Libraries/LibJS/Bytecode/Operand.h @@ -36,6 +36,8 @@ public: [[nodiscard]] Type type() const { return m_type; } [[nodiscard]] u32 index() const { return m_index; } + [[nodiscard]] Register as_register() const; + private: Type m_type {}; u32 m_index { 0 }; diff --git a/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp new file mode 100644 index 00000000000..50aa61d3368 --- /dev/null +++ b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace JS::Bytecode { + +ScopedOperandImpl::~ScopedOperandImpl() +{ + if (!m_generator.is_finished() && m_operand.is_register() && m_operand.as_register().index() != 0) + m_generator.free_register(m_operand.as_register()); +} + +Register Operand::as_register() const +{ + return Register { m_index }; +} + +} diff --git a/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h new file mode 100644 index 00000000000..a2f42a42a43 --- /dev/null +++ b/Userland/Libraries/LibJS/Bytecode/ScopedOperand.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace JS::Bytecode { + +class ScopedOperandImpl : public RefCounted { +public: + ScopedOperandImpl(Generator& generator, Operand operand) + : m_generator(generator) + , m_operand(operand) + { + } + + ~ScopedOperandImpl(); + + [[nodiscard]] Operand operand() const { return m_operand; } + +private: + Generator& m_generator; + Operand m_operand; +}; + +class ScopedOperand { +public: + explicit ScopedOperand(Generator& generator, Operand operand) + : m_impl(adopt_ref(*new ScopedOperandImpl(generator, operand))) + { + } + + [[nodiscard]] Operand operand() const { return m_impl->operand(); } + operator Operand() const { return operand(); } + + [[nodiscard]] bool operator==(ScopedOperand const& other) const { return operand() == other.operand(); } + +private: + NonnullRefPtr m_impl; +}; + +} diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index c60ac43685f..adff8fbe896 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES Bytecode/Interpreter.cpp Bytecode/Label.cpp Bytecode/RegexTable.cpp + Bytecode/ScopedOperand.cpp Bytecode/StringTable.cpp Console.cpp Contrib/Test262/262Object.cpp