• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/jit/jit.h"
17 #include "ecmascript/jit/jit_task.h"
18 #include "ecmascript/dfx/vmstat/jit_warmup_profiler.h"
19 #include "ecmascript/ohos/jit_tools.h"
20 #include "ecmascript/checkpoint/thread_state_transition.h"
21 
22 namespace panda::ecmascript {
23 
GetInstance()24 Jit *Jit::GetInstance()
25 {
26     static Jit instance_;
27     return &instance_;
28 }
29 
CreateJitResources()30 void Jit::CreateJitResources()
31 {
32     if (jitResources_ == nullptr) {
33         jitResources_ = std::make_unique<JitResources>();
34         jitResources_->ResolveLib();
35     }
36 }
37 
IsLibResourcesResolved() const38 bool Jit::IsLibResourcesResolved() const
39 {
40     if (jitResources_ != nullptr) {
41         return jitResources_->IsLibResolved();
42     }
43     return false;
44 }
45 
PreFork()46 void Jit::PreFork()
47 {
48     CreateJitResources();
49 }
50 
SetJitEnablePostFork(EcmaVM * vm,const std::string & bundleName)51 void Jit::SetJitEnablePostFork(EcmaVM *vm, const std::string &bundleName)
52 {
53     JSRuntimeOptions &options = vm->GetJSOptions();
54     bool jitEnable = ohos::JitTools::GetJitEscapeDisable() || !AotCrashInfo::IsJitEscape();
55     jitEnable &= ohos::EnableAotJitListHelper::GetInstance()->IsEnableJit(bundleName);
56     jitEnable &= !vm->GetJSOptions().GetAOTHasException();
57     jitEnable &= ohos::JitTools::IsSupportJitCodeSigner();
58     if (jitEnable) {
59         bool isEnableFastJit = options.IsEnableJIT() && options.GetEnableAsmInterpreter();
60         bool isEnableBaselineJit = options.IsEnableBaselineJIT() && options.GetEnableAsmInterpreter();
61 
62         options.SetEnableJitFrame(ohos::JitTools::GetJitFrameEnable());
63         options.SetEnableAPPJIT(true);
64         isApp_ = true;
65         // for app threshold
66         uint32_t defaultSize = 150;
67         uint32_t threshold = ohos::JitTools::GetJitHotnessThreshold(defaultSize);
68         options.SetJitHotnessThreshold(threshold);
69         hotnessThreshold_ = threshold;
70         bundleName_ = bundleName;
71 
72         SetEnableOrDisable(options, isEnableFastJit, isEnableBaselineJit);
73         if (fastJitEnable_ || baselineJitEnable_) {
74             ConfigJit(vm);
75         }
76     }
77 }
78 
SwitchProfileStubs(EcmaVM * vm)79 void Jit::SwitchProfileStubs(EcmaVM *vm)
80 {
81     JSThread *thread = vm->GetAssociatedJSThread();
82     JSRuntimeOptions &options = vm->GetJSOptions();
83     std::shared_ptr<PGOProfiler> pgoProfiler = vm->GetPGOProfiler();
84     if (!options.IsEnableJITPGO() || pgoProfiler == nullptr) {
85         thread->SwitchJitProfileStubs(false);
86     } else {
87         // if not enable aot pgo
88         if (!pgo::PGOProfilerManager::GetInstance()->IsEnable()) {
89             // disable dump
90             options.SetEnableProfileDump(false);
91             SetProfileNeedDump(false);
92             // enable profiler
93             options.SetEnablePGOProfiler(true);
94             pgoProfiler->Reset(true);
95             // switch pgo stub
96             thread->SwitchJitProfileStubs(true);
97         }
98         pgoProfiler->InitJITProfiler();
99     }
100 }
101 
ConfigOptions(EcmaVM * vm) const102 void Jit::ConfigOptions(EcmaVM *vm) const
103 {
104     JSRuntimeOptions &options = vm->GetJSOptions();
105 
106     options.SetEnableAPPJIT(isApp_);
107     options.SetEnableProfileDump(isProfileNeedDump_);
108 
109     bool jitEnableLitecg = ohos::JitTools::IsJitEnableLitecg(options.IsCompilerEnableLiteCG());
110     options.SetCompilerEnableLiteCG(jitEnableLitecg);
111 
112     uint16_t jitCallThreshold = ohos::JitTools::GetJitCallThreshold(options.GetJitCallThreshold());
113     options.SetJitCallThreshold(jitCallThreshold);
114 
115     uint32_t jitHotnessThreshold = GetHotnessThreshold();
116     options.SetJitHotnessThreshold(jitHotnessThreshold);
117 
118     bool jitDisableCodeSign = ohos::JitTools::GetCodeSignDisable(options.GetDisableCodeSign());
119     options.SetDisableCodeSign(jitDisableCodeSign);
120 
121     bool jitEnableJitFort = ohos::JitTools::GetEnableJitFort(options.GetEnableJitFort());
122     options.SetEnableJitFort(jitEnableJitFort);
123 
124     bool jitEnableVerifyPass = ohos::JitTools::GetEnableJitVerifyPass(options.IsEnableJitVerifyPass());
125     options.SetEnableJitVerifyPass(jitEnableVerifyPass);
126 
127     bool jitEnableAsyncCopyToFort = ohos::JitTools::GetEnableAsyncCopyToFort(options.GetEnableAsyncCopyToFort());
128     options.SetEnableAsyncCopyToFort(jitEnableAsyncCopyToFort);
129 
130     vm->SetEnableJitLogSkip(ohos::JitTools::GetSkipJitLogEnable());
131 
132     LOG_JIT(INFO) << "enable jit bundle:" << bundleName_ <<
133         ", litecg:" << jitEnableLitecg <<
134         ", call threshold:" << static_cast<int>(jitCallThreshold) <<
135         ", hotness threshold:" << jitHotnessThreshold <<
136         ", disable codesigner:" << jitDisableCodeSign;
137 }
138 
ConfigJit(EcmaVM * vm)139 void Jit::ConfigJit(EcmaVM *vm)
140 {
141     SwitchProfileStubs(vm);
142     ConfigOptions(vm);
143     ConfigJitFortOptions(vm);
144 }
145 
ConfigJitFortOptions(EcmaVM * vm)146 void Jit::ConfigJitFortOptions(EcmaVM *vm)
147 {
148     SetDisableCodeSign(vm->GetJSOptions().GetDisableCodeSign());
149     SetEnableJitFort(vm->GetJSOptions().GetEnableJitFort());
150     SetEnableAsyncCopyToFort(vm->GetJSOptions().GetEnableAsyncCopyToFort());
151 }
152 
SetEnableOrDisable(const JSRuntimeOptions & options,bool isEnableFastJit,bool isEnableBaselineJit)153 void Jit::SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJit, bool isEnableBaselineJit)
154 {
155     LockHolder holder(setEnableLock_);
156     bool enableJit = isEnableFastJit || isEnableBaselineJit;
157     if (enableJit) {
158         CreateJitResources();
159     }
160 
161     if (IsLibResourcesResolved()) {
162         jitDfx_ = JitDfx::GetInstance();
163         jitDfx_->Init(options, bundleName_);
164         jitResources_->InitJitEnv(options);
165         initialized_ = true;
166     }
167 
168     if (initialized_) {
169         fastJitEnable_ = isEnableFastJit;
170         baselineJitEnable_ = isEnableBaselineJit;
171         hotnessThreshold_ = options.GetJitHotnessThreshold();
172     }
173 }
174 
Destroy()175 void Jit::Destroy()
176 {
177     LockHolder holder(setEnableLock_);
178     if (!initialized_) {
179         return;
180     }
181 
182     initialized_ = false;
183     fastJitEnable_ = false;
184     baselineJitEnable_ = false;
185     ASSERT(jitResources_ != nullptr);
186     jitResources_->Destroy();
187     jitResources_ = nullptr;
188 }
189 
IsEnableFastJit() const190 bool Jit::IsEnableFastJit() const
191 {
192     return fastJitEnable_;
193 }
194 
IsEnableBaselineJit() const195 bool Jit::IsEnableBaselineJit() const
196 {
197     return baselineJitEnable_;
198 }
199 
IsEnableJitFort() const200 bool Jit::IsEnableJitFort() const
201 {
202     return isEnableJitFort_;
203 }
204 
SetEnableJitFort(bool isEnableJitFort)205 void Jit::SetEnableJitFort(bool isEnableJitFort)
206 {
207     isEnableJitFort_ = isEnableJitFort;
208 }
209 
IsDisableCodeSign() const210 bool Jit::IsDisableCodeSign() const
211 {
212     return isDisableCodeSign_;
213 }
214 
SetDisableCodeSign(bool isDisableCodeSign)215 void Jit::SetDisableCodeSign(bool isDisableCodeSign)
216 {
217     isDisableCodeSign_ = isDisableCodeSign;
218 }
219 
IsEnableAsyncCopyToFort() const220 bool Jit::IsEnableAsyncCopyToFort() const
221 {
222     return isEnableAsyncCopyToFort_;
223 }
224 
SetEnableAsyncCopyToFort(bool isEnableAsyncCopyToFort)225 void Jit::SetEnableAsyncCopyToFort(bool isEnableAsyncCopyToFort)
226 {
227     isEnableAsyncCopyToFort_ = isEnableAsyncCopyToFort;
228 }
229 
~Jit()230 Jit::~Jit()
231 {
232 }
233 
CountInterpExecFuncs(JSHandle<JSFunction> & jsFunction)234 void Jit::CountInterpExecFuncs(JSHandle<JSFunction> &jsFunction)
235 {
236     Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
237     auto jSPandaFile = method->GetJSPandaFile();
238     ASSERT(jSPandaFile != nullptr);
239     CString fileDesc = jSPandaFile->GetJSPandaFileDesc();
240     CString methodInfo = fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName());
241     auto &profMap = JitWarmupProfiler::GetInstance()->profMap_;
242     if (profMap.find(methodInfo) == profMap.end()) {
243         profMap.insert({methodInfo, false});
244     }
245 }
246 
Compile(EcmaVM * vm,JSHandle<JSFunction> & jsFunction,CompilerTier tier,int32_t osrOffset,JitCompileMode mode)247 void Jit::Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier,
248                   int32_t osrOffset, JitCompileMode mode)
249 {
250     auto jit = Jit::GetInstance();
251     if ((!jit->IsEnableBaselineJit() && tier.IsBaseLine()) ||
252         (!jit->IsEnableFastJit() && tier.IsFast())) {
253         return;
254     }
255 
256     if (!vm->IsEnableOsr() && osrOffset != MachineCode::INVALID_OSR_OFFSET) {
257         return;
258     }
259 
260     CompileDecision compileDecision(vm, jsFunction, tier, osrOffset, mode);
261     if (!compileDecision.Decision()) {
262         return;
263     }
264 
265     jit->Compile(vm, compileDecision);
266 }
267 
Compile(EcmaVM * vm,const CompileDecision & decision)268 void Jit::Compile(EcmaVM *vm, const CompileDecision &decision)
269 {
270     auto tier = decision.GetTier();
271     auto jsFunction = decision.GetJsFunction();
272     auto methodInfo = decision.GetMethodInfo();
273     auto methodName = decision.GetMethodName();
274     auto osrOffset = decision.GetOsrOffset();
275     auto mode = decision.GetCompileMode();
276 
277     CString msg = "compile method:" + methodInfo + ", in work thread";
278     TimeScope scope(vm, msg, tier, true, true);
279 
280     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, ConvertToStdString("JIT::Compile:" + methodInfo));
281     if (tier.IsFast()) {
282         jsFunction->SetJitCompilingFlag(true);
283     } else {
284         ASSERT(tier.IsBaseLine());
285         jsFunction->SetBaselinejitCompilingFlag(true);
286     }
287     GetJitDfx()->SetTriggerCount(tier);
288 
289     {
290         JitTaskpool::GetCurrentTaskpool()->WaitForJitTaskPoolReady();
291         EcmaVM *compilerVm = JitTaskpool::GetCurrentTaskpool()->GetCompilerVm();
292         std::shared_ptr<JitTask> jitTask = std::make_shared<JitTask>(vm->GetJSThread(),
293             // avoid check fail when enable multi-thread check
294             compilerVm->GetJSThreadNoCheck(), this, jsFunction, tier, methodName, osrOffset, mode);
295 
296         jitTask->PrepareCompile();
297         JitTaskpool::GetCurrentTaskpool()->PostTask(
298             std::make_unique<JitTask::AsyncTask>(jitTask, vm->GetJSThread()->GetThreadId()));
299         if (mode.IsSync()) {
300             // sync mode, also compile in taskpool as litecg unsupport parallel compile,
301             // wait task compile finish then install code
302             jitTask->WaitFinish();
303             jitTask->InstallCode();
304         }
305         int spendTime = scope.TotalSpentTimeInMicroseconds();
306         jitTask->SetMainThreadCompilerTime(spendTime);
307         GetJitDfx()->RecordSpentTimeAndPrintStatsLogInJsThread(spendTime);
308     }
309 }
310 
RequestInstallCode(std::shared_ptr<JitTask> jitTask)311 void Jit::RequestInstallCode(std::shared_ptr<JitTask> jitTask)
312 {
313     LockHolder holder(threadTaskInfoLock_);
314     ThreadTaskInfo &info = threadTaskInfo_[jitTask->GetHostThread()];
315     if (info.skipInstallTask_) {
316         return;
317     }
318     info.installJitTasks_.push_back(jitTask);
319 
320     // set
321     jitTask->GetHostThread()->SetInstallMachineCode(true);
322     jitTask->GetHostThread()->SetCheckSafePointStatus();
323 }
324 
GetRunningTaskCnt(EcmaVM * vm)325 uint32_t Jit::GetRunningTaskCnt(EcmaVM *vm)
326 {
327     LockHolder holder(threadTaskInfoLock_);
328     ThreadTaskInfo &info = threadTaskInfo_[vm->GetJSThread()];
329     return info.jitTaskCnt_.load();
330 }
331 
InstallTasks(JSThread * jsThread)332 void Jit::InstallTasks(JSThread *jsThread)
333 {
334     std::deque<std::shared_ptr<JitTask>> taskQueue;
335     {
336         LockHolder holder(threadTaskInfoLock_);
337         ThreadTaskInfo &info = threadTaskInfo_[jsThread];
338         taskQueue = info.installJitTasks_;
339         info.installJitTasks_.clear();
340     }
341     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, ConvertToStdString("Jit::InstallTasks count:" + ToCString(taskQueue.size())));
342 
343     for (auto it = taskQueue.begin(); it != taskQueue.end(); it++) {
344         std::shared_ptr<JitTask> task = *it;
345         // check task state
346         task->InstallCode();
347     }
348 }
349 
JitCompile(void * compiler,JitTask * jitTask)350 bool Jit::JitCompile(void *compiler, JitTask *jitTask)
351 {
352     return jitResources_->Compile(compiler, jitTask);
353 }
354 
JitFinalize(void * compiler,JitTask * jitTask)355 bool Jit::JitFinalize(void *compiler, JitTask *jitTask)
356 {
357     return jitResources_->Finalize(compiler, jitTask);
358 }
359 
CreateJitCompilerTask(JitTask * jitTask)360 void *Jit::CreateJitCompilerTask(JitTask *jitTask)
361 {
362     return jitResources_->CreateJitCompilerTask(jitTask);
363 }
364 
DeleteJitCompilerTask(void * compiler)365 void Jit::DeleteJitCompilerTask(void *compiler)
366 {
367     jitResources_->DeleteJitCompilerTask(compiler);
368 }
369 
ClearTask(const std::function<bool (Task * task)> & checkClear)370 void Jit::ClearTask(const std::function<bool(Task *task)> &checkClear)
371 {
372     JitTaskpool::GetCurrentTaskpool()->ForEachTask([&checkClear](Task *task) {
373         JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
374         if (checkClear(asyncTask)) {
375             asyncTask->Terminated();
376         }
377     });
378 }
379 
ClearTask(EcmaContext * ecmaContext)380 void Jit::ClearTask(EcmaContext *ecmaContext)
381 {
382     ClearTask([ecmaContext](Task *task) {
383         JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
384         return ecmaContext == asyncTask->GetEcmaContext();
385     });
386 }
387 
ClearTaskWithVm(EcmaVM * vm)388 void Jit::ClearTaskWithVm(EcmaVM *vm)
389 {
390     ClearTask([vm](Task *task) {
391         JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
392         return vm == asyncTask->GetHostVM();
393     });
394 
395     {
396         LockHolder holder(threadTaskInfoLock_);
397         ThreadTaskInfo &info = threadTaskInfo_[vm->GetJSThread()];
398         info.skipInstallTask_ = true;
399         auto &taskQueue = info.installJitTasks_;
400         taskQueue.clear();
401 
402         if (info.jitTaskCnt_.load() != 0) {
403             ThreadNativeScope threadNativeScope(vm->GetJSThread());
404             info.jitTaskCntCv_.Wait(&threadTaskInfoLock_);
405         }
406     }
407 }
408 
IncJitTaskCnt(JSThread * thread)409 void Jit::IncJitTaskCnt(JSThread *thread)
410 {
411     LockHolder holder(threadTaskInfoLock_);
412     ThreadTaskInfo &info = threadTaskInfo_[thread];
413     info.jitTaskCnt_.fetch_add(1);
414 }
415 
DecJitTaskCnt(JSThread * thread)416 void Jit::DecJitTaskCnt(JSThread *thread)
417 {
418     LockHolder holder(threadTaskInfoLock_);
419     ThreadTaskInfo &info = threadTaskInfo_[thread];
420     uint32_t old = info.jitTaskCnt_.fetch_sub(1);
421     if (old == 1) {
422         info.jitTaskCntCv_.Signal();
423     }
424 }
425 
CheckMechineCodeSpaceMemory(JSThread * thread,int remainSize)426 void Jit::CheckMechineCodeSpaceMemory(JSThread *thread, int remainSize)
427 {
428     if (!thread->IsMachineCodeLowMemory()) {
429         return;
430     }
431     if (remainSize > MIN_CODE_SPACE_SIZE) {
432         thread->SetMachineCodeLowMemory(false);
433     }
434 }
435 
ChangeTaskPoolState(bool inBackground)436 void Jit::ChangeTaskPoolState(bool inBackground)
437 {
438     if (fastJitEnable_ || baselineJitEnable_) {
439         if (inBackground) {
440             JitTaskpool::GetCurrentTaskpool()->SetThreadPriority(PriorityMode::BACKGROUND);
441         } else {
442             JitTaskpool::GetCurrentTaskpool()->SetThreadPriority(PriorityMode::FOREGROUND);
443         }
444     }
445 }
446 
~TimeScope()447 Jit::TimeScope::~TimeScope()
448 {
449     if (!outPutLog_) {
450         return;
451     }
452     if (isDebugLevel_) {
453         LOG_JIT(DEBUG) << tier_ << message_ << ": " << TotalSpentTime() << "ms";
454     } else {
455         auto bundleName = vm_->GetBundleName();
456         if (vm_->GetEnableJitLogSkip() && bundleName != "" && message_.find(bundleName) == std::string::npos) {
457             return;
458         }
459         LOG_JIT(INFO) << tier_ << message_ << ", compile time: " << TotalSpentTime() << "ms";
460     }
461 }
462 }  // namespace panda::ecmascript
463