• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/include/runtime.h"
17 
18 #include "compiler_options.h"
19 
20 #include <algorithm>
21 #include <cstdint>
22 #include <cstdio>
23 #include <memory>
24 #include <string>
25 #include <string_view>
26 
27 #include "assembler/assembly-literals.h"
28 #include "core/core_language_context.h"
29 #include "intrinsics.h"
30 #include "libpandabase/events/events.h"
31 #include "libpandabase/mem/mem_config.h"
32 #include "libpandabase/mem/pool_manager.h"
33 #include "libpandabase/os/native_stack.h"
34 #include "libpandabase/os/thread.h"
35 #include "libpandabase/utils/arena_containers.h"
36 #include "libpandabase/utils/logger.h"
37 #include "libpandabase/utils/utf.h"
38 #include "libpandafile/file-inl.h"
39 #include "libpandafile/literal_data_accessor-inl.h"
40 #include "libpandafile/proto_data_accessor-inl.h"
41 #include "plugins.h"
42 #include "runtime/cha.h"
43 #include "runtime/compiler.h"
44 #include "runtime/dprofiler/dprofiler.h"
45 #include "runtime/entrypoints/entrypoints.h"
46 #include "runtime/include/class_linker_extension.h"
47 #include "runtime/include/coretypes/array-inl.h"
48 #include "runtime/include/coretypes/string.h"
49 #include "runtime/include/language_context.h"
50 #include "runtime/include/locks.h"
51 #include "runtime/include/runtime_notification.h"
52 #include "runtime/include/thread.h"
53 #include "runtime/include/thread_scopes.h"
54 #include "runtime/include/tooling/debug_inf.h"
55 #include "runtime/handle_scope.h"
56 #include "runtime/handle_scope-inl.h"
57 #include "mem/refstorage/reference_storage.h"
58 #include "runtime/mem/gc/gc_stats.h"
59 #include "runtime/mem/gc/stw-gc/stw-gc.h"
60 #include "runtime/mem/heap_manager.h"
61 #include "runtime/mem/memory_manager.h"
62 #include "runtime/mem/internal_allocator-inl.h"
63 #include "runtime/mem/gc/gc-hung/gc_hung.h"
64 #include "runtime/include/panda_vm.h"
65 #include "runtime/tooling/debugger.h"
66 #include "runtime/include/file_manager.h"
67 #include "runtime/methodtrace/trace.h"
68 #include "trace/trace.h"
69 #include "verification/cache/file_entity_cache.h"
70 #include "verification/cache/results_cache.h"
71 #include "verification/config/config_load.h"
72 #include "verification/config/context/context.h"
73 #include "verification/jobs/cache.h"
74 #include "verification/jobs/thread_pool.h"
75 #include "verification/type/type_systems.h"
76 
77 namespace panda {
78 
79 using std::unique_ptr;
80 
81 Runtime *Runtime::instance = nullptr;
82 RuntimeOptions Runtime::options_;    // NOLINT(fuchsia-statically-constructed-objects)
83 std::string Runtime::runtime_type_;  // NOLINT(fuchsia-statically-constructed-objects)
84 os::memory::Mutex Runtime::mutex;    // NOLINT(fuchsia-statically-constructed-objects)
85 
86 const LanguageContextBase *ctxs_js_runtime = nullptr;  // Deprecated. Only for capability with ets_runtime.
87 
88 class RuntimeInternalAllocator {
89 public:
Create(bool use_malloc_for_internal_allocation)90     static mem::InternalAllocatorPtr Create(bool use_malloc_for_internal_allocation)
91     {
92         ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() == nullptr);
93 
94         mem_stats_s_ = new (std::nothrow) mem::MemStatsType();
95         ASSERT(mem_stats_s_ != nullptr);
96 
97         if (use_malloc_for_internal_allocation) {
98             internal_allocator_s_ = new (std::nothrow)
99                 mem::InternalAllocatorT<mem::InternalAllocatorConfig::MALLOC_ALLOCATOR>(mem_stats_s_);
100         } else {
101             internal_allocator_s_ = new (std::nothrow)
102                 mem::InternalAllocatorT<mem::InternalAllocatorConfig::PANDA_ALLOCATORS>(mem_stats_s_);
103         }
104         ASSERT(internal_allocator_s_ != nullptr);
105         mem::InternalAllocator<>::InitInternalAllocatorFromRuntime(
106             static_cast<mem::Allocator *>(internal_allocator_s_));
107 
108         return internal_allocator_s_;
109     }
110 
Finalize()111     static void Finalize()
112     {
113         internal_allocator_s_->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 *>(internal_allocator_s_);
123         internal_allocator_s_ = nullptr;
124 
125         if (daemon_memory_leak_threshold_ == 0) {
126             // One more check that we don't have memory leak in internal allocator.
127             ASSERT(mem_stats_s_->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(mem_stats_s_->GetFootprint(SpaceType::SPACE_TYPE_INTERNAL) <= daemon_memory_leak_threshold_);
131         }
132         delete mem_stats_s_;
133         mem_stats_s_ = nullptr;
134     }
135 
Get()136     static mem::InternalAllocatorPtr Get()
137     {
138         ASSERT(internal_allocator_s_ != nullptr);
139         return internal_allocator_s_;
140     }
141 
SetDaemonMemoryLeakThreshold(uint32_t daemon_memory_leak_threshold)142     static void SetDaemonMemoryLeakThreshold(uint32_t daemon_memory_leak_threshold)
143     {
144         daemon_memory_leak_threshold_ = daemon_memory_leak_threshold;
145     }
146 
147 private:
148     static mem::MemStatsType *mem_stats_s_;
149     static mem::InternalAllocatorPtr internal_allocator_s_;  // NOLINT(fuchsia-statically-constructed-objects)
150     static uint32_t daemon_memory_leak_threshold_;
151 };
152 
153 uint32_t RuntimeInternalAllocator::daemon_memory_leak_threshold_ = 0;
154 
155 mem::MemStatsType *RuntimeInternalAllocator::mem_stats_s_ = nullptr;
156 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
157 mem::InternalAllocatorPtr RuntimeInternalAllocator::internal_allocator_s_ = nullptr;
158 
DebugSession(Runtime & runtime)159 Runtime::DebugSession::DebugSession(Runtime &runtime)
160     : runtime_(runtime),
161       is_jit_enabled_(runtime.IsJitEnabled()),
162       lock_(runtime.debug_session_uniqueness_mutex_),
163       debugger_()
164 {
165     ASSERT(runtime_.is_debug_mode_);
166     runtime_.ForceDisableJit();
167     debugger_ = MakePandaUnique<tooling::Debugger>(&runtime_);
168 }
169 
~DebugSession()170 Runtime::DebugSession::~DebugSession()
171 {
172     debugger_.reset();
173     if (is_jit_enabled_) {
174         runtime_.ForceEnableJit();
175     }
176 }
177 
GetDebugger()178 tooling::DebugInterface &Runtime::DebugSession::GetDebugger()
179 {
180     return *debugger_;
181 }
182 
183 // all GetLanguageContext(...) methods should be based on this one
GetLanguageContext(panda_file::SourceLang lang)184 LanguageContext Runtime::GetLanguageContext(panda_file::SourceLang lang)
185 {
186     if (ctxs_js_runtime != nullptr) {
187         // Deprecated. Only for capability with ets_runtime.
188         return LanguageContext(ctxs_js_runtime);
189     }
190 
191     auto *ctx = plugins::GetLanguageContextBase(lang);
192     ASSERT(ctx != nullptr);
193     return LanguageContext(ctx);
194 }
195 
GetLanguageContext(const Method & method)196 LanguageContext Runtime::GetLanguageContext(const Method &method)
197 {
198     // Check class source lang
199     auto *cls = method.GetClass();
200     if (cls != nullptr) {
201         return GetLanguageContext(cls->GetSourceLang());
202     }
203 
204     panda_file::MethodDataAccessor mda(*method.GetPandaFile(), method.GetFileId());
205     auto res = mda.GetSourceLang();
206     return GetLanguageContext(res.value());
207 }
208 
GetLanguageContext(const Class & cls)209 LanguageContext Runtime::GetLanguageContext(const Class &cls)
210 {
211     return GetLanguageContext(cls.GetSourceLang());
212 }
213 
GetLanguageContext(const BaseClass & cls)214 LanguageContext Runtime::GetLanguageContext(const BaseClass &cls)
215 {
216     return GetLanguageContext(cls.GetSourceLang());
217 }
218 
GetLanguageContext(panda_file::ClassDataAccessor * cda)219 LanguageContext Runtime::GetLanguageContext(panda_file::ClassDataAccessor *cda)
220 {
221     auto res = cda->GetSourceLang();
222     if (res) {
223         return GetLanguageContext(res.value());
224     }
225 
226     return GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
227 }
228 
GetLanguageContext(const std::string & runtime_type)229 LanguageContext Runtime::GetLanguageContext(const std::string &runtime_type)
230 {
231     return GetLanguageContext(plugins::RuntimeTypeToLang(runtime_type));
232 }
233 
234 /* static */
CreateInstance(const RuntimeOptions & options,mem::InternalAllocatorPtr internal_allocator)235 bool Runtime::CreateInstance(const RuntimeOptions &options, mem::InternalAllocatorPtr internal_allocator)
236 {
237     Locks::Initialize();
238 
239     if (options.WasSetEventsOutput()) {
240         Events::Create(options.GetEventsOutput(), options.GetEventsFile());
241     }
242 
243     {
244         os::memory::LockHolder<os::memory::Mutex> lock(mutex);
245 
246         if (instance != nullptr) {
247             return false;
248         }
249 
250         instance = new Runtime(options, internal_allocator);
251     }
252 
253     return true;
254 }
255 
CreateMemorySpaces(const RuntimeOptions & options)256 inline bool CreateMemorySpaces(const RuntimeOptions &options)
257 {
258     uint32_t min_free_percentage = options.GetMinHeapFreePercentage();
259     uint32_t max_free_percentage = options.GetMaxHeapFreePercentage();
260     if (min_free_percentage > PERCENT_100_U32) {
261         LOG(ERROR, RUNTIME) << "Incorrect minimum free heap size percentage (min-free-percentage="
262                             << min_free_percentage << "), 0 <= min-free-percentage <= 100";
263         return false;
264     }
265     if (max_free_percentage > PERCENT_100_U32) {
266         LOG(ERROR, RUNTIME) << "Incorrect maximum free heap size percentage (max-free-percentage="
267                             << max_free_percentage << "), 0 <= max-free-percentage <= 100";
268         return false;
269     }
270     if (min_free_percentage > max_free_percentage) {
271         LOG(ERROR, RUNTIME) << "Minimum free heap size percentage(min-free-percentage=" << min_free_percentage
272                             << ") must be <= maximum free heap size percentage (max-free-percentage="
273                             << max_free_percentage << ")";
274         return false;
275     }
276     size_t initial_object_size = options.GetInitHeapSizeLimit();
277     size_t max_object_size = options.GetHeapSizeLimit();
278     bool was_set_initial_object_size = options.WasSetInitHeapSizeLimit();
279     bool was_set_max_object_size = options.WasSetHeapSizeLimit();
280     if (!was_set_initial_object_size && was_set_max_object_size) {
281         initial_object_size = max_object_size;
282     } else if (initial_object_size > max_object_size) {
283         if (was_set_initial_object_size && !was_set_max_object_size) {
284             // Initial object heap size was set more default maximum object heap size, so set maximum heap size as
285             // initial heap size
286             max_object_size = initial_object_size;
287         } else {  // In this case user set initial object heap size more maximum object heap size explicitly
288             LOG(ERROR, RUNTIME) << "Initial heap size (" << initial_object_size << ") must be <= max heap size ("
289                                 << max_object_size << ")";
290             return false;
291         }
292     }
293     initial_object_size =
294         std::max(AlignDown(initial_object_size, PANDA_POOL_ALIGNMENT_IN_BYTES), PANDA_POOL_ALIGNMENT_IN_BYTES);
295     max_object_size =
296         std::max(AlignDown(max_object_size, PANDA_POOL_ALIGNMENT_IN_BYTES), PANDA_POOL_ALIGNMENT_IN_BYTES);
297     // Initialize memory spaces sizes
298     mem::MemConfig::Initialize(max_object_size, options.GetInternalMemorySizeLimit(),
299                                options.GetCompilerMemorySizeLimit(), options.GetCodeCacheSizeLimit(),
300                                initial_object_size);
301     PoolManager::Initialize();
302     return true;
303 }
304 
305 // Deprecated. Only for capability with ets_runtime.
Create(const RuntimeOptions & options,const std::vector<LanguageContextBase * > & ctxs)306 bool Runtime::Create(const RuntimeOptions &options, const std::vector<LanguageContextBase *> &ctxs)
307 {
308     ctxs_js_runtime = ctxs.front();
309     return Runtime::Create(options);
310 }
311 
312 /* static */
Create(const RuntimeOptions & options)313 bool Runtime::Create(const RuntimeOptions &options)
314 {
315     if (instance != nullptr) {
316         return false;
317     }
318 
319     const_cast<RuntimeOptions &>(options).InitializeRuntimeSpacesAndType();
320     trace::ScopedTrace scoped_trace("Runtime::Create");
321 
322     if (!CreateMemorySpaces(options)) {
323         LOG(ERROR, RUNTIME) << "Failed to create memory spaces for runtime";
324         return false;
325     }
326 
327     mem::InternalAllocatorPtr internal_allocator =
328         RuntimeInternalAllocator::Create(options.UseMallocForInternalAllocations());
329 
330     BlockSignals();
331 
332     CreateInstance(options, internal_allocator);
333 
334     if (instance == nullptr) {
335         LOG(ERROR, RUNTIME) << "Failed to create runtime instance";
336         return false;
337     }
338 
339     if (!instance->Initialize()) {
340         LOG(ERROR, RUNTIME) << "Failed to initialize runtime";
341         delete instance;
342         instance = nullptr;
343         return false;
344     }
345 
346     instance->GetPandaVM()->StartGC();
347 
348     auto *thread = ManagedThread::GetCurrent();
349     instance->GetNotificationManager()->VmStartEvent();
350     instance->GetNotificationManager()->VmInitializationEvent(thread);
351     instance->GetNotificationManager()->ThreadStartEvent(thread);
352 
353     return true;
354 }
355 
GetCurrent()356 Runtime *Runtime::GetCurrent()
357 {
358     return instance;
359 }
360 
361 /* static */
DestroyUnderLockHolder()362 bool Runtime::DestroyUnderLockHolder()
363 {
364     os::memory::LockHolder<os::memory::Mutex> lock(mutex);
365 
366     if (instance == nullptr) {
367         return false;
368     }
369 
370     if (!instance->Shutdown()) {
371         LOG(ERROR, RUNTIME) << "Failed to shutdown runtime";
372         return false;
373     }
374     if (GetOptions().WasSetEventsOutput()) {
375         Events::Destroy();
376     }
377 
378     /**
379      * NOTE: Users threads can call log after destroying Runtime. We can't control these
380      *       when they are in NATIVE_CODE mode because we don't destroy logger
381      * Logger::Destroy();
382      */
383 
384     panda::Logger::Sync();
385     delete instance;
386     instance = nullptr;
387     panda::mem::MemConfig::Finalize();
388 
389     return true;
390 }
391 
392 /* static */
Destroy()393 bool Runtime::Destroy()
394 {
395     if (instance == nullptr) {
396         return false;
397     }
398 
399     trace::ScopedTrace scoped_trace("Runtime shutdown");
400 
401     // when signal start, but no signal stop tracing, should stop it
402     if (Trace::is_tracing) {
403         Trace::StopTracing();
404     }
405 
406     instance->GetNotificationManager()->VmDeathEvent();
407 
408     instance->GetPandaVM()->UninitializeThreads();
409     // Stop GC after UninitializeThreads because
410     // UninitializeThreads may execute managed code which
411     // uses barriers
412     instance->GetPandaVM()->StopGC();
413 
414     // Destroy compiler first to make sure compile memleak doesn't occur
415     auto compiler = instance->GetPandaVM()->GetCompiler();
416     if (compiler != nullptr) {
417         // ecmascript doesn't have compiler
418         compiler->Destroy();
419     }
420 
421     const auto &verif_options = instance->GetVerificationOptions();
422     if (verif_options.IsEnabled()) {
423         verifier::ThreadPool::Destroy();
424         verifier::TypeSystems::Destroy();
425         verifier::VerificationResultCache::Destroy(verif_options.Cache.UpdateOnExit);
426     }
427 
428     DestroyUnderLockHolder();
429     RuntimeInternalAllocator::Destroy();
430 
431     return true;
432 }
433 
InitializeVerificationResultCache()434 void Runtime::InitializeVerificationResultCache()
435 {
436     const auto &verif_options = GetVerificationOptions();
437     if (verif_options.IsEnabled()) {
438         size_t num_threads = verif_options.VerificationThreads;
439         verifier::TypeSystems::Initialize(num_threads);
440         verifier::ThreadPool::Initialize(internal_allocator_, num_threads);
441 
442         const std::string &cache_file = verif_options.Cache.File;
443         if (!cache_file.empty()) {
444             verifier::VerificationResultCache::Initialize(cache_file);
445         }
446     }
447 }
448 
449 /* static */
Halt(int32_t status)450 void Runtime::Halt(int32_t status)
451 {
452     Runtime *runtime = Runtime::GetCurrent();
453     if (runtime != nullptr && runtime->exit_ != nullptr) {
454         runtime->exit_(status);
455     }
456 
457     // _exit is safer to call because it guarantees a safe
458     // completion in case of multi-threading as static destructors aren't called
459     _exit(status);
460 }
461 
462 /* static */
Abort(const char * message)463 void Runtime::Abort(const char *message /* = nullptr */)
464 {
465     Runtime *runtime = Runtime::GetCurrent();
466     if (runtime != nullptr && runtime->abort_ != nullptr) {
467         runtime->abort_();
468     }
469 
470     std::cerr << "Runtime::Abort: " << ((message != nullptr) ? message : "") << std::endl;
471     std::abort();
472 }
473 
GetMainRuntimeType(const RuntimeOptions & options)474 std::string GetMainRuntimeType(const RuntimeOptions &options)
475 {
476     if (options.WasSetRuntimeType()) {
477         return options.GetRuntimeType();
478     }
479 
480     std::vector<std::string> load_runtimes = options.GetLoadRuntimes();
481     for (const std::string &str_runtime : load_runtimes) {
482         // Choose first non-core runtime.
483         if (str_runtime != "core") {
484             return str_runtime;
485         }
486     }
487 
488     return "core";
489 }
490 
Runtime(const RuntimeOptions & options,mem::InternalAllocatorPtr internal_allocator)491 Runtime::Runtime(const RuntimeOptions &options, mem::InternalAllocatorPtr internal_allocator)
492     : internal_allocator_(internal_allocator),
493       notification_manager_(new RuntimeNotificationManager(internal_allocator_)),
494       cha_(new ClassHierarchyAnalysis),
495       zygote_no_threads_(false)
496 {
497     Runtime::runtime_type_ = GetMainRuntimeType(options);
498     Runtime::options_ = options;
499 
500     auto spaces = GetOptions().GetLoadRuntimes();
501 
502     std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
503     extensions.reserve(spaces.size());
504 
505     for (const auto &space : spaces) {
506         extensions.push_back(GetLanguageContext(space).CreateClassLinkerExtension());
507     }
508 
509     class_linker_ = new ClassLinker(internal_allocator_, std::move(extensions));
510 
511     save_profiling_info_ = options_.IsCompilerEnableJit() && options_.IsProfilesaverEnabled();
512 
513 #ifdef PANDA_COMPILER_ENABLE
514     // TODO(maksenov): Enable JIT for debug mode
515     is_jit_enabled_ = !this->IsDebugMode() && Runtime::GetOptions().IsCompilerEnableJit();
516 #else
517     is_jit_enabled_ = false;
518 #endif
519 
520     VerificationOptions_.Initialize(options_);
521     InitializeVerificationResultCache();
522 
523     is_zygote_ = options_.IsStartAsZygote();
524 
525 #ifdef PANDA_ENABLE_RELAYOUT_PROFILE
526     relayout_profiler_ = internal_allocator_->New<RelayoutProfiler>();
527 #endif
528 }
529 
~Runtime()530 Runtime::~Runtime()
531 {
532     VerificationOptions_.Destroy();
533     panda::verifier::debug::DebugContext::Destroy();
534     trace::ScopedTrace scoped_trace("Delete state");
535 
536     delete cha_;
537     delete class_linker_;
538     if (dprofiler_ != nullptr) {
539         internal_allocator_->Delete(dprofiler_);
540     }
541     delete notification_manager_;
542 
543     if (panda_vm_ != nullptr) {
544         internal_allocator_->Delete(panda_vm_);
545         /* @sync 1
546          * @description: This point is right after runtime deastroys panda VM.
547          * */
548     }
549 
550 #ifdef PANDA_ENABLE_RELAYOUT_PROFILE
551     if (relayout_profiler_ != nullptr) {
552         internal_allocator_->Delete(relayout_profiler_);
553     }
554 #endif
555     // crossing map is shared by different VMs.
556     mem::CrossingMapSingleton::Destroy();
557 
558     RuntimeInternalAllocator::Finalize();
559     PoolManager::Finalize();
560 }
561 
GetPandaFilesList(const std::vector<std::string> & stdvec)562 static PandaVector<PandaString> GetPandaFilesList(const std::vector<std::string> &stdvec)
563 {
564     PandaVector<PandaString> res;
565     for (const auto &i : stdvec) {
566         // NOLINTNEXTLINE(readability-redundant-string-cstr)
567         res.push_back(i.c_str());
568     }
569 
570     return res;
571 }
572 
GetBootPandaFiles()573 PandaVector<PandaString> Runtime::GetBootPandaFiles()
574 {
575     // NOLINTNEXTLINE(readability-redundant-string-cstr)
576     const auto &boot_panda_files = GetPandaFilesList(options_.GetBootPandaFiles());
577     return boot_panda_files;
578 }
579 
GetPandaFiles()580 PandaVector<PandaString> Runtime::GetPandaFiles()
581 {
582     // NOLINTNEXTLINE(readability-redundant-string-cstr)
583     const auto &app_panda_files = GetPandaFilesList(options_.GetPandaFiles());
584     return app_panda_files;
585 }
586 
LoadBootPandaFiles(panda_file::File::OpenMode open_mode)587 bool Runtime::LoadBootPandaFiles(panda_file::File::OpenMode open_mode)
588 {
589     // NOLINTNEXTLINE(readability-redundant-string-cstr)
590     const auto &boot_panda_files = options_.GetBootPandaFiles();
591     for (const auto &name : boot_panda_files) {
592         if (!FileManager::LoadAbcFile(name, open_mode)) {
593 #ifdef PANDA_PRODUCT_BUILD
594             LOG(FATAL, RUNTIME) << "Load boot panda file failed: " << name;
595 #else
596             LOG(ERROR, RUNTIME) << "Load boot panda file failed: " << name;
597 #endif  // PANDA_PRODUCT_BUILD
598             return false;
599         }
600     }
601 
602     return true;
603 }
604 
SetDaemonMemoryLeakThreshold(uint32_t daemon_memory_leak_threshold)605 void Runtime::SetDaemonMemoryLeakThreshold(uint32_t daemon_memory_leak_threshold)
606 {
607     RuntimeInternalAllocator::SetDaemonMemoryLeakThreshold(daemon_memory_leak_threshold);
608 }
609 
GetGCType(const RuntimeOptions & options,panda_file::SourceLang lang)610 mem::GCType Runtime::GetGCType(const RuntimeOptions &options, panda_file::SourceLang lang)
611 {
612     auto gc_type = panda::mem::GCTypeFromString(options.GetGcType(plugins::LangToRuntimeType(lang)));
613     if (options.IsNoAsyncJit()) {
614         // With no-async-jit we can force compilation inside of c2i bridge (we have IncrementHotnessCounter there)
615         // and it can trigger GC which can move objects which are arguments for the method
616         // because StackWalker ignores c2i frame
617         return (gc_type != panda::mem::GCType::EPSILON_GC) ? (panda::mem::GCType::STW_GC) : gc_type;
618     }
619     return gc_type;
620 }
621 
LoadVerificationConfig()622 bool Runtime::LoadVerificationConfig()
623 {
624     const auto &options = GetVerificationOptions();
625     return !options.IsEnabled() || verifier::config::LoadConfig(options.ConfigFile);
626 }
627 
CreatePandaVM(std::string_view runtime_type)628 bool Runtime::CreatePandaVM(std::string_view runtime_type)
629 {
630     ManagedThread::Initialize();
631 
632     panda_vm_ = PandaVM::Create(this, options_, runtime_type);
633     if (panda_vm_ == nullptr) {
634         LOG(ERROR, RUNTIME) << "Failed to create panda vm";
635         return false;
636     }
637 
638     panda_file::File::OpenMode open_mode = GetLanguageContext(GetRuntimeType()).GetBootPandaFilesOpenMode();
639     bool load_boot_panda_files_is_failed = options_.ShouldLoadBootPandaFiles() && !LoadBootPandaFiles(open_mode);
640     if (load_boot_panda_files_is_failed) {
641         LOG(ERROR, RUNTIME) << "Failed to load boot panda files";
642         return false;
643     }
644 
645     auto aot_boot_ctx = class_linker_->GetClassContextForAot();
646     if (options_.GetPandaFiles().empty() && !options_.IsStartAsZygote()) {
647         // Main from panda.cpp puts application file into boot panda files as the last element.
648         // During AOT compilation of boot files no application panda files were used.
649         auto idx = aot_boot_ctx.find_last_of(':');
650         if (idx == std::string::npos) {
651             // Only application file is in aot_boot_ctx
652             class_linker_->GetAotManager()->SetAppClassContext(aot_boot_ctx);
653             aot_boot_ctx = "";
654         } else {
655             // Last file is an application
656             class_linker_->GetAotManager()->SetAppClassContext(aot_boot_ctx.substr(idx + 1));
657             aot_boot_ctx = aot_boot_ctx.substr(0, idx);
658         }
659     }
660     class_linker_->GetAotManager()->SetBootClassContext(aot_boot_ctx);
661     if (panda_vm_->GetLanguageContext().IsEnabledCHA()) {
662         class_linker_->GetAotManager()->VerifyClassHierarchy(true);
663     }
664 
665     notification_manager_->SetRendezvous(panda_vm_->GetRendezvous());
666 
667     return true;
668 }
669 
InitializePandaVM()670 bool Runtime::InitializePandaVM()
671 {
672     // temporary solution, see #7225
673     if (!options_.IsRuntimeCompressedStringsEnabled()) {
674         LOG(FATAL, RUNTIME) << "Non compressed strings is not supported";
675     }
676 
677     if (!class_linker_->Initialize(options_.IsRuntimeCompressedStringsEnabled())) {
678         LOG(ERROR, RUNTIME) << "Failed to initialize class loader";
679         return false;
680     }
681 
682     if (panda_vm_->ShouldEnableDebug()) {
683         SetDebugMode(true);
684         StartDebugSession();
685     }
686 
687     // needed because VM may have to verify some classes during initialization (but see #7616)
688     if (GetVerificationOptions().IsEnabled()) {
689         verifier::ThreadPool::GetCache()->FastAPI().ProcessFiles(class_linker_->GetBootPandaFiles());
690     }
691 
692     if (!panda_vm_->Initialize()) {
693         LOG(ERROR, RUNTIME) << "Failed to initialize panda vm";
694         return false;
695     }
696 
697     return true;
698 }
699 
HandleAotOptions()700 bool Runtime::HandleAotOptions()
701 {
702     auto aot_files = options_.GetAotFiles();
703     const auto &name = options_.GetAotFile();
704     if (!name.empty()) {
705         aot_files.push_back(name);
706     }
707     if (!aot_files.empty()) {
708         for (auto &fname : aot_files) {
709             auto res = FileManager::LoadAnFile(fname, true);
710             if (!res) {
711                 LOG(FATAL, AOT) << "Failed to load AoT file: " << res.Error();
712             }
713             if (!res.Value()) {
714                 LOG(FATAL, AOT) << "Failed to load '" << fname << "' with unknown reason";
715             }
716         }
717     }
718 
719     return true;
720 }
721 
HandleJitOptions()722 void Runtime::HandleJitOptions()
723 {
724     bool enable_np_handler = options_.IsCompilerEnableJit() && panda::compiler::options.IsCompilerImplicitNullCheck();
725     if (GetClassLinker()->GetAotManager()->HasAotFiles()) {
726         if (options_.IsNoAsyncJit()) {
727             LOG(FATAL, AOT) << "We can't use the option --no-async-jit=true with AOT";
728         }
729         enable_np_handler = true;
730     }
731 }
732 
CheckOptionsConsistency()733 bool Runtime::CheckOptionsConsistency()
734 {
735     {
736         auto value = options_.GetResolveStringAotThreshold();
737         auto limit = RuntimeInterface::RESOLVE_STRING_AOT_COUNTER_LIMIT;
738         if (value >= limit) {
739             LOG(ERROR, RUNTIME) << "--resolve-string-aot-threshold value (" << value << ") is "
740                                 << ((value == limit) ? "equal to " : "greater than ") << limit
741                                 << ", ResolveString optimization won't be applied to AOT-compiled code. "
742                                 << "Consider value lower than " << limit << " to enable the optimization.";
743         }
744     }
745     return true;
746 }
747 
SetPandaPath()748 void Runtime::SetPandaPath()
749 {
750     PandaVector<PandaString> app_panda_files = GetPandaFiles();
751     for (size_t i = 0; i < app_panda_files.size(); ++i) {
752         panda_path_string_ += PandaStringToStd(app_panda_files[i]);
753         if (i != app_panda_files.size() - 1) {
754             panda_path_string_ += ":";
755         }
756     }
757 }
758 
Initialize()759 bool Runtime::Initialize()
760 {
761     trace::ScopedTrace scoped_trace("Runtime::Initialize");
762 
763     if (!CheckOptionsConsistency()) {
764         return false;
765     }
766 
767     if (!LoadVerificationConfig()) {
768         return false;
769     }
770 
771     if (!CreatePandaVM(GetRuntimeType())) {
772         return false;
773     }
774 
775 #if defined(PANDA_COMPILER_CFI) && !defined(NDEBUG)
776     if (!compiler::options.WasSetCompilerEmitDebugInfo()) {
777         compiler::options.SetCompilerEmitDebugInfo(true);
778     }
779 #endif
780 
781     // We must load AOT file before InitializePandaVM, because during initialization, code execution may be called.
782     if (!HandleAotOptions()) {
783         return false;
784     }
785 
786     if (!InitializePandaVM()) {
787         return false;
788     }
789 
790     ManagedThread *thread = ManagedThread::GetCurrent();
791     class_linker_->InitializeRoots(thread);
792     auto ext = GetClassLinker()->GetExtension(GetLanguageContext(GetRuntimeType()));
793     if (ext != nullptr) {
794         thread->SetStringClassPtr(ext->GetClassRoot(ClassRoot::STRING));
795     }
796 
797     fingerPrint_ = ConvertToString(options_.GetFingerprint());
798 
799     HandleJitOptions();
800 
801     SetPandaPath();
802 
803     if (!panda_vm_->InitializeFinish()) {
804         LOG(ERROR, RUNTIME) << "Failed to finish panda vm initialization";
805         return false;
806     }
807 
808     if (IsDebugMode()) {
809         panda_vm_->LoadDebuggerAgent();
810     }
811 
812 #ifdef PANDA_TARGET_MOBILE
813     mem::GcHung::InitPreFork(true);
814 #else
815     mem::GcHung::InitPreFork(false);
816 #endif  // PANDA_TARGET_MOBILE
817 
818     is_initialized_ = true;
819     return true;
820 }
821 
GetClassAndMethod(std::string_view entry_point,PandaString * class_name,PandaString * method_name)822 static bool GetClassAndMethod(std::string_view entry_point, PandaString *class_name, PandaString *method_name)
823 {
824     size_t pos = entry_point.find_last_of("::");
825     if (pos == std::string_view::npos) {
826         return false;
827     }
828 
829     *class_name = PandaString(entry_point.substr(0, pos - 1));
830     *method_name = PandaString(entry_point.substr(pos + 1));
831 
832     return true;
833 }
834 
GetStringArrayDescriptor(const LanguageContext & ctx,PandaString * out)835 static const uint8_t *GetStringArrayDescriptor(const LanguageContext &ctx, PandaString *out)
836 {
837     *out = "[";
838     *out += utf::Mutf8AsCString(ctx.GetStringClassDescriptor());
839 
840     return utf::CStringAsMutf8(out->c_str());
841 }
842 
ResolveEntryPoint(std::string_view entry_point)843 Expected<Method *, Runtime::Error> Runtime::ResolveEntryPoint(std::string_view entry_point)
844 {
845     PandaString class_name;
846     PandaString method_name;
847 
848     if (!GetClassAndMethod(entry_point, &class_name, &method_name)) {
849         LOG(ERROR, RUNTIME) << "Invalid entry point: " << entry_point;
850         return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
851     }
852 
853     PandaString descriptor;
854     auto class_name_bytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor);
855     auto method_name_bytes = utf::CStringAsMutf8(method_name.c_str());
856 
857     Class *cls = nullptr;
858     ClassLinkerContext *context = app_context_.ctx;
859     if (context == nullptr) {
860         context = class_linker_->GetExtension(GetLanguageContext(GetRuntimeType()))->GetBootContext();
861     }
862 
863     ManagedThread *thread = ManagedThread::GetCurrent();
864     ScopedManagedCodeThread sa(thread);
865     cls = class_linker_->GetClass(class_name_bytes, true, context);
866 
867     if (cls == nullptr) {
868         LOG(ERROR, RUNTIME) << "Cannot find class '" << class_name << "'";
869         return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
870     }
871 
872     LanguageContext ctx = GetLanguageContext(*cls);
873     PandaString string_array_descriptor;
874     GetStringArrayDescriptor(ctx, &string_array_descriptor);
875 
876     Method::Proto proto(Method::Proto::ShortyVector {panda_file::Type(panda_file::Type::TypeId::VOID),
877                                                      panda_file::Type(panda_file::Type::TypeId::REFERENCE)},
878                         Method::Proto::RefTypeVector {string_array_descriptor});
879 
880     auto method = cls->GetDirectMethod(method_name_bytes, proto);
881     if (method == nullptr) {
882         method = cls->GetDirectMethod(method_name_bytes);
883         if (method == nullptr) {
884             LOG(ERROR, RUNTIME) << "Cannot find method '" << entry_point << "'";
885             return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
886         }
887     }
888 
889     return method;
890 }
891 
GetMemoryStatistics()892 PandaString Runtime::GetMemoryStatistics()
893 {
894     return panda_vm_->GetMemStats()->GetStatistics(panda_vm_->GetHeapManager());
895 }
896 
GetFinalStatistics()897 PandaString Runtime::GetFinalStatistics()
898 {
899     return panda_vm_->GetGCStats()->GetFinalStatistics(panda_vm_->GetHeapManager());
900 }
901 
NotifyAboutLoadedModules()902 void Runtime::NotifyAboutLoadedModules()
903 {
904     PandaVector<const panda_file::File *> pfs;
905 
906     class_linker_->EnumerateBootPandaFiles([&pfs](const panda_file::File &pf) {
907         pfs.push_back(&pf);
908         return true;
909     });
910 
911     for (const auto *pf : pfs) {
912         GetNotificationManager()->LoadModuleEvent(pf->GetFilename());
913     }
914 }
915 
ExtractLanguageContext(const panda_file::File * pf,std::string_view entry_point)916 Expected<LanguageContext, Runtime::Error> Runtime::ExtractLanguageContext(const panda_file::File *pf,
917                                                                           std::string_view entry_point)
918 {
919     PandaString class_name;
920     PandaString method_name;
921     if (!GetClassAndMethod(entry_point, &class_name, &method_name)) {
922         LOG(ERROR, RUNTIME) << "Invalid entry point: " << entry_point;
923         return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
924     }
925 
926     PandaString descriptor;
927     auto class_name_bytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor);
928     auto method_name_bytes = utf::CStringAsMutf8(method_name.c_str());
929 
930     auto class_id = pf->GetClassId(class_name_bytes);
931     if (!class_id.IsValid() || pf->IsExternal(class_id)) {
932         LOG(ERROR, RUNTIME) << "Cannot find class '" << class_name << "'";
933         return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
934     }
935 
936     panda_file::ClassDataAccessor cda(*pf, class_id);
937     LanguageContext ctx = GetLanguageContext(&cda);
938     bool found = false;
939     cda.EnumerateMethods([this, &pf, method_name_bytes, &found, &ctx](panda_file::MethodDataAccessor &mda) {
940         if (!found && utf::IsEqual(pf->GetStringData(mda.GetNameId()).data, method_name_bytes)) {
941             found = true;
942             auto val = mda.GetSourceLang();
943             if (val) {
944                 ctx = GetLanguageContext(val.value());
945             }
946         }
947     });
948 
949     if (!found) {
950         LOG(ERROR, RUNTIME) << "Cannot find method '" << entry_point << "'";
951         return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
952     }
953 
954     return ctx;
955 }
956 
CreateApplicationClassLinkerContext(std::string_view filename,std::string_view entry_point)957 std::optional<Runtime::Error> Runtime::CreateApplicationClassLinkerContext(std::string_view filename,
958                                                                            std::string_view entry_point)
959 {
960     bool is_loaded = false;
961     class_linker_->EnumerateBootPandaFiles([&is_loaded, filename](const panda_file::File &pf) {
962         if (pf.GetFilename() == filename) {
963             is_loaded = true;
964             return false;
965         }
966         return true;
967     });
968 
969     if (is_loaded) {
970         return {};
971     }
972 
973     auto pf = panda_file::OpenPandaFileOrZip(filename);
974 
975     if (pf == nullptr) {
976         return Runtime::Error::PANDA_FILE_LOAD_ERROR;
977     }
978 
979     auto res = ExtractLanguageContext(pf.get(), entry_point);
980 
981     if (!res) {
982         return res.Error();
983     }
984 
985     if (!class_linker_->HasExtension(res.Value())) {
986         LOG(ERROR, RUNTIME) << "class linker hasn't " << res.Value() << " language extension";
987         return Runtime::Error::CLASS_LINKER_EXTENSION_NOT_FOUND;
988     }
989 
990     auto *ext = class_linker_->GetExtension(res.Value());
991     app_context_.lang = ext->GetLanguage();
992     app_context_.ctx = class_linker_->GetAppContext(filename);
993     if (app_context_.ctx == nullptr) {
994         auto app_files = GetPandaFiles();
995         auto found_iter = std::find_if(app_files.begin(), app_files.end(),
996                                        [&](auto &app_file_name) { return app_file_name == filename; });
997         if (found_iter == app_files.end()) {
998             PandaString path(filename);
999             app_files.push_back(path);
1000         }
1001         app_context_.ctx = ext->CreateApplicationClassLinkerContext(app_files);
1002     }
1003 
1004     PandaString aot_ctx;
1005     app_context_.ctx->EnumeratePandaFiles(compiler::AotClassContextCollector(&aot_ctx));
1006     class_linker_->GetAotManager()->SetAppClassContext(aot_ctx);
1007 
1008     tooling::DebugInf::AddCodeMetaInfo(pf.get());
1009     return {};
1010 }
1011 
ExecutePandaFile(std::string_view filename,std::string_view entry_point,const std::vector<std::string> & args)1012 Expected<int, Runtime::Error> Runtime::ExecutePandaFile(std::string_view filename, std::string_view entry_point,
1013                                                         const std::vector<std::string> &args)
1014 {
1015     if (options_.IsDistributedProfiling()) {
1016         // Create app name from path to executable file.
1017         std::string_view app_name = [](std::string_view path) -> std::string_view {
1018             auto pos = path.find_last_of('/');
1019             return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
1020         }(filename);
1021         StartDProfiler(app_name);
1022     }
1023 
1024     auto ctx_err = CreateApplicationClassLinkerContext(filename, entry_point);
1025 
1026     if (ctx_err) {
1027         return Unexpected(ctx_err.value());
1028     }
1029 
1030     if (panda_vm_->GetLanguageContext().IsEnabledCHA()) {
1031         class_linker_->GetAotManager()->VerifyClassHierarchy();
1032     }
1033 
1034     return Execute(entry_point, args);
1035 }
1036 
Execute(std::string_view entry_point,const std::vector<std::string> & args)1037 Expected<int, Runtime::Error> Runtime::Execute(std::string_view entry_point, const std::vector<std::string> &args)
1038 {
1039     auto resolve_res = ResolveEntryPoint(entry_point);
1040 
1041     if (!resolve_res) {
1042         return Unexpected(resolve_res.Error());
1043     }
1044 
1045     NotifyAboutLoadedModules();
1046 
1047     Method *method = resolve_res.Value();
1048 
1049     return panda_vm_->InvokeEntrypoint(method, args);
1050 }
1051 
StartDProfiler(std::string_view app_name)1052 int Runtime::StartDProfiler(std::string_view app_name)
1053 {
1054     if (dprofiler_ != nullptr) {
1055         LOG(ERROR, RUNTIME) << "DProfiller already started";
1056         return -1;
1057     }
1058 
1059     dprofiler_ = internal_allocator_->New<DProfiler>(app_name, Runtime::GetCurrent());
1060     return 0;
1061 }
1062 
StartDebugSession()1063 Runtime::DebugSessionHandle Runtime::StartDebugSession()
1064 {
1065     os::memory::LockHolder<os::memory::Mutex> lock(debug_session_creation_mutex_);
1066 
1067     auto session = debug_session_;
1068     if (session) {
1069         return session;
1070     }
1071 
1072     session = MakePandaShared<DebugSession>(*this);
1073 
1074     debug_session_ = session;
1075 
1076     return session;
1077 }
1078 
Shutdown()1079 bool Runtime::Shutdown()
1080 {
1081     panda_vm_->UnloadDebuggerAgent();
1082     debug_session_.reset();
1083     ManagedThread::Shutdown();
1084     return true;
1085 }
1086 
ResolveString(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)1087 coretypes::String *Runtime::ResolveString(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
1088 {
1089     auto *pf = caller.GetPandaFile();
1090     return vm->ResolveString(*pf, id);
1091 }
1092 
ResolveStringFromCompiledCode(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)1093 coretypes::String *Runtime::ResolveStringFromCompiledCode(PandaVM *vm, const Method &caller,
1094                                                           panda_file::File::EntityId id)
1095 {
1096     auto *pf = caller.GetPandaFile();
1097     return vm->ResolveStringFromCompiledCode(*pf, id);
1098 }
1099 
ResolveString(PandaVM * vm,const panda_file::File & pf,panda_file::File::EntityId id,const LanguageContext & ctx)1100 coretypes::String *Runtime::ResolveString(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
1101                                           const LanguageContext &ctx)
1102 {
1103     coretypes::String *str = vm->GetStringTable()->GetInternalStringFast(pf, id);
1104     if (str != nullptr) {
1105         return str;
1106     }
1107     str = vm->GetStringTable()->GetOrInternInternalString(pf, id, ctx);
1108     return str;
1109 }
1110 
ResolveString(PandaVM * vm,const uint8_t * mutf8,uint32_t length,const LanguageContext & ctx)1111 coretypes::String *Runtime::ResolveString(PandaVM *vm, const uint8_t *mutf8, uint32_t length,
1112                                           const LanguageContext &ctx)
1113 {
1114     return vm->GetStringTable()->GetOrInternString(mutf8, length, ctx);
1115 }
1116 
ResolveLiteralArray(PandaVM * vm,const Method & caller,uint32_t id)1117 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const Method &caller, uint32_t id)
1118 {
1119     auto *pf = caller.GetPandaFile();
1120     LanguageContext ctx = GetLanguageContext(caller);
1121     return ResolveLiteralArray(vm, *pf, id, ctx);
1122 }
1123 
GetClassRootForLiteralTag(const ClassLinkerExtension & ext,panda_file::LiteralTag tag) const1124 Class *Runtime::GetClassRootForLiteralTag(const ClassLinkerExtension &ext, panda_file::LiteralTag tag) const
1125 {
1126     switch (tag) {
1127         case panda_file::LiteralTag::ARRAY_U1:
1128             return ext.GetClassRoot(ClassRoot::ARRAY_U1);
1129         case panda_file::LiteralTag::ARRAY_U8:
1130             return ext.GetClassRoot(ClassRoot::ARRAY_U8);
1131         case panda_file::LiteralTag::ARRAY_I8:
1132             return ext.GetClassRoot(ClassRoot::ARRAY_I8);
1133         case panda_file::LiteralTag::ARRAY_U16:
1134             return ext.GetClassRoot(ClassRoot::ARRAY_U16);
1135         case panda_file::LiteralTag::ARRAY_I16:
1136             return ext.GetClassRoot(ClassRoot::ARRAY_I16);
1137         case panda_file::LiteralTag::ARRAY_U32:
1138             return ext.GetClassRoot(ClassRoot::ARRAY_U32);
1139         case panda_file::LiteralTag::ARRAY_I32:
1140             return ext.GetClassRoot(ClassRoot::ARRAY_I32);
1141         case panda_file::LiteralTag::ARRAY_U64:
1142             return ext.GetClassRoot(ClassRoot::ARRAY_U64);
1143         case panda_file::LiteralTag::ARRAY_I64:
1144             return ext.GetClassRoot(ClassRoot::ARRAY_I64);
1145         case panda_file::LiteralTag::ARRAY_F32:
1146             return ext.GetClassRoot(ClassRoot::ARRAY_F32);
1147         case panda_file::LiteralTag::ARRAY_F64:
1148             return ext.GetClassRoot(ClassRoot::ARRAY_F64);
1149         case panda_file::LiteralTag::ARRAY_STRING:
1150             return ext.GetClassRoot(ClassRoot::ARRAY_STRING);
1151         case panda_file::LiteralTag::TAGVALUE:
1152         case panda_file::LiteralTag::BOOL:
1153         case panda_file::LiteralTag::INTEGER:
1154         case panda_file::LiteralTag::FLOAT:
1155         case panda_file::LiteralTag::DOUBLE:
1156         case panda_file::LiteralTag::STRING:
1157         case panda_file::LiteralTag::METHOD:
1158         case panda_file::LiteralTag::GENERATORMETHOD:
1159         case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
1160         case panda_file::LiteralTag::ACCESSOR:
1161         case panda_file::LiteralTag::NULLVALUE: {
1162             break;
1163         }
1164         default: {
1165             break;
1166         }
1167     }
1168     UNREACHABLE();
1169     return nullptr;
1170 }
1171 
1172 /* static */
GetLiteralTagAndValue(const panda_file::File & pf,uint32_t id,panda_file::LiteralTag * tag,panda_file::LiteralDataAccessor::LiteralValue * value)1173 bool Runtime::GetLiteralTagAndValue(const panda_file::File &pf, uint32_t id, panda_file::LiteralTag *tag,
1174                                     panda_file::LiteralDataAccessor::LiteralValue *value)
1175 {
1176     panda_file::File::EntityId literal_arrays_id = pf.GetLiteralArraysId();
1177     panda_file::LiteralDataAccessor literal_data_accessor(pf, literal_arrays_id);
1178     bool result = false;
1179     literal_data_accessor.EnumerateLiteralVals(
1180         panda_file::File::EntityId(id), [tag, value, &result](const panda_file::LiteralDataAccessor::LiteralValue &val,
1181                                                               const panda_file::LiteralTag &tg) {
1182             *tag = tg;
1183             *value = val;
1184             result = true;
1185         });
1186     return result;
1187 }
1188 
GetPointerToConstArrayData(const panda_file::File & pf,uint32_t id) const1189 uintptr_t Runtime::GetPointerToConstArrayData(const panda_file::File &pf, uint32_t id) const
1190 {
1191     panda_file::LiteralTag tag;
1192     panda_file::LiteralDataAccessor::LiteralValue value;
1193     if (!GetLiteralTagAndValue(pf, id, &tag, &value)) {
1194         UNREACHABLE();
1195         return 0;
1196     }
1197 
1198     auto sp = pf.GetSpanFromId(panda_file::File::EntityId(std::get<uint32_t>(value)));
1199     // first element in the sp is array size, panda_file::helpers::Read move sp pointer to next element
1200     [[maybe_unused]] auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1201     return reinterpret_cast<uintptr_t>(sp.data());
1202 }
1203 
ResolveLiteralArray(PandaVM * vm,const panda_file::File & pf,uint32_t id,const LanguageContext & ctx)1204 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const panda_file::File &pf, uint32_t id,
1205                                                const LanguageContext &ctx)
1206 {
1207     panda_file::LiteralTag tag;
1208     panda_file::LiteralDataAccessor::LiteralValue value;
1209     if (!GetLiteralTagAndValue(pf, id, &tag, &value)) {
1210         return nullptr;
1211     }
1212 
1213     auto sp = pf.GetSpanFromId(panda_file::File::EntityId(std::get<uint32_t>(value)));
1214 
1215     auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1216     auto ext = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx);
1217 
1218     if (tag != panda_file::LiteralTag::ARRAY_STRING) {
1219         return coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), sp.data(), len);
1220     }
1221 
1222     // special handling of arrays of strings
1223     auto array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), len);
1224     [[maybe_unused]] HandleScope<ObjectHeader *> scope(ManagedThread::GetCurrent());
1225     VMHandle<coretypes::Array> obj(ManagedThread::GetCurrent(), array);
1226     // NOLINTNEXTLINE(modernize-loop-convert)
1227     for (size_t i = 0; i < len; i++) {
1228         auto str_id = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1229         auto str = Runtime::GetCurrent()->ResolveString(vm, pf, panda_file::File::EntityId(str_id), ctx);
1230         obj->Set<ObjectHeader *>(i, str);
1231     }
1232     return obj.GetPtr();
1233 }
1234 
UpdateProcessState(int state)1235 void Runtime::UpdateProcessState([[maybe_unused]] int state)
1236 {
1237     LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1238 }
1239 
RegisterSensitiveThread() const1240 void Runtime::RegisterSensitiveThread() const
1241 {
1242     LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1243 }
1244 
BlockSignals()1245 void Runtime::BlockSignals()
1246 {
1247     sigset_t set;
1248     if (sigemptyset(&set) == -1) {
1249         LOG(ERROR, RUNTIME) << "sigemptyset failed";
1250         return;
1251     }
1252     int rc = 0;
1253 #ifdef PANDA_TARGET_MOBILE
1254     rc += sigaddset(&set, SIGQUIT);
1255     rc += sigaddset(&set, SIGUSR1);
1256     rc += sigaddset(&set, SIGUSR2);
1257 #endif  // PANDA_TARGET_MOBILE
1258     if (rc < 0) {
1259         LOG(ERROR, RUNTIME) << "sigaddset failed";
1260         return;
1261     }
1262 
1263     if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
1264         LOG(ERROR, RUNTIME) << "g_PandaThreadSigmask failed";
1265     }
1266 }
1267 
DumpForSigQuit(std::ostream & os)1268 void Runtime::DumpForSigQuit(std::ostream &os)
1269 {
1270     os << "\n";
1271     os << "-> Dump class loaders\n";
1272     class_linker_->EnumerateContextsForDump(
1273         [](ClassLinkerContext *ctx, std::ostream &stream, ClassLinkerContext *parent) {
1274             ctx->Dump(stream);
1275             return ctx->FindClassLoaderParent(parent);
1276         },
1277         os);
1278     os << "\n";
1279 
1280     // dump GC
1281     os << "-> Dump GC\n";
1282     os << GetFinalStatistics();
1283     os << "\n";
1284 
1285     // dump memory management
1286     os << "-> Dump memory management\n";
1287     os << GetMemoryStatistics();
1288     os << "\n";
1289 
1290     // dump PandaVM
1291     os << "-> Dump Ark VM\n";
1292     panda_vm_->DumpForSigQuit(os);
1293     os << "\n";
1294 
1295     WRITE_RELAYOUT_PROFILE_DATA();
1296 }
1297 
InitNonZygoteOrPostFork(bool is_system_server,const char * isa,bool profile_system_server)1298 void Runtime::InitNonZygoteOrPostFork([[maybe_unused]] bool is_system_server, [[maybe_unused]] const char *isa,
1299                                       [[maybe_unused]] bool profile_system_server)
1300 {
1301     is_zygote_ = false;
1302 
1303     // TODO: wait NativeBridge ready
1304 
1305     // TODO: wait profile ready
1306 
1307     // TODO: wait ThreadPool ready
1308 
1309     // TODO: wait ResetGcPerformanceInfo() ready
1310 
1311     panda_vm_->PreStartup();
1312 #if defined(PANDA_TARGET_MOBILE_WITH_MANAGED_LIBS) && PANDA_TARGET_MOBILE_WITH_MANAGED_LIBS
1313     if (IsDebugMode()) {
1314         panda_vm_->LoadDebuggerAgent();
1315 
1316         ManagedThread *thread = ManagedThread::GetCurrent();
1317         ASSERT(thread != nullptr);
1318         ScopedChangeThreadStatus sts(thread, ThreadStatus::RUNNING);
1319         ScopedSuspendAllThreadsRunning ssat(panda_vm_->GetRendezvous());
1320         panda_vm_->GetThreadManager()->EnumerateThreads([&](panda::ManagedThread *manage_thread) {
1321             manage_thread->SetCurrentDispatchTable(manage_thread->GetDebugDispatchTable());
1322             return true;
1323         });
1324     }
1325     // TODO: wait JDWP ready
1326     GetNotificationManager()->StartDebugger();
1327 #endif
1328 
1329     mem::GcHung::InitPostFork(is_system_server);
1330 }
1331 
PreZygoteFork()1332 void Runtime::PreZygoteFork()
1333 {
1334     panda_vm_->PreZygoteFork();
1335 }
1336 
PostZygoteFork()1337 void Runtime::PostZygoteFork()
1338 {
1339     panda_vm_->PostZygoteFork();
1340 }
1341 
1342 // Returns true if profile saving is enabled. GetJit() will be not null in this case.
SaveProfileInfo() const1343 bool Runtime::SaveProfileInfo() const
1344 {
1345     return save_profiling_info_;
1346 }
1347 
1348 }  // namespace panda
1349