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