mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:57:43 +00:00
LibJS: Add PrivateEnvironment
This commit is contained in:
parent
eeb42c21d1
commit
13ead80ee6
13 changed files with 154 additions and 27 deletions
|
@ -199,7 +199,9 @@ Value FunctionExpression::instantiate_ordinary_function_expression(Interpreter&
|
||||||
MUST(scope->create_immutable_binding(global_object, name(), false));
|
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: 6. Perform SetFunctionName(closure, name).
|
||||||
// FIXME: 7. Perform MakeConstructor(closure).
|
// FIXME: 7. Perform MakeConstructor(closure).
|
||||||
|
@ -1232,7 +1234,7 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation
|
||||||
auto body = create_ast_node<ExpressionStatement>(m_initializer->source_range(), copy_initializer.release_nonnull());
|
auto body = create_ast_node<ExpressionStatement>(m_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.
|
||||||
auto name = property_key.is_number() ? property_key.to_string() : property_key.to_string_or_symbol().to_display_string();
|
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);
|
initializer->set_home_object(&target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1248,9 +1250,10 @@ ThrowCompletionOr<ClassElement::ClassValue> ClassField::class_element_evaluation
|
||||||
ThrowCompletionOr<ClassElement::ClassValue> StaticInitializer::class_element_evaluation(Interpreter& interpreter, GlobalObject& global_object, Object& home_object) const
|
ThrowCompletionOr<ClassElement::ClassValue> StaticInitializer::class_element_evaluation(Interpreter& interpreter, GlobalObject& global_object, Object& home_object) const
|
||||||
{
|
{
|
||||||
auto* lexical_environment = interpreter.vm().running_execution_context().lexical_environment;
|
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.
|
// 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);
|
body_function->set_home_object(&home_object);
|
||||||
|
|
||||||
return ClassValue { normal_completion(body_function) };
|
return ClassValue { normal_completion(body_function) };
|
||||||
|
@ -1303,7 +1306,8 @@ ThrowCompletionOr<Value> ClassExpression::class_definition_evaluation(Interprete
|
||||||
if (!binding_name.is_null())
|
if (!binding_name.is_null())
|
||||||
MUST(class_scope->create_immutable_binding(global_object, binding_name, true));
|
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
|
// FIXME: Append names to private environment
|
||||||
|
|
||||||
|
@ -1355,7 +1359,10 @@ ThrowCompletionOr<Value> ClassExpression::class_definition_evaluation(Interprete
|
||||||
VERIFY(prototype);
|
VERIFY(prototype);
|
||||||
|
|
||||||
vm.running_execution_context().lexical_environment = class_scope;
|
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?
|
// FIXME: Step 14.a is done in the parser. But maybe it shouldn't?
|
||||||
Value class_constructor_value = m_constructor->execute(interpreter, global_object);
|
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
|
// See also B.3.2.6 Changes to BlockDeclarationInstantiation, https://tc39.es/ecma262/#sec-web-compat-blockdeclarationinstantiation
|
||||||
VERIFY(environment);
|
VERIFY(environment);
|
||||||
|
auto* private_environment = global_object.vm().running_execution_context().private_environment;
|
||||||
for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
|
for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
|
||||||
auto is_constant_declaration = declaration.is_constant_declaration();
|
auto is_constant_declaration = declaration.is_constant_declaration();
|
||||||
declaration.for_each_bound_name([&](auto const& name) {
|
declaration.for_each_bound_name([&](auto const& name) {
|
||||||
|
@ -3297,7 +3305,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(), 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<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);
|
||||||
}
|
}
|
||||||
|
@ -3424,6 +3432,8 @@ ThrowCompletionOr<void> Program::global_declaration_instantiation(Interpreter& i
|
||||||
declared_function_names.clear();
|
declared_function_names.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrivateEnvironment* private_environment = nullptr;
|
||||||
|
|
||||||
for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
|
for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
|
||||||
declaration.for_each_bound_name([&](auto const& name) {
|
declaration.for_each_bound_name([&](auto const& name) {
|
||||||
if (declaration.is_constant_declaration())
|
if (declaration.is_constant_declaration())
|
||||||
|
@ -3440,7 +3450,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(), 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);
|
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());
|
||||||
|
|
|
@ -353,7 +353,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.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
|
void Return::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
|
|
|
@ -107,6 +107,7 @@ set(SOURCES
|
||||||
Runtime/ObjectEnvironment.cpp
|
Runtime/ObjectEnvironment.cpp
|
||||||
Runtime/ObjectPrototype.cpp
|
Runtime/ObjectPrototype.cpp
|
||||||
Runtime/PrimitiveString.cpp
|
Runtime/PrimitiveString.cpp
|
||||||
|
Runtime/PrivateEnvironment.cpp
|
||||||
Runtime/Promise.cpp
|
Runtime/Promise.cpp
|
||||||
Runtime/PromiseConstructor.cpp
|
Runtime/PromiseConstructor.cpp
|
||||||
Runtime/PromiseJobs.cpp
|
Runtime/PromiseJobs.cpp
|
||||||
|
|
|
@ -418,6 +418,11 @@ FunctionEnvironment* new_function_environment(ECMAScriptFunctionObject& function
|
||||||
return env;
|
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
|
// 9.4.3 GetThisEnvironment ( ), https://tc39.es/ecma262/#sec-getthisenvironment
|
||||||
Environment& get_this_environment(VM& vm)
|
Environment& get_this_environment(VM& vm)
|
||||||
{
|
{
|
||||||
|
@ -490,12 +495,15 @@ ThrowCompletionOr<Value> perform_eval(Value x, GlobalObject& caller_realm, Calle
|
||||||
|
|
||||||
Environment* lexical_environment;
|
Environment* lexical_environment;
|
||||||
Environment* variable_environment;
|
Environment* variable_environment;
|
||||||
|
PrivateEnvironment* private_environment;
|
||||||
if (direct == EvalMode::Direct) {
|
if (direct == EvalMode::Direct) {
|
||||||
lexical_environment = new_declarative_environment(*running_context.lexical_environment);
|
lexical_environment = new_declarative_environment(*running_context.lexical_environment);
|
||||||
variable_environment = running_context.variable_environment;
|
variable_environment = running_context.variable_environment;
|
||||||
|
private_environment = running_context.private_environment;
|
||||||
} else {
|
} else {
|
||||||
lexical_environment = new_declarative_environment(eval_realm->global_environment());
|
lexical_environment = new_declarative_environment(eval_realm->global_environment());
|
||||||
variable_environment = &eval_realm->global_environment();
|
variable_environment = &eval_realm->global_environment();
|
||||||
|
private_environment = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strict_eval)
|
if (strict_eval)
|
||||||
|
@ -515,13 +523,14 @@ ThrowCompletionOr<Value> perform_eval(Value x, GlobalObject& caller_realm, Calle
|
||||||
eval_context.realm = eval_realm;
|
eval_context.realm = eval_realm;
|
||||||
eval_context.variable_environment = variable_environment;
|
eval_context.variable_environment = variable_environment;
|
||||||
eval_context.lexical_environment = lexical_environment;
|
eval_context.lexical_environment = lexical_environment;
|
||||||
|
eval_context.private_environment = private_environment;
|
||||||
vm.push_execution_context(eval_context, eval_realm->global_object());
|
vm.push_execution_context(eval_context, eval_realm->global_object());
|
||||||
|
|
||||||
ScopeGuard pop_guard = [&] {
|
ScopeGuard pop_guard = [&] {
|
||||||
vm.pop_execution_context();
|
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();
|
auto& interpreter = vm.interpreter();
|
||||||
TemporaryChange scope_change_strict(vm.running_execution_context().is_strict_mode, strict_eval);
|
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
|
// 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!
|
// 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;
|
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;
|
HashTable<FlyString> declared_function_names;
|
||||||
Vector<FunctionDeclaration const&> functions_to_initialize;
|
Vector<FunctionDeclaration const&> functions_to_initialize;
|
||||||
program.for_each_var_function_declaration_in_reverse_order([&](FunctionDeclaration const& function) {
|
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());
|
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(), 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) {
|
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())
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <LibJS/AST.h>
|
#include <LibJS/AST.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
#include <LibJS/Runtime/PrivateEnvironment.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -17,6 +18,7 @@ namespace JS {
|
||||||
DeclarativeEnvironment* new_declarative_environment(Environment&);
|
DeclarativeEnvironment* new_declarative_environment(Environment&);
|
||||||
ObjectEnvironment* new_object_environment(Object&, bool is_with_environment, Environment*);
|
ObjectEnvironment* new_object_environment(Object&, bool is_with_environment, Environment*);
|
||||||
FunctionEnvironment* new_function_environment(ECMAScriptFunctionObject&, Object* new_target);
|
FunctionEnvironment* new_function_environment(ECMAScriptFunctionObject&, Object* new_target);
|
||||||
|
PrivateEnvironment* new_private_environment(VM& vm, PrivateEnvironment* outer);
|
||||||
Environment& get_this_environment(VM&);
|
Environment& get_this_environment(VM&);
|
||||||
Object* get_super_constructor(VM&);
|
Object* get_super_constructor(VM&);
|
||||||
ThrowCompletionOr<Reference> make_super_property_reference(GlobalObject&, Value actual_this, StringOrSymbol const& property_key, bool strict);
|
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<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
|
// 7.3.13 Call ( F, V [ , argumentsList ] ), https://tc39.es/ecma262/#sec-call
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
|
|
|
@ -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 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;
|
Object* prototype = nullptr;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
@ -35,12 +35,13 @@ 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, 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)
|
: FunctionObject(prototype)
|
||||||
, m_environment(parent_scope)
|
, m_environment(parent_scope)
|
||||||
|
, m_private_environment(private_scope)
|
||||||
, m_formal_parameters(move(formal_parameters))
|
, m_formal_parameters(move(formal_parameters))
|
||||||
, m_ecmascript_code(ecmascript_code)
|
, m_ecmascript_code(ecmascript_code)
|
||||||
, m_realm(global_object().associated_realm())
|
, m_realm(global_object().associated_realm())
|
||||||
|
@ -540,9 +541,9 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
||||||
});
|
});
|
||||||
|
|
||||||
VERIFY(!vm.exception());
|
VERIFY(!vm.exception());
|
||||||
|
auto* private_environment = callee_context.private_environment;
|
||||||
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(), 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));
|
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;
|
callee_context.variable_environment = local_environment;
|
||||||
|
|
||||||
// 10. Set the PrivateEnvironment of calleeContext to F.[[PrivateEnvironment]].
|
// 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.
|
// 11. If callerContext is not already suspended, suspend callerContext.
|
||||||
// FIXME: We don't have this concept yet.
|
// FIXME: We don't have this concept yet.
|
||||||
|
|
|
@ -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 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 void initialize(GlobalObject&) override;
|
||||||
virtual ~ECMAScriptFunctionObject();
|
virtual ~ECMAScriptFunctionObject();
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ private:
|
||||||
|
|
||||||
// Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects
|
// Internal Slots of ECMAScript Function Objects, https://tc39.es/ecma262/#table-internal-slots-of-ecmascript-function-objects
|
||||||
Environment* m_environment { nullptr }; // [[Environment]]
|
Environment* m_environment { nullptr }; // [[Environment]]
|
||||||
|
PrivateEnvironment* m_private_environment { nullptr }; // [[PrivateEnvironment]]
|
||||||
Vector<FunctionNode::Parameter> const m_formal_parameters; // [[FormalParameters]]
|
Vector<FunctionNode::Parameter> const m_formal_parameters; // [[FormalParameters]]
|
||||||
NonnullRefPtr<Statement> m_ecmascript_code; // [[ECMAScriptCode]]
|
NonnullRefPtr<Statement> m_ecmascript_code; // [[ECMAScriptCode]]
|
||||||
ConstructorKind m_constructor_kind { ConstructorKind::Base }; // [[ConstructorKind]]
|
ConstructorKind m_constructor_kind { ConstructorKind::Base }; // [[ConstructorKind]]
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Runtime/MarkedValueList.h>
|
#include <LibJS/Runtime/MarkedValueList.h>
|
||||||
|
#include <LibJS/Runtime/PrivateEnvironment.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -21,10 +22,11 @@ struct ExecutionContext {
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionObject* function { nullptr }; // [[Function]]
|
FunctionObject* function { nullptr }; // [[Function]]
|
||||||
Realm* realm { nullptr }; // [[Realm]]
|
Realm* realm { nullptr }; // [[Realm]]
|
||||||
Environment* lexical_environment { nullptr }; // [[LexicalEnvironment]]
|
Environment* lexical_environment { nullptr }; // [[LexicalEnvironment]]
|
||||||
Environment* variable_environment { nullptr }; // [[VariableEnvironment]]
|
Environment* variable_environment { nullptr }; // [[VariableEnvironment]]
|
||||||
|
PrivateEnvironment* private_environment { nullptr }; // [[PrivateEnvironment]]
|
||||||
|
|
||||||
ASTNode const* current_node { nullptr };
|
ASTNode const* current_node { nullptr };
|
||||||
FlyString function_name;
|
FlyString function_name;
|
||||||
|
|
|
@ -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(), 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());
|
vm.push_execution_context(eval_context, eval_realm.global_object());
|
||||||
|
|
||||||
// 19. Let result be EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval).
|
// 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;
|
Completion result;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
dbgln("Failed to parse script in event handler attribute '{}'", name);
|
||||||
return;
|
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);
|
VERIFY(function);
|
||||||
listener = adopt_ref(*new DOM::EventListener(JS::make_handle(static_cast<JS::FunctionObject*>(function)), true));
|
listener = adopt_ref(*new DOM::EventListener(JS::make_handle(static_cast<JS::FunctionObject*>(function)), true));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue