13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "evaluate/debugInfoStorage.h"
173af6ab5fSopenharmony_ci#include "assembler/assembly-type.h"
183af6ab5fSopenharmony_ci#include "generated/signatures.h"
193af6ab5fSopenharmony_ci#include "evaluate/helpers.h"
203af6ab5fSopenharmony_ci
213af6ab5fSopenharmony_ci#include "libpandafile/class_data_accessor-inl.h"
223af6ab5fSopenharmony_ci#include "libpandafile/file-inl.h"
233af6ab5fSopenharmony_ci
243af6ab5fSopenharmony_cinamespace ark::es2panda::evaluate {
253af6ab5fSopenharmony_ci
263af6ab5fSopenharmony_cinamespace {
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_cistd::string GetFullRecordName(const panda_file::File &pf, const panda_file::File::EntityId &classId)
293af6ab5fSopenharmony_ci{
303af6ab5fSopenharmony_ci    std::string name = utf::Mutf8AsCString(pf.GetStringData(classId).data);
313af6ab5fSopenharmony_ci
323af6ab5fSopenharmony_ci    auto type = pandasm::Type::FromDescriptor(name);
333af6ab5fSopenharmony_ci    type = pandasm::Type(type.GetComponentName(), type.GetRank());
343af6ab5fSopenharmony_ci
353af6ab5fSopenharmony_ci    return type.GetPandasmName();
363af6ab5fSopenharmony_ci}
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_cibool EndsWith(std::string_view str, std::string_view suffix)
393af6ab5fSopenharmony_ci{
403af6ab5fSopenharmony_ci    auto pos = str.rfind(suffix);
413af6ab5fSopenharmony_ci    return pos != std::string::npos && (str.size() - pos) == suffix.size();
423af6ab5fSopenharmony_ci}
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_ci}  // namespace
453af6ab5fSopenharmony_ci
463af6ab5fSopenharmony_ciImportExportTable::ImportExportTable(ArenaAllocator *allocator)
473af6ab5fSopenharmony_ci    : imports_(allocator->Adapter()), exports_(allocator->Adapter())
483af6ab5fSopenharmony_ci{
493af6ab5fSopenharmony_ci}
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ciDebugInfoStorage::DebugInfoStorage(const CompilerOptions &options, ArenaAllocator *allocator)
523af6ab5fSopenharmony_ci    : allocator_(allocator), sourceFileToDebugInfo_(allocator->Adapter()), moduleNameToDebugInfo_(allocator->Adapter())
533af6ab5fSopenharmony_ci{
543af6ab5fSopenharmony_ci    for (const auto &pfPath : options.debuggerEvalPandaFiles) {
553af6ab5fSopenharmony_ci        LoadFileDebugInfo(pfPath);
563af6ab5fSopenharmony_ci    }
573af6ab5fSopenharmony_ci}
583af6ab5fSopenharmony_ci
593af6ab5fSopenharmony_civoid DebugInfoStorage::LoadFileDebugInfo(std::string_view pfPath)
603af6ab5fSopenharmony_ci{
613af6ab5fSopenharmony_ci    auto pf = panda_file::OpenPandaFile(pfPath);
623af6ab5fSopenharmony_ci    if (!pf) {
633af6ab5fSopenharmony_ci        LOG(FATAL, ES2PANDA) << "Failed to load a provided abc file: " << pfPath;
643af6ab5fSopenharmony_ci    }
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci    for (auto id : pf->GetClasses()) {
673af6ab5fSopenharmony_ci        panda_file::File::EntityId classId(id);
683af6ab5fSopenharmony_ci        if (pf->IsExternal(classId)) {
693af6ab5fSopenharmony_ci            continue;
703af6ab5fSopenharmony_ci        }
713af6ab5fSopenharmony_ci
723af6ab5fSopenharmony_ci        auto recordName = GetFullRecordName(*pf, classId);
733af6ab5fSopenharmony_ci        if (!EndsWith(recordName, compiler::Signatures::ETS_GLOBAL)) {
743af6ab5fSopenharmony_ci            continue;
753af6ab5fSopenharmony_ci        }
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci        std::string_view moduleName = helpers::SplitRecordName(recordName).first;
783af6ab5fSopenharmony_ci        auto *debugInfo = allocator_->New<FileDebugInfo>(std::move(pf), classId, moduleName);
793af6ab5fSopenharmony_ci        auto sourceFileId = debugInfo->globalClassAcc.GetSourceFileId();
803af6ab5fSopenharmony_ci        ASSERT(sourceFileId.has_value());
813af6ab5fSopenharmony_ci        std::string_view sourceFileName = utf::Mutf8AsCString(debugInfo->pf->GetStringData(*sourceFileId).data);
823af6ab5fSopenharmony_ci        debugInfo->sourceFilePath = sourceFileName;
833af6ab5fSopenharmony_ci
843af6ab5fSopenharmony_ci        sourceFileToDebugInfo_.emplace(sourceFileName, debugInfo);
853af6ab5fSopenharmony_ci        moduleNameToDebugInfo_.emplace(moduleName, debugInfo);
863af6ab5fSopenharmony_ci        return;
873af6ab5fSopenharmony_ci    }
883af6ab5fSopenharmony_ci
893af6ab5fSopenharmony_ci    LOG(FATAL, ES2PANDA) << "ETSGLOBAL not found in provided file: " << pfPath;
903af6ab5fSopenharmony_ci}
913af6ab5fSopenharmony_ci
923af6ab5fSopenharmony_ciconst panda_file::File *DebugInfoStorage::GetPandaFile(std::string_view filePath)
933af6ab5fSopenharmony_ci{
943af6ab5fSopenharmony_ci    auto iter = sourceFileToDebugInfo_.find(filePath);
953af6ab5fSopenharmony_ci    if (iter == sourceFileToDebugInfo_.end()) {
963af6ab5fSopenharmony_ci        return nullptr;
973af6ab5fSopenharmony_ci    }
983af6ab5fSopenharmony_ci    return iter->second->pf.get();
993af6ab5fSopenharmony_ci}
1003af6ab5fSopenharmony_ci
1013af6ab5fSopenharmony_ciconst ImportExportTable *DebugInfoStorage::GetImportExportTable(std::string_view filePath)
1023af6ab5fSopenharmony_ci{
1033af6ab5fSopenharmony_ci    auto iter = sourceFileToDebugInfo_.find(filePath);
1043af6ab5fSopenharmony_ci    if (iter == sourceFileToDebugInfo_.end()) {
1053af6ab5fSopenharmony_ci        return nullptr;
1063af6ab5fSopenharmony_ci    }
1073af6ab5fSopenharmony_ci    return &LazyLoadImportExportTable(iter->second);
1083af6ab5fSopenharmony_ci}
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_cipanda_file::ClassDataAccessor *DebugInfoStorage::GetGlobalClassAccessor(std::string_view filePath)
1113af6ab5fSopenharmony_ci{
1123af6ab5fSopenharmony_ci    auto iter = sourceFileToDebugInfo_.find(filePath);
1133af6ab5fSopenharmony_ci    if (iter == sourceFileToDebugInfo_.end()) {
1143af6ab5fSopenharmony_ci        return nullptr;
1153af6ab5fSopenharmony_ci    }
1163af6ab5fSopenharmony_ci    return &iter->second->globalClassAcc;
1173af6ab5fSopenharmony_ci}
1183af6ab5fSopenharmony_ci
1193af6ab5fSopenharmony_cistd::string_view DebugInfoStorage::GetModuleName(std::string_view filePath)
1203af6ab5fSopenharmony_ci{
1213af6ab5fSopenharmony_ci    auto iter = sourceFileToDebugInfo_.find(filePath);
1223af6ab5fSopenharmony_ci    if (iter == sourceFileToDebugInfo_.end()) {
1233af6ab5fSopenharmony_ci        return {};
1243af6ab5fSopenharmony_ci    }
1253af6ab5fSopenharmony_ci    return iter->second->moduleName;
1263af6ab5fSopenharmony_ci}
1273af6ab5fSopenharmony_ci
1283af6ab5fSopenharmony_cipanda_file::File::EntityId DebugInfoStorage::FindClass(std::string_view filePath, std::string_view className)
1293af6ab5fSopenharmony_ci{
1303af6ab5fSopenharmony_ci    auto iter = sourceFileToDebugInfo_.find(filePath);
1313af6ab5fSopenharmony_ci    if (iter == sourceFileToDebugInfo_.end()) {
1323af6ab5fSopenharmony_ci        return panda_file::File::EntityId();
1333af6ab5fSopenharmony_ci    }
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_ci    const auto &records = LazyLoadRecords(iter->second);
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    auto classIter = records.find(className);
1383af6ab5fSopenharmony_ci    return classIter == records.end() ? panda_file::File::EntityId() : classIter->second;
1393af6ab5fSopenharmony_ci}
1403af6ab5fSopenharmony_ci
1413af6ab5fSopenharmony_cibool DebugInfoStorage::FillEvaluateContext(EvaluateContext &context)
1423af6ab5fSopenharmony_ci{
1433af6ab5fSopenharmony_ci    const auto *contextPandaFile = GetPandaFile(context.sourceFilePath.Utf8());
1443af6ab5fSopenharmony_ci    if (contextPandaFile == nullptr) {
1453af6ab5fSopenharmony_ci        LOG(WARNING, ES2PANDA) << "Could not find context file: " << context.sourceFilePath << std::endl;
1463af6ab5fSopenharmony_ci        return false;
1473af6ab5fSopenharmony_ci    }
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_ci    context.file = contextPandaFile;
1503af6ab5fSopenharmony_ci    context.extractor = std::make_unique<panda_file::DebugInfoExtractor>(contextPandaFile);
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_ci    for (auto methodId : context.extractor->GetMethodIdList()) {
1533af6ab5fSopenharmony_ci        for (const auto &entry : context.extractor->GetLineNumberTable(methodId)) {
1543af6ab5fSopenharmony_ci            if (context.lineNumber == entry.line) {
1553af6ab5fSopenharmony_ci                context.methodId = methodId;
1563af6ab5fSopenharmony_ci                context.bytecodeOffset = entry.offset;
1573af6ab5fSopenharmony_ci                util::UString sourceFilePath(std::string_view(context.extractor->GetSourceFile(methodId)), allocator_);
1583af6ab5fSopenharmony_ci                context.sourceFilePath = sourceFilePath.View();
1593af6ab5fSopenharmony_ci                return true;
1603af6ab5fSopenharmony_ci            }
1613af6ab5fSopenharmony_ci        }
1623af6ab5fSopenharmony_ci    }
1633af6ab5fSopenharmony_ci    LOG(WARNING, ES2PANDA) << "Could not find code at line: " << context.lineNumber << std::endl;
1643af6ab5fSopenharmony_ci    return false;
1653af6ab5fSopenharmony_ci}
1663af6ab5fSopenharmony_ci
1673af6ab5fSopenharmony_ciconst ImportExportTable &DebugInfoStorage::LazyLoadImportExportTable(FileDebugInfo *info)
1683af6ab5fSopenharmony_ci{
1693af6ab5fSopenharmony_ci    ASSERT(info);
1703af6ab5fSopenharmony_ci
1713af6ab5fSopenharmony_ci    if (info->importExportTable.has_value()) {
1723af6ab5fSopenharmony_ci        return *info->importExportTable;
1733af6ab5fSopenharmony_ci    }
1743af6ab5fSopenharmony_ci
1753af6ab5fSopenharmony_ci    // NOTE: load table after it is implemented in compiler.
1763af6ab5fSopenharmony_ci    info->importExportTable.emplace(allocator_);
1773af6ab5fSopenharmony_ci    return info->importExportTable.value();
1783af6ab5fSopenharmony_ci}
1793af6ab5fSopenharmony_ci
1803af6ab5fSopenharmony_ciconst FileDebugInfo::RecordsMap &DebugInfoStorage::LazyLoadRecords(FileDebugInfo *info)
1813af6ab5fSopenharmony_ci{
1823af6ab5fSopenharmony_ci    ASSERT(info);
1833af6ab5fSopenharmony_ci
1843af6ab5fSopenharmony_ci    if (info->records.has_value()) {
1853af6ab5fSopenharmony_ci        return *info->records;
1863af6ab5fSopenharmony_ci    }
1873af6ab5fSopenharmony_ci
1883af6ab5fSopenharmony_ci    info->records.emplace(allocator_->Adapter());
1893af6ab5fSopenharmony_ci    auto &records = *info->records;
1903af6ab5fSopenharmony_ci
1913af6ab5fSopenharmony_ci    const auto *pf = info->pf.get();
1923af6ab5fSopenharmony_ci    for (auto id : pf->GetClasses()) {
1933af6ab5fSopenharmony_ci        panda_file::File::EntityId classId(id);
1943af6ab5fSopenharmony_ci        if (pf->IsExternal(classId)) {
1953af6ab5fSopenharmony_ci            // Сlass that marked in currect .abc file as <external> should be define in some other .abc file.
1963af6ab5fSopenharmony_ci            // Thus we will not lose information about this class.
1973af6ab5fSopenharmony_ci            continue;
1983af6ab5fSopenharmony_ci        }
1993af6ab5fSopenharmony_ci
2003af6ab5fSopenharmony_ci        auto recordName = helpers::SplitRecordName(GetFullRecordName(*pf, classId)).second;
2013af6ab5fSopenharmony_ci        auto recordNameView = util::UString(recordName, allocator_).View();
2023af6ab5fSopenharmony_ci        if (!records.emplace(recordNameView, classId).second) {
2033af6ab5fSopenharmony_ci            LOG(FATAL, ES2PANDA) << "Failed to emplace class '" << recordNameView << "' in records."
2043af6ab5fSopenharmony_ci                                 << "There should be only one declaration of the same class.";
2053af6ab5fSopenharmony_ci        }
2063af6ab5fSopenharmony_ci    }
2073af6ab5fSopenharmony_ci
2083af6ab5fSopenharmony_ci    return records;
2093af6ab5fSopenharmony_ci}
2103af6ab5fSopenharmony_ci
2113af6ab5fSopenharmony_ciFileDebugInfo *DebugInfoStorage::GetDebugInfoByModuleName(std::string_view moduleName) const
2123af6ab5fSopenharmony_ci{
2133af6ab5fSopenharmony_ci    auto find = moduleNameToDebugInfo_.find(moduleName);
2143af6ab5fSopenharmony_ci    if (find != moduleNameToDebugInfo_.end()) {
2153af6ab5fSopenharmony_ci        return find->second;
2163af6ab5fSopenharmony_ci    }
2173af6ab5fSopenharmony_ci    return nullptr;
2183af6ab5fSopenharmony_ci}
2193af6ab5fSopenharmony_ci
2203af6ab5fSopenharmony_ci}  // namespace ark::es2panda::evaluate
221