mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2025-03-01 16:59:12 +00:00

issues:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6PLGA?from=project-issue Signed-off-by: changjiaxing <changjiaxing2@huawei.com> Change-Id: I098fc30d850e69b4fc6e6b2197ac735c944829c7
394 lines
13 KiB
C++
394 lines
13 KiB
C++
/*
|
|
* Copyright (c) 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 "ecmascript/jspandafile/js_pandafile_manager.h"
|
|
|
|
#include "ecmascript/aot_file_manager.h"
|
|
#include "ecmascript/base/path_helper.h"
|
|
#include "ecmascript/jspandafile/program_object.h"
|
|
#include "ecmascript/js_file_path.h"
|
|
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
|
|
|
|
namespace panda::ecmascript {
|
|
static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options
|
|
|
|
JSPandaFileManager *JSPandaFileManager::GetInstance()
|
|
{
|
|
static JSPandaFileManager jsFileManager;
|
|
return &jsFileManager;
|
|
}
|
|
|
|
JSPandaFileManager::~JSPandaFileManager()
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
|
|
extractors_.clear();
|
|
|
|
auto iterOld = oldJSPandaFiles_.begin();
|
|
while (iterOld != oldJSPandaFiles_.end()) {
|
|
const JSPandaFile *jsPandaFile = iterOld->first;
|
|
ReleaseJSPandaFile(jsPandaFile);
|
|
iterOld = oldJSPandaFiles_.erase(iterOld);
|
|
}
|
|
auto iter = loadedJSPandaFiles_.begin();
|
|
while (iter != loadedJSPandaFiles_.end()) {
|
|
const JSPandaFile *jsPandaFile = iter->second.first;
|
|
ReleaseJSPandaFile(jsPandaFile);
|
|
iter = loadedJSPandaFiles_.erase(iter);
|
|
}
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
|
|
std::string_view entryPoint, bool needUpdate)
|
|
{
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
const JSPandaFile *jsPandaFile = nullptr;
|
|
if (needUpdate) {
|
|
auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
|
|
if (pf == nullptr) {
|
|
LOG_ECMA(ERROR) << "open file " << filename << " error";
|
|
return nullptr;
|
|
}
|
|
jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
|
|
} else {
|
|
jsPandaFile = FindJSPandaFileUnlocked(filename);
|
|
}
|
|
if (jsPandaFile != nullptr) {
|
|
if (!thread->GetEcmaVM()->HasCachedConstpool(jsPandaFile)) {
|
|
IncreaseRefJSPandaFileUnlocked(jsPandaFile);
|
|
}
|
|
return jsPandaFile;
|
|
}
|
|
}
|
|
|
|
bool mode = thread->GetEcmaVM()->GetModuleManager()->GetCurrentMode();
|
|
std::unique_ptr<const panda_file::File> pf;
|
|
if (!thread->GetEcmaVM()->IsBundlePack() && mode) {
|
|
ResolveBufferCallback resolveBufferCallback = thread->GetEcmaVM()->GetResolveBufferCallback();
|
|
if (resolveBufferCallback == nullptr) {
|
|
LOG_ECMA(ERROR) << "JSPandaFileExecutor::ExecuteFromFile resolveBufferCallback is nullptr";
|
|
return nullptr;
|
|
}
|
|
std::vector<uint8_t> data = resolveBufferCallback(base::PathHelper::ParseHapPath(filename));
|
|
if (data.empty()) {
|
|
LOG_ECMA(ERROR) << "JSPandaFileExecutor::ExecuteFromFile resolveBufferCallback get buffer failed";
|
|
return nullptr;
|
|
}
|
|
pf = panda_file::OpenPandaFileFromMemory(data.data(), data.size());
|
|
} else {
|
|
pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
|
|
}
|
|
|
|
if (pf == nullptr) {
|
|
LOG_ECMA(ERROR) << "open file " << filename << " error";
|
|
return nullptr;
|
|
}
|
|
return GenerateJSPandaFile(thread, pf.release(), filename, entryPoint);
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::LoadJSPandaFile(JSThread *thread, const CString &filename,
|
|
std::string_view entryPoint, const void *buffer, size_t size, bool needUpdate)
|
|
{
|
|
if (buffer == nullptr || size == 0) {
|
|
return nullptr;
|
|
}
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
const JSPandaFile *jsPandaFile = nullptr;
|
|
if (needUpdate) {
|
|
auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
|
|
if (pf == nullptr) {
|
|
LOG_ECMA(ERROR) << "open file " << filename << " error";
|
|
return nullptr;
|
|
}
|
|
jsPandaFile = FindJSPandaFileWithChecksum(filename, pf->GetHeader()->checksum);
|
|
} else {
|
|
jsPandaFile = FindJSPandaFileUnlocked(filename);
|
|
}
|
|
if (jsPandaFile != nullptr) {
|
|
if (!thread->GetEcmaVM()->HasCachedConstpool(jsPandaFile)) {
|
|
IncreaseRefJSPandaFileUnlocked(jsPandaFile);
|
|
}
|
|
return jsPandaFile;
|
|
}
|
|
}
|
|
|
|
auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
|
|
if (pf == nullptr) {
|
|
LOG_ECMA(ERROR) << "open file " << filename << " error";
|
|
return nullptr;
|
|
}
|
|
return GenerateJSPandaFile(thread, pf.release(), filename, entryPoint);
|
|
}
|
|
|
|
JSHandle<Program> JSPandaFileManager::GenerateProgram(
|
|
EcmaVM *vm, const JSPandaFile *jsPandaFile, std::string_view entryPoint)
|
|
{
|
|
ASSERT(GetJSPandaFile(jsPandaFile->GetPandaFile()) != nullptr);
|
|
if (AnFileDataManager::GetInstance()->IsEnable()) {
|
|
vm->GetAOTFileManager()->LoadAiFile(jsPandaFile);
|
|
}
|
|
|
|
return PandaFileTranslator::GenerateProgram(vm, jsPandaFile, entryPoint);
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::FindJSPandaFileWithChecksum(const CString &filename, uint32_t checksum)
|
|
{
|
|
const JSPandaFile *jsPandaFile = FindJSPandaFileUnlocked(filename);
|
|
if (jsPandaFile != nullptr) {
|
|
if (checksum == jsPandaFile->GetChecksum()) {
|
|
return jsPandaFile;
|
|
} else {
|
|
LOG_FULL(INFO) << "reload " << filename << " with new checksum";
|
|
ObsoleteLoadedJSPandaFile(filename);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::FindJSPandaFileUnlocked(const CString &filename)
|
|
{
|
|
if (filename.empty()) {
|
|
return nullptr;
|
|
}
|
|
auto const iter = loadedJSPandaFiles_.find(filename);
|
|
if (iter == loadedJSPandaFiles_.end()) {
|
|
return nullptr;
|
|
}
|
|
return iter->second.first;
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::FindJSPandaFile(const CString &filename)
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
return FindJSPandaFileUnlocked(filename);
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::GetJSPandaFile(const panda_file::File *pf)
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
for (const auto &iter : loadedJSPandaFiles_) {
|
|
const JSPandaFile *jsPandafile = iter.second.first;
|
|
if (jsPandafile->GetPandaFile() == pf) {
|
|
return jsPandafile;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void JSPandaFileManager::InsertJSPandaFile(const JSPandaFile *jsPandaFile)
|
|
{
|
|
const auto &filename = jsPandaFile->GetJSPandaFileDesc();
|
|
std::pair<const JSPandaFile *, uint32_t> pandaFileRecord = std::make_pair(jsPandaFile, 1);
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
ASSERT(loadedJSPandaFiles_.find(filename) == loadedJSPandaFiles_.end());
|
|
loadedJSPandaFiles_[filename] = pandaFileRecord;
|
|
}
|
|
|
|
void JSPandaFileManager::IncreaseRefJSPandaFileUnlocked(const JSPandaFile *jsPandaFile)
|
|
{
|
|
auto const filename = jsPandaFile->GetJSPandaFileDesc();
|
|
auto iter = loadedJSPandaFiles_.find(filename);
|
|
ASSERT(iter != loadedJSPandaFiles_.end());
|
|
iter->second.second++;
|
|
}
|
|
|
|
void JSPandaFileManager::DecreaseRefJSPandaFile(const JSPandaFile *jsPandaFile)
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
auto iterOld = oldJSPandaFiles_.find(jsPandaFile);
|
|
if (iterOld != oldJSPandaFiles_.end()) {
|
|
if (iterOld->second > 1) {
|
|
iterOld->second--;
|
|
return;
|
|
}
|
|
oldJSPandaFiles_.erase(iterOld);
|
|
} else {
|
|
const auto &filename = jsPandaFile->GetJSPandaFileDesc();
|
|
auto iter = loadedJSPandaFiles_.find(filename);
|
|
if (iter != loadedJSPandaFiles_.end()) {
|
|
if (iter->second.second > 1) {
|
|
iter->second.second--;
|
|
return;
|
|
}
|
|
loadedJSPandaFiles_.erase(iter);
|
|
}
|
|
}
|
|
extractors_.erase(jsPandaFile);
|
|
ReleaseJSPandaFile(jsPandaFile);
|
|
}
|
|
|
|
void JSPandaFileManager::ObsoleteLoadedJSPandaFile(const CString &filename)
|
|
{
|
|
auto iter = loadedJSPandaFiles_.find(filename);
|
|
ASSERT(iter != loadedJSPandaFiles_.end());
|
|
const JSPandaFile *jsPandaFile = iter->second.first;
|
|
if (oldJSPandaFiles_.find(jsPandaFile) == oldJSPandaFiles_.end()) {
|
|
oldJSPandaFiles_.emplace(jsPandaFile, iter->second.second);
|
|
} else {
|
|
oldJSPandaFiles_[jsPandaFile] += iter->second.second;
|
|
}
|
|
loadedJSPandaFiles_.erase(iter);
|
|
}
|
|
|
|
void JSPandaFileManager::ClearCache()
|
|
{
|
|
loadedJSPandaFiles_.clear();
|
|
}
|
|
|
|
JSPandaFile *JSPandaFileManager::OpenJSPandaFile(const CString &filename)
|
|
{
|
|
auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
|
|
if (pf == nullptr) {
|
|
LOG_ECMA(ERROR) << "open file " << filename << " error";
|
|
return nullptr;
|
|
}
|
|
|
|
JSPandaFile *jsPandaFile = NewJSPandaFile(pf.release(), filename);
|
|
return jsPandaFile;
|
|
}
|
|
|
|
JSPandaFile *JSPandaFileManager::NewJSPandaFile(const panda_file::File *pf, const CString &desc)
|
|
{
|
|
auto jsPandaFile = new JSPandaFile(pf, desc);
|
|
PGOProfilerManager::GetInstance()->SamplePandaFileInfo(jsPandaFile->GetChecksum());
|
|
return jsPandaFile;
|
|
}
|
|
|
|
void JSPandaFileManager::ReleaseJSPandaFile(const JSPandaFile *jsPandaFile)
|
|
{
|
|
if (jsPandaFile == nullptr) {
|
|
return;
|
|
}
|
|
LOG_ECMA(DEBUG) << "ReleaseJSPandaFile " << jsPandaFile->GetJSPandaFileDesc();
|
|
delete jsPandaFile;
|
|
jsPandaFile = nullptr;
|
|
}
|
|
|
|
DebugInfoExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *jsPandaFile)
|
|
{
|
|
LOG_ECMA_IF(jsPandaFile == nullptr, FATAL) << "GetJSPtExtractor error, js pandafile is nullptr";
|
|
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
[[maybe_unused]] auto const &filename = jsPandaFile->GetJSPandaFileDesc();
|
|
ASSERT(loadedJSPandaFiles_.find(filename) != loadedJSPandaFiles_.end());
|
|
|
|
auto iter = extractors_.find(jsPandaFile);
|
|
if (iter == extractors_.end()) {
|
|
auto extractorPtr = std::make_unique<DebugInfoExtractor>(jsPandaFile);
|
|
DebugInfoExtractor *extractor = extractorPtr.get();
|
|
extractors_[jsPandaFile] = std::move(extractorPtr);
|
|
return extractor;
|
|
}
|
|
|
|
return iter->second.get();
|
|
}
|
|
|
|
const JSPandaFile *JSPandaFileManager::GenerateJSPandaFile(JSThread *thread, const panda_file::File *pf,
|
|
const CString &desc, std::string_view entryPoint)
|
|
{
|
|
ASSERT(GetJSPandaFile(pf) == nullptr);
|
|
JSPandaFile *newJsPandaFile = NewJSPandaFile(pf, desc);
|
|
auto aotFM = thread->GetEcmaVM()->GetAOTFileManager();
|
|
EcmaVM *vm = thread->GetEcmaVM();
|
|
if (aotFM->IsLoad(newJsPandaFile)) {
|
|
uint32_t index = aotFM->GetAnFileIndex(newJsPandaFile);
|
|
newJsPandaFile->SetAOTFileInfoIndex(index);
|
|
}
|
|
|
|
CString methodName = entryPoint.data();
|
|
if (newJsPandaFile->IsBundlePack()) {
|
|
// entryPoint maybe is _GLOBAL::func_main_watch to execute func_main_watch
|
|
auto pos = entryPoint.find_last_of("::");
|
|
if (pos != std::string_view::npos) {
|
|
methodName = entryPoint.substr(pos + 1);
|
|
} else {
|
|
// default use func_main_0 as entryPoint
|
|
methodName = JSPandaFile::ENTRY_FUNCTION_NAME;
|
|
}
|
|
}
|
|
PandaFileTranslator::TranslateClasses(newJsPandaFile, methodName);
|
|
{
|
|
os::memory::LockHolder lock(jsPandaFileLock_);
|
|
const JSPandaFile *jsPandaFile = FindJSPandaFileUnlocked(desc);
|
|
if (jsPandaFile != nullptr) {
|
|
if (!vm->HasCachedConstpool(jsPandaFile)) {
|
|
IncreaseRefJSPandaFileUnlocked(jsPandaFile);
|
|
}
|
|
ReleaseJSPandaFile(newJsPandaFile);
|
|
return jsPandaFile;
|
|
}
|
|
InsertJSPandaFile(newJsPandaFile);
|
|
}
|
|
|
|
return newJsPandaFile;
|
|
}
|
|
|
|
void *JSPandaFileManager::AllocateBuffer(size_t size)
|
|
{
|
|
return JSPandaFileAllocator::AllocateBuffer(size);
|
|
}
|
|
|
|
void *JSPandaFileManager::JSPandaFileAllocator::AllocateBuffer(size_t size)
|
|
{
|
|
if (size == 0) {
|
|
LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
|
|
UNREACHABLE();
|
|
}
|
|
if (size >= MALLOC_SIZE_LIMIT) {
|
|
LOG_ECMA_MEM(FATAL) << "size must be less than the maximum";
|
|
UNREACHABLE();
|
|
}
|
|
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
|
|
void *ptr = malloc(size);
|
|
if (ptr == nullptr) {
|
|
LOG_ECMA_MEM(FATAL) << "malloc failed";
|
|
UNREACHABLE();
|
|
}
|
|
#if ECMASCRIPT_ENABLE_ZAP_MEM
|
|
if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) {
|
|
LOG_ECMA_MEM(FATAL) << "memset_s failed";
|
|
UNREACHABLE();
|
|
}
|
|
#endif
|
|
return ptr;
|
|
}
|
|
|
|
void JSPandaFileManager::FreeBuffer(void *mem)
|
|
{
|
|
JSPandaFileAllocator::FreeBuffer(mem);
|
|
}
|
|
|
|
void JSPandaFileManager::JSPandaFileAllocator::FreeBuffer(void *mem)
|
|
{
|
|
if (mem == nullptr) {
|
|
return;
|
|
}
|
|
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
|
|
free(mem);
|
|
}
|
|
|
|
void JSPandaFileManager::RemoveJSPandaFile(void *pointer)
|
|
{
|
|
if (pointer == nullptr) {
|
|
return;
|
|
}
|
|
auto jsPandaFile = static_cast<JSPandaFile *>(pointer);
|
|
// dec ref in filemanager
|
|
JSPandaFileManager::GetInstance()->DecreaseRefJSPandaFile(jsPandaFile);
|
|
}
|
|
} // namespace panda::ecmascript
|