ladybird/Userland/Libraries/LibJS/Runtime/Error.h
Andreas Kling 87ac906ee6 LibJS: Make Error stack traces lazier
Instead of eagerly populating the stack trace with a textual
representation of every call frame, just store the raw source code range
(code, start offset, end offset). From that, we can generate the full
rich backtrace when requested, and save ourselves the trouble otherwise.

This makes test-wasm take ~7 seconds on my machine instead of ~60. :^)
2023-05-28 10:03:11 +02:00

74 lines
2.8 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/DeprecatedFlyString.h>
#include <AK/String.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/SourceRange.h>
namespace JS {
struct TracebackFrame {
DeprecatedFlyString function_name;
[[nodiscard]] SourceRange const& source_range() const;
struct UnrealizedSourceRange {
u32 start_offset { 0 };
u32 end_offset { 0 };
RefPtr<JS::SourceCode const> source_code;
};
mutable Variant<SourceRange, UnrealizedSourceRange> source_range_storage;
};
class Error : public Object {
JS_OBJECT(Error, Object);
public:
static NonnullGCPtr<Error> create(Realm&);
static NonnullGCPtr<Error> create(Realm&, String message);
static ThrowCompletionOr<NonnullGCPtr<Error>> create(Realm&, StringView message);
virtual ~Error() override = default;
[[nodiscard]] ThrowCompletionOr<String> stack_string(VM&) const;
ThrowCompletionOr<void> install_error_cause(Value options);
Vector<TracebackFrame, 32> const& traceback() const { return m_traceback; }
protected:
explicit Error(Object& prototype);
private:
void populate_stack();
Vector<TracebackFrame, 32> m_traceback;
};
// NOTE: Making these inherit from Error is not required by the spec but
// our way of implementing the [[ErrorData]] internal slot, which is
// used in Object.prototype.toString().
#define DECLARE_NATIVE_ERROR(ClassName, snake_name, PrototypeName, ConstructorName) \
class ClassName final : public Error { \
JS_OBJECT(ClassName, Error); \
\
public: \
static NonnullGCPtr<ClassName> create(Realm&); \
static NonnullGCPtr<ClassName> create(Realm&, String message); \
static ThrowCompletionOr<NonnullGCPtr<ClassName>> create(Realm&, StringView message); \
\
explicit ClassName(Object& prototype); \
virtual ~ClassName() override = default; \
};
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
DECLARE_NATIVE_ERROR(ClassName, snake_name, PrototypeName, ConstructorName)
JS_ENUMERATE_NATIVE_ERRORS
#undef __JS_ENUMERATE
}