1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_JIT_H 17 #define ECMASCRIPT_JIT_H 18 19 #include "ecmascript/common.h" 20 #include "ecmascript/compiler/compilation_env.h" 21 #include "ecmascript/platform/mutex.h" 22 #include "ecmascript/ecma_vm.h" 23 #include "ecmascript/mem/clock_scope.h" 24 #include "ecmascript/mem/machine_code.h" 25 #include "ecmascript/compiler/compiler_log.h" 26 #include "ecmascript/jit/jit_thread.h" 27 #include "ecmascript/jit/jit_dfx.h" 28 29 namespace panda::ecmascript { 30 class JitTask; 31 enum JitCompileMode { 32 SYNC = 0, 33 ASYNC 34 }; 35 36 enum class CompilerTier : uint8_t { 37 BASELINE, 38 FAST, 39 }; 40 41 struct ThreadTaskInfo { 42 std::deque<std::shared_ptr<JitTask>> installJitTasks_; 43 bool skipInstallTask_ { false }; 44 45 std::atomic<uint32_t> jitTaskCnt_; 46 ConditionVariable jitTaskCntCv_; 47 }; 48 49 class Jit { 50 public: Jit()51 Jit() {} 52 ~Jit(); 53 static PUBLIC_API Jit *GetInstance(); 54 void SetJitEnablePostFork(EcmaVM *vm, const std::string &bundleName); 55 void ConfigJit(EcmaVM *vm); 56 void SwitchProfileStubs(EcmaVM *vm); 57 void ConfigOptions(EcmaVM *vm) const; 58 void ConfigJitFortOptions(EcmaVM *vm); 59 void SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJit, bool isEnableBaselineJit); 60 bool PUBLIC_API IsEnableFastJit() const; 61 bool PUBLIC_API IsEnableBaselineJit() const; 62 bool PUBLIC_API IsEnableJitFort() const; 63 void SetEnableJitFort(bool isEnableJitFort); 64 bool IsDisableCodeSign() const; 65 void SetDisableCodeSign(bool isEnableCodeSign); 66 bool PUBLIC_API IsEnableAsyncCopyToFort() const; 67 void SetEnableAsyncCopyToFort(bool isEnableiAsyncCopyToFort); 68 void Initialize(); 69 70 static void Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier = CompilerTier::FAST, 71 int32_t offset = MachineCode::INVALID_OSR_OFFSET, JitCompileMode mode = SYNC); 72 bool JitCompile(void *compiler, JitTask *jitTask); 73 bool JitFinalize(void *compiler, JitTask *jitTask); 74 void *CreateJitCompilerTask(JitTask *jitTask); IsInitialized() const75 bool IsInitialized() const 76 { 77 return initialized_; 78 } 79 80 void DeleteJitCompile(void *compiler); 81 82 void RequestInstallCode(std::shared_ptr<JitTask> jitTask); 83 void InstallTasks(JSThread *jsThread); 84 void ClearTask(const std::function<bool(Task *task)> &checkClear); 85 void ClearTask(EcmaContext *ecmaContext); 86 void ClearTaskWithVm(EcmaVM *vm); 87 void Destroy(); 88 uint32_t GetRunningTaskCnt(EcmaVM *vm); 89 void CheckMechineCodeSpaceMemory(JSThread *thread, int remainSize); 90 void ChangeTaskPoolState(bool inBackground); 91 92 // dfx for jit warmup compile 93 static void CountInterpExecFuncs(JSHandle<JSFunction> &jsFunction); 94 IsAppJit() const95 bool IsAppJit() const 96 { 97 return isApp_; 98 } 99 GetHotnessThreshold() const100 uint32_t GetHotnessThreshold() const 101 { 102 return hotnessThreshold_; 103 } 104 SetProfileNeedDump(bool isNeed)105 void SetProfileNeedDump(bool isNeed) 106 { 107 isProfileNeedDump_ = isNeed; 108 } 109 IsProfileNeedDump() const110 bool IsProfileNeedDump() const 111 { 112 return isProfileNeedDump_; 113 } 114 GetJitDfx() const115 JitDfx *GetJitDfx() const 116 { 117 return jitDfx_; 118 } 119 120 void IncJitTaskCnt(JSThread *thread); 121 void DecJitTaskCnt(JSThread *thread); 122 123 NO_COPY_SEMANTIC(Jit); 124 NO_MOVE_SEMANTIC(Jit); 125 126 class TimeScope : public ClockScope { 127 public: TimeScope(EcmaVM *vm, CString message, CompilerTier tier = CompilerTier::FAST, bool outPutLog = true, bool isDebugLevel = false)128 explicit TimeScope(EcmaVM *vm, CString message, CompilerTier tier = CompilerTier::FAST, bool outPutLog = true, 129 bool isDebugLevel = false) 130 : vm_(vm), message_(message), tier_(tier), outPutLog_(outPutLog), isDebugLevel_(isDebugLevel) {} TimeScope(EcmaVM *vm)131 explicit TimeScope(EcmaVM *vm) 132 : vm_(vm), message_(""), tier_(CompilerTier::FAST), outPutLog_(false), isDebugLevel_(true) {} 133 PUBLIC_API ~TimeScope(); 134 private: 135 EcmaVM *vm_; 136 CString message_; 137 CompilerTier tier_; 138 bool outPutLog_; 139 bool isDebugLevel_; 140 }; 141 142 class JitLockHolder { 143 public: JitLockHolder(JSThread *thread)144 explicit JitLockHolder(JSThread *thread) : thread_(nullptr), scope_(thread->GetEcmaVM()) 145 { 146 if (thread->IsJitThread()) { 147 thread_ = static_cast<JitThread*>(thread); 148 if (thread_->GetState() != ThreadState::RUNNING) { 149 thread_->ManagedCodeBegin(); 150 isInManagedCode_ = true; 151 } 152 thread_->GetHostThread()->GetJitLock()->Lock(); 153 } 154 } 155 JitLockHolder(const CompilationEnv *env, CString message)156 explicit JitLockHolder(const CompilationEnv *env, CString message) : thread_(nullptr), 157 scope_(env->GetJSThread()->GetEcmaVM(), 158 "Jit Compile Pass: " + message + ", Time:", CompilerTier::FAST, false) 159 { 160 if (env->IsJitCompiler()) { 161 JSThread *thread = env->GetJSThread(); 162 ASSERT(thread->IsJitThread()); 163 thread_ = static_cast<JitThread*>(thread); 164 if (thread_->GetState() != ThreadState::RUNNING) { 165 thread_->ManagedCodeBegin(); 166 isInManagedCode_ = true; 167 } 168 thread_->GetHostThread()->GetJitLock()->Lock(); 169 } 170 } 171 ~JitLockHolder()172 ~JitLockHolder() 173 { 174 if (thread_ != nullptr) { 175 thread_->GetHostThread()->GetJitLock()->Unlock(); 176 if (isInManagedCode_) { 177 thread_->ManagedCodeEnd(); 178 } 179 } 180 } 181 JitThread *thread_ {nullptr}; 182 TimeScope scope_; 183 bool isInManagedCode_{false}; 184 ALLOW_HEAP_ACCESS 185 NO_COPY_SEMANTIC(JitLockHolder); 186 NO_MOVE_SEMANTIC(JitLockHolder); 187 }; 188 189 class JitGCLockHolder { 190 public: JitGCLockHolder(JSThread *thread)191 explicit JitGCLockHolder(JSThread *thread) : thread_(thread) 192 { 193 ASSERT(!thread->IsJitThread()); 194 if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) { 195 LockJit(thread_); 196 locked_ = true; 197 } 198 } 199 LockJit(JSThread *thread)200 static void LockJit(JSThread *thread) 201 { 202 Clock::time_point start = Clock::now(); 203 thread->GetJitLock()->Lock(); 204 Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime( 205 std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - start).count()); 206 } 207 UnlockJit(JSThread *thread)208 static void UnlockJit(JSThread *thread) 209 { 210 thread->GetJitLock()->Unlock(); 211 } 212 ~JitGCLockHolder()213 ~JitGCLockHolder() 214 { 215 if (locked_) { 216 UnlockJit(thread_); 217 locked_ = false; 218 } 219 } 220 221 private: 222 JSThread *thread_; 223 bool locked_ { false }; 224 225 NO_COPY_SEMANTIC(JitGCLockHolder); 226 NO_MOVE_SEMANTIC(JitGCLockHolder); 227 }; 228 229 private: 230 bool SupportJIT(JSHandle<JSFunction> &jsFunction, EcmaVM *vm, CompilerTier tier) const; 231 bool initialized_ { false }; 232 bool fastJitEnable_ { false }; 233 bool baselineJitEnable_ { false }; 234 bool isApp_ { false }; 235 bool isProfileNeedDump_ { true }; 236 uint32_t hotnessThreshold_ { 0 }; 237 std::string bundleName_; 238 bool isEnableAppPGO_ { true }; 239 240 std::unordered_map<JSThread*, ThreadTaskInfo> threadTaskInfo_; 241 RecursiveMutex threadTaskInfoLock_; 242 bool isEnableJitFort_ { true }; 243 bool isDisableCodeSign_ { true }; 244 bool isEnableAsyncCopyToFort_ { true }; 245 246 Mutex setEnableLock_; 247 248 JitDfx *jitDfx_ { nullptr }; 249 static constexpr int MIN_CODE_SPACE_SIZE = 1_KB; 250 251 static void (*initJitCompiler_)(JSRuntimeOptions); 252 static bool(*jitCompile_)(void*, JitTask*); 253 static bool(*jitFinalize_)(void*, JitTask*); 254 static void*(*createJitCompilerTask_)(JitTask*); 255 static void(*deleteJitCompile_)(void*); 256 static void *libHandle_; 257 static bool CheckJitCompileStatus(JSHandle<JSFunction> &jsFunction, 258 const CString &methodName, CompilerTier tier); 259 }; 260 } // namespace panda::ecmascript 261 #endif // ECMASCRIPT_JIT_H 262