1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 09:24:57 +00:00

LibJS/Bytecode: Make primitive strings be constants

Instead of emitting a NewString instruction to construct a primitive
string from a parsed literal, we now instantiate the PrimitiveString on
the heap during codegen.
This commit is contained in:
Andreas Kling 2024-03-03 11:34:36 +01:00
parent fd694e8672
commit 46d209c55b
8 changed files with 27 additions and 52 deletions

View file

@ -302,9 +302,7 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> BigIntLiteral::gene
Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> StringLiteral::generate_bytecode(Bytecode::Generator& generator, [[maybe_unused]] Optional<Bytecode::Operand> preferred_dst) const
{
Bytecode::Generator::SourceLocationScope scope(generator, *this);
auto dst = choose_dst(generator, preferred_dst);
generator.emit<Bytecode::Op::NewString>(dst, generator.intern_string(m_value));
return dst;
return generator.add_constant(PrimitiveString::create(generator.vm(), m_value), Bytecode::Generator::DeduplicateConstant::No);
}
Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> RegExpLiteral::generate_bytecode(Bytecode::Generator& generator, Optional<Bytecode::Operand> preferred_dst) const
@ -1165,20 +1163,13 @@ static Bytecode::CodeGenerationErrorOr<void> generate_object_binding_pattern_byt
VERIFY_NOT_REACHED();
}
Bytecode::StringTableIndex name_index;
auto value = Bytecode::Operand(generator.allocate_register());
if (name.has<NonnullRefPtr<Identifier const>>()) {
auto identifier = name.get<NonnullRefPtr<Identifier const>>()->string();
name_index = generator.intern_string(identifier);
auto const& identifier = name.get<NonnullRefPtr<Identifier const>>()->string();
if (has_rest) {
auto excluded_name = Bytecode::Operand(generator.allocate_register());
excluded_property_names.append(excluded_name);
generator.emit<Bytecode::Op::NewString>(excluded_name, name_index);
excluded_property_names.append(generator.add_constant(PrimitiveString::create(generator.vm(), identifier), Bytecode::Generator::DeduplicateConstant::No));
}
generator.emit_get_by_id(value, object, generator.intern_identifier(identifier));
} else {
auto expression = name.get<NonnullRefPtr<Expression const>>();

View file

@ -50,4 +50,11 @@ void Executable::dump() const
warnln("");
}
void Executable::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
for (auto constant : constants)
visitor.visit(constant);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2023, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2024, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -75,6 +75,9 @@ public:
DeprecatedFlyString const& get_identifier(IdentifierTableIndex index) const { return identifier_table->get(index); }
void dump() const;
private:
virtual void visit_edges(Visitor&) override;
};
}

View file

@ -15,16 +15,18 @@
namespace JS::Bytecode {
Generator::Generator()
: m_string_table(make<StringTable>())
Generator::Generator(VM& vm)
: m_vm(vm)
, m_string_table(make<StringTable>())
, m_identifier_table(make<IdentifierTable>())
, m_regex_table(make<RegexTable>())
, m_constants(vm.heap())
{
}
CodeGenerationErrorOr<NonnullGCPtr<Executable>> Generator::generate(VM& vm, ASTNode const& node, ReadonlySpan<FunctionParameter> parameters, FunctionKind enclosing_function_kind)
{
Generator generator;
Generator generator(vm);
for (auto const& parameter : parameters) {
if (auto const* identifier = parameter.binding.get_pointer<NonnullRefPtr<Identifier const>>();

View file

@ -25,6 +25,8 @@ namespace JS::Bytecode {
class Generator {
public:
VM& vm() { return m_vm; }
enum class SurroundingScopeKind {
Global,
Function,
@ -261,6 +263,8 @@ public:
}
private:
VM& m_vm;
enum class JumpType {
Continue,
Break,
@ -268,7 +272,7 @@ private:
void generate_scoped_jump(JumpType);
void generate_labelled_jump(JumpType, DeprecatedFlyString const& label);
Generator();
explicit Generator(VM&);
~Generator() = default;
void grow(size_t);
@ -286,7 +290,7 @@ private:
NonnullOwnPtr<StringTable> m_string_table;
NonnullOwnPtr<IdentifierTable> m_identifier_table;
NonnullOwnPtr<RegexTable> m_regex_table;
Vector<Value> m_constants;
MarkedVector<Value> m_constants;
u32 m_next_register { Register::reserved_register_count };
u32 m_next_block { 1 };

View file

@ -88,7 +88,6 @@
O(NewObject) \
O(NewPrimitiveArray) \
O(NewRegExp) \
O(NewString) \
O(NewTypeError) \
O(Not) \
O(PostfixDecrement) \

View file

@ -63,6 +63,8 @@ static ByteString format_operand(StringView name, Operand operand, Bytecode::Exe
builder.appendff("Int32({})", value.as_i32());
else if (value.is_double())
builder.appendff("Double({})", value.as_double());
else if (value.is_string())
builder.appendff("String(\"{}\")", value.as_string().utf8_string_view());
else if (value.is_undefined())
builder.append("Undefined"sv);
else if (value.is_null())
@ -899,12 +901,6 @@ ThrowCompletionOr<void> IteratorToArray::execute_impl(Bytecode::Interpreter& int
return {};
}
ThrowCompletionOr<void> NewString::execute_impl(Bytecode::Interpreter& interpreter) const
{
interpreter.set(dst(), PrimitiveString::create(interpreter.vm(), interpreter.current_executable().get_string(m_string)));
return {};
}
ThrowCompletionOr<void> NewObject::execute_impl(Bytecode::Interpreter& interpreter) const
{
auto& vm = interpreter.vm();
@ -1656,13 +1652,6 @@ ByteString IteratorToArray::to_byte_string_impl(Bytecode::Executable const& exec
format_operand("iterator"sv, iterator(), executable));
}
ByteString NewString::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("NewString {}, \"{}\"",
format_operand("dst"sv, dst(), executable),
executable.string_table->get(m_string));
}
ByteString NewObject::to_byte_string_impl(Bytecode::Executable const& executable) const
{
return ByteString::formatted("NewObject {}", format_operand("dst"sv, dst(), executable));

View file

@ -136,26 +136,6 @@ JS_ENUMERATE_COMMON_BINARY_OPS_WITH_FAST_PATH(JS_DECLARE_COMMON_BINARY_OP)
JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP)
#undef JS_DECLARE_COMMON_UNARY_OP
class NewString final : public Instruction {
public:
NewString(Operand dst, StringTableIndex string)
: Instruction(Type::NewString, sizeof(*this))
, m_dst(dst)
, m_string(string)
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
Operand dst() const { return m_dst; }
StringTableIndex index() const { return m_string; }
private:
Operand m_dst;
StringTableIndex m_string;
};
class NewObject final : public Instruction {
public:
explicit NewObject(Operand dst)