From dc639584781a01804fb7c59c97f21e0578f1f251 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 5 Jun 2021 15:15:30 +0200 Subject: [PATCH] LibJS: Support basic function calls in the bytecode world :^) This patch adds the Call bytecode instruction which is emitted for the CallExpression AST node. It's pretty barebones and doesn't handle 'this' values properly, etc. But it can perform basic function calls! :^) Note that the called function will *not* execute as bytecode, but will simply fall back into the old codepath and use the AST interpreter. --- Userland/Libraries/LibJS/AST.h | 2 + .../Libraries/LibJS/Bytecode/ASTCodegen.cpp | 21 ++++++++++ Userland/Libraries/LibJS/Bytecode/Op.cpp | 41 +++++++++++++++++++ Userland/Libraries/LibJS/Bytecode/Op.h | 21 ++++++++++ 4 files changed, 85 insertions(+) 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