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/. */
6 
7 #ifndef jit_JitContext_h
8 #define jit_JitContext_h
9 
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Result.h"
12 
13 #include <stdint.h>
14 
15 #include "jstypes.h"
16 
17 struct JS_PUBLIC_API JSContext;
18 
19 namespace js {
20 namespace jit {
21 
22 class CompileRealm;
23 class CompileRuntime;
24 class TempAllocator;
25 
26 enum MethodStatus {
27   Method_Error,
28   Method_CantCompile,
29   Method_Skipped,
30   Method_Compiled
31 };
32 
33 // Use only even, non-zero values for errors, to allow using the UnusedZero and
34 // HasFreeLSB optimizations for mozilla::Result (see specializations of
35 // UnusedZero/HasFreeLSB below).
36 enum class AbortReason : uint8_t {
37   NoAbort,
38   Alloc = 2,
39   Disable = 4,
40   Error = 6,
41 };
42 }  // namespace jit
43 }  // namespace js
44 
45 namespace mozilla::detail {
46 
47 template <>
48 struct UnusedZero<js::jit::AbortReason> : UnusedZeroEnum<js::jit::AbortReason> {
49 };
50 
51 template <>
52 struct HasFreeLSB<js::jit::AbortReason> {
53   static const bool value = true;
54 };
55 
56 }  // namespace mozilla::detail
57 
58 namespace js {
59 namespace jit {
60 
61 template <typename V>
62 using AbortReasonOr = mozilla::Result<V, AbortReason>;
63 using mozilla::Err;
64 using mozilla::Ok;
65 
66 static_assert(sizeof(AbortReasonOr<Ok>) <= sizeof(uintptr_t),
67               "Unexpected size of AbortReasonOr<Ok>");
68 static_assert(mozilla::detail::SelectResultImpl<bool, AbortReason>::value ==
69               mozilla::detail::PackingStrategy::NullIsOk);
70 static_assert(sizeof(AbortReasonOr<bool>) <= sizeof(uintptr_t),
71               "Unexpected size of AbortReasonOr<bool>");
72 static_assert(sizeof(AbortReasonOr<uint16_t*>) == sizeof(uintptr_t),
73               "Unexpected size of AbortReasonOr<uint16_t*>");
74 
75 // A JIT context is needed to enter into either an JIT method or an instance
76 // of a JIT compiler. It points to a temporary allocator and the active
77 // JSContext, either of which may be nullptr, and the active realm, which
78 // will not be nullptr.
79 
80 class JitContext {
81   JitContext* prev_ = nullptr;
82   CompileRealm* realm_ = nullptr;
83   int assemblerCount_ = 0;
84 
85 #ifdef DEBUG
86   // Whether this thread is actively Ion compiling (does not include Wasm or
87   // WarpOracle).
88   bool inIonBackend_ = false;
89 
90   bool isCompilingWasm_ = false;
91   bool oom_ = false;
92 #endif
93 
94  public:
95   // Running context when executing on the main thread. Not available during
96   // compilation.
97   JSContext* cx = nullptr;
98 
99   // Allocator for temporary memory during compilation.
100   TempAllocator* temp = nullptr;
101 
102   // Wrappers with information about the current runtime/realm for use
103   // during compilation.
104   CompileRuntime* runtime = nullptr;
105 
106   // Constructor for compilations happening on the main thread.
107   JitContext(JSContext* cx, TempAllocator* temp);
108 
109   // Constructor for off-thread Ion compilations.
110   JitContext(CompileRuntime* rt, CompileRealm* realm, TempAllocator* temp);
111 
112   // Constructors for Wasm compilation.
113   explicit JitContext(TempAllocator* temp);
114   JitContext();
115 
116   ~JitContext();
117 
118   int getNextAssemblerId() { return assemblerCount_++; }
119 
120   CompileRealm* maybeRealm() const { return realm_; }
121   CompileRealm* realm() const {
122     MOZ_ASSERT(maybeRealm());
123     return maybeRealm();
124   }
125 
126 #ifdef DEBUG
127   bool isCompilingWasm() { return isCompilingWasm_; }
128   bool setIsCompilingWasm(bool flag) {
129     bool oldFlag = isCompilingWasm_;
130     isCompilingWasm_ = flag;
131     return oldFlag;
132   }
133   bool hasOOM() { return oom_; }
134   void setOOM() { oom_ = true; }
135 
136   bool inIonBackend() const { return inIonBackend_; }
137 
138   void enterIonBackend() {
139     MOZ_ASSERT(!inIonBackend_);
140     inIonBackend_ = true;
141   }
142   void leaveIonBackend() {
143     MOZ_ASSERT(inIonBackend_);
144     inIonBackend_ = false;
145   }
146 #endif
147 };
148 
149 // Process-wide initialization of JIT data structures.
150 [[nodiscard]] bool InitializeJit();
151 
152 // Call this after changing hardware parameters via command line flags (on
153 // platforms that support that).
154 void ComputeJitSupportFlags();
155 
156 // Get and set the current JIT context.
157 JitContext* GetJitContext();
158 JitContext* MaybeGetJitContext();
159 
160 void SetJitContext(JitContext* ctx);
161 
162 enum JitExecStatus {
163   // The method call had to be aborted due to a stack limit check. This
164   // error indicates that Ion never attempted to clean up frames.
165   JitExec_Aborted,
166 
167   // The method call resulted in an error, and IonMonkey has cleaned up
168   // frames.
169   JitExec_Error,
170 
171   // The method call succeeded and returned a value.
172   JitExec_Ok
173 };
174 
175 static inline bool IsErrorStatus(JitExecStatus status) {
176   return status == JitExec_Error || status == JitExec_Aborted;
177 }
178 
179 bool JitSupportsWasmSimd();
180 bool JitSupportsAtomics();
181 
182 }  // namespace jit
183 }  // namespace js
184 
185 #endif /* jit_JitContext_h */
186