• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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