LibJS: Cache the formatted Error.prototype.stack string
Generating the stack trace string is expensive as it involves formatting each frame with function names, file paths, and line numbers. Since the stack trace is immutable after error creation, we can cache the formatted string on first access. This matches the caching behavior of V8 and JavaScriptCore, which also return the same cached string on subsequent accesses to the stack property.
This commit is contained in:
parent
59e0e331e3
commit
b5fc557709
3 changed files with 15 additions and 1 deletions
|
|
@ -61,6 +61,7 @@ Error::Error(Object& prototype)
|
|||
void Error::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_cached_string);
|
||||
for (auto& frame : m_traceback)
|
||||
visitor.visit(frame.cached_source_range);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ public:
|
|||
|
||||
Vector<TracebackFrame, 32> const& traceback() const { return m_traceback; }
|
||||
|
||||
void set_cached_string(GC::Ref<PrimitiveString> string) { m_cached_string = string; }
|
||||
GC::Ptr<PrimitiveString> cached_string() const { return m_cached_string; }
|
||||
|
||||
protected:
|
||||
explicit Error(Object& prototype);
|
||||
|
||||
|
|
@ -58,6 +61,8 @@ private:
|
|||
|
||||
void populate_stack();
|
||||
Vector<TracebackFrame, 32> m_traceback;
|
||||
|
||||
GC::Ptr<PrimitiveString> m_cached_string;
|
||||
};
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -83,6 +83,12 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::stack_getter)
|
|||
|
||||
auto& error = static_cast<Error&>(*this_object);
|
||||
|
||||
// OPTIMIZATION: Avoid recomputing the stack string if we already have it cached.
|
||||
// At least one major engine does this as well, so it's not expected that changing
|
||||
// the name or message properties updates the stack string.
|
||||
if (error.cached_string())
|
||||
return error.cached_string();
|
||||
|
||||
// 4. Return ? GetStackString(error).
|
||||
// NOTE: These steps are not implemented based on the proposal, but to roughly follow behavior of other browsers.
|
||||
|
||||
|
|
@ -100,7 +106,9 @@ JS_DEFINE_NATIVE_FUNCTION(ErrorPrototype::stack_getter)
|
|||
? move(name)
|
||||
: MUST(String::formatted("{}: {}", name, message));
|
||||
|
||||
return PrimitiveString::create(vm, MUST(String::formatted("{}\n{}", header, error.stack_string())));
|
||||
auto string = PrimitiveString::create(vm, MUST(String::formatted("{}\n{}", header, error.stack_string())));
|
||||
error.set_cached_string(string);
|
||||
return string;
|
||||
}
|
||||
|
||||
// B.1.2 set Error.prototype.stack ( value ), https://tc39.es/proposal-error-stacks/#sec-set-error.prototype-stack
|
||||
|
|
|
|||
Loading…
Reference in a new issue