From 13ead80ee6083e48f7f987c584fb60728a351534 Mon Sep 17 00:00:00 2001 From: davidot Date: Mon, 11 Oct 2021 20:29:31 +0200 Subject: [PATCH] LibJS: Add PrivateEnvironment --- Userland/Libraries/LibJS/AST.cpp | 24 ++++++--- Userland/Libraries/LibJS/Bytecode/Op.cpp | 2 +- Userland/Libraries/LibJS/CMakeLists.txt | 1 + .../LibJS/Runtime/AbstractOperations.cpp | 17 ++++-- .../LibJS/Runtime/AbstractOperations.h | 4 +- .../Runtime/ECMAScriptFunctionObject.cpp | 13 ++--- .../LibJS/Runtime/ECMAScriptFunctionObject.h | 5 +- .../LibJS/Runtime/ExecutionContext.h | 10 ++-- .../Runtime/GeneratorFunctionConstructor.cpp | 2 +- .../LibJS/Runtime/PrivateEnvironment.cpp | 47 +++++++++++++++++ .../LibJS/Runtime/PrivateEnvironment.h | 52 +++++++++++++++++++ .../Libraries/LibJS/Runtime/ShadowRealm.cpp | 2 +- Userland/Libraries/LibWeb/DOM/EventTarget.cpp | 2 +- 13 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 Userland/Libraries/LibJS/Runtime/PrivateEnvironment.cpp create mode 100644 Userland/Libraries/LibJS/Runtime/PrivateEnvironment.h diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 806157e4b1..2034e0ec4c 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -199,7 +199,9 @@ Value FunctionExpression::instantiate_ordinary_function_expression(Interpreter& MUST(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(), contains_direct_call_to_eval(), is_arrow_function()); + auto* private_scope = interpreter.vm().running_execution_context().private_environment; + + auto closure = ECMAScriptFunctionObject::create(global_object, used_name, body(), parameters(), function_length(), scope, private_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). @@ -1232,7 +1234,7 @@ ThrowCompletionOr ClassField::class_element_evaluation auto body = create_ast_node(m_initializer->source_range(), copy_initializer.release_nonnull()); // FIXME: A potential optimization is not creating the functions here since these are never directly accessible. auto name = property_key.is_number() ? property_key.to_string() : property_key.to_string_or_symbol().to_display_string(); - initializer = ECMAScriptFunctionObject::create(interpreter.global_object(), name, *body, {}, 0, interpreter.lexical_environment(), FunctionKind::Regular, false, false); + initializer = ECMAScriptFunctionObject::create(interpreter.global_object(), name, *body, {}, 0, interpreter.lexical_environment(), interpreter.vm().running_execution_context().private_environment, FunctionKind::Regular, false, false); initializer->set_home_object(&target); } @@ -1248,9 +1250,10 @@ ThrowCompletionOr ClassField::class_element_evaluation ThrowCompletionOr StaticInitializer::class_element_evaluation(Interpreter& interpreter, GlobalObject& global_object, Object& home_object) const { auto* lexical_environment = interpreter.vm().running_execution_context().lexical_environment; + auto* private_scope = interpreter.vm().running_execution_context().private_environment; // Note: The function bodyFunction is never directly accessible to ECMAScript code. - auto* body_function = ECMAScriptFunctionObject::create(global_object, "", *m_function_body, {}, 0, lexical_environment, FunctionKind::Regular, true, false, m_contains_direct_call_to_eval, false); + auto* body_function = ECMAScriptFunctionObject::create(global_object, "", *m_function_body, {}, 0, lexical_environment, private_scope, FunctionKind::Regular, true, false, m_contains_direct_call_to_eval, false); body_function->set_home_object(&home_object); return ClassValue { normal_completion(body_function) }; @@ -1303,7 +1306,8 @@ ThrowCompletionOr ClassExpression::class_definition_evaluation(Interprete if (!binding_name.is_null()) MUST(class_scope->create_immutable_binding(global_object, binding_name, true)); - // FIXME: Add classPrivateEnvironment + auto* outer_private_environment = vm.running_execution_context().private_environment; + auto* class_private_environment = new_private_environment(vm, outer_private_environment); // FIXME: Append names to private environment @@ -1355,7 +1359,10 @@ ThrowCompletionOr ClassExpression::class_definition_evaluation(Interprete VERIFY(prototype); vm.running_execution_context().lexical_environment = class_scope; - // FIXME: Activate the class private environment + vm.running_execution_context().private_environment = class_private_environment; + ScopeGuard restore_private_environment = [&] { + vm.running_execution_context().private_environment = outer_private_environment; + }; // FIXME: Step 14.a is done in the parser. But maybe it shouldn't? Value class_constructor_value = m_constructor->execute(interpreter, global_object); @@ -3284,6 +3291,7 @@ void ScopeNode::block_declaration_instantiation(GlobalObject& global_object, Env { // See also B.3.2.6 Changes to BlockDeclarationInstantiation, https://tc39.es/ecma262/#sec-web-compat-blockdeclarationinstantiation VERIFY(environment); + auto* private_environment = global_object.vm().running_execution_context().private_environment; for_each_lexically_scoped_declaration([&](Declaration const& declaration) { auto is_constant_declaration = declaration.is_constant_declaration(); declaration.for_each_bound_name([&](auto const& name) { @@ -3297,7 +3305,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(), function_declaration.contains_direct_call_to_eval()); + auto* function = ECMAScriptFunctionObject::create(global_object, function_declaration.name(), function_declaration.body(), function_declaration.parameters(), function_declaration.function_length(), environment, private_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); } @@ -3424,6 +3432,8 @@ ThrowCompletionOr Program::global_declaration_instantiation(Interpreter& i declared_function_names.clear(); } + PrivateEnvironment* private_environment = nullptr; + for_each_lexically_scoped_declaration([&](Declaration const& declaration) { declaration.for_each_bound_name([&](auto const& name) { if (declaration.is_constant_declaration()) @@ -3440,7 +3450,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(), declaration.contains_direct_call_to_eval()); + auto* function = ECMAScriptFunctionObject::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), &global_environment, private_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/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 1b8a9b719b..3fb6dc9daa 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -353,7 +353,7 @@ void Call::execute_impl(Bytecode::Interpreter& interpreter) const void NewFunction::execute_impl(Bytecode::Interpreter& interpreter) const { 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.might_need_arguments_object(), 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(), vm.running_execution_context().private_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 diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index 59ec1ea8ab..2f17d0421f 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -107,6 +107,7 @@ set(SOURCES Runtime/ObjectEnvironment.cpp Runtime/ObjectPrototype.cpp Runtime/PrimitiveString.cpp + Runtime/PrivateEnvironment.cpp Runtime/Promise.cpp Runtime/PromiseConstructor.cpp Runtime/PromiseJobs.cpp diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index b3fdeb297d..6b6dc82baa 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -418,6 +418,11 @@ FunctionEnvironment* new_function_environment(ECMAScriptFunctionObject& function return env; } +PrivateEnvironment* new_private_environment(VM& vm, PrivateEnvironment* outer) +{ + return vm.heap().allocate(vm.current_realm()->global_object(), outer); +} + // 9.4.3 GetThisEnvironment ( ), https://tc39.es/ecma262/#sec-getthisenvironment Environment& get_this_environment(VM& vm) { @@ -490,12 +495,15 @@ ThrowCompletionOr perform_eval(Value x, GlobalObject& caller_realm, Calle Environment* lexical_environment; Environment* variable_environment; + PrivateEnvironment* private_environment; if (direct == EvalMode::Direct) { lexical_environment = new_declarative_environment(*running_context.lexical_environment); variable_environment = running_context.variable_environment; + private_environment = running_context.private_environment; } else { lexical_environment = new_declarative_environment(eval_realm->global_environment()); variable_environment = &eval_realm->global_environment(); + private_environment = nullptr; } if (strict_eval) @@ -515,13 +523,14 @@ ThrowCompletionOr perform_eval(Value x, GlobalObject& caller_realm, Calle eval_context.realm = eval_realm; eval_context.variable_environment = variable_environment; eval_context.lexical_environment = lexical_environment; + eval_context.private_environment = private_environment; vm.push_execution_context(eval_context, eval_realm->global_object()); ScopeGuard pop_guard = [&] { vm.pop_execution_context(); }; - TRY(eval_declaration_instantiation(vm, eval_realm->global_object(), program, variable_environment, lexical_environment, strict_eval)); + TRY(eval_declaration_instantiation(vm, eval_realm->global_object(), program, variable_environment, lexical_environment, private_environment, strict_eval)); auto& interpreter = vm.interpreter(); TemporaryChange scope_change_strict(vm.running_execution_context().is_strict_mode, strict_eval); @@ -535,7 +544,7 @@ ThrowCompletionOr perform_eval(Value x, GlobalObject& caller_realm, Calle } // 19.2.1.3 EvalDeclarationInstantiation ( body, varEnv, lexEnv, privateEnv, strict ), https://tc39.es/ecma262/#sec-evaldeclarationinstantiation -ThrowCompletionOr eval_declaration_instantiation(VM& vm, GlobalObject& global_object, Program const& program, Environment* variable_environment, Environment* lexical_environment, bool strict) +ThrowCompletionOr eval_declaration_instantiation(VM& vm, GlobalObject& global_object, Program const& program, Environment* variable_environment, Environment* lexical_environment, PrivateEnvironment* private_environment, bool strict) { // FIXME: I'm not sure if the global object is correct here. And this is quite a crucial spot! GlobalEnvironment* global_var_environment = variable_environment->is_global_environment() ? static_cast(variable_environment) : nullptr; @@ -572,6 +581,8 @@ ThrowCompletionOr eval_declaration_instantiation(VM& vm, GlobalObject& glo } } + // FIXME: Add Private identifiers check here. + HashTable declared_function_names; Vector functions_to_initialize; program.for_each_var_function_declaration_in_reverse_order([&](FunctionDeclaration const& function) { @@ -690,7 +701,7 @@ ThrowCompletionOr eval_declaration_instantiation(VM& vm, GlobalObject& glo return throw_completion(exception->value()); 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(), declaration.might_need_arguments_object()); + auto* function = ECMAScriptFunctionObject::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), lexical_environment, private_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object()); if (global_var_environment) { global_var_environment->create_global_function_binding(declaration.name(), function, true); if (auto* exception = vm.exception()) diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h index b70f0802ca..bb3f7ead8f 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace JS { @@ -17,6 +18,7 @@ namespace JS { DeclarativeEnvironment* new_declarative_environment(Environment&); ObjectEnvironment* new_object_environment(Object&, bool is_with_environment, Environment*); FunctionEnvironment* new_function_environment(ECMAScriptFunctionObject&, Object* new_target); +PrivateEnvironment* new_private_environment(VM& vm, PrivateEnvironment* outer); Environment& get_this_environment(VM&); Object* get_super_constructor(VM&); ThrowCompletionOr make_super_property_reference(GlobalObject&, Value actual_this, StringOrSymbol const& property_key, bool strict); @@ -45,7 +47,7 @@ enum class EvalMode { }; ThrowCompletionOr perform_eval(Value, GlobalObject&, CallerMode, EvalMode); -ThrowCompletionOr eval_declaration_instantiation(VM& vm, GlobalObject& global_object, Program const& program, Environment* variable_environment, Environment* lexical_environment, bool strict); +ThrowCompletionOr eval_declaration_instantiation(VM& vm, GlobalObject& global_object, Program const& program, Environment* variable_environment, Environment* lexical_environment, PrivateEnvironment* private_environment, bool strict); // 7.3.13 Call ( F, V [ , argumentsList ] ), https://tc39.es/ecma262/#sec-call template diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index bf1ee2a6a9..a0cee98063 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 contains_direct_call_to_eval, 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, PrivateEnvironment* private_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,12 +35,13 @@ 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, contains_direct_call_to_eval, is_arrow_function); + return global_object.heap().allocate(global_object, move(name), ecmascript_code, move(parameters), m_function_length, parent_scope, private_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 contains_direct_call_to_eval, bool is_arrow_function) +ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector formal_parameters, i32 function_length, Environment* parent_scope, PrivateEnvironment* private_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_private_environment(private_scope) , m_formal_parameters(move(formal_parameters)) , m_ecmascript_code(ecmascript_code) , m_realm(global_object().associated_realm()) @@ -540,9 +541,9 @@ ThrowCompletionOr ECMAScriptFunctionObject::function_declaration_instantia }); VERIFY(!vm.exception()); - + auto* private_environment = callee_context.private_environment; 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(), declaration.contains_direct_call_to_eval()); + auto* function = ECMAScriptFunctionObject::create(global_object(), declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), lex_environment, private_environment, declaration.kind(), declaration.is_strict_mode(), declaration.might_need_arguments_object(), declaration.contains_direct_call_to_eval()); MUST(var_environment->set_mutable_binding(global_object(), declaration.name(), function, false)); } @@ -595,7 +596,7 @@ void ECMAScriptFunctionObject::prepare_for_ordinary_call(ExecutionContext& calle callee_context.variable_environment = local_environment; // 10. Set the PrivateEnvironment of calleeContext to F.[[PrivateEnvironment]]. - // FIXME: We currently don't support private environments. + callee_context.private_environment = m_private_environment; // 11. If callerContext is not already suspended, suspend callerContext. // FIXME: We don't have this concept yet. diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.h index 29ae2767f9..b2ea1b472b 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 contains_direct_call_to_eval = 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, PrivateEnvironment* private_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 contains_direct_call_to_eval, bool is_arrow_function); + ECMAScriptFunctionObject(FlyString name, Statement const& ecmascript_code, Vector parameters, i32 m_function_length, Environment* parent_scope, PrivateEnvironment* private_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(); @@ -88,6 +88,7 @@ private: // Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects Environment* m_environment { nullptr }; // [[Environment]] + PrivateEnvironment* m_private_environment { nullptr }; // [[PrivateEnvironment]] Vector const m_formal_parameters; // [[FormalParameters]] NonnullRefPtr m_ecmascript_code; // [[ECMAScriptCode]] ConstructorKind m_constructor_kind { ConstructorKind::Base }; // [[ConstructorKind]] diff --git a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h index 6b0270b8af..344205b917 100644 --- a/Userland/Libraries/LibJS/Runtime/ExecutionContext.h +++ b/Userland/Libraries/LibJS/Runtime/ExecutionContext.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace JS { @@ -21,10 +22,11 @@ struct ExecutionContext { { } - FunctionObject* function { nullptr }; // [[Function]] - Realm* realm { nullptr }; // [[Realm]] - Environment* lexical_environment { nullptr }; // [[LexicalEnvironment]] - Environment* variable_environment { nullptr }; // [[VariableEnvironment]] + FunctionObject* function { nullptr }; // [[Function]] + Realm* realm { nullptr }; // [[Realm]] + Environment* lexical_environment { nullptr }; // [[LexicalEnvironment]] + Environment* variable_environment { nullptr }; // [[VariableEnvironment]] + PrivateEnvironment* private_environment { nullptr }; // [[PrivateEnvironment]] ASTNode const* current_node { nullptr }; FlyString function_name; diff --git a/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp index 34851e55b7..c164ba7678 100644 --- a/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/GeneratorFunctionConstructor.cpp @@ -62,7 +62,7 @@ Value GeneratorFunctionConstructor::construct(FunctionObject& new_target) 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(), function->might_need_arguments_object()); + return ECMAScriptFunctionObject::create(global_object(), function->name(), function->body(), function->parameters(), function->function_length(), vm().lexical_environment(), nullptr, FunctionKind::Generator, function->is_strict_mode(), function->might_need_arguments_object()); } } diff --git a/Userland/Libraries/LibJS/Runtime/PrivateEnvironment.cpp b/Userland/Libraries/LibJS/Runtime/PrivateEnvironment.cpp new file mode 100644 index 0000000000..1d1b016cf7 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/PrivateEnvironment.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, David Tuin + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace JS { + +PrivateEnvironment::PrivateEnvironment(PrivateEnvironment* parent) + : m_outer_environment(parent) + , m_unique_id(s_next_id++) +{ + // FIXME: We might want to delay getting the next unique id until required. + VERIFY(s_next_id != 0); +} + +// Note: we start at one such that 0 can be invalid / default initialized. +u64 PrivateEnvironment::s_next_id = 1u; + +PrivateName PrivateEnvironment::resolve_private_identifier(FlyString const& identifier) const +{ + auto name_or_end = find_private_name(identifier); + + if (!name_or_end.is_end()) + return *name_or_end; + + // Note: This verify ensures that we must either have a private name with a matching description + // or have an outer environment. Combined this means that we assert that we always return a PrivateName. + VERIFY(m_outer_environment); + return m_outer_environment->resolve_private_identifier(identifier); +} + +void PrivateEnvironment::add_private_name(Badge, FlyString description) +{ + // FIXME: there is a exception for getter setter pairs. + VERIFY(find_private_name(description).is_end()); + m_private_names.empend(m_unique_id, move(description)); +} + +bool PrivateName::operator==(PrivateName const& rhs) const +{ + return unique_id == rhs.unique_id && description == rhs.description; +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/PrivateEnvironment.h b/Userland/Libraries/LibJS/Runtime/PrivateEnvironment.h new file mode 100644 index 0000000000..92266f35fe --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/PrivateEnvironment.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021, David Tuin + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace JS { + +struct PrivateName { + PrivateName(u64 unique_id, FlyString description) + : unique_id(unique_id) + , description(move(description)) + { + } + + u64 unique_id { 0 }; + FlyString description; + + bool operator==(PrivateName const& rhs) const; +}; + +class PrivateEnvironment : public Cell { +public: + explicit PrivateEnvironment(PrivateEnvironment* parent); + + PrivateName resolve_private_identifier(FlyString const& identifier) const; + + void add_private_name(Badge, FlyString description); + +private: + virtual char const* class_name() const override { return "PrivateEnvironment"; } + + auto find_private_name(FlyString const& description) const + { + return m_private_names.find_if([&](PrivateName const& private_name) { + return private_name.description == description; + }); + } + + static u64 s_next_id; + + PrivateEnvironment* m_outer_environment { nullptr }; // [[OuterEnv]] + Vector m_private_names; // [[Names]] + u64 m_unique_id; +}; + +} diff --git a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp index 02ec8a3ab5..cdc584605b 100644 --- a/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp +++ b/Userland/Libraries/LibJS/Runtime/ShadowRealm.cpp @@ -108,7 +108,7 @@ ThrowCompletionOr perform_shadow_realm_eval(GlobalObject& global_object, vm.push_execution_context(eval_context, eval_realm.global_object()); // 19. Let result be EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval). - auto eval_result = eval_declaration_instantiation(vm, eval_realm.global_object(), program, variable_environment, lexical_environment, strict_eval); + auto eval_result = eval_declaration_instantiation(vm, eval_realm.global_object(), program, variable_environment, lexical_environment, nullptr, strict_eval); Completion result; diff --git a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp index ab81383542..b57108dd75 100644 --- a/Userland/Libraries/LibWeb/DOM/EventTarget.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventTarget.cpp @@ -134,7 +134,7 @@ void EventTarget::set_event_handler_attribute(FlyString const& name, HTML::Event dbgln("Failed to parse script in event handler attribute '{}'", name); return; } - auto* function = JS::ECMAScriptFunctionObject::create(target->script_execution_context()->realm().global_object(), name, program->body(), program->parameters(), program->function_length(), nullptr, JS::FunctionKind::Regular, false, false); + auto* function = JS::ECMAScriptFunctionObject::create(target->script_execution_context()->realm().global_object(), name, program->body(), program->parameters(), program->function_length(), nullptr, nullptr, JS::FunctionKind::Regular, false, false); VERIFY(function); listener = adopt_ref(*new DOM::EventListener(JS::make_handle(static_cast(function)), true)); }