diff options
author | Andreas Kling <kling@serenityos.org> | 2020-04-01 18:51:27 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-01 18:57:00 +0200 |
commit | cd9379dca99ec42aa3b6ef139d1231868be2eeb0 (patch) | |
tree | 94778cd0b8cb7450a9d8e807f78ef18157b72fec /Libraries/LibJS | |
parent | 021d78f8f7249a84b8e3fb197d6a43e4f92059e8 (diff) | |
download | serenity-cd9379dca99ec42aa3b6ef139d1231868be2eeb0.zip |
LibJS: Reorganize computing of |this| for CallExpressions
This avoids executing the LHS of the object expression twice when doing
a call on the result of an object expression.
Diffstat (limited to 'Libraries/LibJS')
-rw-r--r-- | Libraries/LibJS/AST.cpp | 34 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 6 |
2 files changed, 29 insertions, 11 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index a20b90d028..549a577e39 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -60,9 +60,30 @@ Value ExpressionStatement::execute(Interpreter& interpreter) const return m_expression->execute(interpreter); } +CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interpreter& interpreter) const +{ + if (is_new_expression()) { + // Computing |this| is irrelevant for "new" expression. + return { {}, m_callee->execute(interpreter) }; + } + + if (m_callee->is_member_expression()) { + auto& member_expression = static_cast<const MemberExpression&>(*m_callee); + auto object_value = member_expression.object().execute(interpreter); + if (interpreter.exception()) + return {}; + auto* this_value = object_value.to_object(interpreter.heap()); + if (interpreter.exception()) + return {}; + auto callee = this_value->get(member_expression.computed_property_name(interpreter)).value_or({}); + return { this_value, callee }; + } + return { &interpreter.global_object(), m_callee->execute(interpreter) }; +} + Value CallExpression::execute(Interpreter& interpreter) const { - auto callee = m_callee->execute(interpreter); + auto [this_value, callee] = compute_this_and_callee(interpreter); if (interpreter.exception()) return {}; @@ -89,15 +110,7 @@ Value CallExpression::execute(Interpreter& interpreter) const new_object->set_prototype(prototype.value().as_object()); call_frame.this_value = new_object; } else { - if (m_callee->is_member_expression()) { - auto object_value = static_cast<const MemberExpression&>(*m_callee).object().execute(interpreter); - if (interpreter.exception()) - return {}; - auto this_value = object_value.to_object(interpreter.heap()); - if (interpreter.exception()) - return {}; - call_frame.this_value = this_value; - } + call_frame.this_value = this_value; } auto result = function->call(interpreter); @@ -942,5 +955,4 @@ void SwitchCase::dump(int indent) const statement.dump(indent + 1); } } - } diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 80138b2af5..f03b04b111 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -484,6 +484,12 @@ public: private: virtual const char* class_name() const override { return "CallExpression"; } + struct ThisAndCallee { + Value this_value; + Value callee; + }; + ThisAndCallee compute_this_and_callee(Interpreter&) const; + NonnullRefPtr<Expression> m_callee; const NonnullRefPtrVector<Expression> m_arguments; }; |