1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 23:17:45 +00:00

LibJS: Instantiate primitive array expressions using a single operation

This will not meaningfully affect short array literals, but it does
give us a bit of extra perf when evaluating huge array expressions like
in Kraken/imaging-darkroom.js
This commit is contained in:
Idan Horowitz 2023-11-17 22:07:23 +02:00 committed by Andreas Kling
parent 5e3a799e97
commit f19349e1b6
7 changed files with 92 additions and 6 deletions

View file

@ -1012,6 +1012,19 @@ Bytecode::CodeGenerationErrorOr<void> ArrayExpression::generate_bytecode(Bytecod
return {};
}
if (all_of(m_elements, [](auto element) { return !element || is<PrimitiveLiteral>(*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<Value>::create(m_elements.size()));
for (auto i = 0u; i < m_elements.size(); ++i) {
if (!m_elements[i])
continue;
values[i] = static_cast<PrimitiveLiteral const&>(*m_elements[i]).value();
}
generator.emit<Bytecode::Op::NewPrimitiveArray>(move(values));
return {};
}
auto first_spread = find_if(m_elements.begin(), m_elements.end(), [](auto el) { return el && is<SpreadExpression>(*el); });
Bytecode::Register args_start_reg { 0 };

View file

@ -86,6 +86,7 @@
O(NewClass) \
O(NewFunction) \
O(NewObject) \
O(NewPrimitiveArray) \
O(NewRegExp) \
O(NewString) \
O(NewTypeError) \

View file

@ -605,6 +605,15 @@ ThrowCompletionOr<void> NewArray::execute_impl(Bytecode::Interpreter& interprete
return {};
}
ThrowCompletionOr<void> 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<void> 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)

View file

@ -8,6 +8,7 @@
#pragma once
#include <AK/FixedArray.h>
#include <AK/StdLibExtras.h>
#include <LibCrypto/BigInt/SignedBigInteger.h>
#include <LibJS/Bytecode/Builtins.h>
@ -313,6 +314,23 @@ private:
Register m_elements[];
};
class NewPrimitiveArray final : public Instruction {
public:
explicit NewPrimitiveArray(FixedArray<Value> values)
: Instruction(Type::NewPrimitiveArray, sizeof(*this))
, m_values(move(values))
{
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const;
ReadonlySpan<Value> values() const { return m_values.span(); }
private:
FixedArray<Value> m_values;
};
class Append final : public Instruction {
public:
Append(Register lhs, bool is_spread)