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