diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index df17066a04..8077a11eb5 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -195,7 +195,7 @@ Value FunctionExpression::instantiate_ordinary_function_expression(Interpreter& 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(), might_need_arguments_object(), is_arrow_function()); + auto closure = ECMAScriptFunctionObject::create(global_object, used_name, body(), parameters(), function_length(), scope, kind(), is_strict_mode(), might_need_arguments_object(), contains_direct_call_to_eval(), is_arrow_function()); // FIXME: 6. Perform SetFunctionName(closure, name). // FIXME: 7. Perform MakeConstructor(closure). @@ -1734,6 +1734,10 @@ void FunctionNode::dump(int indent, String const& class_name) const { print_indent(indent); outln("{}{} '{}'", class_name, m_kind == FunctionKind::Generator ? "*" : "", name()); + if (m_contains_direct_call_to_eval) { + print_indent(indent + 1); + outln("\033[31;1m(direct eval)\033[0m"); + } if (!m_parameters.is_empty()) { print_indent(indent + 1); outln("(Parameters)"); @@ -3210,7 +3214,7 @@ void ScopeNode::block_declaration_instantiation(GlobalObject& global_object, Env if (is(declaration)) { auto& function_declaration = static_cast(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(), function_declaration.might_need_arguments_object()); + 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(), function_declaration.contains_direct_call_to_eval()); VERIFY(is(*environment)); static_cast(*environment).initialize_or_set_mutable_binding({}, global_object, function_declaration.name(), function); } @@ -3354,7 +3358,7 @@ ThrowCompletionOr Program::global_declaration_instantiation(Interpreter& i }); 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(), declaration.might_need_arguments_object()); + 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(), declaration.contains_direct_call_to_eval()); global_environment.create_global_function_binding(declaration.name(), function, false); if (auto* exception = interpreter.exception()) return throw_completion(exception->value()); diff --git a/Userland/Libraries/LibJS/AST.h b/Userland/Libraries/LibJS/AST.h index 27a1797871..d2cdb8bbaa 100644 --- a/Userland/Libraries/LibJS/AST.h +++ b/Userland/Libraries/LibJS/AST.h @@ -441,11 +441,12 @@ public: 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 contains_direct_call_to_eval() const { return m_contains_direct_call_to_eval; } bool is_arrow_function() const { return m_is_arrow_function; } FunctionKind kind() const { return m_kind; } protected: - FunctionNode(FlyString name, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool is_arrow_function) + FunctionNode(FlyString name, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function) : m_name(move(name)) , m_body(move(body)) , m_parameters(move(parameters)) @@ -453,6 +454,7 @@ protected: , m_kind(kind) , m_is_strict_mode(is_strict_mode) , m_might_need_arguments_object(might_need_arguments_object) + , m_contains_direct_call_to_eval(contains_direct_call_to_eval) , m_is_arrow_function(is_arrow_function) { if (m_is_arrow_function) @@ -476,6 +478,7 @@ private: FunctionKind m_kind; bool m_is_strict_mode { false }; bool m_might_need_arguments_object { false }; + bool m_contains_direct_call_to_eval { false }; bool m_is_arrow_function { false }; }; @@ -485,9 +488,9 @@ class FunctionDeclaration final public: static bool must_have_name() { return true; } - FunctionDeclaration(SourceRange source_range, FlyString const& name, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object) + FunctionDeclaration(SourceRange source_range, FlyString const& name, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval) : Declaration(source_range) - , FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, false) + , FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, false) { } @@ -511,9 +514,9 @@ class FunctionExpression final public: static bool must_have_name() { return false; } - FunctionExpression(SourceRange source_range, FlyString const& name, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool is_arrow_function = false) + FunctionExpression(SourceRange source_range, FlyString const& name, NonnullRefPtr body, Vector parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function = false) : Expression(source_range) - , FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, is_arrow_function) + , FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function) { } diff --git a/Userland/Libraries/LibJS/Parser.cpp b/Userland/Libraries/LibJS/Parser.cpp index bf33bfcb52..875c520ac9 100644 --- a/Userland/Libraries/LibJS/Parser.cpp +++ b/Userland/Libraries/LibJS/Parser.cpp @@ -670,11 +670,13 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe m_state.labels_in_scope = move(old_labels_in_scope); }); + bool contains_direct_call_to_eval = false; + auto function_body_result = [&]() -> RefPtr { TemporaryChange change(m_state.in_arrow_function_context, true); if (match(TokenType::CurlyOpen)) { // Parse a function body with statements - return parse_function_body(parameters, FunctionKind::Regular); + return parse_function_body(parameters, FunctionKind::Regular, contains_direct_call_to_eval); } if (match_expression()) { // Parse a function body which returns a single expression @@ -689,6 +691,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe return_block->append({ m_filename, rule_start.position(), position() }, move(return_expression)); if (m_state.strict_mode) return_block->set_strict_mode(); + contains_direct_call_to_eval = function_scope.contains_direct_call_to_eval(); return return_block; } // Invalid arrow function body @@ -715,7 +718,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe return create_ast_node( { m_state.current_token.filename(), rule_start.position(), position() }, "", move(body), move(parameters), function_length, FunctionKind::Regular, body->in_strict_mode(), - /* might_need_arguments_object */ false, /* is_arrow_function */ true); + /* might_need_arguments_object */ false, contains_direct_call_to_eval, /* is_arrow_function */ true); } RefPtr Parser::try_parse_labelled_statement(AllowLabelledFunction allow_function) @@ -1034,12 +1037,12 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ constructor = create_ast_node( { m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, FunctionKind::Regular, - /* is_strict_mode */ true, /* might_need_arguments_object */ false); + /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); } else { constructor = create_ast_node( { m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), Vector {}, 0, FunctionKind::Regular, - /* is_strict_mode */ true, /* might_need_arguments_object */ false); + /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); } } @@ -1996,7 +1999,7 @@ void Parser::parse_statement_list(ScopeNode& output_node, AllowLabelledFunction } // FunctionBody, https://tc39.es/ecma262/#prod-FunctionBody -NonnullRefPtr Parser::parse_function_body(Vector const& parameters, FunctionKind function_kind) +NonnullRefPtr Parser::parse_function_body(Vector const& parameters, FunctionKind function_kind, bool& contains_direct_call_to_eval) { auto rule_start = push_start(); auto function_body = create_ast_node({ m_state.current_token.filename(), rule_start.position(), position() }); @@ -2052,6 +2055,7 @@ NonnullRefPtr Parser::parse_function_body(Vector Parser::parse_function_node(u8 parse_options) m_state.labels_in_scope = move(old_labels_in_scope); }); - auto body = parse_function_body(parameters, function_kind); + bool contains_direct_call_to_eval = false; + auto body = parse_function_body(parameters, function_kind, contains_direct_call_to_eval); auto has_strict_directive = body->in_strict_mode(); @@ -2127,7 +2132,8 @@ NonnullRefPtr Parser::parse_function_node(u8 parse_options) return create_ast_node( { m_state.current_token.filename(), rule_start.position(), position() }, name, move(body), move(parameters), function_length, - function_kind, has_strict_directive, m_state.function_might_need_arguments_object); + function_kind, has_strict_directive, m_state.function_might_need_arguments_object, + contains_direct_call_to_eval); } Vector Parser::parse_formal_parameters(int& function_length, u8 parse_options) diff --git a/Userland/Libraries/LibJS/Parser.h b/Userland/Libraries/LibJS/Parser.h index 4613aaf8fd..684adb86b3 100644 --- a/Userland/Libraries/LibJS/Parser.h +++ b/Userland/Libraries/LibJS/Parser.h @@ -72,7 +72,7 @@ public: NonnullRefPtr parse_statement(AllowLabelledFunction allow_labelled_function = AllowLabelledFunction::No); NonnullRefPtr parse_block_statement(); - NonnullRefPtr parse_function_body(Vector const& parameters, FunctionKind function_kind); + NonnullRefPtr parse_function_body(Vector const& parameters, FunctionKind function_kind, bool& contains_direct_call_to_eval); NonnullRefPtr parse_return_statement(); NonnullRefPtr parse_variable_declaration(bool for_loop_variable_declaration = false); NonnullRefPtr parse_for_statement(); diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index e998236294..ba8fb91805 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -24,7 +24,7 @@ namespace JS { -ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool is_arrow_function) +ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function) { Object* prototype = nullptr; switch (kind) { @@ -35,10 +35,10 @@ ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_ prototype = global_object.generator_function_prototype(); break; } - return global_object.heap().allocate(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, might_need_arguments_object, is_arrow_function); + return global_object.heap().allocate(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, *prototype, kind, is_strict, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function); } -ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool might_need_arguments_object, bool is_arrow_function) +ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector formal_parameters, i32 function_length, Environment* parent_scope, Object& prototype, FunctionKind kind, bool strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function) : FunctionObject(prototype) , m_environment(parent_scope) , m_formal_parameters(move(formal_parameters)) @@ -49,6 +49,7 @@ ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement con , m_function_length(function_length) , m_kind(kind) , m_might_need_arguments_object(might_need_arguments_object) + , m_contains_direct_call_to_eval(contains_direct_call_to_eval) , m_is_arrow_function(is_arrow_function) { // NOTE: This logic is from OrdinaryFunctionCreate, https://tc39.es/ecma262/#sec-ordinaryfunctioncreate @@ -367,7 +368,7 @@ ThrowCompletionOr ECMAScriptFunctionObject::function_declaration_instantia VERIFY(!vm.exception()); 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(), declaration.might_need_arguments_object()); + 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(), declaration.contains_direct_call_to_eval()); var_environment->set_mutable_binding(global_object(), declaration.name(), function, false); } diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index b936997988..f7f4121869 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h @@ -28,9 +28,9 @@ public: Global, }; - static ECMAScriptFunctionObject* create(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool might_need_arguments_object = true, bool is_arrow_function = false); + static ECMAScriptFunctionObject* create(GlobalObject&, FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, FunctionKind, bool is_strict, bool might_need_arguments_object = true, bool contains_direct_call_to_eval = true, bool is_arrow_function = false); - ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool might_need_arguments_object, bool is_arrow_function); + ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, Object& prototype, FunctionKind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function); virtual void initialize(GlobalObject&) override; virtual ~ECMAScriptFunctionObject(); @@ -101,6 +101,7 @@ private: i32 m_function_length { 0 }; FunctionKind m_kind { FunctionKind::Regular }; bool m_might_need_arguments_object { true }; + bool m_contains_direct_call_to_eval { true }; bool m_is_arrow_function { false }; bool m_has_simple_parameter_list { false }; };