Jelajahi Sumber

LibJS: Generate bytecode for array expressions

Gunnar Beutner 4 tahun lalu
induk
melakukan
a1e5711a27

+ 1 - 0
Userland/Libraries/LibJS/AST.h

@@ -1070,6 +1070,7 @@ public:
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) const override;
+    virtual void generate_bytecode(Bytecode::Generator&) const override;
 
 private:
     Vector<RefPtr<Expression>> m_elements;

+ 20 - 0
Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp

@@ -342,6 +342,26 @@ void ObjectExpression::generate_bytecode(Bytecode::Generator& generator) const
         TODO();
 }
 
+void ArrayExpression::generate_bytecode(Bytecode::Generator& generator) const
+{
+    Vector<Bytecode::Register> element_regs;
+    for (auto& element : m_elements) {
+        generator.emit<Bytecode::Op::LoadImmediate>(Value {});
+        if (element) {
+            element->generate_bytecode(generator);
+
+            if (is<SpreadExpression>(*element)) {
+                TODO();
+                continue;
+            }
+        }
+        auto element_reg = generator.allocate_register();
+        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);
+}
+
 void MemberExpression::generate_bytecode(Bytecode::Generator& generator) const
 {
     object().generate_bytecode(generator);

+ 2 - 0
Userland/Libraries/LibJS/Bytecode/Instruction.cpp

@@ -29,6 +29,8 @@ size_t Instruction::length() const
 {
     if (type() == Type::Call)
         return static_cast<Op::Call const&>(*this).length();
+    else if (type() == Type::NewArray)
+        return static_cast<Op::NewArray const&>(*this).length();
 
 #define __BYTECODE_OP(op) \
     case Type::op:        \

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

@@ -28,6 +28,7 @@
     O(TypedInequals)              \
     O(TypedEquals)                \
     O(NewBigInt)                  \
+    O(NewArray)                   \
     O(NewString)                  \
     O(NewObject)                  \
     O(GetVariable)                \

+ 26 - 0
Userland/Libraries/LibJS/Bytecode/Op.cpp

@@ -8,6 +8,7 @@
 #include <LibJS/AST.h>
 #include <LibJS/Bytecode/Interpreter.h>
 #include <LibJS/Bytecode/Op.h>
+#include <LibJS/Runtime/Array.h>
 #include <LibJS/Runtime/BigInt.h>
 #include <LibJS/Runtime/GlobalObject.h>
 #include <LibJS/Runtime/ScriptFunction.h>
@@ -125,6 +126,15 @@ void NewBigInt::execute(Bytecode::Interpreter& interpreter) const
     interpreter.accumulator() = js_bigint(interpreter.vm().heap(), m_bigint);
 }
 
+void NewArray::execute(Bytecode::Interpreter& interpreter) const
+{
+    Vector<Value> elements;
+    elements.ensure_capacity(m_element_count);
+    for (size_t i = 0; i < m_element_count; i++)
+        elements.append(interpreter.reg(m_elements[i]));
+    interpreter.accumulator() = Array::create_from(interpreter.global_object(), elements);
+}
+
 void NewString::execute(Bytecode::Interpreter& interpreter) const
 {
     interpreter.accumulator() = js_string(interpreter.vm(), m_string);
@@ -258,6 +268,22 @@ String NewBigInt::to_string() const
     return String::formatted("NewBigInt bigint:\"{}\"", m_bigint.to_base10());
 }
 
+String NewArray::to_string() const
+{
+    StringBuilder builder;
+    builder.append("NewArray");
+    if (m_element_count != 0) {
+        builder.append(", elements:[");
+        for (size_t i = 0; i < m_element_count; ++i) {
+            builder.appendff("{}", m_elements[i]);
+            if (i != m_element_count - 1)
+                builder.append(',');
+        }
+        builder.append(']');
+    }
+    return builder.to_string();
+}
+
 String NewString::to_string() const
 {
     return String::formatted("NewString string:\"{}\"", m_string);

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

@@ -168,6 +168,27 @@ private:
     Crypto::SignedBigInteger m_bigint;
 };
 
+// NOTE: This instruction is variable-width depending on the number of elements!
+class NewArray final : public Instruction {
+public:
+    NewArray(Vector<Register> const& elements)
+        : Instruction(Type::NewArray)
+        , m_element_count(elements.size())
+    {
+        for (size_t i = 0; i < m_element_count; ++i)
+            m_elements[i] = elements[i];
+    }
+
+    void execute(Bytecode::Interpreter&) const;
+    String to_string() const;
+
+    size_t length() const { return sizeof(*this) + sizeof(Register) * m_element_count; }
+
+private:
+    size_t m_element_count { 0 };
+    Register m_elements[];
+};
+
 class ConcatString final : public Instruction {
 public:
     ConcatString(Register lhs)