mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-02 22:30:31 +00:00
LibJS: Optimize array destructuring assignment for builtin iterators
...by avoiding `{ value, done }` iterator result value allocation. This
change applies the same otimization 81b6a11
added for `for..in` and
`for..of`.
Makes following micro benchmark go 22% faster on my computer:
```js
function f() {
const arr = [];
for (let i = 0; i < 10_000_000; i++) {
arr.push([i]);
}
let sum = 0;
for (let [i] of arr) {
sum += i;
}
}
f();
```
This commit is contained in:
parent
295b78f7d3
commit
60bd5012fe
Notes:
github-actions[bot]
2025-05-01 13:58:54 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 60bd5012fe
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4544
4 changed files with 11 additions and 15 deletions
|
@ -1504,8 +1504,8 @@ static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_byte
|
|||
generator.switch_to_basic_block(iterator_is_not_exhausted_block);
|
||||
}
|
||||
|
||||
generator.emit<Bytecode::Op::IteratorNext>(temp_iterator_result, iterator);
|
||||
generator.emit_iterator_complete(is_iterator_exhausted, temp_iterator_result);
|
||||
auto value = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::IteratorNextUnpack>(value, is_iterator_exhausted, iterator);
|
||||
|
||||
// We still have to check for exhaustion here. If the iterator is exhausted,
|
||||
// we need to bail before trying to get the value
|
||||
|
@ -1517,10 +1517,6 @@ static Bytecode::CodeGenerationErrorOr<void> generate_array_binding_pattern_byte
|
|||
|
||||
generator.switch_to_basic_block(no_bail_block);
|
||||
|
||||
// Get the next value in the iterator
|
||||
auto value = generator.allocate_register();
|
||||
generator.emit_iterator_value(value, temp_iterator_result);
|
||||
|
||||
auto& create_binding_block = generator.make_block();
|
||||
generator.emit<Bytecode::Op::Jump>(Bytecode::Label { create_binding_block });
|
||||
|
||||
|
@ -3187,7 +3183,7 @@ static Bytecode::CodeGenerationErrorOr<Optional<ScopedOperand>> for_in_of_body_e
|
|||
auto done = generator.allocate_register();
|
||||
|
||||
if (iterator_kind == IteratorHint::Sync) {
|
||||
generator.emit<Bytecode::Op::ForOfNext>(next_value, done, *head_result.iterator);
|
||||
generator.emit<Bytecode::Op::IteratorNextUnpack>(next_value, done, *head_result.iterator);
|
||||
|
||||
auto& loop_continue = generator.make_block();
|
||||
generator.emit_jump_if(
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
O(EnterObjectEnvironment) \
|
||||
O(EnterUnwindContext) \
|
||||
O(Exp) \
|
||||
O(ForOfNext) \
|
||||
O(GetById) \
|
||||
O(GetByIdWithThis) \
|
||||
O(GetByValue) \
|
||||
|
@ -81,6 +80,7 @@
|
|||
O(InstanceOf) \
|
||||
O(IteratorClose) \
|
||||
O(IteratorNext) \
|
||||
O(IteratorNextUnpack) \
|
||||
O(IteratorToArray) \
|
||||
O(Jump) \
|
||||
O(JumpFalse) \
|
||||
|
|
|
@ -612,7 +612,6 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(Dump);
|
||||
HANDLE_INSTRUCTION(EnterObjectEnvironment);
|
||||
HANDLE_INSTRUCTION(Exp);
|
||||
HANDLE_INSTRUCTION(ForOfNext);
|
||||
HANDLE_INSTRUCTION(GetById);
|
||||
HANDLE_INSTRUCTION(GetByIdWithThis);
|
||||
HANDLE_INSTRUCTION(GetByValue);
|
||||
|
@ -642,6 +641,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
HANDLE_INSTRUCTION(InstanceOf);
|
||||
HANDLE_INSTRUCTION(IteratorClose);
|
||||
HANDLE_INSTRUCTION(IteratorNext);
|
||||
HANDLE_INSTRUCTION(IteratorNextUnpack);
|
||||
HANDLE_INSTRUCTION(IteratorToArray);
|
||||
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(LeaveFinally);
|
||||
HANDLE_INSTRUCTION_WITHOUT_EXCEPTION_CHECK(LeaveLexicalEnvironment);
|
||||
|
@ -2982,7 +2982,7 @@ ThrowCompletionOr<void> IteratorNext::execute_impl(Bytecode::Interpreter& interp
|
|||
return {};
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> ForOfNext::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
ThrowCompletionOr<void> IteratorNextUnpack::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
auto& iterator_record = static_cast<IteratorRecord&>(interpreter.get(m_iterator_record).as_cell());
|
||||
|
@ -3777,9 +3777,9 @@ ByteString IteratorNext::to_byte_string_impl(Executable const& executable) const
|
|||
format_operand("iterator_record"sv, m_iterator_record, executable));
|
||||
}
|
||||
|
||||
ByteString ForOfNext::to_byte_string_impl(Executable const& executable) const
|
||||
ByteString IteratorNextUnpack::to_byte_string_impl(Executable const& executable) const
|
||||
{
|
||||
return ByteString::formatted("ForOfNext {}, {}, {}",
|
||||
return ByteString::formatted("IteratorNextUnpack {}, {}, {}",
|
||||
format_operand("dst_value"sv, m_dst_value, executable),
|
||||
format_operand("dst_done"sv, m_dst_done, executable),
|
||||
format_operand("iterator_record"sv, m_iterator_record, executable));
|
||||
|
|
|
@ -2721,10 +2721,10 @@ private:
|
|||
Operand m_iterator_record;
|
||||
};
|
||||
|
||||
class ForOfNext final : public Instruction {
|
||||
class IteratorNextUnpack final : public Instruction {
|
||||
public:
|
||||
ForOfNext(Operand dst_value, Operand dst_done, Operand iterator_record)
|
||||
: Instruction(Type::ForOfNext)
|
||||
IteratorNextUnpack(Operand dst_value, Operand dst_done, Operand iterator_record)
|
||||
: Instruction(Type::IteratorNextUnpack)
|
||||
, m_dst_value(dst_value)
|
||||
, m_dst_done(dst_done)
|
||||
, m_iterator_record(iterator_record)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue