1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 13:47:45 +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:
Linus Groh 2021-10-05 08:44:58 +01:00
parent fcb355f193
commit 4fa5748093
9 changed files with 47 additions and 26 deletions

View file

@ -187,7 +187,7 @@ Value FunctionExpression::instantiate_ordinary_function_expression(Interpreter&
scope->create_immutable_binding(global_object, name(), false); scope->create_immutable_binding(global_object, name(), false);
} }
auto closure = ECMAScriptFunctionObject::create(global_object, used_name, body(), parameters(), function_length(), scope, kind(), is_strict_mode(), is_arrow_function()); auto closure = ECMAScriptFunctionObject::create(global_object, used_name, body(), parameters(), function_length(), scope, kind(), is_strict_mode(), might_need_arguments_object(), is_arrow_function());
// FIXME: 6. Perform SetFunctionName(closure, name). // FIXME: 6. Perform SetFunctionName(closure, name).
// FIXME: 7. Perform MakeConstructor(closure). // FIXME: 7. Perform MakeConstructor(closure).
@ -1289,7 +1289,7 @@ ThrowCompletionOr<Value> ClassExpression::class_definition_evaluation(Interprete
auto copy_initializer = field.initializer(); auto copy_initializer = field.initializer();
auto body = create_ast_node<ExpressionStatement>(field.initializer()->source_range(), copy_initializer.release_nonnull()); auto body = create_ast_node<ExpressionStatement>(field.initializer()->source_range(), copy_initializer.release_nonnull());
// FIXME: A potential optimization is not creating the functions here since these are never directly accessible. // FIXME: A potential optimization is not creating the functions here since these are never directly accessible.
initializer = ECMAScriptFunctionObject::create(interpreter.global_object(), property_key.to_display_string(), *body, {}, 0, interpreter.lexical_environment(), FunctionKind::Regular, false); initializer = ECMAScriptFunctionObject::create(interpreter.global_object(), property_key.to_display_string(), *body, {}, 0, interpreter.lexical_environment(), FunctionKind::Regular, false, false);
initializer->set_home_object(field.is_static() ? class_constructor : &class_prototype.as_object()); initializer->set_home_object(field.is_static() ? class_constructor : &class_prototype.as_object());
} }
@ -3169,7 +3169,7 @@ void ScopeNode::block_declaration_instantiation(GlobalObject& global_object, Env
if (is<FunctionDeclaration>(declaration)) { if (is<FunctionDeclaration>(declaration)) {
auto& function_declaration = static_cast<FunctionDeclaration const&>(declaration); auto& function_declaration = static_cast<FunctionDeclaration const&>(declaration);
auto* function = ECMAScriptFunctionObject::create(global_object, function_declaration.name(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), environment, function_declaration.kind(), function_declaration.is_strict_mode()); auto* function = ECMAScriptFunctionObject::create(global_object, function_declaration.name(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), environment, function_declaration.kind(), function_declaration.is_strict_mode(), function_declaration.might_need_arguments_object());
VERIFY(is<DeclarativeEnvironment>(*environment)); VERIFY(is<DeclarativeEnvironment>(*environment));
static_cast<DeclarativeEnvironment&>(*environment).initialize_or_set_mutable_binding({}, global_object, function_declaration.name(), function); static_cast<DeclarativeEnvironment&>(*environment).initialize_or_set_mutable_binding({}, global_object, function_declaration.name(), function);
} }
@ -3313,7 +3313,7 @@ ThrowCompletionOr<void> Program::global_declaration_instantiation(Interpreter& i
}); });
for (auto& declaration : functions_to_initialize) { for (auto& declaration : functions_to_initialize) {
auto* function = ECMAScriptFunctionObject::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), &global_environment, declaration.kind(), declaration.is_strict_mode()); auto* function = ECMAScriptFunctionObject::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), &global_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object());
global_environment.create_global_function_binding(declaration.name(), function, false); global_environment.create_global_function_binding(declaration.name(), function, false);
if (auto* exception = interpreter.exception()) if (auto* exception = interpreter.exception())
return throw_completion(exception->value()); return throw_completion(exception->value());

View file

@ -432,19 +432,23 @@ public:
Vector<Parameter> const& parameters() const { return m_parameters; }; Vector<Parameter> const& parameters() const { return m_parameters; };
i32 function_length() const { return m_function_length; } i32 function_length() const { return m_function_length; }
bool is_strict_mode() const { return m_is_strict_mode; } 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; } bool is_arrow_function() const { return m_is_arrow_function; }
FunctionKind kind() const { return m_kind; } FunctionKind kind() const { return m_kind; }
protected: 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_name(move(name))
, m_body(move(body)) , m_body(move(body))
, m_parameters(move(parameters)) , m_parameters(move(parameters))
, m_function_length(function_length) , m_function_length(function_length)
, m_kind(kind) , m_kind(kind)
, m_is_strict_mode(is_strict_mode) , m_is_strict_mode(is_strict_mode)
, m_might_need_arguments_object(might_need_arguments_object)
, m_is_arrow_function(is_arrow_function) , 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; void dump(int indent, String const& class_name) const;
@ -462,7 +466,8 @@ private:
Vector<Parameter> const m_parameters; Vector<Parameter> const m_parameters;
const i32 m_function_length; const i32 m_function_length;
FunctionKind m_kind; 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 }; bool m_is_arrow_function { false };
}; };
@ -472,9 +477,9 @@ class FunctionDeclaration final
public: public:
static bool must_have_name() { return true; } 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) : 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: public:
static bool must_have_name() { return false; } 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) : 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)
{ {
} }

View file

@ -334,7 +334,7 @@ void Call::execute_impl(Bytecode::Interpreter& interpreter) const
void NewFunction::execute_impl(Bytecode::Interpreter& interpreter) const void NewFunction::execute_impl(Bytecode::Interpreter& interpreter) const
{ {
auto& vm = interpreter.vm(); auto& vm = interpreter.vm();
interpreter.accumulator() = ECMAScriptFunctionObject::create(interpreter.global_object(), m_function_node.name(), m_function_node.body(), m_function_node.parameters(), m_function_node.function_length(), vm.lexical_environment(), m_function_node.kind(), m_function_node.is_strict_mode(), m_function_node.is_arrow_function()); interpreter.accumulator() = ECMAScriptFunctionObject::create(interpreter.global_object(), m_function_node.name(), m_function_node.body(), m_function_node.parameters(), m_function_node.function_length(), vm.lexical_environment(), m_function_node.kind(), m_function_node.is_strict_mode(), m_function_node.might_need_arguments_object(), m_function_node.is_arrow_function());
} }
void Return::execute_impl(Bytecode::Interpreter& interpreter) const void Return::execute_impl(Bytecode::Interpreter& interpreter) const

View file

@ -657,7 +657,8 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe
return create_ast_node<FunctionExpression>( return create_ast_node<FunctionExpression>(
{ m_state.current_token.filename(), rule_start.position(), position() }, "", move(body), { m_state.current_token.filename(), rule_start.position(), position() }, "", move(body),
move(parameters), function_length, FunctionKind::Regular, body->in_strict_mode(), true); move(parameters), function_length, FunctionKind::Regular, body->in_strict_mode(),
/* might_need_arguments_object */ false, /* is_arrow_function */ true);
} }
RefPtr<Statement> Parser::try_parse_labelled_statement(AllowLabelledFunction allow_function) RefPtr<Statement> Parser::try_parse_labelled_statement(AllowLabelledFunction allow_function)
@ -878,7 +879,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
break; break;
} }
//https://tc39.es/ecma262/#sec-class-definitions-static-semantics-early-errors // https://tc39.es/ecma262/#sec-class-definitions-static-semantics-early-errors
// ClassElement : static MethodDefinition // ClassElement : static MethodDefinition
// It is a Syntax Error if PropName of MethodDefinition is "prototype". // It is a Syntax Error if PropName of MethodDefinition is "prototype".
if (is_static && name == "prototype"sv) if (is_static && name == "prototype"sv)
@ -975,11 +976,13 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
constructor = create_ast_node<FunctionExpression>( constructor = create_ast_node<FunctionExpression>(
{ m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), { m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body),
Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, FunctionKind::Regular, true); Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, FunctionKind::Regular,
/* is_strict_mode */ true, /* might_need_arguments_object */ false);
} else { } else {
constructor = create_ast_node<FunctionExpression>( constructor = create_ast_node<FunctionExpression>(
{ m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), { m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body),
Vector<FunctionNode::Parameter> {}, 0, FunctionKind::Regular, true); Vector<FunctionNode::Parameter> {}, 0, FunctionKind::Regular,
/* is_strict_mode */ true, /* might_need_arguments_object */ false);
} }
} }
@ -1958,6 +1961,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
TemporaryChange break_context_rollback(m_state.in_break_context, false); TemporaryChange break_context_rollback(m_state.in_break_context, false);
TemporaryChange continue_context_rollback(m_state.in_continue_context, false); TemporaryChange continue_context_rollback(m_state.in_continue_context, false);
TemporaryChange class_field_initializer_rollback(m_state.in_class_field_initializer, false); TemporaryChange class_field_initializer_rollback(m_state.in_class_field_initializer, false);
TemporaryChange might_need_arguments_object_rollback(m_state.function_might_need_arguments_object, false);
constexpr auto is_function_expression = IsSame<FunctionNodeType, FunctionExpression>; constexpr auto is_function_expression = IsSame<FunctionNodeType, FunctionExpression>;
auto function_kind = (parse_options & FunctionNodeParseOptions::IsGeneratorFunction) != 0 ? FunctionKind::Generator : FunctionKind::Regular; auto function_kind = (parse_options & FunctionNodeParseOptions::IsGeneratorFunction) != 0 ? FunctionKind::Generator : FunctionKind::Regular;
@ -1989,7 +1993,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
if (function_length == -1) if (function_length == -1)
function_length = parameters.size(); function_length = parameters.size();
TemporaryChange change(m_state.in_function_context, true); TemporaryChange function_context_rollback(m_state.in_function_context, true);
auto old_labels_in_scope = move(m_state.labels_in_scope); auto old_labels_in_scope = move(m_state.labels_in_scope);
ScopeGuard guard([&]() { ScopeGuard guard([&]() {
@ -2006,7 +2010,7 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
return create_ast_node<FunctionNodeType>( return create_ast_node<FunctionNodeType>(
{ m_state.current_token.filename(), rule_start.position(), position() }, { m_state.current_token.filename(), rule_start.position(), position() },
name, move(body), move(parameters), function_length, name, move(body), move(parameters), function_length,
function_kind, has_strict_directive); function_kind, has_strict_directive, m_state.function_might_need_arguments_object);
} }
Vector<FunctionNode::Parameter> Parser::parse_formal_parameters(int& function_length, u8 parse_options) Vector<FunctionNode::Parameter> Parser::parse_formal_parameters(int& function_length, u8 parse_options)
@ -3129,6 +3133,11 @@ Token Parser::consume()
{ {
auto old_token = m_state.current_token; auto old_token = m_state.current_token;
m_state.current_token = m_state.lexer.next(); m_state.current_token = m_state.lexer.next();
// NOTE: This is the bare minimum needed to decide whether we might need an arguments object
// in a function expression or declaration. ("might" because the AST implements some further
// conditions from the spec that rule out the need for allocating one)
if (old_token.type() == TokenType::Identifier && old_token.value().is_one_of("arguments"sv, "eval"sv))
m_state.function_might_need_arguments_object = true;
return old_token; return old_token;
} }

View file

@ -253,6 +253,7 @@ private:
bool in_continue_context { false }; bool in_continue_context { false };
bool string_legacy_octal_escape_sequence_in_scope { false }; bool string_legacy_octal_escape_sequence_in_scope { false };
bool in_class_field_initializer { false }; bool in_class_field_initializer { false };
bool function_might_need_arguments_object { false };
ParserState(Lexer, Program::Type); ParserState(Lexer, Program::Type);
}; };

View file

@ -627,7 +627,7 @@ ThrowCompletionOr<void> eval_declaration_instantiation(VM& vm, GlobalObject& glo
return throw_completion(exception->value()); return throw_completion(exception->value());
for (auto& declaration : functions_to_initialize) { for (auto& declaration : functions_to_initialize) {
auto* function = ECMAScriptFunctionObject::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), lexical_environment, declaration.kind(), declaration.is_strict_mode()); auto* function = ECMAScriptFunctionObject::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), lexical_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object());
if (global_var_environment) { if (global_var_environment) {
global_var_environment->create_global_function_binding(declaration.name(), function, true); global_var_environment->create_global_function_binding(declaration.name(), function, true);
if (auto* exception = vm.exception()) if (auto* exception = vm.exception())

View file

@ -24,7 +24,7 @@
namespace JS { namespace JS {
ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind kind, bool is_strict, bool is_arrow_function) ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool is_arrow_function)
{ {
Object* prototype = nullptr; Object* prototype = nullptr;
switch (kind) { switch (kind) {
@ -35,10 +35,10 @@ ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_
prototype = global_object.generator_function_prototype(); prototype = global_object.generator_function_prototype();
break; break;
} }
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, is_arrow_function); return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, might_need_arguments_object, is_arrow_function);
} }
ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool is_arrow_function) ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool might_need_arguments_object, bool is_arrow_function)
: FunctionObject(prototype) : FunctionObject(prototype)
, m_environment(parent_scope) , m_environment(parent_scope)
, m_formal_parameters(move(formal_parameters)) , m_formal_parameters(move(formal_parameters))
@ -48,6 +48,7 @@ ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement con
, m_name(move(name)) , m_name(move(name))
, m_function_length(function_length) , m_function_length(function_length)
, m_kind(kind) , m_kind(kind)
, m_might_need_arguments_object(might_need_arguments_object)
, m_is_arrow_function(is_arrow_function) , m_is_arrow_function(is_arrow_function)
{ {
// NOTE: This logic is from OrdinaryFunctionCreate, https://tc39.es/ecma262/#sec-ordinaryfunctioncreate // NOTE: This logic is from OrdinaryFunctionCreate, https://tc39.es/ecma262/#sec-ordinaryfunctioncreate
@ -159,7 +160,11 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
}); });
} }
auto arguments_object_needed = this_mode() != ThisMode::Lexical; auto arguments_object_needed = m_might_need_arguments_object;
if (this_mode() == ThisMode::Lexical)
arguments_object_needed = false;
if (parameter_names.contains(vm.names.arguments.as_string())) if (parameter_names.contains(vm.names.arguments.as_string()))
arguments_object_needed = false; arguments_object_needed = false;
@ -360,7 +365,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
VERIFY(!vm.exception()); VERIFY(!vm.exception());
for (auto& declaration : functions_to_initialize) { for (auto& declaration : functions_to_initialize) {
auto* function = ECMAScriptFunctionObject::create(global_object(), declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), lex_environment, declaration.kind(), declaration.is_strict_mode()); auto* function = ECMAScriptFunctionObject::create(global_object(), declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), lex_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object());
var_environment->set_mutable_binding(global_object(), declaration.name(), function, false); var_environment->set_mutable_binding(global_object(), declaration.name(), function, false);
} }

View file

@ -28,9 +28,9 @@ public:
Global, Global,
}; };
static ECMAScriptFunctionObject* create(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool is_arrow_function = false); static ECMAScriptFunctionObject* create(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool might_need_arguments_object = true, bool is_arrow_function = false);
ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool is_arrow_function = false); ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool might_need_arguments_object, bool is_arrow_function);
virtual void initialize(GlobalObject&) override; virtual void initialize(GlobalObject&) override;
virtual ~ECMAScriptFunctionObject(); virtual ~ECMAScriptFunctionObject();
@ -100,6 +100,7 @@ private:
Optional<Bytecode::Executable> m_bytecode_executable; Optional<Bytecode::Executable> m_bytecode_executable;
i32 m_function_length { 0 }; i32 m_function_length { 0 };
FunctionKind m_kind { FunctionKind::Regular }; FunctionKind m_kind { FunctionKind::Regular };
bool m_might_need_arguments_object { true };
bool m_is_arrow_function { false }; bool m_is_arrow_function { false };
bool m_has_simple_parameter_list { false }; bool m_has_simple_parameter_list { false };
}; };

View file

@ -62,7 +62,7 @@ Value GeneratorFunctionConstructor::construct(FunctionObject& new_target)
block.dump(executable); block.dump(executable);
} }
return ECMAScriptFunctionObject::create(global_object(), function->name(), function->body(), function->parameters(), function->function_length(), vm().lexical_environment(), FunctionKind::Generator, function->is_strict_mode(), false); return ECMAScriptFunctionObject::create(global_object(), function->name(), function->body(), function->parameters(), function->function_length(), vm().lexical_environment(), FunctionKind::Generator, function->is_strict_mode(), function->might_need_arguments_object());
} }
} }