LibJS: Use regular stack for VM call frames instead of Vector storage
Keeping the VM call frames in a Vector could cause them to move around underneath us due to Vector resizing. Avoid this issue by allocating CallFrame objects on the stack and having the VM simply keep a list of pointers to each CallFrame, instead of the CallFrames themselves. Fixes #3830. Fixes #3951.
This commit is contained in:
parent
a950d3dd5f
commit
43ff2ea8d8
Notes:
sideshowbarker
2024-07-19 01:31:54 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/43ff2ea8d88
6 changed files with 36 additions and 27 deletions
|
@ -131,7 +131,7 @@ Vector<String> ConsoleClient::get_trace() const
|
|||
auto& call_stack = m_console.global_object().vm().call_stack();
|
||||
// -2 to skip the console.trace() call frame
|
||||
for (ssize_t i = call_stack.size() - 2; i >= 0; --i)
|
||||
trace.append(call_stack[i].function_name);
|
||||
trace.append(call_stack[i]->function_name);
|
||||
return trace;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@ Value Interpreter::run(GlobalObject& global_object, const Program& program)
|
|||
global_call_frame.is_strict_mode = program.is_strict_mode();
|
||||
if (vm().exception())
|
||||
return {};
|
||||
vm().call_stack().append(move(global_call_frame));
|
||||
|
||||
vm().push_call_frame(global_call_frame);
|
||||
auto result = program.execute(*this, global_object);
|
||||
vm().pop_call_frame();
|
||||
return result;
|
||||
|
@ -128,7 +128,7 @@ void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector argume
|
|||
|
||||
if (!scope_variables_with_declaration_kind.is_empty()) {
|
||||
auto* block_lexical_environment = heap().allocate<LexicalEnvironment>(global_object, move(scope_variables_with_declaration_kind), current_environment());
|
||||
vm().call_stack().last().environment = block_lexical_environment;
|
||||
vm().call_frame().environment = block_lexical_environment;
|
||||
pushed_lexical_environment = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ Exception::Exception(Value value)
|
|||
{
|
||||
auto& call_stack = vm().call_stack();
|
||||
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) {
|
||||
String function_name = call_stack[i].function_name;
|
||||
String function_name = call_stack[i]->function_name;
|
||||
if (function_name.is_empty())
|
||||
function_name = "<anonymous>";
|
||||
m_trace.append(function_name);
|
||||
|
|
|
@ -899,8 +899,10 @@ Value Object::invoke(const StringOrSymbol& property_name, Optional<MarkedValueLi
|
|||
Value Object::call_native_property_getter(Object* this_object, Value property) const
|
||||
{
|
||||
ASSERT(property.is_native_property());
|
||||
auto& call_frame = vm().push_call_frame(vm().in_strict_mode());
|
||||
CallFrame call_frame;
|
||||
call_frame.is_strict_mode = vm().in_strict_mode();
|
||||
call_frame.this_value = this_object;
|
||||
vm().push_call_frame(call_frame);
|
||||
auto result = property.as_native_property().get(vm(), global_object());
|
||||
vm().pop_call_frame();
|
||||
return result;
|
||||
|
@ -909,8 +911,10 @@ Value Object::call_native_property_getter(Object* this_object, Value property) c
|
|||
void Object::call_native_property_setter(Object* this_object, Value property, Value value) const
|
||||
{
|
||||
ASSERT(property.is_native_property());
|
||||
auto& call_frame = vm().push_call_frame(vm().in_strict_mode());
|
||||
CallFrame call_frame;
|
||||
call_frame.is_strict_mode = vm().in_strict_mode();
|
||||
call_frame.this_value = this_object;
|
||||
vm().push_call_frame(call_frame);
|
||||
property.as_native_property().set(vm(), global_object(), value);
|
||||
vm().pop_call_frame();
|
||||
}
|
||||
|
|
|
@ -110,13 +110,13 @@ void VM::gather_roots(HashTable<Cell*>& roots)
|
|||
roots.set(m_last_value.as_cell());
|
||||
|
||||
for (auto& call_frame : m_call_stack) {
|
||||
if (call_frame.this_value.is_cell())
|
||||
roots.set(call_frame.this_value.as_cell());
|
||||
for (auto& argument : call_frame.arguments) {
|
||||
if (call_frame->this_value.is_cell())
|
||||
roots.set(call_frame->this_value.as_cell());
|
||||
for (auto& argument : call_frame->arguments) {
|
||||
if (argument.is_cell())
|
||||
roots.set(argument.as_cell());
|
||||
}
|
||||
roots.set(call_frame.environment);
|
||||
roots.set(call_frame->environment);
|
||||
}
|
||||
|
||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||
|
@ -194,7 +194,9 @@ Reference VM::get_reference(const FlyString& name)
|
|||
|
||||
Value VM::construct(Function& function, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject& global_object)
|
||||
{
|
||||
auto& call_frame = push_call_frame(function.is_strict_mode());
|
||||
CallFrame call_frame;
|
||||
call_frame.is_strict_mode = function.is_strict_mode();
|
||||
push_call_frame(call_frame);
|
||||
|
||||
ArmedScopeGuard call_frame_popper = [&] {
|
||||
pop_call_frame();
|
||||
|
@ -310,7 +312,8 @@ Value VM::call_internal(Function& function, Value this_value, Optional<MarkedVal
|
|||
{
|
||||
ASSERT(!exception());
|
||||
|
||||
auto& call_frame = push_call_frame(function.is_strict_mode());
|
||||
CallFrame call_frame;
|
||||
call_frame.is_strict_mode = function.is_strict_mode();
|
||||
call_frame.function_name = function.name();
|
||||
call_frame.this_value = function.bound_this().value_or(this_value);
|
||||
call_frame.arguments = function.bound_arguments();
|
||||
|
@ -321,6 +324,7 @@ Value VM::call_internal(Function& function, Value this_value, Optional<MarkedVal
|
|||
ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
|
||||
call_frame.environment->bind_this_value(function.global_object(), call_frame.this_value);
|
||||
|
||||
push_call_frame(call_frame);
|
||||
auto result = function.call();
|
||||
pop_call_frame();
|
||||
return result;
|
||||
|
|
|
@ -114,19 +114,20 @@ public:
|
|||
return *m_single_ascii_character_strings[character];
|
||||
}
|
||||
|
||||
CallFrame& push_call_frame(bool strict_mode = false)
|
||||
void push_call_frame(CallFrame& call_frame)
|
||||
{
|
||||
m_call_stack.append({ {}, js_undefined(), {}, nullptr, strict_mode });
|
||||
return m_call_stack.last();
|
||||
m_call_stack.append(&call_frame);
|
||||
}
|
||||
void pop_call_frame() { m_call_stack.take_last(); }
|
||||
CallFrame& call_frame() { return m_call_stack.last(); }
|
||||
const CallFrame& call_frame() const { return m_call_stack.last(); }
|
||||
const Vector<CallFrame>& call_stack() const { return m_call_stack; }
|
||||
Vector<CallFrame>& call_stack() { return m_call_stack; }
|
||||
|
||||
const LexicalEnvironment* current_environment() const { return m_call_stack.last().environment; }
|
||||
LexicalEnvironment* current_environment() { return m_call_stack.last().environment; }
|
||||
void pop_call_frame() { m_call_stack.take_last(); }
|
||||
|
||||
CallFrame& call_frame() { return *m_call_stack.last(); }
|
||||
const CallFrame& call_frame() const { return *m_call_stack.last(); }
|
||||
const Vector<CallFrame*>& call_stack() const { return m_call_stack; }
|
||||
Vector<CallFrame*>& call_stack() { return m_call_stack; }
|
||||
|
||||
const LexicalEnvironment* current_environment() const { return call_frame().environment; }
|
||||
LexicalEnvironment* current_environment() { return call_frame().environment; }
|
||||
|
||||
bool in_strict_mode() const;
|
||||
|
||||
|
@ -135,7 +136,7 @@ public:
|
|||
{
|
||||
if (m_call_stack.is_empty())
|
||||
return;
|
||||
for (auto& value : m_call_stack.last().arguments)
|
||||
for (auto& value : call_frame().arguments)
|
||||
callback(value);
|
||||
}
|
||||
|
||||
|
@ -143,14 +144,14 @@ public:
|
|||
{
|
||||
if (m_call_stack.is_empty())
|
||||
return 0;
|
||||
return m_call_stack.last().arguments.size();
|
||||
return call_frame().arguments.size();
|
||||
}
|
||||
|
||||
Value argument(size_t index) const
|
||||
{
|
||||
if (m_call_stack.is_empty())
|
||||
return {};
|
||||
auto& arguments = m_call_stack.last().arguments;
|
||||
auto& arguments = call_frame().arguments;
|
||||
return index < arguments.size() ? arguments[index] : js_undefined();
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,7 @@ public:
|
|||
{
|
||||
if (m_call_stack.is_empty())
|
||||
return &global_object;
|
||||
return m_call_stack.last().this_value;
|
||||
return call_frame().this_value;
|
||||
}
|
||||
|
||||
Value last_value() const { return m_last_value; }
|
||||
|
@ -241,7 +242,7 @@ private:
|
|||
Heap m_heap;
|
||||
Vector<Interpreter*> m_interpreters;
|
||||
|
||||
Vector<CallFrame> m_call_stack;
|
||||
Vector<CallFrame*> m_call_stack;
|
||||
|
||||
Value m_last_value;
|
||||
ScopeType m_unwind_until { ScopeType::None };
|
||||
|
|
Loading…
Add table
Reference in a new issue