mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 02:57:44 +00:00
LibJS: Add an optimization to avoid needless arguments object creation
This gives FunctionNode a "might need arguments object" boolean flag and sets it based on the simplest possible heuristic for this: if we encounter an identifier called "arguments" or "eval" up to the next (nested) function declaration or expression, we won't need an arguments object. Otherwise, we *might* need one - the final decision is made in the FunctionDeclarationInstantiation AO. Now, this is obviously not perfect. Even if you avoid eval, something like `foo.arguments` will still trigger a false positive - but it's a start and already massively cuts down on needlessly allocated objects, especially in real-world code that is often minified, and so a full "arguments" identifier will be an actual arguments object more often than not. To illustrate the actual impact of this change, here's the number of allocated arguments objects during a full test-js run: Before: - Unmapped arguments objects: 78765 - Mapped arguments objects: 2455 After: - Unmapped arguments objects: 18 - Mapped arguments objects: 37 This results in a ~5% speedup of test-js on my Linux host machine, and about 3.5% on i686 Serenity in QEMU (warm runs, average of 5). The following microbenchmark (calling an empty function 1M times) runs 25% faster on Linux and 45% on Serenity: function foo() {} for (var i = 0; i < 1_000_000; ++i) foo(); test262 reports no changes in either direction, apart from a speedup :^)
This commit is contained in:
parent
fcb355f193
commit
4fa5748093
9 changed files with 47 additions and 26 deletions
|
@ -432,19 +432,23 @@ public:
|
|||
Vector<Parameter> const& parameters() const { return m_parameters; };
|
||||
i32 function_length() const { return m_function_length; }
|
||||
bool is_strict_mode() const { return m_is_strict_mode; }
|
||||
bool might_need_arguments_object() const { return m_might_need_arguments_object; }
|
||||
bool is_arrow_function() const { return m_is_arrow_function; }
|
||||
FunctionKind kind() const { return m_kind; }
|
||||
|
||||
protected:
|
||||
FunctionNode(FlyString name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool is_arrow_function)
|
||||
FunctionNode(FlyString name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool is_arrow_function)
|
||||
: m_name(move(name))
|
||||
, m_body(move(body))
|
||||
, m_parameters(move(parameters))
|
||||
, m_function_length(function_length)
|
||||
, m_kind(kind)
|
||||
, m_is_strict_mode(is_strict_mode)
|
||||
, m_might_need_arguments_object(might_need_arguments_object)
|
||||
, m_is_arrow_function(is_arrow_function)
|
||||
{
|
||||
if (m_is_arrow_function)
|
||||
VERIFY(!m_might_need_arguments_object);
|
||||
}
|
||||
|
||||
void dump(int indent, String const& class_name) const;
|
||||
|
@ -462,7 +466,8 @@ private:
|
|||
Vector<Parameter> const m_parameters;
|
||||
const i32 m_function_length;
|
||||
FunctionKind m_kind;
|
||||
bool m_is_strict_mode;
|
||||
bool m_is_strict_mode { false };
|
||||
bool m_might_need_arguments_object { false };
|
||||
bool m_is_arrow_function { false };
|
||||
};
|
||||
|
||||
|
@ -472,9 +477,9 @@ class FunctionDeclaration final
|
|||
public:
|
||||
static bool must_have_name() { return true; }
|
||||
|
||||
FunctionDeclaration(SourceRange source_range, FlyString const& name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode = false)
|
||||
FunctionDeclaration(SourceRange source_range, FlyString const& name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object)
|
||||
: Declaration(source_range)
|
||||
, FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, false)
|
||||
, FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -498,9 +503,9 @@ class FunctionExpression final
|
|||
public:
|
||||
static bool must_have_name() { return false; }
|
||||
|
||||
FunctionExpression(SourceRange source_range, FlyString const& name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool is_arrow_function = false)
|
||||
FunctionExpression(SourceRange source_range, FlyString const& name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool is_arrow_function = false)
|
||||
: Expression(source_range)
|
||||
, FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, is_arrow_function)
|
||||
, FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, is_arrow_function)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue