mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:17:42 +00:00
LibJS: Support array rest elements in the bytecode interpreter
This commit is contained in:
parent
7983324639
commit
57b9a228ab
4 changed files with 172 additions and 77 deletions
|
@ -729,11 +729,61 @@ static void generate_array_binding_pattern_bytecode(Bytecode::Generator& generat
|
|||
|
||||
auto temp_iterator_result_reg = generator.allocate_register();
|
||||
|
||||
auto assign_accumulator_to_alias = [&](auto& alias) {
|
||||
alias.visit(
|
||||
[&](Empty) {
|
||||
// This element is an elision
|
||||
},
|
||||
[&](NonnullRefPtr<Identifier> const& identifier) {
|
||||
auto interned_index = generator.intern_string(identifier->string());
|
||||
generator.emit<Bytecode::Op::SetVariable>(interned_index);
|
||||
},
|
||||
[&](NonnullRefPtr<BindingPattern> const& pattern) {
|
||||
// Store the accumulator value in a permanent register
|
||||
auto target_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(target_reg);
|
||||
generate_binding_pattern_bytecode(generator, pattern, target_reg);
|
||||
});
|
||||
};
|
||||
|
||||
for (auto& [name, alias, initializer, is_rest] : pattern.entries) {
|
||||
VERIFY(name.has<Empty>());
|
||||
|
||||
if (is_rest)
|
||||
TODO();
|
||||
if (is_rest) {
|
||||
if (first) {
|
||||
// The iterator has not been called, and is thus known to be not exhausted
|
||||
generator.emit<Bytecode::Op::Load>(iterator_reg);
|
||||
generator.emit<Bytecode::Op::IteratorToArray>();
|
||||
} else {
|
||||
auto& if_exhausted_block = generator.make_block();
|
||||
auto& if_not_exhausted_block = generator.make_block();
|
||||
auto& continuation_block = generator.make_block();
|
||||
|
||||
generator.emit<Bytecode::Op::Load>(is_iterator_exhausted_register);
|
||||
generator.emit<Bytecode::Op::JumpConditional>().set_targets(
|
||||
Bytecode::Label { if_exhausted_block },
|
||||
Bytecode::Label { if_not_exhausted_block });
|
||||
|
||||
generator.switch_to_basic_block(if_exhausted_block);
|
||||
generator.emit<Bytecode::Op::NewArray>();
|
||||
generator.emit<Bytecode::Op::Jump>().set_targets(
|
||||
Bytecode::Label { continuation_block },
|
||||
{});
|
||||
|
||||
generator.switch_to_basic_block(if_not_exhausted_block);
|
||||
generator.emit<Bytecode::Op::Load>(iterator_reg);
|
||||
generator.emit<Bytecode::Op::IteratorToArray>();
|
||||
generator.emit<Bytecode::Op::Jump>().set_targets(
|
||||
Bytecode::Label { continuation_block },
|
||||
{});
|
||||
|
||||
generator.switch_to_basic_block(continuation_block);
|
||||
}
|
||||
|
||||
assign_accumulator_to_alias(alias);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// In the first iteration of the loop, a few things are true which can save
|
||||
// us some bytecode:
|
||||
|
@ -790,20 +840,7 @@ static void generate_array_binding_pattern_bytecode(Bytecode::Generator& generat
|
|||
// pattern if necessary.
|
||||
generator.switch_to_basic_block(create_binding_block);
|
||||
|
||||
alias.visit(
|
||||
[&](Empty) {
|
||||
// This element is an elision
|
||||
},
|
||||
[&](NonnullRefPtr<Identifier> const& identifier) {
|
||||
auto interned_index = generator.intern_string(identifier->string());
|
||||
generator.emit<Bytecode::Op::SetVariable>(interned_index);
|
||||
},
|
||||
[&](NonnullRefPtr<BindingPattern> const& pattern) {
|
||||
// Store the accumulator value in a permanent register
|
||||
auto target_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Store>(target_reg);
|
||||
generate_binding_pattern_bytecode(generator, pattern, target_reg);
|
||||
});
|
||||
assign_accumulator_to_alias(alias);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
O(TypedEquals) \
|
||||
O(NewBigInt) \
|
||||
O(NewArray) \
|
||||
O(IteratorToArray) \
|
||||
O(NewString) \
|
||||
O(NewObject) \
|
||||
O(GetVariable) \
|
||||
|
|
|
@ -124,6 +124,40 @@ void NewArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
|||
interpreter.accumulator() = Array::create_from(interpreter.global_object(), elements);
|
||||
}
|
||||
|
||||
void IteratorToArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& global_object = interpreter.global_object();
|
||||
auto& vm = interpreter.vm();
|
||||
auto iterator = interpreter.accumulator().to_object(global_object);
|
||||
if (vm.exception())
|
||||
return;
|
||||
|
||||
auto array = Array::create(global_object);
|
||||
size_t index = 0;
|
||||
|
||||
while (true) {
|
||||
auto iterator_result = iterator_next(*iterator);
|
||||
if (!iterator_result)
|
||||
return;
|
||||
|
||||
auto complete = iterator_complete(global_object, *iterator_result);
|
||||
if (vm.exception())
|
||||
return;
|
||||
|
||||
if (complete) {
|
||||
interpreter.accumulator() = array;
|
||||
return;
|
||||
}
|
||||
|
||||
auto value = iterator_value(global_object, *iterator_result);
|
||||
if (vm.exception())
|
||||
return;
|
||||
|
||||
array->put(index, value);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
void NewString::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.accumulator() = js_string(interpreter.vm(), interpreter.current_executable().get_string(m_string));
|
||||
|
@ -418,6 +452,11 @@ String NewArray::to_string_impl(Bytecode::Executable const&) const
|
|||
return builder.to_string();
|
||||
}
|
||||
|
||||
String IteratorToArray::to_string_impl(const Bytecode::Executable&) const
|
||||
{
|
||||
return "IteratorToArray";
|
||||
}
|
||||
|
||||
String NewString::to_string_impl(Bytecode::Executable const& executable) const
|
||||
{
|
||||
return String::formatted("NewString {} (\"{}\")", m_string, executable.string_table->get(m_string));
|
||||
|
|
|
@ -181,6 +181,12 @@ private:
|
|||
// NOTE: This instruction is variable-width depending on the number of elements!
|
||||
class NewArray final : public Instruction {
|
||||
public:
|
||||
NewArray()
|
||||
: Instruction(Type::NewArray)
|
||||
, m_element_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit NewArray(Vector<Register> const& elements)
|
||||
: Instruction(Type::NewArray)
|
||||
, m_element_count(elements.size())
|
||||
|
@ -203,6 +209,18 @@ private:
|
|||
Register m_elements[];
|
||||
};
|
||||
|
||||
class IteratorToArray final : public Instruction {
|
||||
public:
|
||||
IteratorToArray()
|
||||
: Instruction(Type::IteratorToArray)
|
||||
{
|
||||
}
|
||||
|
||||
void execute_impl(Bytecode::Interpreter&) const;
|
||||
String to_string_impl(Bytecode::Executable const&) const;
|
||||
void replace_references_impl(BasicBlock const&, BasicBlock const&) { }
|
||||
};
|
||||
|
||||
class ConcatString final : public Instruction {
|
||||
public:
|
||||
explicit ConcatString(Register lhs)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue