summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorMatthew Olsson <matthewcolsson@gmail.com>2021-06-13 14:06:26 -0700
committerAndreas Kling <kling@serenityos.org>2021-06-19 09:38:26 +0200
commit57b9a228ab7780e606905fe450b3fa01ef1eec44 (patch)
tree454b108df806a3f226b0d4fb6f92f35b1c614290 /Userland/Libraries
parent79833246397359cceb83350dff8848d159c9eb29 (diff)
downloadserenity-57b9a228ab7780e606905fe450b3fa01ef1eec44.zip
LibJS: Support array rest elements in the bytecode interpreter
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp69
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Instruction.h123
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Op.cpp39
-rw-r--r--Userland/Libraries/LibJS/Bytecode/Op.h18
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)