mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 06:17:34 +00:00
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.
This commit is contained in:
parent
5813df21c8
commit
60a555e364
4 changed files with 44 additions and 13 deletions
|
@ -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_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,
|
// 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
|
// 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) {
|
for (auto i = 0u; i < m_elements.size(); ++i) {
|
||||||
if (!m_elements[i])
|
if (!m_elements[i])
|
||||||
continue;
|
continue;
|
||||||
values[i] = static_cast<PrimitiveLiteral const&>(*m_elements[i]).value();
|
values[i] = static_cast<PrimitiveLiteral const&>(*m_elements[i]).value();
|
||||||
}
|
}
|
||||||
auto dst = choose_dst(generator, preferred_dst);
|
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;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,12 +81,12 @@ public:
|
||||||
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
|
op->set_source_record({ m_current_ast_node->start_offset(), m_current_ast_node->end_offset() });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename OpType, typename... Args>
|
template<typename OpType, typename ExtraSlotType, typename... Args>
|
||||||
void emit_with_extra_operand_slots(size_t extra_operand_slots, Args&&... args)
|
void emit_with_extra_slots(size_t extra_slot_count, Args&&... args)
|
||||||
{
|
{
|
||||||
VERIFY(!is_current_block_terminated());
|
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();
|
size_t slot_offset = m_current_basic_block->size();
|
||||||
grow(size_to_allocate);
|
grow(size_to_allocate);
|
||||||
void* slot = m_current_basic_block->data() + slot_offset;
|
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() });
|
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 {
|
struct ReferenceOperands {
|
||||||
Optional<Operand> base {}; // [[Base]]
|
Optional<Operand> base {}; // [[Base]]
|
||||||
Optional<Operand> referenced_name {}; // [[ReferencedName]] as an operand
|
Optional<Operand> referenced_name {}; // [[ReferencedName]] as an operand
|
||||||
|
|
|
@ -96,6 +96,16 @@ static ByteString format_operand_list(StringView name, ReadonlySpan<Operand> ope
|
||||||
return builder.to_byte_string();
|
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)
|
NonnullOwnPtr<CallFrame> CallFrame::create(size_t register_count)
|
||||||
{
|
{
|
||||||
size_t allocation_size = sizeof(CallFrame) + sizeof(Value) * 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
|
ThrowCompletionOr<void> NewPrimitiveArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto array = MUST(Array::create(interpreter.realm(), 0));
|
auto array = MUST(Array::create(interpreter.realm(), 0));
|
||||||
for (size_t i = 0; i < m_values.size(); i++)
|
for (size_t i = 0; i < m_element_count; i++)
|
||||||
array->indexed_properties().put(i, m_values[i], default_attributes);
|
array->indexed_properties().put(i, m_elements[i], default_attributes);
|
||||||
interpreter.set(dst(), array);
|
interpreter.set(dst(), array);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1622,7 +1632,7 @@ ByteString NewPrimitiveArray::to_byte_string_impl(Bytecode::Executable const& ex
|
||||||
{
|
{
|
||||||
return ByteString::formatted("NewPrimitiveArray {}, {}"sv,
|
return ByteString::formatted("NewPrimitiveArray {}, {}"sv,
|
||||||
format_operand("dst"sv, dst(), executable),
|
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
|
ByteString ArrayAppend::to_byte_string_impl(Bytecode::Executable const& executable) const
|
||||||
|
|
|
@ -290,22 +290,30 @@ private:
|
||||||
|
|
||||||
class NewPrimitiveArray final : public Instruction {
|
class NewPrimitiveArray final : public Instruction {
|
||||||
public:
|
public:
|
||||||
NewPrimitiveArray(Operand dst, FixedArray<Value> values)
|
NewPrimitiveArray(Operand dst, ReadonlySpan<Value> elements)
|
||||||
: Instruction(Type::NewPrimitiveArray, sizeof(*this))
|
: Instruction(Type::NewPrimitiveArray, length_impl(elements.size()))
|
||||||
, m_dst(dst)
|
, 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;
|
ThrowCompletionOr<void> execute_impl(Bytecode::Interpreter&) const;
|
||||||
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
ByteString to_byte_string_impl(Bytecode::Executable const&) const;
|
||||||
|
|
||||||
Operand dst() const { return m_dst; }
|
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:
|
private:
|
||||||
Operand m_dst;
|
Operand m_dst;
|
||||||
FixedArray<Value> m_values;
|
size_t m_element_count { 0 };
|
||||||
|
Value m_elements[];
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArrayAppend final : public Instruction {
|
class ArrayAppend final : public Instruction {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue