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:
Andreas Kling 2020-11-07 11:07:17 +01:00
parent a950d3dd5f
commit 43ff2ea8d8
Notes: sideshowbarker 2024-07-19 01:31:54 +09:00
6 changed files with 36 additions and 27 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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;

View file

@ -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 };