From 9ee5029bc5ab24d614525acd3229300063aa1d68 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 11 Jun 2021 00:35:25 +0200 Subject: [PATCH] LibJS: Basic bytecode support for computed member expressions Expressions like foo[1 + 2] now work, and you can assign to them as well! :^) --- .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 14 ++++++-- .../Libraries/LibJS/Bytecode/Instruction.h | 2 ++ Userland/Libraries/LibJS/Bytecode/Op.cpp | 30 +++++++++++++++++ Userland/Libraries/LibJS/Bytecode/Op.h | 32 +++++++++++++++++++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index e5e3704bbe..9b0c95b749 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -375,14 +375,18 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con generator.emit(object_reg); if (expression.is_computed()) { - TODO(); + expression.property().generate_bytecode(generator); + auto property_reg = generator.allocate_register(); + generator.emit(property_reg); + m_rhs->generate_bytecode(generator); + generator.emit(object_reg, property_reg); } else { VERIFY(is(expression.property())); m_rhs->generate_bytecode(generator); auto identifier_table_ref = generator.intern_string(static_cast(expression.property()).string()); generator.emit(object_reg, identifier_table_ref); - return; } + return; } TODO(); @@ -585,7 +589,11 @@ void MemberExpression::generate_bytecode(Bytecode::Generator& generator) const object().generate_bytecode(generator); if (is_computed()) { - TODO(); + auto object_reg = generator.allocate_register(); + generator.emit(object_reg); + + property().generate_bytecode(generator); + generator.emit(object_reg); } else { VERIFY(is(property())); auto identifier_table_ref = generator.intern_string(static_cast(property()).string()); diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index b3a622898f..c60fb451d8 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -35,6 +35,8 @@ O(SetVariable) \ O(PutById) \ O(GetById) \ + O(PutByValue) \ + O(GetByValue) \ O(Jump) \ O(JumpConditional) \ O(JumpNullish) \ diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 2d080627c1..265556b9b1 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -291,6 +291,26 @@ void Yield::execute(Bytecode::Interpreter& interpreter) const interpreter.do_return(object); } +void GetByValue::execute(Bytecode::Interpreter& interpreter) const +{ + if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object())) { + auto property_key = interpreter.accumulator().to_property_key(interpreter.global_object()); + if (interpreter.vm().exception()) + return; + interpreter.accumulator() = object->get(property_key); + } +} + +void PutByValue::execute(Bytecode::Interpreter& interpreter) const +{ + if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object())) { + auto property_key = interpreter.reg(m_property).to_property_key(interpreter.global_object()); + if (interpreter.vm().exception()) + return; + object->put(property_key, interpreter.accumulator()); + } +} + String Load::to_string(Bytecode::Executable const&) const { return String::formatted("Load {}", m_src); @@ -463,4 +483,14 @@ String Yield::to_string(Bytecode::Executable const&) const return String::formatted("Yield return"); } +String GetByValue::to_string(const Bytecode::Executable&) const +{ + return String::formatted("GetByValue base:{}", m_base); +} + +String PutByValue::to_string(const Bytecode::Executable&) const +{ + return String::formatted("PutByValue base:{}, property:{}", m_base, m_property); +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index f5961b87e0..79212526ea 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -266,6 +266,38 @@ private: StringTableIndex m_property; }; +class GetByValue final : public Instruction { +public: + explicit GetByValue(Register base) + : Instruction(Type::GetByValue) + , m_base(base) + { + } + + void execute(Bytecode::Interpreter&) const; + String to_string(Bytecode::Executable const&) const; + +private: + Register m_base; +}; + +class PutByValue final : public Instruction { +public: + PutByValue(Register base, Register property) + : Instruction(Type::PutByValue) + , m_base(base) + , m_property(property) + { + } + + void execute(Bytecode::Interpreter&) const; + String to_string(Bytecode::Executable const&) const; + +private: + Register m_base; + Register m_property; +}; + class Jump : public Instruction { public: constexpr static bool IsTerminator = true;