summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2024-03-03 12:37:28 +0100
committerAndreas Kling <kling@serenityos.org>2024-03-03 22:27:44 +0100
commit60a555e3649797084a72908ce4257890271109ad (patch)
treeceaf3e684e6412861e2a56c751703108e03423a3
parent5813df21c8f8f353a040140ed23c3ea3e798897c (diff)
LibJS/Bytecode: Make NewPrimitiveArray a variable-length instruction
Instead of having a FixedArray with a separate heap allocation, we can just bake the primitive values into the instruction itself.
-rw-r--r--Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp5
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Generator.h18
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Interpreter.cpp16
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Op.h18
4 files changed, 44 insertions, 13 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
index da4db0a361..0a2aa5c148 100644
--- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp
@@ -1024,14 +1024,15 @@ Bytecode::CodeGenerationErrorOr<Optional<Bytecode::Operand>> ArrayExpression::ge
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()));
+ Vector<Value> values;
+ values.resize(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();
}
auto dst = choose_dst(generator, preferred_dst);
- generator.emit<Bytecode::Op::NewPrimitiveArray>(dst, move(values));
+ generator.emit_with_extra_value_slots<Bytecode::Op::NewPrimitiveArray>(values.size(), dst, values);
return dst;
}
diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h
index a716134963..79d0302b29 100644
--- a/Userland/Libraries/LibJS/Bytecode/Generator.h
+++ b/Userland/Libraries/LibJS/Bytecode/Generator.h
@@ -81,12 +81,12 @@ public:
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
}
- template<typename OpType, typename... Args>
- void emit_with_extra_operand_slots(size_t extra_operand_slots, Args&&... args)
+ template<typename OpType, typename ExtraSlotType, typename... Args>
+ void emit_with_extra_slots(size_t extra_slot_count, Args&&... args)
{
VERIFY(!is_current_block_terminated());
- size_t size_to_allocate = round_up_to_power_of_two(sizeof(OpType) + extra_operand_slots * sizeof(Operand), alignof(void*));
+ size_t size_to_allocate = round_up_to_power_of_two(sizeof(OpType) + extra_slot_count * sizeof(ExtraSlotType), alignof(void*));
size_t slot_offset = m_current_basic_block->size();
grow(size_to_allocate);
void* slot = m_current_basic_block->data() + slot_offset;
@@ -97,6 +97,18 @@ public:
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
}
+ template<typename OpType, typename... Args>
+ void emit_with_extra_operand_slots(size_t extra_operand_slots, Args&&... args)
+ {
+ emit_with_extra_slots<OpType, Operand>(extra_operand_slots, forward<Args>(args)...);
+ }
+
+ template<typename OpType, typename... Args>
+ void emit_with_extra_value_slots(size_t extra_operand_slots, Args&&... args)
+ {
+ emit_with_extra_slots<OpType, Value>(extra_operand_slots, forward<Args>(args)...);
+ }
+
struct ReferenceOperands {
Optional<Operand> base {}; // [[Base]]
Optional<Operand> referenced_name {}; // [[ReferencedName]] as an operand
diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
index 6869500e99..c4fad2b5a8 100644
--- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
+++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
@@ -96,6 +96,16 @@ static ByteString format_operand_list(StringView name, ReadonlySpan<Operand> ope
return builder.to_byte_string();
}
+static ByteString format_value_list(StringView name, ReadonlySpan<Value> values)
+{
+ StringBuilder builder;
+ if (!name.is_empty())
+ builder.appendff(", \033[32m{}\033[0m:[", name);
+ builder.join(", "sv, values);
+ builder.append("]"sv);
+ return builder.to_byte_string();
+}
+
NonnullOwnPtr<CallFrame> CallFrame::create(size_t register_count)
{
size_t allocation_size = sizeof(CallFrame) + sizeof(Value) * register_count;
@@ -870,8 +880,8 @@ ThrowCompletionOr<void> NewArray::execute_impl(Bytecode::Interpreter& interprete
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);
+ for (size_t i = 0; i < m_element_count; i++)
+ array->indexed_properties().put(i, m_elements[i], default_attributes);
interpreter.set(dst(), array);
return {};
}
@@ -1622,7 +1632,7 @@ ByteString NewPrimitiveArray::to_byte_string_impl(Bytecode::Executable const& ex
{
return ByteString::formatted("NewPrimitiveArray {}, {}"sv,
format_operand("dst"sv, dst(), executable),
- m_values.span());
+ format_value_list("elements"sv, elements()));
}
ByteString ArrayAppend::to_byte_string_impl(Bytecode::Executable const& executable) const
diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h
index c8489d04f1..ceef01e776 100644
--- a/Userland/Libraries/LibJS/Bytecode/Op.h
+++ b/Userland/Libraries/LibJS/Bytecode/Op.h
@@ -290,22 +290,30 @@ private:
class NewPrimitiveArray final : public Instruction {
public:
- NewPrimitiveArray(Operand dst, FixedArray<Value> values)
- : Instruction(Type::NewPrimitiveArray, sizeof(*this))
+ NewPrimitiveArray(Operand dst, ReadonlySpan<Value> elements)
+ : Instruction(Type::NewPrimitiveArray, length_impl(elements.size()))
, m_dst(dst)
- , m_values(move(values))
+ , m_element_count(elements.size())
{
+ for (size_t i = 0; i < m_element_count; ++i)
+ m_elements[i] = elements[i];
+ }
+
+ size_t length_impl(size_t element_count) const
+ {
+ return round_up_to_power_of_two(alignof(void*), sizeof(*this) + sizeof(Value) * element_count);
}
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
Operand dst() const { return m_dst; }
- ReadonlySpan<Value> values() const { return m_values.span(); }
+ ReadonlySpan<Value> elements() const { return { m_elements, m_element_count }; }
private:
Operand m_dst;
- FixedArray<Value> m_values;
+ size_t m_element_count { 0 };
+ Value m_elements[];
};
class ArrayAppend final : public Instruction {