Bug 1904979 - Update codespell to 2.3.0 r=linter-reviewers,Standard8
[gecko.git] / js / src / frontend / FrontendContext.h
blobe7fc30ca7049ba5d47d73f81ac7ef220d7fa38ab
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 frontend_FrontendContext_h
8 #define frontend_FrontendContext_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS
12 #include "mozilla/Maybe.h" // mozilla::Maybe
14 #include <stddef.h> // size_t
16 #include "js/AllocPolicy.h" // SystemAllocPolicy, AllocFunction
17 #include "js/ErrorReport.h" // JSErrorCallback, JSErrorFormatString
18 #include "js/Stack.h" // JS::NativeStackSize, JS::NativeStackLimit, JS::NativeStackLimitMax
19 #include "js/Vector.h" // Vector
20 #include "vm/ErrorReporting.h" // CompileError
21 #include "vm/MallocProvider.h" // MallocProvider
22 #include "vm/SharedScriptDataTableHolder.h" // js::SharedScriptDataTableHolder, js::globalSharedScriptDataTableHolder
24 struct JSContext;
26 namespace js {
28 class FrontendContext;
30 namespace frontend {
31 class NameCollectionPool;
32 } // namespace frontend
34 struct FrontendErrors {
35 FrontendErrors() = default;
36 // Any errors or warnings produced during compilation. These are reported
37 // when finishing the script.
38 mozilla::Maybe<CompileError> error;
39 Vector<CompileError, 0, SystemAllocPolicy> warnings;
40 bool overRecursed = false;
41 bool outOfMemory = false;
42 bool allocationOverflow = false;
44 // Set to true if the compilation is initiated with extra bindings, but
45 // the script has no reference to the bindings, and the script should be
46 // compiled without the extra bindings.
48 // See frontend::CompileGlobalScriptWithExtraBindings.
49 bool extraBindingsAreNotUsed = false;
51 bool hadErrors() const {
52 return outOfMemory || overRecursed || allocationOverflow ||
53 extraBindingsAreNotUsed || error;
56 void clearErrors();
57 void clearWarnings();
60 class FrontendAllocator : public MallocProvider<FrontendAllocator> {
61 private:
62 FrontendContext* const fc_;
64 public:
65 explicit FrontendAllocator(FrontendContext* fc) : fc_(fc) {}
67 void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena,
68 size_t nbytes, void* reallocPtr = nullptr);
69 void reportAllocationOverflow();
72 class FrontendContext {
73 private:
74 FrontendAllocator alloc_;
75 js::FrontendErrors errors_;
77 // NameCollectionPool can be either:
78 // * owned by this FrontendContext, or
79 // * borrowed from JSContext
80 frontend::NameCollectionPool* nameCollectionPool_;
81 bool ownNameCollectionPool_;
83 js::SharedScriptDataTableHolder* scriptDataTableHolder_;
85 // Limit pointer for checking native stack consumption.
87 // The pointer is calculated based on the stack base of the current thread
88 // except for JS::NativeStackLimitMax. Once such value is set, this
89 // FrontendContext can be used only in the thread.
91 // In order to enforce this thread rule, setNativeStackLimitThread should
92 // be called when setting the value, and assertNativeStackLimitThread should
93 // be called at each entry-point that might make use of this field.
94 JS::NativeStackLimit stackLimit_ = JS::NativeStackLimitMax;
96 #ifdef DEBUG
97 // The thread ID where the native stack limit is set.
98 mozilla::Maybe<size_t> stackLimitThreadId_;
100 // The stack pointer where the AutoCheckRecursionLimit check is performed
101 // last time.
102 void* previousStackPointer_ = nullptr;
103 #endif
105 protected:
106 // (optional) Current JSContext to support main-thread-specific
107 // handling for error reporting, GC, and memory allocation.
109 // Set by setCurrentJSContext.
110 JSContext* maybeCx_ = nullptr;
112 public:
113 FrontendContext()
114 : alloc_(this),
115 nameCollectionPool_(nullptr),
116 ownNameCollectionPool_(false),
117 scriptDataTableHolder_(&js::globalSharedScriptDataTableHolder) {}
118 ~FrontendContext();
120 void setStackQuota(JS::NativeStackSize stackSize);
121 JS::NativeStackLimit stackLimit() const { return stackLimit_; }
123 bool allocateOwnedPool();
125 frontend::NameCollectionPool& nameCollectionPool() {
126 MOZ_ASSERT(
127 nameCollectionPool_,
128 "Either allocateOwnedPool or setCurrentJSContext must be called");
129 return *nameCollectionPool_;
132 js::SharedScriptDataTableHolder* scriptDataTableHolder() {
133 MOZ_ASSERT(scriptDataTableHolder_);
134 return scriptDataTableHolder_;
137 FrontendAllocator* getAllocator() { return &alloc_; }
139 // Use the given JSContext's for:
140 // * js::frontend::NameCollectionPool for reusing allocation
141 // * js::SharedScriptDataTableHolder for de-duplicating bytecode
142 // within given runtime
143 // * Copy the native stack limit from the JSContext
145 // And also this JSContext can be retrieved by maybeCurrentJSContext below.
146 void setCurrentJSContext(JSContext* cx);
148 // Returns JSContext if any.
150 // This can be used only for:
151 // * Main-thread-specific operation, such as operating on JSAtom
152 // * Optional operation, such as providing better error message
153 JSContext* maybeCurrentJSContext() { return maybeCx_; }
155 enum class Warning { Suppress, Report };
157 // Returns false if the error cannot be converted (such as due to OOM). An
158 // error might still be reported to the given JSContext. Returns true
159 // otherwise.
160 bool convertToRuntimeError(JSContext* cx, Warning warning = Warning::Report);
162 mozilla::Maybe<CompileError>& maybeError() { return errors_.error; }
163 Vector<CompileError, 0, SystemAllocPolicy>& warnings() {
164 return errors_.warnings;
167 // Report CompileErrors
168 void reportError(js::CompileError&& err);
169 bool reportWarning(js::CompileError&& err);
171 // Report FrontendAllocator errors
172 void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena,
173 size_t nbytes, void* reallocPtr = nullptr);
174 void onAllocationOverflow();
176 void onOutOfMemory();
177 void onOverRecursed();
179 void recoverFromOutOfMemory();
181 const JSErrorFormatString* gcSafeCallback(JSErrorCallback callback,
182 void* userRef,
183 const unsigned errorNumber);
185 // Status of errors reported to this FrontendContext
186 bool hadOutOfMemory() const { return errors_.outOfMemory; }
187 bool hadOverRecursed() const { return errors_.overRecursed; }
188 bool hadAllocationOverflow() const { return errors_.allocationOverflow; }
189 bool extraBindingsAreNotUsed() const {
190 return errors_.extraBindingsAreNotUsed;
192 void reportExtraBindingsAreNotUsed() {
193 errors_.extraBindingsAreNotUsed = true;
195 void clearNoExtraBindingReferencesFound() {
196 errors_.extraBindingsAreNotUsed = false;
198 bool hadErrors() const;
199 // Clear errors and warnings.
200 void clearErrors();
201 // Clear warnings only.
202 void clearWarnings();
204 #ifdef __wasi__
205 void incWasiRecursionDepth();
206 void decWasiRecursionDepth();
207 bool checkWasiRecursionLimit();
208 #endif // __wasi__
210 #ifdef DEBUG
211 void setNativeStackLimitThread();
212 void assertNativeStackLimitThread();
213 #endif
215 #ifdef DEBUG
216 void checkAndUpdateFrontendContextRecursionLimit(void* sp);
217 #endif
219 private:
220 void ReportOutOfMemory();
221 void addPendingOutOfMemory();
224 // Automatically report any pending exception when leaving the scope.
225 class MOZ_STACK_CLASS AutoReportFrontendContext : public FrontendContext {
226 // The target JSContext to report the errors to.
227 JSContext* cx_;
229 Warning warning_;
231 public:
232 explicit AutoReportFrontendContext(JSContext* cx,
233 Warning warning = Warning::Report)
234 : cx_(cx), warning_(warning) {
235 setCurrentJSContext(cx_);
236 MOZ_ASSERT(cx_ == maybeCx_);
239 ~AutoReportFrontendContext() {
240 if (cx_) {
241 convertToRuntimeErrorAndClear();
245 void clearAutoReport() { cx_ = nullptr; }
247 bool convertToRuntimeErrorAndClear() {
248 bool result = convertToRuntimeError(cx_, warning_);
249 cx_ = nullptr;
250 return result;
255 * Explicitly report any pending exception before leaving the scope.
257 * Before an instance of this class leaves the scope, you must call either
258 * failure() (if there are exceptions to report) or ok() (if there are no
259 * exceptions to report).
261 class ManualReportFrontendContext : public FrontendContext {
262 JSContext* cx_;
263 #ifdef DEBUG
264 bool handled_ = false;
265 #endif
267 public:
268 explicit ManualReportFrontendContext(JSContext* cx) : cx_(cx) {
269 setCurrentJSContext(cx_);
272 ~ManualReportFrontendContext() { MOZ_ASSERT(handled_); }
274 void ok() {
275 #ifdef DEBUG
276 handled_ = true;
277 #endif
280 void failure() {
281 #ifdef DEBUG
282 handled_ = true;
283 #endif
284 convertToRuntimeError(cx_);
288 // Create function for FrontendContext, which is manually allocated and
289 // exclusively owned.
290 extern FrontendContext* NewFrontendContext();
292 // Destroy function for FrontendContext, which was allocated with
293 // NewFrontendContext.
294 extern void DestroyFrontendContext(FrontendContext* fc);
296 } // namespace js
298 #endif /* frontend_FrontendContext_h */