Переглянути джерело

LibJS: Use ranges instead of specifying all registers for NewArray

Listing all the registers will lead to the inability to allocate enough
space in one basic block (as there can be an arbitrary number of
registers used), instead switch to specifying the range of registers
used and save a lot of space in the process.
Ali Mohammad Pur 3 роки тому
батько
коміт
a37bee919a

+ 41 - 14
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -845,24 +845,33 @@ Bytecode::CodeGenerationErrorOr<void> ObjectExpression::generate_bytecode(Byteco
 Bytecode::CodeGenerationErrorOr<void> ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const
 {
     Vector<Bytecode::Register> element_regs;
+    for (auto& element : m_elements) {
+        if (element && is<SpreadExpression>(*element)) {
+            return Bytecode::CodeGenerationError {
+                this,
+                "Unimplemented element kind: SpreadExpression"sv,
+            };
+        }
+        element_regs.append(generator.allocate_register());
+    }
+    size_t i = 0;
     for (auto& element : m_elements) {
         if (element) {
             TRY(element->generate_bytecode(generator));
 
-            if (is<SpreadExpression>(*element)) {
-                return Bytecode::CodeGenerationError {
-                    this,
-                    "Unimplemented element kind: SpreadExpression"sv,
-                };
-            }
+            if (is<SpreadExpression>(*element))
+                VERIFY_NOT_REACHED();
         } else {
             generator.emit<Bytecode::Op::LoadImmediate>(Value {});
         }
-        auto element_reg = generator.allocate_register();
+        auto& element_reg = element_regs[i++];
         generator.emit<Bytecode::Op::Store>(element_reg);
-        element_regs.append(element_reg);
     }
-    generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(element_regs.size(), element_regs);
+    if (element_regs.is_empty()) {
+        generator.emit<Bytecode::Op::NewArray>();
+    } else {
+        generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2u, AK::Array { element_regs.first(), element_regs.last() });
+    }
     return {};
 }
 
@@ -1391,17 +1400,27 @@ Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(B
 
     Vector<Bytecode::Register> 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(generator.allocate_register());
+    }
+
+    size_t reg_index = 0;
     for (size_t i = 0; i < expressions.size(); ++i) {
         if (i % 2 != 0)
             continue;
 
         TRY(expressions[i].generate_bytecode(generator));
-        auto string_reg = generator.allocate_register();
+        auto string_reg = string_regs[reg_index++];
         generator.emit<Bytecode::Op::Store>(string_reg);
-        string_regs.append(string_reg);
     }
 
-    generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(string_regs.size(), string_regs);
+    if (string_regs.is_empty()) {
+        generator.emit<Bytecode::Op::NewArray>();
+    } else {
+        generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2u, AK::Array { string_regs.first(), string_regs.last() });
+    }
     auto strings_reg = generator.allocate_register();
     generator.emit<Bytecode::Op::Store>(strings_reg);
 
@@ -1418,14 +1437,22 @@ Bytecode::CodeGenerationErrorOr<void> TaggedTemplateLiteral::generate_bytecode(B
     }
 
     Vector<Bytecode::Register> raw_string_regs;
+    for ([[maybe_unused]] auto& raw_string : m_template_literal->raw_strings())
+        string_regs.append(generator.allocate_register());
+
+    reg_index = 0;
     for (auto& raw_string : m_template_literal->raw_strings()) {
         TRY(raw_string.generate_bytecode(generator));
-        auto raw_string_reg = generator.allocate_register();
+        auto raw_string_reg = string_regs[reg_index++];
         generator.emit<Bytecode::Op::Store>(raw_string_reg);
         raw_string_regs.append(raw_string_reg);
     }
 
-    generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(raw_string_regs.size(), raw_string_regs);
+    if (raw_string_regs.is_empty()) {
+        generator.emit<Bytecode::Op::NewArray>();
+    } else {
+        generator.emit_with_extra_register_slots<Bytecode::Op::NewArray>(2u, AK::Array { raw_string_regs.first(), raw_string_regs.last() });
+    }
     auto raw_strings_reg = generator.allocate_register();
     generator.emit<Bytecode::Op::Store>(raw_strings_reg);
 

+ 1 - 1
Userland/Libraries/LibJS/Bytecode/Op.cpp

@@ -129,7 +129,7 @@ ThrowCompletionOr<void> NewArray::execute_impl(Bytecode::Interpreter& interprete
 {
     auto* array = MUST(Array::create(interpreter.global_object(), 0));
     for (size_t i = 0; i < m_element_count; i++) {
-        auto& value = interpreter.reg(m_elements[i]);
+        auto& value = interpreter.reg(Register(m_elements[0].index() + i));
         array->indexed_properties().put(i, value, default_attributes);
     }
     interpreter.accumulator() = array;

+ 5 - 5
Userland/Libraries/LibJS/Bytecode/Op.h

@@ -232,12 +232,12 @@ public:
     {
     }
 
-    explicit NewArray(Vector<Register> const& elements)
+    explicit NewArray(AK::Array<Register, 2> const& elements_range)
         : Instruction(Type::NewArray)
-        , m_element_count(elements.size())
+        , m_element_count(elements_range[1].index() - elements_range[0].index() + 1)
     {
-        for (size_t i = 0; i < m_element_count; ++i)
-            m_elements[i] = elements[i];
+        m_elements[0] = elements_range[0];
+        m_elements[1] = elements_range[1];
     }
 
     ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
@@ -246,7 +246,7 @@ public:
 
     size_t length_impl() const
     {
-        return sizeof(*this) + sizeof(Register) * m_element_count;
+        return sizeof(*this) + sizeof(Register) * (m_element_count == 0 ? 0 : 2);
     }
 
 private: