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