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