diff options
author | Andreas Kling <kling@serenityos.org> | 2021-06-11 00:35:25 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-11 00:36:18 +0200 |
commit | 9ee5029bc5ab24d614525acd3229300063aa1d68 (patch) | |
tree | 20e96f3ea5836d1765acc31ab09093a38379987e | |
parent | b47246ec70e8243639772cc1cc280ed42a6c4ff5 (diff) | |
download | serenity-9ee5029bc5ab24d614525acd3229300063aa1d68.zip |
LibJS: Basic bytecode support for computed member expressions
Expressions like foo[1 + 2] now work, and you can assign to them
as well! :^)
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Instruction.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.cpp | 30 | ||||
-rw-r--r-- | 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<Bytecode::Op::Store>(object_reg); if (expression.is_computed()) { - TODO(); + expression.property().generate_bytecode(generator); + auto property_reg = generator.allocate_register(); + generator.emit<Bytecode::Op::Store>(property_reg); + m_rhs->generate_bytecode(generator); + generator.emit<Bytecode::Op::PutByValue>(object_reg, property_reg); } else { VERIFY(is<Identifier>(expression.property())); m_rhs->generate_bytecode(generator); auto identifier_table_ref = generator.intern_string(static_cast<Identifier const&>(expression.property()).string()); generator.emit<Bytecode::Op::PutById>(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<Bytecode::Op::Store>(object_reg); + + property().generate_bytecode(generator); + generator.emit<Bytecode::Op::GetByValue>(object_reg); } else { VERIFY(is<Identifier>(property())); auto identifier_table_ref = generator.intern_string(static_cast<Identifier const&>(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; |