1/* 2 * Copyright (c) 2021-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 <semaphore.h> 17#include "ecmascript/napi/include/dfx_jsnapi.h" 18 19#include "ecmascript/base/block_hook_scope.h" 20#include "ecmascript/builtins/builtins_ark_tools.h" 21#include "ecmascript/checkpoint/thread_state_transition.h" 22#include "ecmascript/debugger/debugger_api.h" 23#include "ecmascript/debugger/js_debugger_manager.h" 24#include "ecmascript/dfx/stackinfo/js_stackinfo.h" 25#include "ecmascript/dfx/tracing/tracing.h" 26#include "ecmascript/mem/heap-inl.h" 27#include "ecmascript/jit/jit.h" 28#include "ecmascript/dfx/vm_thread_control.h" 29 30#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 31#include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" 32#include "ecmascript/dfx/cpu_profiler/samples_record.h" 33#endif 34#if defined(ENABLE_DUMP_IN_FAULTLOG) 35#include "faultloggerd_client.h" 36#include "uv.h" 37#endif 38 39namespace panda { 40using ecmascript::CString; 41#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 42using BuiltinsArkTools = ecmascript::builtins::BuiltinsArkTools; 43using ecmascript::CpuProfiler; 44#endif 45using ecmascript::EcmaString; 46using ecmascript::JSTaggedValue; 47using ecmascript::GCStats; 48template<typename T> 49using JSHandle = ecmascript::JSHandle<T>; 50using ecmascript::FileStream; 51using ecmascript::FileDescriptorStream; 52using ecmascript::CMap; 53using ecmascript::Tracing; 54using ecmascript::DumpSnapShotOption; 55sem_t g_heapdumpCnt; 56 57void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const std::string &path, 58 [[maybe_unused]] const DumpSnapShotOption &dumpOption) 59{ 60#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 61 FileStream stream(path); 62 DumpHeapSnapshot(vm, &stream, dumpOption); 63#else 64 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot"; 65#endif 66} 67 68// IDE interface. 69void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream *stream, 70 [[maybe_unused]] const DumpSnapShotOption &dumpOption, 71 [[maybe_unused]] Progress *progress) 72{ 73#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 74 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 75 const_cast<EcmaVM *>(vm)); 76 heapProfile->DumpHeapSnapshot(stream, dumpOption, progress); 77#else 78 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot"; 79#endif 80} 81 82[[maybe_unused]] static uint8_t killCount = 0; 83 84void DFXJSNApi::DumpCpuProfile([[maybe_unused]] const EcmaVM *vm) 85{ 86#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 87#if defined(ENABLE_DUMP_IN_FAULTLOG) 88#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 89 // for CpuProfiler kill contral 90 if (DFXJSNApi::StopCpuProfilerForColdStart(vm)) { 91 return; 92 } 93 94 (void)killCount; 95 if (DFXJSNApi::CpuProfilerSamplingAnyTime(vm)) { 96 killCount++; 97 return; 98 } 99#endif // ECMASCRIPT_SUPPORT_CPUPROFILER 100#endif // ENABLE_DUMP_IN_FAULTLOG 101#endif // ECMASCRIPT_SUPPORT_SNAPSHOT 102} 103 104// kill -39. 105void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, 106 [[maybe_unused]] const DumpSnapShotOption &dumpOption) 107{ 108#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 109#if defined(ENABLE_DUMP_IN_FAULTLOG) 110 sem_wait(&g_heapdumpCnt); 111 auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions(); 112 options.SwitchStartGlobalLeakCheck(); 113 if (options.EnableGlobalLeakCheck() && options.IsStartGlobalLeakCheck()) { 114 int32_t stackTraceFd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_STACKTRACE)); 115 if (stackTraceFd < 0) { 116 options.SwitchStartGlobalLeakCheck(); 117 } else { 118 vm->GetJSThread()->SetStackTraceFd(stackTraceFd); 119 } 120 } 121 122 // Write in faultlog for heap leak. 123 int32_t fd; 124 if (dumpOption.isDumpOOM && dumpOption.dumpFormat == DumpFormat::BINARY) { 125 fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_RAW_SNAPSHOT)); 126 } else { 127 fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_HEAP_SNAPSHOT)); 128 } 129 if (fd < 0) { 130 LOG_ECMA(ERROR) << "Write FD failed, fd" << fd; 131 return; 132 } 133 FileDescriptorStream stream(fd); 134 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 135 const_cast<EcmaVM *>(vm)); 136 heapProfile->DumpHeapSnapshot(&stream, dumpOption); 137 138 sem_post(&g_heapdumpCnt); 139#endif // ENABLE_DUMP_IN_FAULTLOG 140#else 141 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot"; 142#endif // ECMASCRIPT_SUPPORT_SNAPSHOT 143} 144 145// tid = 0: dump all vm; tid != 0: dump tid vm, hidumper. 146void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, 147 [[maybe_unused]] const DumpSnapShotOption &dumpOption, [[maybe_unused]] uint32_t tid) 148{ 149 const int THREAD_COUNT = 1; 150 if (vm->IsWorkerThread()) { 151 LOG_ECMA(ERROR) << "this is a workthread!"; 152 return; 153 } 154 sem_init(&g_heapdumpCnt, 0, THREAD_COUNT); 155 uint32_t curTid = vm->GetTid(); 156 LOG_ECMA(INFO) << "DumpHeapSnapshot tid " << tid << " curTid " << curTid; 157 DumpHeapSnapshotWithVm(vm, dumpOption, tid); 158} 159 160void DFXJSNApi::DumpHeapSnapshotWithVm([[maybe_unused]] const EcmaVM *vm, 161 [[maybe_unused]] const DumpSnapShotOption &dumpOption, 162 [[maybe_unused]] uint32_t tid) 163{ 164#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 165#if defined(ENABLE_DUMP_IN_FAULTLOG) 166 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm->GetLoop()); 167 if (loop == nullptr || uv_loop_alive(loop) == 0) { 168 LOG_ECMA(ERROR) << "loop nullptr or uv_loop_alive dead"; 169 return; 170 } 171 struct DumpForSnapShotStruct *dumpStruct = new DumpForSnapShotStruct(); 172 dumpStruct->vm = vm; 173 dumpStruct->dumpOption = dumpOption; 174 uv_work_t *work = new(std::nothrow) uv_work_t; 175 if (work == nullptr) { 176 LOG_ECMA(ERROR) << "work nullptr"; 177 delete dumpStruct; 178 return; 179 } 180 work->data = static_cast<void *>(dumpStruct); 181 182 uint32_t curTid = vm->GetTid(); 183 int ret = 0; 184 if (tid == 0 || tid == curTid) { 185 ret = uv_queue_work(loop, work, [](uv_work_t *) {}, [](uv_work_t *work, int32_t) { 186 struct DumpForSnapShotStruct *dump = static_cast<struct DumpForSnapShotStruct *>(work->data); 187 DFXJSNApi::GetHeapPrepare(dump->vm); 188 DumpSnapShotOption dumpOption = dump->dumpOption; 189 DumpHeapSnapshot(dump->vm, dumpOption); 190 delete dump; 191 delete work; 192 }); 193 } else { 194 delete dumpStruct; 195 delete work; 196 } 197 198 // dump worker vm 199 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void { 200 uint32_t curTid = workerVm->GetTid(); 201 LOG_ECMA(INFO) << "DumpHeapSnapshot workthread curTid " << curTid; 202 DumpHeapSnapshotWithVm(workerVm, dumpOption, tid); 203 return; 204 }); 205 206 if (ret != 0) { 207 LOG_ECMA(ERROR) << "uv_queue_work fail ret " << ret; 208 delete dumpStruct; 209 delete work; 210 } 211#endif 212#endif 213} 214 215void DFXJSNApi::GenerateHeapSnapshotByBinFile([[maybe_unused]] const EcmaVM *vm, 216 [[maybe_unused]] std::string &inputFilePath, 217 [[maybe_unused]] std::string &outputPath) 218{ 219#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 220 auto *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(const_cast<EcmaVM *>(vm)); 221 heapProfile->GenerateHeapSnapshot(inputFilePath, outputPath); 222#else 223 LOG_ECMA(ERROR) << "Not support GenerateHeapSnapshotByBinFile"; 224#endif // ECMASCRIPT_SUPPORT_SNAPSHOT 225} 226 227// tid = 0: TriggerGC all vm; tid != 0: TriggerGC tid vm 228void DFXJSNApi::TriggerGC([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] uint32_t tid) 229{ 230 if (vm->IsWorkerThread()) { 231 LOG_ECMA(ERROR) << "this is a workthread!"; 232 return; 233 } 234 // triggerGC host vm 235 uint32_t curTid = vm->GetTid(); 236 LOG_ECMA(INFO) << "TriggerGC tid " << tid << " curTid " << curTid; 237 if (tid == 0 || tid == curTid) { 238 TriggerGCWithVm(vm); 239 } 240 // triggerGC worker vm 241 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void { 242 curTid = workerVm->GetTid(); 243 LOG_ECMA(INFO) << "TriggerGC tid " << tid << " curTid " << curTid; 244 if (tid == 0 || tid == curTid) { 245 TriggerGCWithVm(workerVm); 246 return; 247 } 248 }); 249 // triggerSharedFullGC 250 TriggerSharedGCWithVm(vm); 251} 252 253void DFXJSNApi::TriggerSharedGCWithVm([[maybe_unused]] const EcmaVM *vm) 254{ 255#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 256#if defined(ENABLE_DUMP_IN_FAULTLOG) 257 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm->GetLoop()); 258 if (loop == nullptr) { 259 LOG_ECMA(ERROR) << "loop nullptr"; 260 return; 261 } 262 if (uv_loop_alive(loop) == 0) { 263 LOG_ECMA(ERROR) << "uv_loop_alive dead"; 264 return; 265 } 266 uv_work_t *work = new(std::nothrow) uv_work_t; 267 if (work == nullptr) { 268 LOG_ECMA(FATAL) << "DFXJSNApi::TriggerGCWithVm:work is nullptr"; 269 return; 270 } 271 work->data = static_cast<void *>(const_cast<EcmaVM *>(vm)); 272 int ret = uv_queue_work(loop, work, [](uv_work_t *) {}, [](uv_work_t *work, int32_t) { 273 EcmaVM *vm = static_cast<EcmaVM *>(work->data); 274 ecmascript::SharedHeap* sHeap = ecmascript::SharedHeap::GetInstance(); 275 JSThread *thread = vm->GetJSThread(); 276 ecmascript::ThreadManagedScope managedScope(thread); 277 sHeap->CollectGarbage<ecmascript::TriggerGCType::SHARED_FULL_GC, 278 ecmascript::GCReason::TRIGGER_BY_MEM_TOOLS>(thread); 279 delete work; 280 }); 281 if (ret != 0) { 282 LOG_ECMA(ERROR) << "uv_queue_work fail ret " << ret; 283 delete work; 284 } 285#endif 286#endif 287} 288 289void DFXJSNApi::TriggerGCWithVm([[maybe_unused]] const EcmaVM *vm) 290{ 291#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 292#if defined(ENABLE_DUMP_IN_FAULTLOG) 293 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm->GetLoop()); 294 if (loop == nullptr) { 295 LOG_ECMA(ERROR) << "loop nullptr"; 296 return; 297 } 298 if (uv_loop_alive(loop) == 0) { 299 LOG_ECMA(ERROR) << "uv_loop_alive dead"; 300 return; 301 } 302 uv_work_t *work = new(std::nothrow) uv_work_t; 303 if (work == nullptr) { 304 LOG_ECMA(FATAL) << "DFXJSNApi::TriggerGCWithVm:work is nullptr"; 305 return; 306 } 307 work->data = static_cast<void *>(const_cast<EcmaVM *>(vm)); 308 int ret = uv_queue_work(loop, work, [](uv_work_t *) {}, [](uv_work_t *work, int32_t) { 309 EcmaVM *vm = static_cast<EcmaVM *>(work->data); 310 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 311 vm->CollectGarbage(ecmascript::TriggerGCType::FULL_GC, ecmascript::GCReason::TRIGGER_BY_MEM_TOOLS); 312 delete work; 313 }); 314 if (ret != 0) { 315 LOG_ECMA(ERROR) << "uv_queue_work fail ret " << ret; 316 delete work; 317 } 318#endif 319#endif 320} 321 322void DFXJSNApi::DestroyHeapProfiler([[maybe_unused]] const EcmaVM *vm) 323{ 324#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 325 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 326 ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm)); 327#else 328 LOG_ECMA(ERROR) << "Not support arkcompiler heap snapshot"; 329#endif 330} 331 332bool DFXJSNApi::BuildNativeAndJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr) 333{ 334 stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), true); 335 if (stackTraceStr.empty()) { 336 return false; 337 } 338 return true; 339} 340 341bool DFXJSNApi::BuildJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr) 342{ 343 stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), false); 344 if (stackTraceStr.empty()) { 345 return false; 346 } 347 return true; 348} 349 350bool DFXJSNApi::StartHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] double timeInterval, 351 [[maybe_unused]] bool isVmMode, [[maybe_unused]] Stream *stream, 352 [[maybe_unused]] bool traceAllocation, [[maybe_unused]] bool newThread) 353{ 354#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 355 ecmascript::base::BlockHookScope blockScope; 356 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 357 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 358 const_cast<EcmaVM *>(vm)); 359 return heapProfile->StartHeapTracking(timeInterval, isVmMode, stream, traceAllocation, newThread); 360#else 361 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking"; 362 return false; 363#endif 364} 365 366bool DFXJSNApi::UpdateHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream *stream) 367{ 368#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 369 ecmascript::base::BlockHookScope blockScope; 370 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 371 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 372 const_cast<EcmaVM *>(vm)); 373 return heapProfile->UpdateHeapTracking(stream); 374#else 375 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking"; 376 return false; 377#endif 378} 379 380bool DFXJSNApi::StopHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] const std::string &filePath, 381 [[maybe_unused]] bool newThread) 382{ 383#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 384 FileStream stream(filePath); 385 return StopHeapTracking(vm, &stream, nullptr, newThread); 386#else 387 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking"; 388 return false; 389#endif 390} 391 392bool DFXJSNApi::StopHeapTracking([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] Stream* stream, 393 [[maybe_unused]] Progress *progress, [[maybe_unused]] bool newThread) 394{ 395#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 396 ecmascript::base::BlockHookScope blockScope; 397 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 398 bool result = false; 399 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 400 const_cast<EcmaVM *>(vm)); 401 result = heapProfile->StopHeapTracking(stream, progress, newThread); 402 ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm)); 403 return result; 404#else 405 LOG_ECMA(ERROR) << "Not support arkcompiler heap tracking"; 406 return false; 407#endif 408} 409 410void DFXJSNApi::PrintStatisticResult(const EcmaVM *vm) 411{ 412 ecmascript::GCStats gcstats(vm->GetHeap()); 413 gcstats.PrintStatisticResult(); 414} 415 416void DFXJSNApi::StartRuntimeStat(EcmaVM *vm) 417{ 418 vm->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(true); 419} 420 421void DFXJSNApi::StopRuntimeStat(EcmaVM *vm) 422{ 423 vm->GetJSThread()->GetCurrentEcmaContext()->SetRuntimeStatEnable(false); 424} 425 426size_t DFXJSNApi::GetArrayBufferSize(const EcmaVM *vm) 427{ 428 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 429 return vm->GetHeap()->GetArrayBufferSize(); 430} 431 432size_t DFXJSNApi::GetHeapTotalSize(const EcmaVM *vm) 433{ 434 return vm->GetHeap()->GetCommittedSize(); 435} 436 437size_t DFXJSNApi::GetHeapUsedSize(const EcmaVM *vm) 438{ 439 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 440 return vm->GetHeap()->GetLiveObjectSize(); 441} 442 443size_t DFXJSNApi::GetHeapObjectSize(const EcmaVM *vm) 444{ 445 return vm->GetHeap()->GetHeapObjectSize(); 446} 447 448size_t DFXJSNApi::GetHeapLimitSize(const EcmaVM *vm) 449{ 450 return vm->GetHeap()->GetHeapLimitSize(); 451} 452 453size_t DFXJSNApi::GetProcessHeapLimitSize() 454{ 455 return ecmascript::MemMapAllocator::GetInstance()->GetCapacity(); 456} 457 458size_t DFXJSNApi::GetGCCount(const EcmaVM *vm) 459{ 460 if (vm->IsWorkerThread()) { 461 return vm->GetEcmaGCStats()->GetGCCount(); 462 } 463 return vm->GetEcmaGCStats()->GetGCCount() + 464 ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetGCCount(); 465} 466 467size_t DFXJSNApi::GetGCDuration(const EcmaVM *vm) 468{ 469 if (vm->IsWorkerThread()) { 470 return vm->GetEcmaGCStats()->GetGCDuration(); 471 } 472 return vm->GetEcmaGCStats()->GetGCDuration() + 473 ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetGCDuration(); 474} 475 476size_t DFXJSNApi::GetAccumulatedAllocateSize(const EcmaVM *vm) 477{ 478 if (vm->IsWorkerThread()) { 479 return vm->GetEcmaGCStats()->GetAccumulatedAllocateSize(); 480 } 481 return vm->GetEcmaGCStats()->GetAccumulatedAllocateSize() + 482 ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetAccumulatedAllocateSize(); 483} 484 485size_t DFXJSNApi::GetAccumulatedFreeSize(const EcmaVM *vm) 486{ 487 if (vm->IsWorkerThread()) { 488 return vm->GetEcmaGCStats()->GetAccumulatedFreeSize(); 489 } 490 return vm->GetEcmaGCStats()->GetAccumulatedFreeSize() + 491 ecmascript::SharedHeap::GetInstance()->GetEcmaGCStats()->GetAccumulatedFreeSize(); 492} 493 494size_t DFXJSNApi::GetFullGCLongTimeCount(const EcmaVM *vm) 495{ 496 return vm->GetEcmaGCStats()->GetFullGCLongTimeCount(); 497} 498 499void DFXJSNApi::GetHeapPrepare(const EcmaVM *vm) 500{ 501 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 502 const_cast<ecmascript::Heap *>(vm->GetHeap())->GetHeapPrepare(); 503} 504 505void DFXJSNApi::SetJsDumpThresholds([[maybe_unused]] EcmaVM *vm, [[maybe_unused]] size_t thresholds) 506{ 507#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) && defined(PANDA_TARGET_OHOS) && defined(ENABLE_HISYSEVENT) 508 vm->GetHeap()->SetJsDumpThresholds(thresholds); 509#else 510 LOG_ECMA(ERROR) << "Not support set jsdump thresholds"; 511#endif 512} 513 514void DFXJSNApi::SetAppFreezeFilterCallback(const EcmaVM *vm, AppFreezeFilterCallback cb) 515{ 516 const_cast<ecmascript::Heap *>(vm->GetHeap())->SetAppFreezeFilterCallback(cb); 517 ecmascript::SharedHeap* sHeap = ecmascript::SharedHeap::GetInstance(); 518 sHeap->SetAppFreezeFilterCallback(cb); 519} 520 521void DFXJSNApi::NotifyApplicationState(EcmaVM *vm, bool inBackground) 522{ 523 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 524 const_cast<ecmascript::Heap *>(vm->GetHeap())->ChangeGCParams(inBackground); 525 ecmascript::Jit::GetInstance()->ChangeTaskPoolState(inBackground); 526} 527 528void DFXJSNApi::NotifyIdleStatusControl(const EcmaVM *vm, std::function<void(bool)> callback) 529{ 530 const_cast<ecmascript::Heap *>(vm->GetHeap())->InitializeIdleStatusControl(callback); 531} 532 533void DFXJSNApi::NotifyIdleTime(const EcmaVM *vm, int idleMicroSec) 534{ 535 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 536 const_cast<ecmascript::Heap *>(vm->GetHeap())->TriggerIdleCollection(idleMicroSec); 537} 538 539void DFXJSNApi::NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure) 540{ 541 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyMemoryPressure(inHighMemoryPressure); 542} 543 544void DFXJSNApi::NotifyFinishColdStart(EcmaVM *vm, bool isConvinced) 545{ 546 ecmascript::ThreadManagedScope managedScope(vm->GetJSThread()); 547 if (isConvinced) { 548 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyFinishColdStart(); 549 } else { 550 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyFinishColdStartSoon(); 551 } 552} 553 554void DFXJSNApi::NotifyHighSensitive(EcmaVM *vm, bool isStart) 555{ 556 const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyHighSensitive(isStart); 557} 558 559bool DFXJSNApi::StopCpuProfilerForColdStart([[maybe_unused]] const EcmaVM *vm) 560{ 561#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 562 bool success = false; 563 auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions(); 564 if (options.EnableCpuProfilerColdStartMainThread()) { 565 success = true; 566 DFXJSNApi::StopCpuProfilerForFile(vm); 567 } 568 569 if (options.EnableCpuProfilerColdStartWorkerThread()) { 570 success = true; 571 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void { 572 if (workerVm->GetJSThread()->GetIsProfiling()) { 573 DFXJSNApi::StopCpuProfilerForFile(workerVm); 574 } 575 }); 576 } 577 578 return success; 579#else 580 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler"; 581 return false; 582#endif 583} 584 585#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 586void DFXJSNApi::CpuProfilerAnyTimeMainThread(const EcmaVM *vm) 587{ 588 const uint8_t KILL_COUNT_FACTOR = 2; 589 if (killCount % KILL_COUNT_FACTOR == 0) { 590 uint8_t fileCount = killCount / KILL_COUNT_FACTOR + 1; 591 LOG_ECMA(INFO) << "Start CpuProfiler Any Time Main Thread, killCount = " << killCount; 592 std::string fileName = ConvertToStdString(const_cast<EcmaVM *>(vm)->GetBundleName()) 593 + "_" + std::to_string(fileCount) + ".cpuprofile"; 594 if (!BuiltinsArkTools::CreateFile(fileName)) { 595 LOG_ECMA(ERROR) << "createFile failed " << fileName; 596 } else { 597 DFXJSNApi::StartCpuProfilerForFile(vm, fileName, CpuProfiler::INTERVAL_OF_INNER_START); 598 } 599 } else { 600 LOG_ECMA(INFO) << "Stop CpuProfiler Any Time Main Thread, killCount = " << killCount; 601 if (vm->GetJSThread()->GetIsProfiling()) { 602 DFXJSNApi::StopCpuProfilerForFile(vm); 603 } 604 } 605} 606#endif 607 608bool DFXJSNApi::CpuProfilerSamplingAnyTime([[maybe_unused]] const EcmaVM *vm) 609{ 610#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 611 (void)killCount; 612 bool success = false; 613 const uint8_t KILL_COUNT_FACTOR = 2; 614 auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions(); 615 if (options.EnableCpuProfilerAnyTimeMainThread()) { 616 success = true; 617 CpuProfilerAnyTimeMainThread(vm); 618 } 619 620 if (options.EnableCpuProfilerAnyTimeWorkerThread()) { 621 success = true; 622 if (killCount % KILL_COUNT_FACTOR == 0) { 623 uint8_t fileCount = killCount / KILL_COUNT_FACTOR + 1; 624 LOG_ECMA(INFO) << "Start CpuProfiler Any Time Worker Thread, killCount = " << killCount; 625 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void { 626 auto *thread = workerVm->GetAssociatedJSThread(); 627 std::string fileName = ConvertToStdString(workerVm->GetBundleName()) + "_" 628 + std::to_string(thread->GetThreadId()) + "_" 629 + std::to_string(fileCount) + ".cpuprofile"; 630 if (!BuiltinsArkTools::CreateFile(fileName)) { 631 LOG_ECMA(ERROR) << "createFile failed " << fileName; 632 } else { 633 thread->SetCpuProfileName(fileName); 634 thread->SetNeedProfiling(true); 635 } 636 }); 637 } else { 638 LOG_ECMA(INFO) << "Stop CpuProfiler Any Time Worker Thread, killCount = " << killCount; 639 const_cast<EcmaVM *>(vm)->EnumerateWorkerVm([&](const EcmaVM *workerVm) -> void { 640 auto *thread = workerVm->GetAssociatedJSThread(); 641 if (thread->GetIsProfiling()) { 642 DFXJSNApi::StopCpuProfilerForFile(workerVm); 643 } 644 thread->SetNeedProfiling(false); 645 }); 646 } 647 } 648 649 return success; 650#else 651 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler"; 652 return false; 653#endif 654} 655 656bool DFXJSNApi::StartCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm, 657 [[maybe_unused]] const std::string &fileName, 658 [[maybe_unused]] int interval) 659{ 660#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 661 LOG_ECMA(INFO) << "DFXJSNApi::StartCpuProfilerForFile, vm = " << vm; 662 if (interval <= 0) { 663 LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, interval <= 0"; 664 return false; 665 } 666 if (vm == nullptr) { 667 LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, vm == nullptr"; 668 return false; 669 } 670 CpuProfiler *profiler = vm->GetProfiler(); 671 if (profiler == nullptr) { 672 profiler = new CpuProfiler(vm, interval); 673 const_cast<EcmaVM *>(vm)->SetProfiler(profiler); 674 } 675 return profiler->StartCpuProfilerForFile(fileName); 676#else 677 LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, not support cpu profiler"; 678 return false; 679#endif 680} 681 682void DFXJSNApi::StopCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm) 683{ 684#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 685 LOG_ECMA(INFO) << "DFXJSNApi::StopCpuProfilerForFile, vm = " << vm; 686 if (vm == nullptr) { 687 LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile, vm == nullptr"; 688 return; 689 } 690 CpuProfiler *profiler = vm->GetProfiler(); 691 if (profiler == nullptr) { 692 LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile, profiler == nullptr"; 693 return; 694 } 695 bool result = profiler->StopCpuProfilerForFile(); 696 if (!result) { 697 LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile failed"; 698 return; 699 } 700 delete profiler; 701 profiler = nullptr; 702 const_cast<EcmaVM *>(vm)->SetProfiler(nullptr); 703#else 704 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler"; 705#endif 706} 707 708bool DFXJSNApi::StartCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval) 709{ 710#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 711 LOG_ECMA(INFO) << "DFXJSNApi::StartCpuProfilerForInfo, vm = " << vm; 712 if (interval <= 0) { 713 LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, interval <= 0"; 714 return false; 715 } 716 if (vm == nullptr) { 717 LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, vm == nullptr"; 718 return false; 719 } 720 CpuProfiler *profiler = vm->GetProfiler(); 721 if (profiler == nullptr) { 722 profiler = new CpuProfiler(vm, interval); 723 const_cast<EcmaVM *>(vm)->SetProfiler(profiler); 724 } 725 return profiler->StartCpuProfilerForInfo(); 726#else 727 LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, not support cpu profiler"; 728 return false; 729#endif 730} 731 732std::unique_ptr<ProfileInfo> DFXJSNApi::StopCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm) 733{ 734#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 735 LOG_ECMA(INFO) << "DFXJSNApi::StopCpuProfilerForInfo, vm = " << vm; 736 if (vm == nullptr) { 737 LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo, vm == nullptr"; 738 return nullptr; 739 } 740 CpuProfiler *profiler = vm->GetProfiler(); 741 if (profiler == nullptr) { 742 LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo, profiler == nullptr"; 743 return nullptr; 744 } 745 std::unique_ptr<ProfileInfo> profileInfo; 746 bool result = profiler->StopCpuProfilerForInfo(profileInfo); 747 if (!result) { 748 LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo failed"; 749 return nullptr; 750 } 751 delete profiler; 752 profiler = nullptr; 753 const_cast<EcmaVM *>(vm)->SetProfiler(nullptr); 754 return profileInfo; 755#else 756 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler"; 757 return nullptr; 758#endif 759} 760 761void DFXJSNApi::SetCpuSamplingInterval([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval) 762{ 763#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 764 if (interval < 0) { 765 LOG_ECMA(ERROR) << "Sampling interval is illegal"; 766 return; 767 } 768 LOG_ECMA(INFO) << "SetCpuProfilerSamplingInterval, Sampling interval is: " << interval; 769 if (vm == nullptr) { 770 return; 771 } 772 CpuProfiler *profiler = vm->GetProfiler(); 773 if (profiler == nullptr) { 774 profiler = new CpuProfiler(vm, interval); 775 const_cast<EcmaVM *>(vm)->SetProfiler(profiler); 776 return; 777 } 778 profiler->SetCpuSamplingInterval(interval); 779#else 780 LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler"; 781#endif 782} 783 784void DFXJSNApi::EnableSeriliazationTimeoutCheck(const EcmaVM *ecmaVM, int32_t threshold) 785{ 786 ecmaVM->GetJsDebuggerManager()->EnableSerializationTimeoutCheck(); 787 ecmaVM->GetJsDebuggerManager()->SetSerializationCheckThreshold(threshold); 788} 789 790void DFXJSNApi::DisableSeriliazationTimeoutCheck(const EcmaVM *ecmaVM) 791{ 792 ecmaVM->GetJsDebuggerManager()->DisableSerializationTimeoutCheck(); 793} 794 795bool DFXJSNApi::SuspendVM([[maybe_unused]] const EcmaVM *vm) 796{ 797#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 798 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl(); 799 return vmThreadControl->NotifyVMThreadSuspension(); 800#else 801 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot"; 802 return false; 803#endif 804} 805 806void DFXJSNApi::ResumeVM([[maybe_unused]] const EcmaVM *vm) 807{ 808#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 809 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl(); 810 vmThreadControl->ResumeVM(); 811#else 812 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot"; 813#endif 814} 815 816bool DFXJSNApi::IsSuspended([[maybe_unused]] const EcmaVM *vm) 817{ 818#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 819 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl(); 820 return vmThreadControl->IsSuspended(); 821#else 822 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot"; 823 return false; 824#endif 825} 826 827void DFXJSNApi::TerminateExecution(const EcmaVM *vm) 828{ 829 ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl(); 830 vmThreadControl->RequestTerminateExecution(); 831} 832 833bool DFXJSNApi::CheckSafepoint([[maybe_unused]] const EcmaVM *vm) 834{ 835#if defined(ECMASCRIPT_SUPPORT_SNAPSHOT) 836 ecmascript::JSThread* thread = vm->GetJSThread(); 837 return thread->CheckSafepoint(); 838#else 839 LOG_ECMA(ERROR) << "Not support arkcompiler snapshot"; 840 return false; 841#endif 842} 843 844bool DFXJSNApi::BuildJsStackInfoList(const EcmaVM *hostVm, uint32_t tid, std::vector<JsFrameInfo>& jsFrames) 845{ 846 EcmaVM *vm; 847 if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) { 848 vm = const_cast<EcmaVM*>(hostVm); 849 } else { 850 vm = const_cast<EcmaVM*>(hostVm)->GetWorkerVm(tid); 851 if (vm == nullptr) { 852 return false; 853 } 854 } 855 jsFrames = ecmascript::JsStackInfo::BuildJsStackInfo(vm->GetAssociatedJSThread()); 856 if (jsFrames.size() > 0) { 857 return true; 858 } 859 return false; 860} 861 862int32_t DFXJSNApi::GetObjectHash(const EcmaVM *vm, Local<JSValueRef> nativeObject) 863{ 864 JSHandle<JSTaggedValue> obj = JSNApiHelper::ToJSHandle(nativeObject); 865 return ecmascript::tooling::DebuggerApi::GetObjectHash(vm, obj); 866} 867 868bool DFXJSNApi::StartSampling([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] uint64_t samplingInterval) 869{ 870#if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING) 871 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 872 const_cast<EcmaVM *>(vm)); 873 return heapProfile->StartHeapSampling(samplingInterval); 874#else 875 LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling"; 876 return false; 877#endif 878} 879 880const SamplingInfo *DFXJSNApi::GetAllocationProfile([[maybe_unused]] const EcmaVM *vm) 881{ 882#if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING) 883 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 884 const_cast<EcmaVM *>(vm)); 885 return heapProfile->GetAllocationProfile(); 886#else 887 LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling"; 888 return nullptr; 889#endif 890} 891 892void DFXJSNApi::StopSampling([[maybe_unused]] const EcmaVM *vm) 893{ 894#if defined(ECMASCRIPT_SUPPORT_HEAPSAMPLING) 895 ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance( 896 const_cast<EcmaVM *>(vm)); 897 heapProfile->StopHeapSampling(); 898#else 899 LOG_ECMA(ERROR) << "Not support arkcompiler heap sampling"; 900#endif 901} 902 903// release or debug hap : aa start -p 'dumpheap' 904// aa start -p 'profile' 905bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, int tid, 906 int32_t instanceId, const DebuggerPostTask &debuggerPostTask, bool isDebugApp) 907{ 908 LOG_ECMA(INFO) << "DFXJSNApi::StartProfiler, type = " << (int)option.profilerType 909 << ", tid = " << tid << ", isDebugApp = " << isDebugApp; 910 JSNApi::DebugOption debugOption; 911 debugOption.libraryPath = option.libraryPath; 912 if (option.profilerType == ProfilerType::CPU_PROFILER) { 913 debugOption.isDebugMode = false; 914 if (JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp)) { 915 return StartCpuProfilerForInfo(vm, option.interval); 916 } else { 917 LOG_ECMA(ERROR) << "DFXJSNApi::StartProfiler, NotifyDebugMode failed"; 918 return false; 919 } 920 } else { 921 debugOption.isDebugMode = true; 922 return JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp); 923 } 924} 925 926void DFXJSNApi::ResumeVMById(EcmaVM *hostVm, uint32_t tid) 927{ 928 if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) { 929 ResumeVM(hostVm); 930 } else { 931 hostVm->ResumeWorkerVm(tid); 932 } 933} 934 935bool DFXJSNApi::SuspendVMById(EcmaVM *hostVm, uint32_t tid) 936{ 937 bool success = false; 938 if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) { 939 success = SuspendVM(hostVm); 940 LOG_ECMA(INFO) << "The main thread, SuspendVMById succeeded: " << success; 941 return success; 942 } else { 943 success = hostVm->SuspendWorkerVm(tid); 944 LOG_ECMA(INFO) << "The worker thread, SuspendVMById succeeded: " << success; 945 return success; 946 } 947} 948 949bool DFXJSNApi::StartTracing([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] std::string &categories) 950{ 951#if defined(ECMASCRIPT_SUPPORT_TRACING) 952 if (vm == nullptr) { 953 return false; 954 } 955 Tracing *tracing = vm->GetTracing(); 956 if (tracing == nullptr) { 957 tracing = new Tracing(vm); 958 const_cast<EcmaVM *>(vm)->SetTracing(tracing); 959 } 960 tracing->StartTracing(categories); 961 return true; 962#else 963 LOG_ECMA(ERROR) << "Not support arkcompiler tracing"; 964 return false; 965#endif 966} 967 968std::unique_ptr<std::vector<TraceEvent>> DFXJSNApi::StopTracing([[maybe_unused]] const EcmaVM *vm) 969{ 970#if defined(ECMASCRIPT_SUPPORT_TRACING) 971 if (vm == nullptr) { 972 return nullptr; 973 } 974 Tracing *tracing = vm->GetTracing(); 975 if (tracing == nullptr) { 976 LOG_ECMA(ERROR) << "StopTracing tracing is nullptr"; 977 return nullptr; 978 } 979 auto traceEvents = tracing->StopTracing(); 980 if (traceEvents == nullptr) { 981 LOG_ECMA(ERROR) << "trace events is nullptr"; 982 } 983 delete tracing; 984 tracing = nullptr; 985 const_cast<EcmaVM *>(vm)->SetTracing(nullptr); 986 return traceEvents; 987#else 988 LOG_ECMA(ERROR) << "Not support arkcompiler tracing"; 989 return nullptr; 990#endif 991} 992 993void DFXJSNApi::GetTracingBufferUseage([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] double &percentFull, 994 [[maybe_unused]] uint32_t &eventCount, [[maybe_unused]] double &value) 995{ 996#if defined(ECMASCRIPT_SUPPORT_TRACING) 997 if (vm == nullptr) { 998 return; 999 } 1000 ecmascript::Tracing *tracing = vm->GetTracing(); 1001 if (tracing == nullptr) { 1002 LOG_ECMA(ERROR) << "GetTracingBufferUseage tracing is nullptr"; 1003 } else { 1004 tracing->GetBufferUseage(percentFull, eventCount, value); 1005 } 1006#else 1007 LOG_ECMA(ERROR) << "Not support arkcompiler tracing"; 1008#endif 1009} 1010 1011void DFXJSNApi::TranslateJSStackInfo(const EcmaVM *vm, std::string &url, int32_t &line, int32_t &column) 1012{ 1013 auto cb = vm->GetSourceMapTranslateCallback(); 1014 if (cb == nullptr) { 1015 LOG_ECMA(ERROR) << "Translate failed, callback function is nullptr."; 1016 } else if (!cb(url, line, column)) { 1017 LOG_ECMA(ERROR) << "Translate failed, url: " << url; 1018 } 1019} 1020 1021uint32_t DFXJSNApi::GetCurrentThreadId() 1022{ 1023 return JSThread::GetCurrentThreadId(); 1024} 1025} // namespace panda 1026