1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 03:58:12 +00:00

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
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(); auto& call_stack = m_console.global_object().vm().call_stack();
// -2 to skip the console.trace() call frame // -2 to skip the console.trace() call frame
for (ssize_t i = call_stack.size() - 2; i >= 0; --i) 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; 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(); global_call_frame.is_strict_mode = program.is_strict_mode();
if (vm().exception()) if (vm().exception())
return {}; return {};
vm().call_stack().append(move(global_call_frame));
vm().push_call_frame(global_call_frame);
auto result = program.execute(*this, global_object); auto result = program.execute(*this, global_object);
vm().pop_call_frame(); vm().pop_call_frame();
return result; return result;
@ -128,7 +128,7 @@ void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector argume
if (!scope_variables_with_declaration_kind.is_empty()) { 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()); 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; pushed_lexical_environment = true;
} }

View file

@ -35,7 +35,7 @@ Exception::Exception(Value value)
{ {
auto& call_stack = vm().call_stack(); auto& call_stack = vm().call_stack();
for (ssize_t i = call_stack.size() - 1; i >= 0; --i) { 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()) if (function_name.is_empty())
function_name = "<anonymous>"; function_name = "<anonymous>";
m_trace.append(function_name); 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 Value Object::call_native_property_getter(Object* this_object, Value property) const
{ {
ASSERT(property.is_native_property()); 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; call_frame.this_value = this_object;
vm().push_call_frame(call_frame);
auto result = property.as_native_property().get(vm(), global_object()); auto result = property.as_native_property().get(vm(), global_object());
vm().pop_call_frame(); vm().pop_call_frame();
return result; 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 void Object::call_native_property_setter(Object* this_object, Value property, Value value) const
{ {
ASSERT(property.is_native_property()); 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; call_frame.this_value = this_object;
vm().push_call_frame(call_frame);
property.as_native_property().set(vm(), global_object(), value); property.as_native_property().set(vm(), global_object(), value);
vm().pop_call_frame(); vm().pop_call_frame();
} }

View file

@ -110,13 +110,13 @@ void VM::gather_roots(HashTable<Cell*>& roots)
roots.set(m_last_value.as_cell()); roots.set(m_last_value.as_cell());
for (auto& call_frame : m_call_stack) { for (auto& call_frame : m_call_stack) {
if (call_frame.this_value.is_cell()) if (call_frame->this_value.is_cell())
roots.set(call_frame.this_value.as_cell()); roots.set(call_frame->this_value.as_cell());
for (auto& argument : call_frame.arguments) { for (auto& argument : call_frame->arguments) {
if (argument.is_cell()) if (argument.is_cell())
roots.set(argument.as_cell()); roots.set(argument.as_cell());
} }
roots.set(call_frame.environment); roots.set(call_frame->environment);
} }
#define __JS_ENUMERATE(SymbolName, snake_name) \ #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) 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 = [&] { ArmedScopeGuard call_frame_popper = [&] {
pop_call_frame(); pop_call_frame();
@ -310,7 +312,8 @@ Value VM::call_internal(Function& function, Value this_value, Optional<MarkedVal
{ {
ASSERT(!exception()); 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.function_name = function.name();
call_frame.this_value = function.bound_this().value_or(this_value); call_frame.this_value = function.bound_this().value_or(this_value);
call_frame.arguments = function.bound_arguments(); 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); ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
call_frame.environment->bind_this_value(function.global_object(), call_frame.this_value); call_frame.environment->bind_this_value(function.global_object(), call_frame.this_value);
push_call_frame(call_frame);
auto result = function.call(); auto result = function.call();
pop_call_frame(); pop_call_frame();
return result; return result;

View file

@ -114,19 +114,20 @@ public:
return *m_single_ascii_character_strings[character]; 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 }); m_call_stack.append(&call_frame);
return m_call_stack.last();
} }
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; } void pop_call_frame() { m_call_stack.take_last(); }
LexicalEnvironment* current_environment() { return m_call_stack.last().environment; }
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; bool in_strict_mode() const;
@ -135,7 +136,7 @@ public:
{ {
if (m_call_stack.is_empty()) if (m_call_stack.is_empty())
return; return;
for (auto& value : m_call_stack.last().arguments) for (auto& value : call_frame().arguments)
callback(value); callback(value);
} }
@ -143,14 +144,14 @@ public:
{ {
if (m_call_stack.is_empty()) if (m_call_stack.is_empty())
return 0; return 0;
return m_call_stack.last().arguments.size(); return call_frame().arguments.size();
} }
Value argument(size_t index) const Value argument(size_t index) const
{ {
if (m_call_stack.is_empty()) if (m_call_stack.is_empty())
return {}; return {};
auto& arguments = m_call_stack.last().arguments; auto& arguments = call_frame().arguments;
return index < arguments.size() ? arguments[index] : js_undefined(); return index < arguments.size() ? arguments[index] : js_undefined();
} }
@ -158,7 +159,7 @@ public:
{ {
if (m_call_stack.is_empty()) if (m_call_stack.is_empty())
return &global_object; return &global_object;
return m_call_stack.last().this_value; return call_frame().this_value;
} }
Value last_value() const { return m_last_value; } Value last_value() const { return m_last_value; }
@ -241,7 +242,7 @@ private:
Heap m_heap; Heap m_heap;
Vector<Interpreter*> m_interpreters; Vector<Interpreter*> m_interpreters;
Vector<CallFrame> m_call_stack; Vector<CallFrame*> m_call_stack;
Value m_last_value; Value m_last_value;
ScopeType m_unwind_until { ScopeType::None }; ScopeType m_unwind_until { ScopeType::None };