mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 18:07:34 +00:00
LibJS: Always allocate ExecutionContext objects on the malloc heap
Instead of allocating these in a mixture of ways, we now always put them on the malloc heap, and keep an intrusive linked list of them that we can iterate for GC marking purposes.
This commit is contained in:
parent
845da3901d
commit
3dc5f467a8
38 changed files with 251 additions and 217 deletions
|
@ -638,31 +638,31 @@ ThrowCompletionOr<Value> perform_eval(VM& vm, Value x, CallerMode strict_caller,
|
|||
// FIXME: We don't have this concept yet.
|
||||
|
||||
// 20. Let evalContext be a new ECMAScript code execution context.
|
||||
ExecutionContext eval_context(vm.heap());
|
||||
auto eval_context = ExecutionContext::create(vm.heap());
|
||||
|
||||
// 21. Set evalContext's Function to null.
|
||||
// NOTE: This was done in the construction of eval_context.
|
||||
|
||||
// 22. Set evalContext's Realm to evalRealm.
|
||||
eval_context.realm = &eval_realm;
|
||||
eval_context->realm = &eval_realm;
|
||||
|
||||
// 23. Set evalContext's ScriptOrModule to runningContext's ScriptOrModule.
|
||||
eval_context.script_or_module = running_context.script_or_module;
|
||||
eval_context->script_or_module = running_context.script_or_module;
|
||||
|
||||
// 24. Set evalContext's VariableEnvironment to varEnv.
|
||||
eval_context.variable_environment = variable_environment;
|
||||
eval_context->variable_environment = variable_environment;
|
||||
|
||||
// 25. Set evalContext's LexicalEnvironment to lexEnv.
|
||||
eval_context.lexical_environment = lexical_environment;
|
||||
eval_context->lexical_environment = lexical_environment;
|
||||
|
||||
// 26. Set evalContext's PrivateEnvironment to privateEnv.
|
||||
eval_context.private_environment = private_environment;
|
||||
eval_context->private_environment = private_environment;
|
||||
|
||||
// NOTE: This isn't in the spec, but we require it.
|
||||
eval_context.is_strict_mode = strict_eval;
|
||||
eval_context->is_strict_mode = strict_eval;
|
||||
|
||||
// 27. Push evalContext onto the execution context stack; evalContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(eval_context, {}));
|
||||
TRY(vm.push_execution_context(*eval_context, {}));
|
||||
|
||||
// NOTE: We use a ScopeGuard to automatically pop the execution context when any of the `TRY`s below return a throw completion.
|
||||
ScopeGuard pop_guard = [&] {
|
||||
|
@ -1025,7 +1025,7 @@ ThrowCompletionOr<void> eval_declaration_instantiation(VM& vm, Program const& pr
|
|||
}
|
||||
|
||||
// 10.4.4.6 CreateUnmappedArgumentsObject ( argumentsList ), https://tc39.es/ecma262/#sec-createunmappedargumentsobject
|
||||
Object* create_unmapped_arguments_object(VM& vm, Span<Value> arguments)
|
||||
Object* create_unmapped_arguments_object(VM& vm, ReadonlySpan<Value> arguments)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
|
@ -1065,7 +1065,7 @@ Object* create_unmapped_arguments_object(VM& vm, Span<Value> arguments)
|
|||
}
|
||||
|
||||
// 10.4.4.7 CreateMappedArgumentsObject ( func, formals, argumentsList, env ), https://tc39.es/ecma262/#sec-createmappedargumentsobject
|
||||
Object* create_mapped_arguments_object(VM& vm, FunctionObject& function, Vector<FunctionParameter> const& formals, Span<Value> arguments, Environment& environment)
|
||||
Object* create_mapped_arguments_object(VM& vm, FunctionObject& function, Vector<FunctionParameter> const& formals, ReadonlySpan<Value> arguments, Environment& environment)
|
||||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ ThrowCompletionOr<void> initialize_bound_name(VM&, DeprecatedFlyString const&, V
|
|||
bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current);
|
||||
bool validate_and_apply_property_descriptor(Object*, PropertyKey const&, bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current);
|
||||
ThrowCompletionOr<Object*> get_prototype_from_constructor(VM&, FunctionObject const& constructor, NonnullGCPtr<Object> (Intrinsics::*intrinsic_default_prototype)());
|
||||
Object* create_unmapped_arguments_object(VM&, Span<Value> arguments);
|
||||
Object* create_mapped_arguments_object(VM&, FunctionObject&, Vector<FunctionParameter> const&, Span<Value> arguments, Environment&);
|
||||
Object* create_unmapped_arguments_object(VM&, ReadonlySpan<Value> arguments);
|
||||
Object* create_mapped_arguments_object(VM&, FunctionObject&, Vector<FunctionParameter> const&, ReadonlySpan<Value> arguments, Environment&);
|
||||
|
||||
struct DisposableResource {
|
||||
Value resource_value;
|
||||
|
|
|
@ -45,7 +45,9 @@ ThrowCompletionOr<NonnullGCPtr<Object>> AsyncFunctionConstructor::construct(Func
|
|||
auto* constructor = vm.active_function_object();
|
||||
|
||||
// 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
|
||||
auto& args = vm.running_execution_context().arguments;
|
||||
MarkedVector<Value> args(heap());
|
||||
for (auto argument : vm.running_execution_context().arguments)
|
||||
args.append(argument);
|
||||
|
||||
// 3. Return CreateDynamicFunction(C, NewTarget, async, args).
|
||||
return *TRY(FunctionConstructor::create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Async, args));
|
||||
|
|
|
@ -45,7 +45,8 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
|||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Let asyncContext be the running execution context.
|
||||
m_suspended_execution_context = vm.running_execution_context().copy();
|
||||
if (!m_suspended_execution_context)
|
||||
m_suspended_execution_context = vm.running_execution_context().copy();
|
||||
|
||||
// 2. Let promise be ? PromiseResolve(%Promise%, value).
|
||||
auto* promise_object = TRY(promise_resolve(vm, realm.intrinsics().promise_constructor(), value));
|
||||
|
@ -61,7 +62,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
|||
// FIXME: b. Suspend prevContext.
|
||||
|
||||
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(m_suspended_execution_context.value(), {}));
|
||||
TRY(vm.push_execution_context(*m_suspended_execution_context, {}));
|
||||
|
||||
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(v) as the result of the operation that
|
||||
// suspended it.
|
||||
|
@ -89,7 +90,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
|||
// FIXME: b. Suspend prevContext.
|
||||
|
||||
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(m_suspended_execution_context.value(), {}));
|
||||
TRY(vm.push_execution_context(*m_suspended_execution_context, {}));
|
||||
|
||||
// d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that
|
||||
// suspended it.
|
||||
|
@ -191,8 +192,6 @@ void AsyncFunctionDriverWrapper::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(m_top_level_promise);
|
||||
if (m_current_promise)
|
||||
visitor.visit(m_current_promise);
|
||||
if (m_suspended_execution_context.has_value())
|
||||
m_suspended_execution_context->visit_edges(visitor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ private:
|
|||
NonnullGCPtr<Promise> m_top_level_promise;
|
||||
GCPtr<Promise> m_current_promise { nullptr };
|
||||
Handle<AsyncFunctionDriverWrapper> m_self_handle;
|
||||
Optional<ExecutionContext> m_suspended_execution_context;
|
||||
OwnPtr<ExecutionContext> m_suspended_execution_context;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace JS {
|
|||
|
||||
JS_DEFINE_ALLOCATOR(AsyncGenerator);
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> AsyncGenerator::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, ExecutionContext execution_context, Bytecode::CallFrame frame)
|
||||
ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> AsyncGenerator::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullOwnPtr<ExecutionContext> execution_context, Bytecode::CallFrame frame)
|
||||
{
|
||||
auto& vm = realm.vm();
|
||||
// This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
|
||||
|
@ -29,7 +29,7 @@ ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> AsyncGenerator::create(Realm& re
|
|||
return object;
|
||||
}
|
||||
|
||||
AsyncGenerator::AsyncGenerator(Realm&, Object& prototype, ExecutionContext context)
|
||||
AsyncGenerator::AsyncGenerator(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext> context)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
, m_async_generator_context(move(context))
|
||||
{
|
||||
|
@ -43,7 +43,6 @@ void AsyncGenerator::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(*request.completion.value());
|
||||
visitor.visit(request.capability);
|
||||
}
|
||||
m_async_generator_context.visit_edges(visitor);
|
||||
visitor.visit(m_generating_function);
|
||||
visitor.visit(m_previous_value);
|
||||
if (m_frame.has_value())
|
||||
|
@ -328,7 +327,7 @@ ThrowCompletionOr<void> AsyncGenerator::resume(VM& vm, Completion completion)
|
|||
m_async_generator_state = State::Executing;
|
||||
|
||||
// 6. Push genContext onto the execution context stack; genContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(generator_context, {}));
|
||||
TRY(vm.push_execution_context(*generator_context, {}));
|
||||
|
||||
// 7. Resume the suspended evaluation of genContext using completion as the result of the operation that suspended
|
||||
// it. Let result be the Completion Record returned by the resumed computation.
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
Completed,
|
||||
};
|
||||
|
||||
static ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> create(Realm&, Value, ECMAScriptFunctionObject*, ExecutionContext, Bytecode::CallFrame);
|
||||
static ThrowCompletionOr<NonnullGCPtr<AsyncGenerator>> create(Realm&, Value, ECMAScriptFunctionObject*, NonnullOwnPtr<ExecutionContext>, Bytecode::CallFrame);
|
||||
|
||||
virtual ~AsyncGenerator() override = default;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
|||
Optional<String> const& generator_brand() const { return m_generator_brand; }
|
||||
|
||||
private:
|
||||
AsyncGenerator(Realm&, Object& prototype, ExecutionContext);
|
||||
AsyncGenerator(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext>);
|
||||
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
|
@ -53,10 +53,10 @@ private:
|
|||
|
||||
// At the time of constructing an AsyncGenerator, we still need to point to an
|
||||
// execution context on the stack, but later need to 'adopt' it.
|
||||
State m_async_generator_state { State::SuspendedStart }; // [[AsyncGeneratorState]]
|
||||
ExecutionContext m_async_generator_context; // [[AsyncGeneratorContext]]
|
||||
Vector<AsyncGeneratorRequest> m_async_generator_queue; // [[AsyncGeneratorQueue]]
|
||||
Optional<String> m_generator_brand; // [[GeneratorBrand]]
|
||||
State m_async_generator_state { State::SuspendedStart }; // [[AsyncGeneratorState]]
|
||||
NonnullOwnPtr<ExecutionContext> m_async_generator_context; // [[AsyncGeneratorContext]]
|
||||
Vector<AsyncGeneratorRequest> m_async_generator_queue; // [[AsyncGeneratorQueue]]
|
||||
Optional<String> m_generator_brand; // [[GeneratorBrand]]
|
||||
|
||||
GCPtr<ECMAScriptFunctionObject> m_generating_function;
|
||||
Value m_previous_value;
|
||||
|
|
|
@ -46,7 +46,9 @@ ThrowCompletionOr<NonnullGCPtr<Object>> AsyncGeneratorFunctionConstructor::const
|
|||
auto* constructor = vm.active_function_object();
|
||||
|
||||
// 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
|
||||
auto& args = vm.running_execution_context().arguments;
|
||||
MarkedVector<Value> args(heap());
|
||||
for (auto argument : vm.running_execution_context().arguments)
|
||||
args.append(argument);
|
||||
|
||||
// 3. Return ? CreateDynamicFunction(C, NewTarget, asyncGenerator, args).
|
||||
return *TRY(FunctionConstructor::create_dynamic_function(vm, *constructor, &new_target, FunctionKind::AsyncGenerator, args));
|
||||
|
|
|
@ -370,20 +370,20 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
|
|||
// 1. Let callerContext be the running execution context.
|
||||
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||
|
||||
ExecutionContext callee_context(heap());
|
||||
auto callee_context = ExecutionContext::create(heap());
|
||||
|
||||
callee_context.local_variables.resize(m_local_variables_names.size());
|
||||
callee_context->locals.resize(m_local_variables_names.size());
|
||||
|
||||
// Non-standard
|
||||
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
callee_context->arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context->instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
// 2. Let calleeContext be PrepareForOrdinaryCall(F, undefined).
|
||||
// NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
|
||||
TRY(prepare_for_ordinary_call(callee_context, nullptr));
|
||||
TRY(prepare_for_ordinary_call(*callee_context, nullptr));
|
||||
|
||||
// 3. Assert: calleeContext is now the running execution context.
|
||||
VERIFY(&vm.running_execution_context() == &callee_context);
|
||||
VERIFY(&vm.running_execution_context() == callee_context);
|
||||
|
||||
// 4. If F.[[IsClassConstructor]] is true, then
|
||||
if (m_is_class_constructor) {
|
||||
|
@ -399,7 +399,7 @@ ThrowCompletionOr<Value> ECMAScriptFunctionObject::internal_call(Value this_argu
|
|||
}
|
||||
|
||||
// 5. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
|
||||
ordinary_call_bind_this(callee_context, this_argument);
|
||||
ordinary_call_bind_this(*callee_context, this_argument);
|
||||
|
||||
// 6. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
|
||||
auto result = ordinary_call_evaluate_body();
|
||||
|
@ -440,25 +440,25 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_const
|
|||
this_argument = TRY(ordinary_create_from_constructor<Object>(vm, new_target, &Intrinsics::object_prototype, ConstructWithPrototypeTag::Tag));
|
||||
}
|
||||
|
||||
ExecutionContext callee_context(heap());
|
||||
auto callee_context = ExecutionContext::create(heap());
|
||||
|
||||
callee_context.local_variables.resize(m_local_variables_names.size());
|
||||
callee_context->locals.resize(m_local_variables_names.size());
|
||||
|
||||
// Non-standard
|
||||
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
callee_context->arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context->instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
// 4. Let calleeContext be PrepareForOrdinaryCall(F, newTarget).
|
||||
// NOTE: We throw if the end of the native stack is reached, so unlike in the spec this _does_ need an exception check.
|
||||
TRY(prepare_for_ordinary_call(callee_context, &new_target));
|
||||
TRY(prepare_for_ordinary_call(*callee_context, &new_target));
|
||||
|
||||
// 5. Assert: calleeContext is now the running execution context.
|
||||
VERIFY(&vm.running_execution_context() == &callee_context);
|
||||
VERIFY(&vm.running_execution_context() == callee_context);
|
||||
|
||||
// 6. If kind is base, then
|
||||
if (kind == ConstructorKind::Base) {
|
||||
// a. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).
|
||||
ordinary_call_bind_this(callee_context, this_argument);
|
||||
ordinary_call_bind_this(*callee_context, this_argument);
|
||||
|
||||
// b. Let initializeResult be Completion(InitializeInstanceElements(thisArgument, F)).
|
||||
auto initialize_result = this_argument->initialize_instance_elements(*this);
|
||||
|
@ -474,7 +474,7 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ECMAScriptFunctionObject::internal_const
|
|||
}
|
||||
|
||||
// 7. Let constructorEnv be the LexicalEnvironment of calleeContext.
|
||||
auto constructor_env = callee_context.lexical_environment;
|
||||
auto constructor_env = callee_context->lexical_environment;
|
||||
|
||||
// 8. Let result be Completion(OrdinaryCallEvaluateBody(F, argumentsList)).
|
||||
auto result = ordinary_call_evaluate_body();
|
||||
|
@ -681,7 +681,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
// 26. Else,
|
||||
// a. Perform ? IteratorBindingInitialization of formals with arguments iteratorRecord and env.
|
||||
// NOTE: The spec makes an iterator here to do IteratorBindingInitialization but we just do it manually
|
||||
auto& execution_context_arguments = vm.running_execution_context().arguments;
|
||||
auto execution_context_arguments = vm.running_execution_context().arguments;
|
||||
|
||||
size_t default_parameter_index = 0;
|
||||
for (size_t i = 0; i < m_formal_parameters.size(); ++i) {
|
||||
|
@ -713,7 +713,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
|
||||
if constexpr (IsSame<NonnullRefPtr<Identifier const> const&, decltype(param)>) {
|
||||
if (param->is_local()) {
|
||||
callee_context.local_variables[param->local_variable_index()] = argument_value;
|
||||
callee_context.locals[param->local_variable_index()] = argument_value;
|
||||
return {};
|
||||
}
|
||||
Reference reference = TRY(vm.resolve_binding(param->string(), used_environment));
|
||||
|
@ -749,7 +749,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
// i. If instantiatedVarNames does not contain n, then
|
||||
// 1. Append n to instantiatedVarNames.
|
||||
if (id.is_local()) {
|
||||
callee_context.local_variables[id.local_variable_index()] = js_undefined();
|
||||
callee_context.locals[id.local_variable_index()] = js_undefined();
|
||||
} else {
|
||||
// 2. Perform ! env.CreateMutableBinding(n, false).
|
||||
// 3. Perform ! env.InitializeBinding(n, undefined).
|
||||
|
@ -804,7 +804,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
else {
|
||||
// a. Let initialValue be ! env.GetBindingValue(n, false).
|
||||
if (id.is_local()) {
|
||||
initial_value = callee_context.local_variables[id.local_variable_index()];
|
||||
initial_value = callee_context.locals[id.local_variable_index()];
|
||||
} else {
|
||||
initial_value = MUST(environment->get_binding_value(vm, id.string(), false));
|
||||
}
|
||||
|
@ -813,7 +813,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
// 5. Perform ! varEnv.InitializeBinding(n, initialValue).
|
||||
if (id.is_local()) {
|
||||
// NOTE: Local variables are supported only in bytecode interpreter
|
||||
callee_context.local_variables[id.local_variable_index()] = initial_value;
|
||||
callee_context.locals[id.local_variable_index()] = initial_value;
|
||||
} else {
|
||||
MUST(var_environment->initialize_binding(vm, id.string(), initial_value, Environment::InitializeBindingHint::Normal));
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ ThrowCompletionOr<void> ECMAScriptFunctionObject::function_declaration_instantia
|
|||
|
||||
// c. Perform ! varEnv.SetMutableBinding(fn, fo, false).
|
||||
if (declaration.name_identifier()->is_local()) {
|
||||
callee_context.local_variables[declaration.name_identifier()->local_variable_index()] = function;
|
||||
callee_context.locals[declaration.name_identifier()->local_variable_index()] = function;
|
||||
} else {
|
||||
MUST(var_environment->set_mutable_binding(vm, declaration.name(), function, false));
|
||||
}
|
||||
|
@ -1056,7 +1056,7 @@ void async_function_start(VM& vm, PromiseCapability const& promise_capability, T
|
|||
// 3. NOTE: Copying the execution state is required for AsyncBlockStart to resume its execution. It is ill-defined to resume a currently executing context.
|
||||
|
||||
// 4. Perform AsyncBlockStart(promiseCapability, asyncFunctionBody, asyncContext).
|
||||
async_block_start(vm, async_function_body, promise_capability, async_context);
|
||||
async_block_start(vm, async_function_body, promise_capability, *async_context);
|
||||
|
||||
// 5. Return unused.
|
||||
}
|
||||
|
|
|
@ -7,38 +7,44 @@
|
|||
*/
|
||||
|
||||
#include <LibJS/Bytecode/Executable.h>
|
||||
#include <LibJS/Heap/Heap.h>
|
||||
#include <LibJS/Runtime/ExecutionContext.h>
|
||||
#include <LibJS/Runtime/FunctionObject.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
NonnullOwnPtr<ExecutionContext> ExecutionContext::create(Heap& heap)
|
||||
{
|
||||
return adopt_own(*new ExecutionContext(heap));
|
||||
}
|
||||
|
||||
ExecutionContext::ExecutionContext(Heap& heap)
|
||||
: arguments(heap)
|
||||
, local_variables(heap)
|
||||
: m_heap(heap)
|
||||
{
|
||||
m_heap.did_create_execution_context({}, *this);
|
||||
}
|
||||
|
||||
ExecutionContext::ExecutionContext(MarkedVector<Value> existing_arguments, MarkedVector<Value> existing_local_variables)
|
||||
: arguments(move(existing_arguments))
|
||||
, local_variables(move(existing_local_variables))
|
||||
ExecutionContext::~ExecutionContext()
|
||||
{
|
||||
m_heap.did_destroy_execution_context({}, *this);
|
||||
}
|
||||
|
||||
ExecutionContext ExecutionContext::copy() const
|
||||
NonnullOwnPtr<ExecutionContext> ExecutionContext::copy() const
|
||||
{
|
||||
ExecutionContext copy { arguments, local_variables };
|
||||
|
||||
copy.function = function;
|
||||
copy.realm = realm;
|
||||
copy.script_or_module = script_or_module;
|
||||
copy.lexical_environment = lexical_environment;
|
||||
copy.variable_environment = variable_environment;
|
||||
copy.private_environment = private_environment;
|
||||
copy.instruction_stream_iterator = instruction_stream_iterator;
|
||||
copy.function_name = function_name;
|
||||
copy.this_value = this_value;
|
||||
copy.is_strict_mode = is_strict_mode;
|
||||
|
||||
auto copy = create(m_heap);
|
||||
copy->function = function;
|
||||
copy->realm = realm;
|
||||
copy->script_or_module = script_or_module;
|
||||
copy->lexical_environment = lexical_environment;
|
||||
copy->variable_environment = variable_environment;
|
||||
copy->private_environment = private_environment;
|
||||
copy->instruction_stream_iterator = instruction_stream_iterator;
|
||||
copy->function_name = function_name;
|
||||
copy->this_value = this_value;
|
||||
copy->is_strict_mode = is_strict_mode;
|
||||
copy->executable = executable;
|
||||
copy->arguments = arguments;
|
||||
copy->locals = locals;
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -51,9 +57,14 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(private_environment);
|
||||
visitor.visit(context_owner);
|
||||
visitor.visit(this_value);
|
||||
visitor.visit(executable);
|
||||
if (instruction_stream_iterator.has_value())
|
||||
visitor.visit(const_cast<Bytecode::Executable*>(instruction_stream_iterator.value().executable()));
|
||||
visitor.visit(function_name);
|
||||
for (auto argument : arguments)
|
||||
visitor.visit(argument);
|
||||
for (auto local : locals)
|
||||
visitor.visit(local);
|
||||
script_or_module.visit(
|
||||
[](Empty) {},
|
||||
[&](auto& script_or_module) {
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <AK/WeakPtr.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/MarkedVector.h>
|
||||
#include <LibJS/Module.h>
|
||||
#include <LibJS/Runtime/PrivateEnvironment.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
@ -24,9 +23,10 @@ using ScriptOrModule = Variant<Empty, NonnullGCPtr<Script>, NonnullGCPtr<Module>
|
|||
|
||||
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
||||
struct ExecutionContext {
|
||||
explicit ExecutionContext(Heap& heap);
|
||||
static NonnullOwnPtr<ExecutionContext> create(Heap&);
|
||||
[[nodiscard]] NonnullOwnPtr<ExecutionContext> copy() const;
|
||||
|
||||
[[nodiscard]] ExecutionContext copy() const;
|
||||
~ExecutionContext();
|
||||
|
||||
void visit_edges(Cell::Visitor&);
|
||||
|
||||
|
@ -35,9 +35,15 @@ struct ExecutionContext {
|
|||
static FlatPtr variable_environment_offset() { return OFFSET_OF(ExecutionContext, variable_environment); }
|
||||
|
||||
private:
|
||||
explicit ExecutionContext(MarkedVector<Value> existing_arguments, MarkedVector<Value> existing_local_variables);
|
||||
ExecutionContext(Heap&);
|
||||
|
||||
IntrusiveListNode<ExecutionContext> m_list_node;
|
||||
|
||||
public:
|
||||
Heap& m_heap;
|
||||
|
||||
using List = IntrusiveList<&ExecutionContext::m_list_node>;
|
||||
|
||||
GCPtr<FunctionObject> function; // [[Function]]
|
||||
GCPtr<Realm> realm; // [[Realm]]
|
||||
ScriptOrModule script_or_module; // [[ScriptOrModule]]
|
||||
|
@ -51,8 +57,6 @@ public:
|
|||
Optional<Bytecode::InstructionStreamIterator> instruction_stream_iterator;
|
||||
GCPtr<PrimitiveString> function_name;
|
||||
Value this_value;
|
||||
MarkedVector<Value> arguments;
|
||||
MarkedVector<Value> local_variables;
|
||||
bool is_strict_mode { false };
|
||||
|
||||
GCPtr<Bytecode::Executable> executable;
|
||||
|
@ -60,6 +64,21 @@ public:
|
|||
// https://html.spec.whatwg.org/multipage/webappapis.html#skip-when-determining-incumbent-counter
|
||||
// FIXME: Move this out of LibJS (e.g. by using the CustomData concept), as it's used exclusively by LibWeb.
|
||||
size_t skip_when_determining_incumbent_counter { 0 };
|
||||
|
||||
Value argument(size_t index) const
|
||||
{
|
||||
if (index >= arguments.size()) [[unlikely]]
|
||||
return js_undefined();
|
||||
return arguments[index];
|
||||
}
|
||||
|
||||
Value& local(size_t index)
|
||||
{
|
||||
return locals[index];
|
||||
}
|
||||
|
||||
Vector<Value> arguments;
|
||||
Vector<Value> locals;
|
||||
};
|
||||
|
||||
struct StackTraceElement {
|
||||
|
|
|
@ -268,7 +268,9 @@ ThrowCompletionOr<NonnullGCPtr<Object>> FunctionConstructor::construct(FunctionO
|
|||
auto* constructor = vm.active_function_object();
|
||||
|
||||
// 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
|
||||
auto& args = vm.running_execution_context().arguments;
|
||||
MarkedVector<Value> args(heap());
|
||||
for (auto argument : vm.running_execution_context().arguments)
|
||||
args.append(argument);
|
||||
|
||||
// 3. Return ? CreateDynamicFunction(C, NewTarget, normal, args).
|
||||
return *TRY(create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Normal, args));
|
||||
|
|
|
@ -98,8 +98,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
|
|||
|
||||
Vector<Value> arguments;
|
||||
if (vm.argument_count() > 1) {
|
||||
arguments = vm.running_execution_context().arguments;
|
||||
arguments.remove(0);
|
||||
arguments.append(vm.running_execution_context().arguments.span().slice(1).data(), vm.argument_count() - 1);
|
||||
}
|
||||
|
||||
// 3. Let F be ? BoundFunctionCreate(Target, thisArg, args).
|
||||
|
|
|
@ -44,7 +44,9 @@ ThrowCompletionOr<NonnullGCPtr<Object>> GeneratorFunctionConstructor::construct(
|
|||
auto* constructor = vm.active_function_object();
|
||||
|
||||
// 2. Let args be the argumentsList that was passed to this function by [[Call]] or [[Construct]].
|
||||
auto& args = vm.running_execution_context().arguments;
|
||||
MarkedVector<Value> args(heap());
|
||||
for (auto argument : vm.running_execution_context().arguments)
|
||||
args.append(argument);
|
||||
|
||||
// 3. Return ? CreateDynamicFunction(C, NewTarget, generator, args).
|
||||
return *TRY(FunctionConstructor::create_dynamic_function(vm, *constructor, &new_target, FunctionKind::Generator, args));
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace JS {
|
|||
|
||||
JS_DEFINE_ALLOCATOR(GeneratorObject);
|
||||
|
||||
ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, ExecutionContext execution_context, Bytecode::CallFrame frame)
|
||||
ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm& realm, Value initial_value, ECMAScriptFunctionObject* generating_function, NonnullOwnPtr<ExecutionContext> execution_context, Bytecode::CallFrame frame)
|
||||
{
|
||||
auto& vm = realm.vm();
|
||||
// This is "g1.prototype" in figure-2 (https://tc39.es/ecma262/img/figure-2.png)
|
||||
|
@ -37,7 +37,7 @@ ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> GeneratorObject::create(Realm&
|
|||
return object;
|
||||
}
|
||||
|
||||
GeneratorObject::GeneratorObject(Realm&, Object& prototype, ExecutionContext context, Optional<StringView> generator_brand)
|
||||
GeneratorObject::GeneratorObject(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext> context, Optional<StringView> generator_brand)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
, m_execution_context(move(context))
|
||||
, m_generator_brand(move(generator_brand))
|
||||
|
@ -49,7 +49,6 @@ void GeneratorObject::visit_edges(Cell::Visitor& visitor)
|
|||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_generating_function);
|
||||
visitor.visit(m_previous_value);
|
||||
m_execution_context.visit_edges(visitor);
|
||||
if (m_frame.has_value())
|
||||
m_frame->visit_edges(visitor);
|
||||
}
|
||||
|
@ -166,7 +165,7 @@ ThrowCompletionOr<Value> GeneratorObject::resume(VM& vm, Value value, Optional<S
|
|||
// 8. Push genContext onto the execution context stack; genContext is now the running execution context.
|
||||
// NOTE: This is done out of order as to not permanently disable the generator if push_execution_context throws,
|
||||
// as `resume` will immediately throw when [[GeneratorState]] is "executing", never allowing the state to change.
|
||||
TRY(vm.push_execution_context(generator_context, {}));
|
||||
TRY(vm.push_execution_context(*generator_context, {}));
|
||||
|
||||
// 7. Set generator.[[GeneratorState]] to executing.
|
||||
m_generator_state = GeneratorState::Executing;
|
||||
|
@ -228,7 +227,7 @@ ThrowCompletionOr<Value> GeneratorObject::resume_abrupt(JS::VM& vm, JS::Completi
|
|||
// 9. Push genContext onto the execution context stack; genContext is now the running execution context.
|
||||
// NOTE: This is done out of order as to not permanently disable the generator if push_execution_context throws,
|
||||
// as `resume_abrupt` will immediately throw when [[GeneratorState]] is "executing", never allowing the state to change.
|
||||
TRY(vm.push_execution_context(generator_context, {}));
|
||||
TRY(vm.push_execution_context(*generator_context, {}));
|
||||
|
||||
// 8. Set generator.[[GeneratorState]] to executing.
|
||||
m_generator_state = GeneratorState::Executing;
|
||||
|
|
|
@ -17,7 +17,7 @@ class GeneratorObject : public Object {
|
|||
JS_DECLARE_ALLOCATOR(GeneratorObject);
|
||||
|
||||
public:
|
||||
static ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> create(Realm&, Value, ECMAScriptFunctionObject*, ExecutionContext, Bytecode::CallFrame);
|
||||
static ThrowCompletionOr<NonnullGCPtr<GeneratorObject>> create(Realm&, Value, ECMAScriptFunctionObject*, NonnullOwnPtr<ExecutionContext>, Bytecode::CallFrame);
|
||||
virtual ~GeneratorObject() override = default;
|
||||
void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
|
@ -34,13 +34,13 @@ public:
|
|||
void set_generator_state(GeneratorState generator_state) { m_generator_state = generator_state; }
|
||||
|
||||
protected:
|
||||
GeneratorObject(Realm&, Object& prototype, ExecutionContext, Optional<StringView> generator_brand = {});
|
||||
GeneratorObject(Realm&, Object& prototype, NonnullOwnPtr<ExecutionContext>, Optional<StringView> generator_brand = {});
|
||||
|
||||
ThrowCompletionOr<GeneratorState> validate(VM&, Optional<StringView> const& generator_brand);
|
||||
virtual ThrowCompletionOr<Value> execute(VM&, JS::Completion const& completion);
|
||||
|
||||
private:
|
||||
ExecutionContext m_execution_context;
|
||||
NonnullOwnPtr<ExecutionContext> m_execution_context;
|
||||
GCPtr<ECMAScriptFunctionObject> m_generating_function;
|
||||
Value m_previous_value;
|
||||
Optional<Bytecode::CallFrame> m_frame;
|
||||
|
|
|
@ -121,11 +121,11 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Read
|
|||
// NOTE: We don't support this concept yet.
|
||||
|
||||
// 3. Let calleeContext be a new execution context.
|
||||
ExecutionContext callee_context(heap());
|
||||
auto callee_context = ExecutionContext::create(heap());
|
||||
|
||||
// 4. Set the Function of calleeContext to F.
|
||||
callee_context.function = this;
|
||||
callee_context.function_name = m_name_string;
|
||||
callee_context->function = this;
|
||||
callee_context->function_name = m_name_string;
|
||||
|
||||
// 5. Let calleeRealm be F.[[Realm]].
|
||||
auto callee_realm = m_realm;
|
||||
|
@ -139,29 +139,29 @@ ThrowCompletionOr<Value> NativeFunction::internal_call(Value this_argument, Read
|
|||
VERIFY(callee_realm);
|
||||
|
||||
// 6. Set the Realm of calleeContext to calleeRealm.
|
||||
callee_context.realm = callee_realm;
|
||||
callee_context->realm = callee_realm;
|
||||
|
||||
// 7. Set the ScriptOrModule of calleeContext to null.
|
||||
// Note: This is already the default value.
|
||||
|
||||
// 8. Perform any necessary implementation-defined initialization of calleeContext.
|
||||
callee_context.this_value = this_argument;
|
||||
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
callee_context->this_value = this_argument;
|
||||
callee_context->arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context->instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
callee_context.lexical_environment = caller_context.lexical_environment;
|
||||
callee_context.variable_environment = caller_context.variable_environment;
|
||||
callee_context->lexical_environment = caller_context.lexical_environment;
|
||||
callee_context->variable_environment = caller_context.variable_environment;
|
||||
// Note: Keeping the private environment is probably only needed because of async methods in classes
|
||||
// calling async_block_start which goes through a NativeFunction here.
|
||||
callee_context.private_environment = caller_context.private_environment;
|
||||
callee_context->private_environment = caller_context.private_environment;
|
||||
|
||||
// NOTE: This is a LibJS specific hack for NativeFunction to inherit the strictness of its caller.
|
||||
callee_context.is_strict_mode = vm.in_strict_mode();
|
||||
callee_context->is_strict_mode = vm.in_strict_mode();
|
||||
|
||||
// </8.> --------------------------------------------------------------------------
|
||||
|
||||
// 9. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(callee_context, {}));
|
||||
TRY(vm.push_execution_context(*callee_context, {}));
|
||||
|
||||
// 10. Let result be the Completion Record that is the result of evaluating F in a manner that conforms to the specification of F. thisArgument is the this value, argumentsList provides the named parameters, and the NewTarget value is undefined.
|
||||
auto result = call();
|
||||
|
@ -185,11 +185,11 @@ ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(Reado
|
|||
// NOTE: We don't support this concept yet.
|
||||
|
||||
// 3. Let calleeContext be a new execution context.
|
||||
ExecutionContext callee_context(heap());
|
||||
auto callee_context = ExecutionContext::create(heap());
|
||||
|
||||
// 4. Set the Function of calleeContext to F.
|
||||
callee_context.function = this;
|
||||
callee_context.function_name = m_name_string;
|
||||
callee_context->function = this;
|
||||
callee_context->function_name = m_name_string;
|
||||
|
||||
// 5. Let calleeRealm be F.[[Realm]].
|
||||
auto callee_realm = m_realm;
|
||||
|
@ -203,25 +203,25 @@ ThrowCompletionOr<NonnullGCPtr<Object>> NativeFunction::internal_construct(Reado
|
|||
VERIFY(callee_realm);
|
||||
|
||||
// 6. Set the Realm of calleeContext to calleeRealm.
|
||||
callee_context.realm = callee_realm;
|
||||
callee_context->realm = callee_realm;
|
||||
|
||||
// 7. Set the ScriptOrModule of calleeContext to null.
|
||||
// Note: This is already the default value.
|
||||
|
||||
// 8. Perform any necessary implementation-defined initialization of calleeContext.
|
||||
callee_context.arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context.instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
callee_context->arguments.append(arguments_list.data(), arguments_list.size());
|
||||
callee_context->instruction_stream_iterator = vm.bytecode_interpreter().instruction_stream_iterator();
|
||||
|
||||
callee_context.lexical_environment = caller_context.lexical_environment;
|
||||
callee_context.variable_environment = caller_context.variable_environment;
|
||||
callee_context->lexical_environment = caller_context.lexical_environment;
|
||||
callee_context->variable_environment = caller_context.variable_environment;
|
||||
|
||||
// NOTE: This is a LibJS specific hack for NativeFunction to inherit the strictness of its caller.
|
||||
callee_context.is_strict_mode = vm.in_strict_mode();
|
||||
callee_context->is_strict_mode = vm.in_strict_mode();
|
||||
|
||||
// </8.> --------------------------------------------------------------------------
|
||||
|
||||
// 9. Push calleeContext onto the execution context stack; calleeContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(callee_context, {}));
|
||||
TRY(vm.push_execution_context(*callee_context, {}));
|
||||
|
||||
// 10. Let result be the Completion Record that is the result of evaluating F in a manner that conforms to the specification of F. The this value is uninitialized, argumentsList provides the named parameters, and newTarget provides the NewTarget value.
|
||||
auto result = construct(new_target);
|
||||
|
|
|
@ -42,7 +42,7 @@ ThrowCompletionOr<NonnullOwnPtr<ExecutionContext>> Realm::initialize_host_define
|
|||
auto realm = MUST_OR_THROW_OOM(Realm::create(vm));
|
||||
|
||||
// 2. Let newContext be a new execution context.
|
||||
auto new_context = make<ExecutionContext>(vm.heap());
|
||||
auto new_context = ExecutionContext::create(vm.heap());
|
||||
|
||||
// 3. Set the Function of newContext to null.
|
||||
new_context->function = nullptr;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace JS {
|
|||
|
||||
JS_DEFINE_ALLOCATOR(ShadowRealm);
|
||||
|
||||
ShadowRealm::ShadowRealm(Realm& shadow_realm, ExecutionContext execution_context, Object& prototype)
|
||||
ShadowRealm::ShadowRealm(Realm& shadow_realm, NonnullOwnPtr<ExecutionContext> execution_context, Object& prototype)
|
||||
: Object(ConstructWithPrototypeTag::Tag, prototype)
|
||||
, m_shadow_realm(shadow_realm)
|
||||
, m_execution_context(move(execution_context))
|
||||
|
@ -143,28 +143,28 @@ ThrowCompletionOr<Value> perform_shadow_realm_eval(VM& vm, StringView source_tex
|
|||
// NOTE: We don't support this concept yet.
|
||||
|
||||
// 9. Let evalContext be a new ECMAScript code execution context.
|
||||
auto eval_context = ExecutionContext { vm.heap() };
|
||||
auto eval_context = ExecutionContext::create(vm.heap());
|
||||
|
||||
// 10. Set evalContext's Function to null.
|
||||
eval_context.function = nullptr;
|
||||
eval_context->function = nullptr;
|
||||
|
||||
// 11. Set evalContext's Realm to evalRealm.
|
||||
eval_context.realm = &eval_realm;
|
||||
eval_context->realm = &eval_realm;
|
||||
|
||||
// 12. Set evalContext's ScriptOrModule to null.
|
||||
// Note: This is already the default value.
|
||||
|
||||
// 13. Set evalContext's VariableEnvironment to varEnv.
|
||||
eval_context.variable_environment = variable_environment;
|
||||
eval_context->variable_environment = variable_environment;
|
||||
|
||||
// 14. Set evalContext's LexicalEnvironment to lexEnv.
|
||||
eval_context.lexical_environment = lexical_environment;
|
||||
eval_context->lexical_environment = lexical_environment;
|
||||
|
||||
// Non-standard
|
||||
eval_context.is_strict_mode = strict_eval;
|
||||
eval_context->is_strict_mode = strict_eval;
|
||||
|
||||
// 15. Push evalContext onto the execution context stack; evalContext is now the running execution context.
|
||||
TRY(vm.push_execution_context(eval_context, {}));
|
||||
TRY(vm.push_execution_context(*eval_context, {}));
|
||||
|
||||
// 16. Let result be Completion(EvalDeclarationInstantiation(body, varEnv, lexEnv, null, strictEval)).
|
||||
auto eval_result = eval_declaration_instantiation(vm, program, variable_environment, lexical_environment, nullptr, strict_eval);
|
||||
|
|
|
@ -22,17 +22,17 @@ public:
|
|||
|
||||
[[nodiscard]] Realm const& shadow_realm() const { return m_shadow_realm; }
|
||||
[[nodiscard]] Realm& shadow_realm() { return m_shadow_realm; }
|
||||
[[nodiscard]] ExecutionContext const& execution_context() const { return m_execution_context; }
|
||||
[[nodiscard]] ExecutionContext& execution_context() { return m_execution_context; }
|
||||
[[nodiscard]] ExecutionContext const& execution_context() const { return *m_execution_context; }
|
||||
[[nodiscard]] ExecutionContext& execution_context() { return *m_execution_context; }
|
||||
|
||||
private:
|
||||
ShadowRealm(Realm&, ExecutionContext, Object& prototype);
|
||||
ShadowRealm(Realm&, NonnullOwnPtr<ExecutionContext>, Object& prototype);
|
||||
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
// 3.5 Properties of ShadowRealm Instances, https://tc39.es/proposal-shadowrealm/#sec-properties-of-shadowrealm-instances
|
||||
NonnullGCPtr<Realm> m_shadow_realm; // [[ShadowRealm]]
|
||||
ExecutionContext m_execution_context; // [[ExecutionContext]]
|
||||
NonnullGCPtr<Realm> m_shadow_realm; // [[ShadowRealm]]
|
||||
NonnullOwnPtr<ExecutionContext> m_execution_context; // [[ExecutionContext]]
|
||||
};
|
||||
|
||||
ThrowCompletionOr<void> copy_name_and_length(VM&, FunctionObject& function, FunctionObject& target, Optional<StringView> prefix = {}, Optional<unsigned> arg_count = {});
|
||||
|
|
|
@ -47,13 +47,13 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ShadowRealmConstructor::construct(Functi
|
|||
auto realm = MUST_OR_THROW_OOM(Realm::create(vm));
|
||||
|
||||
// 5. Let context be a new execution context.
|
||||
auto context = ExecutionContext { vm.heap() };
|
||||
auto context = ExecutionContext::create(vm.heap());
|
||||
|
||||
// 6. Set the Function of context to null.
|
||||
context.function = nullptr;
|
||||
context->function = nullptr;
|
||||
|
||||
// 7. Set the Realm of context to realmRec.
|
||||
context.realm = realm;
|
||||
context->realm = realm;
|
||||
|
||||
// 8. Set the ScriptOrModule of context to null.
|
||||
// Note: This is already the default value.
|
||||
|
|
|
@ -199,31 +199,6 @@ void VM::gather_roots(HashMap<Cell*, HeapRoot>& roots)
|
|||
for (auto string : m_single_ascii_character_strings)
|
||||
roots.set(string, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
|
||||
auto gather_roots_from_execution_context_stack = [&roots](Vector<ExecutionContext*> const& stack) {
|
||||
for (auto& execution_context : stack) {
|
||||
if (execution_context->this_value.is_cell())
|
||||
roots.set(&execution_context->this_value.as_cell(), { .type = HeapRoot::Type::VM });
|
||||
for (auto& argument : execution_context->arguments) {
|
||||
if (argument.is_cell())
|
||||
roots.set(&argument.as_cell(), HeapRoot { .type = HeapRoot::Type::VM });
|
||||
}
|
||||
roots.set(execution_context->lexical_environment, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
roots.set(execution_context->variable_environment, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
roots.set(execution_context->private_environment, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
if (auto context_owner = execution_context->context_owner)
|
||||
roots.set(context_owner, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
execution_context->script_or_module.visit(
|
||||
[](Empty) {},
|
||||
[&](auto& script_or_module) {
|
||||
roots.set(script_or_module.ptr(), HeapRoot { .type = HeapRoot::Type::VM });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
gather_roots_from_execution_context_stack(m_execution_context_stack);
|
||||
for (auto& saved_stack : m_saved_execution_context_stacks)
|
||||
gather_roots_from_execution_context_stack(saved_stack);
|
||||
|
||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||
roots.set(m_well_known_symbols.snake_name, HeapRoot { .type = HeapRoot::Type::VM });
|
||||
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
|
||||
|
|
|
@ -150,8 +150,7 @@ public:
|
|||
{
|
||||
if (m_execution_context_stack.is_empty())
|
||||
return {};
|
||||
auto& arguments = running_execution_context().arguments;
|
||||
return index < arguments.size() ? arguments[index] : js_undefined();
|
||||
return running_execution_context().argument(index);
|
||||
}
|
||||
|
||||
Value this_value() const
|
||||
|
|
|
@ -343,6 +343,12 @@ public:
|
|||
return *extract_pointer<Cell>();
|
||||
}
|
||||
|
||||
Cell& as_cell() const
|
||||
{
|
||||
VERIFY(is_cell());
|
||||
return *extract_pointer<Cell>();
|
||||
}
|
||||
|
||||
Accessor& as_accessor()
|
||||
{
|
||||
VERIFY(is_accessor());
|
||||
|
|
|
@ -62,11 +62,11 @@ ThrowCompletionOr<Value> WrappedFunction::internal_call(Value this_argument, Rea
|
|||
// NOTE: No-op, kept by the VM in its execution context stack.
|
||||
|
||||
// 2. Let calleeContext be PrepareForWrappedFunctionCall(F).
|
||||
ExecutionContext callee_context { vm.heap() };
|
||||
prepare_for_wrapped_function_call(*this, callee_context);
|
||||
auto callee_context = ExecutionContext::create(vm.heap());
|
||||
prepare_for_wrapped_function_call(*this, *callee_context);
|
||||
|
||||
// 3. Assert: calleeContext is now the running execution context.
|
||||
VERIFY(&vm.running_execution_context() == &callee_context);
|
||||
VERIFY(&vm.running_execution_context() == callee_context);
|
||||
|
||||
// 4. Let result be OrdinaryWrappedFunctionCall(F, thisArgument, argumentsList).
|
||||
auto result = ordinary_wrapped_function_call(*this, this_argument, arguments_list);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue