1/*
2 * Copyright (c) 2023 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#ifndef ECMASCRIPT_OHOS_OHOS_PGO_PROCESSOR_H
17#define ECMASCRIPT_OHOS_OHOS_PGO_PROCESSOR_H
18
19#include "ecmascript/compiler/aot_compiler_preprocessor.h"
20#include "ecmascript/log_wrapper.h"
21#include "ecmascript/ohos/ohos_pkg_args.h"
22#include "ecmascript/platform/os.h"
23
24namespace panda::ecmascript::kungfu {
25class OhosPgoProcessor {
26public:
27    static bool MergeAndRemoveRuntimeAp(CompilationOptions &cOptions, const std::shared_ptr<OhosPkgArgs> &mainPkgArgs)
28    {
29        if (!cOptions.needMerge_) {
30            // use baseline ap, do not need to merge and remove runtime ap(s)
31            return true;
32        }
33        if (cOptions.profilerIn_.empty()) {
34            LOG_COMPILER(WARN) << "No valid ap files found in : " << mainPkgArgs->GetPgoDir();
35            return true;
36        }
37        std::string mergedAp(mainPkgArgs->GetMergedApPathWithoutCheck());
38        bool isSingleAp = cOptions.profilerIn_.find(GetFileDelimiter()) == std::string::npos;
39        if (isSingleAp) {
40            if (!RenameSingleAp(cOptions.profilerIn_, mergedAp)) {
41                return false;
42            }
43        } else {
44            if (!ExportMergedAp(cOptions.profilerIn_, cOptions.hotnessThreshold_, mergedAp)) {
45                return false;
46            }
47            if (!UnlinkRuntimeAp(mainPkgArgs->GetRuntimeApPath())) {
48                return false;
49            }
50        }
51        ASSERT(mainPkgArgs != nullptr);
52        // all ohos ap(s) merged into the merged ap file.
53        cOptions.profilerIn_ = mainPkgArgs->GetMergedApPath();
54        SetSecurityLabel(cOptions.profilerIn_);
55        ASSERT(!cOptions.profilerIn_.empty());
56        return true;
57    }
58
59private:
60    NO_MOVE_SEMANTIC(OhosPgoProcessor);
61    NO_COPY_SEMANTIC(OhosPgoProcessor);
62    static bool RenameSingleAp(const std::string &apPath, const std::string &exportAp)
63    {
64        ASSERT(!exportAp.empty());
65        if (apPath == exportAp) {
66            // no need to merge self.
67            return true;
68        }
69        std::string apRealPath;
70        if (!RealPath(apPath, apRealPath)) {
71            return false;
72        }
73        if (rename(apRealPath.c_str(), exportAp.c_str())) {
74            LOG_ECMA(ERROR) << "RenameSingleAp " << apRealPath << " --> " << exportAp << " failure!, errno: " << errno;
75            return false;
76        }
77        return true;
78    }
79
80    static bool UnlinkRuntimeAp(const std::string &runtimeAp)
81    {
82        ASSERT(!runtimeAp.empty());
83        std::string runtimeApRealPath;
84        if (!RealPath(runtimeAp, runtimeApRealPath)) {
85            return false;
86        }
87        if (!runtimeApRealPath.empty() && (Unlink(runtimeApRealPath.c_str()) == -1)) {
88            LOG_COMPILER(ERROR) << "Remove runtime ap failed. file: " << runtimeApRealPath << ", errno: " << errno;
89            return false;
90        }
91        return true;
92    }
93
94    static bool ExportMergedAp(const std::string &profilerIn, uint32_t hotnessThreshold, const std::string &exportAp)
95    {
96        ASSERT(!exportAp.empty());
97        return pgo::PGOProfilerManager::MergeApFiles(profilerIn, exportAp, hotnessThreshold,
98                                                     pgo::PGOProfilerEncoder::ApGenMode::MERGE);
99    }
100};
101}  // namespace panda::ecmascript::kungfu
102#endif  // ECMASCRIPT_OHOS_OHOS_PGO_PROCESSOR_H