Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / FrontendContext.h
blob43503608d2283e8213763207754d592ecfeb6ec6
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/Modules.h" // JS::ImportAssertionVector
19 #include "js/Stack.h" // JS::NativeStackSize, JS::NativeStackLimit, JS::NativeStackLimitMax
20 #include "js/Vector.h" // Vector
21 #include "vm/ErrorReporting.h" // CompileError
22 #include "vm/MallocProvider.h" // MallocProvider
23 #include "vm/SharedScriptDataTableHolder.h" // js::SharedScriptDataTableHolder, js::globalSharedScriptDataTableHolder
25 struct JSContext;
27 namespace js {
29 class FrontendContext;
31 namespace frontend {
32 class NameCollectionPool;
33 } // namespace frontend
35 struct FrontendErrors {
36 FrontendErrors() = default;
37 // Any errors or warnings produced during compilation. These are reported
38 // when finishing the script.
39 mozilla::Maybe<CompileError> error;
40 Vector<CompileError, 0, SystemAllocPolicy> warnings;
41 bool overRecursed = false;
42 bool outOfMemory = false;
43 bool allocationOverflow = false;
45 // Set to true if the compilation is initiated with extra bindings, but
46 // the script has no reference to the bindings, and the script should be
47 // compiled without the extra bindings.
49 // See frontend::CompileGlobalScriptWithExtraBindings.
50 bool extraBindingsAreNotUsed = false;
52 bool hadErrors() const {
53 return outOfMemory || overRecursed || allocationOverflow ||
54 extraBindingsAreNotUsed || error;
57 void clearErrors();
58 void clearWarnings();
61 class FrontendAllocator : public MallocProvider<FrontendAllocator> {
62 private:
63 FrontendContext* const fc_;
65 public:
66 explicit FrontendAllocator(FrontendContext* fc) : fc_(fc) {}
68 void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena,
69 size_t nbytes, void* reallocPtr = nullptr);
70 void reportAllocationOverflow();
73 class FrontendContext {
74 private:
75 FrontendAllocator alloc_;
76 js::FrontendErrors errors_;
78 // NameCollectionPool can be either:
79 // * owned by this FrontendContext, or
80 // * borrowed from JSContext
81 frontend::NameCollectionPool* nameCollectionPool_;
82 bool ownNameCollectionPool_;
84 js::SharedScriptDataTableHolder* scriptDataTableHolder_;
86 JS::ImportAssertionVector supportedImportAssertions_;
88 // Limit pointer for checking native stack consumption.
90 // The pointer is calculated based on the stack base of the current thread
91 // except for JS::NativeStackLimitMax. Once such value is set, this
92 // FrontendContext can be used only in the thread.
94 // In order to enforce this thread rule, setNativeStackLimitThread should
95 // be called when setting the value, and assertNativeStackLimitThread should
96 // be called at each entry-point that might make use of this field.
97 JS::NativeStackLimit stackLimit_ = JS::NativeStackLimitMax;
99 #ifdef DEBUG
100 // The thread ID where the native stack limit is set.
101 mozilla::Maybe<size_t> stackLimitThreadId_;
103 // The stack pointer where the AutoCheckRecursionLimit check is performed
104 // last time.
105 void* previousStackPointer_ = nullptr;
106 #endif
108 protected:
109 // (optional) Current JSContext to support main-thread-specific
110 // handling for error reporting, GC, and memory allocation.
112 // Set by setCurrentJSContext.
113 JSContext* maybeCx_ = nullptr;
115 public:
116 FrontendContext()
117 : alloc_(this),
118 nameCollectionPool_(nullptr),
119 ownNameCollectionPool_(false),
120 scriptDataTableHolder_(&js::globalSharedScriptDataTableHolder) {}
121 ~FrontendContext();
123 void setStackQuota(JS::NativeStackSize stackSize);
124 JS::NativeStackLimit stackLimit() const { return stackLimit_; }
126 bool allocateOwnedPool();
128 frontend::NameCollectionPool& nameCollectionPool() {
129 MOZ_ASSERT(
130 nameCollectionPool_,
131 "Either allocateOwnedPool or setCurrentJSContext must be called");
132 return *nameCollectionPool_;
135 js::SharedScriptDataTableHolder* scriptDataTableHolder() {
136 MOZ_ASSERT(scriptDataTableHolder_);
137 return scriptDataTableHolder_;
140 FrontendAllocator* getAllocator() { return &alloc_; }
142 // Use the given JSContext's for:
143 // * js::frontend::NameCollectionPool for reusing allocation
144 // * js::SharedScriptDataTableHolder for de-duplicating bytecode
145 // within given runtime
146 // * Copy the native stack limit from the JSContext
148 // And also this JSContext can be retrieved by maybeCurrentJSContext below.
149 void setCurrentJSContext(JSContext* cx);
151 // Returns JSContext if any.
153 // This can be used only for:
154 // * Main-thread-specific operation, such as operating on JSAtom
155 // * Optional operation, such as providing better error message
156 JSContext* maybeCurrentJSContext() { return maybeCx_; }
158 const JS::ImportAssertionVector& getSupportedImportAssertions() const {
159 return supportedImportAssertions_;
161 bool setSupportedImportAssertions(
162 const JS::ImportAssertionVector& supportedImportAssertions);
164 enum class Warning { Suppress, Report };
166 // Returns false if the error cannot be converted (such as due to OOM). An
167 // error might still be reported to the given JSContext. Returns true
168 // otherwise.
169 bool convertToRuntimeError(JSContext* cx, Warning warning = Warning::Report);
171 mozilla::Maybe<CompileError>& maybeError() { return errors_.error; }
172 Vector<CompileError, 0, SystemAllocPolicy>& warnings() {
173 return errors_.warnings;
176 // Report CompileErrors
177 void reportError(js::CompileError&& err);
178 bool reportWarning(js::CompileError&& err);
180 // Report FrontendAllocator errors
181 void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena,
182 size_t nbytes, void* reallocPtr = nullptr);
183 void onAllocationOverflow();
185 void onOutOfMemory();
186 void onOverRecursed();
188 void recoverFromOutOfMemory();
190 const JSErrorFormatString* gcSafeCallback(JSErrorCallback callback,
191 void* userRef,
192 const unsigned errorNumber);
194 // Status of errors reported to this FrontendContext
195 bool hadOutOfMemory() const { return errors_.outOfMemory; }
196 bool hadOverRecursed() const { return errors_.overRecursed; }
197 bool hadAllocationOverflow() const { return errors_.allocationOverflow; }
198 bool extraBindingsAreNotUsed() const {
199 return errors_.extraBindingsAreNotUsed;
201 void reportExtraBindingsAreNotUsed() {
202 errors_.extraBindingsAreNotUsed = true;
204 void clearNoExtraBindingReferencesFound() {
205 errors_.extraBindingsAreNotUsed = false;
207 bool hadErrors() const;
208 // Clear errors and warnings.
209 void clearErrors();
210 // Clear warnings only.
211 void clearWarnings();
213 #ifdef __wasi__
214 void incWasiRecursionDepth();
215 void decWasiRecursionDepth();
216 bool checkWasiRecursionLimit();
217 #endif // __wasi__
219 #ifdef DEBUG
220 void setNativeStackLimitThread();
221 void assertNativeStackLimitThread();
222 #endif
224 #ifdef DEBUG
225 void checkAndUpdateFrontendContextRecursionLimit(void* sp);
226 #endif
228 private:
229 void ReportOutOfMemory();
230 void addPendingOutOfMemory();
233 // Automatically report any pending exception when leaving the scope.
234 class MOZ_STACK_CLASS AutoReportFrontendContext : public FrontendContext {
235 // The target JSContext to report the errors to.
236 JSContext* cx_;
238 Warning warning_;
240 public:
241 explicit AutoReportFrontendContext(JSContext* cx,
242 Warning warning = Warning::Report)
243 : cx_(cx), warning_(warning) {
244 setCurrentJSContext(cx_);
245 MOZ_ASSERT(cx_ == maybeCx_);
248 ~AutoReportFrontendContext() {
249 if (cx_) {
250 convertToRuntimeErrorAndClear();
254 void clearAutoReport() { cx_ = nullptr; }
256 bool convertToRuntimeErrorAndClear() {
257 bool result = convertToRuntimeError(cx_, warning_);
258 cx_ = nullptr;
259 return result;
264 * Explicitly report any pending exception before leaving the scope.
266 * Before an instance of this class leaves the scope, you must call either
267 * failure() (if there are exceptions to report) or ok() (if there are no
268 * exceptions to report).
270 class ManualReportFrontendContext : public FrontendContext {
271 JSContext* cx_;
272 #ifdef DEBUG
273 bool handled_ = false;
274 #endif
276 public:
277 explicit ManualReportFrontendContext(JSContext* cx) : cx_(cx) {
278 setCurrentJSContext(cx_);
281 ~ManualReportFrontendContext() { MOZ_ASSERT(handled_); }
283 void ok() {
284 #ifdef DEBUG
285 handled_ = true;
286 #endif
289 void failure() {
290 #ifdef DEBUG
291 handled_ = true;
292 #endif
293 convertToRuntimeError(cx_);
297 // Create function for FrontendContext, which is manually allocated and
298 // exclusively owned.
299 extern FrontendContext* NewFrontendContext();
301 // Destroy function for FrontendContext, which was allocated with
302 // NewFrontendContext.
303 extern void DestroyFrontendContext(FrontendContext* fc);
305 } // namespace js
307 #endif /* frontend_FrontendContext_h */