mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:07:34 +00:00
LibJS: Rename CallFrame => ExecutionContext
This struct represents what the ECMAScript specification calls an "execution context" so let's use the same terminology. :^)
This commit is contained in:
parent
7c88caf99f
commit
c2ad599783
13 changed files with 139 additions and 138 deletions
|
@ -43,7 +43,7 @@ public:
|
||||||
: m_interpreter(interpreter)
|
: m_interpreter(interpreter)
|
||||||
, m_chain_node { nullptr, node }
|
, m_chain_node { nullptr, node }
|
||||||
{
|
{
|
||||||
m_interpreter.vm().call_frame().current_node = &node;
|
m_interpreter.vm().running_execution_context().current_node = &node;
|
||||||
m_interpreter.push_ast_node(m_chain_node);
|
m_interpreter.push_ast_node(m_chain_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
|
||||||
return perform_eval(script_value, global_object, vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct);
|
return perform_eval(script_value, global_object, vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct);
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.call_frame().current_node = interpreter.current_node();
|
vm.running_execution_context().current_node = interpreter.current_node();
|
||||||
Object* new_object = nullptr;
|
Object* new_object = nullptr;
|
||||||
Value result;
|
Value result;
|
||||||
if (is<NewExpression>(*this)) {
|
if (is<NewExpression>(*this)) {
|
||||||
|
@ -308,8 +308,8 @@ Value WithStatement::execute(Interpreter& interpreter, GlobalObject& global_obje
|
||||||
|
|
||||||
VERIFY(object);
|
VERIFY(object);
|
||||||
|
|
||||||
auto* object_environment_record = new_object_environment(*object, true, interpreter.vm().call_frame().lexical_environment);
|
auto* object_environment_record = new_object_environment(*object, true, interpreter.vm().running_execution_context().lexical_environment);
|
||||||
TemporaryChange<EnvironmentRecord*> scope_change(interpreter.vm().call_frame().lexical_environment, object_environment_record);
|
TemporaryChange<EnvironmentRecord*> scope_change(interpreter.vm().running_execution_context().lexical_environment, object_environment_record);
|
||||||
return interpreter.execute_statement(global_object, m_body).value_or(js_undefined());
|
return interpreter.execute_statement(global_object, m_body).value_or(js_undefined());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2049,8 +2049,8 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
|
||||||
|
|
||||||
HashMap<FlyString, Variable> parameters;
|
HashMap<FlyString, Variable> parameters;
|
||||||
parameters.set(m_handler->parameter(), Variable { exception->value(), DeclarationKind::Var });
|
parameters.set(m_handler->parameter(), Variable { exception->value(), DeclarationKind::Var });
|
||||||
auto* catch_scope = interpreter.heap().allocate<DeclarativeEnvironmentRecord>(global_object, move(parameters), interpreter.vm().call_frame().lexical_environment);
|
auto* catch_scope = interpreter.heap().allocate<DeclarativeEnvironmentRecord>(global_object, move(parameters), interpreter.vm().running_execution_context().lexical_environment);
|
||||||
TemporaryChange<EnvironmentRecord*> scope_change(interpreter.vm().call_frame().lexical_environment, catch_scope);
|
TemporaryChange<EnvironmentRecord*> scope_change(interpreter.vm().running_execution_context().lexical_environment, catch_scope);
|
||||||
result = interpreter.execute_statement(global_object, m_handler->body());
|
result = interpreter.execute_statement(global_object, m_handler->body());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,17 +44,17 @@ Value Interpreter::run(Executable const& executable, BasicBlock const* entry_poi
|
||||||
|
|
||||||
vm().set_last_value(Badge<Interpreter> {}, {});
|
vm().set_last_value(Badge<Interpreter> {}, {});
|
||||||
|
|
||||||
CallFrame global_call_frame;
|
ExecutionContext execution_context;
|
||||||
if (vm().call_stack().is_empty()) {
|
if (vm().execution_context_stack().is_empty()) {
|
||||||
global_call_frame.this_value = &global_object();
|
execution_context.this_value = &global_object();
|
||||||
static FlyString global_execution_context_name = "(*BC* global execution context)";
|
static FlyString global_execution_context_name = "(*BC* global execution context)";
|
||||||
global_call_frame.function_name = global_execution_context_name;
|
execution_context.function_name = global_execution_context_name;
|
||||||
global_call_frame.lexical_environment = &global_object().environment_record();
|
execution_context.lexical_environment = &global_object().environment_record();
|
||||||
global_call_frame.variable_environment = &global_object().environment_record();
|
execution_context.variable_environment = &global_object().environment_record();
|
||||||
VERIFY(!vm().exception());
|
VERIFY(!vm().exception());
|
||||||
// FIXME: How do we know if we're in strict mode? Maybe the Bytecode::Block should know this?
|
// FIXME: How do we know if we're in strict mode? Maybe the Bytecode::Block should know this?
|
||||||
// global_call_frame.is_strict_mode = ???;
|
// execution_context.is_strict_mode = ???;
|
||||||
vm().push_call_frame(global_call_frame, global_object());
|
vm().push_execution_context(execution_context, global_object());
|
||||||
VERIFY(!vm().exception());
|
VERIFY(!vm().exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ Value Interpreter::run(Executable const& executable, BasicBlock const* entry_poi
|
||||||
if (!m_register_windows.is_empty())
|
if (!m_register_windows.is_empty())
|
||||||
m_register_windows.last()[0] = return_value;
|
m_register_windows.last()[0] = return_value;
|
||||||
|
|
||||||
if (vm().call_stack().size() == 1)
|
if (vm().execution_context_stack().size() == 1)
|
||||||
vm().pop_call_frame();
|
vm().pop_execution_context();
|
||||||
|
|
||||||
vm().finish_execution_generation();
|
vm().finish_execution_generation();
|
||||||
|
|
||||||
|
|
|
@ -387,8 +387,8 @@ void PushDeclarativeEnvironmentRecord::execute_impl(Bytecode::Interpreter& inter
|
||||||
for (auto& it : m_variables)
|
for (auto& it : m_variables)
|
||||||
resolved_variables.set(interpreter.current_executable().get_string(it.key), it.value);
|
resolved_variables.set(interpreter.current_executable().get_string(it.key), it.value);
|
||||||
auto* environment_record = interpreter.vm().heap().allocate<DeclarativeEnvironmentRecord>(interpreter.global_object(), move(resolved_variables), interpreter.vm().lexical_environment());
|
auto* environment_record = interpreter.vm().heap().allocate<DeclarativeEnvironmentRecord>(interpreter.global_object(), move(resolved_variables), interpreter.vm().lexical_environment());
|
||||||
interpreter.vm().call_frame().lexical_environment = environment_record;
|
interpreter.vm().running_execution_context().lexical_environment = environment_record;
|
||||||
interpreter.vm().call_frame().variable_environment = environment_record;
|
interpreter.vm().running_execution_context().variable_environment = environment_record;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Yield::execute_impl(Bytecode::Interpreter& interpreter) const
|
void Yield::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
|
|
|
@ -135,10 +135,10 @@ VM& ConsoleClient::vm()
|
||||||
Vector<String> ConsoleClient::get_trace() const
|
Vector<String> ConsoleClient::get_trace() const
|
||||||
{
|
{
|
||||||
Vector<String> trace;
|
Vector<String> trace;
|
||||||
auto& call_stack = m_console.global_object().vm().call_stack();
|
auto& execution_context_stack = m_console.global_object().vm().execution_context_stack();
|
||||||
// -2 to skip the console.trace() call frame
|
// NOTE: -2 to skip the console.trace() execution context
|
||||||
for (ssize_t i = call_stack.size() - 2; i >= 0; --i)
|
for (ssize_t i = execution_context_stack.size() - 2; i >= 0; --i)
|
||||||
trace.append(call_stack[i]->function_name);
|
trace.append(execution_context_stack[i]->function_name);
|
||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,21 +46,21 @@ void Interpreter::run(GlobalObject& global_object, const Program& program)
|
||||||
|
|
||||||
vm.set_last_value(Badge<Interpreter> {}, {});
|
vm.set_last_value(Badge<Interpreter> {}, {});
|
||||||
|
|
||||||
CallFrame global_call_frame;
|
ExecutionContext execution_context;
|
||||||
global_call_frame.current_node = &program;
|
execution_context.current_node = &program;
|
||||||
global_call_frame.this_value = &global_object;
|
execution_context.this_value = &global_object;
|
||||||
static FlyString global_execution_context_name = "(global execution context)";
|
static FlyString global_execution_context_name = "(global execution context)";
|
||||||
global_call_frame.function_name = global_execution_context_name;
|
execution_context.function_name = global_execution_context_name;
|
||||||
global_call_frame.lexical_environment = &global_object.environment_record();
|
execution_context.lexical_environment = &global_object.environment_record();
|
||||||
global_call_frame.variable_environment = &global_object.environment_record();
|
execution_context.variable_environment = &global_object.environment_record();
|
||||||
VERIFY(!vm.exception());
|
VERIFY(!vm.exception());
|
||||||
global_call_frame.is_strict_mode = program.is_strict_mode();
|
execution_context.is_strict_mode = program.is_strict_mode();
|
||||||
vm.push_call_frame(global_call_frame, global_object);
|
vm.push_execution_context(execution_context, global_object);
|
||||||
VERIFY(!vm.exception());
|
VERIFY(!vm.exception());
|
||||||
auto value = program.execute(*this, global_object);
|
auto value = program.execute(*this, global_object);
|
||||||
vm.set_last_value(Badge<Interpreter> {}, value.value_or(js_undefined()));
|
vm.set_last_value(Badge<Interpreter> {}, value.value_or(js_undefined()));
|
||||||
|
|
||||||
vm.pop_call_frame();
|
vm.pop_execution_context();
|
||||||
|
|
||||||
// At this point we may have already run any queued promise jobs via on_call_stack_emptied,
|
// At this point we may have already run any queued promise jobs via on_call_stack_emptied,
|
||||||
// in which case this is a no-op.
|
// in which case this is a no-op.
|
||||||
|
@ -134,8 +134,8 @@ void Interpreter::enter_scope(const ScopeNode& scope_node, ScopeType scope_type,
|
||||||
|
|
||||||
if (!scope_variables_with_declaration_kind.is_empty()) {
|
if (!scope_variables_with_declaration_kind.is_empty()) {
|
||||||
auto* environment_record = heap().allocate<DeclarativeEnvironmentRecord>(global_object, move(scope_variables_with_declaration_kind), lexical_environment());
|
auto* environment_record = heap().allocate<DeclarativeEnvironmentRecord>(global_object, move(scope_variables_with_declaration_kind), lexical_environment());
|
||||||
vm().call_frame().lexical_environment = environment_record;
|
vm().running_execution_context().lexical_environment = environment_record;
|
||||||
vm().call_frame().variable_environment = environment_record;
|
vm().running_execution_context().variable_environment = environment_record;
|
||||||
pushed_environment_record = true;
|
pushed_environment_record = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +147,8 @@ void Interpreter::exit_scope(const ScopeNode& scope_node)
|
||||||
while (!m_scope_stack.is_empty()) {
|
while (!m_scope_stack.is_empty()) {
|
||||||
auto popped_scope = m_scope_stack.take_last();
|
auto popped_scope = m_scope_stack.take_last();
|
||||||
if (popped_scope.pushed_environment) {
|
if (popped_scope.pushed_environment) {
|
||||||
vm().call_frame().lexical_environment = vm().call_frame().lexical_environment->outer_environment();
|
vm().running_execution_context().lexical_environment = vm().running_execution_context().lexical_environment->outer_environment();
|
||||||
vm().call_frame().variable_environment = vm().call_frame().variable_environment->outer_environment();
|
vm().running_execution_context().variable_environment = vm().running_execution_context().variable_environment->outer_environment();
|
||||||
}
|
}
|
||||||
if (popped_scope.scope_node.ptr() == &scope_node)
|
if (popped_scope.scope_node.ptr() == &scope_node)
|
||||||
break;
|
break;
|
||||||
|
@ -200,8 +200,8 @@ Value Interpreter::execute_statement(GlobalObject& global_object, const Statemen
|
||||||
|
|
||||||
FunctionEnvironmentRecord* Interpreter::current_function_environment_record()
|
FunctionEnvironmentRecord* Interpreter::current_function_environment_record()
|
||||||
{
|
{
|
||||||
VERIFY(is<FunctionEnvironmentRecord>(vm().call_frame().lexical_environment));
|
VERIFY(is<FunctionEnvironmentRecord>(vm().running_execution_context().lexical_environment));
|
||||||
return static_cast<FunctionEnvironmentRecord*>(vm().call_frame().lexical_environment);
|
return static_cast<FunctionEnvironmentRecord*>(vm().running_execution_context().lexical_environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ Value perform_eval(Value x, GlobalObject& caller_realm, CallerMode strict_caller
|
||||||
if (direct == EvalMode::Direct)
|
if (direct == EvalMode::Direct)
|
||||||
return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
|
return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
|
||||||
|
|
||||||
TemporaryChange scope_change(vm.call_frame().lexical_environment, static_cast<EnvironmentRecord*>(&caller_realm.environment_record()));
|
TemporaryChange scope_change(vm.running_execution_context().lexical_environment, static_cast<EnvironmentRecord*>(&caller_realm.environment_record()));
|
||||||
return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
|
return interpreter.execute_statement(caller_realm, program).value_or(js_undefined());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,19 @@ Exception::Exception(Value value)
|
||||||
: m_value(value)
|
: m_value(value)
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
m_traceback.ensure_capacity(vm.call_stack().size());
|
m_traceback.ensure_capacity(vm.execution_context_stack().size());
|
||||||
for (ssize_t i = vm.call_stack().size() - 1; i >= 0; i--) {
|
for (ssize_t i = vm.execution_context_stack().size() - 1; i >= 0; i--) {
|
||||||
auto* call_frame = vm.call_stack()[i];
|
auto* context = vm.execution_context_stack()[i];
|
||||||
auto function_name = call_frame->function_name;
|
auto function_name = context->function_name;
|
||||||
if (function_name.is_empty())
|
if (function_name.is_empty())
|
||||||
function_name = "<anonymous>";
|
function_name = "<anonymous>";
|
||||||
m_traceback.empend(
|
m_traceback.empend(
|
||||||
move(function_name),
|
move(function_name),
|
||||||
// We might not have an AST node associated with the call frame, e.g. in promise
|
// We might not have an AST node associated with the execution context, e.g. in promise
|
||||||
// reaction jobs (which aren't called anywhere from the source code).
|
// reaction jobs (which aren't called anywhere from the source code).
|
||||||
// They're not going to generate any _unhandled_ exceptions though, so a meaningless
|
// They're not going to generate any _unhandled_ exceptions though, so a meaningless
|
||||||
// source range is fine.
|
// source range is fine.
|
||||||
call_frame->current_node ? call_frame->current_node->source_range() : SourceRange {});
|
context->current_node ? context->current_node->source_range() : SourceRange {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::bind)
|
||||||
|
|
||||||
Vector<Value> arguments;
|
Vector<Value> arguments;
|
||||||
if (vm.argument_count() > 1) {
|
if (vm.argument_count() > 1) {
|
||||||
arguments = vm.call_frame().arguments;
|
arguments = vm.running_execution_context().arguments;
|
||||||
arguments.remove(0);
|
arguments.remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ Value GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<V
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporarily switch to the captured environment record
|
// Temporarily switch to the captured environment record
|
||||||
TemporaryChange change { vm.call_frame().lexical_environment, m_environment_record };
|
TemporaryChange change { vm.running_execution_context().lexical_environment, m_environment_record };
|
||||||
|
|
||||||
m_previous_value = bytecode_interpreter->run(*m_generating_function->bytecode_executable(), next_block);
|
m_previous_value = bytecode_interpreter->run(*m_generating_function->bytecode_executable(), next_block);
|
||||||
|
|
||||||
|
|
|
@ -1151,32 +1151,32 @@ Value Object::invoke_internal(const StringOrSymbol& property_name, Optional<Mark
|
||||||
Value Object::call_native_property_getter(NativeProperty& property, Value this_value) const
|
Value Object::call_native_property_getter(NativeProperty& property, Value this_value) const
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
CallFrame call_frame;
|
ExecutionContext execution_context;
|
||||||
if (auto* interpreter = vm.interpreter_if_exists())
|
if (auto* interpreter = vm.interpreter_if_exists())
|
||||||
call_frame.current_node = interpreter->current_node();
|
execution_context.current_node = interpreter->current_node();
|
||||||
call_frame.is_strict_mode = vm.in_strict_mode();
|
execution_context.is_strict_mode = vm.in_strict_mode();
|
||||||
call_frame.this_value = this_value;
|
execution_context.this_value = this_value;
|
||||||
vm.push_call_frame(call_frame, global_object());
|
vm.push_execution_context(execution_context, global_object());
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
auto result = property.get(vm, global_object());
|
auto result = property.get(vm, global_object());
|
||||||
vm.pop_call_frame();
|
vm.pop_execution_context();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::call_native_property_setter(NativeProperty& property, Value this_value, Value setter_value) const
|
void Object::call_native_property_setter(NativeProperty& property, Value this_value, Value setter_value) const
|
||||||
{
|
{
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
CallFrame call_frame;
|
ExecutionContext execution_context;
|
||||||
if (auto* interpreter = vm.interpreter_if_exists())
|
if (auto* interpreter = vm.interpreter_if_exists())
|
||||||
call_frame.current_node = interpreter->current_node();
|
execution_context.current_node = interpreter->current_node();
|
||||||
call_frame.is_strict_mode = vm.in_strict_mode();
|
execution_context.is_strict_mode = vm.in_strict_mode();
|
||||||
call_frame.this_value = this_value;
|
execution_context.this_value = this_value;
|
||||||
vm.push_call_frame(call_frame, global_object());
|
vm.push_execution_context(execution_context, global_object());
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return;
|
return;
|
||||||
property.set(vm, global_object(), setter_value);
|
property.set(vm, global_object(), setter_value);
|
||||||
vm.pop_call_frame();
|
vm.pop_execution_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ Value ScriptFunction::execute_function_body()
|
||||||
auto* bytecode_interpreter = Bytecode::Interpreter::current();
|
auto* bytecode_interpreter = Bytecode::Interpreter::current();
|
||||||
|
|
||||||
auto prepare_arguments = [&] {
|
auto prepare_arguments = [&] {
|
||||||
auto& call_frame_args = vm.call_frame().arguments;
|
auto& execution_context_arguments = vm.running_execution_context().arguments;
|
||||||
for (size_t i = 0; i < m_parameters.size(); ++i) {
|
for (size_t i = 0; i < m_parameters.size(); ++i) {
|
||||||
auto& parameter = m_parameters[i];
|
auto& parameter = m_parameters[i];
|
||||||
parameter.binding.visit(
|
parameter.binding.visit(
|
||||||
|
@ -148,11 +148,11 @@ Value ScriptFunction::execute_function_body()
|
||||||
Value argument_value;
|
Value argument_value;
|
||||||
if (parameter.is_rest) {
|
if (parameter.is_rest) {
|
||||||
auto* array = Array::create(global_object());
|
auto* array = Array::create(global_object());
|
||||||
for (size_t rest_index = i; rest_index < call_frame_args.size(); ++rest_index)
|
for (size_t rest_index = i; rest_index < execution_context_arguments.size(); ++rest_index)
|
||||||
array->indexed_properties().append(call_frame_args[rest_index]);
|
array->indexed_properties().append(execution_context_arguments[rest_index]);
|
||||||
argument_value = move(array);
|
argument_value = move(array);
|
||||||
} else if (i < call_frame_args.size() && !call_frame_args[i].is_undefined()) {
|
} else if (i < execution_context_arguments.size() && !execution_context_arguments[i].is_undefined()) {
|
||||||
argument_value = call_frame_args[i];
|
argument_value = execution_context_arguments[i];
|
||||||
} else if (parameter.default_value) {
|
} else if (parameter.default_value) {
|
||||||
// FIXME: Support default arguments in the bytecode world!
|
// FIXME: Support default arguments in the bytecode world!
|
||||||
if (!bytecode_interpreter)
|
if (!bytecode_interpreter)
|
||||||
|
@ -163,9 +163,9 @@ Value ScriptFunction::execute_function_body()
|
||||||
argument_value = js_undefined();
|
argument_value = js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= call_frame_args.size())
|
if (i >= execution_context_arguments.size())
|
||||||
call_frame_args.resize(i + 1);
|
execution_context_arguments.resize(i + 1);
|
||||||
call_frame_args[i] = argument_value;
|
execution_context_arguments[i] = argument_value;
|
||||||
vm.assign(param, argument_value, global_object(), true, vm.lexical_environment());
|
vm.assign(param, argument_value, global_object(), true, vm.lexical_environment());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ Value ScriptFunction::execute_function_body()
|
||||||
if (m_kind != FunctionKind::Generator)
|
if (m_kind != FunctionKind::Generator)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
return GeneratorObject::create(global_object(), result, this, vm.call_frame().lexical_environment, bytecode_interpreter->snapshot_frame());
|
return GeneratorObject::create(global_object(), result, this, vm.running_execution_context().lexical_environment, bytecode_interpreter->snapshot_frame());
|
||||||
} else {
|
} else {
|
||||||
VERIFY(m_kind != FunctionKind::Generator);
|
VERIFY(m_kind != FunctionKind::Generator);
|
||||||
OwnPtr<Interpreter> local_interpreter;
|
OwnPtr<Interpreter> local_interpreter;
|
||||||
|
|
|
@ -97,15 +97,15 @@ void VM::gather_roots(HashTable<Cell*>& roots)
|
||||||
if (m_last_value.is_cell())
|
if (m_last_value.is_cell())
|
||||||
roots.set(&m_last_value.as_cell());
|
roots.set(&m_last_value.as_cell());
|
||||||
|
|
||||||
for (auto& call_frame : m_call_stack) {
|
for (auto& execution_context : m_execution_context_stack) {
|
||||||
if (call_frame->this_value.is_cell())
|
if (execution_context->this_value.is_cell())
|
||||||
roots.set(&call_frame->this_value.as_cell());
|
roots.set(&execution_context->this_value.as_cell());
|
||||||
roots.set(call_frame->arguments_object);
|
roots.set(execution_context->arguments_object);
|
||||||
for (auto& argument : call_frame->arguments) {
|
for (auto& argument : execution_context->arguments) {
|
||||||
if (argument.is_cell())
|
if (argument.is_cell())
|
||||||
roots.set(&argument.as_cell());
|
roots.set(&argument.as_cell());
|
||||||
}
|
}
|
||||||
roots.set(call_frame->lexical_environment);
|
roots.set(execution_context->lexical_environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||||
|
@ -134,7 +134,7 @@ Symbol* VM::get_global_symbol(const String& description)
|
||||||
void VM::set_variable(const FlyString& name, Value value, GlobalObject& global_object, bool first_assignment, EnvironmentRecord* specific_scope)
|
void VM::set_variable(const FlyString& name, Value value, GlobalObject& global_object, bool first_assignment, EnvironmentRecord* specific_scope)
|
||||||
{
|
{
|
||||||
Optional<Variable> possible_match;
|
Optional<Variable> possible_match;
|
||||||
if (!specific_scope && m_call_stack.size()) {
|
if (!specific_scope && m_execution_context_stack.size()) {
|
||||||
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||||
possible_match = environment_record->get_from_environment_record(name);
|
possible_match = environment_record->get_from_environment_record(name);
|
||||||
if (possible_match.has_value()) {
|
if (possible_match.has_value()) {
|
||||||
|
@ -166,7 +166,7 @@ bool VM::delete_variable(FlyString const& name)
|
||||||
{
|
{
|
||||||
EnvironmentRecord* specific_scope = nullptr;
|
EnvironmentRecord* specific_scope = nullptr;
|
||||||
Optional<Variable> possible_match;
|
Optional<Variable> possible_match;
|
||||||
if (!m_call_stack.is_empty()) {
|
if (!m_execution_context_stack.is_empty()) {
|
||||||
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||||
possible_match = environment_record->get_from_environment_record(name);
|
possible_match = environment_record->get_from_environment_record(name);
|
||||||
if (possible_match.has_value()) {
|
if (possible_match.has_value()) {
|
||||||
|
@ -356,8 +356,9 @@ void VM::assign(const NonnullRefPtr<BindingPattern>& target, Value value, Global
|
||||||
|
|
||||||
Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
if (!m_call_stack.is_empty()) {
|
if (!m_execution_context_stack.is_empty()) {
|
||||||
if (name == names.arguments.as_string() && !call_frame().callee.is_empty()) {
|
auto& context = running_execution_context();
|
||||||
|
if (name == names.arguments.as_string() && context.callee) {
|
||||||
// HACK: Special handling for the name "arguments":
|
// HACK: Special handling for the name "arguments":
|
||||||
// If the name "arguments" is defined in the current scope, for example via
|
// If the name "arguments" is defined in the current scope, for example via
|
||||||
// a function parameter, or by a local var declaration, we use that.
|
// a function parameter, or by a local var declaration, we use that.
|
||||||
|
@ -366,14 +367,14 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
||||||
auto possible_match = lexical_environment()->get_from_environment_record(name);
|
auto possible_match = lexical_environment()->get_from_environment_record(name);
|
||||||
if (possible_match.has_value())
|
if (possible_match.has_value())
|
||||||
return possible_match.value().value;
|
return possible_match.value().value;
|
||||||
if (!call_frame().arguments_object) {
|
if (!context.arguments_object) {
|
||||||
call_frame().arguments_object = Array::create(global_object);
|
context.arguments_object = Array::create(global_object);
|
||||||
call_frame().arguments_object->put(names.callee, call_frame().callee);
|
context.arguments_object->put(names.callee, context.callee);
|
||||||
for (auto argument : call_frame().arguments) {
|
for (auto argument : context.arguments) {
|
||||||
call_frame().arguments_object->indexed_properties().append(argument);
|
context.arguments_object->indexed_properties().append(argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return call_frame().arguments_object;
|
return context.arguments_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||||
|
@ -403,26 +404,26 @@ Reference VM::get_reference(const FlyString& name)
|
||||||
Value VM::construct(Function& function, Function& new_target, Optional<MarkedValueList> arguments)
|
Value VM::construct(Function& function, Function& new_target, Optional<MarkedValueList> arguments)
|
||||||
{
|
{
|
||||||
auto& global_object = function.global_object();
|
auto& global_object = function.global_object();
|
||||||
CallFrame call_frame;
|
ExecutionContext execution_context;
|
||||||
call_frame.callee = &function;
|
execution_context.callee = &function;
|
||||||
if (auto* interpreter = interpreter_if_exists())
|
if (auto* interpreter = interpreter_if_exists())
|
||||||
call_frame.current_node = interpreter->current_node();
|
execution_context.current_node = interpreter->current_node();
|
||||||
call_frame.is_strict_mode = function.is_strict_mode();
|
execution_context.is_strict_mode = function.is_strict_mode();
|
||||||
|
|
||||||
push_call_frame(call_frame, global_object);
|
push_execution_context(execution_context, global_object);
|
||||||
if (exception())
|
if (exception())
|
||||||
return {};
|
return {};
|
||||||
ArmedScopeGuard call_frame_popper = [&] {
|
ArmedScopeGuard pop_guard = [&] {
|
||||||
pop_call_frame();
|
pop_execution_context();
|
||||||
};
|
};
|
||||||
|
|
||||||
call_frame.function_name = function.name();
|
execution_context.function_name = function.name();
|
||||||
call_frame.arguments = function.bound_arguments();
|
execution_context.arguments = function.bound_arguments();
|
||||||
if (arguments.has_value())
|
if (arguments.has_value())
|
||||||
call_frame.arguments.extend(arguments.value().values());
|
execution_context.arguments.extend(arguments.value().values());
|
||||||
auto* environment = function.create_environment_record();
|
auto* environment = function.create_environment_record();
|
||||||
call_frame.lexical_environment = environment;
|
execution_context.lexical_environment = environment;
|
||||||
call_frame.variable_environment = environment;
|
execution_context.variable_environment = environment;
|
||||||
if (environment)
|
if (environment)
|
||||||
environment->set_new_target(&new_target);
|
environment->set_new_target(&new_target);
|
||||||
|
|
||||||
|
@ -445,13 +446,13 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
|
||||||
|
|
||||||
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
// If we are a Derived constructor, |this| has not been constructed before super is called.
|
||||||
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
|
||||||
call_frame.this_value = this_value;
|
execution_context.this_value = this_value;
|
||||||
auto result = function.construct(new_target);
|
auto result = function.construct(new_target);
|
||||||
|
|
||||||
if (environment)
|
if (environment)
|
||||||
this_value = environment->get_this_binding(global_object);
|
this_value = environment->get_this_binding(global_object);
|
||||||
pop_call_frame();
|
pop_execution_context();
|
||||||
call_frame_popper.disarm();
|
pop_guard.disarm();
|
||||||
|
|
||||||
// If we are constructing an instance of a derived class,
|
// If we are constructing an instance of a derived class,
|
||||||
// set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
|
// set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
|
||||||
|
@ -509,41 +510,41 @@ Value VM::call_internal(Function& function, Value this_value, Optional<MarkedVal
|
||||||
VERIFY(!exception());
|
VERIFY(!exception());
|
||||||
VERIFY(!this_value.is_empty());
|
VERIFY(!this_value.is_empty());
|
||||||
|
|
||||||
CallFrame call_frame;
|
ExecutionContext execution_context;
|
||||||
call_frame.callee = &function;
|
execution_context.callee = &function;
|
||||||
if (auto* interpreter = interpreter_if_exists())
|
if (auto* interpreter = interpreter_if_exists())
|
||||||
call_frame.current_node = interpreter->current_node();
|
execution_context.current_node = interpreter->current_node();
|
||||||
call_frame.is_strict_mode = function.is_strict_mode();
|
execution_context.is_strict_mode = function.is_strict_mode();
|
||||||
call_frame.function_name = function.name();
|
execution_context.function_name = function.name();
|
||||||
call_frame.this_value = function.bound_this().value_or(this_value);
|
execution_context.this_value = function.bound_this().value_or(this_value);
|
||||||
call_frame.arguments = function.bound_arguments();
|
execution_context.arguments = function.bound_arguments();
|
||||||
if (arguments.has_value())
|
if (arguments.has_value())
|
||||||
call_frame.arguments.extend(arguments.value().values());
|
execution_context.arguments.extend(arguments.value().values());
|
||||||
auto* environment = function.create_environment_record();
|
auto* environment = function.create_environment_record();
|
||||||
call_frame.lexical_environment = environment;
|
execution_context.lexical_environment = environment;
|
||||||
call_frame.variable_environment = environment;
|
execution_context.variable_environment = environment;
|
||||||
|
|
||||||
if (environment) {
|
if (environment) {
|
||||||
VERIFY(environment->this_binding_status() == FunctionEnvironmentRecord::ThisBindingStatus::Uninitialized);
|
VERIFY(environment->this_binding_status() == FunctionEnvironmentRecord::ThisBindingStatus::Uninitialized);
|
||||||
environment->bind_this_value(function.global_object(), call_frame.this_value);
|
environment->bind_this_value(function.global_object(), execution_context.this_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exception())
|
if (exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
push_call_frame(call_frame, function.global_object());
|
push_execution_context(execution_context, function.global_object());
|
||||||
if (exception())
|
if (exception())
|
||||||
return {};
|
return {};
|
||||||
auto result = function.call();
|
auto result = function.call();
|
||||||
pop_call_frame();
|
pop_execution_context();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VM::in_strict_mode() const
|
bool VM::in_strict_mode() const
|
||||||
{
|
{
|
||||||
if (call_stack().is_empty())
|
if (execution_context_stack().is_empty())
|
||||||
return false;
|
return false;
|
||||||
return call_frame().is_strict_mode;
|
return running_execution_context().is_strict_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::run_queued_promise_jobs()
|
void VM::run_queued_promise_jobs()
|
||||||
|
@ -602,8 +603,8 @@ void VM::promise_rejection_tracker(const Promise& promise, Promise::RejectionOpe
|
||||||
|
|
||||||
void VM::dump_backtrace() const
|
void VM::dump_backtrace() const
|
||||||
{
|
{
|
||||||
for (ssize_t i = m_call_stack.size() - 1; i >= 0; --i)
|
for (ssize_t i = m_execution_context_stack.size() - 1; i >= 0; --i)
|
||||||
dbgln("-> {}", m_call_stack[i]->function_name);
|
dbgln("-> {}", m_execution_context_stack[i]->function_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::dump_environment_record_chain() const
|
void VM::dump_environment_record_chain() const
|
||||||
|
|
|
@ -42,7 +42,7 @@ struct ScopeFrame {
|
||||||
bool pushed_environment { false };
|
bool pushed_environment { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CallFrame {
|
struct ExecutionContext {
|
||||||
const ASTNode* current_node { nullptr };
|
const ASTNode* current_node { nullptr };
|
||||||
FlyString function_name;
|
FlyString function_name;
|
||||||
Value callee;
|
Value callee;
|
||||||
|
@ -100,7 +100,7 @@ public:
|
||||||
return *m_single_ascii_character_strings[character];
|
return *m_single_ascii_character_strings[character];
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_call_frame(CallFrame& call_frame, GlobalObject& global_object)
|
void push_execution_context(ExecutionContext& context, GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
VERIFY(!exception());
|
VERIFY(!exception());
|
||||||
// Ensure we got some stack space left, so the next function call doesn't kill us.
|
// Ensure we got some stack space left, so the next function call doesn't kill us.
|
||||||
|
@ -108,58 +108,58 @@ public:
|
||||||
if (m_stack_info.size_free() < 32 * KiB)
|
if (m_stack_info.size_free() < 32 * KiB)
|
||||||
throw_exception<Error>(global_object, "Call stack size limit exceeded");
|
throw_exception<Error>(global_object, "Call stack size limit exceeded");
|
||||||
else
|
else
|
||||||
m_call_stack.append(&call_frame);
|
m_execution_context_stack.append(&context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_call_frame()
|
void pop_execution_context()
|
||||||
{
|
{
|
||||||
m_call_stack.take_last();
|
m_execution_context_stack.take_last();
|
||||||
if (m_call_stack.is_empty() && on_call_stack_emptied)
|
if (m_execution_context_stack.is_empty() && on_call_stack_emptied)
|
||||||
on_call_stack_emptied();
|
on_call_stack_emptied();
|
||||||
}
|
}
|
||||||
|
|
||||||
CallFrame& call_frame() { return *m_call_stack.last(); }
|
ExecutionContext& running_execution_context() { return *m_execution_context_stack.last(); }
|
||||||
const CallFrame& call_frame() const { return *m_call_stack.last(); }
|
ExecutionContext const& running_execution_context() const { return *m_execution_context_stack.last(); }
|
||||||
const Vector<CallFrame*>& call_stack() const { return m_call_stack; }
|
Vector<ExecutionContext*> const& execution_context_stack() const { return m_execution_context_stack; }
|
||||||
Vector<CallFrame*>& call_stack() { return m_call_stack; }
|
Vector<ExecutionContext*>& execution_context_stack() { return m_execution_context_stack; }
|
||||||
|
|
||||||
EnvironmentRecord const* lexical_environment() const { return call_frame().lexical_environment; }
|
EnvironmentRecord const* lexical_environment() const { return running_execution_context().lexical_environment; }
|
||||||
EnvironmentRecord* lexical_environment() { return call_frame().lexical_environment; }
|
EnvironmentRecord* lexical_environment() { return running_execution_context().lexical_environment; }
|
||||||
|
|
||||||
EnvironmentRecord const* variable_environment() const { return call_frame().variable_environment; }
|
EnvironmentRecord const* variable_environment() const { return running_execution_context().variable_environment; }
|
||||||
EnvironmentRecord* variable_environment() { return call_frame().variable_environment; }
|
EnvironmentRecord* variable_environment() { return running_execution_context().variable_environment; }
|
||||||
|
|
||||||
bool in_strict_mode() const;
|
bool in_strict_mode() const;
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_argument(Callback callback)
|
void for_each_argument(Callback callback)
|
||||||
{
|
{
|
||||||
if (m_call_stack.is_empty())
|
if (m_execution_context_stack.is_empty())
|
||||||
return;
|
return;
|
||||||
for (auto& value : call_frame().arguments)
|
for (auto& value : running_execution_context().arguments)
|
||||||
callback(value);
|
callback(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t argument_count() const
|
size_t argument_count() const
|
||||||
{
|
{
|
||||||
if (m_call_stack.is_empty())
|
if (m_execution_context_stack.is_empty())
|
||||||
return 0;
|
return 0;
|
||||||
return call_frame().arguments.size();
|
return running_execution_context().arguments.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value argument(size_t index) const
|
Value argument(size_t index) const
|
||||||
{
|
{
|
||||||
if (m_call_stack.is_empty())
|
if (m_execution_context_stack.is_empty())
|
||||||
return {};
|
return {};
|
||||||
auto& arguments = call_frame().arguments;
|
auto& arguments = running_execution_context().arguments;
|
||||||
return index < arguments.size() ? arguments[index] : js_undefined();
|
return index < arguments.size() ? arguments[index] : js_undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value this_value(Object& global_object) const
|
Value this_value(Object& global_object) const
|
||||||
{
|
{
|
||||||
if (m_call_stack.is_empty())
|
if (m_execution_context_stack.is_empty())
|
||||||
return &global_object;
|
return &global_object;
|
||||||
return call_frame().this_value;
|
return running_execution_context().this_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value last_value() const { return m_last_value; }
|
Value last_value() const { return m_last_value; }
|
||||||
|
@ -264,7 +264,7 @@ private:
|
||||||
Heap m_heap;
|
Heap m_heap;
|
||||||
Vector<Interpreter*> m_interpreters;
|
Vector<Interpreter*> m_interpreters;
|
||||||
|
|
||||||
Vector<CallFrame*> m_call_stack;
|
Vector<ExecutionContext*> m_execution_context_stack;
|
||||||
|
|
||||||
Value m_last_value;
|
Value m_last_value;
|
||||||
ScopeType m_unwind_until { ScopeType::None };
|
ScopeType m_unwind_until { ScopeType::None };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue