• 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 #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