diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2021-06-13 14:06:26 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-19 09:38:26 +0200 |
commit | 57b9a228ab7780e606905fe450b3fa01ef1eec44 (patch) | |
tree | 454b108df806a3f226b0d4fb6f92f35b1c614290 /Userland | |
parent | 79833246397359cceb83350dff8848d159c9eb29 (diff) | |
download | serenity-57b9a228ab7780e606905fe450b3fa01ef1eec44.zip |
LibJS: Support array rest elements in the bytecode interpreter
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 69 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Instruction.h | 123 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.cpp | 39 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.h | 18 |
4 files changed, 172 insertions, 77 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 3a3a49980a..ca54c0a7df 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -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; } diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 9de97037ec..55fe69d7d3 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -9,67 +9,68 @@ #include <AK/Forward.h> #include <LibJS/Forward.h> -#define ENUMERATE_BYTECODE_OPS(O) \ - O(Load) \ - O(LoadImmediate) \ - O(Store) \ - O(Add) \ - O(Sub) \ - O(Mul) \ - O(Div) \ - O(Mod) \ - O(Exp) \ - O(GreaterThan) \ - O(GreaterThanEquals) \ - O(LessThan) \ - O(LessThanEquals) \ - O(AbstractInequals) \ - O(AbstractEquals) \ - O(TypedInequals) \ - O(TypedEquals) \ - O(NewBigInt) \ - O(NewArray) \ - O(NewString) \ - O(NewObject) \ - O(GetVariable) \ - O(SetVariable) \ - O(PutById) \ - O(GetById) \ - O(PutByValue) \ - O(GetByValue) \ - O(Jump) \ - O(JumpConditional) \ - O(JumpNullish) \ - O(JumpUndefined) \ - O(Call) \ - O(NewFunction) \ - O(Return) \ - O(BitwiseAnd) \ - O(BitwiseOr) \ - O(BitwiseXor) \ - O(BitwiseNot) \ - O(Not) \ - O(UnaryPlus) \ - O(UnaryMinus) \ - O(Typeof) \ - O(LeftShift) \ - O(RightShift) \ - O(UnsignedRightShift) \ - O(In) \ - O(InstanceOf) \ - O(ConcatString) \ - O(Increment) \ - O(Decrement) \ - O(Throw) \ - O(PushLexicalEnvironment) \ - O(LoadArgument) \ - O(EnterUnwindContext) \ - O(LeaveUnwindContext) \ - O(ContinuePendingUnwind) \ - O(Yield) \ - O(GetIterator) \ - O(IteratorNext) \ - O(IteratorResultDone) \ +#define ENUMERATE_BYTECODE_OPS(O) \ + O(Load) \ + O(LoadImmediate) \ + O(Store) \ + O(Add) \ + O(Sub) \ + O(Mul) \ + O(Div) \ + O(Mod) \ + O(Exp) \ + O(GreaterThan) \ + O(GreaterThanEquals) \ + O(LessThan) \ + O(LessThanEquals) \ + O(AbstractInequals) \ + O(AbstractEquals) \ + O(TypedInequals) \ + O(TypedEquals) \ + O(NewBigInt) \ + O(NewArray) \ + O(IteratorToArray) \ + O(NewString) \ + O(NewObject) \ + O(GetVariable) \ + O(SetVariable) \ + O(PutById) \ + O(GetById) \ + O(PutByValue) \ + O(GetByValue) \ + O(Jump) \ + O(JumpConditional) \ + O(JumpNullish) \ + O(JumpUndefined) \ + O(Call) \ + O(NewFunction) \ + O(Return) \ + O(BitwiseAnd) \ + O(BitwiseOr) \ + O(BitwiseXor) \ + O(BitwiseNot) \ + O(Not) \ + O(UnaryPlus) \ + O(UnaryMinus) \ + O(Typeof) \ + O(LeftShift) \ + O(RightShift) \ + O(UnsignedRightShift) \ + O(In) \ + O(InstanceOf) \ + O(ConcatString) \ + O(Increment) \ + O(Decrement) \ + O(Throw) \ + O(PushLexicalEnvironment) \ + O(LoadArgument) \ + O(EnterUnwindContext) \ + O(LeaveUnwindContext) \ + O(ContinuePendingUnwind) \ + O(Yield) \ + O(GetIterator) \ + O(IteratorNext) \ + O(IteratorResultDone) \ O(IteratorResultValue) namespace JS::Bytecode { diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 32a70f534c..a624d02663 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -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)); diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 4af2dce98a..9c2475ed66 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -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) |