• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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