Bug 1874684 - Part 25: Editorial updates. r=dminor
[gecko.git] / js / public / Stack.h
blob7384e92d398eec2f558dcc2636cf56573dc2cc18
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/. */
7 #ifndef js_Stack_h
8 #define js_Stack_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Maybe.h" // mozilla::Maybe
12 #include "mozilla/Variant.h" // mozilla::Variant
14 #include <stddef.h> // size_t
15 #include <stdint.h> // uint32_t, uintptr_t, UINTPTR_MAX
16 #include <utility> // std::move
18 #include "jstypes.h" // JS_PUBLIC_API
20 #include "js/Principals.h" // JSPrincipals, JS_HoldPrincipals, JS_DropPrincipals
21 #include "js/TypeDecls.h" // JSContext, Handle*, MutableHandle*
23 namespace JS {
25 using NativeStackSize = size_t;
27 using NativeStackBase = uintptr_t;
29 using NativeStackLimit = uintptr_t;
31 #if JS_STACK_GROWTH_DIRECTION > 0
32 constexpr NativeStackLimit NativeStackLimitMin = 0;
33 constexpr NativeStackLimit NativeStackLimitMax = UINTPTR_MAX;
34 #else
35 constexpr NativeStackLimit NativeStackLimitMin = UINTPTR_MAX;
36 constexpr NativeStackLimit NativeStackLimitMax = 0;
37 #endif
39 #ifdef __wasi__
40 // We build with the "stack-first" wasm-ld option, so the stack grows downward
41 // toward zero. Let's set a limit just a bit above this so that we catch an
42 // overflow before a Wasm trap occurs.
43 constexpr NativeStackLimit WASINativeStackLimit = 1024;
44 #endif // __wasi__
46 inline NativeStackLimit GetNativeStackLimit(NativeStackBase base,
47 NativeStackSize size) {
48 #if JS_STACK_GROWTH_DIRECTION > 0
49 MOZ_ASSERT(base <= size_t(-1) - size);
50 return base + size - 1;
51 #else // stack grows up
52 MOZ_ASSERT(base >= size);
53 return base - (size - 1);
54 #endif // stack grows down
57 } // namespace JS
59 /**
60 * Set the size of the native stack that should not be exceed. To disable
61 * stack size checking pass 0.
63 * SpiderMonkey allows for a distinction between system code (such as GCs, which
64 * may incidentally be triggered by script but are not strictly performed on
65 * behalf of such script), trusted script (as determined by
66 * JS_SetTrustedPrincipals), and untrusted script. Each kind of code may have a
67 * different stack quota, allowing embedders to keep higher-priority machinery
68 * running in the face of scripted stack exhaustion by something else.
70 * The stack quotas for each kind of code should be monotonically descending,
71 * and may be specified with this function. If 0 is passed for a given kind
72 * of code, it defaults to the value of the next-highest-priority kind.
74 * This function may only be called immediately after the runtime is initialized
75 * and before any code is executed and/or interrupts requested.
77 extern JS_PUBLIC_API void JS_SetNativeStackQuota(
78 JSContext* cx, JS::NativeStackSize systemCodeStackSize,
79 JS::NativeStackSize trustedScriptStackSize = 0,
80 JS::NativeStackSize untrustedScriptStackSize = 0);
82 namespace js {
84 enum class StackFormat { SpiderMonkey, V8, Default };
87 * Sets the format used for stringifying Error stacks.
89 * The default format is StackFormat::SpiderMonkey. Use StackFormat::V8
90 * in order to emulate V8's stack formatting. StackFormat::Default can't be
91 * used here.
93 extern JS_PUBLIC_API void SetStackFormat(JSContext* cx, StackFormat format);
95 extern JS_PUBLIC_API StackFormat GetStackFormat(JSContext* cx);
97 } // namespace js
99 namespace JS {
102 * Capture all frames.
104 struct AllFrames {};
107 * Capture at most this many frames.
109 struct MaxFrames {
110 uint32_t maxFrames;
112 explicit MaxFrames(uint32_t max) : maxFrames(max) { MOZ_ASSERT(max > 0); }
116 * Capture the first frame with the given principals. By default, do not
117 * consider self-hosted frames with the given principals as satisfying the stack
118 * capture.
120 struct JS_PUBLIC_API FirstSubsumedFrame {
121 JSContext* cx;
122 JSPrincipals* principals;
123 bool ignoreSelfHosted;
126 * Use the cx's current compartment's principals.
128 explicit FirstSubsumedFrame(JSContext* cx,
129 bool ignoreSelfHostedFrames = true);
131 explicit FirstSubsumedFrame(JSContext* ctx, JSPrincipals* p,
132 bool ignoreSelfHostedFrames = true)
133 : cx(ctx), principals(p), ignoreSelfHosted(ignoreSelfHostedFrames) {
134 if (principals) {
135 JS_HoldPrincipals(principals);
139 // No copying because we want to avoid holding and dropping principals
140 // unnecessarily.
141 FirstSubsumedFrame(const FirstSubsumedFrame&) = delete;
142 FirstSubsumedFrame& operator=(const FirstSubsumedFrame&) = delete;
143 FirstSubsumedFrame& operator=(FirstSubsumedFrame&&) = delete;
145 FirstSubsumedFrame(FirstSubsumedFrame&& rhs)
146 : principals(rhs.principals), ignoreSelfHosted(rhs.ignoreSelfHosted) {
147 MOZ_ASSERT(this != &rhs, "self move disallowed");
148 rhs.principals = nullptr;
151 ~FirstSubsumedFrame() {
152 if (principals) {
153 JS_DropPrincipals(cx, principals);
158 using StackCapture = mozilla::Variant<AllFrames, MaxFrames, FirstSubsumedFrame>;
161 * Capture the current call stack as a chain of SavedFrame JSObjects, and set
162 * |stackp| to the SavedFrame for the youngest stack frame, or nullptr if there
163 * are no JS frames on the stack.
165 * The |capture| parameter describes the portion of the JS stack to capture:
167 * * |JS::AllFrames|: Capture all frames on the stack.
169 * * |JS::MaxFrames|: Capture no more than |JS::MaxFrames::maxFrames| from the
170 * stack.
172 * * |JS::FirstSubsumedFrame|: Capture the first frame whose principals are
173 * subsumed by |JS::FirstSubsumedFrame::principals|. By default, do not
174 * consider self-hosted frames; this can be controlled via the
175 * |JS::FirstSubsumedFrame::ignoreSelfHosted| flag. Do not capture any async
176 * stack.
178 extern JS_PUBLIC_API bool CaptureCurrentStack(
179 JSContext* cx, MutableHandleObject stackp,
180 StackCapture&& capture = StackCapture(AllFrames()));
183 * Returns true if capturing stack trace data to associate with an asynchronous
184 * operation is currently enabled for the current context realm.
186 * Users should check this state before capturing a stack that will be passed
187 * back to AutoSetAsyncStackForNewCalls later, in order to avoid capturing a
188 * stack for async use when we don't actually want to capture it.
190 extern JS_PUBLIC_API bool IsAsyncStackCaptureEnabledForRealm(JSContext* cx);
193 * This is a utility function for preparing an async stack to be used
194 * by some other object. This may be used when you need to treat a
195 * given stack trace as an async parent. If you just need to capture
196 * the current stack, async parents and all, use CaptureCurrentStack
197 * instead.
199 * Here |asyncStack| is the async stack to prepare. It is copied into
200 * |cx|'s current compartment, and the newest frame is given
201 * |asyncCause| as its asynchronous cause. If |maxFrameCount| is
202 * |Some(n)|, capture at most the youngest |n| frames. The
203 * new stack object is written to |stackp|. Returns true on success,
204 * or sets an exception and returns |false| on error.
206 extern JS_PUBLIC_API bool CopyAsyncStack(
207 JSContext* cx, HandleObject asyncStack, HandleString asyncCause,
208 MutableHandleObject stackp, const mozilla::Maybe<size_t>& maxFrameCount);
211 * Given a SavedFrame JSObject stack, stringify it in the same format as
212 * Error.prototype.stack. The stringified stack out parameter is placed in the
213 * cx's compartment. Defaults to the empty string.
215 * The same notes above about SavedFrame accessors applies here as well: cx
216 * doesn't need to be in stack's compartment, and stack can be null, a
217 * SavedFrame object, or a wrapper (CCW or Xray) around a SavedFrame object.
218 * SavedFrames not subsumed by |principals| are skipped.
220 * Optional indent parameter specifies the number of white spaces to indent
221 * each line.
223 extern JS_PUBLIC_API bool BuildStackString(
224 JSContext* cx, JSPrincipals* principals, HandleObject stack,
225 MutableHandleString stringp, size_t indent = 0,
226 js::StackFormat stackFormat = js::StackFormat::Default);
228 } // namespace JS
230 #endif // js_Stack_h