mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 08:07:44 +00:00
LibJS: Add PrivateEnvironment
This commit is contained in:
parent
eeb42c21d1
commit
13ead80ee6
13 changed files with 154 additions and 27 deletions
|
@ -418,6 +418,11 @@ FunctionEnvironment* new_function_environment(ECMAScriptFunctionObject& function
|
|||
return env;
|
||||
}
|
||||
|
||||
PrivateEnvironment* new_private_environment(VM& vm, PrivateEnvironment* outer)
|
||||
{
|
||||
return vm.heap().allocate<PrivateEnvironment>(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<Value> 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<Value> 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<Value> 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<void> eval_declaration_instantiation(VM& vm, GlobalObject& global_object, Program const& program, Environment* variable_environment, Environment* lexical_environment, bool strict)
|
||||
ThrowCompletionOr<void> 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<GlobalEnvironment*>(variable_environment) : nullptr;
|
||||
|
@ -572,6 +581,8 @@ ThrowCompletionOr<void> eval_declaration_instantiation(VM& vm, GlobalObject& glo
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Add Private identifiers check here.
|
||||
|
||||
HashTable<FlyString> declared_function_names;
|
||||
Vector<FunctionDeclaration const&> functions_to_initialize;
|
||||
program.for_each_var_function_declaration_in_reverse_order([&](FunctionDeclaration const& function) {
|
||||
|
@ -690,7 +701,7 @@ ThrowCompletionOr<void> 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())
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/GlobalObject.h>
|
||||
#include <LibJS/Runtime/PrivateEnvironment.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
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<Reference> make_super_property_reference(GlobalObject&, Value actual_this, StringOrSymbol const& property_key, bool strict);
|
||||
|
@ -45,7 +47,7 @@ enum class EvalMode {
|
|||
};
|
||||
ThrowCompletionOr<Value> perform_eval(Value, GlobalObject&, CallerMode, EvalMode);
|
||||
|
||||
ThrowCompletionOr<void> eval_declaration_instantiation(VM& vm, GlobalObject& global_object, Program const& program, Environment* variable_environment, Environment* lexical_environment, bool strict);
|
||||
ThrowCompletionOr<void> 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<typename... Args>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
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 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<FunctionNode::Parameter> 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<ECMAScriptFunctionObject>(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<ECMAScriptFunctionObject>(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<FunctionNode::Parameter> 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<FunctionNode::Parameter> 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<void> 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.
|
||||
|
|
|
@ -28,9 +28,9 @@ public:
|
|||
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 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<FunctionNode::Parameter> 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<FunctionNode::Parameter> 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<FunctionNode::Parameter> 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<FunctionNode::Parameter> const m_formal_parameters; // [[FormalParameters]]
|
||||
NonnullRefPtr<Statement> m_ecmascript_code; // [[ECMAScriptCode]]
|
||||
ConstructorKind m_constructor_kind { ConstructorKind::Base }; // [[ConstructorKind]]
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/FlyString.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/MarkedValueList.h>
|
||||
#include <LibJS/Runtime/PrivateEnvironment.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
47
Userland/Libraries/LibJS/Runtime/PrivateEnvironment.cpp
Normal file
47
Userland/Libraries/LibJS/Runtime/PrivateEnvironment.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/PrivateEnvironment.h>
|
||||
|
||||
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<ClassExpression>, 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;
|
||||
}
|
||||
|
||||
}
|
52
Userland/Libraries/LibJS/Runtime/PrivateEnvironment.h
Normal file
52
Userland/Libraries/LibJS/Runtime/PrivateEnvironment.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2021, David Tuin <davidot@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
|
||||
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<ClassExpression>, 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<PrivateName> m_private_names; // [[Names]]
|
||||
u64 m_unique_id;
|
||||
};
|
||||
|
||||
}
|
|
@ -108,7 +108,7 @@ ThrowCompletionOr<Value> 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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue