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:
parent
5dd5896588
commit
b99cc7d050
178 changed files with 883 additions and 609 deletions
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue