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()75 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 95 void ReuseCompiledFunc(JSThread *thread, JSHandle<JSFunction> &function); 96 IsAppJit()97 bool IsAppJit() const 98 { 99 return isApp_; 100 } 101 GetHotnessThreshold()102 uint32_t GetHotnessThreshold() const 103 { 104 return hotnessThreshold_; 105 } 106 SetProfileNeedDump(bool isNeed)107 void SetProfileNeedDump(bool isNeed) 108 { 109 isProfileNeedDump_ = isNeed; 110 } 111 IsProfileNeedDump()112 bool IsProfileNeedDump() const 113 { 114 return isProfileNeedDump_; 115 } 116 GetJitDfx()117 JitDfx *GetJitDfx() const 118 { 119 return jitDfx_; 120 } 121 122 void IncJitTaskCnt(JSThread *thread); 123 void DecJitTaskCnt(JSThread *thread); 124 125 NO_COPY_SEMANTIC(Jit); 126 NO_MOVE_SEMANTIC(Jit); 127 128 class TimeScope : public ClockScope { 129 public: 130 explicit TimeScope(EcmaVM *vm, CString message, CompilerTier tier = CompilerTier::FAST, bool outPutLog = true, 131 bool isDebugLevel = false) vm_(vm)132 : vm_(vm), message_(message), tier_(tier), outPutLog_(outPutLog), isDebugLevel_(isDebugLevel) {} TimeScope(EcmaVM * vm)133 explicit TimeScope(EcmaVM *vm) 134 : vm_(vm), message_(""), tier_(CompilerTier::FAST), outPutLog_(false), isDebugLevel_(true) {} 135 PUBLIC_API ~TimeScope(); 136 private: 137 EcmaVM *vm_; 138 CString message_; 139 CompilerTier tier_; 140 bool outPutLog_; 141 bool isDebugLevel_; 142 }; 143 144 class JitLockHolder { 145 public: JitLockHolder(JSThread * thread)146 explicit JitLockHolder(JSThread *thread) : thread_(nullptr), scope_(thread->GetEcmaVM()) 147 { 148 if (thread->IsJitThread()) { 149 thread_ = static_cast<JitThread*>(thread); 150 if (thread_->GetState() != ThreadState::RUNNING) { 151 thread_->ManagedCodeBegin(); 152 isInManagedCode_ = true; 153 } 154 thread_->GetHostThread()->GetJitLock()->Lock(); 155 } 156 } 157 JitLockHolder(const CompilationEnv * env,CString message)158 explicit JitLockHolder(const CompilationEnv *env, CString message) : thread_(nullptr), 159 scope_(env->GetJSThread()->GetEcmaVM(), 160 "Jit Compile Pass: " + message + ", Time:", CompilerTier::FAST, false) 161 { 162 if (env->IsJitCompiler()) { 163 JSThread *thread = env->GetJSThread(); 164 ASSERT(thread->IsJitThread()); 165 thread_ = static_cast<JitThread*>(thread); 166 if (thread_->GetState() != ThreadState::RUNNING) { 167 thread_->ManagedCodeBegin(); 168 isInManagedCode_ = true; 169 } 170 thread_->GetHostThread()->GetJitLock()->Lock(); 171 } 172 } 173 ~JitLockHolder()174 ~JitLockHolder() 175 { 176 if (thread_ != nullptr) { 177 thread_->GetHostThread()->GetJitLock()->Unlock(); 178 if (isInManagedCode_) { 179 thread_->ManagedCodeEnd(); 180 } 181 } 182 } 183 JitThread *thread_ {nullptr}; 184 TimeScope scope_; 185 bool isInManagedCode_{false}; 186 ALLOW_HEAP_ACCESS 187 NO_COPY_SEMANTIC(JitLockHolder); 188 NO_MOVE_SEMANTIC(JitLockHolder); 189 }; 190 191 class JitGCLockHolder { 192 public: JitGCLockHolder(JSThread * thread)193 explicit JitGCLockHolder(JSThread *thread) : thread_(thread) 194 { 195 ASSERT(!thread->IsJitThread()); 196 if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) { 197 LockJit(thread_); 198 locked_ = true; 199 } 200 } 201 LockJit(JSThread * thread)202 static void LockJit(JSThread *thread) 203 { 204 Clock::time_point start = Clock::now(); 205 thread->GetJitLock()->Lock(); 206 Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime( 207 std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - start).count()); 208 } 209 UnlockJit(JSThread * thread)210 static void UnlockJit(JSThread *thread) 211 { 212 thread->GetJitLock()->Unlock(); 213 } 214 ~JitGCLockHolder()215 ~JitGCLockHolder() 216 { 217 if (locked_) { 218 UnlockJit(thread_); 219 locked_ = false; 220 } 221 } 222 223 private: 224 JSThread *thread_; 225 bool locked_ { false }; 226 227 NO_COPY_SEMANTIC(JitGCLockHolder); 228 NO_MOVE_SEMANTIC(JitGCLockHolder); 229 }; 230 231 private: 232 bool SupportJIT(JSHandle<JSFunction> &jsFunction, EcmaVM *vm, CompilerTier tier) const; 233 bool initialized_ { false }; 234 bool fastJitEnable_ { false }; 235 bool baselineJitEnable_ { false }; 236 bool isApp_ { false }; 237 bool isProfileNeedDump_ { true }; 238 uint32_t hotnessThreshold_ { 0 }; 239 std::string bundleName_; 240 bool isEnableAppPGO_ { true }; 241 242 std::unordered_map<JSThread*, ThreadTaskInfo> threadTaskInfo_; 243 RecursiveMutex threadTaskInfoLock_; 244 bool isEnableJitFort_ { true }; 245 bool isDisableCodeSign_ { true }; 246 bool isEnableAsyncCopyToFort_ { true }; 247 248 Mutex setEnableLock_; 249 250 JitDfx *jitDfx_ { nullptr }; 251 static constexpr int MIN_CODE_SPACE_SIZE = 1_KB; 252 253 static void (*initJitCompiler_)(JSRuntimeOptions); 254 static bool(*jitCompile_)(void*, JitTask*); 255 static bool(*jitFinalize_)(void*, JitTask*); 256 static void*(*createJitCompilerTask_)(JitTask*); 257 static void(*deleteJitCompile_)(void*); 258 static void *libHandle_; 259 static bool CheckJitCompileStatus(JSHandle<JSFunction> &jsFunction, 260 const CString &methodName, CompilerTier tier); 261 }; 262 } // namespace panda::ecmascript 263 #endif // ECMASCRIPT_JIT_H 264