• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <cstdint>
19 #include <cstdio>
20 #include <memory>
21 #include <string>
22 #include <string_view>
23 
24 #include "assembler/assembly-literals.h"
25 #include "intrinsics.h"
26 #include "libpandabase/events/events.h"
27 #include "libpandabase/mem/mem_config.h"
28 #include "libpandabase/mem/pool_manager.h"
29 #include "libpandabase/os/library_loader.h"
30 #include "libpandabase/os/native_stack.h"
31 #include "libpandabase/os/thread.h"
32 #include "libpandabase/utils/arena_containers.h"
33 #include "libpandabase/utils/logger.h"
34 #include "libpandabase/utils/dfx.h"
35 #include "libpandabase/utils/utf.h"
36 #include "libpandafile/file-inl.h"
37 #include "libpandafile/literal_data_accessor-inl.h"
38 #include "libpandafile/proto_data_accessor-inl.h"
39 #include "runtime/core/core_language_context.h"
40 #include "runtime/dprofiler/dprofiler.h"
41 #include "runtime/entrypoints/entrypoints.h"
42 #include "runtime/include/class_linker_extension.h"
43 #include "runtime/include/coretypes/array-inl.h"
44 #include "runtime/include/coretypes/string.h"
45 #include "runtime/include/language_context.h"
46 #include "runtime/include/locks.h"
47 #include "runtime/include/runtime_notification.h"
48 #include "runtime/include/thread.h"
49 #include "runtime/include/thread_scopes.h"
50 #include "runtime/include/tooling/debug_inf.h"
51 #include "mem/refstorage/reference_storage.h"
52 #include "runtime/mem/gc/gc_stats.h"
53 #include "runtime/mem/gc/stw-gc/stw-gc.h"
54 #include "runtime/mem/gc/crossing_map_singleton.h"
55 #include "runtime/mem/heap_manager.h"
56 #include "runtime/mem/mem_hooks.h"
57 #include "runtime/mem/memory_manager.h"
58 #include "runtime/mem/internal_allocator-inl.h"
59 #include "runtime/core/core_class_linker_extension.h"
60 #include "runtime/include/panda_vm.h"
61 #include "runtime/tooling/debugger.h"
62 #include "runtime/tooling/pt_lang_ext_private.h"
63 #include "runtime/include/file_manager.h"
64 #include "trace/trace.h"
65 #include "verification/cache/file_entity_cache.h"
66 #include "verification/cache/results_cache.h"
67 #include "verification/debug/config_load.h"
68 #include "verification/debug/context/context.h"
69 #include "verification/job_queue/job_queue.h"
70 #include "verification/type/type_systems.h"
71 
72 namespace panda {
73 
74 using std::unique_ptr;
75 
76 Runtime *Runtime::instance = nullptr;
77 RuntimeOptions Runtime::options_;  // NOLINT(fuchsia-statically-constructed-objects)
78 os::memory::Mutex Runtime::mutex;  // NOLINT(fuchsia-statically-constructed-objects)
79 
80 class RuntimeInternalAllocator {
81 public:
Create(bool use_malloc_for_internal_allocation)82     static mem::InternalAllocatorPtr Create(bool use_malloc_for_internal_allocation)
83     {
84         ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() == nullptr);
85 
86         // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
87         mem_stats_s_ = new (std::nothrow) mem::MemStatsType();
88         ASSERT(mem_stats_s_ != nullptr);
89 
90         if (use_malloc_for_internal_allocation) {
91             // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
92             internal_allocator_s_ = new (std::nothrow)
93                 mem::InternalAllocatorT<mem::InternalAllocatorConfig::MALLOC_ALLOCATOR>(mem_stats_s_);
94         } else {
95             // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
96             internal_allocator_s_ = new (std::nothrow)
97                 mem::InternalAllocatorT<mem::InternalAllocatorConfig::PANDA_ALLOCATORS>(mem_stats_s_);
98         }
99         ASSERT(internal_allocator_s_ != nullptr);
100         mem::InternalAllocator<>::InitInternalAllocatorFromRuntime(
101             static_cast<mem::Allocator *>(internal_allocator_s_));
102 
103         return internal_allocator_s_;
104     }
105 
Finalize()106     static void Finalize()
107     {
108         internal_allocator_s_->VisitAndRemoveAllPools(
109             [](void *mem, size_t size) { PoolManager::GetMmapMemPool()->FreePool(mem, size); });
110     }
111 
Destroy()112     static void Destroy()
113     {
114         ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() != nullptr);
115 
116         mem::InternalAllocator<>::ClearInternalAllocatorFromRuntime();
117         delete static_cast<mem::Allocator *>(internal_allocator_s_);
118         internal_allocator_s_ = nullptr;
119 
120         // One more check that we don't have memory leak in internal allocator.
121         ASSERT(mem_stats_s_->GetFootprint(SpaceType::SPACE_TYPE_INTERNAL) == 0);
122         delete mem_stats_s_;
123         mem_stats_s_ = nullptr;
124     }
125 
Get()126     static mem::InternalAllocatorPtr Get()
127     {
128         ASSERT(internal_allocator_s_ != nullptr);
129         return internal_allocator_s_;
130     }
131 
132 private:
133     static mem::MemStatsType *mem_stats_s_;
134     static mem::InternalAllocatorPtr internal_allocator_s_;  // NOLINT(fuchsia-statically-constructed-objects)
135 };
136 
137 mem::MemStatsType *RuntimeInternalAllocator::mem_stats_s_ = nullptr;
138 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
139 mem::InternalAllocatorPtr RuntimeInternalAllocator::internal_allocator_s_ = nullptr;
140 
141 // all GetLanguageContext(...) methods should be based on this one
GetLanguageContext(panda_file::SourceLang lang)142 LanguageContext Runtime::GetLanguageContext(panda_file::SourceLang lang)
143 {
144     auto *ctx = language_contexts_[static_cast<size_t>(lang)];
145     ASSERT(ctx != nullptr);
146     return LanguageContext(ctx);
147 }
148 
GetLanguageContext(const Method & method)149 LanguageContext Runtime::GetLanguageContext(const Method &method)
150 {
151     // See EcmaVM::GetMethodForNativeFunction
152     // Remove this 'if' when the function above gets fixed
153     if (method.GetPandaFile() != nullptr) {
154         panda_file::MethodDataAccessor mda(*method.GetPandaFile(), method.GetFileId());
155         auto res = mda.GetSourceLang();
156         if (res) {
157             return GetLanguageContext(res.value());
158         }
159     }
160 
161     // Check class source lang
162     auto *cls = method.GetClass();
163     return GetLanguageContext(cls->GetSourceLang());
164 }
165 
GetLanguageContext(const Class & cls)166 LanguageContext Runtime::GetLanguageContext(const Class &cls)
167 {
168     return GetLanguageContext(cls.GetSourceLang());
169 }
170 
GetLanguageContext(const BaseClass & cls)171 LanguageContext Runtime::GetLanguageContext(const BaseClass &cls)
172 {
173     return GetLanguageContext(cls.GetSourceLang());
174 }
175 
GetLanguageContext(panda_file::ClassDataAccessor * cda)176 LanguageContext Runtime::GetLanguageContext(panda_file::ClassDataAccessor *cda)
177 {
178     auto res = cda->GetSourceLang();
179     if (res) {
180         return GetLanguageContext(res.value());
181     }
182 
183     return GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
184 }
185 
GetLanguageContext(const std::string & runtime_type)186 LanguageContext Runtime::GetLanguageContext(const std::string &runtime_type)
187 {
188     if (runtime_type == "core") {
189         return GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
190     }
191     if (runtime_type == "ecmascript") {
192         return GetLanguageContext(panda_file::SourceLang::ECMASCRIPT);
193     }
194     LOG(FATAL, RUNTIME) << "Incorrect runtime_type: " << runtime_type;
195     UNREACHABLE();
196 }
197 
198 /* static */
CreateInstance(const RuntimeOptions & options,mem::InternalAllocatorPtr internal_allocator,const std::vector<LanguageContextBase * > & ctxs)199 bool Runtime::CreateInstance(const RuntimeOptions &options, mem::InternalAllocatorPtr internal_allocator,
200                              const std::vector<LanguageContextBase *> &ctxs)
201 {
202     Locks::Initialize();
203 
204     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
205 
206     if (options.WasSetEventsOutput()) {
207         Events::Create(options.GetEventsOutput(), options.GetEventsFile());
208     }
209 
210     {
211         os::memory::LockHolder<os::memory::Mutex> lock(mutex);
212 
213         if (instance != nullptr) {
214             return false;
215         }
216 
217         // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
218         instance = new Runtime(options, internal_allocator, ctxs);
219     }
220 
221     return true;
222 }
223 
224 /* static */
Create(const RuntimeOptions & options,const std::vector<LanguageContextBase * > & ctxs)225 bool Runtime::Create(const RuntimeOptions &options, const std::vector<LanguageContextBase *> &ctxs)
226 {
227     if (instance != nullptr) {
228         return false;
229     }
230 
231     trace::ScopedTrace scoped_trace("Runtime::Create");
232 
233     panda::mem::MemConfig::Initialize(options.GetHeapSizeLimit(), options.GetInternalMemorySizeLimit(),
234                                       options.GetCompilerMemorySizeLimit(), options.GetCodeCacheSizeLimit());
235     PoolManager::Initialize();
236 
237     mem::InternalAllocatorPtr internal_allocator =
238         RuntimeInternalAllocator::Create(options.UseMallocForInternalAllocations());
239 
240     BlockSignals();
241 
242     CreateDfxController(options);
243 
244     CreateInstance(options, internal_allocator, ctxs);
245 
246     if (!instance->Initialize()) {
247         LOG(ERROR, RUNTIME) << "Failed to initialize runtime";
248         delete instance;
249         instance = nullptr;
250         return false;
251     }
252 
253     instance->GetPandaVM()->StartGC();
254 
255     auto *thread = ManagedThread::GetCurrent();
256     instance->GetNotificationManager()->VmStartEvent();
257     instance->GetNotificationManager()->VmInitializationEvent(thread->GetId());
258     instance->GetNotificationManager()->ThreadStartEvent(thread->GetId());
259 
260     return true;
261 }
262 
GetCurrent()263 Runtime *Runtime::GetCurrent()
264 {
265     return instance;
266 }
267 
268 /* static */
DestroyUnderLockHolder()269 bool Runtime::DestroyUnderLockHolder()
270 {
271     os::memory::LockHolder<os::memory::Mutex> lock(mutex);
272 
273     if (instance == nullptr) {
274         return false;
275     }
276 
277     if (!instance->Shutdown()) {
278         LOG(ERROR, RUNTIME) << "Failed to shutdown runtime";
279         return false;
280     }
281     if (GetOptions().WasSetEventsOutput()) {
282         Events::Destroy();
283     }
284 
285     /**
286      * NOTE: Users threads can call log after destroying Runtime. We can't control these
287      *       when they are in NATIVE_CODE mode because we don't destroy logger
288      * Logger::Destroy();
289      */
290 
291     DfxController::Destroy();
292     delete instance;
293     instance = nullptr;
294     panda::mem::MemConfig::Finalize();
295 
296     return true;
297 }
298 
299 /* static */
Destroy()300 bool Runtime::Destroy()
301 {
302     if (instance == nullptr) {
303         return false;
304     }
305 
306     trace::ScopedTrace scoped_trace("Runtime shutdown");
307     instance->GetPandaVM()->StopGC();
308 
309     instance->GetPandaVM()->UninitializeThreads();
310 
311     verifier::JobQueue::Stop(instance->GetVerificationOptions().Mode.OnlyVerify);
312 
313     instance->GetNotificationManager()->VmDeathEvent();
314 
315     verifier::JobQueue::Destroy();
316     verifier::TypeSystems::Destroy();
317     verifier::VerificationResultCache::Destroy(Runtime::GetCurrent()->GetVerificationOptions().Cache.UpdateOnExit);
318 
319     DestroyUnderLockHolder();
320     RuntimeInternalAllocator::Destroy();
321 
322     return true;
323 }
324 
InitializeVerificationResultCache(const panda::RuntimeOptions & options)325 void Runtime::InitializeVerificationResultCache(const panda::RuntimeOptions &options)
326 {
327     auto &&verif_options = GetVerificationOptions();
328     if (verif_options.Enable) {
329         verifier::TypeSystems::Initialize();
330         verifier::JobQueue::Initialize(verif_options.Mode.VerificationThreads);
331         const auto &boot_panda_files = options.GetBootPandaFiles();
332         size_t files_len = options.GetPandaFiles().empty() ? boot_panda_files.size() - 1 : boot_panda_files.size();
333         for (size_t i = 0; i < files_len; i++) {
334             verifier::JobQueue::AddSystemFile(boot_panda_files[i]);
335         }
336 
337         auto &&cache_file = verif_options.Cache.File;
338         if (!cache_file.empty()) {
339             verifier::VerificationResultCache::Initialize(cache_file);
340         }
341     }
342 }
343 
344 /* static */
Halt(int32_t status)345 void Runtime::Halt(int32_t status)
346 {
347     Runtime *runtime = Runtime::GetCurrent();
348     if (runtime != nullptr && runtime->exit_ != nullptr) {
349         runtime->exit_(status);
350     }
351 
352     // _exit is safer to call because it guarantees a safe
353     // completion in case of multi-threading as static destructors aren't called
354     _exit(status);
355 }
356 
357 /* static */
Abort(const char * message)358 void Runtime::Abort(const char *message /* = nullptr */)
359 {
360     Runtime *runtime = Runtime::GetCurrent();
361     if (runtime != nullptr && runtime->abort_ != nullptr) {
362         runtime->abort_();
363     }
364 
365     std::cerr << "Runtime::Abort: " << (message != nullptr ? message : "") << std::endl;
366     std::abort();
367 }
368 
369 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
Runtime(const RuntimeOptions & options,mem::InternalAllocatorPtr internal_allocator,const std::vector<LanguageContextBase * > & ctxs)370 Runtime::Runtime(const RuntimeOptions &options, mem::InternalAllocatorPtr internal_allocator,
371                  const std::vector<LanguageContextBase *> &ctxs)
372     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
373     : internal_allocator_(internal_allocator),
374       // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
375       notification_manager_(new RuntimeNotificationManager(internal_allocator_)),
376       // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
377       debugger_library_(nullptr),
378       zygote_no_threads_(false)
379 {
380     Runtime::options_ = options;
381     // ECMAScript doesn't use intrinsics
382     if (options_.GetRuntimeType() == "ecmascript") {
383         options_.SetShouldInitializeIntrinsics(false);
384     }
385 
386     auto spaces = GetOptions().GetBootClassSpaces();
387 
388     // Default core context
389     static CoreLanguageContext lcCore;
390     language_contexts_[static_cast<size_t>(lcCore.GetLanguage())] = &lcCore;
391 
392     for (const auto &ctx : ctxs) {
393         language_contexts_[static_cast<size_t>(ctx->GetLanguage())] = ctx;
394     }
395 
396     std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
397     extensions.reserve(spaces.size());
398 
399     for (const auto &space : spaces) {
400         extensions.push_back(GetLanguageContext(space).CreateClassLinkerExtension());
401     }
402 
403     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
404     class_linker_ = new ClassLinker(internal_allocator_, std::move(extensions));
405     // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
406     signal_manager_ = new SignalManager(internal_allocator_);
407 
408     if (IsEnableMemoryHooks()) {
409         // libbfd (which is used to get debug info from elf files) does a lot of allocations.
410         // Don't track allocations in this case.
411         if (!options_.IsSafepointBacktrace()) {
412             mem::PandaHooks::Enable();
413         }
414     }
415 
416     save_profiling_info_ = false;
417 
418     VerificationOptions_.Initialize(options_);
419     InitializeVerificationResultCache(options_);
420 
421     is_zygote_ = options_.IsStartAsZygote();
422 }
423 
~Runtime()424 Runtime::~Runtime()
425 {
426     VerificationOptions_.Destroy();
427     panda::verifier::debug::DebugContext::Destroy();
428 
429     if (IsEnableMemoryHooks()) {
430         mem::PandaHooks::Disable();
431     }
432     trace::ScopedTrace scoped_trace("Delete state");
433 
434     signal_manager_->DeleteHandlersArray();
435     delete signal_manager_;
436     delete class_linker_;
437     if (dprofiler_ != nullptr) {
438         internal_allocator_->Delete(dprofiler_);
439     }
440     delete notification_manager_;
441 
442     if (pt_lang_ext_ != nullptr) {
443         internal_allocator_->Delete(pt_lang_ext_);
444     }
445 
446     if (panda_vm_ != nullptr) {
447         internal_allocator_->Delete(panda_vm_);
448     }
449 
450     // crossing map is shared by Java VM and Js VM.
451     mem::CrossingMapSingleton::Destroy();
452 
453     RuntimeInternalAllocator::Finalize();
454     PoolManager::Finalize();
455 }
456 
IsEnableMemoryHooks() const457 bool Runtime::IsEnableMemoryHooks() const
458 {
459     auto log_level = Logger::IsInitialized() ? Logger::GetLevel() : Logger::Level::DEBUG;
460     return options_.IsLimitStandardAlloc() &&
461            (log_level == Logger::Level::FATAL || log_level == Logger::Level::ERROR) &&
462            (!options_.UseMallocForInternalAllocations());
463 }
464 
GetPandaFilesList(const std::vector<std::string> & stdvec)465 static PandaVector<PandaString> GetPandaFilesList(const std::vector<std::string> &stdvec)
466 {
467     PandaVector<PandaString> res;
468     for (const auto &i : stdvec) {
469         // NOLINTNEXTLINE(readability-redundant-string-cstr)
470         res.push_back(i.c_str());
471     }
472 
473     return res;
474 }
475 
GetBootPandaFiles()476 PandaVector<PandaString> Runtime::GetBootPandaFiles()
477 {
478     // NOLINTNEXTLINE(readability-redundant-string-cstr)
479     const auto &boot_panda_files = GetPandaFilesList(options_.GetBootPandaFiles());
480     return boot_panda_files;
481 }
482 
GetPandaFiles()483 PandaVector<PandaString> Runtime::GetPandaFiles()
484 {
485     // NOLINTNEXTLINE(readability-redundant-string-cstr)
486     const auto &app_panda_files = GetPandaFilesList(options_.GetPandaFiles());
487     return app_panda_files;
488 }
489 
LoadBootPandaFiles(panda_file::File::OpenMode open_mode)490 bool Runtime::LoadBootPandaFiles(panda_file::File::OpenMode open_mode)
491 {
492     // NOLINTNEXTLINE(readability-redundant-string-cstr)
493     const auto &boot_panda_files = options_.GetBootPandaFiles();
494     for (const auto &name : boot_panda_files) {
495         if (!FileManager::LoadAbcFile(ConvertToString(name), open_mode)) {
496             LOG(ERROR, RUNTIME) << "Load boot panda file failed: " << name;
497             return false;
498         }
499     }
500 
501     return true;
502 }
503 
GetGCType(const RuntimeOptions & options)504 mem::GCType Runtime::GetGCType(const RuntimeOptions &options)
505 {
506     auto gc_type = panda::mem::GCTypeFromString(options.GetGcType());
507     if (options.IsNoAsyncJit()) {
508         // With no-async-jit we can force compilation inside of c2i bridge (we have IncrementHotnessCounter there)
509         // and it can trigger GC which can move objects which are arguments for the method
510         // because StackWalker ignores c2i frame
511         return gc_type == panda::mem::GCType::GEN_GC ? panda::mem::GCType::STW_GC : gc_type;
512     }
513     return gc_type;
514 }
515 
LoadVerificationConfig()516 bool Runtime::LoadVerificationConfig()
517 {
518     const auto &options = GetVerificationOptions();
519 
520     if (options.Enable) {
521         if (options.Mode.DebugEnable) {
522             if (!verifier::config::LoadConfig(options.Debug.ConfigFile)) {
523                 return false;
524             }
525         }
526     }
527 
528     return true;
529 }
530 
CreatePandaVM(std::string_view runtime_type)531 bool Runtime::CreatePandaVM(std::string_view runtime_type)
532 {
533     if (!ManagedThread::Initialize()) {
534         LOG(ERROR, RUNTIME) << "Failed to initialize managed thread";
535         return false;
536     }
537 
538     panda_vm_ = PandaVM::Create(this, options_, runtime_type);
539     if (panda_vm_ == nullptr) {
540         LOG(ERROR, RUNTIME) << "Failed to create panda vm";
541         return false;
542     }
543 
544     panda_file::File::OpenMode open_mode = panda_file::File::READ_ONLY;
545     if (Runtime::GetOptions().GetRuntimeType() == "ecmascript") {
546         // In case of JS vm open a panda file for reading / writing
547         // because EcmaVM patches bytecode in-place
548         open_mode = panda_file::File::READ_WRITE;
549     }
550     bool load_boot_panda_files_is_failed = options_.ShouldLoadBootPandaFiles() && !LoadBootPandaFiles(open_mode);
551     if (load_boot_panda_files_is_failed) {
552         LOG(ERROR, RUNTIME) << "Failed to load boot panda files";
553         return false;
554     }
555 
556     notification_manager_->SetRendezvous(panda_vm_->GetRendezvous());
557 
558     return true;
559 }
560 
InitializePandaVM()561 bool Runtime::InitializePandaVM()
562 {
563     if (!class_linker_->Initialize(options_.IsRuntimeCompressedStringsEnabled())) {
564         LOG(ERROR, RUNTIME) << "Failed to initialize class loader";
565         return false;
566     }
567 
568     if (options_.ShouldInitializeIntrinsics() && !intrinsics::Initialize()) {
569         LOG(ERROR, RUNTIME) << "Failed to initialize intrinsics";
570         return false;
571     }
572 
573     std::string debug_library_path = options_.GetDebuggerLibraryPath();
574     if (!debug_library_path.empty()) {
575         if (!StartDebugger(debug_library_path)) {
576             LOG(ERROR, RUNTIME) << "Failed to start debugger";
577             return false;
578         }
579     }
580 
581     if (!panda_vm_->Initialize()) {
582         LOG(ERROR, RUNTIME) << "Failed to initialize panda vm";
583         return false;
584     }
585 
586     return true;
587 }
588 
CheckOptionsConsistency()589 bool Runtime::CheckOptionsConsistency()
590 {
591     return true;
592 }
593 
SetPandaPath()594 void Runtime::SetPandaPath()
595 {
596     PandaVector<PandaString> app_panda_files = GetPandaFiles();
597     for (size_t i = 0; i < app_panda_files.size(); ++i) {
598         panda_path_string_ += PandaStringToStd(app_panda_files[i]);
599         if (i != app_panda_files.size() - 1) {
600             panda_path_string_ += ":";
601         }
602     }
603 }
604 
Initialize()605 bool Runtime::Initialize()
606 {
607     trace::ScopedTrace scoped_trace("Runtime::Initialize");
608 
609     if (!CheckOptionsConsistency()) {
610         return false;
611     }
612 
613     if (!LoadVerificationConfig()) {
614         return false;
615     }
616 
617     auto runtime_type = options_.GetRuntimeType();
618     if (!CreatePandaVM(runtime_type)) {
619         return false;
620     }
621 
622     if (!InitializePandaVM()) {
623         return false;
624     }
625 
626     ManagedThread *thread = ManagedThread::GetCurrent();
627     class_linker_->InitializeRoots(thread);
628     auto ext = GetClassLinker()->GetExtension(GetLanguageContext(runtime_type));
629     if (ext != nullptr) {
630         thread->SetStringClassPtr(ext->GetClassRoot(ClassRoot::STRING));
631     }
632 
633     fingerPrint_ = ConvertToString(options_.GetFingerprint());
634 
635     SetPandaPath();
636 
637     if (!panda_vm_->InitializeFinish()) {
638         LOG(ERROR, RUNTIME) << "Failed to finish panda vm initialization";
639         return false;
640     }
641 
642     is_initialized_ = true;
643     return true;
644 }
645 
GetClassAndMethod(std::string_view entry_point,PandaString * class_name,PandaString * method_name)646 static bool GetClassAndMethod(std::string_view entry_point, PandaString *class_name, PandaString *method_name)
647 {
648     size_t pos = entry_point.find_last_of("::");
649     if (pos == std::string_view::npos) {
650         return false;
651     }
652 
653     *class_name = PandaString(entry_point.substr(0, pos - 1));
654     *method_name = PandaString(entry_point.substr(pos + 1));
655 
656     return true;
657 }
658 
GetStringArrayDescriptor(LanguageContext ctx,PandaString * out)659 static const uint8_t *GetStringArrayDescriptor(LanguageContext ctx, PandaString *out)
660 {
661     *out = "[";
662     *out += utf::Mutf8AsCString(ctx.GetStringClassDescriptor());
663 
664     return utf::CStringAsMutf8(out->c_str());
665 }
666 
ResolveEntryPoint(std::string_view entry_point)667 Expected<Method *, Runtime::Error> Runtime::ResolveEntryPoint(std::string_view entry_point)
668 {
669     PandaString class_name;
670     PandaString method_name;
671 
672     if (!GetClassAndMethod(entry_point, &class_name, &method_name)) {
673         LOG(ERROR, RUNTIME) << "Invalid entry point: " << entry_point;
674         return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
675     }
676 
677     PandaString descriptor;
678     auto class_name_bytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor);
679     auto method_name_bytes = utf::CStringAsMutf8(method_name.c_str());
680 
681     Class *cls = nullptr;
682     ClassLinkerContext *context = app_context_.ctx;
683     if (context == nullptr) {
684         context = class_linker_->GetExtension(GetLanguageContext(options_.GetRuntimeType()))->GetBootContext();
685     }
686 
687     ManagedThread *thread = ManagedThread::GetCurrent();
688     if (MTManagedThread::ThreadIsMTManagedThread(thread)) {
689         ScopedManagedCodeThread sa(static_cast<MTManagedThread *>(thread));
690         cls = class_linker_->GetClass(class_name_bytes, true, context);
691     } else {
692         cls = class_linker_->GetClass(class_name_bytes, true, context);
693     }
694 
695     if (cls == nullptr) {
696         LOG(ERROR, RUNTIME) << "Cannot find class '" << class_name << "'";
697         return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
698     }
699 
700     LanguageContext ctx = GetLanguageContext(*cls);
701     PandaString string_array_descriptor;
702     GetStringArrayDescriptor(ctx, &string_array_descriptor);
703 
704     Method::Proto proto(PandaVector<panda_file::Type> {panda_file::Type(panda_file::Type::TypeId::VOID),
705                                                        panda_file::Type(panda_file::Type::TypeId::REFERENCE)},
706                         PandaVector<std::string_view> {string_array_descriptor});
707 
708     auto method = cls->GetDirectMethod(method_name_bytes, proto);
709     if (method == nullptr) {
710         method = cls->GetDirectMethod(method_name_bytes);
711         if (method == nullptr) {
712             LOG(ERROR, RUNTIME) << "Cannot find method '" << entry_point << "'";
713             return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
714         }
715     }
716 
717     return method;
718 }
719 
GetMemoryStatistics()720 PandaString Runtime::GetMemoryStatistics()
721 {
722     return panda_vm_->GetMemStats()->GetStatistics(panda_vm_->GetHeapManager());
723 }
724 
GetFinalStatistics()725 PandaString Runtime::GetFinalStatistics()
726 {
727     return panda_vm_->GetGCStats()->GetFinalStatistics(panda_vm_->GetHeapManager());
728 }
729 
NotifyAboutLoadedModules()730 void Runtime::NotifyAboutLoadedModules()
731 {
732     PandaVector<const panda_file::File *> pfs;
733 
734     class_linker_->EnumerateBootPandaFiles([&pfs](const panda_file::File &pf) {
735         pfs.push_back(&pf);
736         return true;
737     });
738 
739     for (const auto *pf : pfs) {
740         GetNotificationManager()->LoadModuleEvent(pf->GetFilename());
741     }
742 }
743 
ExtractLanguageContext(const panda_file::File * pf,std::string_view entry_point)744 Expected<LanguageContext, Runtime::Error> Runtime::ExtractLanguageContext(const panda_file::File *pf,
745                                                                           std::string_view entry_point)
746 {
747     PandaString class_name;
748     PandaString method_name;
749     if (!GetClassAndMethod(entry_point, &class_name, &method_name)) {
750         LOG(ERROR, RUNTIME) << "Invalid entry point: " << entry_point;
751         return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
752     }
753 
754     PandaString descriptor;
755     auto class_name_bytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor);
756     auto method_name_bytes = utf::CStringAsMutf8(method_name.c_str());
757 
758     auto class_id = pf->GetClassId(class_name_bytes);
759     if (!class_id.IsValid() || pf->IsExternal(class_id)) {
760         LOG(ERROR, RUNTIME) << "Cannot find class '" << class_name << "'";
761         return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
762     }
763 
764     panda_file::ClassDataAccessor cda(*pf, class_id);
765     LanguageContext ctx = GetLanguageContext(&cda);
766     bool found = false;
767     cda.EnumerateMethods([this, &pf, method_name_bytes, &found, &ctx](panda_file::MethodDataAccessor &mda) {
768         if (!found && utf::IsEqual(pf->GetStringData(mda.GetNameId()).data, method_name_bytes)) {
769             found = true;
770             auto val = mda.GetSourceLang();
771             if (val) {
772                 ctx = GetLanguageContext(val.value());
773             }
774         }
775     });
776 
777     if (!found) {
778         LOG(ERROR, RUNTIME) << "Cannot find method '" << entry_point << "'";
779         return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
780     }
781 
782     return ctx;
783 }
784 
CreateApplicationClassLinkerContext(std::string_view filename,std::string_view entry_point)785 std::optional<Runtime::Error> Runtime::CreateApplicationClassLinkerContext(std::string_view filename,
786                                                                            std::string_view entry_point)
787 {
788     bool is_loaded = false;
789     class_linker_->EnumerateBootPandaFiles([&is_loaded, filename](const panda_file::File &pf) {
790         if (pf.GetFilename() == filename) {
791             is_loaded = true;
792             return false;
793         }
794         return true;
795     });
796 
797     if (is_loaded) {
798         return {};
799     }
800 
801     auto pf = panda_file::OpenPandaFileOrZip(filename);
802     if (pf == nullptr) {
803         return Runtime::Error::PANDA_FILE_LOAD_ERROR;
804     }
805 
806     auto res = ExtractLanguageContext(pf.get(), entry_point);
807     if (!res) {
808         return res.Error();
809     }
810 
811     if (!class_linker_->HasExtension(res.Value())) {
812         LOG(ERROR, RUNTIME) << "class linker hasn't " << res.Value() << " language extension";
813         return Runtime::Error::CLASS_LINKER_EXTENSION_NOT_FOUND;
814     }
815 
816     auto *ext = class_linker_->GetExtension(res.Value());
817     app_context_.lang = ext->GetLanguage();
818     app_context_.ctx = class_linker_->GetAppContext(filename);
819     if (app_context_.ctx == nullptr) {
820         auto app_files = GetPandaFiles();
821         auto found_iter = std::find_if(app_files.begin(), app_files.end(),
822                                        [&](auto &app_file_name) { return app_file_name == filename; });
823         if (found_iter == app_files.end()) {
824             PandaString path(filename);
825             app_files.push_back(path);
826         }
827         app_context_.ctx = ext->CreateApplicationClassLinkerContext(app_files);
828     }
829 
830     tooling::DebugInf::AddCodeMetaInfo(pf.get());
831     return {};
832 }
833 
ExecutePandaFile(std::string_view filename,std::string_view entry_point,const std::vector<std::string> & args)834 Expected<int, Runtime::Error> Runtime::ExecutePandaFile(std::string_view filename, std::string_view entry_point,
835                                                         const std::vector<std::string> &args)
836 {
837     if (options_.IsDistributedProfiling()) {
838         // Create app name from path to executable file.
839         std::string_view app_name = [](std::string_view path) -> std::string_view {
840             auto pos = path.find_last_of('/');
841             return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
842         }(filename);
843         StartDProfiler(app_name);
844     }
845 
846     auto ctx_err = CreateApplicationClassLinkerContext(filename, entry_point);
847     if (ctx_err) {
848         return Unexpected(ctx_err.value());
849     }
850 
851     return Execute(entry_point, args);
852 }
853 
Execute(std::string_view entry_point,const std::vector<std::string> & args)854 Expected<int, Runtime::Error> Runtime::Execute(std::string_view entry_point, const std::vector<std::string> &args)
855 {
856     auto resolve_res = ResolveEntryPoint(entry_point);
857     if (!resolve_res) {
858         return Unexpected(resolve_res.Error());
859     }
860 
861     NotifyAboutLoadedModules();
862 
863     Method *method = resolve_res.Value();
864 
865     return panda_vm_->InvokeEntrypoint(method, args);
866 }
867 
RegisterAppInfo(const PandaVector<PandaString> & code_paths,const PandaString & profile_output_filename)868 void Runtime::RegisterAppInfo(const PandaVector<PandaString> &code_paths, const PandaString &profile_output_filename)
869 {
870     for (const auto &str : code_paths) {
871         LOG(INFO, RUNTIME) << "Code path: " << str;
872     }
873     std::string_view app_name = [](std::string_view path) -> std::string_view {
874         auto pos = path.find_last_of('/');
875         return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
876     }(profile_output_filename);
877 
878     StartDProfiler(app_name);
879 }
880 
StartDProfiler(std::string_view app_name)881 int Runtime::StartDProfiler(std::string_view app_name)
882 {
883     if (dprofiler_ != nullptr) {
884         LOG(ERROR, RUNTIME) << "DProfiller already started";
885         return -1;
886     }
887 
888     dprofiler_ = internal_allocator_->New<DProfiler>(app_name, Runtime::GetCurrent());
889     return 0;
890 }
891 
StartDebugger(const std::string & library_path)892 bool Runtime::StartDebugger(const std::string &library_path)
893 {
894     auto handle = os::library_loader::Load(library_path);
895     if (!handle) {
896         return true;
897     }
898 
899     using StartDebuggerT = int (*)(uint32_t, tooling::DebugInterface *, void *);
900 
901     auto sym = os::library_loader::ResolveSymbol(handle.Value(), "StartDebugger");
902     if (!sym) {
903         LOG(ERROR, RUNTIME) << sym.Error().ToString();
904         return false;
905     }
906 
907     uint32_t port = options_.GetDebuggerPort();
908     SetDebugMode(true);
909     if (!AttachDebugger()) {
910         return false;
911     }
912     ASSERT(debugger_ != nullptr);
913 
914     int res = reinterpret_cast<StartDebuggerT>(sym.Value())(port, debugger_, nullptr);
915     if (res != 0) {
916         LOG(ERROR, RUNTIME) << "StartDebugger has failed";
917         return false;
918     }
919 
920     ASSERT(!debugger_library_.IsValid());
921     debugger_library_ = std::move(handle.Value());
922 
923     // Turn off stdout buffering in debug mode
924     setvbuf(stdout, nullptr, _IONBF, 0);
925     return true;
926 }
927 
AttachDebugger()928 bool Runtime::AttachDebugger()
929 {
930     ASSERT(is_debug_mode_);
931     auto pt_lang_ext = tooling::CreatePtLangExt(options_.GetRuntimeType());
932     if (!pt_lang_ext) {
933         LOG(ERROR, RUNTIME) << "Cannot create PtLangExt";
934         return false;
935     }
936     pt_lang_ext_ = pt_lang_ext.release();
937     ASSERT(debugger_ == nullptr);
938     debugger_ = internal_allocator_->New<tooling::Debugger>(this);
939     return true;
940 }
941 
Shutdown()942 bool Runtime::Shutdown()
943 {
944     if (IsDebugMode() && debugger_library_.IsValid()) {
945         using StopDebugger = int (*)();
946 
947         ASSERT(debugger_library_.IsValid());
948         auto sym = os::library_loader::ResolveSymbol(debugger_library_, "StopDebugger");
949         if (!sym) {
950             LOG(ERROR, RUNTIME) << sym.Error().ToString();
951             return false;
952         }
953 
954         int res = reinterpret_cast<StopDebugger>(sym.Value())();
955         if (res != 0) {
956             LOG(ERROR, RUNTIME) << "StopDebugger has failed";
957             return false;
958         }
959     }
960 
961     if (debugger_ != nullptr) {
962         internal_allocator_->Delete(debugger_);
963     }
964 
965     return ManagedThread::Shutdown();
966 }
967 
ResolveString(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)968 coretypes::String *Runtime::ResolveString(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
969 {
970     auto *pf = caller.GetPandaFile();
971     LanguageContext ctx = GetLanguageContext(caller);
972     return ResolveString(vm, *pf, id, ctx);
973 }
974 
ResolveString(PandaVM * vm,const panda_file::File & pf,panda_file::File::EntityId id,LanguageContext ctx)975 coretypes::String *Runtime::ResolveString(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
976                                           LanguageContext ctx)
977 {
978     coretypes::String *str = vm->GetStringTable()->GetInternalStringFast(pf, id);
979     if (str != nullptr) {
980         return str;
981     }
982     str = vm->GetStringTable()->GetOrInternInternalString(pf, id, ctx);
983     return str;
984 }
985 
ResolveString(PandaVM * vm,const uint8_t * mutf8,uint32_t length,LanguageContext ctx)986 coretypes::String *Runtime::ResolveString(PandaVM *vm, const uint8_t *mutf8, uint32_t length, LanguageContext ctx)
987 {
988     return vm->GetStringTable()->GetOrInternString(mutf8, length, ctx);
989 }
990 
ResolveLiteralArray(PandaVM * vm,const Method & caller,panda_file::File::EntityId id)991 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
992 {
993     auto *pf = caller.GetPandaFile();
994     LanguageContext ctx = GetLanguageContext(caller);
995     return ResolveLiteralArray(vm, *pf, id, ctx);
996 }
997 
GetClassRootForLiteralTag(const ClassLinkerExtension & ext,panda_file::LiteralTag tag) const998 Class *Runtime::GetClassRootForLiteralTag(const ClassLinkerExtension &ext, panda_file::LiteralTag tag) const
999 {
1000     switch (tag) {
1001         case panda_file::LiteralTag::ARRAY_I8:
1002             return ext.GetClassRoot(ClassRoot::ARRAY_I8);
1003         case panda_file::LiteralTag::ARRAY_I16:
1004             return ext.GetClassRoot(ClassRoot::ARRAY_I16);
1005         case panda_file::LiteralTag::ARRAY_I32:
1006             return ext.GetClassRoot(ClassRoot::ARRAY_I32);
1007         case panda_file::LiteralTag::ARRAY_I64:
1008             return ext.GetClassRoot(ClassRoot::ARRAY_I64);
1009         case panda_file::LiteralTag::ARRAY_F32:
1010             return ext.GetClassRoot(ClassRoot::ARRAY_F32);
1011         case panda_file::LiteralTag::ARRAY_F64:
1012             return ext.GetClassRoot(ClassRoot::ARRAY_F64);
1013         case panda_file::LiteralTag::ARRAY_STRING:
1014             return ext.GetClassRoot(ClassRoot::ARRAY_STRING);
1015         case panda_file::LiteralTag::TAGVALUE:
1016         case panda_file::LiteralTag::BOOL:
1017         case panda_file::LiteralTag::INTEGER:
1018         case panda_file::LiteralTag::FLOAT:
1019         case panda_file::LiteralTag::DOUBLE:
1020         case panda_file::LiteralTag::STRING:
1021         case panda_file::LiteralTag::METHOD:
1022         case panda_file::LiteralTag::GENERATORMETHOD:
1023         case panda_file::LiteralTag::ACCESSOR:
1024         case panda_file::LiteralTag::NULLVALUE: {
1025             break;
1026         }
1027         default: {
1028             break;
1029         }
1030     }
1031     UNREACHABLE();
1032     return nullptr;
1033 }
1034 
1035 /* static */
GetLiteralTagAndValue(const panda_file::File & pf,panda_file::File::EntityId id,panda_file::LiteralTag * tag,panda_file::LiteralDataAccessor::LiteralValue * value)1036 bool Runtime::GetLiteralTagAndValue(const panda_file::File &pf, panda_file::File::EntityId id,
1037                                     panda_file::LiteralTag *tag, panda_file::LiteralDataAccessor::LiteralValue *value)
1038 {
1039     panda_file::File::EntityId literalArraysId = pf.GetLiteralArraysId();
1040     panda_file::LiteralDataAccessor literal_data_accessor(pf, literalArraysId);
1041     bool result = false;
1042     literal_data_accessor.EnumerateLiteralVals(
1043         id, [tag, value, &result](const panda_file::LiteralDataAccessor::LiteralValue &val,
1044                                   const panda_file::LiteralTag &tg) {
1045             *tag = tg;
1046             *value = val;
1047             result = true;
1048         });
1049     return result;
1050 }
1051 
ResolveLiteralArray(PandaVM * vm,const panda_file::File & pf,panda_file::File::EntityId id,LanguageContext ctx)1052 coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
1053                                                LanguageContext ctx)
1054 {
1055     panda_file::LiteralTag tag;
1056     panda_file::LiteralDataAccessor::LiteralValue value;
1057 
1058     coretypes::Array *array = nullptr;
1059 
1060     if (GetLiteralTagAndValue(pf, id, &tag, &value)) {
1061         panda_file::File::EntityId value_id(std::get<uint32_t>(value));
1062         auto sp = pf.GetSpanFromId(value_id);
1063         auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1064         auto ext = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx);
1065         // special handling of arrays of strings
1066         if (tag == panda_file::LiteralTag::ARRAY_STRING) {
1067             array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), len);
1068             VMHandle<coretypes::Array> obj(ManagedThread::GetCurrent(), array);
1069             // NOLINTNEXTLINE(modernize-loop-convert)
1070             for (size_t i = 0; i < len; i++) {
1071                 auto str_id = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
1072                 auto str = Runtime::GetCurrent()->ResolveString(vm, pf, panda_file::File::EntityId(str_id), ctx);
1073                 obj->Set<ObjectHeader *>(i, str);
1074             }
1075             array = obj.GetPtr();
1076         } else {
1077             array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), sp.data(), len);
1078         }
1079     }
1080 
1081     return array;
1082 }
1083 
UpdateProcessState(int state)1084 void Runtime::UpdateProcessState([[maybe_unused]] int state)
1085 {
1086     LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1087 }
1088 
RegisterSensitiveThread() const1089 void Runtime::RegisterSensitiveThread() const
1090 {
1091     LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
1092 }
1093 
CreateDfxController(const RuntimeOptions & options)1094 void Runtime::CreateDfxController(const RuntimeOptions &options)
1095 {
1096     DfxController::Initialize();
1097 #ifdef PANDA_TARGET_UNIX
1098     DfxController::SetOptionValue(DfxOptionHandler::REFERENCE_DUMP, options.GetReferenceDump());
1099     DfxController::SetOptionValue(DfxOptionHandler::SIGNAL_HANDLER, options.GetSignalHandler());
1100     DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGQUIT, options.GetSigquitFlag());
1101     DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR1, options.GetSigusr1Flag());
1102     DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR2, options.GetSigusr2Flag());
1103     DfxController::SetOptionValue(DfxOptionHandler::MOBILE_LOG, options.GetMobileLogFlag());
1104 #endif
1105     DfxController::SetOptionValue(DfxOptionHandler::DFXLOG, options.GetDfxLog());
1106 }
1107 
BlockSignals()1108 void Runtime::BlockSignals()
1109 {
1110 #if defined(PANDA_TARGET_UNIX)
1111     sigset_t set;
1112     if (sigemptyset(&set) == -1) {
1113         LOG(ERROR, RUNTIME) << "sigemptyset failed";
1114         return;
1115     }
1116 #ifdef PANDA_TARGET_MOBILE
1117     int rc = 0;
1118     rc += sigaddset(&set, SIGQUIT);
1119     rc += sigaddset(&set, SIGUSR1);
1120     rc += sigaddset(&set, SIGUSR2);
1121     if (rc < 0) {
1122         LOG(ERROR, RUNTIME) << "sigaddset failed";
1123         return;
1124     }
1125 #endif  // PANDA_TARGET_MOBILE
1126 
1127     if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
1128         LOG(ERROR, RUNTIME) << "PandaThreadSigmask failed";
1129     }
1130 #endif  // PANDA_TARGET_UNIX
1131 }
1132 
DumpForSigQuit(std::ostream & os)1133 void Runtime::DumpForSigQuit(std::ostream &os)
1134 {
1135     os << "\n";
1136     os << "-> Dump class loaders\n";
1137     class_linker_->EnumerateContextsForDump(
1138         [](ClassLinkerContext *ctx, std::ostream &stream, ClassLinkerContext *parent) {
1139             ctx->Dump(stream);
1140             return ctx->FindClassLoaderParent(parent);
1141         },
1142         os);
1143     os << "\n";
1144 
1145     // dump GC
1146     os << "-> Dump GC\n";
1147     os << GetFinalStatistics();
1148     os << "\n";
1149 
1150     // dump memory management
1151     os << "-> Dump memory management\n";
1152     os << GetMemoryStatistics();
1153     os << "\n";
1154 }
1155 
PreZygoteFork()1156 void Runtime::PreZygoteFork()
1157 {
1158     panda_vm_->PreZygoteFork();
1159 }
1160 
PostZygoteFork()1161 void Runtime::PostZygoteFork()
1162 {
1163     panda_vm_->PostZygoteFork();
1164 }
1165 
1166 // Returns true if profile saving is enabled. GetJit() will be not null in this case.
SaveProfileInfo() const1167 bool Runtime::SaveProfileInfo() const
1168 {
1169     return save_profiling_info_;
1170 }
1171 
CreateTrace(LanguageContext ctx,PandaUniquePtr<os::unix::file::File> trace_file,size_t buffer_size)1172 Trace *Runtime::CreateTrace([[maybe_unused]] LanguageContext ctx,
1173                             [[maybe_unused]] PandaUniquePtr<os::unix::file::File> trace_file,
1174                             [[maybe_unused]] size_t buffer_size)
1175 {
1176     LOG(FATAL, RUNTIME) << "Method tracing isn't supported at the moment!";
1177     return nullptr;
1178 }
1179 }  // namespace panda
1180