mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 17:27:35 +00:00
LibJS: Split the per-call-frame environment into lexical and variable
To better follow the spec, we need to distinguish between the current execution context's lexical environment and variable environment. This patch moves us to having two record pointers, although both of them point at the same environment records for now.
This commit is contained in:
parent
aabd82d508
commit
1d20380859
13 changed files with 52 additions and 41 deletions
|
@ -181,7 +181,7 @@ ObjectEnvironmentRecord* new_object_environment(Object& object, bool is_with_env
|
|||
EnvironmentRecord& get_this_environment(VM& vm)
|
||||
{
|
||||
// FIXME: Should be the *lexical* environment.
|
||||
for (auto* env = vm.current_environment_record(); env; env = env->outer_environment()) {
|
||||
for (auto* env = vm.lexical_environment(); env; env = env->outer_environment()) {
|
||||
if (env->has_this_binding())
|
||||
return *env;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ Value GeneratorFunctionConstructor::construct(Function& new_target)
|
|||
block.dump(executable);
|
||||
}
|
||||
|
||||
return ScriptFunction::create(global_object(), function->name(), function->body(), function->parameters(), function->function_length(), vm().current_environment_record(), FunctionKind::Generator, function->is_strict_mode(), false);
|
||||
return ScriptFunction::create(global_object(), function->name(), function->body(), function->parameters(), function->function_length(), vm().lexical_environment(), FunctionKind::Generator, function->is_strict_mode(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ Value GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<V
|
|||
}
|
||||
|
||||
// Temporarily switch to the captured environment record
|
||||
TemporaryChange change { vm.call_frame().environment_record, m_environment_record };
|
||||
TemporaryChange change { vm.call_frame().lexical_environment, m_environment_record };
|
||||
|
||||
m_previous_value = bytecode_interpreter->run(*m_generating_function->bytecode_executable(), next_block);
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ JS_DEFINE_NATIVE_FUNCTION(GlobalObject::eval)
|
|||
}
|
||||
|
||||
auto& caller_frame = vm.call_stack().at(vm.call_stack().size() - 2);
|
||||
TemporaryChange scope_change(vm.call_frame().environment_record, caller_frame->environment_record);
|
||||
TemporaryChange scope_change(vm.call_frame().lexical_environment, caller_frame->lexical_environment);
|
||||
|
||||
auto& interpreter = vm.interpreter();
|
||||
return interpreter.execute_statement(global_object, program).value_or(js_undefined());
|
||||
|
|
|
@ -166,7 +166,7 @@ Value ScriptFunction::execute_function_body()
|
|||
if (i >= call_frame_args.size())
|
||||
call_frame_args.resize(i + 1);
|
||||
call_frame_args[i] = argument_value;
|
||||
vm.assign(param, argument_value, global_object(), true, vm.current_environment_record());
|
||||
vm.assign(param, argument_value, global_object(), true, vm.lexical_environment());
|
||||
});
|
||||
|
||||
if (vm.exception())
|
||||
|
@ -191,7 +191,7 @@ Value ScriptFunction::execute_function_body()
|
|||
if (m_kind != FunctionKind::Generator)
|
||||
return result;
|
||||
|
||||
return GeneratorObject::create(global_object(), result, this, vm.call_frame().environment_record, bytecode_interpreter->snapshot_frame());
|
||||
return GeneratorObject::create(global_object(), result, this, vm.call_frame().lexical_environment, bytecode_interpreter->snapshot_frame());
|
||||
} else {
|
||||
VERIFY(m_kind != FunctionKind::Generator);
|
||||
OwnPtr<Interpreter> local_interpreter;
|
||||
|
|
|
@ -107,7 +107,7 @@ void VM::gather_roots(HashTable<Cell*>& roots)
|
|||
if (argument.is_cell())
|
||||
roots.set(&argument.as_cell());
|
||||
}
|
||||
roots.set(call_frame->environment_record);
|
||||
roots.set(call_frame->lexical_environment);
|
||||
}
|
||||
|
||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||
|
@ -137,7 +137,7 @@ void VM::set_variable(const FlyString& name, Value value, GlobalObject& global_o
|
|||
{
|
||||
Optional<Variable> possible_match;
|
||||
if (!specific_scope && m_call_stack.size()) {
|
||||
for (auto* environment_record = current_environment_record(); 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);
|
||||
if (possible_match.has_value()) {
|
||||
specific_scope = environment_record;
|
||||
|
@ -169,7 +169,7 @@ bool VM::delete_variable(FlyString const& name)
|
|||
EnvironmentRecord* specific_scope = nullptr;
|
||||
Optional<Variable> possible_match;
|
||||
if (!m_call_stack.is_empty()) {
|
||||
for (auto* environment_record = current_environment_record(); 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);
|
||||
if (possible_match.has_value()) {
|
||||
specific_scope = environment_record;
|
||||
|
@ -365,7 +365,7 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
|||
// a function parameter, or by a local var declaration, we use that.
|
||||
// Otherwise, we return a lazily constructed Array with all the argument values.
|
||||
// FIXME: Do something much more spec-compliant.
|
||||
auto possible_match = current_environment_record()->get_from_environment_record(name);
|
||||
auto possible_match = lexical_environment()->get_from_environment_record(name);
|
||||
if (possible_match.has_value())
|
||||
return possible_match.value().value;
|
||||
if (!call_frame().arguments_object) {
|
||||
|
@ -378,7 +378,7 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
|||
return call_frame().arguments_object;
|
||||
}
|
||||
|
||||
for (auto* environment_record = current_environment_record(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||
auto possible_match = environment_record->get_from_environment_record(name);
|
||||
if (exception())
|
||||
return {};
|
||||
|
@ -395,7 +395,7 @@ Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
|
|||
Reference VM::get_reference(const FlyString& name)
|
||||
{
|
||||
if (m_call_stack.size()) {
|
||||
for (auto* environment_record = current_environment_record(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||
if (is<GlobalObject>(environment_record))
|
||||
break;
|
||||
auto possible_match = environment_record->get_from_environment_record(name);
|
||||
|
@ -427,7 +427,8 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
|
|||
if (arguments.has_value())
|
||||
call_frame.arguments.extend(arguments.value().values());
|
||||
auto* environment = function.create_environment_record();
|
||||
call_frame.environment_record = environment;
|
||||
call_frame.lexical_environment = environment;
|
||||
call_frame.variable_environment = environment;
|
||||
if (environment)
|
||||
environment->set_new_target(&new_target);
|
||||
|
||||
|
@ -462,8 +463,8 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
|
|||
// set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
|
||||
if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
|
||||
if (environment) {
|
||||
VERIFY(is<FunctionEnvironmentRecord>(current_environment_record()));
|
||||
static_cast<FunctionEnvironmentRecord*>(current_environment_record())->replace_this_binding(result);
|
||||
VERIFY(is<FunctionEnvironmentRecord>(lexical_environment()));
|
||||
static_cast<FunctionEnvironmentRecord*>(lexical_environment())->replace_this_binding(result);
|
||||
}
|
||||
auto prototype = new_target.get(names.prototype);
|
||||
if (exception())
|
||||
|
@ -525,7 +526,8 @@ Value VM::call_internal(Function& function, Value this_value, Optional<MarkedVal
|
|||
if (arguments.has_value())
|
||||
call_frame.arguments.extend(arguments.value().values());
|
||||
auto* environment = function.create_environment_record();
|
||||
call_frame.environment_record = environment;
|
||||
call_frame.lexical_environment = environment;
|
||||
call_frame.variable_environment = environment;
|
||||
|
||||
if (environment) {
|
||||
VERIFY(environment->this_binding_status() == FunctionEnvironmentRecord::ThisBindingStatus::Uninitialized);
|
||||
|
@ -612,7 +614,7 @@ void VM::dump_backtrace() const
|
|||
|
||||
void VM::dump_environment_record_chain() const
|
||||
{
|
||||
for (auto* environment_record = current_environment_record(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||
for (auto* environment_record = lexical_environment(); environment_record; environment_record = environment_record->outer_environment()) {
|
||||
dbgln("+> {} ({:p})", environment_record->class_name(), environment_record);
|
||||
if (is<DeclarativeEnvironmentRecord>(*environment_record)) {
|
||||
auto& declarative_environment_record = static_cast<DeclarativeEnvironmentRecord const&>(*environment_record);
|
||||
|
|
|
@ -49,7 +49,8 @@ struct CallFrame {
|
|||
Value this_value;
|
||||
Vector<Value> arguments;
|
||||
Array* arguments_object { nullptr };
|
||||
EnvironmentRecord* environment_record { nullptr };
|
||||
EnvironmentRecord* lexical_environment { nullptr };
|
||||
EnvironmentRecord* variable_environment { nullptr };
|
||||
bool is_strict_mode { false };
|
||||
};
|
||||
|
||||
|
@ -122,8 +123,11 @@ public:
|
|||
const Vector<CallFrame*>& call_stack() const { return m_call_stack; }
|
||||
Vector<CallFrame*>& call_stack() { return m_call_stack; }
|
||||
|
||||
EnvironmentRecord const* current_environment_record() const { return call_frame().environment_record; }
|
||||
EnvironmentRecord* current_environment_record() { return call_frame().environment_record; }
|
||||
EnvironmentRecord const* lexical_environment() const { return call_frame().lexical_environment; }
|
||||
EnvironmentRecord* lexical_environment() { return call_frame().lexical_environment; }
|
||||
|
||||
EnvironmentRecord const* variable_environment() const { return call_frame().variable_environment; }
|
||||
EnvironmentRecord* variable_environment() { return call_frame().variable_environment; }
|
||||
|
||||
bool in_strict_mode() const;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue