1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-29 01:22:11 +00:00

LibJS+LibWeb: Replace GlobalObject with Realm in create() functions

This is a continuation of the previous two commits.

As allocating a JS cell already primarily involves a realm instead of a
global object, and we'll need to pass one to the allocate() function
itself eventually (it's bridged via the global object right now), the
create() functions need to receive a realm as well.
The plan is for this to be the highest-level function that actually
receives a realm and passes it around, AOs on an even higher level will
use the "current realm" concept via VM::current_realm() as that's what
the spec assumes; passing around realms (or global objects, for that
matter) on higher AO levels is pointless and unlike for allocating
individual objects, which may happen outside of regular JS execution, we
don't need control over the specific realm that is being used there.
This commit is contained in:
Linus Groh 2022-08-16 00:20:49 +01:00
parent 5dd5896588
commit b99cc7d050
178 changed files with 883 additions and 609 deletions

View file

@ -28,29 +28,29 @@
namespace JS {
ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, String source_text, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(Realm& realm, FlyString name, String source_text, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
{
Object* prototype = nullptr;
switch (kind) {
case FunctionKind::Normal:
prototype = global_object.function_prototype();
prototype = realm.global_object().function_prototype();
break;
case FunctionKind::Generator:
prototype = global_object.generator_function_prototype();
prototype = realm.global_object().generator_function_prototype();
break;
case FunctionKind::Async:
prototype = global_object.async_function_prototype();
prototype = realm.global_object().async_function_prototype();
break;
case FunctionKind::AsyncGenerator:
prototype = global_object.async_generator_function_prototype();
prototype = realm.global_object().async_generator_function_prototype();
break;
}
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, parent_environment, private_environment, *prototype, kind, is_strict, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(class_field_initializer_name));
return realm.heap().allocate<ECMAScriptFunctionObject>(realm.global_object(), move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, parent_environment, private_environment, *prototype, kind, is_strict, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(class_field_initializer_name));
}
ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(GlobalObject& global_object, FlyString name, Object& prototype, String source_text, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
ECMAScriptFunctionObject* ECMAScriptFunctionObject::create(Realm& realm, FlyString name, Object& prototype, String source_text, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> parameters, i32 m_function_length, Environment* parent_environment, PrivateEnvironment* private_environment, FunctionKind kind, bool is_strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
{
return global_object.heap().allocate<ECMAScriptFunctionObject>(global_object, move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, parent_environment, private_environment, prototype, kind, is_strict, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(class_field_initializer_name));
return realm.heap().allocate<ECMAScriptFunctionObject>(realm.global_object(), move(name), move(source_text), ecmascript_code, move(parameters), m_function_length, parent_environment, private_environment, prototype, kind, is_strict, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function, move(class_field_initializer_name));
}
ECMAScriptFunctionObject::ECMAScriptFunctionObject(FlyString name, String source_text, Statement const& ecmascript_code, Vector<FunctionNode::Parameter> formal_parameters, i32 function_length, Environment* parent_environment, PrivateEnvironment* private_environment, Object& prototype, FunctionKind kind, bool strict, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function, Variant<PropertyKey, PrivateName, Empty> class_field_initializer_name)
@ -119,12 +119,12 @@ void ECMAScriptFunctionObject::initialize(Realm& realm)
break;
case FunctionKind::Generator:
// prototype is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
prototype = Object::create(realm.global_object(), realm.global_object().generator_function_prototype_prototype());
prototype = Object::create(realm, realm.global_object().generator_function_prototype_prototype());
break;
case FunctionKind::Async:
break;
case FunctionKind::AsyncGenerator:
prototype = Object::create(realm.global_object(), realm.global_object().async_generator_function_prototype_prototype());
prototype = Object::create(realm, realm.global_object().async_generator_function_prototype_prototype());
break;
}
// 27.7.4 AsyncFunction Instances, https://tc39.es/ecma262/#sec-async-function-instances
@ -319,6 +319,8 @@ void ECMAScriptFunctionObject::make_method(Object& home_object)
ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantiation(Interpreter* interpreter)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto& realm = *global_object.associated_realm();
auto& callee_context = vm.running_execution_context();
@ -399,24 +401,24 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
if (MUST(environment->has_binding(parameter_name)))
continue;
MUST(environment->create_mutable_binding(global_object(), parameter_name, false));
MUST(environment->create_mutable_binding(global_object, parameter_name, false));
if (has_duplicates)
MUST(environment->initialize_binding(global_object(), parameter_name, js_undefined()));
MUST(environment->initialize_binding(global_object, parameter_name, js_undefined()));
}
if (arguments_object_needed) {
Object* arguments_object;
if (is_strict_mode() || !has_simple_parameter_list())
arguments_object = create_unmapped_arguments_object(global_object(), vm.running_execution_context().arguments);
arguments_object = create_unmapped_arguments_object(global_object, vm.running_execution_context().arguments);
else
arguments_object = create_mapped_arguments_object(global_object(), *this, formal_parameters(), vm.running_execution_context().arguments, *environment);
arguments_object = create_mapped_arguments_object(global_object, *this, formal_parameters(), vm.running_execution_context().arguments, *environment);
if (is_strict_mode())
MUST(environment->create_immutable_binding(global_object(), vm.names.arguments.as_string(), false));
MUST(environment->create_immutable_binding(global_object, vm.names.arguments.as_string(), false));
else
MUST(environment->create_mutable_binding(global_object(), vm.names.arguments.as_string(), false));
MUST(environment->create_mutable_binding(global_object, vm.names.arguments.as_string(), false));
MUST(environment->initialize_binding(global_object(), vm.names.arguments.as_string(), arguments_object));
MUST(environment->initialize_binding(global_object, vm.names.arguments.as_string(), arguments_object));
parameter_names.set(vm.names.arguments.as_string());
}
@ -435,7 +437,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
[&](auto const& param) -> ThrowCompletionOr<void> {
Value argument_value;
if (parameter.is_rest) {
auto* array = MUST(Array::create(global_object(), 0));
auto* array = MUST(Array::create(realm, 0));
for (size_t rest_index = i; rest_index < execution_context_arguments.size(); ++rest_index)
array->indexed_properties().append(execution_context_arguments[rest_index]);
argument_value = array;
@ -449,7 +451,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
// Resulting value is in the accumulator.
argument_value = value_and_frame.frame->registers.at(0);
} else if (interpreter) {
argument_value = TRY(parameter.default_value->execute(*interpreter, global_object())).release_value();
argument_value = TRY(parameter.default_value->execute(*interpreter, global_object)).release_value();
}
} else {
argument_value = js_undefined();
@ -461,12 +463,12 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
Reference reference = TRY(vm.resolve_binding(param, used_environment));
// Here the difference from hasDuplicates is important
if (has_duplicates)
return reference.put_value(global_object(), argument_value);
return reference.put_value(global_object, argument_value);
else
return reference.initialize_referenced_binding(global_object(), argument_value);
return reference.initialize_referenced_binding(global_object, argument_value);
} else if (IsSame<NonnullRefPtr<BindingPattern> const&, decltype(param)>) {
// Here the difference from hasDuplicates is important
return vm.binding_initialization(param, argument_value, used_environment, global_object());
return vm.binding_initialization(param, argument_value, used_environment, global_object);
}
}));
}
@ -481,8 +483,8 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
if (scope_body) {
scope_body->for_each_var_declared_name([&](auto const& name) {
if (!parameter_names.contains(name) && instantiated_var_names.set(name) == AK::HashSetResult::InsertedNewEntry) {
MUST(environment->create_mutable_binding(global_object(), name, false));
MUST(environment->initialize_binding(global_object(), name, js_undefined()));
MUST(environment->create_mutable_binding(global_object, name, false));
MUST(environment->initialize_binding(global_object, name, js_undefined()));
}
});
}
@ -495,15 +497,15 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
scope_body->for_each_var_declared_name([&](auto const& name) {
if (instantiated_var_names.set(name) != AK::HashSetResult::InsertedNewEntry)
return;
MUST(var_environment->create_mutable_binding(global_object(), name, false));
MUST(var_environment->create_mutable_binding(global_object, name, false));
Value initial_value;
if (!parameter_names.contains(name) || function_names.contains(name))
initial_value = js_undefined();
else
initial_value = MUST(environment->get_binding_value(global_object(), name, false));
initial_value = MUST(environment->get_binding_value(global_object, name, false));
MUST(var_environment->initialize_binding(global_object(), name, initial_value));
MUST(var_environment->initialize_binding(global_object, name, initial_value));
});
}
}
@ -516,8 +518,8 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
return;
// The spec says 'initializedBindings' here but that does not exist and it then adds it to 'instantiatedVarNames' so it probably means 'instantiatedVarNames'.
if (!instantiated_var_names.contains(function_name) && function_name != vm.names.arguments.as_string()) {
MUST(var_environment->create_mutable_binding(global_object(), function_name, false));
MUST(var_environment->initialize_binding(global_object(), function_name, js_undefined()));
MUST(var_environment->create_mutable_binding(global_object, function_name, false));
MUST(var_environment->initialize_binding(global_object, function_name, js_undefined()));
instantiated_var_names.set(function_name);
}
@ -558,17 +560,17 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
scope_body->for_each_lexically_scoped_declaration([&](Declaration const& declaration) {
declaration.for_each_bound_name([&](auto const& name) {
if (declaration.is_constant_declaration())
MUST(lex_environment->create_immutable_binding(global_object(), name, true));
MUST(lex_environment->create_immutable_binding(global_object, name, true));
else
MUST(lex_environment->create_mutable_binding(global_object(), name, false));
MUST(lex_environment->create_mutable_binding(global_object, name, false));
});
});
}
auto* private_environment = callee_context.private_environment;
for (auto& declaration : functions_to_initialize) {
auto* function = ECMAScriptFunctionObject::create(global_object(), declaration.name(), declaration.source_text(), 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));
auto* function = ECMAScriptFunctionObject::create(realm, declaration.name(), declaration.source_text(), 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));
}
return {};
@ -717,14 +719,16 @@ void ECMAScriptFunctionObject::async_function_start(PromiseCapability const& pro
// 27.7.5.2 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext ), https://tc39.es/ecma262/#sec-asyncblockstart
void async_block_start(VM& vm, NonnullRefPtr<Statement> const& async_body, PromiseCapability const& promise_capability, ExecutionContext& async_context)
{
auto& global_object = vm.current_realm()->global_object();
auto& realm = *vm.current_realm();
auto& global_object = realm.global_object();
// 1. Assert: promiseCapability is a PromiseCapability Record.
// 2. Let runningContext be the running execution context.
auto& running_context = vm.running_execution_context();
// 3. Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution context the following steps will be performed:
auto* execution_steps = NativeFunction::create(global_object, "", [&async_body, &promise_capability](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
auto* execution_steps = NativeFunction::create(realm, "", [&async_body, &promise_capability](auto& vm, auto& global_object) -> ThrowCompletionOr<Value> {
// a. Let result be the result of evaluating asyncBody.
auto result = async_body->execute(vm.interpreter(), global_object);
@ -778,10 +782,12 @@ void async_block_start(VM& vm, NonnullRefPtr<Statement> const& async_body, Promi
Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto& realm = *global_object.associated_realm();
auto* bytecode_interpreter = Bytecode::Interpreter::current();
if (m_kind == FunctionKind::AsyncGenerator)
return vm.throw_completion<InternalError>(global_object(), ErrorType::NotImplemented, "Async Generator function execution");
return vm.throw_completion<InternalError>(global_object, ErrorType::NotImplemented, "Async Generator function execution");
if (bytecode_interpreter) {
if (!m_bytecode_executable) {
@ -828,23 +834,23 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
if (m_kind == FunctionKind::Normal)
return { Completion::Type::Return, result.value_or(js_undefined()), {} };
auto generator_object = TRY(GeneratorObject::create(global_object(), result, this, vm.running_execution_context().copy(), move(*result_and_frame.frame)));
auto generator_object = TRY(GeneratorObject::create(realm, result, this, vm.running_execution_context().copy(), move(*result_and_frame.frame)));
// NOTE: Async functions are entirely transformed to generator functions, and wrapped in a custom driver that returns a promise
// See AwaitExpression::generate_bytecode() for the transformation.
if (m_kind == FunctionKind::Async)
return { Completion::Type::Return, TRY(AsyncFunctionDriverWrapper::create(global_object(), generator_object)), {} };
return { Completion::Type::Return, TRY(AsyncFunctionDriverWrapper::create(realm, generator_object)), {} };
VERIFY(m_kind == FunctionKind::Generator);
return { Completion::Type::Return, generator_object, {} };
} else {
if (m_kind == FunctionKind::Generator)
return vm.throw_completion<InternalError>(global_object(), ErrorType::NotImplemented, "Generator function execution in AST interpreter");
return vm.throw_completion<InternalError>(global_object, ErrorType::NotImplemented, "Generator function execution in AST interpreter");
OwnPtr<Interpreter> local_interpreter;
Interpreter* ast_interpreter = vm.interpreter_if_exists();
if (!ast_interpreter) {
local_interpreter = Interpreter::create_with_existing_realm(*realm());
local_interpreter = Interpreter::create_with_existing_realm(realm);
ast_interpreter = local_interpreter.ptr();
}
@ -856,12 +862,12 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
TRY(function_declaration_instantiation(ast_interpreter));
// 2. Return the result of evaluating FunctionStatementList.
return m_ecmascript_code->execute(*ast_interpreter, global_object());
return m_ecmascript_code->execute(*ast_interpreter, global_object);
}
// AsyncFunctionBody : FunctionBody
else if (m_kind == FunctionKind::Async) {
// 1. Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promise_capability = MUST(new_promise_capability(global_object(), global_object().promise_constructor()));
auto promise_capability = MUST(new_promise_capability(global_object, global_object.promise_constructor()));
// 2. Let declResult be Completion(FunctionDeclarationInstantiation(functionObject, argumentsList)).
auto declaration_result = function_declaration_instantiation(ast_interpreter);
@ -869,7 +875,7 @@ Completion ECMAScriptFunctionObject::ordinary_call_evaluate_body()
// 3. If declResult is an abrupt completion, then
if (declaration_result.is_throw_completion()) {
// a. Perform ! Call(promiseCapability.[[Reject]], undefined, « declResult.[[Value]] »).
MUST(call(global_object(), promise_capability.reject, js_undefined(), *declaration_result.throw_completion().value()));
MUST(call(global_object, promise_capability.reject, js_undefined(), *declaration_result.throw_completion().value()));
}
// 4. Else,
else {