1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
15 #include "js/RootingAPI.h" // JS::{Handle,Rooted}
16 #include "js/TypeDecls.h"
17 #include "js/Value.h" // JS::Value, JS::Handle<JS::Value>
22 enum class ExceptionStackBehavior
: bool {
23 // Do not capture any stack.
26 // Capture the current JS stack when setting the exception. It may be
27 // retrieved by JS::GetPendingExceptionStack.
32 extern JS_PUBLIC_API
bool JS_IsExceptionPending(JSContext
* cx
);
34 extern JS_PUBLIC_API
bool JS_IsThrowingOutOfMemory(JSContext
* cx
);
36 extern JS_PUBLIC_API
bool JS_GetPendingException(JSContext
* cx
,
37 JS::MutableHandleValue vp
);
39 extern JS_PUBLIC_API
void JS_SetPendingException(
40 JSContext
* cx
, JS::HandleValue v
,
41 JS::ExceptionStackBehavior behavior
= JS::ExceptionStackBehavior::Capture
);
43 extern JS_PUBLIC_API
void JS_ClearPendingException(JSContext
* cx
);
46 * If the given object is an exception object, the exception will have (or be
47 * able to lazily create) an error report struct, and this function will return
48 * the address of that struct. Otherwise, it returns nullptr. The lifetime
49 * of the error report struct that might be returned is the same as the
50 * lifetime of the exception object.
52 extern JS_PUBLIC_API JSErrorReport
* JS_ErrorFromException(JSContext
* cx
,
53 JS::HandleObject obj
);
57 // When propagating an exception up the call stack, we store the underlying
58 // reason on the JSContext as one of the following enum values.
60 // TODO: Track uncatchable exceptions explicitly.
61 enum class ExceptionStatus
{
62 // No exception status.
65 // Used by debugger when forcing an early return from a frame. This uses
66 // exception machinery, but at the right time is turned back into a normal
67 // non-error completion.
70 // Throwing a (catchable) exception. Certain well-known exceptions are
71 // explicitly tracked for convenience.
77 // Returns true if the status is a catchable exception. Formerly this was
78 // indicated by the `JSContext::throwing` flag.
79 static MOZ_ALWAYS_INLINE
bool IsCatchableExceptionStatus(
80 ExceptionStatus status
) {
81 return status
>= ExceptionStatus::Throwing
;
84 // This class encapsulates a (pending) exception and the corresponding optional
85 // SavedFrame stack object captured when the pending exception was set
86 // on the JSContext. This fuzzily correlates with a `throw` statement in JS,
87 // although arbitrary JSAPI consumers or VM code may also set pending exceptions
88 // via `JS_SetPendingException`.
90 // This is not the same stack as `e.stack` when `e` is an `Error` object.
91 // (That would be JS::ExceptionStackOrNull).
92 class MOZ_STACK_CLASS ExceptionStack
{
93 Rooted
<Value
> exception_
;
94 Rooted
<JSObject
*> stack_
;
96 friend JS_PUBLIC_API
bool GetPendingExceptionStack(
97 JSContext
* cx
, JS::ExceptionStack
* exceptionStack
);
99 void init(HandleValue exception
, HandleObject stack
) {
100 exception_
= exception
;
105 explicit ExceptionStack(JSContext
* cx
) : exception_(cx
), stack_(cx
) {}
107 ExceptionStack(JSContext
* cx
, HandleValue exception
, HandleObject stack
)
108 : exception_(cx
, exception
), stack_(cx
, stack
) {}
110 HandleValue
exception() const { return exception_
; }
112 // |stack| can be null.
113 HandleObject
stack() const { return stack_
; }
117 * Save and later restore the current exception state of a given JSContext.
118 * This is useful for implementing behavior in C++ that's like try/catch
119 * or try/finally in JS.
123 * bool ok = JS::Evaluate(cx, ...);
124 * AutoSaveExceptionState savedExc(cx);
125 * ... cleanup that might re-enter JS ...
128 class JS_PUBLIC_API AutoSaveExceptionState
{
131 ExceptionStatus status
;
132 RootedValue exceptionValue
;
133 RootedObject exceptionStack
;
137 * Take a snapshot of cx's current exception state. Then clear any current
138 * pending exception in cx.
140 explicit AutoSaveExceptionState(JSContext
* cx
);
143 * If neither drop() nor restore() was called, restore the exception
144 * state only if no exception is currently pending on cx.
146 ~AutoSaveExceptionState();
149 * Discard any stored exception state.
150 * If this is called, the destructor is a no-op.
155 * Replace cx's exception state with the stored exception state. Then
156 * discard the stored exception state. If this is called, the
157 * destructor is a no-op.
162 // Get the current pending exception value and stack.
163 // This function asserts that there is a pending exception.
164 // If this function returns false, then retrieving the current pending exception
165 // failed and might have been overwritten by a new exception.
166 extern JS_PUBLIC_API
bool GetPendingExceptionStack(
167 JSContext
* cx
, JS::ExceptionStack
* exceptionStack
);
169 // Similar to GetPendingExceptionStack, but also clears the current
170 // pending exception.
171 extern JS_PUBLIC_API
bool StealPendingExceptionStack(
172 JSContext
* cx
, JS::ExceptionStack
* exceptionStack
);
174 // Set both the exception value and its associated stack on the context as
175 // the current pending exception.
176 extern JS_PUBLIC_API
void SetPendingExceptionStack(
177 JSContext
* cx
, const JS::ExceptionStack
& exceptionStack
);
180 * If the given object is an exception object (or an unwrappable
181 * cross-compartment wrapper for one), return the stack for that exception, if
182 * any. Will return null if the given object is not an exception object
183 * (including if it's null or a security wrapper that can't be unwrapped) or if
184 * the exception has no stack.
186 extern JS_PUBLIC_API JSObject
* ExceptionStackOrNull(JS::HandleObject obj
);
189 * If the given object is an exception object, return the error cause for that
190 * exception, if any, or mozilla::Nothing.
192 extern JS_PUBLIC_API
mozilla::Maybe
<JS::Value
> GetExceptionCause(JSObject
* exc
);
196 #endif // js_Exception_h