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
29 class FrontendContext
;
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
;
61 class FrontendAllocator
: public MallocProvider
<FrontendAllocator
> {
63 FrontendContext
* const fc_
;
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
{
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
;
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
105 void* previousStackPointer_
= nullptr;
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;
118 nameCollectionPool_(nullptr),
119 ownNameCollectionPool_(false),
120 scriptDataTableHolder_(&js::globalSharedScriptDataTableHolder
) {}
123 void setStackQuota(JS::NativeStackSize stackSize
);
124 JS::NativeStackLimit
stackLimit() const { return stackLimit_
; }
126 bool allocateOwnedPool();
128 frontend::NameCollectionPool
& 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
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
,
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.
210 // Clear warnings only.
211 void clearWarnings();
214 void incWasiRecursionDepth();
215 void decWasiRecursionDepth();
216 bool checkWasiRecursionLimit();
220 void setNativeStackLimitThread();
221 void assertNativeStackLimitThread();
225 void checkAndUpdateFrontendContextRecursionLimit(void* sp
);
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.
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() {
250 convertToRuntimeErrorAndClear();
254 void clearAutoReport() { cx_
= nullptr; }
256 bool convertToRuntimeErrorAndClear() {
257 bool result
= convertToRuntimeError(cx_
, warning_
);
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
{
273 bool handled_
= false;
277 explicit ManualReportFrontendContext(JSContext
* cx
) : cx_(cx
) {
278 setCurrentJSContext(cx_
);
281 ~ManualReportFrontendContext() { MOZ_ASSERT(handled_
); }
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
);
307 #endif /* frontend_FrontendContext_h */