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 #include "ecmascript/jit/compile_decision.h" 29 #include "ecmascript/jit/jit_resources.h" 30 31 namespace panda::ecmascript { 32 class JitTask; 33 34 struct ThreadTaskInfo { 35 std::deque<std::shared_ptr<JitTask>> installJitTasks_; 36 bool skipInstallTask_ { false }; 37 38 std::atomic<uint32_t> jitTaskCnt_; 39 ConditionVariable jitTaskCntCv_; 40 }; 41 42 class Jit { 43 public: Jit()44 Jit() {} 45 ~Jit(); 46 static PUBLIC_API Jit *GetInstance(); 47 void SetJitEnablePostFork(EcmaVM *vm, const std::string &bundleName); 48 void PreFork(); 49 void ConfigJit(EcmaVM *vm); 50 void SwitchProfileStubs(EcmaVM *vm); 51 void ConfigOptions(EcmaVM *vm) const; 52 void ConfigJitFortOptions(EcmaVM *vm); 53 void SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJit, bool isEnableBaselineJit); 54 bool PUBLIC_API IsEnableFastJit() const; 55 bool PUBLIC_API IsEnableBaselineJit() const; 56 bool PUBLIC_API IsEnableJitFort() const; 57 void SetEnableJitFort(bool isEnableJitFort); 58 bool IsDisableCodeSign() const; 59 void SetDisableCodeSign(bool isEnableCodeSign); 60 bool PUBLIC_API IsEnableAsyncCopyToFort() const; 61 void SetEnableAsyncCopyToFort(bool isEnableiAsyncCopyToFort); 62 63 static void Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, 64 CompilerTier::Tier tier = CompilerTier::Tier::FAST, 65 int32_t offset = MachineCode::INVALID_OSR_OFFSET, 66 JitCompileMode::Mode mode = JitCompileMode::Mode::SYNC) 67 { 68 Compile(vm, jsFunction, CompilerTier(tier), offset, JitCompileMode(mode)); 69 } 70 71 bool JitCompile(void *compiler, JitTask *jitTask); 72 bool JitFinalize(void *compiler, JitTask *jitTask); 73 void *CreateJitCompilerTask(JitTask *jitTask); IsInitialized()74 bool IsInitialized() const 75 { 76 return initialized_; 77 } 78 79 void DeleteJitCompilerTask(void *compiler); 80 81 void RequestInstallCode(std::shared_ptr<JitTask> jitTask); 82 void InstallTasks(JSThread *jsThread); 83 void ClearTask(const std::function<bool(common::Task *task)> &checkClear); 84 void ClearTaskWithVm(EcmaVM *vm); 85 void Destroy(); 86 uint32_t GetRunningTaskCnt(EcmaVM *vm); 87 void CheckMechineCodeSpaceMemory(JSThread *thread, int remainSize); 88 void ChangeTaskPoolState(bool inBackground); 89 90 // dfx for jit warmup compile 91 static void CountInterpExecFuncs(JSThread *jsThread, JSHandle<JSFunction> &jsFunction); 92 IsAppJit()93 bool IsAppJit() const 94 { 95 return isApp_; 96 } 97 GetHotnessThreshold()98 uint32_t GetHotnessThreshold() const 99 { 100 return hotnessThreshold_; 101 } 102 SetProfileNeedDump(bool isNeed)103 void SetProfileNeedDump(bool isNeed) 104 { 105 isProfileNeedDump_ = isNeed; 106 } 107 IsProfileNeedDump()108 bool IsProfileNeedDump() const 109 { 110 return isProfileNeedDump_; 111 } 112 GetJitDfx()113 JitDfx *GetJitDfx() const 114 { 115 return jitDfx_; 116 } 117 118 void IncJitTaskCnt(JSThread *thread); 119 void DecJitTaskCnt(JSThread *thread); 120 121 NO_COPY_SEMANTIC(Jit); 122 NO_MOVE_SEMANTIC(Jit); 123 124 class TimeScope : public ClockScope { 125 public: 126 PUBLIC_API explicit TimeScope(EcmaVM *vm, CString message, CompilerTier tier, bool outPutLog = true, 127 bool isDebugLevel = false); TimeScope(EcmaVM * vm)128 explicit TimeScope(EcmaVM *vm) 129 : vm_(vm), message_(""), tier_(CompilerTier::Tier::FAST), outPutLog_(false), isDebugLevel_(true) {} 130 PUBLIC_API ~TimeScope(); 131 appendMessage(const CString & value)132 void appendMessage(const CString& value) { message_ += value; } 133 134 private: 135 EcmaVM *vm_; 136 CString message_; 137 CompilerTier tier_; 138 bool outPutLog_; 139 bool isDebugLevel_; 140 }; 141 142 class JitLockBase { 143 public: 144 virtual ~JitLockBase() = default; 145 146 protected: 147 JitLockBase() = default; 148 149 NO_COPY_SEMANTIC(JitLockBase); 150 NO_MOVE_SEMANTIC(JitLockBase); 151 }; 152 153 class JitLockHolder : public JitLockBase { 154 public: JitLockHolder(JSThread * thread)155 explicit JitLockHolder(JSThread *thread) : thread_(nullptr), scope_(thread->GetEcmaVM()) 156 { 157 if (thread->IsJitThread()) { 158 thread_ = static_cast<JitThread*>(thread); 159 if (!thread_->IsInRunningState()) { 160 thread_->ManagedCodeBegin(); 161 isInManagedCode_ = true; 162 } 163 thread_->GetHostThread()->GetJitLock()->Lock(); 164 } 165 } 166 JitLockHolder(const CompilationEnv * env,CString message)167 explicit JitLockHolder(const CompilationEnv *env, CString message) : thread_(nullptr), 168 scope_(env->GetJSThread()->GetEcmaVM(), 169 "Jit Compile Pass: " + message + ", Time:", CompilerTier::Tier::FAST, false) 170 { 171 if (env->IsJitCompiler()) { 172 JSThread *thread = env->GetJSThread(); 173 ASSERT(thread->IsJitThread()); 174 thread_ = static_cast<JitThread*>(thread); 175 if (!thread_->IsInRunningState()) { 176 thread_->ManagedCodeBegin(); 177 isInManagedCode_ = true; 178 } 179 thread_->GetHostThread()->GetJitLock()->Lock(); 180 } 181 } 182 ~JitLockHolder()183 ~JitLockHolder() 184 { 185 if (thread_ != nullptr) { 186 thread_->GetHostThread()->GetJitLock()->Unlock(); 187 if (isInManagedCode_) { 188 thread_->ManagedCodeEnd(); 189 } 190 } 191 } 192 JitThread *thread_ {nullptr}; 193 TimeScope scope_; 194 bool isInManagedCode_{false}; 195 ALLOW_HEAP_ACCESS 196 NO_COPY_SEMANTIC(JitLockHolder); 197 NO_MOVE_SEMANTIC(JitLockHolder); 198 }; 199 200 class JitGCLockHolder : public JitLockBase { 201 public: JitGCLockHolder(JSThread * thread)202 explicit JitGCLockHolder(JSThread *thread) : thread_(thread) 203 { 204 ASSERT(!thread->IsJitThread()); 205 if (Jit::GetInstance()->IsEnableFastJit() || Jit::GetInstance()->IsEnableBaselineJit()) { 206 LockJit(thread_); 207 locked_ = true; 208 } 209 } 210 LockJit(JSThread * thread)211 static void LockJit(JSThread *thread) 212 { 213 Clock::time_point start = Clock::now(); 214 thread->GetJitLock()->Lock(); 215 Jit::GetInstance()->GetJitDfx()->SetLockHoldingTime( 216 std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - start).count()); 217 } 218 UnlockJit(JSThread * thread)219 static void UnlockJit(JSThread *thread) 220 { 221 thread->GetJitLock()->Unlock(); 222 } 223 ~JitGCLockHolder()224 ~JitGCLockHolder() 225 { 226 if (locked_) { 227 UnlockJit(thread_); 228 locked_ = false; 229 } 230 } 231 232 private: 233 JSThread *thread_; 234 bool locked_ { false }; 235 236 NO_COPY_SEMANTIC(JitGCLockHolder); 237 NO_MOVE_SEMANTIC(JitGCLockHolder); 238 }; 239 240 private: 241 void Compile(EcmaVM *vm, const CompileDecision &decision); 242 static void Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier, 243 int32_t offset, JitCompileMode mode); 244 void CreateJitResources(); 245 bool IsLibResourcesResolved() const; 246 bool initialized_ { false }; 247 bool fastJitEnable_ { false }; 248 bool baselineJitEnable_ { false }; 249 bool isApp_ { false }; 250 bool isProfileNeedDump_ { true }; 251 uint32_t hotnessThreshold_ { 0 }; 252 std::string bundleName_; 253 254 std::unordered_map<JSThread*, ThreadTaskInfo> threadTaskInfo_; 255 RecursiveMutex threadTaskInfoLock_; 256 bool isEnableJitFort_ { true }; 257 bool isDisableCodeSign_ { true }; 258 bool isEnableAsyncCopyToFort_ { true }; 259 260 Mutex setEnableLock_; 261 262 JitDfx *jitDfx_ { nullptr }; 263 std::unique_ptr<JitResources> jitResources_; 264 static constexpr int MIN_CODE_SPACE_SIZE = 1_KB; 265 }; 266 } // namespace panda::ecmascript 267 #endif // ECMASCRIPT_JIT_H 268