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