1 /*
2  * Copyright (c) 2023-2024 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_TASK_H
17 #define ECMASCRIPT_JIT_TASK_H
18 
19 #include "ecmascript/common.h"
20 #include "ecmascript/platform/mutex.h"
21 #include "ecmascript/ecma_vm.h"
22 
23 #include "ecmascript/ic/profile_type_info.h"
24 #include "ecmascript/jit/jit.h"
25 #include "ecmascript/jit/jit_thread.h"
26 #include "ecmascript/sustaining_js_handle.h"
27 
28 namespace panda::ecmascript {
29 enum CompileState : uint8_t {
30     SUCCESS = 0,
31     FAIL,
32 };
33 
34 enum RunState : uint8_t {
35     INIT = 0,
36     RUNNING,
37     FINISH
38 };
39 
40 class JitTaskpool : public Taskpool {
41 public:
42     PUBLIC_API static JitTaskpool *GetCurrentTaskpool();
43     JitTaskpool() = default;
44     NO_COPY_SEMANTIC(JitTaskpool);
45     NO_MOVE_SEMANTIC(JitTaskpool);
46 
GetCompilerVm()47     EcmaVM *GetCompilerVm()
48     {
49         return compilerVm_;
50     }
51 
SetCompilerVm(EcmaVM *vm)52     void SetCompilerVm(EcmaVM *vm)
53     {
54         LockHolder lock(jitTaskPoolMutex_);
55         compilerVm_ = vm;
56         threadId_ = static_cast<int32_t>(compilerVm_->GetJSThread()->GetThreadId());
57         jitTaskPoolCV_.SignalAll();
58     }
59 
WaitForJitTaskPoolReady()60     void WaitForJitTaskPoolReady()
61     {
62         LockHolder lock(jitTaskPoolMutex_);
63         if (compilerVm_ == nullptr) {
64             jitTaskPoolCV_.Wait(&jitTaskPoolMutex_);
65         }
66     }
67 
Initialize(bool needInitJitFort)68     void Initialize(bool needInitJitFort)
69     {
70         Taskpool::Initialize(0, [needInitJitFort](os::thread::native_handle_type thread) {
71             os::thread::SetThreadName(thread, "OS_JIT_Thread");
72             constexpr int32_t priorityVal = 5; // 5: The priority can be set within range [-20, 19]
73             os::thread::SetPriority(os::thread::GetCurrentThreadId(), priorityVal);
74             auto jitVm = JitVM::Create();
75             JitTaskpool::GetCurrentTaskpool()->SetCompilerVm(jitVm);
76             if (needInitJitFort) {
77                 JitFort::InitJitFortResource();
78             }
79         }, []([[maybe_unused]] os::thread::native_handle_type thread) {
80             EcmaVM *compilerVm = JitTaskpool::GetCurrentTaskpool()->GetCompilerVm();
81             JitVM::Destroy(compilerVm);
82         });
83     }
84 
Destroy()85     void Destroy()
86     {
87         Taskpool::Destroy(threadId_);
88     }
89 
90 private:
91     uint32_t TheMostSuitableThreadNum(uint32_t threadNum) const override;
92     EcmaVM *compilerVm_ { nullptr };
93     Mutex jitTaskPoolMutex_;
94     ConditionVariable jitTaskPoolCV_;
95     int32_t threadId_ { -1 };
96 };
97 
98 class JitTask {
99 public:
100     JitTask(JSThread *hostThread, JSThread *compilerThread, Jit *jit,
101         JSHandle<JSFunction> &jsFunction, CompilerTier tier, CString &methodName, int32_t offset,
102         uint32_t taskThreadId, JitCompileMode mode);
103     // for ut
104     JitTask(EcmaVM *hVm, EcmaVM *cVm, Jit *jit, uint32_t taskThreadId, JitCompileMode mode);
105     ~JitTask();
106     void Optimize();
107     void Finalize();
108     void PrepareCompile();
109 
110     void InstallCode();
111     void InstallOsrCode(JSHandle<MachineCode> &codeObj);
112     void InstallCodeByCompilerTier(JSHandle<MachineCode> &machineCode,
113         JSHandle<Method> &methodHandle);
GetMachineCodeDesc()114     MachineCodeDesc &GetMachineCodeDesc()
115     {
116         return codeDesc_;
117     }
118 
GetJsFunction() const119     JSHandle<JSFunction> GetJsFunction() const
120     {
121         return jsFunction_;
122     }
123 
GetOffset() const124     int32_t GetOffset() const
125     {
126         return offset_;
127     }
128 
GetProfileTypeInfo() const129     JSHandle<ProfileTypeInfo> GetProfileTypeInfo() const
130     {
131         return profileTypeInfo_;
132     }
133 
IsCompileSuccess() const134     bool IsCompileSuccess() const
135     {
136         return state_ == CompileState::SUCCESS;
137     }
138 
SetCompileFailed()139     void SetCompileFailed()
140     {
141         state_ = CompileState::FAIL;
142     }
143 
IsOsrTask()144     bool IsOsrTask()
145     {
146         return offset_ != MachineCode::INVALID_OSR_OFFSET;
147     }
148 
GetCompilerTier() const149     CompilerTier GetCompilerTier() const
150     {
151         return compilerTier_;
152     }
153 
GetJit()154     Jit *GetJit()
155     {
156         return jit_;
157     }
158 
GetHostThread()159     JSThread *GetHostThread()
160     {
161         return hostThread_;
162     }
163 
GetHostVM()164     EcmaVM *GetHostVM()
165     {
166         return hostThread_->GetEcmaVM();
167     }
168 
GetCompilerThread()169     JSThread *GetCompilerThread()
170     {
171         return compilerThread_;
172     }
173 
GetCompilerVM()174     JitVM *GetCompilerVM()
175     {
176         return static_cast<JitVM*>(compilerThread_->GetEcmaVM());
177     }
178 
GetMethodName() const179     CString GetMethodName() const
180     {
181         return methodName_;
182     }
183 
SetMethodInfo(CString methodName)184     void SetMethodInfo(CString methodName)
185     {
186         methodName_ = methodName;
187     }
188 
GetTaskThreadId() const189     uint32_t GetTaskThreadId() const
190     {
191         return taskThreadId_;
192     }
193 
GetEcmaContext() const194     EcmaContext *GetEcmaContext() const
195     {
196         return ecmaContext_;
197     }
198 
SetRunState(RunState s)199     void SetRunState(RunState s)
200     {
201         runState_.store(s, std::memory_order_release);
202     }
203 
SetRunStateFinish()204     void SetRunStateFinish()
205     {
206         LockHolder lock(runStateMutex_);
207         runState_.store(RunState::FINISH);
208         runStateCondition_.SignalAll();
209     }
210 
IsFinish() const211     bool IsFinish() const
212     {
213         return runState_.load(std::memory_order_acquire) == RunState::FINISH;
214     }
IsRunning() const215     bool IsRunning() const
216     {
217         return runState_.load(std::memory_order_acquire) == RunState::RUNNING;
218     }
219     void WaitFinish();
IsAsyncTask() const220     bool IsAsyncTask() const
221     {
222         return jitCompileMode_ == JitCompileMode::ASYNC;
223     }
224 
SetMainThreadCompilerTime(int time)225     void SetMainThreadCompilerTime(int time)
226     {
227         mainThreadCompileTime_ = time;
228     }
229 
GetMainThreadCompilerTime() const230     int GetMainThreadCompilerTime() const
231     {
232         return mainThreadCompileTime_;
233     }
234     static size_t PUBLIC_API ComputePayLoadSize(MachineCodeDesc &codeDesc);
235 
236     class AsyncTask : public Task {
237     public:
AsyncTask(std::shared_ptr<JitTask>jitTask, int32_t id)238         explicit AsyncTask(std::shared_ptr<JitTask>jitTask, int32_t id) : Task(id), jitTask_(jitTask) { }
239         virtual ~AsyncTask() override = default;
240 
241         bool Run(uint32_t threadIndex) override;
GetEcmaContext() const242         EcmaContext *GetEcmaContext() const
243         {
244             return jitTask_->GetEcmaContext();
245         }
GetHostVM() const246         EcmaVM *GetHostVM() const
247         {
248             return jitTask_->GetHostThread()->GetEcmaVM();
249         }
IsRunning() const250         bool IsRunning() const
251         {
252             return jitTask_->IsRunning();
253         }
WaitFinish() const254         void WaitFinish() const
255         {
256             jitTask_->WaitFinish();
257         }
258 
Terminated()259         void Terminated()
260         {
261             Task::Terminated();
262         }
263 
ReleaseSustainingJSHandle()264         void ReleaseSustainingJSHandle()
265         {
266             jitTask_->ReleaseSustainingJSHandle();
267         }
268     private:
269         std::shared_ptr<JitTask> jitTask_ { nullptr };
270 
271         class AsyncTaskRunScope {
272         public:
273             AsyncTaskRunScope(JitTask *jitTask);
274             ~AsyncTaskRunScope();
275         private:
276             JitTask *jitTask_ { nullptr };
277             JitVM *jitvm_ { nullptr };
278         };
279     };
280 private:
281     void SustainingJSHandles();
282     void ReleaseSustainingJSHandle();
283     void CloneProfileTypeInfo();
SetJsFunction(JSHandle<JSFunction> &jsFunction)284     void SetJsFunction(JSHandle<JSFunction> &jsFunction)
285     {
286         jsFunction_ = jsFunction;
287     }
288 
SetProfileTypeInfo(JSHandle<ProfileTypeInfo> &profileTypeInfo)289     void SetProfileTypeInfo(JSHandle<ProfileTypeInfo> &profileTypeInfo)
290     {
291         profileTypeInfo_ = profileTypeInfo;
292     }
293 
294     JSThread *hostThread_;
295     JSThread *compilerThread_;
296     Jit *jit_;
297     JSHandle<JSFunction> jsFunction_;
298     JSHandle<ProfileTypeInfo> profileTypeInfo_;
299     void *compilerTask_;
300     MachineCodeDesc codeDesc_;
301     CompileState state_;
302     CompilerTier compilerTier_;
303     CString methodName_;
304     int32_t offset_;
305     uint32_t taskThreadId_;
306     std::unique_ptr<SustainingJSHandle> sustainingJSHandle_;
307     EcmaContext *ecmaContext_;
308     JitCompileMode jitCompileMode_;
309     JitDfx *jitDfx_ { nullptr };
310     int mainThreadCompileTime_ {0};
311 
312     std::atomic<RunState> runState_;
313     Mutex runStateMutex_;
314     ConditionVariable runStateCondition_;
315 };
316 }  // namespace panda::ecmascript
317 #endif  // ECMASCRIPT_JIT_TASK_H
318