mirror of
https://github.com/openharmony/ark_runtime_core.git
synced 2026-07-18 18:24:30 -04:00
04a4ad57e1
Signed-off-by: huangyu <huangyu76@huawei.com> Change-Id: I9ab44583d364fec1f73aa10d6d066e730b320c17
1181 lines
38 KiB
C++
1181 lines
38 KiB
C++
/*
|
|
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "runtime/include/runtime.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
#include "assembler/assembly-literals.h"
|
|
#include "intrinsics.h"
|
|
#include "libpandabase/events/events.h"
|
|
#include "libpandabase/mem/mem_config.h"
|
|
#include "libpandabase/mem/pool_manager.h"
|
|
#include "libpandabase/os/mem_hooks.h"
|
|
#include "libpandabase/os/native_stack.h"
|
|
#include "libpandabase/os/thread.h"
|
|
#include "libpandabase/utils/arena_containers.h"
|
|
#include "libpandabase/utils/logger.h"
|
|
#include "libpandabase/utils/dfx.h"
|
|
#include "libpandabase/utils/utf.h"
|
|
#include "libpandafile/file-inl.h"
|
|
#include "libpandafile/literal_data_accessor-inl.h"
|
|
#include "libpandafile/proto_data_accessor-inl.h"
|
|
#include "runtime/core/core_language_context.h"
|
|
#include "runtime/dprofiler/dprofiler.h"
|
|
#include "runtime/entrypoints/entrypoints.h"
|
|
#include "runtime/include/class_linker_extension.h"
|
|
#include "runtime/include/coretypes/array-inl.h"
|
|
#include "runtime/include/coretypes/string.h"
|
|
#include "runtime/include/language_context.h"
|
|
#include "runtime/include/locks.h"
|
|
#include "runtime/include/runtime_notification.h"
|
|
#include "runtime/include/thread.h"
|
|
#include "runtime/include/thread_scopes.h"
|
|
#include "runtime/include/tooling/debug_inf.h"
|
|
#include "mem/refstorage/reference_storage.h"
|
|
#include "runtime/mem/gc/gc_stats.h"
|
|
#include "runtime/mem/gc/stw-gc/stw-gc.h"
|
|
#include "runtime/mem/gc/crossing_map_singleton.h"
|
|
#include "runtime/mem/heap_manager.h"
|
|
#include "runtime/mem/memory_manager.h"
|
|
#include "runtime/mem/internal_allocator-inl.h"
|
|
#include "runtime/core/core_class_linker_extension.h"
|
|
#include "runtime/include/panda_vm.h"
|
|
#include "runtime/tooling/debugger.h"
|
|
#include "runtime/tooling/pt_lang_ext_private.h"
|
|
#include "runtime/include/file_manager.h"
|
|
#include "trace/trace.h"
|
|
#include "verification/cache/file_entity_cache.h"
|
|
#include "verification/cache/results_cache.h"
|
|
#include "verification/debug/config_load.h"
|
|
#include "verification/debug/context/context.h"
|
|
#include "verification/job_queue/job_queue.h"
|
|
#include "verification/type/type_systems.h"
|
|
|
|
namespace panda {
|
|
|
|
using std::unique_ptr;
|
|
|
|
Runtime *Runtime::instance = nullptr;
|
|
RuntimeOptions Runtime::options_; // NOLINT(fuchsia-statically-constructed-objects)
|
|
os::memory::Mutex Runtime::mutex; // NOLINT(fuchsia-statically-constructed-objects)
|
|
|
|
class RuntimeInternalAllocator {
|
|
public:
|
|
static mem::InternalAllocatorPtr Create(bool use_malloc_for_internal_allocation)
|
|
{
|
|
ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() == nullptr);
|
|
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
mem_stats_s_ = new (std::nothrow) mem::MemStatsType();
|
|
ASSERT(mem_stats_s_ != nullptr);
|
|
|
|
if (use_malloc_for_internal_allocation) {
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
internal_allocator_s_ = new (std::nothrow)
|
|
mem::InternalAllocatorT<mem::InternalAllocatorConfig::MALLOC_ALLOCATOR>(mem_stats_s_);
|
|
} else {
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
internal_allocator_s_ = new (std::nothrow)
|
|
mem::InternalAllocatorT<mem::InternalAllocatorConfig::PANDA_ALLOCATORS>(mem_stats_s_);
|
|
}
|
|
ASSERT(internal_allocator_s_ != nullptr);
|
|
mem::InternalAllocator<>::InitInternalAllocatorFromRuntime(
|
|
static_cast<mem::Allocator *>(internal_allocator_s_));
|
|
|
|
return internal_allocator_s_;
|
|
}
|
|
|
|
static void Finalize()
|
|
{
|
|
internal_allocator_s_->VisitAndRemoveAllPools(
|
|
[](void *mem, size_t size) { PoolManager::GetMmapMemPool()->FreePool(mem, size); });
|
|
}
|
|
|
|
static void Destroy()
|
|
{
|
|
ASSERT(mem::InternalAllocator<>::GetInternalAllocatorFromRuntime() != nullptr);
|
|
|
|
mem::InternalAllocator<>::ClearInternalAllocatorFromRuntime();
|
|
delete static_cast<mem::Allocator *>(internal_allocator_s_);
|
|
internal_allocator_s_ = nullptr;
|
|
|
|
// One more check that we don't have memory leak in internal allocator.
|
|
ASSERT(mem_stats_s_->GetFootprint(SpaceType::SPACE_TYPE_INTERNAL) == 0);
|
|
delete mem_stats_s_;
|
|
mem_stats_s_ = nullptr;
|
|
}
|
|
|
|
static mem::InternalAllocatorPtr Get()
|
|
{
|
|
ASSERT(internal_allocator_s_ != nullptr);
|
|
return internal_allocator_s_;
|
|
}
|
|
|
|
private:
|
|
static mem::MemStatsType *mem_stats_s_;
|
|
static mem::InternalAllocatorPtr internal_allocator_s_; // NOLINT(fuchsia-statically-constructed-objects)
|
|
};
|
|
|
|
mem::MemStatsType *RuntimeInternalAllocator::mem_stats_s_ = nullptr;
|
|
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
|
|
mem::InternalAllocatorPtr RuntimeInternalAllocator::internal_allocator_s_ = nullptr;
|
|
|
|
// all GetLanguageContext(...) methods should be based on this one
|
|
LanguageContext Runtime::GetLanguageContext(panda_file::SourceLang lang)
|
|
{
|
|
auto *ctx = language_contexts_[static_cast<size_t>(lang)];
|
|
ASSERT(ctx != nullptr);
|
|
return LanguageContext(ctx);
|
|
}
|
|
|
|
LanguageContext Runtime::GetLanguageContext(const Method &method)
|
|
{
|
|
// See EcmaVM::GetMethodForNativeFunction
|
|
// Remove this 'if' when the function above gets fixed
|
|
if (method.GetPandaFile() != nullptr) {
|
|
panda_file::MethodDataAccessor mda(*method.GetPandaFile(), method.GetFileId());
|
|
auto res = mda.GetSourceLang();
|
|
if (res) {
|
|
return GetLanguageContext(res.value());
|
|
}
|
|
}
|
|
|
|
// Check class source lang
|
|
auto *cls = method.GetClass();
|
|
return GetLanguageContext(cls->GetSourceLang());
|
|
}
|
|
|
|
LanguageContext Runtime::GetLanguageContext(const Class &cls)
|
|
{
|
|
return GetLanguageContext(cls.GetSourceLang());
|
|
}
|
|
|
|
LanguageContext Runtime::GetLanguageContext(const BaseClass &cls)
|
|
{
|
|
return GetLanguageContext(cls.GetSourceLang());
|
|
}
|
|
|
|
LanguageContext Runtime::GetLanguageContext(panda_file::ClassDataAccessor *cda)
|
|
{
|
|
auto res = cda->GetSourceLang();
|
|
if (res) {
|
|
return GetLanguageContext(res.value());
|
|
}
|
|
|
|
return GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
|
|
}
|
|
|
|
LanguageContext Runtime::GetLanguageContext(const std::string &runtime_type)
|
|
{
|
|
if (runtime_type == "core") {
|
|
return GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
|
|
}
|
|
if (runtime_type == "ecmascript") {
|
|
return GetLanguageContext(panda_file::SourceLang::ECMASCRIPT);
|
|
}
|
|
LOG(FATAL, RUNTIME) << "Incorrect runtime_type: " << runtime_type;
|
|
UNREACHABLE();
|
|
}
|
|
|
|
/* static */
|
|
bool Runtime::CreateInstance(const RuntimeOptions &options, mem::InternalAllocatorPtr internal_allocator,
|
|
const std::vector<LanguageContextBase *> &ctxs)
|
|
{
|
|
Locks::Initialize();
|
|
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
|
|
if (options.WasSetEventsOutput()) {
|
|
Events::Create(options.GetEventsOutput(), options.GetEventsFile());
|
|
}
|
|
|
|
{
|
|
os::memory::LockHolder<os::memory::Mutex> lock(mutex);
|
|
|
|
if (instance != nullptr) {
|
|
return false;
|
|
}
|
|
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
instance = new Runtime(options, internal_allocator, ctxs);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* static */
|
|
bool Runtime::Create(const RuntimeOptions &options, const std::vector<LanguageContextBase *> &ctxs)
|
|
{
|
|
if (instance != nullptr) {
|
|
return false;
|
|
}
|
|
|
|
trace::ScopedTrace scoped_trace("Runtime::Create");
|
|
|
|
panda::mem::MemConfig::Initialize(options.GetHeapSizeLimit(), options.GetInternalMemorySizeLimit(),
|
|
options.GetCompilerMemorySizeLimit(), options.GetCodeCacheSizeLimit());
|
|
PoolManager::Initialize();
|
|
|
|
mem::InternalAllocatorPtr internal_allocator =
|
|
RuntimeInternalAllocator::Create(options.UseMallocForInternalAllocations());
|
|
|
|
BlockSignals();
|
|
|
|
CreateDfxController(options);
|
|
|
|
CreateInstance(options, internal_allocator, ctxs);
|
|
|
|
if (instance == nullptr) {
|
|
LOG(ERROR, RUNTIME) << "Failed to create runtime instance";
|
|
return false;
|
|
}
|
|
|
|
if (!instance->Initialize()) {
|
|
LOG(ERROR, RUNTIME) << "Failed to initialize runtime";
|
|
delete instance;
|
|
instance = nullptr;
|
|
return false;
|
|
}
|
|
|
|
instance->GetPandaVM()->StartGC();
|
|
|
|
auto *thread = ManagedThread::GetCurrent();
|
|
instance->GetNotificationManager()->VmStartEvent();
|
|
instance->GetNotificationManager()->VmInitializationEvent(thread->GetId());
|
|
instance->GetNotificationManager()->ThreadStartEvent(thread->GetId());
|
|
|
|
return true;
|
|
}
|
|
|
|
Runtime *Runtime::GetCurrent()
|
|
{
|
|
return instance;
|
|
}
|
|
|
|
/* static */
|
|
bool Runtime::DestroyUnderLockHolder()
|
|
{
|
|
os::memory::LockHolder<os::memory::Mutex> lock(mutex);
|
|
|
|
if (instance == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
if (!instance->Shutdown()) {
|
|
LOG(ERROR, RUNTIME) << "Failed to shutdown runtime";
|
|
return false;
|
|
}
|
|
if (GetOptions().WasSetEventsOutput()) {
|
|
Events::Destroy();
|
|
}
|
|
|
|
/**
|
|
* NOTE: Users threads can call log after destroying Runtime. We can't control these
|
|
* when they are in NATIVE_CODE mode because we don't destroy logger
|
|
* Logger::Destroy();
|
|
*/
|
|
|
|
DfxController::Destroy();
|
|
delete instance;
|
|
instance = nullptr;
|
|
panda::mem::MemConfig::Finalize();
|
|
|
|
return true;
|
|
}
|
|
|
|
/* static */
|
|
bool Runtime::Destroy()
|
|
{
|
|
if (instance == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
trace::ScopedTrace scoped_trace("Runtime shutdown");
|
|
instance->GetPandaVM()->StopGC();
|
|
|
|
instance->GetPandaVM()->UninitializeThreads();
|
|
|
|
verifier::JobQueue::Stop(instance->GetVerificationOptions().Mode.OnlyVerify);
|
|
|
|
instance->GetNotificationManager()->VmDeathEvent();
|
|
|
|
verifier::JobQueue::Destroy();
|
|
verifier::TypeSystems::Destroy();
|
|
verifier::VerificationResultCache::Destroy(Runtime::GetCurrent()->GetVerificationOptions().Cache.UpdateOnExit);
|
|
|
|
DestroyUnderLockHolder();
|
|
RuntimeInternalAllocator::Destroy();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Runtime::InitializeVerificationResultCache(const panda::RuntimeOptions &options)
|
|
{
|
|
auto &&verif_options = GetVerificationOptions();
|
|
if (verif_options.Enable) {
|
|
verifier::TypeSystems::Initialize();
|
|
verifier::JobQueue::Initialize(verif_options.Mode.VerificationThreads);
|
|
const auto &boot_panda_files = options.GetBootPandaFiles();
|
|
size_t files_len = options.GetPandaFiles().empty() ? boot_panda_files.size() - 1 : boot_panda_files.size();
|
|
for (size_t i = 0; i < files_len; i++) {
|
|
verifier::JobQueue::AddSystemFile(boot_panda_files[i]);
|
|
}
|
|
|
|
auto &&cache_file = verif_options.Cache.File;
|
|
if (!cache_file.empty()) {
|
|
verifier::VerificationResultCache::Initialize(cache_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
void Runtime::Halt(int32_t status)
|
|
{
|
|
Runtime *runtime = Runtime::GetCurrent();
|
|
if (runtime != nullptr && runtime->exit_ != nullptr) {
|
|
runtime->exit_(status);
|
|
}
|
|
|
|
// _exit is safer to call because it guarantees a safe
|
|
// completion in case of multi-threading as static destructors aren't called
|
|
_exit(status);
|
|
}
|
|
|
|
/* static */
|
|
void Runtime::Abort(const char *message /* = nullptr */)
|
|
{
|
|
Runtime *runtime = Runtime::GetCurrent();
|
|
if (runtime != nullptr && runtime->abort_ != nullptr) {
|
|
runtime->abort_();
|
|
}
|
|
|
|
std::cerr << "Runtime::Abort: " << (message != nullptr ? message : "") << std::endl;
|
|
std::abort();
|
|
}
|
|
|
|
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
|
Runtime::Runtime(const RuntimeOptions &options, mem::InternalAllocatorPtr internal_allocator,
|
|
const std::vector<LanguageContextBase *> &ctxs)
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
: internal_allocator_(internal_allocator),
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
notification_manager_(new RuntimeNotificationManager(internal_allocator_)),
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
debugger_library_(nullptr),
|
|
zygote_no_threads_(false)
|
|
{
|
|
Runtime::options_ = options;
|
|
// ECMAScript doesn't use intrinsics
|
|
if (options_.GetRuntimeType() == "ecmascript") {
|
|
options_.SetShouldInitializeIntrinsics(false);
|
|
}
|
|
|
|
auto spaces = GetOptions().GetBootClassSpaces();
|
|
|
|
// Default core context
|
|
static CoreLanguageContext lcCore;
|
|
language_contexts_[static_cast<size_t>(lcCore.GetLanguage())] = &lcCore;
|
|
|
|
for (const auto &ctx : ctxs) {
|
|
language_contexts_[static_cast<size_t>(ctx->GetLanguage())] = ctx;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<ClassLinkerExtension>> extensions;
|
|
extensions.reserve(spaces.size());
|
|
|
|
for (const auto &space : spaces) {
|
|
extensions.push_back(GetLanguageContext(space).CreateClassLinkerExtension());
|
|
}
|
|
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
class_linker_ = new ClassLinker(internal_allocator_, std::move(extensions));
|
|
#ifndef PANDA_TARGET_WINDOWS
|
|
// CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
|
|
signal_manager_ = new SignalManager(internal_allocator_);
|
|
#endif
|
|
|
|
if (IsEnableMemoryHooks()) {
|
|
// libbfd (which is used to get debug info from elf files) does a lot of allocations.
|
|
// Don't track allocations in this case.
|
|
if (!options_.IsSafepointBacktrace()) {
|
|
panda::os::mem_hooks::PandaHooks::Enable();
|
|
}
|
|
}
|
|
|
|
save_profiling_info_ = false;
|
|
|
|
VerificationOptions_.Initialize(options_);
|
|
InitializeVerificationResultCache(options_);
|
|
|
|
is_zygote_ = options_.IsStartAsZygote();
|
|
}
|
|
|
|
Runtime::~Runtime()
|
|
{
|
|
VerificationOptions_.Destroy();
|
|
panda::verifier::debug::DebugContext::Destroy();
|
|
|
|
if (IsEnableMemoryHooks()) {
|
|
panda::os::mem_hooks::PandaHooks::Disable();
|
|
}
|
|
trace::ScopedTrace scoped_trace("Delete state");
|
|
|
|
#ifndef PANDA_TARGET_WINDOWS
|
|
signal_manager_->DeleteHandlersArray();
|
|
delete signal_manager_;
|
|
#endif
|
|
delete class_linker_;
|
|
if (dprofiler_ != nullptr) {
|
|
internal_allocator_->Delete(dprofiler_);
|
|
}
|
|
delete notification_manager_;
|
|
|
|
if (pt_lang_ext_ != nullptr) {
|
|
internal_allocator_->Delete(pt_lang_ext_);
|
|
}
|
|
|
|
if (panda_vm_ != nullptr) {
|
|
internal_allocator_->Delete(panda_vm_);
|
|
}
|
|
|
|
// crossing map is shared by Java VM and Js VM.
|
|
mem::CrossingMapSingleton::Destroy();
|
|
|
|
RuntimeInternalAllocator::Finalize();
|
|
PoolManager::Finalize();
|
|
}
|
|
|
|
bool Runtime::IsEnableMemoryHooks() const
|
|
{
|
|
auto log_level = Logger::IsInitialized() ? Logger::GetLevel() : Logger::Level::DEBUG;
|
|
return options_.IsLimitStandardAlloc() &&
|
|
(log_level == Logger::Level::FATAL || log_level == Logger::Level::ERROR) &&
|
|
(!options_.UseMallocForInternalAllocations());
|
|
}
|
|
|
|
static PandaVector<PandaString> GetPandaFilesList(const std::vector<std::string> &stdvec)
|
|
{
|
|
PandaVector<PandaString> res;
|
|
for (const auto &i : stdvec) {
|
|
// NOLINTNEXTLINE(readability-redundant-string-cstr)
|
|
res.push_back(i.c_str());
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
PandaVector<PandaString> Runtime::GetBootPandaFiles()
|
|
{
|
|
// NOLINTNEXTLINE(readability-redundant-string-cstr)
|
|
const auto &boot_panda_files = GetPandaFilesList(options_.GetBootPandaFiles());
|
|
return boot_panda_files;
|
|
}
|
|
|
|
PandaVector<PandaString> Runtime::GetPandaFiles()
|
|
{
|
|
// NOLINTNEXTLINE(readability-redundant-string-cstr)
|
|
const auto &app_panda_files = GetPandaFilesList(options_.GetPandaFiles());
|
|
return app_panda_files;
|
|
}
|
|
|
|
bool Runtime::LoadBootPandaFiles(panda_file::File::OpenMode open_mode)
|
|
{
|
|
// NOLINTNEXTLINE(readability-redundant-string-cstr)
|
|
const auto &boot_panda_files = options_.GetBootPandaFiles();
|
|
for (const auto &name : boot_panda_files) {
|
|
if (!FileManager::LoadAbcFile(ConvertToString(name), open_mode)) {
|
|
LOG(ERROR, RUNTIME) << "Load boot panda file failed: " << name;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
mem::GCType Runtime::GetGCType(const RuntimeOptions &options)
|
|
{
|
|
auto gc_type = panda::mem::GCTypeFromString(options.GetGcType());
|
|
if (options.IsNoAsyncJit()) {
|
|
// With no-async-jit we can force compilation inside of c2i bridge (we have IncrementHotnessCounter there)
|
|
// and it can trigger GC which can move objects which are arguments for the method
|
|
// because StackWalker ignores c2i frame
|
|
return gc_type == panda::mem::GCType::GEN_GC ? panda::mem::GCType::STW_GC : gc_type;
|
|
}
|
|
return gc_type;
|
|
}
|
|
|
|
bool Runtime::LoadVerificationConfig()
|
|
{
|
|
const auto &options = GetVerificationOptions();
|
|
|
|
if (options.Enable) {
|
|
if (options.Mode.DebugEnable) {
|
|
if (!verifier::config::LoadConfig(options.Debug.ConfigFile)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Runtime::CreatePandaVM(std::string_view runtime_type)
|
|
{
|
|
if (!ManagedThread::Initialize()) {
|
|
LOG(ERROR, RUNTIME) << "Failed to initialize managed thread";
|
|
return false;
|
|
}
|
|
|
|
panda_vm_ = PandaVM::Create(this, options_, runtime_type);
|
|
if (panda_vm_ == nullptr) {
|
|
LOG(ERROR, RUNTIME) << "Failed to create panda vm";
|
|
return false;
|
|
}
|
|
|
|
panda_file::File::OpenMode open_mode = panda_file::File::READ_ONLY;
|
|
if (Runtime::GetOptions().GetRuntimeType() == "ecmascript") {
|
|
// In case of JS vm open a panda file for reading / writing
|
|
// because EcmaVM patches bytecode in-place
|
|
open_mode = panda_file::File::READ_WRITE;
|
|
}
|
|
bool load_boot_panda_files_is_failed = options_.ShouldLoadBootPandaFiles() && !LoadBootPandaFiles(open_mode);
|
|
if (load_boot_panda_files_is_failed) {
|
|
LOG(ERROR, RUNTIME) << "Failed to load boot panda files";
|
|
return false;
|
|
}
|
|
|
|
notification_manager_->SetRendezvous(panda_vm_->GetRendezvous());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Runtime::InitializePandaVM()
|
|
{
|
|
if (!class_linker_->Initialize(options_.IsRuntimeCompressedStringsEnabled())) {
|
|
LOG(ERROR, RUNTIME) << "Failed to initialize class loader";
|
|
return false;
|
|
}
|
|
|
|
if (options_.ShouldInitializeIntrinsics() && !intrinsics::Initialize()) {
|
|
LOG(ERROR, RUNTIME) << "Failed to initialize intrinsics";
|
|
return false;
|
|
}
|
|
|
|
std::string debug_library_path = options_.GetDebuggerLibraryPath();
|
|
if (!debug_library_path.empty()) {
|
|
if (!StartDebugger(debug_library_path)) {
|
|
LOG(ERROR, RUNTIME) << "Failed to start debugger";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!panda_vm_->Initialize()) {
|
|
LOG(ERROR, RUNTIME) << "Failed to initialize panda vm";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Runtime::CheckOptionsConsistency()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void Runtime::SetPandaPath()
|
|
{
|
|
PandaVector<PandaString> app_panda_files = GetPandaFiles();
|
|
for (size_t i = 0; i < app_panda_files.size(); ++i) {
|
|
panda_path_string_ += PandaStringToStd(app_panda_files[i]);
|
|
if (i != app_panda_files.size() - 1) {
|
|
panda_path_string_ += ":";
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Runtime::Initialize()
|
|
{
|
|
trace::ScopedTrace scoped_trace("Runtime::Initialize");
|
|
|
|
if (!CheckOptionsConsistency()) {
|
|
return false;
|
|
}
|
|
|
|
if (!LoadVerificationConfig()) {
|
|
return false;
|
|
}
|
|
|
|
auto runtime_type = options_.GetRuntimeType();
|
|
if (!CreatePandaVM(runtime_type)) {
|
|
return false;
|
|
}
|
|
|
|
if (!InitializePandaVM()) {
|
|
return false;
|
|
}
|
|
|
|
ManagedThread *thread = ManagedThread::GetCurrent();
|
|
class_linker_->InitializeRoots(thread);
|
|
auto ext = GetClassLinker()->GetExtension(GetLanguageContext(runtime_type));
|
|
if (ext != nullptr) {
|
|
thread->SetStringClassPtr(ext->GetClassRoot(ClassRoot::STRING));
|
|
}
|
|
|
|
fingerPrint_ = ConvertToString(options_.GetFingerprint());
|
|
|
|
SetPandaPath();
|
|
|
|
if (!panda_vm_->InitializeFinish()) {
|
|
LOG(ERROR, RUNTIME) << "Failed to finish panda vm initialization";
|
|
return false;
|
|
}
|
|
|
|
is_initialized_ = true;
|
|
return true;
|
|
}
|
|
|
|
static bool GetClassAndMethod(std::string_view entry_point, PandaString *class_name, PandaString *method_name)
|
|
{
|
|
size_t pos = entry_point.find_last_of("::");
|
|
if (pos == std::string_view::npos) {
|
|
return false;
|
|
}
|
|
|
|
*class_name = PandaString(entry_point.substr(0, pos - 1));
|
|
*method_name = PandaString(entry_point.substr(pos + 1));
|
|
|
|
return true;
|
|
}
|
|
|
|
static const uint8_t *GetStringArrayDescriptor(LanguageContext ctx, PandaString *out)
|
|
{
|
|
*out = "[";
|
|
*out += utf::Mutf8AsCString(ctx.GetStringClassDescriptor());
|
|
|
|
return utf::CStringAsMutf8(out->c_str());
|
|
}
|
|
|
|
Expected<Method *, Runtime::Error> Runtime::ResolveEntryPoint(std::string_view entry_point)
|
|
{
|
|
PandaString class_name;
|
|
PandaString method_name;
|
|
|
|
if (!GetClassAndMethod(entry_point, &class_name, &method_name)) {
|
|
LOG(ERROR, RUNTIME) << "Invalid entry point: " << entry_point;
|
|
return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
|
|
}
|
|
|
|
PandaString descriptor;
|
|
auto class_name_bytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor);
|
|
auto method_name_bytes = utf::CStringAsMutf8(method_name.c_str());
|
|
|
|
Class *cls = nullptr;
|
|
ClassLinkerContext *context = app_context_.ctx;
|
|
if (context == nullptr) {
|
|
context = class_linker_->GetExtension(GetLanguageContext(options_.GetRuntimeType()))->GetBootContext();
|
|
}
|
|
|
|
ManagedThread *thread = ManagedThread::GetCurrent();
|
|
if (MTManagedThread::ThreadIsMTManagedThread(thread)) {
|
|
ScopedManagedCodeThread sa(static_cast<MTManagedThread *>(thread));
|
|
cls = class_linker_->GetClass(class_name_bytes, true, context);
|
|
} else {
|
|
cls = class_linker_->GetClass(class_name_bytes, true, context);
|
|
}
|
|
|
|
if (cls == nullptr) {
|
|
LOG(ERROR, RUNTIME) << "Cannot find class '" << class_name << "'";
|
|
return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
|
|
}
|
|
|
|
LanguageContext ctx = GetLanguageContext(*cls);
|
|
PandaString string_array_descriptor;
|
|
GetStringArrayDescriptor(ctx, &string_array_descriptor);
|
|
|
|
Method::Proto proto(PandaVector<panda_file::Type> {panda_file::Type(panda_file::Type::TypeId::VOID),
|
|
panda_file::Type(panda_file::Type::TypeId::REFERENCE)},
|
|
PandaVector<std::string_view> {string_array_descriptor});
|
|
|
|
auto method = cls->GetDirectMethod(method_name_bytes, proto);
|
|
if (method == nullptr) {
|
|
method = cls->GetDirectMethod(method_name_bytes);
|
|
if (method == nullptr) {
|
|
LOG(ERROR, RUNTIME) << "Cannot find method '" << entry_point << "'";
|
|
return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
|
|
}
|
|
}
|
|
|
|
return method;
|
|
}
|
|
|
|
PandaString Runtime::GetMemoryStatistics()
|
|
{
|
|
return panda_vm_->GetMemStats()->GetStatistics(panda_vm_->GetHeapManager());
|
|
}
|
|
|
|
PandaString Runtime::GetFinalStatistics()
|
|
{
|
|
return panda_vm_->GetGCStats()->GetFinalStatistics(panda_vm_->GetHeapManager());
|
|
}
|
|
|
|
void Runtime::NotifyAboutLoadedModules()
|
|
{
|
|
PandaVector<const panda_file::File *> pfs;
|
|
|
|
class_linker_->EnumerateBootPandaFiles([&pfs](const panda_file::File &pf) {
|
|
pfs.push_back(&pf);
|
|
return true;
|
|
});
|
|
|
|
for (const auto *pf : pfs) {
|
|
GetNotificationManager()->LoadModuleEvent(pf->GetFilename());
|
|
}
|
|
}
|
|
|
|
Expected<LanguageContext, Runtime::Error> Runtime::ExtractLanguageContext(const panda_file::File *pf,
|
|
std::string_view entry_point)
|
|
{
|
|
PandaString class_name;
|
|
PandaString method_name;
|
|
if (!GetClassAndMethod(entry_point, &class_name, &method_name)) {
|
|
LOG(ERROR, RUNTIME) << "Invalid entry point: " << entry_point;
|
|
return Unexpected(Runtime::Error::INVALID_ENTRY_POINT);
|
|
}
|
|
|
|
PandaString descriptor;
|
|
auto class_name_bytes = ClassHelper::GetDescriptor(utf::CStringAsMutf8(class_name.c_str()), &descriptor);
|
|
auto method_name_bytes = utf::CStringAsMutf8(method_name.c_str());
|
|
|
|
auto class_id = pf->GetClassId(class_name_bytes);
|
|
if (!class_id.IsValid() || pf->IsExternal(class_id)) {
|
|
LOG(ERROR, RUNTIME) << "Cannot find class '" << class_name << "'";
|
|
return Unexpected(Runtime::Error::CLASS_NOT_FOUND);
|
|
}
|
|
|
|
panda_file::ClassDataAccessor cda(*pf, class_id);
|
|
LanguageContext ctx = GetLanguageContext(&cda);
|
|
bool found = false;
|
|
cda.EnumerateMethods([this, &pf, method_name_bytes, &found, &ctx](panda_file::MethodDataAccessor &mda) {
|
|
if (!found && utf::IsEqual(pf->GetStringData(mda.GetNameId()).data, method_name_bytes)) {
|
|
found = true;
|
|
auto val = mda.GetSourceLang();
|
|
if (val) {
|
|
ctx = GetLanguageContext(val.value());
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!found) {
|
|
LOG(ERROR, RUNTIME) << "Cannot find method '" << entry_point << "'";
|
|
return Unexpected(Runtime::Error::METHOD_NOT_FOUND);
|
|
}
|
|
|
|
return ctx;
|
|
}
|
|
|
|
std::optional<Runtime::Error> Runtime::CreateApplicationClassLinkerContext(std::string_view filename,
|
|
std::string_view entry_point)
|
|
{
|
|
bool is_loaded = false;
|
|
class_linker_->EnumerateBootPandaFiles([&is_loaded, filename](const panda_file::File &pf) {
|
|
if (pf.GetFilename() == filename) {
|
|
is_loaded = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
if (is_loaded) {
|
|
return {};
|
|
}
|
|
|
|
auto pf = panda_file::OpenPandaFileOrZip(filename);
|
|
if (pf == nullptr) {
|
|
return Runtime::Error::PANDA_FILE_LOAD_ERROR;
|
|
}
|
|
|
|
auto res = ExtractLanguageContext(pf.get(), entry_point);
|
|
if (!res) {
|
|
return res.Error();
|
|
}
|
|
|
|
if (!class_linker_->HasExtension(res.Value())) {
|
|
LOG(ERROR, RUNTIME) << "class linker hasn't " << res.Value() << " language extension";
|
|
return Runtime::Error::CLASS_LINKER_EXTENSION_NOT_FOUND;
|
|
}
|
|
|
|
auto *ext = class_linker_->GetExtension(res.Value());
|
|
app_context_.lang = ext->GetLanguage();
|
|
app_context_.ctx = class_linker_->GetAppContext(filename);
|
|
if (app_context_.ctx == nullptr) {
|
|
auto app_files = GetPandaFiles();
|
|
auto found_iter = std::find_if(app_files.begin(), app_files.end(),
|
|
[&](auto &app_file_name) { return app_file_name == filename; });
|
|
if (found_iter == app_files.end()) {
|
|
PandaString path(filename);
|
|
app_files.push_back(path);
|
|
}
|
|
app_context_.ctx = ext->CreateApplicationClassLinkerContext(app_files);
|
|
}
|
|
|
|
tooling::DebugInf::AddCodeMetaInfo(pf.get());
|
|
return {};
|
|
}
|
|
|
|
Expected<int, Runtime::Error> Runtime::ExecutePandaFile(std::string_view filename, std::string_view entry_point,
|
|
const std::vector<std::string> &args)
|
|
{
|
|
if (options_.IsDistributedProfiling()) {
|
|
// Create app name from path to executable file.
|
|
std::string_view app_name = [](std::string_view path) -> std::string_view {
|
|
auto pos = path.find_last_of('/');
|
|
return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
|
|
}(filename);
|
|
StartDProfiler(app_name);
|
|
}
|
|
|
|
auto ctx_err = CreateApplicationClassLinkerContext(filename, entry_point);
|
|
if (ctx_err) {
|
|
return Unexpected(ctx_err.value());
|
|
}
|
|
|
|
return Execute(entry_point, args);
|
|
}
|
|
|
|
Expected<int, Runtime::Error> Runtime::Execute(std::string_view entry_point, const std::vector<std::string> &args)
|
|
{
|
|
auto resolve_res = ResolveEntryPoint(entry_point);
|
|
if (!resolve_res) {
|
|
return Unexpected(resolve_res.Error());
|
|
}
|
|
|
|
NotifyAboutLoadedModules();
|
|
|
|
Method *method = resolve_res.Value();
|
|
|
|
return panda_vm_->InvokeEntrypoint(method, args);
|
|
}
|
|
|
|
void Runtime::RegisterAppInfo(const PandaVector<PandaString> &code_paths, const PandaString &profile_output_filename)
|
|
{
|
|
for (const auto &str : code_paths) {
|
|
LOG(INFO, RUNTIME) << "Code path: " << str;
|
|
}
|
|
std::string_view app_name = [](std::string_view path) -> std::string_view {
|
|
auto pos = path.find_last_of('/');
|
|
return path.substr((pos == std::string_view::npos) ? 0 : (pos + 1));
|
|
}(profile_output_filename);
|
|
|
|
StartDProfiler(app_name);
|
|
}
|
|
|
|
int Runtime::StartDProfiler(std::string_view app_name)
|
|
{
|
|
if (dprofiler_ != nullptr) {
|
|
LOG(ERROR, RUNTIME) << "DProfiller already started";
|
|
return -1;
|
|
}
|
|
|
|
dprofiler_ = internal_allocator_->New<DProfiler>(app_name, Runtime::GetCurrent());
|
|
return 0;
|
|
}
|
|
|
|
bool Runtime::StartDebugger(const std::string &library_path)
|
|
{
|
|
auto handle = os::library_loader::Load(library_path);
|
|
if (!handle) {
|
|
return true;
|
|
}
|
|
|
|
using StartDebuggerT = int (*)(uint32_t, tooling::DebugInterface *, void *);
|
|
|
|
auto sym = os::library_loader::ResolveSymbol(handle.Value(), "StartDebugger");
|
|
if (!sym) {
|
|
LOG(ERROR, RUNTIME) << sym.Error().ToString();
|
|
return false;
|
|
}
|
|
|
|
uint32_t port = options_.GetDebuggerPort();
|
|
SetDebugMode(true);
|
|
if (!AttachDebugger()) {
|
|
return false;
|
|
}
|
|
ASSERT(debugger_ != nullptr);
|
|
|
|
int res = reinterpret_cast<StartDebuggerT>(sym.Value())(port, debugger_, nullptr);
|
|
if (res != 0) {
|
|
LOG(ERROR, RUNTIME) << "StartDebugger has failed";
|
|
return false;
|
|
}
|
|
|
|
ASSERT(!debugger_library_.IsValid());
|
|
debugger_library_ = std::move(handle.Value());
|
|
|
|
// Turn off stdout buffering in debug mode
|
|
setvbuf(stdout, nullptr, _IONBF, 0);
|
|
return true;
|
|
}
|
|
|
|
bool Runtime::AttachDebugger()
|
|
{
|
|
ASSERT(is_debug_mode_);
|
|
auto pt_lang_ext = tooling::CreatePtLangExt(options_.GetRuntimeType());
|
|
if (!pt_lang_ext) {
|
|
LOG(ERROR, RUNTIME) << "Cannot create PtLangExt";
|
|
return false;
|
|
}
|
|
pt_lang_ext_ = pt_lang_ext.release();
|
|
ASSERT(debugger_ == nullptr);
|
|
debugger_ = internal_allocator_->New<tooling::Debugger>(this);
|
|
return true;
|
|
}
|
|
|
|
bool Runtime::Shutdown()
|
|
{
|
|
if (IsDebugMode() && debugger_library_.IsValid()) {
|
|
using StopDebugger = int (*)();
|
|
|
|
ASSERT(debugger_library_.IsValid());
|
|
auto sym = os::library_loader::ResolveSymbol(debugger_library_, "StopDebugger");
|
|
if (!sym) {
|
|
LOG(ERROR, RUNTIME) << sym.Error().ToString();
|
|
return false;
|
|
}
|
|
|
|
int res = reinterpret_cast<StopDebugger>(sym.Value())();
|
|
if (res != 0) {
|
|
LOG(ERROR, RUNTIME) << "StopDebugger has failed";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (debugger_ != nullptr) {
|
|
internal_allocator_->Delete(debugger_);
|
|
}
|
|
|
|
return ManagedThread::Shutdown();
|
|
}
|
|
|
|
coretypes::String *Runtime::ResolveString(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
|
|
{
|
|
auto *pf = caller.GetPandaFile();
|
|
LanguageContext ctx = GetLanguageContext(caller);
|
|
return ResolveString(vm, *pf, id, ctx);
|
|
}
|
|
|
|
coretypes::String *Runtime::ResolveString(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
|
|
LanguageContext ctx)
|
|
{
|
|
coretypes::String *str = vm->GetStringTable()->GetInternalStringFast(pf, id);
|
|
if (str != nullptr) {
|
|
return str;
|
|
}
|
|
str = vm->GetStringTable()->GetOrInternInternalString(pf, id, ctx);
|
|
return str;
|
|
}
|
|
|
|
coretypes::String *Runtime::ResolveString(PandaVM *vm, const uint8_t *mutf8, uint32_t length, LanguageContext ctx)
|
|
{
|
|
return vm->GetStringTable()->GetOrInternString(mutf8, length, ctx);
|
|
}
|
|
|
|
coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const Method &caller, panda_file::File::EntityId id)
|
|
{
|
|
auto *pf = caller.GetPandaFile();
|
|
LanguageContext ctx = GetLanguageContext(caller);
|
|
return ResolveLiteralArray(vm, *pf, id, ctx);
|
|
}
|
|
|
|
Class *Runtime::GetClassRootForLiteralTag(const ClassLinkerExtension &ext, panda_file::LiteralTag tag) const
|
|
{
|
|
switch (tag) {
|
|
case panda_file::LiteralTag::ARRAY_I8:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_I8);
|
|
case panda_file::LiteralTag::ARRAY_I16:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_I16);
|
|
case panda_file::LiteralTag::ARRAY_I32:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_I32);
|
|
case panda_file::LiteralTag::ARRAY_I64:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_I64);
|
|
case panda_file::LiteralTag::ARRAY_F32:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_F32);
|
|
case panda_file::LiteralTag::ARRAY_F64:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_F64);
|
|
case panda_file::LiteralTag::ARRAY_STRING:
|
|
return ext.GetClassRoot(ClassRoot::ARRAY_STRING);
|
|
case panda_file::LiteralTag::TAGVALUE:
|
|
case panda_file::LiteralTag::BOOL:
|
|
case panda_file::LiteralTag::INTEGER:
|
|
case panda_file::LiteralTag::FLOAT:
|
|
case panda_file::LiteralTag::DOUBLE:
|
|
case panda_file::LiteralTag::STRING:
|
|
case panda_file::LiteralTag::METHOD:
|
|
case panda_file::LiteralTag::GENERATORMETHOD:
|
|
case panda_file::LiteralTag::ACCESSOR:
|
|
case panda_file::LiteralTag::NULLVALUE: {
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
UNREACHABLE();
|
|
return nullptr;
|
|
}
|
|
|
|
/* static */
|
|
bool Runtime::GetLiteralTagAndValue(const panda_file::File &pf, panda_file::File::EntityId id,
|
|
panda_file::LiteralTag *tag, panda_file::LiteralDataAccessor::LiteralValue *value)
|
|
{
|
|
panda_file::File::EntityId literalArraysId = pf.GetLiteralArraysId();
|
|
panda_file::LiteralDataAccessor literal_data_accessor(pf, literalArraysId);
|
|
bool result = false;
|
|
literal_data_accessor.EnumerateLiteralVals(
|
|
id, [tag, value, &result](const panda_file::LiteralDataAccessor::LiteralValue &val,
|
|
const panda_file::LiteralTag &tg) {
|
|
*tag = tg;
|
|
*value = val;
|
|
result = true;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
coretypes::Array *Runtime::ResolveLiteralArray(PandaVM *vm, const panda_file::File &pf, panda_file::File::EntityId id,
|
|
LanguageContext ctx)
|
|
{
|
|
panda_file::LiteralTag tag;
|
|
panda_file::LiteralDataAccessor::LiteralValue value;
|
|
|
|
coretypes::Array *array = nullptr;
|
|
|
|
if (GetLiteralTagAndValue(pf, id, &tag, &value)) {
|
|
panda_file::File::EntityId value_id(std::get<uint32_t>(value));
|
|
auto sp = pf.GetSpanFromId(value_id);
|
|
auto len = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
|
|
auto ext = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx);
|
|
// special handling of arrays of strings
|
|
if (tag == panda_file::LiteralTag::ARRAY_STRING) {
|
|
array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), len);
|
|
VMHandle<coretypes::Array> obj(ManagedThread::GetCurrent(), array);
|
|
// NOLINTNEXTLINE(modernize-loop-convert)
|
|
for (size_t i = 0; i < len; i++) {
|
|
auto str_id = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
|
|
auto str = Runtime::GetCurrent()->ResolveString(vm, pf, panda_file::File::EntityId(str_id), ctx);
|
|
obj->Set<ObjectHeader *>(i, str);
|
|
}
|
|
array = obj.GetPtr();
|
|
} else {
|
|
array = coretypes::Array::Create(GetClassRootForLiteralTag(*ext, tag), sp.data(), len);
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
void Runtime::UpdateProcessState([[maybe_unused]] int state)
|
|
{
|
|
LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
|
|
}
|
|
|
|
void Runtime::RegisterSensitiveThread() const
|
|
{
|
|
LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
|
|
}
|
|
|
|
void Runtime::CreateDfxController(const RuntimeOptions &options)
|
|
{
|
|
DfxController::Initialize();
|
|
#ifdef PANDA_TARGET_UNIX
|
|
DfxController::SetOptionValue(DfxOptionHandler::REFERENCE_DUMP, options.GetReferenceDump());
|
|
DfxController::SetOptionValue(DfxOptionHandler::SIGNAL_HANDLER, options.GetSignalHandler());
|
|
DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGQUIT, options.GetSigquitFlag());
|
|
DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR1, options.GetSigusr1Flag());
|
|
DfxController::SetOptionValue(DfxOptionHandler::ARK_SIGUSR2, options.GetSigusr2Flag());
|
|
DfxController::SetOptionValue(DfxOptionHandler::MOBILE_LOG, options.GetMobileLogFlag());
|
|
#endif
|
|
DfxController::SetOptionValue(DfxOptionHandler::DFXLOG, options.GetDfxLog());
|
|
}
|
|
|
|
void Runtime::BlockSignals()
|
|
{
|
|
#if defined(PANDA_TARGET_UNIX)
|
|
sigset_t set;
|
|
if (sigemptyset(&set) == -1) {
|
|
LOG(ERROR, RUNTIME) << "sigemptyset failed";
|
|
return;
|
|
}
|
|
#ifdef PANDA_TARGET_MOBILE
|
|
int rc = 0;
|
|
rc += sigaddset(&set, SIGQUIT);
|
|
rc += sigaddset(&set, SIGUSR1);
|
|
rc += sigaddset(&set, SIGUSR2);
|
|
if (rc < 0) {
|
|
LOG(ERROR, RUNTIME) << "sigaddset failed";
|
|
return;
|
|
}
|
|
#endif // PANDA_TARGET_MOBILE
|
|
|
|
if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
|
|
LOG(ERROR, RUNTIME) << "PandaThreadSigmask failed";
|
|
}
|
|
#endif // PANDA_TARGET_UNIX
|
|
}
|
|
|
|
void Runtime::DumpForSigQuit(std::ostream &os)
|
|
{
|
|
os << "\n";
|
|
os << "-> Dump class loaders\n";
|
|
class_linker_->EnumerateContextsForDump(
|
|
[](ClassLinkerContext *ctx, std::ostream &stream, ClassLinkerContext *parent) {
|
|
ctx->Dump(stream);
|
|
return ctx->FindClassLoaderParent(parent);
|
|
},
|
|
os);
|
|
os << "\n";
|
|
|
|
// dump GC
|
|
os << "-> Dump GC\n";
|
|
os << GetFinalStatistics();
|
|
os << "\n";
|
|
|
|
// dump memory management
|
|
os << "-> Dump memory management\n";
|
|
os << GetMemoryStatistics();
|
|
os << "\n";
|
|
}
|
|
|
|
void Runtime::PreZygoteFork()
|
|
{
|
|
panda_vm_->PreZygoteFork();
|
|
}
|
|
|
|
void Runtime::PostZygoteFork()
|
|
{
|
|
panda_vm_->PostZygoteFork();
|
|
}
|
|
|
|
// Returns true if profile saving is enabled. GetJit() will be not null in this case.
|
|
bool Runtime::SaveProfileInfo() const
|
|
{
|
|
return save_profiling_info_;
|
|
}
|
|
|
|
} // namespace panda
|