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 #include "ecmascript/jit/jit.h"
17 #include "ecmascript/jit/jit_task.h"
18 #include "ecmascript/platform/mutex.h"
19 #include "ecmascript/platform/file.h"
20
21 namespace panda::ecmascript {
22 std::deque<JitTask*> Jit::asyncCompileJitTasks_;
23 Mutex Jit::asyncCompileJitTasksMtx_;
Initialize()24 void Jit::Initialize()
25 {
26 if (!vm_->IsEnableJit()) {
27 return;
28 }
29 static const std::string CREATEJITCOMPILE = "CreateJitCompiler";
30 static const std::string JITCOMPILE = "JitCompile";
31 static const std::string JITFINALIZE = "JitFinalize";
32 static const std::string DELETEJITCOMPILE = "DeleteJitCompile";
33 static const std::string LIBARK_JSOPTIMIZER = "libark_jsoptimizer.so";
34
35 libHandle_ = LoadLib(LIBARK_JSOPTIMIZER);
36 if (libHandle_ == nullptr) {
37 LOG_JIT(ERROR) << "jit dlopen libark_jsoptimizer.so failed";
38 return;
39 }
40
41 jitCompile_ = reinterpret_cast<bool(*)(void*, JitTask*)>(FindSymbol(libHandle_, JITCOMPILE.c_str()));
42 if (jitCompile_ == nullptr) {
43 LOG_JIT(ERROR) << "jit can't find symbol jitCompile";
44 return;
45 }
46
47 jitFinalize_ = reinterpret_cast<bool(*)(void*, JitTask*)>(FindSymbol(libHandle_, JITFINALIZE.c_str()));
48 if (jitFinalize_ == nullptr) {
49 LOG_JIT(ERROR) << "jit can't find symbol jitFinalize";
50 return;
51 }
52
53 createJitCompiler_ = reinterpret_cast<void*(*)(EcmaVM*, JitTask*)>(FindSymbol(libHandle_,
54 CREATEJITCOMPILE.c_str()));
55 if (createJitCompiler_ == nullptr) {
56 LOG_JIT(ERROR) << "jit can't find symbol createJitCompiler";
57 return;
58 }
59
60 deleteJitCompile_ = reinterpret_cast<void(*)(void*)>(FindSymbol(libHandle_, DELETEJITCOMPILE.c_str()));
61 if (createJitCompiler_ == nullptr) {
62 LOG_JIT(ERROR) << "jit can't find symbol deleteJitCompile";
63 return;
64 }
65 initialized_= true;
66 vm_->GetJSThread()->SwitchJitProfileStubsIfNeeded();
67 return;
68 }
69
~Jit()70 Jit::~Jit()
71 {
72 if (libHandle_ != nullptr) {
73 CloseLib(libHandle_);
74 libHandle_ = nullptr;
75 }
76 }
77
SupportJIT(Method * method)78 bool Jit::SupportJIT(Method *method)
79 {
80 FunctionKind kind = method->GetFunctionKind();
81 switch (kind) {
82 case FunctionKind::NORMAL_FUNCTION:
83 case FunctionKind::BASE_CONSTRUCTOR:
84 case FunctionKind::ARROW_FUNCTION:
85 return true;
86 default:
87 return false;
88 }
89 }
90
DeleteJitCompile(void * compiler)91 void Jit::DeleteJitCompile(void *compiler)
92 {
93 deleteJitCompile_(compiler);
94 }
95
Compile(EcmaVM * vm,JSHandle<JSFunction> & jsFunction,JitCompileMode mode)96 void Jit::Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, JitCompileMode mode)
97 {
98 if (!vm->IsEnableJit()) {
99 return;
100 }
101 auto jit = vm->GetJit();
102 if (!jit->IsInitialized()) {
103 return;
104 }
105
106 Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
107 CString fileDesc = method->GetJSPandaFile()->GetJSPandaFileDesc();
108 FunctionKind kind = method->GetFunctionKind();
109 CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName()) + ", at:" + fileDesc;
110 if (!jit->SupportJIT(method)) {
111 LOG_JIT(INFO) << "method does not support jit:" << methodName << ", kind:" << static_cast<int>(kind);
112 return;
113 }
114 if (method->GetMachineCode() != JSTaggedValue::Undefined()) {
115 LOG_JIT(DEBUG) << "skip method, as it has been jit compiled:" << methodName;
116 return;
117 }
118
119 if (jit->IsCompiling(jsFunction)) {
120 LOG_JIT(DEBUG) << "skip method, as it compiling:" << methodName;
121 return;
122 }
123
124 LOG_JIT(DEBUG) << "start compile:" << methodName << ", kind:" << static_cast<int>(kind) <<
125 ", mode:" << ((mode == SYNC) ? "sync" : "async");
126
127 {
128 CString msg = "compile method:" + methodName + ", in work thread";
129 Scope scope(msg);
130
131 ASSERT(jit->createJitCompiler_ != nullptr);
132 ASSERT(jit->deleteJitCompile_ != nullptr);
133
134 JitTask *jitTask = new JitTask(vm, jit, jsFunction);
135 jitTask->SetMethodInfo(methodName);
136 jit->AddCompilingTask(jitTask);
137
138 void *compiler = jit->createJitCompiler_(vm, jitTask);
139 jitTask->SetCompiler(compiler);
140
141 jitTask->Optimize();
142
143 if (mode == SYNC) {
144 // cg
145 jitTask->Finalize();
146 jitTask->InstallCode();
147 jit->RemoveCompilingTask(jitTask);
148 // free
149 delete jitTask;
150 } else {
151 jit->AddAsyncCompileTask(jitTask);
152 }
153 }
154 }
155
AddCompilingTask(JitTask * jitTask)156 void Jit::AddCompilingTask(JitTask *jitTask)
157 {
158 compilingJitTasks_.push_back(jitTask);
159 }
160
RemoveCompilingTask(JitTask * jitTask)161 void Jit::RemoveCompilingTask(JitTask *jitTask)
162 {
163 auto findIt = std::find(compilingJitTasks_.begin(), compilingJitTasks_.end(), jitTask);
164 ASSERT(findIt != compilingJitTasks_.end());
165 compilingJitTasks_.erase(findIt);
166 }
167
GetAsyncCompileTask()168 JitTask *Jit::GetAsyncCompileTask()
169 {
170 LockHolder holder(asyncCompileJitTasksMtx_);
171 if (asyncCompileJitTasks_.empty()) {
172 return nullptr;
173 } else {
174 auto jitTask = asyncCompileJitTasks_.front();
175 return jitTask;
176 }
177 }
178
AddAsyncCompileTask(JitTask * jitTask)179 void Jit::AddAsyncCompileTask(JitTask *jitTask)
180 {
181 LockHolder holder(asyncCompileJitTasksMtx_);
182 if (asyncCompileJitTasks_.empty()) {
183 Taskpool::GetCurrentTaskpool()->PostTask(
184 std::make_unique<JitTask::AsyncTask>(jitTask, vm_->GetJSThread()->GetThreadId()));
185 }
186 asyncCompileJitTasks_.push_back(jitTask);
187 }
188
RemoveAsyncCompileTask(JitTask * jitTask)189 void Jit::RemoveAsyncCompileTask([[maybe_unused]] JitTask *jitTask)
190 {
191 LockHolder holder(asyncCompileJitTasksMtx_);
192 ASSERT(!asyncCompileJitTasks_.empty());
193 ASSERT(asyncCompileJitTasks_.front() == jitTask);
194 asyncCompileJitTasks_.pop_front();
195 }
196
RequestInstallCode(JitTask * jitTask)197 void Jit::RequestInstallCode(JitTask *jitTask)
198 {
199 LockHolder holder(installJitTasksDequeMtx_);
200 installJitTasks_.push_back(jitTask);
201
202 // set
203 vm_->GetJSThread()->SetInstallMachineCode(true);
204 vm_->GetJSThread()->SetCheckSafePointStatus();
205 }
206
IsCompiling(JSHandle<JSFunction> & jsFunction)207 bool Jit::IsCompiling(JSHandle<JSFunction> &jsFunction)
208 {
209 Method *srcMethod = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
210 for (auto it = compilingJitTasks_.begin(); it != compilingJitTasks_.end(); it++) {
211 JitTask *task = *it;
212 Method *compilingMethod = Method::Cast(task->GetJsFunction()->GetMethod().GetTaggedObject());
213 if (srcMethod == compilingMethod) {
214 return true;
215 }
216 }
217 return false;
218 }
219
InstallTasksWithoutClearFlag()220 void Jit::InstallTasksWithoutClearFlag()
221 {
222 LockHolder holder(installJitTasksDequeMtx_);
223 for (auto it = installJitTasks_.begin(); it != installJitTasks_.end(); it++) {
224 JitTask *task = *it;
225 // check task state
226 task->InstallCode();
227 RemoveCompilingTask(task);
228 delete task;
229 }
230 installJitTasks_.clear();
231 }
232
InstallTasks()233 void Jit::InstallTasks()
234 {
235 InstallTasksWithoutClearFlag();
236 // clear flag
237 vm_->GetJSThread()->SetInstallMachineCode(false);
238 }
239
JitCompile(void * compiler,JitTask * jitTask)240 bool Jit::JitCompile(void *compiler, JitTask *jitTask)
241 {
242 ASSERT(jitCompile_ != nullptr);
243 return jitCompile_(compiler, jitTask);
244 }
245
JitFinalize(void * compiler,JitTask * jitTask)246 bool Jit::JitFinalize(void *compiler, JitTask *jitTask)
247 {
248 ASSERT(jitFinalize_ != nullptr);
249 return jitFinalize_(compiler, jitTask);
250 }
251
~Scope()252 Jit::Scope::~Scope()
253 {
254 LOG_JIT(INFO) << message_ << ": " << TotalSpentTime() << "ms";
255 }
256 } // namespace panda::ecmascript
257