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