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