浏览代码

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.
Andreas Kling 1 年之前
父节点
当前提交
46d209c55b

+ 3 - 12
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -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>>();

+ 7 - 0
Userland/Libraries/LibJS/Bytecode/Executable.cpp

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

+ 4 - 1
Userland/Libraries/LibJS/Bytecode/Executable.h

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

+ 5 - 3
Userland/Libraries/LibJS/Bytecode/Generator.cpp

@@ -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>>();

+ 6 - 2
Userland/Libraries/LibJS/Bytecode/Generator.h

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

+ 0 - 1
Userland/Libraries/LibJS/Bytecode/Instruction.h

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

+ 2 - 13
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

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

+ 0 - 20
Userland/Libraries/LibJS/Bytecode/Op.h

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