14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <cstdint>
204514f5e3Sopenharmony_ci#include <fstream>
214514f5e3Sopenharmony_ci#include <unordered_map>
224514f5e3Sopenharmony_ci#include <utility>
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_ci#include "ecmascript/common.h"
254514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/js_pandafile.h"
264514f5e3Sopenharmony_ci#include "ecmascript/log_wrapper.h"
274514f5e3Sopenharmony_ci#include "ecmascript/mem/c_string.h"
284514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h"
294514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_utils.h"
304514f5e3Sopenharmony_ci#include "macros.h"
314514f5e3Sopenharmony_ci
324514f5e3Sopenharmony_cinamespace panda::ecmascript::pgo {
334514f5e3Sopenharmony_citemplate <typename Entry, typename V>
344514f5e3Sopenharmony_ciclass PoolTemplate : public PGOFileSectionInterface {
354514f5e3Sopenharmony_cipublic:
364514f5e3Sopenharmony_ci    using IsReservedCb = std::function<bool(const V &value)>;
374514f5e3Sopenharmony_ci    using GetReservedIdCb = std::function<ApEntityId(const V &value)>;
384514f5e3Sopenharmony_ci
394514f5e3Sopenharmony_ci    using SupportCb = std::function<bool(PGOProfilerHeader const *header)>;
404514f5e3Sopenharmony_ci    using GetSectionCb = std::function<SectionInfo *(PGOProfilerHeader const *header)>;
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ci    PoolTemplate(std::string poolName, uint32_t reservedCount)
434514f5e3Sopenharmony_ci        : poolName_(std::move(poolName)), RESERVED_COUNT(reservedCount) {};
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_ci    ~PoolTemplate() override
464514f5e3Sopenharmony_ci    {
474514f5e3Sopenharmony_ci        Clear();
484514f5e3Sopenharmony_ci    }
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ci    bool TryAdd(const V &value, ApEntityId &entryId)
514514f5e3Sopenharmony_ci    {
524514f5e3Sopenharmony_ci        auto it = valueToId_.find(value);
534514f5e3Sopenharmony_ci        if (it != valueToId_.end()) {
544514f5e3Sopenharmony_ci            entryId = it->second;
554514f5e3Sopenharmony_ci            return true;
564514f5e3Sopenharmony_ci        }
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ci        entryId = ApEntityId(IsReserved(value) ? (++reservedUsed_, GetReservedId(value))
594514f5e3Sopenharmony_ci                                               : RESERVED_COUNT + pool_.size() - reservedUsed_);
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ci        auto result = pool_.emplace(entryId, value);
624514f5e3Sopenharmony_ci        valueToId_.emplace(value, entryId);
634514f5e3Sopenharmony_ci        auto &entry = result.first->second;
644514f5e3Sopenharmony_ci        entry.SetEntryId(entryId);
654514f5e3Sopenharmony_ci        return true;
664514f5e3Sopenharmony_ci    }
674514f5e3Sopenharmony_ci
684514f5e3Sopenharmony_ci    bool GetEntryId(const V &value, ApEntityId &entryId) const
694514f5e3Sopenharmony_ci    {
704514f5e3Sopenharmony_ci        for (const auto &entry : pool_) {
714514f5e3Sopenharmony_ci            if (entry.second.GetData() == value) {
724514f5e3Sopenharmony_ci                entryId = entry.first;
734514f5e3Sopenharmony_ci                return true;
744514f5e3Sopenharmony_ci            }
754514f5e3Sopenharmony_ci        }
764514f5e3Sopenharmony_ci        return false;
774514f5e3Sopenharmony_ci    }
784514f5e3Sopenharmony_ci
794514f5e3Sopenharmony_ci    const Entry *GetEntry(ApEntityId id) const
804514f5e3Sopenharmony_ci    {
814514f5e3Sopenharmony_ci        auto iter = pool_.find(id);
824514f5e3Sopenharmony_ci        if (iter == pool_.end()) {
834514f5e3Sopenharmony_ci            return nullptr;
844514f5e3Sopenharmony_ci        }
854514f5e3Sopenharmony_ci        return &(iter->second);
864514f5e3Sopenharmony_ci    }
874514f5e3Sopenharmony_ci
884514f5e3Sopenharmony_ci    bool GetEntryIdByNormalizedName(const V &value, ApEntityId &entryId) const
894514f5e3Sopenharmony_ci    {
904514f5e3Sopenharmony_ci        for (const auto &entry : pool_) {
914514f5e3Sopenharmony_ci            if (JSPandaFile::GetNormalizedFileDesc(entry.second.GetData()) == value) {
924514f5e3Sopenharmony_ci                entryId = entry.first;
934514f5e3Sopenharmony_ci                return true;
944514f5e3Sopenharmony_ci            }
954514f5e3Sopenharmony_ci        }
964514f5e3Sopenharmony_ci        return false;
974514f5e3Sopenharmony_ci    }
984514f5e3Sopenharmony_ci
994514f5e3Sopenharmony_ci    void Clear()
1004514f5e3Sopenharmony_ci    {
1014514f5e3Sopenharmony_ci        pool_.clear();
1024514f5e3Sopenharmony_ci        valueToId_.clear();
1034514f5e3Sopenharmony_ci        reservedUsed_ = 0;
1044514f5e3Sopenharmony_ci    }
1054514f5e3Sopenharmony_ci
1064514f5e3Sopenharmony_ci    bool Empty() const
1074514f5e3Sopenharmony_ci    {
1084514f5e3Sopenharmony_ci        return pool_.empty();
1094514f5e3Sopenharmony_ci    }
1104514f5e3Sopenharmony_ci
1114514f5e3Sopenharmony_ci    void Merge(const PoolTemplate &pool, const std::function<void(ApEntityId, ApEntityId)> &callback)
1124514f5e3Sopenharmony_ci    {
1134514f5e3Sopenharmony_ci        for (const auto &entry : pool.pool_) {
1144514f5e3Sopenharmony_ci            ApEntityId newId(0);
1154514f5e3Sopenharmony_ci            TryAdd(entry.second.GetData(), newId);
1164514f5e3Sopenharmony_ci            if (callback != nullptr) {
1174514f5e3Sopenharmony_ci                callback(entry.first, newId);
1184514f5e3Sopenharmony_ci            }
1194514f5e3Sopenharmony_ci        }
1204514f5e3Sopenharmony_ci    }
1214514f5e3Sopenharmony_ci
1224514f5e3Sopenharmony_ci    uint32_t ProcessToBinary([[maybe_unused]] PGOContext &context, std::fstream &stream) override
1234514f5e3Sopenharmony_ci    {
1244514f5e3Sopenharmony_ci        LOG_ECMA(DEBUG) << "ProcessToBinary. name: " << poolName_ << ", count: " << pool_.size();
1254514f5e3Sopenharmony_ci        SectionInfo secInfo;
1264514f5e3Sopenharmony_ci        secInfo.number_ = pool_.size();
1274514f5e3Sopenharmony_ci        secInfo.offset_ = sizeof(SectionInfo);
1284514f5e3Sopenharmony_ci        auto secInfoPos = stream.tellp();
1294514f5e3Sopenharmony_ci        stream.seekp(secInfo.offset_, std::ofstream::cur);
1304514f5e3Sopenharmony_ci        for (auto &entry : pool_) {
1314514f5e3Sopenharmony_ci            stream.write(reinterpret_cast<const char *>(&(entry.first)), sizeof(ApEntityId));
1324514f5e3Sopenharmony_ci            entry.second.ProcessToBinary(context, stream);
1334514f5e3Sopenharmony_ci        }
1344514f5e3Sopenharmony_ci        secInfo.size_ = static_cast<uint32_t>(stream.tellp()) - static_cast<uint32_t>(secInfoPos);
1354514f5e3Sopenharmony_ci        auto tail = stream.tellp();
1364514f5e3Sopenharmony_ci        stream.seekp(secInfoPos, std::ofstream::beg);
1374514f5e3Sopenharmony_ci        stream.write(reinterpret_cast<const char *>(&(secInfo)), sizeof(SectionInfo));
1384514f5e3Sopenharmony_ci        stream.seekp(tail, std::ofstream::beg);
1394514f5e3Sopenharmony_ci        return 1;
1404514f5e3Sopenharmony_ci    }
1414514f5e3Sopenharmony_ci
1424514f5e3Sopenharmony_ci    bool ProcessToText(std::ofstream &stream) override
1434514f5e3Sopenharmony_ci    {
1444514f5e3Sopenharmony_ci        bool isFirst = true;
1454514f5e3Sopenharmony_ci        for (auto &entry : pool_) {
1464514f5e3Sopenharmony_ci            if (isFirst) {
1474514f5e3Sopenharmony_ci                stream << DumpUtils::NEW_LINE;
1484514f5e3Sopenharmony_ci                stream << poolName_;
1494514f5e3Sopenharmony_ci                stream << DumpUtils::BLOCK_START;
1504514f5e3Sopenharmony_ci                isFirst = false;
1514514f5e3Sopenharmony_ci            }
1524514f5e3Sopenharmony_ci            stream << DumpUtils::NEW_LINE;
1534514f5e3Sopenharmony_ci            stream << std::to_string(entry.first);
1544514f5e3Sopenharmony_ci            stream << DumpUtils::SPACE;
1554514f5e3Sopenharmony_ci            stream << DumpUtils::ARRAY_START;
1564514f5e3Sopenharmony_ci            entry.second.ProcessToText(stream);
1574514f5e3Sopenharmony_ci            stream << DumpUtils::ARRAY_END;
1584514f5e3Sopenharmony_ci        }
1594514f5e3Sopenharmony_ci        if (!isFirst) {
1604514f5e3Sopenharmony_ci            stream << (DumpUtils::SPACE + DumpUtils::NEW_LINE);
1614514f5e3Sopenharmony_ci        }
1624514f5e3Sopenharmony_ci        return true;
1634514f5e3Sopenharmony_ci    }
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_ci    void ProcessToJson(std::vector<ProfileType::StringMap> &abcPoolArray)
1664514f5e3Sopenharmony_ci    {
1674514f5e3Sopenharmony_ci        for (auto &entry : pool_) {
1684514f5e3Sopenharmony_ci            ProfileType::StringMap abcPool;
1694514f5e3Sopenharmony_ci            abcPool.insert(std::make_pair(DumpJsonUtils::ABC_ID, std::to_string(entry.first)));
1704514f5e3Sopenharmony_ci            abcPool.insert(std::make_pair(DumpJsonUtils::ABC_FILE, entry.second.GetData()));
1714514f5e3Sopenharmony_ci            abcPoolArray.push_back(abcPool);
1724514f5e3Sopenharmony_ci        }
1734514f5e3Sopenharmony_ci    }
1744514f5e3Sopenharmony_ci    uint32_t ParseFromBinary([[maybe_unused]] PGOContext &context, void **buffer,
1754514f5e3Sopenharmony_ci                             PGOProfilerHeader const *header) override
1764514f5e3Sopenharmony_ci    {
1774514f5e3Sopenharmony_ci        auto secInfo = base::ReadBuffer<SectionInfo>(buffer);
1784514f5e3Sopenharmony_ci        for (uint32_t i = 0; i < secInfo.number_; i++) {
1794514f5e3Sopenharmony_ci            auto entryId = base::ReadBuffer<ApEntityId>(buffer, sizeof(ApEntityId));
1804514f5e3Sopenharmony_ci            auto result = pool_.try_emplace(entryId);
1814514f5e3Sopenharmony_ci            result.first->second.SetEntryId(entryId);
1824514f5e3Sopenharmony_ci            result.first->second.ParseFromBinary(context, buffer, header);
1834514f5e3Sopenharmony_ci        }
1844514f5e3Sopenharmony_ci        return 1;
1854514f5e3Sopenharmony_ci    }
1864514f5e3Sopenharmony_ci
1874514f5e3Sopenharmony_ci    void SetIsReservedCb(const IsReservedCb &isReservedCb)
1884514f5e3Sopenharmony_ci    {
1894514f5e3Sopenharmony_ci        isReservedCb_ = isReservedCb;
1904514f5e3Sopenharmony_ci    }
1914514f5e3Sopenharmony_ci
1924514f5e3Sopenharmony_ci    void SetGetReservedIdCb(const GetReservedIdCb &getReservedIdCb)
1934514f5e3Sopenharmony_ci    {
1944514f5e3Sopenharmony_ci        getReservedIdCb_ = getReservedIdCb;
1954514f5e3Sopenharmony_ci    }
1964514f5e3Sopenharmony_ci
1974514f5e3Sopenharmony_ci    void SetSupportCb(const SupportCb &supportCb)
1984514f5e3Sopenharmony_ci    {
1994514f5e3Sopenharmony_ci        supportCb_ = supportCb;
2004514f5e3Sopenharmony_ci    }
2014514f5e3Sopenharmony_ci
2024514f5e3Sopenharmony_ci    void SetGetSectionCb(const GetSectionCb &getSectionCb)
2034514f5e3Sopenharmony_ci    {
2044514f5e3Sopenharmony_ci        getSectionCb_ = getSectionCb;
2054514f5e3Sopenharmony_ci    }
2064514f5e3Sopenharmony_ci
2074514f5e3Sopenharmony_ci    std::unordered_map<ApEntityId, Entry> &GetPool()
2084514f5e3Sopenharmony_ci    {
2094514f5e3Sopenharmony_ci        return pool_;
2104514f5e3Sopenharmony_ci    }
2114514f5e3Sopenharmony_ci
2124514f5e3Sopenharmony_ci    std::unordered_map<V, ApEntityId> &GetValueToId()
2134514f5e3Sopenharmony_ci    {
2144514f5e3Sopenharmony_ci        return valueToId_;
2154514f5e3Sopenharmony_ci    }
2164514f5e3Sopenharmony_ci
2174514f5e3Sopenharmony_ciprivate:
2184514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(PoolTemplate);
2194514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(PoolTemplate);
2204514f5e3Sopenharmony_ci
2214514f5e3Sopenharmony_ci    bool Support(PGOProfilerHeader const *header) const override
2224514f5e3Sopenharmony_ci    {
2234514f5e3Sopenharmony_ci        return supportCb_(header);
2244514f5e3Sopenharmony_ci    }
2254514f5e3Sopenharmony_ci
2264514f5e3Sopenharmony_ci    SectionInfo *GetSection(PGOProfilerHeader const *header) const override
2274514f5e3Sopenharmony_ci    {
2284514f5e3Sopenharmony_ci        return getSectionCb_(header);
2294514f5e3Sopenharmony_ci    }
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_ci    bool IsReserved(const V &value)
2324514f5e3Sopenharmony_ci    {
2334514f5e3Sopenharmony_ci        return isReservedCb_(value);
2344514f5e3Sopenharmony_ci    }
2354514f5e3Sopenharmony_ci
2364514f5e3Sopenharmony_ci    ApEntityId GetReservedId(const V &value)
2374514f5e3Sopenharmony_ci    {
2384514f5e3Sopenharmony_ci        return getReservedIdCb_(value);
2394514f5e3Sopenharmony_ci    }
2404514f5e3Sopenharmony_ci
2414514f5e3Sopenharmony_ci    const std::string poolName_;
2424514f5e3Sopenharmony_ci    const uint32_t RESERVED_COUNT {};
2434514f5e3Sopenharmony_ci    uint32_t reservedUsed_ {0};
2444514f5e3Sopenharmony_ci
2454514f5e3Sopenharmony_ci    IsReservedCb isReservedCb_;
2464514f5e3Sopenharmony_ci    GetReservedIdCb getReservedIdCb_;
2474514f5e3Sopenharmony_ci    SupportCb supportCb_;
2484514f5e3Sopenharmony_ci    GetSectionCb getSectionCb_;
2494514f5e3Sopenharmony_ci    std::unordered_map<ApEntityId, Entry> pool_;
2504514f5e3Sopenharmony_ci    std::unordered_map<V, ApEntityId> valueToId_;
2514514f5e3Sopenharmony_ci};
2524514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::pgo
2534514f5e3Sopenharmony_ci
2544514f5e3Sopenharmony_cinamespace std {
2554514f5e3Sopenharmony_ciusing panda::ecmascript::pgo::ProfileType;
2564514f5e3Sopenharmony_citemplate<>
2574514f5e3Sopenharmony_cistruct hash<ProfileType> {
2584514f5e3Sopenharmony_ci    size_t operator()(const ProfileType& type) const noexcept
2594514f5e3Sopenharmony_ci    {
2604514f5e3Sopenharmony_ci        return type.GetRaw();
2614514f5e3Sopenharmony_ci    }
2624514f5e3Sopenharmony_ci};
2634514f5e3Sopenharmony_ci} // namespace std
2644514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_PGO_PROFILER_AP_FILE_POOL_TEMPLATE_H
265