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