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/ic/profile_type_info.h"
20 #include "ecmascript/ohos/jit_tools.h"
21 #include "ecmascript/js_tagged_value-inl.h"
22 #include "ecmascript/jspandafile/js_pandafile.h"
23
24 namespace panda::ecmascript {
25 void (*Jit::initJitCompiler_)(JSRuntimeOptions options) = nullptr;
26 bool(*Jit::jitCompile_)(void*, JitTask*) = nullptr;
27 bool(*Jit::jitFinalize_)(void*, JitTask*) = nullptr;
28 void*(*Jit::createJitCompilerTask_)(JitTask*) = nullptr;
29 void(*Jit::deleteJitCompile_)(void*) = nullptr;
30 void *Jit::libHandle_ = nullptr;
31
GetInstance()32 Jit *Jit::GetInstance()
33 {
34 static Jit instance_;
35 return &instance_;
36 }
37
SetJitEnablePostFork(EcmaVM * vm,const std::string & bundleName)38 void Jit::SetJitEnablePostFork(EcmaVM *vm, const std::string &bundleName)
39 {
40 JSRuntimeOptions &options = vm->GetJSOptions();
41 bool jitEnable = ohos::JitTools::GetJitEscapeDisable() || !AotCrashInfo::IsJitEscape();
42 jitEnable &= ohos::EnableAotJitListHelper::GetInstance()->IsEnableJit(bundleName);
43 jitEnable &= !vm->GetJSOptions().GetAOTHasException();
44 if (jitEnable) {
45 bool isEnableFastJit = options.IsEnableJIT() && options.GetEnableAsmInterpreter();
46 bool isEnableBaselineJit = options.IsEnableBaselineJIT() && options.GetEnableAsmInterpreter();
47
48 options.SetEnableJitFrame(ohos::JitTools::GetJitFrameEnable());
49 options.SetEnableAPPJIT(true);
50 // for app threshold
51 uint32_t defaultSize = 3000;
52 uint32_t threshold = ohos::JitTools::GetJitHotnessThreshold(defaultSize);
53 options.SetJitHotnessThreshold(threshold);
54 bundleName_ = bundleName;
55 isEnableAppPGO_ = pgo::PGOProfilerManager::GetInstance()->IsEnable();
56
57 SetEnableOrDisable(options, isEnableFastJit, isEnableBaselineJit);
58 if (fastJitEnable_ || baselineJitEnable_) {
59 ConfigJit(vm);
60 }
61 }
62 }
63
SwitchProfileStubs(EcmaVM * vm)64 void Jit::SwitchProfileStubs(EcmaVM *vm)
65 {
66 JSThread *thread = vm->GetAssociatedJSThread();
67 JSRuntimeOptions &options = vm->GetJSOptions();
68 std::shared_ptr<PGOProfiler> pgoProfiler = vm->GetPGOProfiler();
69 if (!options.IsEnableJITPGO() || pgoProfiler == nullptr || (isApp_ && !isEnableAppPGO_)) {
70 thread->SwitchJitProfileStubs(false);
71 options.SetEnableJITPGO(false);
72 } else {
73 // if not enable aot pgo
74 if (!pgo::PGOProfilerManager::GetInstance()->IsEnable()) {
75 // disable dump
76 options.SetEnableProfileDump(false);
77 SetProfileNeedDump(false);
78 // enable profiler
79 options.SetEnablePGOProfiler(true);
80 pgoProfiler->Reset(true);
81 // switch pgo stub
82 thread->SwitchJitProfileStubs(true);
83 }
84 pgoProfiler->InitJITProfiler();
85 }
86 }
87
ConfigOptions(EcmaVM * vm) const88 void Jit::ConfigOptions(EcmaVM *vm) const
89 {
90 JSRuntimeOptions &options = vm->GetJSOptions();
91
92 options.SetEnableAPPJIT(isApp_);
93 options.SetEnableProfileDump(isProfileNeedDump_);
94
95 bool jitEnableLitecg = ohos::JitTools::IsJitEnableLitecg(options.IsCompilerEnableLiteCG());
96 options.SetCompilerEnableLiteCG(jitEnableLitecg);
97
98 uint8_t jitCallThreshold = ohos::JitTools::GetJitCallThreshold(options.GetJitCallThreshold());
99 options.SetJitCallThreshold(jitCallThreshold);
100
101 uint32_t jitHotnessThreshold = GetHotnessThreshold();
102 options.SetJitHotnessThreshold(jitHotnessThreshold);
103
104 bool jitDisableCodeSign = ohos::JitTools::GetCodeSignDisable(options.GetDisableCodeSign());
105 options.SetDisableCodeSign(jitDisableCodeSign);
106
107 bool jitEnableJitFort = ohos::JitTools::GetEnableJitFort(options.GetEnableJitFort());
108 options.SetEnableJitFort(jitEnableJitFort);
109
110 bool jitEnableAsyncCopyToFort = ohos::JitTools::GetEnableAsyncCopyToFort(options.GetEnableAsyncCopyToFort());
111 options.SetEnableAsyncCopyToFort(jitEnableAsyncCopyToFort);
112
113 vm->SetEnableJitLogSkip(ohos::JitTools::GetSkipJitLogEnable());
114
115 LOG_JIT(INFO) << "enable jit bundle:" << bundleName_ <<
116 ", litecg:" << jitEnableLitecg <<
117 ", call threshold:" << static_cast<int>(jitCallThreshold) <<
118 ", hotness threshold:" << jitHotnessThreshold <<
119 ", disable codesigner:" << jitDisableCodeSign;
120 }
121
ConfigJit(EcmaVM * vm)122 void Jit::ConfigJit(EcmaVM *vm)
123 {
124 SwitchProfileStubs(vm);
125 ConfigOptions(vm);
126 ConfigJitFortOptions(vm);
127 }
128
ConfigJitFortOptions(EcmaVM * vm)129 void Jit::ConfigJitFortOptions(EcmaVM *vm)
130 {
131 SetDisableCodeSign(vm->GetJSOptions().GetDisableCodeSign());
132 SetEnableJitFort(vm->GetJSOptions().GetEnableJitFort());
133 SetEnableAsyncCopyToFort(vm->GetJSOptions().GetEnableAsyncCopyToFort());
134 }
135
SetEnableOrDisable(const JSRuntimeOptions & options,bool isEnableFastJit,bool isEnableBaselineJit)136 void Jit::SetEnableOrDisable(const JSRuntimeOptions &options, bool isEnableFastJit, bool isEnableBaselineJit)
137 {
138 LockHolder holder(setEnableLock_);
139
140 bool needInitialize = false;
141 if (!isEnableFastJit) {
142 fastJitEnable_ = false;
143 } else {
144 needInitialize = true;
145 }
146 if (!isEnableBaselineJit) {
147 baselineJitEnable_ = false;
148 } else {
149 needInitialize = true;
150 }
151 if (!needInitialize) {
152 return;
153 }
154 if (!initialized_) {
155 Initialize();
156 }
157 if (initialized_) {
158 bool jitEnable = false;
159 if (isEnableFastJit && !fastJitEnable_) {
160 fastJitEnable_ = true;
161 jitEnable = true;
162 }
163 if (isEnableBaselineJit && !baselineJitEnable_) {
164 baselineJitEnable_ = true;
165 jitEnable = true;
166 }
167 if (jitEnable) {
168 jitDfx_ = JitDfx::GetInstance();
169 jitDfx_->Init(options, bundleName_);
170
171 isApp_ = options.IsEnableAPPJIT();
172 hotnessThreshold_ = options.GetJitHotnessThreshold();
173 initJitCompiler_(options);
174 bool enableCodeSign = !ohos::JitTools::GetCodeSignDisable(options.GetDisableCodeSign());
175 bool shouldCompileMain =
176 options.IsEnableForceJitCompileMain() || options.IsEnableForceBaselineCompileMain();
177 if (enableCodeSign && shouldCompileMain) {
178 JitFort::InitJitFortResource();
179 }
180 JitTaskpool::GetCurrentTaskpool()->Initialize(enableCodeSign && !shouldCompileMain);
181 }
182 }
183 }
184
Destroy()185 void Jit::Destroy()
186 {
187 if (!initialized_) {
188 return;
189 }
190
191 LockHolder holder(setEnableLock_);
192
193 JitTaskpool::GetCurrentTaskpool()->Destroy();
194 initialized_ = false;
195 fastJitEnable_ = false;
196 baselineJitEnable_ = false;
197 if (libHandle_ != nullptr) {
198 CloseLib(libHandle_);
199 libHandle_ = nullptr;
200 }
201 }
202
IsEnableFastJit() const203 bool Jit::IsEnableFastJit() const
204 {
205 return fastJitEnable_;
206 }
207
IsEnableBaselineJit() const208 bool Jit::IsEnableBaselineJit() const
209 {
210 return baselineJitEnable_;
211 }
212
IsEnableJitFort() const213 bool Jit::IsEnableJitFort() const
214 {
215 return isEnableJitFort_;
216 }
217
SetEnableJitFort(bool isEnableJitFort)218 void Jit::SetEnableJitFort(bool isEnableJitFort)
219 {
220 isEnableJitFort_ = isEnableJitFort;
221 }
222
IsDisableCodeSign() const223 bool Jit::IsDisableCodeSign() const
224 {
225 return isDisableCodeSign_;
226 }
227
SetDisableCodeSign(bool isDisableCodeSign)228 void Jit::SetDisableCodeSign(bool isDisableCodeSign)
229 {
230 isDisableCodeSign_ = isDisableCodeSign;
231 }
232
IsEnableAsyncCopyToFort() const233 bool Jit::IsEnableAsyncCopyToFort() const
234 {
235 return isEnableAsyncCopyToFort_;
236 }
237
SetEnableAsyncCopyToFort(bool isEnableAsyncCopyToFort)238 void Jit::SetEnableAsyncCopyToFort(bool isEnableAsyncCopyToFort)
239 {
240 isEnableAsyncCopyToFort_ = isEnableAsyncCopyToFort;
241 }
242
Initialize()243 void Jit::Initialize()
244 {
245 static const std::string CREATEJITCOMPILETASK = "CreateJitCompilerTask";
246 static const std::string JITCOMPILEINIT = "InitJitCompiler";
247 static const std::string JITCOMPILE = "JitCompile";
248 static const std::string JITFINALIZE = "JitFinalize";
249 static const std::string DELETEJITCOMPILE = "DeleteJitCompile";
250 static const std::string LIBARK_JSOPTIMIZER = "libark_jsoptimizer.so";
251
252 libHandle_ = LoadLib(LIBARK_JSOPTIMIZER);
253 if (libHandle_ == nullptr) {
254 char *error = LoadLibError();
255 LOG_JIT(ERROR) << "jit dlopen libark_jsoptimizer.so failed, as:" <<
256 ((error == nullptr) ? "unknown error" : error);
257 return;
258 }
259
260 initJitCompiler_ = reinterpret_cast<void(*)(JSRuntimeOptions)>(FindSymbol(libHandle_, JITCOMPILEINIT.c_str()));
261 if (initJitCompiler_ == nullptr) {
262 LOG_JIT(ERROR) << "jit can't find symbol initJitCompiler";
263 return;
264 }
265 jitCompile_ = reinterpret_cast<bool(*)(void*, JitTask*)>(FindSymbol(libHandle_, JITCOMPILE.c_str()));
266 if (jitCompile_ == nullptr) {
267 LOG_JIT(ERROR) << "jit can't find symbol jitCompile";
268 return;
269 }
270
271 jitFinalize_ = reinterpret_cast<bool(*)(void*, JitTask*)>(FindSymbol(libHandle_, JITFINALIZE.c_str()));
272 if (jitFinalize_ == nullptr) {
273 LOG_JIT(ERROR) << "jit can't find symbol jitFinalize";
274 return;
275 }
276
277 createJitCompilerTask_ = reinterpret_cast<void*(*)(JitTask*)>(FindSymbol(libHandle_,
278 CREATEJITCOMPILETASK.c_str()));
279 if (createJitCompilerTask_ == nullptr) {
280 LOG_JIT(ERROR) << "jit can't find symbol createJitCompilertask";
281 return;
282 }
283
284 deleteJitCompile_ = reinterpret_cast<void(*)(void*)>(FindSymbol(libHandle_, DELETEJITCOMPILE.c_str()));
285 if (deleteJitCompile_ == nullptr) {
286 LOG_JIT(ERROR) << "jit can't find symbol deleteJitCompile";
287 return;
288 }
289 initialized_= true;
290 return;
291 }
292
~Jit()293 Jit::~Jit()
294 {
295 }
296
SupportJIT(JSHandle<JSFunction> & jsFunction,EcmaVM * vm,CompilerTier tier) const297 bool Jit::SupportJIT(JSHandle<JSFunction> &jsFunction, [[maybe_unused]] EcmaVM *vm, CompilerTier tier) const
298 {
299 Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
300 if (jsFunction.GetTaggedValue().IsJSSharedFunction()) {
301 LOG_JIT(DEBUG) << "method does not support compile shared function:" <<
302 method->GetRecordNameStr() + "." + method->GetMethodName();
303 return false;
304 }
305
306 FunctionKind kind = method->GetFunctionKind();
307 switch (kind) {
308 case FunctionKind::NORMAL_FUNCTION:
309 case FunctionKind::GETTER_FUNCTION:
310 case FunctionKind::SETTER_FUNCTION:
311 case FunctionKind::ARROW_FUNCTION:
312 case FunctionKind::BASE_CONSTRUCTOR:
313 case FunctionKind::CLASS_CONSTRUCTOR:
314 case FunctionKind::DERIVED_CONSTRUCTOR:
315 case FunctionKind::NONE_FUNCTION:
316 return true;
317 default:
318 break;
319 }
320 std::stringstream msgStr;
321 msgStr << "method does not support jit:" << method->GetRecordNameStr() + "." + method->GetMethodName() <<
322 ", kind:" << static_cast<int>(kind);
323 if (tier == CompilerTier::BASELINE) {
324 LOG_BASELINEJIT(DEBUG) << msgStr.str();
325 } else {
326 LOG_JIT(DEBUG) << msgStr.str();
327 }
328 return false;
329 }
330
DeleteJitCompile(void * compiler)331 void Jit::DeleteJitCompile(void *compiler)
332 {
333 deleteJitCompile_(compiler);
334 }
335
CountInterpExecFuncs(JSHandle<JSFunction> & jsFunction)336 void Jit::CountInterpExecFuncs(JSHandle<JSFunction> &jsFunction)
337 {
338 Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
339 auto jSPandaFile = method->GetJSPandaFile();
340 ASSERT(jSPandaFile != nullptr);
341 CString fileDesc = jSPandaFile->GetJSPandaFileDesc();
342 CString methodInfo = fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName());
343 auto &profMap = JitWarmupProfiler::GetInstance()->profMap_;
344 if (profMap.find(methodInfo) == profMap.end()) {
345 profMap.insert({methodInfo, false});
346 }
347 }
348
349 // Used for jit machine code reusing of inner functions have the same method to improve performance.
ReuseCompiledFunc(JSThread * thread,JSHandle<JSFunction> & jsFunction)350 void Jit::ReuseCompiledFunc(JSThread *thread, JSHandle<JSFunction> &jsFunction)
351 {
352 JSHandle<ProfileTypeInfoCell> profCell(thread, jsFunction->GetRawProfileTypeInfo());
353 JSTaggedValue machineCode = profCell->GetMachineCode().GetWeakRawValue();
354 if (machineCode.IsHole()) {
355 return;
356 }
357
358 ProfileTypeInfo *profileTypeInfo = ProfileTypeInfo::Cast(profCell->GetValue().GetTaggedObject());
359 if (profileTypeInfo->GetJitHotnessThreshold() == ProfileTypeInfo::JIT_DISABLE_FLAG) {
360 // disable reuse as disable jit in deopt
361 return;
362 }
363 if (machineCode.IsUndefined()) {
364 LOG_JIT(DEBUG) << "reset fuction jit hotness count";
365 // if old gc triggered, jit hotness cnt need to be recounted
366 profileTypeInfo->SetJitHotnessCnt(0);
367 profCell->SetMachineCode(thread, JSTaggedValue::Hole());
368 return;
369 }
370 JSHandle<MachineCode> machineCodeHandle(thread, machineCode.GetTaggedObject());
371 JSHandle<Method> method(thread, Method::Cast(jsFunction->GetMethod().GetTaggedObject()));
372 uintptr_t codeAddr = machineCodeHandle->GetFuncAddr();
373 FuncEntryDes *funcEntryDes = reinterpret_cast<FuncEntryDes *>(machineCodeHandle->GetFuncEntryDes());
374 jsFunction->SetCompiledFuncEntry(codeAddr, funcEntryDes->isFastCall_);
375 jsFunction->SetMachineCode(thread, machineCodeHandle);
376 }
377
Compile(EcmaVM * vm,JSHandle<JSFunction> & jsFunction,CompilerTier tier,int32_t offset,JitCompileMode mode)378 void Jit::Compile(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier,
379 int32_t offset, JitCompileMode mode)
380 {
381 auto jit = Jit::GetInstance();
382 if ((!jit->IsEnableBaselineJit() && tier == CompilerTier::BASELINE) ||
383 (!jit->IsEnableFastJit() && tier == CompilerTier::FAST)) {
384 return;
385 }
386
387 if (!vm->IsEnableOsr() && offset != MachineCode::INVALID_OSR_OFFSET) {
388 return;
389 }
390
391 Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
392 auto jSPandaFile = method->GetJSPandaFile();
393 ASSERT(jSPandaFile != nullptr);
394 CString fileDesc = jSPandaFile->GetJSPandaFileDesc();
395 CString methodName = fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName());
396 uint32_t codeSize = method->GetCodeSize();
397 CString methodInfo = methodName + ", bytecode size:" + ToCString(codeSize);
398 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, ConvertToStdString("JIT::Compile:" + methodInfo));
399
400 uint32_t maxSize = 9000;
401 if (vm->GetJSOptions().IsEnableJitFastCompile()) {
402 maxSize = 15; // 15 is method codesize threshold during fast compiling
403 }
404 if (codeSize > maxSize && !(vm->GetJSOptions().IsEnableForceJitCompileMain() && mode == SYNC)) {
405 if (tier == CompilerTier::BASELINE) {
406 LOG_BASELINEJIT(DEBUG) << "skip jit task, as too large:" << methodInfo;
407 } else {
408 LOG_JIT(DEBUG) << "skip jit task, as too large:" << methodInfo;
409 }
410
411 return;
412 }
413 if (vm->IsEnableOsr() && offset != MachineCode::INVALID_OSR_OFFSET && method->HasCatchBlock()) {
414 LOG_JIT(DEBUG) << "skip jit task, as osr does not support catch blocks: " << methodInfo;
415 return;
416 }
417
418 CString msg = "compile method:" + methodInfo + ", in work thread";
419 TimeScope scope(vm, msg, tier, true, true);
420 if (vm->GetJSThread()->IsMachineCodeLowMemory()) {
421 if (tier == CompilerTier::BASELINE) {
422 LOG_BASELINEJIT(DEBUG) << "skip jit task, as low code memory:" << methodInfo;
423 } else {
424 LOG_JIT(DEBUG) << "skip jit task, as low code memory:" << methodInfo;
425 }
426
427 return;
428 }
429 if (!jit->SupportJIT(jsFunction, vm, tier)) {
430 return;
431 }
432 bool needCompile = jit->CheckJitCompileStatus(jsFunction, methodName, tier);
433 if (!needCompile) {
434 return;
435 }
436
437 // using hole value to indecate compiling. todo: reset when failed
438 if (tier == CompilerTier::FAST) {
439 jsFunction->SetMachineCode(vm->GetJSThread(), JSTaggedValue::Hole());
440 jit->GetJitDfx()->SetTriggerCount(false);
441 } else {
442 ASSERT(tier == CompilerTier::BASELINE);
443 jsFunction->SetBaselineCode(vm->GetJSThread(), JSTaggedValue::Hole());
444 jit->GetJitDfx()->SetTriggerCount(true);
445 }
446
447 {
448 JitTaskpool::GetCurrentTaskpool()->WaitForJitTaskPoolReady();
449 EcmaVM *compilerVm = JitTaskpool::GetCurrentTaskpool()->GetCompilerVm();
450 std::shared_ptr<JitTask> jitTask = std::make_shared<JitTask>(vm->GetJSThread(), compilerVm->GetJSThread(),
451 jit, jsFunction, tier, methodName, offset, vm->GetJSThread()->GetThreadId(), mode);
452
453 jitTask->PrepareCompile();
454 JitTaskpool::GetCurrentTaskpool()->PostTask(
455 std::make_unique<JitTask::AsyncTask>(jitTask, vm->GetJSThread()->GetThreadId()));
456 if (mode == SYNC) {
457 // sync mode, also compile in taskpool as litecg unsupport parallel compile,
458 // wait task compile finish then install code
459 jitTask->WaitFinish();
460 jitTask->InstallCode();
461 }
462 int spendTime = scope.TotalSpentTimeInMicroseconds();
463 jitTask->SetMainThreadCompilerTime(spendTime);
464 jit->GetJitDfx()->RecordSpentTimeAndPrintStatsLogInJsThread(spendTime);
465 }
466 }
467
RequestInstallCode(std::shared_ptr<JitTask> jitTask)468 void Jit::RequestInstallCode(std::shared_ptr<JitTask> jitTask)
469 {
470 LockHolder holder(threadTaskInfoLock_);
471 ThreadTaskInfo &info = threadTaskInfo_[jitTask->GetHostThread()];
472 if (info.skipInstallTask_) {
473 return;
474 }
475 info.installJitTasks_.push_back(jitTask);
476
477 // set
478 jitTask->GetHostThread()->SetInstallMachineCode(true);
479 jitTask->GetHostThread()->SetCheckSafePointStatus();
480 }
481
CheckJitCompileStatus(JSHandle<JSFunction> & jsFunction,const CString & methodName,CompilerTier tier)482 bool Jit::CheckJitCompileStatus(JSHandle<JSFunction> &jsFunction,
483 const CString &methodName, CompilerTier tier)
484 {
485 if (tier == CompilerTier::FAST &&
486 jsFunction->GetMachineCode() == JSTaggedValue::Hole()) {
487 LOG_JIT(DEBUG) << "skip method, as it compiling:" << methodName;
488 #if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
489 auto &profMap = JitWarmupProfiler::GetInstance()->profMap_;
490 if (profMap.find(methodName) != profMap.end()) {
491 profMap.erase(methodName);
492 }
493 #endif
494 return false;
495 }
496
497 if (tier == CompilerTier::BASELINE &&
498 jsFunction->GetBaselineCode() == JSTaggedValue::Hole()) {
499 LOG_BASELINEJIT(DEBUG) << "skip method, as it compiling:" << methodName;
500 return false;
501 }
502
503 if (tier == CompilerTier::FAST && jsFunction->IsCompiledCode()) {
504 JSTaggedValue machineCode = jsFunction->GetMachineCode();
505 if (machineCode.IsMachineCodeObject() &&
506 MachineCode::Cast(machineCode.GetTaggedObject())->GetOSROffset() == MachineCode::INVALID_OSR_OFFSET) {
507 LOG_JIT(DEBUG) << "skip method, as it has been jit compiled:" << methodName;
508 return false;
509 }
510 return true;
511 }
512
513 if (tier == CompilerTier::BASELINE &&
514 jsFunction->GetBaselineCode() != JSTaggedValue::Undefined()) {
515 LOG_BASELINEJIT(DEBUG) << "skip method, as it has been jit compiled:" << methodName;
516 return false;
517 }
518 return true;
519 }
520
GetRunningTaskCnt(EcmaVM * vm)521 uint32_t Jit::GetRunningTaskCnt(EcmaVM *vm)
522 {
523 uint32_t cnt = 0;
524 JitTaskpool::GetCurrentTaskpool()->ForEachTask([&cnt, &vm](Task *task) {
525 JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
526 if (asyncTask->GetHostVM() == vm) {
527 cnt ++;
528 }
529 });
530 LockHolder holder(threadTaskInfoLock_);
531 ThreadTaskInfo &info = threadTaskInfo_[vm->GetJSThread()];
532 auto &taskQueue = info.installJitTasks_;
533 return taskQueue.size() + cnt;
534 }
535
InstallTasks(JSThread * jsThread)536 void Jit::InstallTasks(JSThread *jsThread)
537 {
538 LockHolder holder(threadTaskInfoLock_);
539 ThreadTaskInfo &info = threadTaskInfo_[jsThread];
540 auto &taskQueue = info.installJitTasks_;
541
542 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, ConvertToStdString("Jit::InstallTasks count:" + ToCString(taskQueue.size())));
543
544 for (auto it = taskQueue.begin(); it != taskQueue.end(); it++) {
545 std::shared_ptr<JitTask> task = *it;
546 // check task state
547 task->InstallCode();
548 }
549 taskQueue.clear();
550 }
551
JitCompile(void * compiler,JitTask * jitTask)552 bool Jit::JitCompile(void *compiler, JitTask *jitTask)
553 {
554 ASSERT(jitCompile_ != nullptr);
555 return jitCompile_(compiler, jitTask);
556 }
557
JitFinalize(void * compiler,JitTask * jitTask)558 bool Jit::JitFinalize(void *compiler, JitTask *jitTask)
559 {
560 ASSERT(jitFinalize_ != nullptr);
561 return jitFinalize_(compiler, jitTask);
562 }
563
CreateJitCompilerTask(JitTask * jitTask)564 void *Jit::CreateJitCompilerTask(JitTask *jitTask)
565 {
566 ASSERT(createJitCompilerTask_ != nullptr);
567 return createJitCompilerTask_(jitTask);
568 }
569
ClearTask(const std::function<bool (Task * task)> & checkClear)570 void Jit::ClearTask(const std::function<bool(Task *task)> &checkClear)
571 {
572 JitTaskpool::GetCurrentTaskpool()->ForEachTask([&checkClear](Task *task) {
573 JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
574 if (checkClear(asyncTask)) {
575 asyncTask->Terminated();
576 }
577 });
578 }
579
ClearTask(EcmaContext * ecmaContext)580 void Jit::ClearTask(EcmaContext *ecmaContext)
581 {
582 ClearTask([ecmaContext](Task *task) {
583 JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
584 return ecmaContext == asyncTask->GetEcmaContext();
585 });
586 }
587
ClearTaskWithVm(EcmaVM * vm)588 void Jit::ClearTaskWithVm(EcmaVM *vm)
589 {
590 ClearTask([vm](Task *task) {
591 JitTask::AsyncTask *asyncTask = static_cast<JitTask::AsyncTask*>(task);
592 return vm == asyncTask->GetHostVM();
593 });
594
595 {
596 LockHolder holder(threadTaskInfoLock_);
597 ThreadTaskInfo &info = threadTaskInfo_[vm->GetJSThread()];
598 info.skipInstallTask_ = true;
599 auto &taskQueue = info.installJitTasks_;
600 taskQueue.clear();
601
602 if (info.jitTaskCnt_.load() != 0) {
603 info.jitTaskCntCv_.Wait(&threadTaskInfoLock_);
604 }
605 }
606 }
607
IncJitTaskCnt(JSThread * thread)608 void Jit::IncJitTaskCnt(JSThread *thread)
609 {
610 LockHolder holder(threadTaskInfoLock_);
611 ThreadTaskInfo &info = threadTaskInfo_[thread];
612 info.jitTaskCnt_.fetch_add(1);
613 }
614
DecJitTaskCnt(JSThread * thread)615 void Jit::DecJitTaskCnt(JSThread *thread)
616 {
617 LockHolder holder(threadTaskInfoLock_);
618 ThreadTaskInfo &info = threadTaskInfo_[thread];
619 uint32_t old = info.jitTaskCnt_.fetch_sub(1);
620 if (old == 1) {
621 info.jitTaskCntCv_.Signal();
622 }
623 }
624
CheckMechineCodeSpaceMemory(JSThread * thread,int remainSize)625 void Jit::CheckMechineCodeSpaceMemory(JSThread *thread, int remainSize)
626 {
627 if (!thread->IsMachineCodeLowMemory()) {
628 return;
629 }
630 if (remainSize > MIN_CODE_SPACE_SIZE) {
631 thread->SetMachineCodeLowMemory(false);
632 }
633 }
634
ChangeTaskPoolState(bool inBackground)635 void Jit::ChangeTaskPoolState(bool inBackground)
636 {
637 if (fastJitEnable_ || baselineJitEnable_) {
638 if (inBackground) {
639 JitTaskpool::GetCurrentTaskpool()->SetThreadPriority(PriorityMode::BACKGROUND);
640 } else {
641 JitTaskpool::GetCurrentTaskpool()->SetThreadPriority(PriorityMode::FOREGROUND);
642 }
643 }
644 }
645
~TimeScope()646 Jit::TimeScope::~TimeScope()
647 {
648 if (!outPutLog_) {
649 return;
650 }
651 if (isDebugLevel_) {
652 if (tier_ == CompilerTier::BASELINE) {
653 LOG_BASELINEJIT(DEBUG) << message_ << ": " << TotalSpentTime() << "ms";
654 return;
655 }
656 ASSERT(tier_ == CompilerTier::FAST);
657 LOG_JIT(DEBUG) << message_ << ": " << TotalSpentTime() << "ms";
658 } else {
659 if (tier_ == CompilerTier::BASELINE) {
660 LOG_BASELINEJIT(INFO) << message_ << ": " << TotalSpentTime() << "ms";
661 return;
662 }
663 ASSERT(tier_ == CompilerTier::FAST);
664 auto bundleName = vm_->GetBundleName();
665 if (vm_->GetEnableJitLogSkip() && bundleName != "" && message_.find(bundleName) == std::string::npos) {
666 return;
667 }
668 LOG_JIT(INFO) << message_ << ": " << TotalSpentTime() << "ms";
669 }
670 }
671 } // namespace panda::ecmascript
672