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(Task *task)> &checkClear); 84 void ClearTask(EcmaContext *ecmaContext); 85 void ClearTaskWithVm(EcmaVM *vm); 86 void Destroy(); 87 uint32_t GetRunningTaskCnt(EcmaVM *vm); 88 void CheckMechineCodeSpaceMemory(JSThread *thread, int remainSize); 89 void ChangeTaskPoolState(bool inBackground); 90 91 // dfx for jit warmup compile 92 static void CountInterpExecFuncs(JSHandle<JSFunction> &jsFunction); 93 IsAppJit()94 bool IsAppJit() const 95 { 96 return isApp_; 97 } 98 GetHotnessThreshold()99 uint32_t GetHotnessThreshold() const 100 { 101 return hotnessThreshold_; 102 } 103 SetProfileNeedDump(bool isNeed)104 void SetProfileNeedDump(bool isNeed) 105 { 106 isProfileNeedDump_ = isNeed; 107 } 108 IsProfileNeedDump()109 bool IsProfileNeedDump() const 110 { 111 return isProfileNeedDump_; 112 } 113 GetJitDfx()114 JitDfx *GetJitDfx() const 115 { 116 return jitDfx_; 117 } 118 119 void IncJitTaskCnt(JSThread *thread); 120 void DecJitTaskCnt(JSThread *thread); 121 122 NO_COPY_SEMANTIC(Jit); 123 NO_MOVE_SEMANTIC(Jit); 124 125 class TimeScope : public ClockScope { 126 public: 127 explicit TimeScope(EcmaVM *vm, CString message, CompilerTier tier, bool outPutLog = true, 128 bool isDebugLevel = false) vm_(vm)129 : vm_(vm), message_(message), tier_(tier), outPutLog_(outPutLog), isDebugLevel_(isDebugLevel) {} TimeScope(EcmaVM * vm)130 explicit TimeScope(EcmaVM *vm) 131 : vm_(vm), message_(""), tier_(CompilerTier::Tier::FAST), outPutLog_(false), isDebugLevel_(true) {} 132 PUBLIC_API ~TimeScope(); 133 appendMessage(const CString & value)134 void appendMessage(const CString& value) { message_ += value; } 135 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::Tier::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 void Compile(EcmaVM *vm, const CompileDecision &decision); 233 static void Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier, 234 int32_t offset, JitCompileMode mode); 235 void CreateJitResources(); 236 bool IsLibResourcesResolved() const; 237 bool initialized_ { false }; 238 bool fastJitEnable_ { false }; 239 bool baselineJitEnable_ { false }; 240 bool isApp_ { false }; 241 bool isProfileNeedDump_ { true }; 242 uint32_t hotnessThreshold_ { 0 }; 243 std::string bundleName_; 244 245 std::unordered_map<JSThread*, ThreadTaskInfo> threadTaskInfo_; 246 RecursiveMutex threadTaskInfoLock_; 247 bool isEnableJitFort_ { true }; 248 bool isDisableCodeSign_ { true }; 249 bool isEnableAsyncCopyToFort_ { true }; 250 251 Mutex setEnableLock_; 252 253 JitDfx *jitDfx_ { nullptr }; 254 std::unique_ptr<JitResources> jitResources_; 255 static constexpr int MIN_CODE_SPACE_SIZE = 1_KB; 256 }; 257 } // namespace panda::ecmascript 258 #endif // ECMASCRIPT_JIT_H 259