mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
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.
This commit is contained in:
parent
021d78f8f7
commit
cd9379dca9
Notes:
sideshowbarker
2024-07-19 08:01:00 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/cd9379dca99
2 changed files with 29 additions and 11 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue