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 "runtime/include/runtime.h"
17
18 #include "compiler_options.h"
19
20 #include <algorithm>
21 #include <cstdint>
22 #include <cstdio>
23 #include <memory>
24 #include <string>
25 #include <string_view>
26
27 #include "assembler/assembly-literals.h"
28 #include "core/core_language_context.h"
29 #include "intrinsics.h"
30 #include "libpandabase/events/events.h"
31 #include "libpandabase/mem/mem_config.h"
32 #include "libpandabase/mem/pool_manager.h"
33 #include "libpandabase/os/cpu_affinity.h"
34 #include "libpandabase/os/mem_hooks.h"
35 #include "libpandabase/os/native_stack.h"
36 #include "libpandabase/os/thread.h"
37 #include "libpandabase/utils/arena_containers.h"
38 #include "libpandabase/utils/logger.h"
39 #include "libpandabase/utils/dfx.h"
40 #include "libpandabase/utils/utf.h"
41 #include "libpandafile/file-inl.h"
42 #include "libpandafile/literal_data_accessor-inl.h"
43 #include "libpandafile/proto_data_accessor-inl.h"
44 #include "plugins.h"
45 #include "public.h"
46 #include "runtime/cha.h"
47 #include "runtime/compiler.h"
48 #include "runtime/dprofiler/dprofiler.h"
49 #include "runtime/entrypoints/entrypoints.h"
50 #include "runtime/include/class_linker_extension.h"
51 #include "runtime/include/coretypes/array-inl.h"
52 #include "runtime/include/coretypes/string.h"
53 #include "runtime/include/language_context.h"
54 #include "runtime/include/locks.h"
55 #include "runtime/include/runtime_notification.h"
56 #include "runtime/include/thread.h"
57 #include "runtime/include/thread_scopes.h"
58 #include "runtime/include/tooling/debug_inf.h"
59 #include "runtime/handle_scope.h"
60 #include "runtime/handle_scope-inl.h"
61 #include "mem/refstorage/reference_storage.h"
62 #include "runtime/mem/gc/gc_stats.h"
63 #include "runtime/mem/gc/stw-gc/stw-gc.h"
64 #include "runtime/mem/heap_manager.h"
65 #include "runtime/mem/memory_manager.h"
66 #include "runtime/mem/internal_allocator-inl.h"
67 #include "runtime/mem/gc/gc-hung/gc_hung.h"
68 #include "runtime/include/panda_vm.h"
69 #include "runtime/profilesaver/profile_saver.h"
70 #include "runtime/tooling/debugger.h"
71 #include "runtime/tooling/memory_allocation_dumper.h"
72 #include "runtime/include/file_manager.h"
73 #include "runtime/methodtrace/trace.h"
74 #include "trace/trace.h"
75 #include "runtime/tests/intrusive-tests/intrusive_test_option.h"
76
77 namespace ark {
78
79 using std::unique_ptr;
80
81 Runtime *Runtime::instance_ = nullptr;
82 RuntimeOptions Runtime::options_; // NOLINT(fuchsia-statically-constructed-objects)
83 std::string Runtime::runtimeType_; // NOLINT(fuchsia-statically-constructed-objects)
84 os::memory::Mutex Runtime::mutex_; // NOLINT(fuchsia-statically-constructed-objects)
85 taskmanager::TaskScheduler *Runtime::taskScheduler_ = nullptr;
86
87 const LanguageContextBase *g_ctxsJsRuntime = nullptr; // Deprecated. Only for capability with js_runtime.
88
89 class RuntimeInternalAllocator {
90 public:
Create(bool useMallocForInternalAllocation)91 static mem::InternalAllocatorPtr Create(bool useMallocForInternalAllocation)
92 {
93 ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() == nullptr);
94
95 memStatsS_ = new (std::nothrow) mem::MemStatsType();
96 ASSERT(memStatsS_ != nullptr);
97
98 if (useMallocForInternalAllocation) {
99 internalAllocatorS_ =
100 new (std::nothrow) mem::InternalAllocatorT<mem::InternalAllocatorConfig::MALLOC_ALLOCATOR>(memStatsS_);
101 } else {
102 internalAllocatorS_ =
103 new (std::nothrow) mem::InternalAllocatorT<mem::InternalAllocatorConfig::PANDA_ALLOCATORS>(memStatsS_);
104 }
105 ASSERT(internalAllocatorS_ != nullptr);
106 mem::InternalAllocator<>::InitInternalAllocatorFromRuntime(static_cast<mem::Allocator *>(internalAllocatorS_));
107
108 return internalAllocatorS_;
109 }
110
Finalize()111 static void Finalize()
112 {
113 internalAllocatorS_->VisitAndRemoveAllPools(
114 [](void *mem, size_t size) { PoolManager::GetMmapMemPool()->FreePool(mem, size); });
115 }
116
Destroy()117 static void Destroy()
118 {
119 ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() != nullptr);
120
121 mem::InternalAllocator<>::ClearInternalAllocatorFromRuntime();
122 delete static_cast<mem::Allocator *>(internalAllocatorS_);
123 internalAllocatorS_ = nullptr;
124
125 if (daemonMemoryLeakThreshold_ == 0) {
126 // One more check that we don't have memory leak in internal allocator.
127 ASSERT(daemonThreadsCnt_ > 0 || memStatsS_->GetFootprint(SpaceType::SPACE_TYPE_INTERNAL) == 0);
128 } else {
129 // There might be a memory leaks in daemon threads, which we intend to ignore (issue #6539).
130 ASSERT(memStatsS_->GetFootprint(SpaceType::SPACE_TYPE_INTERNAL) <= daemonMemoryLeakThreshold_);
131 }
132
133 delete memStatsS_;
134 memStatsS_ = nullptr;
135 }
136
Get()137 static mem::InternalAllocatorPtr Get()
138 {
139 ASSERT(internalAllocatorS_ != nullptr);
140 return internalAllocatorS_;
141 }
142
SetDaemonMemoryLeakThreshold(uint32_t daemonMemoryLeakThreshold)143 static void SetDaemonMemoryLeakThreshold(uint32_t daemonMemoryLeakThreshold)
144 {
145 daemonMemoryLeakThreshold_ = daemonMemoryLeakThreshold;
146 }
147
SetDaemonThreadsCount(uint32_t daemonThreadsCnt)148 static void SetDaemonThreadsCount(uint32_t daemonThreadsCnt)
149 {
150 daemonThreadsCnt_ = daemonThreadsCnt;
151 }
152
153 private:
154 static mem::MemStatsType *memStatsS_;
155 static mem::InternalAllocatorPtr internalAllocatorS_; // NOLINT(fuchsia-statically-constructed-objects)
156 static uint32_t daemonMemoryLeakThreshold_;
157 static uint32_t daemonThreadsCnt_;
158 };
159
160 uint32_t RuntimeInternalAllocator::daemonMemoryLeakThreshold_ = 0;
161 uint32_t RuntimeInternalAllocator::daemonThreadsCnt_ = 0;
162
163 mem::MemStatsType *RuntimeInternalAllocator::memStatsS_ = nullptr;
164 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
165 mem::InternalAllocatorPtr RuntimeInternalAllocator::internalAllocatorS_ = nullptr;
166
DebugSession(Runtime & runtime)167 Runtime::DebugSession::DebugSession(Runtime &runtime)
168 : runtime_(runtime), isJitEnabled_(runtime.IsJitEnabled()), lock_(runtime.debugSessionUniquenessMutex_)
169 {
170 ASSERT(runtime_.isDebugMode_);
171 runtime_.ForceDisableJit();
172 debugger_ = MakePandaUnique<tooling::Debugger>(&runtime_);
173 }
174
~DebugSession()175 Runtime::DebugSession::~DebugSession()
176 {
177 debugger_.reset();
178 if (isJitEnabled_) {
179 runtime_.ForceEnableJit();
180 }
181 }
182
GetDebugger()183 tooling::DebugInterface &Runtime::DebugSession::GetDebugger()
184 {
185 return *debugger_;
186 }
187
188 // all GetLanguageContext(...) methods should be based on this one
GetLanguageContext(panda_file::SourceLang lang)189 LanguageContext Runtime::GetLanguageContext(panda_file::SourceLang lang)
190 {
191 if (g_ctxsJsRuntime != nullptr) {
192 // Deprecated. Only for capability with js_runtime.
193 return LanguageContext(g_ctxsJsRuntime);
194 }
195
196 auto *ctx = plugins::GetLanguageContextBase(lang);
197 ASSERT(ctx != nullptr);
198 return LanguageContext(ctx);
199 }
200
GetLanguageContext(const Method & method)201 LanguageContext Runtime::GetLanguageContext(const Method &method)
202 {
203 // Check class source lang
204 auto *cls = method.GetClass();
205 if (cls != nullptr) {
206 return GetLanguageContext(cls->GetSourceLang());
207 }
208
209 panda_file::MethodDataAccessor mda(*method.GetPandaFile(), method.GetFileId());
210 auto res = mda.GetSourceLang();
211 return GetLanguageContext(res.value());
212 }
213
GetLanguageContext(const Class & cls)214 LanguageContext Runtime::GetLanguageContext(const Class &cls)
215 {
216 return GetLanguageContext(cls.GetSourceLang());
217 }
218
GetLanguageContext(const BaseClass & cls)219 LanguageContext Runtime::GetLanguageContext(const BaseClass &cls)
220 {
221 return GetLanguageContext(cls.GetSourceLang());
222 }
223
GetLanguageContext(panda_file::ClassDataAccessor * cda)224 LanguageContext Runtime::GetLanguageContext(panda_file::ClassDataAccessor *cda)
225 {
226 auto res = cda->GetSourceLang();
227 if (res) {
228 return GetLanguageContext(res.value());
229 }
230
231 return GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
232 }
233
GetLanguageContext(const std::string & runtimeType)234 LanguageContext Runtime::GetLanguageContext(const std::string &runtimeType)
235 {
236 return GetLanguageContext(plugins::RuntimeTypeToLang(runtimeType));
237 }
238
239 /* static */
CreateInstance(const RuntimeOptions & options,mem::InternalAllocatorPtr internalAllocator)240 bool Runtime::CreateInstance(const RuntimeOptions &options, mem::InternalAllocatorPtr internalAllocator)
241 {
242 Locks::Initialize();
243
244 if (options.WasSetEventsOutput()) {
245 Events::Create(options.GetEventsOutput(), options.GetEventsFile());
246 }
247
248 {
249 os::memory::LockHolder lock(mutex_);
250
251 if (instance_ != nullptr) {
252 return false;
253 }
254
255 instance_ = new Runtime(options, internalAllocator);
256 }
257
258 return true;
259 }
260
CreateMemorySpaces(const RuntimeOptions & options)261 inline bool CreateMemorySpaces(const RuntimeOptions &options)
262 {
263 uint32_t minFreePercentage = options.GetMinHeapFreePercentage();
264 uint32_t maxFreePercentage = options.GetMaxHeapFreePercentage();
265 if (minFreePercentage > PERCENT_100_U32) {
266 LOG(ERROR, RUNTIME) << "Incorrect minimum free heap size percentage (min-free-percentage=" << minFreePercentage
267 << "), 0 <= min-free-percentage <= 100";
268 return false;
269 }
270 if (maxFreePercentage > PERCENT_100_U32) {
271 LOG(ERROR, RUNTIME) << "Incorrect maximum free heap size percentage (max-free-percentage=" << maxFreePercentage
272 << "), 0 <= max-free-percentage <= 100";
273 return false;
274 }
275 if (minFreePercentage > maxFreePercentage) {
276 LOG(ERROR, RUNTIME) << "Minimum free heap size percentage(min-free-percentage=" << minFreePercentage
277 << ") must be <= maximum free heap size percentage (max-free-percentage="
278 << maxFreePercentage << ")";
279 return false;
280 }
281 size_t initialObjectSize = options.GetInitHeapSizeLimit();
282 size_t maxObjectSize = options.GetHeapSizeLimit();
283 bool wasSetInitialObjectSize = options.WasSetInitHeapSizeLimit();
284 bool wasSetMaxObjectSize = options.WasSetHeapSizeLimit();
285 if (!wasSetInitialObjectSize && wasSetMaxObjectSize) {
286 initialObjectSize = maxObjectSize;
287 } else if (initialObjectSize > maxObjectSize) {
288 if (wasSetInitialObjectSize && !wasSetMaxObjectSize) {
289 // Initial object heap size was set more default maximum object heap size, so set maximum heap size as
290 // initial heap size
291 maxObjectSize = initialObjectSize;
292 } else { // In this case user set initial object heap size more maximum object heap size explicitly
293 LOG(ERROR, RUNTIME) << "Initial heap size (" << initialObjectSize << ") must be <= max heap size ("
294 << maxObjectSize << ")";
295 return false;
296 }
297 }
298 initialObjectSize =
299 std::max(AlignDown(initialObjectSize, PANDA_POOL_ALIGNMENT_IN_BYTES), PANDA_POOL_ALIGNMENT_IN_BYTES);
300 maxObjectSize = std::max(AlignDown(maxObjectSize, PANDA_POOL_ALIGNMENT_IN_BYTES), PANDA_POOL_ALIGNMENT_IN_BYTES);
301 // Initialize memory spaces sizes
302 mem::MemConfig::Initialize(maxObjectSize, options.GetInternalMemorySizeLimit(),
303 options.GetCompilerMemorySizeLimit(), options.GetCodeCacheSizeLimit(),
304 options.GetFramesMemorySizeLimit(), options.GetCoroutinesStackMemLimit(),
305 initialObjectSize);
306 PoolManager::Initialize();
307 return true;
308 }
309
310 // Deprecated. Only for capability with js_runtime.
Create(const RuntimeOptions & options,const std::vector<LanguageContextBase * > & ctxs)311 bool Runtime::Create(const RuntimeOptions &options, const std::vector<LanguageContextBase *> &ctxs)
312 {
313 g_ctxsJsRuntime = ctxs.front();
314 return Runtime::Create(options);
315 }
316
317 /* static */
Create(const RuntimeOptions & options)318 bool Runtime::Create(const RuntimeOptions &options)
319 {
320 if (instance_ != nullptr) {
321 return false;
322 }
323
324 IntrusiveTestOption::SetTestId(options);
325
326 const_cast<RuntimeOptions &>(options).InitializeRuntimeSpacesAndType();
327 trace::ScopedTrace scopedTrace("Runtime::Create");
328
329 os::CpuAffinityManager::Initialize();
330
331 if (!CreateMemorySpaces(options)) {
332 LOG(ERROR, RUNTIME) << "Failed to create memory spaces for runtime";
333 return false;
334 }
335
336 mem::InternalAllocatorPtr internalAllocator =
337 RuntimeInternalAllocator::Create(options.UseMallocForInternalAllocations());
338
339 BlockSignals();
340
341 CreateDfxController(options);
342
343 CreateInstance(options, internalAllocator);
344
345 if (instance_ == nullptr) {
346 LOG(ERROR, RUNTIME) << "Failed to create runtime instance";
347 return false;
348 }
349
350 if (!instance_->Initialize()) {
351 LOG(ERROR, RUNTIME) << "Failed to initialize runtime";
352 if (instance_->GetPandaVM() != nullptr) {
353 instance_->GetPandaVM()->UninitializeThreads();
354 }
355 delete instance_;
356 instance_ = nullptr;
357 return false;
358 }
359
360 instance_->GetPandaVM()->StartGC();
361
362 auto *thread = ManagedThread::GetCurrent();
363 instance_->GetNotificationManager()->VmStartEvent();
364 instance_->GetNotificationManager()->VmInitializationEvent(thread);
365 instance_->GetNotificationManager()->ThreadStartEvent(thread);
366
367 if (options.IsSamplingProfilerEnable()) {
368 instance_->GetTools().CreateSamplingProfiler();
369 instance_->GetTools().StartSamplingProfiler(options.GetSamplingProfilerOutputFile(),
370 options.GetSamplingProfilerInterval());
371 }
372
373 return true;
374 }
375
GetCurrent()376 Runtime *Runtime::GetCurrent()
377 {
378 return instance_;
379 }
380
381 /* static */
DestroyUnderLockHolder()382 bool Runtime::DestroyUnderLockHolder()
383 {
384 os::memory::LockHolder lock(mutex_);
385
386 if (instance_ == nullptr) {
387 return false;
388 }
389
390 if (!instance_->Shutdown()) {
391 LOG(ERROR, RUNTIME) << "Failed to shutdown runtime";
392 return false;
393 }
394 if (GetOptions().WasSetEventsOutput()) {
395 Events::Destroy();
396 }
397
398 /**
399 * NOTE: Users threads can call log after destroying Runtime. We can't control these
400 * when they are in NATIVE_CODE mode because we don't destroy logger
401 * Logger::Destroy();
402 */
403
404 DfxController::Destroy();
405 ark::Logger::Sync();
406 delete instance_;
407 instance_ = nullptr;
408 ark::mem::MemConfig::Finalize();
409
410 return true;
411 }
412
413 /* static */
Destroy()414 bool Runtime::Destroy()
415 {
416 if (instance_ == nullptr) {
417 return false;
418 }
419
420 trace::ScopedTrace scopedTrace("Runtime shutdown");
421
422 if (instance_->GetOptions().IsSamplingProfilerEnable()) {
423 instance_->GetTools().StopSamplingProfiler();
424 }
425
426 // when signal start, but no signal stop tracing, should stop it
427 if (Trace::isTracing_) {
428 Trace::StopTracing();
429 }
430
431 instance_->GetPandaVM()->SaveProfileInfo();
432
433 instance_->GetNotificationManager()->VmDeathEvent();
434
435 // Stop compiler first to make sure compile memleak doesn't occur
436 auto compiler = instance_->GetPandaVM()->GetCompiler();
437 if (compiler != nullptr) {
438 // ecmascript doesn't have compiler
439 // Here we just join JITthread
440 // And destruction will be performed after thread uninitialization
441 compiler->JoinWorker();
442 }
443
444 instance_->UnloadDebugger();
445
446 // Note JIT thread (compiler) may access to thread data,
447 // so, it should be stopped before thread destroy
448 /* @sync 1
449 * @description Before starting to unitialize threads
450 * */
451 instance_->GetPandaVM()->UninitializeThreads();
452
453 /* @sync 2
454 * @description After uninitialization of threads all deamon threads should have gone into the termination loop and
455 * all other threads should have finished.
456 * */
457 // Stop GC after UninitializeThreads because
458 // UninitializeThreads may execute managed code which
459 // uses barriers
460 instance_->GetPandaVM()->StopGC();
461
462 if (taskScheduler_ != nullptr) {
463 taskScheduler_->Finalize();
464 }
465
466 if (IsEnabled(options_.GetVerificationMode())) {
467 verifier::DestroyService(instance_->verifierService_, options_.IsVerificationUpdateCache());
468 }
469
470 DestroyUnderLockHolder();
471 RuntimeInternalAllocator::Destroy();
472
473 os::CpuAffinityManager::Finalize();
474 if (taskScheduler_ != nullptr) {
475 taskmanager::TaskScheduler::Destroy();
476 taskScheduler_ = nullptr;
477 }
478
479 return true;
480 }
481
InitializeVerifierRuntime()482 void Runtime::InitializeVerifierRuntime()
483 {
484 auto mode = options_.GetVerificationMode();
485 if (IsEnabled(mode)) {
486 std::string const &cacheFile = options_.GetVerificationCacheFile();
487 verifierService_ = ark::verifier::CreateService(verifierConfig_, internalAllocator_, classLinker_, cacheFile);
488 }
489 }
490
491 /* static */
Halt(int32_t status)492 void Runtime::Halt(int32_t status)
493 {
494 Runtime *runtime = Runtime::GetCurrent();
495 if (runtime != nullptr && runtime->exit_ != nullptr) {
496 runtime->exit_(status);
497 }
498
499 // _exit is safer to call because it guarantees a safe
500 // completion in case of multi-threading as static destructors aren't called
501 _exit(status);
502 }
503
504 /* static */
Abort(const char * message)505 void Runtime::Abort(const char *message /* = nullptr */)
506 {
507 Runtime *runtime = Runtime::GetCurrent();
508 if (runtime != nullptr && runtime->abort_ != nullptr) {
509 runtime->abort_();
510 }
511
512 std::cerr << "Runtime::Abort: " << ((message != nullptr) ? message : "") << std::endl;
513 std::abort();
514 }
515
Runtime(const RuntimeOptions & options,mem::InternalAllocatorPtr internalAllocator)516 Runtime::Runtime(const RuntimeOptions &options, mem::InternalAllocatorPtr internalAllocator)
517 : internalAllocator_(internalAllocator),
518 notificationManager_(new RuntimeNotificationManager(internalAllocator_)),
519 cha_(new ClassHierarchyAnalysis)
520 {
521 Runtime::runtimeType_ = options.GetRuntimeType();
522 /* @sync 1
523 * @description Right before setting runtime options in Runtime constructor
524 */
525 Runtime::options_ = options;
526 /* @sync 3
527 * @description Right after setting runtime options in Runtime constructor
528 */
529
530 auto spaces = GetOptions().GetBootClassSpaces();
531
532 std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
533 extensions.reserve(spaces.size());
534
535 for (const auto &space : spaces) {
536 extensions.push_back(GetLanguageContext(space).CreateClassLinkerExtension());
537 }
538
539 classLinker_ = new ClassLinker(internalAllocator_, std::move(extensions));
540 #ifndef PANDA_TARGET_WINDOWS
541 signalManager_ = new SignalManager(internalAllocator_);
542 #endif
543
544 if (IsEnableMemoryHooks()) {
545 ark::os::mem_hooks::PandaHooks::Initialize();
546 ark::os::mem_hooks::PandaHooks::Enable();
547 }
548
549 saveProfilingInfo_ = options_.IsCompilerEnableJit() && options_.IsProfilesaverEnabled();
550
551 #ifdef PANDA_COMPILER_ENABLE
552 // NOTE(maksenov): Enable JIT for debug mode
553 isJitEnabled_ = !this->IsDebugMode() && Runtime::GetOptions().IsCompilerEnableJit();
554 #else
555 isJitEnabled_ = false;
556 #endif
557
558 verifierConfig_ = ark::verifier::NewConfig();
559 InitializeVerifierRuntime();
560
561 isZygote_ = options_.IsStartAsZygote();
562
563 #ifdef PANDA_ENABLE_RELAYOUT_PROFILE
564 relayoutProfiler_ = internalAllocator_->New<RelayoutProfiler>();
565 #endif
566 /* @sync 2
567 * @description At the very end of the Runtime's constructor when all initialization actions have completed.
568 * */
569 }
570
~Runtime()571 Runtime::~Runtime()
572 {
573 ark::verifier::DestroyConfig(verifierConfig_);
574
575 if (IsEnableMemoryHooks()) {
576 ark::os::mem_hooks::PandaHooks::Disable();
577 }
578 trace::ScopedTrace scopedTrace("Delete state");
579
580 #ifndef PANDA_TARGET_WINDOWS
581 signalManager_->DeleteHandlersArray();
582 delete signalManager_;
583 #endif
584 delete cha_;
585 delete classLinker_;
586 if (dprofiler_ != nullptr) {
587 internalAllocator_->Delete(dprofiler_);
588 }
589 delete notificationManager_;
590
591 if (pandaVm_ != nullptr) {
592 internalAllocator_->Delete(pandaVm_);
593 /* @sync 1
594 * @description: This point is right after runtime deastroys panda VM.
595 * */
596 }
597
598 #ifdef PANDA_ENABLE_RELAYOUT_PROFILE
599 if (relayoutProfiler_ != nullptr) {
600 internalAllocator_->Delete(relayoutProfiler_);
601 }
602 #endif
603 /* @sync 1
604 * @description Right after runtime's destructor has deleted panda virtual machine
605 * */
606
607 // crossing map is shared by different VMs.
608 mem::CrossingMapSingleton::Destroy();
609
610 RuntimeInternalAllocator::Finalize();
611 PoolManager::Finalize();
612 }
613
IsEnableMemoryHooks() const614 bool Runtime::IsEnableMemoryHooks() const
615 {
616 auto logLevel = Logger::IsInitialized() ? Logger::GetLevel() : Logger::Level::DEBUG;
617 return options_.IsLimitStandardAlloc() && (logLevel == Logger::Level::FATAL || logLevel == Logger::Level::ERROR) &&
618 (!options_.UseMallocForInternalAllocations());
619 }
620
GetPandaFilesList(const std::vector<std::string> & stdvec)621 static PandaVector<PandaString> GetPandaFilesList(const std::vector<std::string> &stdvec)
622 {
623 PandaVector<PandaString> res;
624 for (const auto &i : stdvec) {
625 // NOLINTNEXTLINE(readability-redundant-string-cstr)
626 res.push_back(i.c_str());
627 }
628
629 return res;
630 }
631
GetBootPandaFiles()632 PandaVector<PandaString> Runtime::GetBootPandaFiles()
633 {
634 // NOLINTNEXTLINE(readability-redundant-string-cstr)
635 const auto &bootPandaFiles = GetPandaFilesList(options_.GetBootPandaFiles());
636 return bootPandaFiles;
637 }
638
GetPandaFiles()639 PandaVector<PandaString> Runtime::GetPandaFiles()
640 {
641 // NOLINTNEXTLINE(readability-redundant-string-cstr)
642 const auto &appPandaFiles = GetPandaFilesList(options_.GetPandaFiles());
643 return appPandaFiles;
644 }
645
LoadBootPandaFiles(panda_file::File::OpenMode openMode)646 bool Runtime::LoadBootPandaFiles(panda_file::File::OpenMode openMode)
647 {
648 // NOLINTNEXTLINE(readability-redundant-string-cstr)
649 const auto &bootPandaFiles = options_.GetBootPandaFiles();
650 for (const auto &name : bootPandaFiles) {
651 if (!FileManager::LoadAbcFile(name, openMode)) {
652 #ifdef PANDA_PRODUCT_BUILD
653 LOG(FATAL, RUNTIME) << "Load boot panda file failed: " << name;
654 #else
655 LOG(ERROR, RUNTIME) << "Load boot panda file failed: " << name;
656 #endif // PANDA_PRODUCT_BUILD
657 return false;
658 }
659 }
660
661 return true;
662 }
663
CheckBootPandaFiles()664 void Runtime::CheckBootPandaFiles()
665 {
666 auto skipLast = static_cast<size_t>(options_.GetPandaFiles().empty() && !options_.IsStartAsZygote());
667 // NOLINTNEXTLINE(readability-redundant-string-cstr)
668 const auto &bootPandaFiles = options_.GetBootPandaFiles();
669 for (size_t i = 0; i + skipLast < bootPandaFiles.size(); ++i) {
670 auto &name = bootPandaFiles[i];
671 if (classLinker_->GetAotManager()->FindPandaFile(name) == nullptr) {
672 LOG(FATAL, RUNTIME) << "AOT file wasn't loaded for panda file: " << name;
673 }
674 }
675 }
676
SetDaemonMemoryLeakThreshold(uint32_t daemonMemoryLeakThreshold)677 void Runtime::SetDaemonMemoryLeakThreshold(uint32_t daemonMemoryLeakThreshold)
678 {
679 RuntimeInternalAllocator::SetDaemonMemoryLeakThreshold(daemonMemoryLeakThreshold);
680 }
681
SetDaemonThreadsCount(uint32_t daemonThreadsCnt)682 void Runtime::SetDaemonThreadsCount(uint32_t daemonThreadsCnt)
683 {
684 RuntimeInternalAllocator::SetDaemonThreadsCount(daemonThreadsCnt);
685 }
686
GetGCType(const RuntimeOptions & options,panda_file::SourceLang lang)687 mem::GCType Runtime::GetGCType(const RuntimeOptions &options, panda_file::SourceLang lang)
688 {
689 auto gcType = ark::mem::GCTypeFromString(options.GetGcType(plugins::LangToRuntimeType(lang)));
690 if (options.IsNoAsyncJit()) {
691 // With no-async-jit we can force compilation inside of c2i bridge (we have DecrementHotnessCounter there)
692 // and it can trigger GC which can move objects which are arguments for the method
693 // because StackWalker ignores c2i frame
694 return (gcType != ark::mem::GCType::EPSILON_GC) ? (ark::mem::GCType::STW_GC) : gcType;
695 }
696 return gcType;
697 }
698
LoadVerificationConfig()699 bool Runtime::LoadVerificationConfig()
700 {
701 return !IsEnabled(options_.GetVerificationMode()) ||
702 verifier::LoadConfigFile(verifierConfig_, options_.GetVerificationConfigFile());
703 }
704
CreatePandaVM(std::string_view runtimeType)705 bool Runtime::CreatePandaVM(std::string_view runtimeType)
706 {
707 ManagedThread::Initialize();
708
709 pandaVm_ = PandaVM::Create(this, options_, runtimeType);
710 if (pandaVm_ == nullptr) {
711 LOG(ERROR, RUNTIME) << "Failed to create panda vm";
712 return false;
713 }
714
715 if (taskScheduler_ != nullptr) {
716 taskScheduler_->Initialize();
717 }
718
719 panda_file::File::OpenMode openMode = GetLanguageContext(GetRuntimeType()).GetBootPandaFilesOpenMode();
720 bool loadBootPandaFilesIsFailed = options_.ShouldLoadBootPandaFiles() && !LoadBootPandaFiles(openMode);
721 if (loadBootPandaFilesIsFailed) {
722 LOG(ERROR, RUNTIME) << "Failed to load boot panda files";
723 return false;
724 }
725
726 auto aotBootCtx = classLinker_->GetClassContextForAot(options_.IsAotVerifyAbsPath());
727 if (options_.GetPandaFiles().empty() && !options_.IsStartAsZygote()) {
728 // Main from panda.cpp puts application file into boot panda files as the last element.
729 // During AOT compilation of boot files no application panda files were used.
730 auto idx = aotBootCtx.find_last_of(':');
731 if (idx == std::string::npos) {
732 // Only application file is in aot_boot_ctx
733 classLinker_->GetAotManager()->SetAppClassContext(aotBootCtx);
734 aotBootCtx = "";
735 } else {
736 // Last file is an application
737 classLinker_->GetAotManager()->SetAppClassContext(aotBootCtx.substr(idx + 1));
738 aotBootCtx = aotBootCtx.substr(0, idx);
739 }
740 }
741 classLinker_->GetAotManager()->SetBootClassContext(aotBootCtx);
742 if (pandaVm_->GetLanguageContext().IsEnabledCHA()) {
743 classLinker_->GetAotManager()->VerifyClassHierarchy();
744 }
745 #ifndef PANDA_PRODUCT_BUILD
746 if (Runtime::GetOptions().IsEnableAnForce() && !Runtime::GetOptions().IsArkAot()) {
747 CheckBootPandaFiles();
748 }
749 #endif // PANDA_PRODUCT_BUILD
750 notificationManager_->SetRendezvous(pandaVm_->GetRendezvous());
751
752 return true;
753 }
754
InitializePandaVM()755 bool Runtime::InitializePandaVM()
756 {
757 // temporary solution, see #7225
758 if (!options_.IsRuntimeCompressedStringsEnabled()) {
759 LOG(FATAL, RUNTIME) << "Non compressed strings is not supported";
760 }
761
762 if (!classLinker_->Initialize(options_.IsRuntimeCompressedStringsEnabled())) {
763 LOG(ERROR, RUNTIME) << "Failed to initialize class loader";
764 return false;
765 }
766
767 if (pandaVm_->ShouldEnableDebug()) {
768 SetDebugMode(true);
769 StartDebugSession();
770 }
771
772 if (!pandaVm_->Initialize()) {
773 LOG(ERROR, RUNTIME) << "Failed to initialize panda vm";
774 return false;
775 }
776
777 return true;
778 }
779
HandleAotOptions()780 bool Runtime::HandleAotOptions()
781 {
782 auto aotFiles = options_.GetAotFiles();
783 const auto &name = options_.GetAotFile();
784 if (!name.empty()) {
785 aotFiles.push_back(name);
786 }
787 if (!aotFiles.empty()) {
788 for (auto &fname : aotFiles) {
789 auto res = FileManager::LoadAnFile(fname, true);
790 if (!res) {
791 LOG(FATAL, AOT) << "Failed to load AoT file: " << res.Error();
792 }
793 if (!res.Value()) {
794 LOG(FATAL, AOT) << "Failed to load '" << fname << "' with unknown reason";
795 }
796 }
797 }
798
799 return true;
800 }
801
HandleJitOptions()802 void Runtime::HandleJitOptions()
803 {
804 #ifndef PANDA_TARGET_WINDOWS
805 auto signalManagerFlag = DfxController::GetOptionValue(DfxOptionHandler::SIGNAL_HANDLER);
806 if (signalManagerFlag == 1) {
807 signalManager_->InitSignals();
808 } else {
809 LOG(ERROR, DFX) << "signal handler disabled, setprop ark.dfx.options to restart";
810 }
811 #endif
812
813 bool enableNpHandler = options_.IsCompilerEnableJit() && ark::compiler::g_options.IsCompilerImplicitNullCheck();
814 if (GetClassLinker()->GetAotManager()->HasAotFiles()) {
815 ASSERT(GetPandaVM()->GetCompiler()->IsNoAsyncJit() == options_.IsNoAsyncJit());
816 if (GetPandaVM()->GetCompiler()->IsNoAsyncJit()) {
817 LOG(FATAL, AOT) << "We can't use the option --no-async-jit=true with AOT";
818 }
819 enableNpHandler = true;
820 }
821
822 #ifndef PANDA_TARGET_WINDOWS
823 if (signalManager_->IsInitialized() && enableNpHandler) {
824 auto *handler = signalManager_->GetAllocator()->New<NullPointerHandler>();
825 signalManager_->AddHandler(handler, true);
826 }
827 {
828 auto *handler = signalManager_->GetAllocator()->New<StackOverflowHandler>();
829 signalManager_->AddHandler(handler, true);
830 }
831 #endif
832 }
833
CheckOptionsConsistency()834 bool Runtime::CheckOptionsConsistency()
835 {
836 {
837 auto value = options_.GetResolveStringAotThreshold();
838 auto limit = RuntimeInterface::RESOLVE_STRING_AOT_COUNTER_LIMIT;
839 if (value >= limit) {
840 LOG(ERROR, RUNTIME) << "--resolve-string-aot-threshold value (" << value << ") is "
841 << ((value == limit) ? "equal to " : "greater than ") << limit
842 << ", ResolveString optimization won't be applied to AOT-compiled code. "
843 << "Consider value lower than " << limit << " to enable the optimization.";
844 }
845 }
846 return true;
847 }
848
SetPandaPath()849 void Runtime::SetPandaPath()
850 {
851 PandaVector<PandaString> appPandaFiles = GetPandaFiles();
852 for (size_t i = 0; i < appPandaFiles.size(); ++i) {
853 pandaPathString_ += PandaStringToStd(appPandaFiles[i]);
854 if (i != appPandaFiles.size() - 1) {
855 pandaPathString_ += ":";
856 }
857 }
858 }
859
SetThreadClassPointers()860 void Runtime::SetThreadClassPointers()
861 {
862 ManagedThread *thread = ManagedThread::GetCurrent();
863 classLinker_->InitializeRoots(thread);
864 auto ext = GetClassLinker()->GetExtension(GetLanguageContext(GetRuntimeType()));
865 if (ext != nullptr) {
866 thread->SetStringClassPtr(ext->GetClassRoot(ClassRoot::STRING));
867 thread->SetArrayU16ClassPtr(ext->GetClassRoot(ClassRoot::ARRAY_U16));
868 }
869 }
870
Initialize()871 bool Runtime::Initialize()
872 {
873 trace::ScopedTrace scopedTrace("Runtime::Initialize");
874
875 if (!CheckOptionsConsistency()) {
876 return false;
877 }
878
879 if (!LoadVerificationConfig()) {
880 return false;
881 }
882
883 CheckOptionsFromOs();
884
885 if (!CreatePandaVM(GetRuntimeType())) {
886 return false;
887 }
888
889 #if defined(PANDA_COMPILER_DEBUG_INFO) && !defined(NDEBUG)
890 if (!compiler::g_options.WasSetCompilerEmitDebugInfo()) {
891 compiler::g_options.SetCompilerEmitDebugInfo(true);
892 }
893 #endif
894
895 // We must load AOT file before InitializePandaVM, because during initialization, code execution may be called.
896 if (!HandleAotOptions()) {
897 return false;
898 }
899
900 if (!InitializePandaVM()) {
901 return false;
902 }
903
904 SetThreadClassPointers();
905
906 fingerPrint_ = ConvertToString(options_.GetFingerprint());
907
908 HandleJitOptions();
909
910 SetPandaPath();
911
912 if (!pandaVm_->InitializeFinish()) {
913 LOG(ERROR, RUNTIME) << "Failed to finish panda vm initialization";
914 return false;
915 }
916
917 if (IsDebugMode()) {
918 pandaVm_->LoadDebuggerAgent();
919 }
920
921 if (options_.WasSetMemAllocDumpExec()) {
922 StartMemAllocDumper(ConvertToString(options_.GetMemAllocDumpFile()));
923 }
924
925 #ifdef PANDA_TARGET_MOBILE
926 mem::GcHung::InitPreFork(true);
927 #else
928 mem::GcHung::InitPreFork(false);
929 #endif // PANDA_TARGET_MOBILE
930
931 isInitialized_ = true;
932 return true;
933 }
934
StartMemAllocDumper(const PandaString & dumpFile)935 int Runtime::StartMemAllocDumper(const PandaString &dumpFile)
936 {
937 ASSERT(memAllocDumper_ == nullptr);
938
939 memAllocDumper_ = internalAllocator_->New<tooling::MemoryAllocationDumper>(dumpFile, Runtime::GetCurrent());
940 return 0;
941 }
942
GetClassAndMethod(std::string_view entryPoint,PandaString * className,PandaString * methodName)943 static bool GetClassAndMethod(std::string_view entryPoint, PandaString *className, PandaString *methodName)
944 {
945 size_t pos = entryPoint.find_last_of("::");
946 if (pos == std::string_view::npos) {
947 return false;
948 }
949
950 *className = PandaString(entryPoint.substr(0, pos - 1));
951 *methodName = PandaString(entryPoint.substr(pos + 1));
952
953 return true;
954 }
955
GetStringArrayDescriptor(const LanguageContext & ctx,PandaString * out)956 static const uint8_t *GetStringArrayDescriptor(const LanguageContext &ctx, PandaString *out)
957 {
958 *out = "[";
959 *out += utf::Mutf8AsCString(ctx.GetStringClassDescriptor());
960
961 return utf::CStringAsMutf8(out->c_str());
962 }
963
ResolveEntryPoint(std::string_view entryPoint)964 Expected<Method *, Runtime::Error> Runtime::ResolveEntryPoint(std::string_view entryPoint)
965 {
966 PandaString className;
967 PandaString methodName;
968
969 if (!GetClassAndMethod(entryPoint, &className, &methodName)) {
970 LOG(ERROR, RUNTIME) << "Invalid entry point: " << entryPoint;
971 return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
972 }
973
974 PandaString descriptor;
975 auto classNameBytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &descriptor);
976 auto methodNameBytes = utf::CStringAsMutf8(methodName.c_str());
977
978 Class *cls = nullptr;
979 ClassLinkerContext *context = appContext_.ctx;
980 if (context == nullptr) {
981 context = classLinker_->GetExtension(GetLanguageContext(GetRuntimeType()))->GetBootContext();
982 }
983
984 ManagedThread *thread = ManagedThread::GetCurrent();
985 ScopedManagedCodeThread sa(thread);
986 cls = classLinker_->GetClass(classNameBytes, true, context);
987 if (cls == nullptr) {
988 LOG(ERROR, RUNTIME) << "Cannot find class '" << className << "'";
989 return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
990 }
991
992 LanguageContext ctx = GetLanguageContext(*cls);
993 PandaString stringArrayDescriptor;
994 GetStringArrayDescriptor(ctx, &stringArrayDescriptor);
995
996 Method::Proto proto(Method::Proto::ShortyVector {panda_file::Type(panda_file::Type::TypeId::VOID),
997 panda_file::Type(panda_file::Type::TypeId::REFERENCE)},
998 Method::Proto::RefTypeVector {stringArrayDescriptor});
999
1000 auto method = cls->GetDirectMethod(methodNameBytes, proto);
1001 if (method == nullptr) {
1002 method = cls->GetDirectMethod(methodNameBytes);
1003 if (method == nullptr) {
1004 LOG(ERROR, RUNTIME) << "Cannot find method '" << entryPoint << "'";
1005 return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
1006 }
1007 }
1008
1009 return method;
1010 }
1011
GetMemoryStatistics()1012 PandaString Runtime::GetMemoryStatistics()
1013 {
1014 return pandaVm_->GetMemStats()->GetStatistics();
1015 }
1016
GetFinalStatistics()1017 PandaString Runtime::GetFinalStatistics()
1018 {
1019 return pandaVm_->GetGCStats()->GetFinalStatistics(pandaVm_->GetHeapManager());
1020 }
1021
NotifyAboutLoadedModules()1022 void Runtime::NotifyAboutLoadedModules()
1023 {
1024 PandaVector<const panda_file::File *> pfs;
1025
1026 classLinker_->EnumerateBootPandaFiles([&pfs](const panda_file::File &pf) {
1027 pfs.push_back(&pf);
1028 return true;
1029 });
1030
1031 for (const auto *pf : pfs) {
1032 GetNotificationManager()->LoadModuleEvent(pf->GetFilename());
1033 }
1034 }
1035
ExtractLanguageContext(const panda_file::File * pf,std::string_view entryPoint)1036 Expected<LanguageContext, Runtime::Error> Runtime::ExtractLanguageContext(const panda_file::File *pf,
1037 std::string_view entryPoint)
1038 {
1039 PandaString className;
1040 PandaString methodName;
1041 if (!GetClassAndMethod(entryPoint, &className, &methodName)) {
1042 LOG(ERROR, RUNTIME) << "Invalid entry point: " << entryPoint;
1043 return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
1044 }
1045
1046 PandaString descriptor;
1047 auto classNameBytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &descriptor);
1048 auto methodNameBytes = utf::CStringAsMutf8(methodName.c_str());
1049
1050 auto classId = pf->GetClassId(classNameBytes);
1051 if (!classId.IsValid() || pf->IsExternal(classId)) {
1052 LOG(ERROR, RUNTIME) << "Cannot find class '" << className << "'";
1053 return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
1054 }
1055
1056 panda_file::ClassDataAccessor cda(*pf, classId);
1057 LanguageContext ctx = GetLanguageContext(&cda);
1058 bool found = false;
1059 cda.EnumerateMethods([this, &pf, methodNameBytes, &found, &ctx](panda_file::MethodDataAccessor &mda) {
1060 if (!found && utf::IsEqual(pf->GetStringData(mda.GetNameId()).data, methodNameBytes)) {
1061 found = true;
1062 auto val = mda.GetSourceLang();
1063 if (val) {
1064 ctx = GetLanguageContext(val.value());
1065 }
1066 }
1067 });
1068
1069 if (!found) {
1070 LOG(ERROR, RUNTIME) << "Cannot find method '" << entryPoint << "'";
1071 return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
1072 }
1073
1074 return ctx;
1075 }
1076
CreateApplicationClassLinkerContext(std::string_view filename,std::string_view entryPoint)1077 std::optional<Runtime::Error> Runtime::CreateApplicationClassLinkerContext(std::string_view filename,
1078 std::string_view entryPoint)
1079 {
1080 bool isLoaded = false;
1081 classLinker_->EnumerateBootPandaFiles([&isLoaded, filename](const panda_file::File &pf) {
1082 if (pf.GetFilename() == filename) {
1083 isLoaded = true;
1084 return false;
1085 }
1086 return true;
1087 });
1088
1089 if (isLoaded) {
1090 return {};
1091 }
1092
1093 auto pf = panda_file::OpenPandaFileOrZip(filename);
1094 if (pf == nullptr) {
1095 return Runtime::Error::PANDA_FILE_LOAD_ERROR;
1096 }
1097
1098 auto res = ExtractLanguageContext(pf.get(), entryPoint);
1099 if (!res) {
1100 return res.Error();
1101 }
1102
1103 if (!classLinker_->HasExtension(res.Value())) {
1104 LOG(ERROR, RUNTIME) << "class linker hasn't " << res.Value() << " language extension";
1105 return Runtime::Error::CLASS_LINKER_EXTENSION_NOT_FOUND;
1106 }
1107
1108 auto *ext = classLinker_->GetExtension(res.Value());
1109 appContext_.lang = ext->GetLanguage();
1110 appContext_.ctx = classLinker_->GetAppContext(filename);
1111 if (appContext_.ctx == nullptr) {
1112 auto appFiles = GetPandaFiles();
1113 auto foundIter =
1114 std::find_if(appFiles.begin(), appFiles.end(), [&](auto &appFileName) { return appFileName == filename; });
1115 if (foundIter == appFiles.end()) {
1116 PandaString path(filename);
1117 appFiles.push_back(path);
1118 }
1119 appContext_.ctx = ext->CreateApplicationClassLinkerContext(appFiles);
1120 }
1121
1122 PandaString aotCtx;
1123 appContext_.ctx->EnumeratePandaFiles(compiler::AotClassContextCollector(&aotCtx, options_.IsAotVerifyAbsPath()));
1124 classLinker_->GetAotManager()->SetAppClassContext(aotCtx);
1125
1126 tooling::DebugInf::AddCodeMetaInfo(pf.get());
1127 return {};
1128 }
1129
ExecutePandaFile(std::string_view filename,std::string_view entryPoint,const std::vector<std::string> & args)1130 Expected<int, Runtime::Error> Runtime::ExecutePandaFile(std::string_view filename, std::string_view entryPoint,
1131 const std::vector<std::string> &args)
1132 {
1133 if (options_.IsDistributedProfiling()) {
1134 // Create app name from path to executable file.
1135 std::string_view appName = [](std::string_view path) -> std::string_view {
1136 auto pos = path.find_last_of('/');
1137 return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
1138 }(filename);
1139 StartDProfiler(appName);
1140 }
1141
1142 auto ctxErr = CreateApplicationClassLinkerContext(filename, entryPoint);
1143 if (ctxErr) {
1144 return Unexpected(ctxErr.value());
1145 }
1146
1147 if (pandaVm_->GetLanguageContext().IsEnabledCHA()) {
1148 classLinker_->GetAotManager()->VerifyClassHierarchy();
1149 }
1150
1151 // Check if all input files are either quickened or not
1152 uint32_t quickenedFiles = 0;
1153 uint32_t pandaFiles = 0;
1154 classLinker_->EnumeratePandaFiles([&quickenedFiles, &pandaFiles](const panda_file::File &pf) {
1155 if (pf.GetHeader()->quickenedFlag != 0) {
1156 ++quickenedFiles;
1157 }
1158 pandaFiles++;
1159 return true;
1160 });
1161 if (quickenedFiles != 0 && quickenedFiles != pandaFiles) {
1162 LOG(ERROR, RUNTIME) << "All input files should be either quickened or not. Got " << quickenedFiles
1163 << " quickened files out of " << pandaFiles << " input files.";
1164 classLinker_->EnumeratePandaFiles([](const panda_file::File &pf) {
1165 if (pf.GetHeader()->quickenedFlag != 0) {
1166 LOG(ERROR, RUNTIME) << "File " << pf.GetFilename() << " is quickened";
1167 } else {
1168 LOG(ERROR, RUNTIME) << "File " << pf.GetFilename() << " is not quickened";
1169 }
1170 return true;
1171 });
1172 UNREACHABLE();
1173 }
1174
1175 return Execute(entryPoint, args);
1176 }
1177
Execute(std::string_view entryPoint,const std::vector<std::string> & args)1178 Expected<int, Runtime::Error> Runtime::Execute(std::string_view entryPoint, const std::vector<std::string> &args)
1179 {
1180 auto resolveRes = ResolveEntryPoint(entryPoint);
1181 if (!resolveRes) {
1182 return Unexpected(resolveRes.Error());
1183 }
1184
1185 NotifyAboutLoadedModules();
1186
1187 Method *method = resolveRes.Value();
1188
1189 return pandaVm_->InvokeEntrypoint(method, args);
1190 }
1191
StartDProfiler(std::string_view appName)1192 int Runtime::StartDProfiler(std::string_view appName)
1193 {
1194 if (dprofiler_ != nullptr) {
1195 LOG(ERROR, RUNTIME) << "DProfiller already started";
1196 return -1;
1197 }
1198
1199 dprofiler_ = internalAllocator_->New<DProfiler>(appName, Runtime::GetCurrent());
1200 return 0;
1201 }
1202
StartDebugSession()1203 Runtime::DebugSessionHandle Runtime::StartDebugSession()
1204 {
1205 os::memory::LockHolder lock(debugSessionCreationMutex_);
1206
1207 auto session = debugSession_;
1208 if (session) {
1209 return session;
1210 }
1211
1212 session = MakePandaShared<DebugSession>(*this);
1213
1214 debugSession_ = session;
1215
1216 return session;
1217 }
1218
UnloadDebugger()1219 void Runtime::UnloadDebugger()
1220 {
1221 GetPandaVM()->UnloadDebuggerAgent();
1222 debugSession_.reset();
1223 }
1224
Shutdown()1225 bool Runtime::Shutdown()
1226 {
1227 if (memAllocDumper_ != nullptr) {
1228 internalAllocator_->Delete(memAllocDumper_);
1229 }
1230 ManagedThread::Shutdown();
1231 return true;
1232 }
1233
ResolveString(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)1234 coretypes::String *Runtime::ResolveString(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
1235 {
1236 auto *pf = caller.GetPandaFile();
1237 return vm->ResolveString(*pf, id);
1238 }
1239
ResolveStringFromCompiledCode(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)1240 coretypes::String *Runtime::ResolveStringFromCompiledCode(PandaVM *vm, const Method &caller,
1241 panda_file::File::EntityId id)
1242 {
1243 auto *pf = caller.GetPandaFile();
1244 return vm->ResolveStringFromCompiledCode(*pf, id);
1245 }
1246
ResolveString(PandaVM * vm,const panda_file::File & pf,panda_file::File::EntityId id,const LanguageContext & ctx)1247 coretypes::String *Runtime::ResolveString(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
1248 const LanguageContext &ctx)
1249 {
1250 coretypes::String *str = vm->GetStringTable()->GetInternalStringFast(pf, id);
1251 if (str != nullptr) {
1252 return str;
1253 }
1254 str = vm->GetStringTable()->GetOrInternInternalString(pf, id, ctx);
1255 return str;
1256 }
1257
ResolveString(PandaVM * vm,const uint8_t * mutf8,uint32_t length,const LanguageContext & ctx)1258 coretypes::String *Runtime::ResolveString(PandaVM *vm, const uint8_t *mutf8, uint32_t length,
1259 const LanguageContext &ctx)
1260 {
1261 return vm->GetStringTable()->GetOrInternString(mutf8, length, ctx);
1262 }
1263
ResolveLiteralArray(PandaVM * vm,const Method & caller,uint32_t id)1264 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const Method &caller, uint32_t id)
1265 {
1266 auto *pf = caller.GetPandaFile();
1267 id = pf->GetLiteralArrays()[id];
1268 LanguageContext ctx = GetLanguageContext(caller);
1269 return ResolveLiteralArray(vm, *pf, id, ctx);
1270 }
1271
GetClassRootForLiteralTag(const ClassLinkerExtension & ext,panda_file::LiteralTag tag) const1272 Class *Runtime::GetClassRootForLiteralTag(const ClassLinkerExtension &ext, panda_file::LiteralTag tag) const
1273 {
1274 switch (tag) {
1275 case panda_file::LiteralTag::ARRAY_U1:
1276 return ext.GetClassRoot(ClassRoot::ARRAY_U1);
1277 case panda_file::LiteralTag::ARRAY_U8:
1278 return ext.GetClassRoot(ClassRoot::ARRAY_U8);
1279 case panda_file::LiteralTag::ARRAY_I8:
1280 return ext.GetClassRoot(ClassRoot::ARRAY_I8);
1281 case panda_file::LiteralTag::ARRAY_U16:
1282 return ext.GetClassRoot(ClassRoot::ARRAY_U16);
1283 case panda_file::LiteralTag::ARRAY_I16:
1284 return ext.GetClassRoot(ClassRoot::ARRAY_I16);
1285 case panda_file::LiteralTag::ARRAY_U32:
1286 return ext.GetClassRoot(ClassRoot::ARRAY_U32);
1287 case panda_file::LiteralTag::ARRAY_I32:
1288 return ext.GetClassRoot(ClassRoot::ARRAY_I32);
1289 case panda_file::LiteralTag::ARRAY_U64:
1290 return ext.GetClassRoot(ClassRoot::ARRAY_U64);
1291 case panda_file::LiteralTag::ARRAY_I64:
1292 return ext.GetClassRoot(ClassRoot::ARRAY_I64);
1293 case panda_file::LiteralTag::ARRAY_F32:
1294 return ext.GetClassRoot(ClassRoot::ARRAY_F32);
1295 case panda_file::LiteralTag::ARRAY_F64:
1296 return ext.GetClassRoot(ClassRoot::ARRAY_F64);
1297 case panda_file::LiteralTag::ARRAY_STRING:
1298 return ext.GetClassRoot(ClassRoot::ARRAY_STRING);
1299 case panda_file::LiteralTag::TAGVALUE:
1300 case panda_file::LiteralTag::BOOL:
1301 case panda_file::LiteralTag::INTEGER:
1302 case panda_file::LiteralTag::FLOAT:
1303 case panda_file::LiteralTag::DOUBLE:
1304 case panda_file::LiteralTag::STRING:
1305 case panda_file::LiteralTag::METHOD:
1306 case panda_file::LiteralTag::GENERATORMETHOD:
1307 case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
1308 case panda_file::LiteralTag::ASYNCMETHOD:
1309 case panda_file::LiteralTag::ACCESSOR:
1310 case panda_file::LiteralTag::NULLVALUE: {
1311 break;
1312 }
1313 default: {
1314 break;
1315 }
1316 }
1317 UNREACHABLE();
1318 return nullptr;
1319 }
1320
1321 /* static */
GetLiteralTagAndValue(const panda_file::File & pf,uint32_t id,panda_file::LiteralTag * tag,panda_file::LiteralDataAccessor::LiteralValue * value)1322 bool Runtime::GetLiteralTagAndValue(const panda_file::File &pf, uint32_t id, panda_file::LiteralTag *tag,
1323 panda_file::LiteralDataAccessor::LiteralValue *value)
1324 {
1325 panda_file::File::EntityId literalArraysId = pf.GetLiteralArraysId();
1326 panda_file::LiteralDataAccessor literalDataAccessor(pf, literalArraysId);
1327 bool result = false;
1328 literalDataAccessor.EnumerateLiteralVals(
1329 panda_file::File::EntityId(id), [tag, value, &result](const panda_file::LiteralDataAccessor::LiteralValue &val,
1330 const panda_file::LiteralTag &tg) {
1331 *tag = tg;
1332 *value = val;
1333 result = true;
1334 });
1335 return result;
1336 }
1337
GetPointerToConstArrayData(const panda_file::File & pf,uint32_t id) const1338 uintptr_t Runtime::GetPointerToConstArrayData(const panda_file::File &pf, uint32_t id) const
1339 {
1340 panda_file::LiteralTag tag;
1341 panda_file::LiteralDataAccessor::LiteralValue value;
1342 if (!GetLiteralTagAndValue(pf, id, &tag, &value)) {
1343 UNREACHABLE();
1344 return 0;
1345 }
1346
1347 auto sp = pf.GetSpanFromId(panda_file::File::EntityId(std::get<uint32_t>(value)));
1348 // first element in the sp is array size, panda_file::helpers::Read move sp pointer to next element
1349 [[maybe_unused]] auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1350 return reinterpret_cast<uintptr_t>(sp.data());
1351 }
1352
ResolveLiteralArray(PandaVM * vm,const panda_file::File & pf,uint32_t id,const LanguageContext & ctx)1353 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const panda_file::File &pf, uint32_t id,
1354 const LanguageContext &ctx)
1355 {
1356 panda_file::LiteralTag tag;
1357 panda_file::LiteralDataAccessor::LiteralValue value;
1358 if (!GetLiteralTagAndValue(pf, id, &tag, &value)) {
1359 return nullptr;
1360 }
1361
1362 auto sp = pf.GetSpanFromId(panda_file::File::EntityId(std::get<uint32_t>(value)));
1363
1364 auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1365 auto ext = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx);
1366
1367 if (tag != panda_file::LiteralTag::ARRAY_STRING) {
1368 return coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), sp.data(), len);
1369 }
1370
1371 // special handling of arrays of strings
1372 auto array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), len);
1373 [[maybe_unused]] HandleScope<ObjectHeader *> scope(ManagedThread::GetCurrent());
1374 VMHandle<coretypes::Array> obj(ManagedThread::GetCurrent(), array);
1375 // NOLINTNEXTLINE(modernize-loop-convert)
1376 for (size_t i = 0; i < len; i++) {
1377 auto strId = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1378 auto str = Runtime::GetCurrent()->ResolveString(vm, pf, panda_file::File::EntityId(strId), ctx);
1379 obj->Set<ObjectHeader *>(i, str);
1380 }
1381 return obj.GetPtr();
1382 }
1383
UpdateProcessState(int state)1384 void Runtime::UpdateProcessState([[maybe_unused]] int state)
1385 {
1386 LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1387 }
1388
RegisterSensitiveThread() const1389 void Runtime::RegisterSensitiveThread() const
1390 {
1391 LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1392 }
1393
CreateDfxController(const RuntimeOptions & options)1394 void Runtime::CreateDfxController(const RuntimeOptions &options)
1395 {
1396 DfxController::Initialize();
1397 DfxController::SetOptionValue(DfxOptionHandler::COMPILER_NULLCHECK, options.GetCompilerNullcheck());
1398 DfxController::SetOptionValue(DfxOptionHandler::REFERENCE_DUMP, options.GetReferenceDump());
1399 DfxController::SetOptionValue(DfxOptionHandler::SIGNAL_CATCHER, options.GetSignalCatcher());
1400 DfxController::SetOptionValue(DfxOptionHandler::SIGNAL_HANDLER, options.GetSignalHandler());
1401 DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGQUIT, options.GetSigquitFlag());
1402 DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR1, options.GetSigusr1Flag());
1403 DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR2, options.GetSigusr2Flag());
1404 DfxController::SetOptionValue(DfxOptionHandler::MOBILE_LOG, options.GetMobileLogFlag());
1405 DfxController::SetOptionValue(DfxOptionHandler::DFXLOG, options.GetDfxLog());
1406
1407 auto compilerNullcheckFlag = DfxController::GetOptionValue(DfxOptionHandler::COMPILER_NULLCHECK);
1408 if (compilerNullcheckFlag == 0) {
1409 ark::compiler::g_options.SetCompilerImplicitNullCheck(false);
1410 }
1411 }
1412
BlockSignals()1413 void Runtime::BlockSignals()
1414 {
1415 sigset_t set;
1416 if (sigemptyset(&set) == -1) {
1417 LOG(ERROR, RUNTIME) << "sigemptyset failed";
1418 return;
1419 }
1420 int rc = 0;
1421 rc += sigaddset(&set, SIGPIPE);
1422 #ifdef PANDA_TARGET_MOBILE
1423 rc += sigaddset(&set, SIGQUIT);
1424 rc += sigaddset(&set, SIGUSR1);
1425 rc += sigaddset(&set, SIGUSR2);
1426 #endif // PANDA_TARGET_MOBILE
1427 if (rc < 0) {
1428 LOG(ERROR, RUNTIME) << "sigaddset failed";
1429 return;
1430 }
1431
1432 if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
1433 LOG(ERROR, RUNTIME) << "g_PandaThreadSigmask failed";
1434 }
1435 }
1436
DumpForSigQuit(std::ostream & os)1437 void Runtime::DumpForSigQuit(std::ostream &os)
1438 {
1439 os << "\n";
1440 os << "-> Dump class loaders\n";
1441 classLinker_->EnumerateContextsForDump(
1442 [](ClassLinkerContext *ctx, std::ostream &stream, ClassLinkerContext *parent) {
1443 ctx->Dump(stream);
1444 return ctx->FindClassLoaderParent(parent);
1445 },
1446 os);
1447 os << "\n";
1448
1449 // dump GC
1450 os << "-> Dump GC\n";
1451 os << GetFinalStatistics();
1452 os << "\n";
1453
1454 // dump memory management
1455 os << "-> Dump memory management\n";
1456 os << GetMemoryStatistics();
1457 os << "\n";
1458
1459 // dump PandaVM
1460 os << "-> Dump Ark VM\n";
1461 pandaVm_->DumpForSigQuit(os);
1462 os << "\n";
1463
1464 WRITE_RELAYOUT_PROFILE_DATA();
1465 }
1466
InitNonZygoteOrPostFork(bool isSystemServer,const char * isa,const std::function<void ()> & initHook,bool profileSystemServer)1467 void Runtime::InitNonZygoteOrPostFork(bool isSystemServer, [[maybe_unused]] const char *isa,
1468 const std::function<void()> &initHook, [[maybe_unused]] bool profileSystemServer)
1469 {
1470 isZygote_ = false;
1471
1472 // NOTE(00510180): wait NativeBridge ready
1473
1474 // NOTE(00510180): wait profile ready
1475
1476 // NOTE(00510180): wait ThreadPool ready
1477
1478 // NOTE(00510180): wait ResetGcPerformanceInfo() ready
1479
1480 pandaVm_->PreStartup();
1481
1482 initHook();
1483
1484 mem::GcHung::InitPostFork(isSystemServer);
1485 }
1486
PreZygoteFork()1487 void Runtime::PreZygoteFork()
1488 {
1489 pandaVm_->PreZygoteFork();
1490 }
1491
PostZygoteFork()1492 void Runtime::PostZygoteFork()
1493 {
1494 pandaVm_->PostZygoteFork();
1495 }
1496
1497 // Returns true if profile saving is enabled. GetJit() will be not null in this case.
SaveProfileInfo() const1498 bool Runtime::SaveProfileInfo() const
1499 {
1500 return saveProfilingInfo_;
1501 }
1502
CheckOptionsFromOs() const1503 void Runtime::CheckOptionsFromOs() const
1504 {
1505 #if !defined(PANDA_QEMU_BUILD) && !defined(PANDA_TARGET_MOBILE)
1506 // for qemu-aarch64 we will get 32 from GetCacheLineSize()
1507 // for native arm and qemu-arm we will get 0 from GetCacheLineSize()
1508 ASSERT(ark::CACHE_LINE_SIZE == os::mem::GetCacheLineSize());
1509 #endif
1510 }
1511
1512 } // namespace ark
1513