1 /**
2 * Copyright (c) 2021-2022 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 panda {
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<os::memory::Mutex> 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<os::memory::Mutex> 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 panda::Logger::Sync();
406 delete instance_;
407 instance_ = nullptr;
408 panda::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 // Note JIT thread (compiler) may access to thread data,
445 // so, it should be stopped before thread destroy
446 /* @sync 1
447 * @description Before starting to unitialize threads
448 * */
449 instance_->GetPandaVM()->UninitializeThreads();
450
451 /* @sync 2
452 * @description After uninitialization of threads all deamon threads should have gone into the termination loop and
453 * all other threads should have finished.
454 * */
455 // Stop GC after UninitializeThreads because
456 // UninitializeThreads may execute managed code which
457 // uses barriers
458 instance_->GetPandaVM()->StopGC();
459
460 if (taskScheduler_ != nullptr) {
461 taskScheduler_->Finalize();
462 }
463
464 if (IsEnabled(options_.GetVerificationMode())) {
465 verifier::DestroyService(instance_->verifierService_, options_.IsVerificationUpdateCache());
466 }
467
468 DestroyUnderLockHolder();
469 RuntimeInternalAllocator::Destroy();
470
471 os::CpuAffinityManager::Finalize();
472 if (taskScheduler_ != nullptr) {
473 taskmanager::TaskScheduler::Destroy();
474 taskScheduler_ = nullptr;
475 }
476
477 return true;
478 }
479
InitializeVerifierRuntime()480 void Runtime::InitializeVerifierRuntime()
481 {
482 auto mode = options_.GetVerificationMode();
483 if (IsEnabled(mode)) {
484 std::string const &cacheFile = options_.GetVerificationCacheFile();
485 verifierService_ = panda::verifier::CreateService(verifierConfig_, internalAllocator_, classLinker_, cacheFile);
486 }
487 }
488
489 /* static */
Halt(int32_t status)490 void Runtime::Halt(int32_t status)
491 {
492 Runtime *runtime = Runtime::GetCurrent();
493 if (runtime != nullptr && runtime->exit_ != nullptr) {
494 runtime->exit_(status);
495 }
496
497 // _exit is safer to call because it guarantees a safe
498 // completion in case of multi-threading as static destructors aren't called
499 _exit(status);
500 }
501
502 /* static */
Abort(const char * message)503 void Runtime::Abort(const char *message /* = nullptr */)
504 {
505 Runtime *runtime = Runtime::GetCurrent();
506 if (runtime != nullptr && runtime->abort_ != nullptr) {
507 runtime->abort_();
508 }
509
510 std::cerr << "Runtime::Abort: " << ((message != nullptr) ? message : "") << std::endl;
511 std::abort();
512 }
513
Runtime(const RuntimeOptions & options,mem::InternalAllocatorPtr internalAllocator)514 Runtime::Runtime(const RuntimeOptions &options, mem::InternalAllocatorPtr internalAllocator)
515 : internalAllocator_(internalAllocator),
516 notificationManager_(new RuntimeNotificationManager(internalAllocator_)),
517 cha_(new ClassHierarchyAnalysis)
518 {
519 Runtime::runtimeType_ = options.GetRuntimeType();
520 /* @sync 1
521 * @description Right before setting runtime options in Runtime constructor
522 */
523 Runtime::options_ = options;
524 /* @sync 3
525 * @description Right after setting runtime options in Runtime constructor
526 */
527
528 auto spaces = GetOptions().GetBootClassSpaces();
529
530 std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
531 extensions.reserve(spaces.size());
532
533 for (const auto &space : spaces) {
534 extensions.push_back(GetLanguageContext(space).CreateClassLinkerExtension());
535 }
536
537 classLinker_ = new ClassLinker(internalAllocator_, std::move(extensions));
538 #ifndef PANDA_TARGET_WINDOWS
539 signalManager_ = new SignalManager(internalAllocator_);
540 #endif
541
542 if (IsEnableMemoryHooks()) {
543 panda::os::mem_hooks::PandaHooks::Initialize();
544 panda::os::mem_hooks::PandaHooks::Enable();
545 }
546
547 saveProfilingInfo_ = options_.IsCompilerEnableJit() && options_.IsProfilesaverEnabled();
548
549 #ifdef PANDA_COMPILER_ENABLE
550 // NOTE(maksenov): Enable JIT for debug mode
551 isJitEnabled_ = !this->IsDebugMode() && Runtime::GetOptions().IsCompilerEnableJit();
552 #else
553 isJitEnabled_ = false;
554 #endif
555
556 verifierConfig_ = panda::verifier::NewConfig();
557 InitializeVerifierRuntime();
558
559 isZygote_ = options_.IsStartAsZygote();
560
561 #ifdef PANDA_ENABLE_RELAYOUT_PROFILE
562 relayoutProfiler_ = internalAllocator_->New<RelayoutProfiler>();
563 #endif
564 /* @sync 2
565 * @description At the very end of the Runtime's constructor when all initialization actions have completed.
566 * */
567 }
568
~Runtime()569 Runtime::~Runtime()
570 {
571 panda::verifier::DestroyConfig(verifierConfig_);
572
573 if (IsEnableMemoryHooks()) {
574 panda::os::mem_hooks::PandaHooks::Disable();
575 }
576 trace::ScopedTrace scopedTrace("Delete state");
577
578 #ifndef PANDA_TARGET_WINDOWS
579 signalManager_->DeleteHandlersArray();
580 delete signalManager_;
581 #endif
582 delete cha_;
583 delete classLinker_;
584 if (dprofiler_ != nullptr) {
585 internalAllocator_->Delete(dprofiler_);
586 }
587 delete notificationManager_;
588
589 if (pandaVm_ != nullptr) {
590 internalAllocator_->Delete(pandaVm_);
591 /* @sync 1
592 * @description: This point is right after runtime deastroys panda VM.
593 * */
594 }
595
596 #ifdef PANDA_ENABLE_RELAYOUT_PROFILE
597 if (relayoutProfiler_ != nullptr) {
598 internalAllocator_->Delete(relayoutProfiler_);
599 }
600 #endif
601 /* @sync 1
602 * @description Right after runtime's destructor has deleted panda virtual machine
603 * */
604
605 // crossing map is shared by different VMs.
606 mem::CrossingMapSingleton::Destroy();
607
608 RuntimeInternalAllocator::Finalize();
609 PoolManager::Finalize();
610 }
611
IsEnableMemoryHooks() const612 bool Runtime::IsEnableMemoryHooks() const
613 {
614 auto logLevel = Logger::IsInitialized() ? Logger::GetLevel() : Logger::Level::DEBUG;
615 return options_.IsLimitStandardAlloc() && (logLevel == Logger::Level::FATAL || logLevel == Logger::Level::ERROR) &&
616 (!options_.UseMallocForInternalAllocations());
617 }
618
GetPandaFilesList(const std::vector<std::string> & stdvec)619 static PandaVector<PandaString> GetPandaFilesList(const std::vector<std::string> &stdvec)
620 {
621 PandaVector<PandaString> res;
622 for (const auto &i : stdvec) {
623 // NOLINTNEXTLINE(readability-redundant-string-cstr)
624 res.push_back(i.c_str());
625 }
626
627 return res;
628 }
629
GetBootPandaFiles()630 PandaVector<PandaString> Runtime::GetBootPandaFiles()
631 {
632 // NOLINTNEXTLINE(readability-redundant-string-cstr)
633 const auto &bootPandaFiles = GetPandaFilesList(options_.GetBootPandaFiles());
634 return bootPandaFiles;
635 }
636
GetPandaFiles()637 PandaVector<PandaString> Runtime::GetPandaFiles()
638 {
639 // NOLINTNEXTLINE(readability-redundant-string-cstr)
640 const auto &appPandaFiles = GetPandaFilesList(options_.GetPandaFiles());
641 return appPandaFiles;
642 }
643
LoadBootPandaFiles(panda_file::File::OpenMode openMode)644 bool Runtime::LoadBootPandaFiles(panda_file::File::OpenMode openMode)
645 {
646 // NOLINTNEXTLINE(readability-redundant-string-cstr)
647 const auto &bootPandaFiles = options_.GetBootPandaFiles();
648 for (const auto &name : bootPandaFiles) {
649 if (!FileManager::LoadAbcFile(name, openMode)) {
650 #ifdef PANDA_PRODUCT_BUILD
651 LOG(FATAL, RUNTIME) << "Load boot panda file failed: " << name;
652 #else
653 LOG(ERROR, RUNTIME) << "Load boot panda file failed: " << name;
654 #endif // PANDA_PRODUCT_BUILD
655 return false;
656 }
657 }
658
659 return true;
660 }
661
CheckBootPandaFiles()662 void Runtime::CheckBootPandaFiles()
663 {
664 auto skipLast = static_cast<size_t>(options_.GetPandaFiles().empty() && !options_.IsStartAsZygote());
665 // NOLINTNEXTLINE(readability-redundant-string-cstr)
666 const auto &bootPandaFiles = options_.GetBootPandaFiles();
667 for (size_t i = 0; i + skipLast < bootPandaFiles.size(); ++i) {
668 auto &name = bootPandaFiles[i];
669 if (classLinker_->GetAotManager()->FindPandaFile(name) == nullptr) {
670 LOG(FATAL, RUNTIME) << "AOT file wasn't loaded for panda file: " << name;
671 }
672 }
673 }
674
SetDaemonMemoryLeakThreshold(uint32_t daemonMemoryLeakThreshold)675 void Runtime::SetDaemonMemoryLeakThreshold(uint32_t daemonMemoryLeakThreshold)
676 {
677 RuntimeInternalAllocator::SetDaemonMemoryLeakThreshold(daemonMemoryLeakThreshold);
678 }
679
SetDaemonThreadsCount(uint32_t daemonThreadsCnt)680 void Runtime::SetDaemonThreadsCount(uint32_t daemonThreadsCnt)
681 {
682 RuntimeInternalAllocator::SetDaemonThreadsCount(daemonThreadsCnt);
683 }
684
GetGCType(const RuntimeOptions & options,panda_file::SourceLang lang)685 mem::GCType Runtime::GetGCType(const RuntimeOptions &options, panda_file::SourceLang lang)
686 {
687 auto gcType = panda::mem::GCTypeFromString(options.GetGcType(plugins::LangToRuntimeType(lang)));
688 if (options.IsNoAsyncJit()) {
689 // With no-async-jit we can force compilation inside of c2i bridge (we have DecrementHotnessCounter there)
690 // and it can trigger GC which can move objects which are arguments for the method
691 // because StackWalker ignores c2i frame
692 return (gcType != panda::mem::GCType::EPSILON_GC) ? (panda::mem::GCType::STW_GC) : gcType;
693 }
694 return gcType;
695 }
696
LoadVerificationConfig()697 bool Runtime::LoadVerificationConfig()
698 {
699 return !IsEnabled(options_.GetVerificationMode()) ||
700 verifier::LoadConfigFile(verifierConfig_, options_.GetVerificationConfigFile());
701 }
702
CreatePandaVM(std::string_view runtimeType)703 bool Runtime::CreatePandaVM(std::string_view runtimeType)
704 {
705 ManagedThread::Initialize();
706
707 pandaVm_ = PandaVM::Create(this, options_, runtimeType);
708 if (pandaVm_ == nullptr) {
709 LOG(ERROR, RUNTIME) << "Failed to create panda vm";
710 return false;
711 }
712
713 if (taskScheduler_ != nullptr) {
714 taskScheduler_->Initialize();
715 }
716
717 panda_file::File::OpenMode openMode = GetLanguageContext(GetRuntimeType()).GetBootPandaFilesOpenMode();
718 bool loadBootPandaFilesIsFailed = options_.ShouldLoadBootPandaFiles() && !LoadBootPandaFiles(openMode);
719 if (loadBootPandaFilesIsFailed) {
720 LOG(ERROR, RUNTIME) << "Failed to load boot panda files";
721 return false;
722 }
723
724 auto aotBootCtx = classLinker_->GetClassContextForAot(options_.IsAotVerifyAbsPath());
725 if (options_.GetPandaFiles().empty() && !options_.IsStartAsZygote()) {
726 // Main from panda.cpp puts application file into boot panda files as the last element.
727 // During AOT compilation of boot files no application panda files were used.
728 auto idx = aotBootCtx.find_last_of(':');
729 if (idx == std::string::npos) {
730 // Only application file is in aot_boot_ctx
731 classLinker_->GetAotManager()->SetAppClassContext(aotBootCtx);
732 aotBootCtx = "";
733 } else {
734 // Last file is an application
735 classLinker_->GetAotManager()->SetAppClassContext(aotBootCtx.substr(idx + 1));
736 aotBootCtx = aotBootCtx.substr(0, idx);
737 }
738 }
739 classLinker_->GetAotManager()->SetBootClassContext(aotBootCtx);
740 if (pandaVm_->GetLanguageContext().IsEnabledCHA()) {
741 classLinker_->GetAotManager()->VerifyClassHierarchy();
742 }
743 #ifndef PANDA_PRODUCT_BUILD
744 if (Runtime::GetOptions().IsEnableAnForce() && !Runtime::GetOptions().IsArkAot()) {
745 CheckBootPandaFiles();
746 }
747 #endif // PANDA_PRODUCT_BUILD
748 notificationManager_->SetRendezvous(pandaVm_->GetRendezvous());
749
750 return true;
751 }
752
InitializePandaVM()753 bool Runtime::InitializePandaVM()
754 {
755 // temporary solution, see #7225
756 if (!options_.IsRuntimeCompressedStringsEnabled()) {
757 LOG(FATAL, RUNTIME) << "Non compressed strings is not supported";
758 }
759
760 if (!classLinker_->Initialize(options_.IsRuntimeCompressedStringsEnabled())) {
761 LOG(ERROR, RUNTIME) << "Failed to initialize class loader";
762 return false;
763 }
764
765 if (pandaVm_->ShouldEnableDebug()) {
766 SetDebugMode(true);
767 StartDebugSession();
768 }
769
770 if (!pandaVm_->Initialize()) {
771 LOG(ERROR, RUNTIME) << "Failed to initialize panda vm";
772 return false;
773 }
774
775 return true;
776 }
777
HandleAotOptions()778 bool Runtime::HandleAotOptions()
779 {
780 auto aotFiles = options_.GetAotFiles();
781 const auto &name = options_.GetAotFile();
782 if (!name.empty()) {
783 aotFiles.push_back(name);
784 }
785 if (!aotFiles.empty()) {
786 for (auto &fname : aotFiles) {
787 auto res = FileManager::LoadAnFile(fname, true);
788 if (!res) {
789 LOG(FATAL, AOT) << "Failed to load AoT file: " << res.Error();
790 }
791 if (!res.Value()) {
792 LOG(FATAL, AOT) << "Failed to load '" << fname << "' with unknown reason";
793 }
794 }
795 }
796
797 return true;
798 }
799
HandleJitOptions()800 void Runtime::HandleJitOptions()
801 {
802 #ifndef PANDA_TARGET_WINDOWS
803 auto signalManagerFlag = DfxController::GetOptionValue(DfxOptionHandler::SIGNAL_HANDLER);
804 if (signalManagerFlag == 1) {
805 signalManager_->InitSignals();
806 } else {
807 LOG(ERROR, DFX) << "signal handler disabled, setprop ark.dfx.options to restart";
808 }
809 #endif
810
811 bool enableNpHandler = options_.IsCompilerEnableJit() && panda::compiler::g_options.IsCompilerImplicitNullCheck();
812 if (GetClassLinker()->GetAotManager()->HasAotFiles()) {
813 ASSERT(GetPandaVM()->GetCompiler()->IsNoAsyncJit() == options_.IsNoAsyncJit());
814 if (GetPandaVM()->GetCompiler()->IsNoAsyncJit()) {
815 LOG(FATAL, AOT) << "We can't use the option --no-async-jit=true with AOT";
816 }
817 enableNpHandler = true;
818 }
819
820 #ifndef PANDA_TARGET_WINDOWS
821 if (signalManager_->IsInitialized() && enableNpHandler) {
822 auto *handler = signalManager_->GetAllocator()->New<NullPointerHandler>();
823 signalManager_->AddHandler(handler, true);
824 }
825 {
826 auto *handler = signalManager_->GetAllocator()->New<StackOverflowHandler>();
827 signalManager_->AddHandler(handler, true);
828 }
829 #endif
830 }
831
CheckOptionsConsistency()832 bool Runtime::CheckOptionsConsistency()
833 {
834 {
835 auto value = options_.GetResolveStringAotThreshold();
836 auto limit = RuntimeInterface::RESOLVE_STRING_AOT_COUNTER_LIMIT;
837 if (value >= limit) {
838 LOG(ERROR, RUNTIME) << "--resolve-string-aot-threshold value (" << value << ") is "
839 << ((value == limit) ? "equal to " : "greater than ") << limit
840 << ", ResolveString optimization won't be applied to AOT-compiled code. "
841 << "Consider value lower than " << limit << " to enable the optimization.";
842 }
843 }
844 return true;
845 }
846
SetPandaPath()847 void Runtime::SetPandaPath()
848 {
849 PandaVector<PandaString> appPandaFiles = GetPandaFiles();
850 for (size_t i = 0; i < appPandaFiles.size(); ++i) {
851 pandaPathString_ += PandaStringToStd(appPandaFiles[i]);
852 if (i != appPandaFiles.size() - 1) {
853 pandaPathString_ += ":";
854 }
855 }
856 }
857
SetThreadClassPointers()858 void Runtime::SetThreadClassPointers()
859 {
860 ManagedThread *thread = ManagedThread::GetCurrent();
861 classLinker_->InitializeRoots(thread);
862 auto ext = GetClassLinker()->GetExtension(GetLanguageContext(GetRuntimeType()));
863 if (ext != nullptr) {
864 thread->SetStringClassPtr(ext->GetClassRoot(ClassRoot::STRING));
865 thread->SetArrayU16ClassPtr(ext->GetClassRoot(ClassRoot::ARRAY_U16));
866 }
867 }
868
Initialize()869 bool Runtime::Initialize()
870 {
871 trace::ScopedTrace scopedTrace("Runtime::Initialize");
872
873 if (!CheckOptionsConsistency()) {
874 return false;
875 }
876
877 if (!LoadVerificationConfig()) {
878 return false;
879 }
880
881 CheckOptionsFromOs();
882
883 if (!CreatePandaVM(GetRuntimeType())) {
884 return false;
885 }
886
887 #if defined(PANDA_COMPILER_DEBUG_INFO) && !defined(NDEBUG)
888 if (!compiler::g_options.WasSetCompilerEmitDebugInfo()) {
889 compiler::g_options.SetCompilerEmitDebugInfo(true);
890 }
891 #endif
892
893 // We must load AOT file before InitializePandaVM, because during initialization, code execution may be called.
894 if (!HandleAotOptions()) {
895 return false;
896 }
897
898 if (!InitializePandaVM()) {
899 return false;
900 }
901
902 SetThreadClassPointers();
903
904 fingerPrint_ = ConvertToString(options_.GetFingerprint());
905
906 HandleJitOptions();
907
908 SetPandaPath();
909
910 if (!pandaVm_->InitializeFinish()) {
911 LOG(ERROR, RUNTIME) << "Failed to finish panda vm initialization";
912 return false;
913 }
914
915 if (IsDebugMode()) {
916 pandaVm_->LoadDebuggerAgent();
917 }
918
919 if (options_.WasSetMemAllocDumpExec()) {
920 StartMemAllocDumper(ConvertToString(options_.GetMemAllocDumpFile()));
921 }
922
923 #ifdef PANDA_TARGET_MOBILE
924 mem::GcHung::InitPreFork(true);
925 #else
926 mem::GcHung::InitPreFork(false);
927 #endif // PANDA_TARGET_MOBILE
928
929 isInitialized_ = true;
930 return true;
931 }
932
StartMemAllocDumper(const PandaString & dumpFile)933 int Runtime::StartMemAllocDumper(const PandaString &dumpFile)
934 {
935 ASSERT(memAllocDumper_ == nullptr);
936
937 memAllocDumper_ = internalAllocator_->New<tooling::MemoryAllocationDumper>(dumpFile, Runtime::GetCurrent());
938 return 0;
939 }
940
GetClassAndMethod(std::string_view entryPoint,PandaString * className,PandaString * methodName)941 static bool GetClassAndMethod(std::string_view entryPoint, PandaString *className, PandaString *methodName)
942 {
943 size_t pos = entryPoint.find_last_of("::");
944 if (pos == std::string_view::npos) {
945 return false;
946 }
947
948 *className = PandaString(entryPoint.substr(0, pos - 1));
949 *methodName = PandaString(entryPoint.substr(pos + 1));
950
951 return true;
952 }
953
GetStringArrayDescriptor(const LanguageContext & ctx,PandaString * out)954 static const uint8_t *GetStringArrayDescriptor(const LanguageContext &ctx, PandaString *out)
955 {
956 *out = "[";
957 *out += utf::Mutf8AsCString(ctx.GetStringClassDescriptor());
958
959 return utf::CStringAsMutf8(out->c_str());
960 }
961
ResolveEntryPoint(std::string_view entryPoint)962 Expected<Method *, Runtime::Error> Runtime::ResolveEntryPoint(std::string_view entryPoint)
963 {
964 PandaString className;
965 PandaString methodName;
966
967 if (!GetClassAndMethod(entryPoint, &className, &methodName)) {
968 LOG(ERROR, RUNTIME) << "Invalid entry point: " << entryPoint;
969 return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
970 }
971
972 PandaString descriptor;
973 auto classNameBytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &descriptor);
974 auto methodNameBytes = utf::CStringAsMutf8(methodName.c_str());
975
976 Class *cls = nullptr;
977 ClassLinkerContext *context = appContext_.ctx;
978 if (context == nullptr) {
979 context = classLinker_->GetExtension(GetLanguageContext(GetRuntimeType()))->GetBootContext();
980 }
981
982 ManagedThread *thread = ManagedThread::GetCurrent();
983 ScopedManagedCodeThread sa(thread);
984 cls = classLinker_->GetClass(classNameBytes, true, context);
985 if (cls == nullptr) {
986 LOG(ERROR, RUNTIME) << "Cannot find class '" << className << "'";
987 return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
988 }
989
990 LanguageContext ctx = GetLanguageContext(*cls);
991 PandaString stringArrayDescriptor;
992 GetStringArrayDescriptor(ctx, &stringArrayDescriptor);
993
994 Method::Proto proto(Method::Proto::ShortyVector {panda_file::Type(panda_file::Type::TypeId::VOID),
995 panda_file::Type(panda_file::Type::TypeId::REFERENCE)},
996 Method::Proto::RefTypeVector {stringArrayDescriptor});
997
998 auto method = cls->GetDirectMethod(methodNameBytes, proto);
999 if (method == nullptr) {
1000 method = cls->GetDirectMethod(methodNameBytes);
1001 if (method == nullptr) {
1002 LOG(ERROR, RUNTIME) << "Cannot find method '" << entryPoint << "'";
1003 return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
1004 }
1005 }
1006
1007 return method;
1008 }
1009
GetMemoryStatistics()1010 PandaString Runtime::GetMemoryStatistics()
1011 {
1012 return pandaVm_->GetMemStats()->GetStatistics();
1013 }
1014
GetFinalStatistics()1015 PandaString Runtime::GetFinalStatistics()
1016 {
1017 return pandaVm_->GetGCStats()->GetFinalStatistics(pandaVm_->GetHeapManager());
1018 }
1019
NotifyAboutLoadedModules()1020 void Runtime::NotifyAboutLoadedModules()
1021 {
1022 PandaVector<const panda_file::File *> pfs;
1023
1024 classLinker_->EnumerateBootPandaFiles([&pfs](const panda_file::File &pf) {
1025 pfs.push_back(&pf);
1026 return true;
1027 });
1028
1029 for (const auto *pf : pfs) {
1030 GetNotificationManager()->LoadModuleEvent(pf->GetFilename());
1031 }
1032 }
1033
ExtractLanguageContext(const panda_file::File * pf,std::string_view entryPoint)1034 Expected<LanguageContext, Runtime::Error> Runtime::ExtractLanguageContext(const panda_file::File *pf,
1035 std::string_view entryPoint)
1036 {
1037 PandaString className;
1038 PandaString methodName;
1039 if (!GetClassAndMethod(entryPoint, &className, &methodName)) {
1040 LOG(ERROR, RUNTIME) << "Invalid entry point: " << entryPoint;
1041 return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
1042 }
1043
1044 PandaString descriptor;
1045 auto classNameBytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(className.c_str()), &descriptor);
1046 auto methodNameBytes = utf::CStringAsMutf8(methodName.c_str());
1047
1048 auto classId = pf->GetClassId(classNameBytes);
1049 if (!classId.IsValid() || pf->IsExternal(classId)) {
1050 LOG(ERROR, RUNTIME) << "Cannot find class '" << className << "'";
1051 return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
1052 }
1053
1054 panda_file::ClassDataAccessor cda(*pf, classId);
1055 LanguageContext ctx = GetLanguageContext(&cda);
1056 bool found = false;
1057 cda.EnumerateMethods([this, &pf, methodNameBytes, &found, &ctx](panda_file::MethodDataAccessor &mda) {
1058 if (!found && utf::IsEqual(pf->GetStringData(mda.GetNameId()).data, methodNameBytes)) {
1059 found = true;
1060 auto val = mda.GetSourceLang();
1061 if (val) {
1062 ctx = GetLanguageContext(val.value());
1063 }
1064 }
1065 });
1066
1067 if (!found) {
1068 LOG(ERROR, RUNTIME) << "Cannot find method '" << entryPoint << "'";
1069 return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
1070 }
1071
1072 return ctx;
1073 }
1074
CreateApplicationClassLinkerContext(std::string_view filename,std::string_view entryPoint)1075 std::optional<Runtime::Error> Runtime::CreateApplicationClassLinkerContext(std::string_view filename,
1076 std::string_view entryPoint)
1077 {
1078 bool isLoaded = false;
1079 classLinker_->EnumerateBootPandaFiles([&isLoaded, filename](const panda_file::File &pf) {
1080 if (pf.GetFilename() == filename) {
1081 isLoaded = true;
1082 return false;
1083 }
1084 return true;
1085 });
1086
1087 if (isLoaded) {
1088 return {};
1089 }
1090
1091 auto pf = panda_file::OpenPandaFileOrZip(filename);
1092 if (pf == nullptr) {
1093 return Runtime::Error::PANDA_FILE_LOAD_ERROR;
1094 }
1095
1096 auto res = ExtractLanguageContext(pf.get(), entryPoint);
1097 if (!res) {
1098 return res.Error();
1099 }
1100
1101 if (!classLinker_->HasExtension(res.Value())) {
1102 LOG(ERROR, RUNTIME) << "class linker hasn't " << res.Value() << " language extension";
1103 return Runtime::Error::CLASS_LINKER_EXTENSION_NOT_FOUND;
1104 }
1105
1106 auto *ext = classLinker_->GetExtension(res.Value());
1107 appContext_.lang = ext->GetLanguage();
1108 appContext_.ctx = classLinker_->GetAppContext(filename);
1109 if (appContext_.ctx == nullptr) {
1110 auto appFiles = GetPandaFiles();
1111 auto foundIter =
1112 std::find_if(appFiles.begin(), appFiles.end(), [&](auto &appFileName) { return appFileName == filename; });
1113 if (foundIter == appFiles.end()) {
1114 PandaString path(filename);
1115 appFiles.push_back(path);
1116 }
1117 appContext_.ctx = ext->CreateApplicationClassLinkerContext(appFiles);
1118 }
1119
1120 PandaString aotCtx;
1121 appContext_.ctx->EnumeratePandaFiles(compiler::AotClassContextCollector(&aotCtx, options_.IsAotVerifyAbsPath()));
1122 classLinker_->GetAotManager()->SetAppClassContext(aotCtx);
1123
1124 tooling::DebugInf::AddCodeMetaInfo(pf.get());
1125 return {};
1126 }
1127
ExecutePandaFile(std::string_view filename,std::string_view entryPoint,const std::vector<std::string> & args)1128 Expected<int, Runtime::Error> Runtime::ExecutePandaFile(std::string_view filename, std::string_view entryPoint,
1129 const std::vector<std::string> &args)
1130 {
1131 if (options_.IsDistributedProfiling()) {
1132 // Create app name from path to executable file.
1133 std::string_view appName = [](std::string_view path) -> std::string_view {
1134 auto pos = path.find_last_of('/');
1135 return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
1136 }(filename);
1137 StartDProfiler(appName);
1138 }
1139
1140 auto ctxErr = CreateApplicationClassLinkerContext(filename, entryPoint);
1141 if (ctxErr) {
1142 return Unexpected(ctxErr.value());
1143 }
1144
1145 if (pandaVm_->GetLanguageContext().IsEnabledCHA()) {
1146 classLinker_->GetAotManager()->VerifyClassHierarchy();
1147 }
1148
1149 // Check if all input files are either quickened or not
1150 uint32_t quickenedFiles = 0;
1151 uint32_t pandaFiles = 0;
1152 classLinker_->EnumeratePandaFiles([&quickenedFiles, &pandaFiles](const panda_file::File &pf) {
1153 if (pf.GetHeader()->quickenedFlag != 0) {
1154 ++quickenedFiles;
1155 }
1156 pandaFiles++;
1157 return true;
1158 });
1159 if (quickenedFiles != 0 && quickenedFiles != pandaFiles) {
1160 LOG(ERROR, RUNTIME) << "All input files should be either quickened or not. Got " << quickenedFiles
1161 << " quickened files out of " << pandaFiles << " input files.";
1162 classLinker_->EnumeratePandaFiles([](const panda_file::File &pf) {
1163 if (pf.GetHeader()->quickenedFlag != 0) {
1164 LOG(ERROR, RUNTIME) << "File " << pf.GetFilename() << " is quickened";
1165 } else {
1166 LOG(ERROR, RUNTIME) << "File " << pf.GetFilename() << " is not quickened";
1167 }
1168 return true;
1169 });
1170 UNREACHABLE();
1171 }
1172
1173 return Execute(entryPoint, args);
1174 }
1175
Execute(std::string_view entryPoint,const std::vector<std::string> & args)1176 Expected<int, Runtime::Error> Runtime::Execute(std::string_view entryPoint, const std::vector<std::string> &args)
1177 {
1178 auto resolveRes = ResolveEntryPoint(entryPoint);
1179 if (!resolveRes) {
1180 return Unexpected(resolveRes.Error());
1181 }
1182
1183 NotifyAboutLoadedModules();
1184
1185 Method *method = resolveRes.Value();
1186
1187 return pandaVm_->InvokeEntrypoint(method, args);
1188 }
1189
StartDProfiler(std::string_view appName)1190 int Runtime::StartDProfiler(std::string_view appName)
1191 {
1192 if (dprofiler_ != nullptr) {
1193 LOG(ERROR, RUNTIME) << "DProfiller already started";
1194 return -1;
1195 }
1196
1197 dprofiler_ = internalAllocator_->New<DProfiler>(appName, Runtime::GetCurrent());
1198 return 0;
1199 }
1200
StartDebugSession()1201 Runtime::DebugSessionHandle Runtime::StartDebugSession()
1202 {
1203 os::memory::LockHolder<os::memory::Mutex> lock(debugSessionCreationMutex_);
1204
1205 auto session = debugSession_;
1206 if (session) {
1207 return session;
1208 }
1209
1210 session = MakePandaShared<DebugSession>(*this);
1211
1212 debugSession_ = session;
1213
1214 return session;
1215 }
1216
Shutdown()1217 bool Runtime::Shutdown()
1218 {
1219 if (memAllocDumper_ != nullptr) {
1220 internalAllocator_->Delete(memAllocDumper_);
1221 }
1222 pandaVm_->UnloadDebuggerAgent();
1223 debugSession_.reset();
1224 ManagedThread::Shutdown();
1225 return true;
1226 }
1227
ResolveString(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)1228 coretypes::String *Runtime::ResolveString(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
1229 {
1230 auto *pf = caller.GetPandaFile();
1231 return vm->ResolveString(*pf, id);
1232 }
1233
ResolveStringFromCompiledCode(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)1234 coretypes::String *Runtime::ResolveStringFromCompiledCode(PandaVM *vm, const Method &caller,
1235 panda_file::File::EntityId id)
1236 {
1237 auto *pf = caller.GetPandaFile();
1238 return vm->ResolveStringFromCompiledCode(*pf, id);
1239 }
1240
ResolveString(PandaVM * vm,const panda_file::File & pf,panda_file::File::EntityId id,const LanguageContext & ctx)1241 coretypes::String *Runtime::ResolveString(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
1242 const LanguageContext &ctx)
1243 {
1244 coretypes::String *str = vm->GetStringTable()->GetInternalStringFast(pf, id);
1245 if (str != nullptr) {
1246 return str;
1247 }
1248 str = vm->GetStringTable()->GetOrInternInternalString(pf, id, ctx);
1249 return str;
1250 }
1251
ResolveString(PandaVM * vm,const uint8_t * mutf8,uint32_t length,const LanguageContext & ctx)1252 coretypes::String *Runtime::ResolveString(PandaVM *vm, const uint8_t *mutf8, uint32_t length,
1253 const LanguageContext &ctx)
1254 {
1255 return vm->GetStringTable()->GetOrInternString(mutf8, length, ctx);
1256 }
1257
ResolveLiteralArray(PandaVM * vm,const Method & caller,uint32_t id)1258 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const Method &caller, uint32_t id)
1259 {
1260 auto *pf = caller.GetPandaFile();
1261 id = pf->GetLiteralArrays()[id];
1262 LanguageContext ctx = GetLanguageContext(caller);
1263 return ResolveLiteralArray(vm, *pf, id, ctx);
1264 }
1265
GetClassRootForLiteralTag(const ClassLinkerExtension & ext,panda_file::LiteralTag tag) const1266 Class *Runtime::GetClassRootForLiteralTag(const ClassLinkerExtension &ext, panda_file::LiteralTag tag) const
1267 {
1268 switch (tag) {
1269 case panda_file::LiteralTag::ARRAY_U1:
1270 return ext.GetClassRoot(ClassRoot::ARRAY_U1);
1271 case panda_file::LiteralTag::ARRAY_U8:
1272 return ext.GetClassRoot(ClassRoot::ARRAY_U8);
1273 case panda_file::LiteralTag::ARRAY_I8:
1274 return ext.GetClassRoot(ClassRoot::ARRAY_I8);
1275 case panda_file::LiteralTag::ARRAY_U16:
1276 return ext.GetClassRoot(ClassRoot::ARRAY_U16);
1277 case panda_file::LiteralTag::ARRAY_I16:
1278 return ext.GetClassRoot(ClassRoot::ARRAY_I16);
1279 case panda_file::LiteralTag::ARRAY_U32:
1280 return ext.GetClassRoot(ClassRoot::ARRAY_U32);
1281 case panda_file::LiteralTag::ARRAY_I32:
1282 return ext.GetClassRoot(ClassRoot::ARRAY_I32);
1283 case panda_file::LiteralTag::ARRAY_U64:
1284 return ext.GetClassRoot(ClassRoot::ARRAY_U64);
1285 case panda_file::LiteralTag::ARRAY_I64:
1286 return ext.GetClassRoot(ClassRoot::ARRAY_I64);
1287 case panda_file::LiteralTag::ARRAY_F32:
1288 return ext.GetClassRoot(ClassRoot::ARRAY_F32);
1289 case panda_file::LiteralTag::ARRAY_F64:
1290 return ext.GetClassRoot(ClassRoot::ARRAY_F64);
1291 case panda_file::LiteralTag::ARRAY_STRING:
1292 return ext.GetClassRoot(ClassRoot::ARRAY_STRING);
1293 case panda_file::LiteralTag::TAGVALUE:
1294 case panda_file::LiteralTag::BOOL:
1295 case panda_file::LiteralTag::INTEGER:
1296 case panda_file::LiteralTag::FLOAT:
1297 case panda_file::LiteralTag::DOUBLE:
1298 case panda_file::LiteralTag::STRING:
1299 case panda_file::LiteralTag::METHOD:
1300 case panda_file::LiteralTag::GENERATORMETHOD:
1301 case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
1302 case panda_file::LiteralTag::ASYNCMETHOD:
1303 case panda_file::LiteralTag::ACCESSOR:
1304 case panda_file::LiteralTag::NULLVALUE: {
1305 break;
1306 }
1307 default: {
1308 break;
1309 }
1310 }
1311 UNREACHABLE();
1312 return nullptr;
1313 }
1314
1315 /* static */
GetLiteralTagAndValue(const panda_file::File & pf,uint32_t id,panda_file::LiteralTag * tag,panda_file::LiteralDataAccessor::LiteralValue * value)1316 bool Runtime::GetLiteralTagAndValue(const panda_file::File &pf, uint32_t id, panda_file::LiteralTag *tag,
1317 panda_file::LiteralDataAccessor::LiteralValue *value)
1318 {
1319 panda_file::File::EntityId literalArraysId = pf.GetLiteralArraysId();
1320 panda_file::LiteralDataAccessor literalDataAccessor(pf, literalArraysId);
1321 bool result = false;
1322 literalDataAccessor.EnumerateLiteralVals(
1323 panda_file::File::EntityId(id), [tag, value, &result](const panda_file::LiteralDataAccessor::LiteralValue &val,
1324 const panda_file::LiteralTag &tg) {
1325 *tag = tg;
1326 *value = val;
1327 result = true;
1328 });
1329 return result;
1330 }
1331
GetPointerToConstArrayData(const panda_file::File & pf,uint32_t id) const1332 uintptr_t Runtime::GetPointerToConstArrayData(const panda_file::File &pf, uint32_t id) const
1333 {
1334 panda_file::LiteralTag tag;
1335 panda_file::LiteralDataAccessor::LiteralValue value;
1336 if (!GetLiteralTagAndValue(pf, id, &tag, &value)) {
1337 UNREACHABLE();
1338 return 0;
1339 }
1340
1341 auto sp = pf.GetSpanFromId(panda_file::File::EntityId(std::get<uint32_t>(value)));
1342 // first element in the sp is array size, panda_file::helpers::Read move sp pointer to next element
1343 [[maybe_unused]] auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1344 return reinterpret_cast<uintptr_t>(sp.data());
1345 }
1346
ResolveLiteralArray(PandaVM * vm,const panda_file::File & pf,uint32_t id,const LanguageContext & ctx)1347 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const panda_file::File &pf, uint32_t id,
1348 const LanguageContext &ctx)
1349 {
1350 panda_file::LiteralTag tag;
1351 panda_file::LiteralDataAccessor::LiteralValue value;
1352 if (!GetLiteralTagAndValue(pf, id, &tag, &value)) {
1353 return nullptr;
1354 }
1355
1356 auto sp = pf.GetSpanFromId(panda_file::File::EntityId(std::get<uint32_t>(value)));
1357
1358 auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1359 auto ext = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx);
1360
1361 if (tag != panda_file::LiteralTag::ARRAY_STRING) {
1362 return coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), sp.data(), len);
1363 }
1364
1365 // special handling of arrays of strings
1366 auto array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), len);
1367 [[maybe_unused]] HandleScope<ObjectHeader *> scope(ManagedThread::GetCurrent());
1368 VMHandle<coretypes::Array> obj(ManagedThread::GetCurrent(), array);
1369 // NOLINTNEXTLINE(modernize-loop-convert)
1370 for (size_t i = 0; i < len; i++) {
1371 auto strId = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1372 auto str = Runtime::GetCurrent()->ResolveString(vm, pf, panda_file::File::EntityId(strId), ctx);
1373 obj->Set<ObjectHeader *>(i, str);
1374 }
1375 return obj.GetPtr();
1376 }
1377
UpdateProcessState(int state)1378 void Runtime::UpdateProcessState([[maybe_unused]] int state)
1379 {
1380 LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1381 }
1382
RegisterSensitiveThread() const1383 void Runtime::RegisterSensitiveThread() const
1384 {
1385 LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1386 }
1387
CreateDfxController(const RuntimeOptions & options)1388 void Runtime::CreateDfxController(const RuntimeOptions &options)
1389 {
1390 DfxController::Initialize();
1391 DfxController::SetOptionValue(DfxOptionHandler::COMPILER_NULLCHECK, options.GetCompilerNullcheck());
1392 DfxController::SetOptionValue(DfxOptionHandler::REFERENCE_DUMP, options.GetReferenceDump());
1393 DfxController::SetOptionValue(DfxOptionHandler::SIGNAL_CATCHER, options.GetSignalCatcher());
1394 DfxController::SetOptionValue(DfxOptionHandler::SIGNAL_HANDLER, options.GetSignalHandler());
1395 DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGQUIT, options.GetSigquitFlag());
1396 DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR1, options.GetSigusr1Flag());
1397 DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR2, options.GetSigusr2Flag());
1398 DfxController::SetOptionValue(DfxOptionHandler::MOBILE_LOG, options.GetMobileLogFlag());
1399 DfxController::SetOptionValue(DfxOptionHandler::DFXLOG, options.GetDfxLog());
1400
1401 auto compilerNullcheckFlag = DfxController::GetOptionValue(DfxOptionHandler::COMPILER_NULLCHECK);
1402 if (compilerNullcheckFlag == 0) {
1403 panda::compiler::g_options.SetCompilerImplicitNullCheck(false);
1404 }
1405 }
1406
BlockSignals()1407 void Runtime::BlockSignals()
1408 {
1409 sigset_t set;
1410 if (sigemptyset(&set) == -1) {
1411 LOG(ERROR, RUNTIME) << "sigemptyset failed";
1412 return;
1413 }
1414 int rc = 0;
1415 rc += sigaddset(&set, SIGPIPE);
1416 #ifdef PANDA_TARGET_MOBILE
1417 rc += sigaddset(&set, SIGQUIT);
1418 rc += sigaddset(&set, SIGUSR1);
1419 rc += sigaddset(&set, SIGUSR2);
1420 #endif // PANDA_TARGET_MOBILE
1421 if (rc < 0) {
1422 LOG(ERROR, RUNTIME) << "sigaddset failed";
1423 return;
1424 }
1425
1426 if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
1427 LOG(ERROR, RUNTIME) << "g_PandaThreadSigmask failed";
1428 }
1429 }
1430
DumpForSigQuit(std::ostream & os)1431 void Runtime::DumpForSigQuit(std::ostream &os)
1432 {
1433 os << "\n";
1434 os << "-> Dump class loaders\n";
1435 classLinker_->EnumerateContextsForDump(
1436 [](ClassLinkerContext *ctx, std::ostream &stream, ClassLinkerContext *parent) {
1437 ctx->Dump(stream);
1438 return ctx->FindClassLoaderParent(parent);
1439 },
1440 os);
1441 os << "\n";
1442
1443 // dump GC
1444 os << "-> Dump GC\n";
1445 os << GetFinalStatistics();
1446 os << "\n";
1447
1448 // dump memory management
1449 os << "-> Dump memory management\n";
1450 os << GetMemoryStatistics();
1451 os << "\n";
1452
1453 // dump PandaVM
1454 os << "-> Dump Ark VM\n";
1455 pandaVm_->DumpForSigQuit(os);
1456 os << "\n";
1457
1458 WRITE_RELAYOUT_PROFILE_DATA();
1459 }
1460
InitNonZygoteOrPostFork(bool isSystemServer,const char * isa,const std::function<void ()> & initHook,bool profileSystemServer)1461 void Runtime::InitNonZygoteOrPostFork(bool isSystemServer, [[maybe_unused]] const char *isa,
1462 const std::function<void()> &initHook, [[maybe_unused]] bool profileSystemServer)
1463 {
1464 isZygote_ = false;
1465
1466 // NOTE(00510180): wait NativeBridge ready
1467
1468 // NOTE(00510180): wait profile ready
1469
1470 // NOTE(00510180): wait ThreadPool ready
1471
1472 // NOTE(00510180): wait ResetGcPerformanceInfo() ready
1473
1474 pandaVm_->PreStartup();
1475
1476 initHook();
1477
1478 mem::GcHung::InitPostFork(isSystemServer);
1479 }
1480
PreZygoteFork()1481 void Runtime::PreZygoteFork()
1482 {
1483 pandaVm_->PreZygoteFork();
1484 }
1485
PostZygoteFork()1486 void Runtime::PostZygoteFork()
1487 {
1488 pandaVm_->PostZygoteFork();
1489 }
1490
1491 // Returns true if profile saving is enabled. GetJit() will be not null in this case.
SaveProfileInfo() const1492 bool Runtime::SaveProfileInfo() const
1493 {
1494 return saveProfilingInfo_;
1495 }
1496
CheckOptionsFromOs() const1497 void Runtime::CheckOptionsFromOs() const
1498 {
1499 #if !defined(PANDA_QEMU_BUILD) && !defined(PANDA_TARGET_MOBILE)
1500 // for qemu-aarch64 we will get 32 from GetCacheLineSize()
1501 // for native arm and qemu-arm we will get 0 from GetCacheLineSize()
1502 ASSERT(panda::CACHE_LINE_SIZE == os::mem::GetCacheLineSize());
1503 #endif
1504 }
1505
1506 } // namespace panda
1507