LibJS/Bytecode: Reuse bytecode registers

This patch adds a register freelist to Bytecode::Generator and switches
all operands inside the generator to a new ScopedOperand type that is
ref-counted and automatically frees the register when nothing uses it.

This dramatically reduces the size of bytecode executable register
windows, which were often in the several thousands of registers for
large functions. Most functions now use less than 100 registers.
This commit is contained in:
Andreas Kling 2024-05-07 21:36:56 +02:00
parent f537d0b3cf
commit cea59b6642
10 changed files with 505 additions and 381 deletions

View file

@ -19,6 +19,7 @@
#include <LibJS/Bytecode/Executable.h>
#include <LibJS/Bytecode/IdentifierTable.h>
#include <LibJS/Bytecode/Operand.h>
#include <LibJS/Bytecode/ScopedOperand.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Handle.h>
#include <LibJS/Runtime/ClassFieldDefinition.h>
@ -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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
};
class ErrorStatement final : public Statement {
@ -236,7 +237,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
Expression const& expression() const { return m_expression; }
@ -299,7 +300,7 @@ public:
Vector<NonnullRefPtr<Statement const>> const& children() const { return m_children; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
void add_var_scoped_declaration(NonnullRefPtr<Declaration const> variables);
void add_lexical_declaration(NonnullRefPtr<Declaration const> variables);
@ -387,7 +388,7 @@ public:
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
bool has_bound_name(DeprecatedFlyString const& name) const;
Vector<ImportEntry> const& entries() const { return m_entries; }
@ -484,7 +485,7 @@ public:
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
ThrowCompletionOr<void> for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&&) const override;
@ -787,8 +788,8 @@ public:
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional<Bytecode::IdentifierTableIndex> lhs_name, Optional<Bytecode::Operand> preferred_dst = {}) const;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional<Bytecode::IdentifierTableIndex> lhs_name, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
RefPtr<Expression const> m_argument;
@ -835,7 +836,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_argument;
@ -852,7 +853,7 @@ public:
Expression const* argument() const { return m_argument; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
RefPtr<Expression const> m_argument;
@ -873,7 +874,7 @@ public:
Statement const* alternate() const { return m_alternate; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_predicate;
@ -894,8 +895,8 @@ public:
Statement const& body() const { return *m_body; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_test;
@ -915,8 +916,8 @@ public:
Statement const& body() const { return *m_body; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_test;
@ -936,7 +937,7 @@ public:
Statement const& body() const { return *m_body; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_object;
@ -960,8 +961,8 @@ public:
Statement const& body() const { return *m_body; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
RefPtr<ASTNode const> m_init;
@ -984,8 +985,8 @@ public:
Expression const& rhs() const { return *m_rhs; }
Statement const& body() const { return *m_body; }
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual void dump(int indent) const override;
private:
@ -1028,8 +1029,8 @@ public:
{
}
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
BinaryOp m_op;
@ -1099,7 +1100,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
LogicalOp m_op;
@ -1127,7 +1128,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
UnaryOp m_op;
@ -1144,7 +1145,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
Vector<NonnullRefPtr<Expression const>> m_expressions;
@ -1170,7 +1171,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
ByteString m_value;
@ -1221,7 +1222,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual bool is_super_expression() const override { return true; }
};
@ -1425,8 +1426,8 @@ public:
RefPtr<FunctionExpression const> constructor() const { return m_constructor; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional<Bytecode::IdentifierTableIndex> lhs_name, Optional<Bytecode::Operand> preferred_dst = {}) const;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode_with_lhs_name(Bytecode::Generator&, Optional<Bytecode::IdentifierTableIndex> lhs_name, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
ThrowCompletionOr<void> for_each_bound_identifier(ThrowCompletionOrVoidCallback<Identifier const&>&&) const override;
@ -1482,7 +1483,7 @@ public:
}
virtual void dump(int) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_expression;
@ -1498,7 +1499,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_target;
@ -1511,7 +1512,7 @@ public:
{
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
};
struct CallExpressionArgument {
@ -1541,7 +1542,7 @@ public:
static NonnullRefPtr<CallExpression> create(SourceRange, NonnullRefPtr<Expression const> callee, ReadonlySpan<Argument> arguments, InvocationStyleEnum invocation_style, InsideParenthesesEnum inside_parens);
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
Vector<CallExpression::Argument> const m_arguments;
@ -1654,7 +1655,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
AssignmentOp m_op;
@ -1678,7 +1679,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
Vector<NonnullRefPtr<VariableDeclarator const>> const& declarations() const { return m_declarations; }
@ -1824,7 +1825,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
virtual bool is_object_expression() const override { return true; }
@ -1843,7 +1844,7 @@ public:
Vector<RefPtr<Expression const>> const& elements() const { return m_elements; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
Vector<NonnullRefPtr<Expression const>> const& expressions() const { return m_expressions; }
Vector<NonnullRefPtr<Expression const>> const& raw_strings() const { return m_raw_strings; }
@ -1887,7 +1888,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> const m_tag;
@ -1905,7 +1906,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
Expression const& base() const { return *m_base; }
Vector<Reference> const& references() const { return m_references; }
@ -1981,7 +1982,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
Type m_type;
@ -1997,7 +1998,7 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> 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<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_test;
@ -2066,7 +2067,7 @@ public:
BlockStatement const* finalizer() const { return m_finalizer; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<BlockStatement const> m_block;
@ -2085,7 +2086,7 @@ public:
Expression const& argument() const { return m_argument; }
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
NonnullRefPtr<Expression const> m_argument;
@ -2116,8 +2117,8 @@ public:
}
virtual void dump(int indent) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::Operand> preferred_dst = {}) const;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_labelled_evaluation(Bytecode::Generator&, Vector<DeprecatedFlyString> const&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const;
void add_case(NonnullRefPtr<SwitchCase const> switch_case) { m_cases.append(move(switch_case)); }
@ -2135,7 +2136,7 @@ public:
}
Optional<DeprecatedFlyString> const& target_label() const { return m_target_label; }
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
private:
Optional<DeprecatedFlyString> m_target_label;
@ -2149,7 +2150,7 @@ public:
{
}
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
Optional<DeprecatedFlyString> const& target_label() const { return m_target_label; }
@ -2164,7 +2165,7 @@ public:
{
}
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::Operand> preferred_dst = {}) const override;
virtual Bytecode::CodeGenerationErrorOr<Optional<Bytecode::ScopedOperand>> generate_bytecode(Bytecode::Generator&, Optional<Bytecode::ScopedOperand> preferred_dst = {}) const override;
};
class SyntheticReferenceExpression final : public Expression {

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@
#include <AK/Badge.h>
#include <AK/String.h>
#include <LibJS/Bytecode/Executable.h>
#include <LibJS/Bytecode/Operand.h>
#include <LibJS/Bytecode/ScopedOperand.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Handle.h>
@ -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<size_t, SourceRecord> m_source_map;
Optional<Operand> m_this;
Optional<ScopedOperand> m_this;
};
}

View file

@ -22,6 +22,7 @@ Generator::Generator(VM& vm)
, m_identifier_table(make<IdentifierTable>())
, m_regex_table(make<RegexTable>())
, m_constants(vm.heap())
, m_accumulator(*this, Operand(Register::accumulator()))
{
}
@ -208,6 +209,8 @@ CodeGenerationErrorOr<NonnullGCPtr<Executable>> 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<u32>::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<u32>(local_index) } };
}
Generator::SourceLocationScope::SourceLocationScope(Generator& generator, ASTNode const& node)
@ -311,10 +332,10 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> 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<Bytecode::Op::ResolveThisBinding>(actual_this);
Optional<Bytecode::Operand> computed_property_value;
Optional<ScopedOperand> computed_property_value;
if (expression.is_computed()) {
// SuperProperty : super [ Expression ]
@ -329,7 +350,7 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> 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<Bytecode::Op::ResolveSuperBase>(base_value);
// 4. Return the Reference Record { [[Base]]: baseValue, [[ReferencedName]]: propertyKey, [[Strict]]: strict, [[ThisValue]]: actualThis }.
@ -340,7 +361,7 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_super_refere
};
}
CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_load_from_reference(JS::ASTNode const& node, Optional<Operand> preferred_dst)
CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_load_from_reference(JS::ASTNode const& node, Optional<ScopedOperand> preferred_dst)
{
if (is<Identifier>(node)) {
auto& identifier = static_cast<Identifier const&>(node);
@ -360,7 +381,7 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_load_from_re
// https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation
if (is<SuperExpression>(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::ReferenceOperands> 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<Bytecode::Op::Mov>(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<Bytecode::Op::GetByValue>(dst, base, property, move(base_identifier));
return ReferenceOperands {
.base = base,
@ -394,7 +415,7 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_load_from_re
}
if (expression.property().is_identifier()) {
auto identifier_table_ref = intern_identifier(verify_cast<Identifier>(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::ReferenceOperands> Generator::emit_load_from_re
}
if (expression.property().is_private_identifier()) {
auto identifier_table_ref = intern_identifier(verify_cast<PrivateIdentifier>(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<Bytecode::Op::GetPrivateById>(dst, base, identifier_table_ref);
return ReferenceOperands {
.base = base,
@ -420,7 +441,7 @@ CodeGenerationErrorOr<Generator::ReferenceOperands> Generator::emit_load_from_re
};
}
CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const& node, Operand value)
CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const& node, ScopedOperand value)
{
if (is<Identifier>(node)) {
auto& identifier = static_cast<Identifier const&>(node);
@ -473,7 +494,7 @@ CodeGenerationErrorOr<void> Generator::emit_store_to_reference(JS::ASTNode const
};
}
CodeGenerationErrorOr<void> Generator::emit_store_to_reference(ReferenceOperands const& reference, Operand value)
CodeGenerationErrorOr<void> Generator::emit_store_to_reference(ReferenceOperands const& reference, ScopedOperand value)
{
if (reference.referenced_private_identifier.has_value()) {
emit<Bytecode::Op::PutPrivateById>(*reference.base, *reference.referenced_private_identifier, value);
@ -493,14 +514,14 @@ CodeGenerationErrorOr<void> Generator::emit_store_to_reference(ReferenceOperands
return {};
}
CodeGenerationErrorOr<Optional<Operand>> Generator::emit_delete_reference(JS::ASTNode const& node)
CodeGenerationErrorOr<Optional<ScopedOperand>> Generator::emit_delete_reference(JS::ASTNode const& node)
{
if (is<Identifier>(node)) {
auto& identifier = static_cast<Identifier const&>(node);
if (identifier.is_local()) {
return add_constant(Value(false));
}
auto dst = Operand(allocate_register());
auto dst = allocate_register();
emit<Bytecode::Op::DeleteVariable>(dst, intern_identifier(identifier.string()));
return dst;
}
@ -520,11 +541,11 @@ CodeGenerationErrorOr<Optional<Operand>> Generator::emit_delete_reference(JS::AS
emit<Bytecode::Op::DeleteByIdWithThis>(dst, *super_reference.base, *super_reference.this_value, identifier_table_ref);
}
return Optional<Operand> {};
return Optional<ScopedOperand> {};
}
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<Optional<Operand>> 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<IdentifierTableIndex> lhs_name)
void Generator::emit_new_function(ScopedOperand dst, FunctionExpression const& function_node, Optional<IdentifierTableIndex> lhs_name)
{
if (m_home_objects.is_empty()) {
emit<Op::NewFunction>(dst, function_node, lhs_name);
@ -749,7 +770,7 @@ void Generator::emit_new_function(Operand dst, FunctionExpression const& functio
}
}
CodeGenerationErrorOr<Optional<Operand>> Generator::emit_named_evaluation_if_anonymous_function(Expression const& expression, Optional<IdentifierTableIndex> lhs_name, Optional<Operand> preferred_dst)
CodeGenerationErrorOr<Optional<ScopedOperand>> Generator::emit_named_evaluation_if_anonymous_function(Expression const& expression, Optional<IdentifierTableIndex> lhs_name, Optional<ScopedOperand> preferred_dst)
{
if (is<FunctionExpression>(expression)) {
auto const& function_expression = static_cast<FunctionExpression const&>(expression);
@ -768,22 +789,22 @@ CodeGenerationErrorOr<Optional<Operand>> 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<IdentifierTableIndex> base_identifier)
void Generator::emit_get_by_id(ScopedOperand dst, ScopedOperand base, IdentifierTableIndex property_identifier, Optional<IdentifierTableIndex> base_identifier)
{
emit<Op::GetById>(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<Op::GetByIdWithThis>(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<Operand> preferred_dst)
ScopedOperand Generator::get_this(Optional<ScopedOperand> 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<Operand> 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<Bytecode::Op::ResolveThisBinding>(dst);
m_current_basic_block->set_this(dst);
return dst;
}
ScopedOperand Generator::accumulator()
{
return m_accumulator;
}
}

View file

@ -34,7 +34,13 @@ public:
};
static CodeGenerationErrorOr<NonnullGCPtr<Executable>> generate(VM&, ASTNode const&, ReadonlySpan<FunctionParameter> 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<Operand> base {}; // [[Base]]
Optional<Operand> referenced_name {}; // [[ReferencedName]] as an operand
Optional<ScopedOperand> base {}; // [[Base]]
Optional<ScopedOperand> referenced_name {}; // [[ReferencedName]] as an operand
Optional<IdentifierTableIndex> referenced_identifier {}; // [[ReferencedName]] as an identifier
Optional<IdentifierTableIndex> referenced_private_identifier {}; // [[ReferencedName]] as a private identifier
Optional<Operand> this_value {}; // [[ThisValue]]
Optional<Operand> loaded_value {}; // Loaded value, if we've performed a load.
Optional<ScopedOperand> this_value {}; // [[ThisValue]]
Optional<ScopedOperand> loaded_value {}; // Loaded value, if we've performed a load.
};
CodeGenerationErrorOr<ReferenceOperands> emit_load_from_reference(JS::ASTNode const&, Optional<Operand> preferred_dst = {});
CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&, Operand value);
CodeGenerationErrorOr<void> emit_store_to_reference(ReferenceOperands const&, Operand value);
CodeGenerationErrorOr<Optional<Operand>> emit_delete_reference(JS::ASTNode const&);
CodeGenerationErrorOr<ReferenceOperands> emit_load_from_reference(JS::ASTNode const&, Optional<ScopedOperand> preferred_dst = {});
CodeGenerationErrorOr<void> emit_store_to_reference(JS::ASTNode const&, ScopedOperand value);
CodeGenerationErrorOr<void> emit_store_to_reference(ReferenceOperands const&, ScopedOperand value);
CodeGenerationErrorOr<Optional<ScopedOperand>> emit_delete_reference(JS::ASTNode const&);
CodeGenerationErrorOr<ReferenceOperands> 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<IdentifierTableIndex> lhs_name);
void emit_new_function(ScopedOperand dst, JS::FunctionExpression const&, Optional<IdentifierTableIndex> lhs_name);
CodeGenerationErrorOr<Optional<Operand>> emit_named_evaluation_if_anonymous_function(Expression const&, Optional<IdentifierTableIndex> lhs_name, Optional<Operand> preferred_dst = {});
CodeGenerationErrorOr<Optional<ScopedOperand>> emit_named_evaluation_if_anonymous_function(Expression const&, Optional<IdentifierTableIndex> lhs_name, Optional<ScopedOperand> preferred_dst = {});
void begin_continuable_scope(Label continue_target, Vector<DeprecatedFlyString> const& language_label_set);
void end_continuable_scope();
@ -257,14 +263,14 @@ public:
m_boundaries.take_last();
}
[[nodiscard]] Operand get_this(Optional<Operand> preferred_dst = {});
[[nodiscard]] ScopedOperand get_this(Optional<ScopedOperand> preferred_dst = {});
void emit_get_by_id(Operand dst, Operand base, IdentifierTableIndex property_identifier, Optional<IdentifierTableIndex> base_identifier = {});
void emit_get_by_id(ScopedOperand dst, ScopedOperand base, IdentifierTableIndex property_identifier, Optional<IdentifierTableIndex> 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<RegexTable> m_regex_table;
MarkedVector<Value> m_constants;
ScopedOperand m_accumulator;
Vector<Register> 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<LabelableScope> m_continuable_scopes;
Vector<LabelableScope> m_breakable_scopes;
Vector<BlockBoundaryType> m_boundaries;
Vector<Operand> m_home_objects;
Vector<ScopedOperand> m_home_objects;
HashTable<u32> m_initialized_locals;
bool m_finished { false };
};
}

View file

@ -18,6 +18,7 @@
#include <LibJS/Bytecode/Operand.h>
#include <LibJS/Bytecode/RegexTable.h>
#include <LibJS/Bytecode/Register.h>
#include <LibJS/Bytecode/ScopedOperand.h>
#include <LibJS/Bytecode/StringTable.h>
#include <LibJS/Heap/Cell.h>
#include <LibJS/Runtime/Environment.h>
@ -211,7 +212,7 @@ class CopyObjectExcludingProperties final : public Instruction {
public:
static constexpr bool IsVariableLength = true;
CopyObjectExcludingProperties(Operand dst, Operand from_object, Vector<Operand> const& excluded_names)
CopyObjectExcludingProperties(Operand dst, Operand from_object, Vector<ScopedOperand> 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<Operand> arguments, Optional<StringTableIndex> expression_string = {}, Optional<Builtin> builtin = {})
Call(CallType type, Operand dst, Operand callee, Operand this_value, ReadonlySpan<ScopedOperand> arguments, Optional<StringTableIndex> expression_string = {}, Optional<Builtin> builtin = {})
: Instruction(Type::Call)
, m_dst(dst)
, m_callee(callee)

View file

@ -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 };

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2024, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Bytecode/Generator.h>
#include <LibJS/Bytecode/ScopedOperand.h>
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 };
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2024, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/RefCounted.h>
#include <LibJS/Bytecode/Operand.h>
namespace JS::Bytecode {
class ScopedOperandImpl : public RefCounted<ScopedOperandImpl> {
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<ScopedOperandImpl> m_impl;
};
}

View file

@ -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