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