diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index f3d096b21f..076427e7be 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -1133,10 +1133,21 @@ private: Vector> m_expressions; }; -class BooleanLiteral final : public Expression { +class PrimitiveLiteral : public Expression { +public: + virtual Value value() const = 0; + +protected: + explicit PrimitiveLiteral(SourceRange source_range) + : Expression(move(source_range)) + { + } +}; + +class BooleanLiteral final : public PrimitiveLiteral { public: explicit BooleanLiteral(SourceRange source_range, bool value) - : Expression(move(source_range)) + : PrimitiveLiteral(move(source_range)) , m_value(value) { } @@ -1144,14 +1155,16 @@ public: virtual void dump(int indent) const override; virtual Bytecode::CodeGenerationErrorOr generate_bytecode(Bytecode::Generator&) const override; + virtual Value value() const override { return Value(m_value); } + private: bool m_value { false }; }; -class NumericLiteral final : public Expression { +class NumericLiteral final : public PrimitiveLiteral { public: explicit NumericLiteral(SourceRange source_range, double value) - : Expression(move(source_range)) + : PrimitiveLiteral(move(source_range)) , m_value(value) { } @@ -1159,6 +1172,8 @@ public: virtual void dump(int indent) const override; virtual Bytecode::CodeGenerationErrorOr generate_bytecode(Bytecode::Generator&) const override; + virtual Value value() const override { return m_value; } + private: Value m_value; }; @@ -1197,15 +1212,17 @@ private: DeprecatedString m_value; }; -class NullLiteral final : public Expression { +class NullLiteral final : public PrimitiveLiteral { public: explicit NullLiteral(SourceRange source_range) - : Expression(move(source_range)) + : PrimitiveLiteral(move(source_range)) { } virtual void dump(int indent) const override; virtual Bytecode::CodeGenerationErrorOr generate_bytecode(Bytecode::Generator&) const override; + + virtual Value value() const override { return js_null(); } }; class RegExpLiteral final : public Expression { diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 40ece11b4a..9c8fc3303b 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -1012,6 +1012,19 @@ Bytecode::CodeGenerationErrorOr ArrayExpression::generate_bytecode(Bytecod return {}; } + if (all_of(m_elements, [](auto element) { return !element || is(*element); })) { + // If all elements are constant primitives, we can just emit a single instruction to initialize the array, + // instead of emitting instructions to manually evaluate them one-by-one + auto values = MUST(FixedArray::create(m_elements.size())); + for (auto i = 0u; i < m_elements.size(); ++i) { + if (!m_elements[i]) + continue; + values[i] = static_cast(*m_elements[i]).value(); + } + generator.emit(move(values)); + return {}; + } + auto first_spread = find_if(m_elements.begin(), m_elements.end(), [](auto el) { return el && is(*el); }); Bytecode::Register args_start_reg { 0 }; diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 1d08b1cff7..8b8a6e8ab9 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -86,6 +86,7 @@ O(NewClass) \ O(NewFunction) \ O(NewObject) \ + O(NewPrimitiveArray) \ O(NewRegExp) \ O(NewString) \ O(NewTypeError) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index d82005d954..fae1176ef5 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -605,6 +605,15 @@ ThrowCompletionOr NewArray::execute_impl(Bytecode::Interpreter& interprete return {}; } +ThrowCompletionOr NewPrimitiveArray::execute_impl(Bytecode::Interpreter& interpreter) const +{ + auto array = MUST(Array::create(interpreter.realm(), 0)); + for (size_t i = 0; i < m_values.size(); i++) + array->indexed_properties().put(i, m_values[i], default_attributes); + interpreter.accumulator() = array; + return {}; +} + ThrowCompletionOr Append::execute_impl(Bytecode::Interpreter& interpreter) const { return append(interpreter.vm(), interpreter.reg(m_lhs), interpreter.accumulator(), m_is_spread); @@ -1306,6 +1315,11 @@ DeprecatedString NewArray::to_deprecated_string_impl(Bytecode::Executable const& return builder.to_deprecated_string(); } +DeprecatedString NewPrimitiveArray::to_deprecated_string_impl(Bytecode::Executable const&) const +{ + return DeprecatedString::formatted("NewPrimitiveArray {}"sv, m_values.span()); +} + DeprecatedString Append::to_deprecated_string_impl(Bytecode::Executable const&) const { if (m_is_spread) diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index f20e930aec..78a91d762f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -313,6 +314,23 @@ private: Register m_elements[]; }; +class NewPrimitiveArray final : public Instruction { +public: + explicit NewPrimitiveArray(FixedArray values) + : Instruction(Type::NewPrimitiveArray, sizeof(*this)) + , m_values(move(values)) + { + } + + ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; + DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; + + ReadonlySpan values() const { return m_values.span(); } + +private: + FixedArray m_values; +}; + class Append final : public Instruction { public: Append(Register lhs, bool is_spread) diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index 251f89253d..282e9f6488 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -1528,6 +1528,28 @@ void Compiler::compile_new_array(Bytecode::Op::NewArray const& op) store_accumulator(RET); } +static Value cxx_new_primitive_array(VM& vm, Value* values, size_t element_count) +{ + auto& realm = *vm.current_realm(); + auto array = MUST(Array::create(realm, 0)); + for (size_t i = 0; i < element_count; ++i) { + array->indexed_properties().put(i, values[i], default_attributes); + } + return array; +} + +void Compiler::compile_new_primitive_array(Bytecode::Op::NewPrimitiveArray const& op) +{ + m_assembler.mov( + Assembler::Operand::Register(ARG1), + Assembler::Operand::Imm(bit_cast(op.values().data()))); + m_assembler.mov( + Assembler::Operand::Register(ARG2), + Assembler::Operand::Imm(op.values().size())); + native_call((void*)cxx_new_primitive_array); + store_accumulator(RET); +} + void Compiler::compile_new_function(Bytecode::Op::NewFunction const& op) { m_assembler.mov( diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index 01b2ab08ca..352853150f 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -92,6 +92,7 @@ private: O(NewString, new_string) \ O(NewObject, new_object) \ O(NewArray, new_array) \ + O(NewPrimitiveArray, new_primitive_array) \ O(NewFunction, new_function) \ O(NewRegExp, new_regexp) \ O(NewBigInt, new_bigint) \