mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibJS: Move ExecutionContext members with destructors to "rare data"
This makes ExecutionContext trivially destructible, which means less work to do on function exit.
This commit is contained in:
parent
9ded35f98f
commit
1e0b56586b
|
|
@ -311,8 +311,8 @@ NEVER_INLINE Interpreter::HandleExceptionResponse Interpreter::handle_exception(
|
|||
auto& handler = handlers->handler_offset;
|
||||
auto& finalizer = handlers->finalizer_offset;
|
||||
|
||||
VERIFY(!running_execution_context().unwind_contexts.is_empty());
|
||||
auto& unwind_context = running_execution_context().unwind_contexts.last();
|
||||
auto& unwind_contexts = running_execution_context().ensure_rare_data()->unwind_contexts;
|
||||
auto& unwind_context = unwind_contexts.last();
|
||||
VERIFY(unwind_context.executable == ¤t_executable());
|
||||
|
||||
if (handler.has_value()) {
|
||||
|
|
@ -485,8 +485,8 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
do_return(saved_return_value());
|
||||
if (auto handlers = executable.exception_handlers_for_offset(program_counter); handlers.has_value()) {
|
||||
if (auto finalizer = handlers.value().finalizer_offset; finalizer.has_value()) {
|
||||
VERIFY(!running_execution_context.unwind_contexts.is_empty());
|
||||
auto& unwind_context = running_execution_context.unwind_contexts.last();
|
||||
auto& unwind_contexts = running_execution_context.ensure_rare_data()->unwind_contexts;
|
||||
auto& unwind_context = unwind_contexts.last();
|
||||
VERIFY(unwind_context.executable == ¤t_executable());
|
||||
reg(Register::saved_return_value()) = reg(Register::return_value());
|
||||
reg(Register::return_value()) = js_special_empty_value();
|
||||
|
|
@ -497,7 +497,7 @@ FLATTEN_ON_CLANG void Interpreter::run_bytecode(size_t entry_point)
|
|||
}
|
||||
return;
|
||||
}
|
||||
auto const old_scheduled_jump = running_execution_context.previously_scheduled_jumps.take_last();
|
||||
auto const old_scheduled_jump = running_execution_context.ensure_rare_data()->previously_scheduled_jumps.take_last();
|
||||
if (m_running_execution_context->scheduled_jump.has_value()) {
|
||||
program_counter = m_running_execution_context->scheduled_jump.value();
|
||||
m_running_execution_context->scheduled_jump = {};
|
||||
|
|
@ -762,23 +762,23 @@ ThrowCompletionOr<Value> Interpreter::run_executable(ExecutionContext& context,
|
|||
|
||||
void Interpreter::enter_unwind_context()
|
||||
{
|
||||
running_execution_context().unwind_contexts.empend(
|
||||
running_execution_context().ensure_rare_data()->unwind_contexts.empend(
|
||||
current_executable(),
|
||||
running_execution_context().lexical_environment);
|
||||
running_execution_context().previously_scheduled_jumps.append(m_running_execution_context->scheduled_jump);
|
||||
running_execution_context().rare_data()->previously_scheduled_jumps.append(m_running_execution_context->scheduled_jump);
|
||||
m_running_execution_context->scheduled_jump = {};
|
||||
}
|
||||
|
||||
void Interpreter::leave_unwind_context()
|
||||
{
|
||||
running_execution_context().unwind_contexts.take_last();
|
||||
running_execution_context().rare_data()->unwind_contexts.take_last();
|
||||
}
|
||||
|
||||
void Interpreter::catch_exception(Operand dst)
|
||||
{
|
||||
set(dst, reg(Register::exception()));
|
||||
reg(Register::exception()) = js_special_empty_value();
|
||||
auto& context = running_execution_context().unwind_contexts.last();
|
||||
auto& context = running_execution_context().rare_data()->unwind_contexts.last();
|
||||
VERIFY(!context.handler_called);
|
||||
VERIFY(context.executable == ¤t_executable());
|
||||
context.handler_called = true;
|
||||
|
|
@ -787,19 +787,19 @@ void Interpreter::catch_exception(Operand dst)
|
|||
|
||||
void Interpreter::restore_scheduled_jump()
|
||||
{
|
||||
m_running_execution_context->scheduled_jump = running_execution_context().previously_scheduled_jumps.take_last();
|
||||
m_running_execution_context->scheduled_jump = running_execution_context().rare_data()->previously_scheduled_jumps.take_last();
|
||||
}
|
||||
|
||||
void Interpreter::leave_finally()
|
||||
{
|
||||
reg(Register::exception()) = js_special_empty_value();
|
||||
m_running_execution_context->scheduled_jump = running_execution_context().previously_scheduled_jumps.take_last();
|
||||
m_running_execution_context->scheduled_jump = running_execution_context().rare_data()->previously_scheduled_jumps.take_last();
|
||||
}
|
||||
|
||||
void Interpreter::enter_object_environment(Object& object)
|
||||
{
|
||||
auto& old_environment = running_execution_context().lexical_environment;
|
||||
running_execution_context().saved_lexical_environments.append(old_environment);
|
||||
running_execution_context().ensure_rare_data()->saved_lexical_environments.append(old_environment);
|
||||
running_execution_context().lexical_environment = new_object_environment(object, true, old_environment);
|
||||
}
|
||||
|
||||
|
|
@ -1593,7 +1593,7 @@ inline ThrowCompletionOr<ECMAScriptFunctionObject*> new_class(VM& vm, Value supe
|
|||
|
||||
// NOTE: NewClass expects classEnv to be active lexical environment
|
||||
auto* class_environment = vm.lexical_environment();
|
||||
vm.running_execution_context().lexical_environment = vm.running_execution_context().saved_lexical_environments.take_last();
|
||||
vm.running_execution_context().lexical_environment = vm.running_execution_context().rare_data()->saved_lexical_environments.take_last();
|
||||
|
||||
Optional<Utf16FlyString> binding_name;
|
||||
Utf16FlyString class_name;
|
||||
|
|
@ -2416,7 +2416,7 @@ void CreateLexicalEnvironment::execute_impl(Bytecode::Interpreter& interpreter)
|
|||
return environment;
|
||||
};
|
||||
auto& running_execution_context = interpreter.running_execution_context();
|
||||
running_execution_context.saved_lexical_environments.append(make_and_swap_envs(running_execution_context.lexical_environment));
|
||||
running_execution_context.ensure_rare_data()->saved_lexical_environments.append(make_and_swap_envs(running_execution_context.lexical_environment));
|
||||
if (m_dst.has_value())
|
||||
interpreter.set(*m_dst, running_execution_context.lexical_environment);
|
||||
}
|
||||
|
|
@ -3161,7 +3161,7 @@ ThrowCompletionOr<void> ThrowIfTDZ::execute_impl(Bytecode::Interpreter& interpre
|
|||
void LeaveLexicalEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& running_execution_context = interpreter.running_execution_context();
|
||||
running_execution_context.lexical_environment = running_execution_context.saved_lexical_environments.take_last();
|
||||
running_execution_context.lexical_environment = running_execution_context.rare_data()->saved_lexical_environments.take_last();
|
||||
}
|
||||
|
||||
void LeavePrivateEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
namespace JS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(CachedSourceRange);
|
||||
GC_DEFINE_ALLOCATOR(ExecutionContextRareData);
|
||||
|
||||
class ExecutionContextAllocator {
|
||||
public:
|
||||
|
|
@ -110,10 +111,6 @@ ExecutionContext::ExecutionContext(u32 registers_and_constants_and_locals_count,
|
|||
arguments = { registers_and_constants_and_locals_and_arguments + registers_and_constants_and_locals_count, arguments_count };
|
||||
}
|
||||
|
||||
ExecutionContext::~ExecutionContext()
|
||||
{
|
||||
}
|
||||
|
||||
NonnullOwnPtr<ExecutionContext> ExecutionContext::copy() const
|
||||
{
|
||||
auto copy = create(registers_and_constants_and_locals_and_arguments_count, arguments.size());
|
||||
|
|
@ -127,9 +124,12 @@ NonnullOwnPtr<ExecutionContext> ExecutionContext::copy() const
|
|||
copy->this_value = this_value;
|
||||
copy->executable = executable;
|
||||
copy->passed_argument_count = passed_argument_count;
|
||||
copy->unwind_contexts = unwind_contexts;
|
||||
copy->saved_lexical_environments = saved_lexical_environments;
|
||||
copy->previously_scheduled_jumps = previously_scheduled_jumps;
|
||||
if (m_rare_data) {
|
||||
auto copy_rare_data = copy->ensure_rare_data();
|
||||
copy_rare_data->unwind_contexts = m_rare_data->unwind_contexts;
|
||||
copy_rare_data->saved_lexical_environments = m_rare_data->saved_lexical_environments;
|
||||
copy_rare_data->previously_scheduled_jumps = m_rare_data->previously_scheduled_jumps;
|
||||
}
|
||||
copy->registers_and_constants_and_locals_and_arguments_count = registers_and_constants_and_locals_and_arguments_count;
|
||||
for (size_t i = 0; i < registers_and_constants_and_locals_and_arguments_count; ++i)
|
||||
copy->registers_and_constants_and_locals_and_arguments()[i] = registers_and_constants_and_locals_and_arguments()[i];
|
||||
|
|
@ -146,14 +146,11 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor)
|
|||
visitor.visit(private_environment);
|
||||
visitor.visit(context_owner);
|
||||
visitor.visit(cached_source_range);
|
||||
visitor.visit(m_rare_data);
|
||||
if (this_value.has_value())
|
||||
visitor.visit(*this_value);
|
||||
visitor.visit(executable);
|
||||
visitor.visit(registers_and_constants_and_locals_and_arguments_span());
|
||||
for (auto& context : unwind_contexts) {
|
||||
visitor.visit(context.lexical_environment);
|
||||
}
|
||||
visitor.visit(saved_lexical_environments);
|
||||
script_or_module.visit(
|
||||
[](Empty) {},
|
||||
[&](auto& script_or_module) {
|
||||
|
|
@ -161,4 +158,21 @@ void ExecutionContext::visit_edges(Cell::Visitor& visitor)
|
|||
});
|
||||
}
|
||||
|
||||
void ExecutionContextRareData::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
for (auto& context : unwind_contexts) {
|
||||
visitor.visit(context.lexical_environment);
|
||||
}
|
||||
visitor.visit(saved_lexical_environments);
|
||||
}
|
||||
|
||||
GC::Ref<ExecutionContextRareData> ExecutionContext::ensure_rare_data()
|
||||
{
|
||||
if (!m_rare_data) {
|
||||
m_rare_data = executable->heap().allocate<ExecutionContextRareData>();
|
||||
}
|
||||
return *m_rare_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,12 +36,25 @@ public:
|
|||
Variant<UnrealizedSourceRange, SourceRange> source_range;
|
||||
};
|
||||
|
||||
class ExecutionContextRareData final : public GC::Cell {
|
||||
GC_CELL(ExecutionContextRareData, GC::Cell);
|
||||
GC_DECLARE_ALLOCATOR(ExecutionContextRareData);
|
||||
|
||||
public:
|
||||
Vector<Bytecode::UnwindInfo> unwind_contexts;
|
||||
Vector<Optional<size_t>> previously_scheduled_jumps;
|
||||
Vector<GC::Ptr<Environment>> saved_lexical_environments;
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
};
|
||||
|
||||
// 9.4 Execution Contexts, https://tc39.es/ecma262/#sec-execution-contexts
|
||||
struct JS_API ExecutionContext {
|
||||
static NonnullOwnPtr<ExecutionContext> create(u32 registers_and_constants_and_locals_count, u32 arguments_count);
|
||||
[[nodiscard]] NonnullOwnPtr<ExecutionContext> copy() const;
|
||||
|
||||
~ExecutionContext();
|
||||
~ExecutionContext() = default;
|
||||
|
||||
void visit_edges(Cell::Visitor&);
|
||||
|
||||
|
|
@ -51,6 +64,9 @@ private:
|
|||
public:
|
||||
ExecutionContext(u32 registers_and_constants_and_locals_count, u32 arguments_count);
|
||||
|
||||
GC::Ptr<ExecutionContextRareData> rare_data() const { return m_rare_data; }
|
||||
GC::Ref<ExecutionContextRareData> ensure_rare_data();
|
||||
|
||||
void operator delete(void* ptr);
|
||||
|
||||
GC::Ptr<FunctionObject> function; // [[Function]]
|
||||
|
|
@ -105,9 +121,9 @@ public:
|
|||
|
||||
Span<Value> arguments;
|
||||
|
||||
Vector<Bytecode::UnwindInfo> unwind_contexts;
|
||||
Vector<Optional<size_t>> previously_scheduled_jumps;
|
||||
Vector<GC::Ptr<Environment>> saved_lexical_environments;
|
||||
// NOTE: Rarely used data members go here to keep the size of ExecutionContext down,
|
||||
// and to avoid needing an ExecutionContext destructor in the common case.
|
||||
GC::Ptr<ExecutionContextRareData> m_rare_data;
|
||||
|
||||
u32 passed_argument_count { 0 };
|
||||
|
||||
|
|
@ -122,21 +138,19 @@ private:
|
|||
u32 registers_and_constants_and_locals_and_arguments_count { 0 };
|
||||
};
|
||||
|
||||
#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(execution_context, \
|
||||
registers_and_constants_and_locals_count, \
|
||||
arguments_count) \
|
||||
auto execution_context_size = sizeof(JS::ExecutionContext) \
|
||||
+ (((registers_and_constants_and_locals_count) + (arguments_count)) \
|
||||
* sizeof(JS::Value)); \
|
||||
\
|
||||
void* execution_context_memory = alloca(execution_context_size); \
|
||||
\
|
||||
execution_context = new (execution_context_memory) \
|
||||
JS::ExecutionContext((registers_and_constants_and_locals_count), (arguments_count)); \
|
||||
\
|
||||
ScopeGuard run_execution_context_destructor([execution_context] { \
|
||||
execution_context->~ExecutionContext(); \
|
||||
})
|
||||
static_assert(IsTriviallyDestructible<ExecutionContext>);
|
||||
|
||||
#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK_WITHOUT_CLEARING_ARGS(execution_context, \
|
||||
registers_and_constants_and_locals_count, \
|
||||
arguments_count) \
|
||||
auto execution_context_size = sizeof(JS::ExecutionContext) \
|
||||
+ (((registers_and_constants_and_locals_count) + (arguments_count)) \
|
||||
* sizeof(JS::Value)); \
|
||||
\
|
||||
void* execution_context_memory = alloca(execution_context_size); \
|
||||
\
|
||||
execution_context = new (execution_context_memory) \
|
||||
JS::ExecutionContext((registers_and_constants_and_locals_count), (arguments_count));
|
||||
|
||||
#define ALLOCATE_EXECUTION_CONTEXT_ON_NATIVE_STACK(execution_context, registers_and_constants_and_locals_count, \
|
||||
arguments_count) \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user