diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index b97d0c5322..d6ff389251 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -272,6 +272,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; + virtual Optional generate_bytecode(Bytecode::Generator&) const override; }; class FunctionExpression final @@ -849,6 +850,7 @@ public: virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; + virtual Optional generate_bytecode(Bytecode::Generator&) const override; private: struct ThisAndCallee { diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index a0b34e50fa..32d80310be 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -156,4 +156,25 @@ Optional MemberExpression::generate_bytecode(Bytecode::Gener } } +Optional FunctionDeclaration::generate_bytecode(Bytecode::Generator&) const +{ + return {}; +} + +Optional CallExpression::generate_bytecode(Bytecode::Generator& generator) const +{ + auto callee_reg = m_callee->generate_bytecode(generator); + + // FIXME: Load the correct 'this' value into 'this_reg'. + auto this_reg = generator.allocate_register(); + generator.emit(this_reg, js_undefined()); + + Vector argument_registers; + for (auto& arg : m_arguments) + argument_registers.append(*arg.value->generate_bytecode(generator)); + auto dst_reg = generator.allocate_register(); + generator.emit(dst_reg, *callee_reg, this_reg, argument_registers); + return dst_reg; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 225ee92b42..d40584067e 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -91,6 +91,31 @@ void JumpIfTrue::execute(Bytecode::Interpreter& interpreter) const interpreter.jump(m_target.value()); } +void Call::execute(Bytecode::Interpreter& interpreter) const +{ + auto callee = interpreter.reg(m_callee); + if (!callee.is_function()) { + TODO(); + } + auto& function = callee.as_function(); + + auto this_value = interpreter.reg(m_this_value); + + Value return_value; + + if (m_arguments.is_empty()) { + return_value = interpreter.vm().call(function, this_value); + } else { + MarkedValueList argument_values { interpreter.vm().heap() }; + for (auto& arg : m_arguments) { + argument_values.append(interpreter.reg(arg)); + } + return_value = interpreter.vm().call(function, this_value, move(argument_values)); + } + + interpreter.reg(m_dst) = return_value; +} + void EnterScope::execute(Bytecode::Interpreter& interpreter) const { auto& vm = interpreter.vm(); @@ -182,6 +207,22 @@ String JumpIfTrue::to_string() const return String::formatted("JumpIfTrue result:{}, target:", m_result); } +String Call::to_string() const +{ + StringBuilder builder; + builder.appendff("Call dst:{}, callee:{}, this:{}", m_dst, m_callee, m_this_value); + if (!m_arguments.is_empty()) { + builder.append(", arguments:["); + for (size_t i = 0; i < m_arguments.size(); ++i) { + builder.appendff("{}", m_arguments[i]); + if (i != m_arguments.size() - 1) + builder.append(','); + } + builder.append(']'); + } + return builder.to_string(); +} + String EnterScope::to_string() const { return "EnterScope"; diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index c80ca2ba6c..793abff75d 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -265,6 +265,27 @@ private: Optional