Coverage Report

Created: 2025-12-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hermes/include/hermes/VM/JSError.h
Line
Count
Source
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#ifndef HERMES_VM_JSERROR_H
9
#define HERMES_VM_JSERROR_H
10
11
#include "hermes/VM/JSObject.h"
12
#include "hermes/VM/NativeArgs.h"
13
#include "hermes/VM/SmallXString.h"
14
15
namespace hermes {
16
namespace vm {
17
18
/// StackTraceInfo holds information of an entry in the stacktrace upon
19
/// exceptions. We only need to store the CodeBlock and bytecode offset
20
/// to obtain the full function name/file name/position later when we
21
/// need to generate the stacktrace string.
22
/// We store the domains for the CodeBlocks within the JSError to ensure that
23
/// the CodeBlocks never get freed, and thus every StackTraceInfo is still
24
/// valid.
25
struct StackTraceInfo {
26
  /// The code block of the function.
27
  CodeBlock *codeBlock;
28
29
  /// The bytecode offset where exception was thrown.
30
  uint32_t bytecodeOffset;
31
32
  StackTraceInfo(CodeBlock *codeBlock, uint32_t bytecodeOffset)
33
85
      : codeBlock(codeBlock), bytecodeOffset(bytecodeOffset) {}
34
35
  StackTraceInfo(const StackTraceInfo &) = default;
36
37
  StackTraceInfo(StackTraceInfo &&) = default;
38
};
39
using StackTrace = std::vector<StackTraceInfo>;
40
using StackTracePtr = std::unique_ptr<StackTrace>;
41
42
/// Error Object.
43
class JSError final : public JSObject {
44
 public:
45
  using Super = JSObject;
46
  static const ObjectVTable vt;
47
48
82
  static constexpr CellKind getCellKind() {
49
82
    return CellKind::JSErrorKind;
50
82
  }
51
284
  static bool classof(const GCCell *cell) {
52
284
    return cell->getKind() == CellKind::JSErrorKind;
53
284
  }
54
55
  /// Create an Error Object.
56
  static PseudoHandle<JSError> create(
57
      Runtime &runtime,
58
      Handle<JSObject> prototype);
59
  /// Create an uncatchable Error Object. If this object is thrown, no catch
60
  /// handlers or finally handlers are called.
61
  /// NOTE: This should be used only in very specific circumstances where it is
62
  /// impossible or undesirable to continue running the VM. The error should be
63
  /// considered a fatal abort, but one that cleans up internal VM resources.
64
  static PseudoHandle<JSError> createUncatchable(
65
      Runtime &runtime,
66
      Handle<JSObject> prototype);
67
68
  /// If the stack trace is not set, attempt to record it by walking the runtime
69
  /// stack. If the top call frame indicates a JS callee, but the codeBlock and
70
  /// ip are not supplied, return without doing anything. This handles the case
71
  /// when an exception is thrown from within the current code block.
72
  ///
73
  /// \param skipTopFrame don't record the topmost frame. This is used when
74
  ///   we want to skip the Error() constructor itself.
75
  /// \param codeBlock optional current CodeBlock.
76
  /// \param ip if \c codeBlock is not \c nullptr, the instruction in the
77
  ///   current CodeBlock.
78
  static ExecutionStatus recordStackTrace(
79
      Handle<JSError> selfHandle,
80
      Runtime &runtime,
81
      bool skipTopFrame = false,
82
      CodeBlock *codeBlock = nullptr,
83
      const Inst *ip = nullptr);
84
85
  /// Define the stack setter and getter, for later stack trace creation.
86
  /// May be used on JSError instances, or on any JSObject that has a
87
  /// \c CapturedError property.
88
  static ExecutionStatus setupStack(
89
      Handle<JSObject> selfHandle,
90
      Runtime &runtime);
91
92
  /// Implements steps 3 through 9 for ES2023 20.5.3.4 Error.prototype.toString.
93
  static CallResult<Handle<StringPrimitive>> toString(
94
      Handle<JSObject> O,
95
      Runtime &runtime);
96
97
  /// Set the message property.
98
  static ExecutionStatus
99
  setMessage(Handle<JSError> selfHandle, Runtime &runtime, Handle<> message);
100
101
  /// \return a pointer to the stack trace, or NULL if the stack trace has been
102
  /// cleared or not been set.
103
41
  const StackTrace *getStackTrace() const {
104
41
    return stacktrace_.get();
105
41
  }
106
107
41
  bool catchable() const {
108
41
    return catchable_;
109
41
  }
110
111
  /// When called, construct the stacktrace string based on the value of
112
  /// stacktrace_, and reset the stack property to the stacktrace string.
113
  friend CallResult<HermesValue>
114
  errorStackGetter(void *, Runtime &runtime, NativeArgs args);
115
116
  /// This is called when someone manually set the stack property to
117
  /// an error object, which should happen rarely. It destroys the
118
  /// stack access and replace it with a regular property.
119
  friend CallResult<HermesValue>
120
  errorStackSetter(void *, Runtime &runtime, NativeArgs args);
121
122
  /// Pop frames from the stack trace until we encounter a frame attributed to
123
  /// \p callable, and pop that frame too. No frames are skipped if a matching
124
  /// frame isn't found.
125
  /// \pre \p selfHandle's stacktrace_ is non-null.
126
  static void popFramesUntilInclusive(
127
      Runtime &runtime,
128
      Handle<JSError> selfHandle,
129
      Handle<Callable> callableHandle);
130
131
  /// Given a codeblock and opcode offset, \returns the debug information.
132
  static OptValue<hbc::DebugSourceLocation> getDebugInfo(
133
      CodeBlock *codeBlock,
134
      uint32_t bytecodeOffset);
135
136
  /// \return the name of the function at \p index.
137
  static Handle<StringPrimitive> getFunctionNameAtIndex(
138
      Runtime &runtime,
139
      Handle<JSError> selfHandle,
140
      size_t index);
141
142
  JSError(
143
      Runtime &runtime,
144
      Handle<JSObject> parent,
145
      Handle<HiddenClass> clazz,
146
      bool catchable)
147
41
      : JSObject(runtime, *parent, *clazz), catchable_{catchable} {}
148
149
 private:
150
  friend void JSErrorBuildMeta(const GCCell *cell, Metadata::Builder &mb);
151
  static void _finalizeImpl(GCCell *cell, GC &gc);
152
  static size_t _mallocSizeImpl(GCCell *cell);
153
154
  static PseudoHandle<JSError>
155
  create(Runtime &runtime, Handle<JSObject> prototype, bool catchable);
156
157
  /// A pointer to the stack trace, or nullptr if it has not been set.
158
  StackTracePtr stacktrace_;
159
160
  /// The index of the stack frame to start from when converting the stack
161
  /// trace to a string or otherwise exposing it to user code.
162
  /// This can only be changed while stacktrace_ is non-null.
163
  size_t firstExposedFrameIndex_{0};
164
165
  /// A list of Domains which are referenced by the stacktrace_.
166
  GCPointer<ArrayStorageSmall> domains_;
167
168
  /// If not null, an array of function names as the 'name' property of the
169
  /// Callables. This is parallel to the stack trace array.
170
  GCPointer<PropStorage> funcNames_;
171
172
  /// If true, JS catch and finally blocks will be run after this error is
173
  /// thrown. Else, there will be no more JS executed after this error is
174
  /// thrown. This is most useful in scenarios where an abrupt abort is desired,
175
  /// or when the VM is not in a state where it can execute JS usefully, for
176
  /// example if an OOM has occurred.
177
  bool catchable_{true};
178
179
  /// Construct the stacktrace string, append to \p stack.
180
  /// If the construction of the stack throws an uncatchable error, this
181
  /// function returns prematurely.
182
  ///
183
  /// \param selfHandle supplies the call stack for the trace.
184
  /// \param targetHandle supplies the error name and message for the trace.
185
  ///
186
  /// In the `(new Error).stack` case, selfHandle and targetHandle will both
187
  /// refer to the same object.
188
  /// In the `target = {}; Error.captureErrorStack(target); target.stack` case,
189
  /// selfHandle will be the value of `target`'s [[CapturedError]] slot.
190
  static ExecutionStatus constructStackTraceString_RJS(
191
      Runtime &runtime,
192
      Handle<JSError> selfHandle,
193
      Handle<JSObject> targetHandle,
194
      SmallU16String<32> &stack);
195
196
  /// Construct the callSites array for Error.prepareStackTrace.
197
  static CallResult<HermesValue> constructCallSitesArray(
198
      Runtime &runtime,
199
      Handle<JSError> selfHandle);
200
201
  /// Append the name of the function at \p index to the given \p str.
202
  /// \return true on success, false if the name was missing, invalid or empty.
203
  static bool appendFunctionNameAtIndex(
204
      Runtime &runtime,
205
      Handle<JSError> selfHandle,
206
      size_t index,
207
      llvh::SmallVectorImpl<char16_t> &str);
208
};
209
210
} // namespace vm
211
} // namespace hermes
212
#endif