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:
parent
a950d3dd5f
commit
43ff2ea8d8
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();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue