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