1/*
2 * Copyright (c) 2022 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_COMPILER_COMPILATION_DRIVER_H
17#define ECMASCRIPT_COMPILER_COMPILATION_DRIVER_H
18
19#include "ecmascript/compiler/aot_compiler_preprocessor.h"
20#include "ecmascript/compiler/bytecode_info_collector.h"
21#include "ecmascript/js_function.h"
22
23namespace panda::ecmascript::kungfu {
24class AOTFileGenerator;
25class CompilerLog;
26struct LOptions;
27class Module;
28class CompilationDriver {
29public:
30    CompilationDriver(PGOProfilerDecoder &profilerDecoder,
31                      BytecodeInfoCollector* collector,
32                      AOTFileGenerator *fileGenerator,
33                      const std::string &fileName,
34                      const std::string &triple,
35                      LOptions *lOptions,
36                      CompilerLog *log,
37                      bool outputAsm,
38                      size_t maxMethodsInModule);
39    ~CompilationDriver() = default;
40
41    NO_COPY_SEMANTIC(CompilationDriver);
42    NO_MOVE_SEMANTIC(CompilationDriver);
43
44    bool IsPGOLoaded() const
45    {
46        return pfDecoder_.IsLoaded();
47    }
48
49    template <class Callback>
50    void CompileMethod(const Callback &cb,
51                       const CString &recordName,
52                       const std::string &methodName,
53                       MethodLiteral *methodLiteral,
54                       uint32_t methodOffset,
55                       const MethodPcInfo &methodPcInfo,
56                       MethodInfo &methodInfo)
57    {
58        Module *module = GetModule();
59        cb(recordName, methodName, methodLiteral, methodOffset,
60            methodPcInfo, methodInfo, module);
61        IncCompiledMethod();
62        CompileModuleThenDestroyIfNeeded(false);
63    }
64
65    template <class Callback>
66    void Run(const CallMethodFlagMap &callMethonFlagMap, const Callback &cb)
67    {
68        SetCurrentCompilationFile();
69        const auto &methodPcInfos = bytecodeInfo_.GetMethodPcInfos();
70        for (auto &[methodId, methodInfo] : bytecodeInfo_.GetMethodList()) {
71            bytecodeInfo_.AddMethodOffsetToRecordName(methodId, methodInfo.GetRecordName());
72            auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
73            auto methodLiteral = jsPandaFile_->FindMethodLiteral(methodId);
74            if (methodLiteral == nullptr) {
75                continue;
76            }
77            const std::string methodName(MethodLiteral::GetMethodName(jsPandaFile_, methodLiteral->GetMethodId()));
78            if (!callMethonFlagMap.IsAotCompile(jsPandaFile_->GetNormalizedFileDesc(),
79                                                methodLiteral->GetMethodId().GetOffset())) {
80                bytecodeInfo_.AddSkippedMethod(methodId);
81            } else {
82                if (!methodInfo.IsCompiled()) {
83                    methodInfo.SetIsCompiled(true);
84                    CompileMethod(cb, methodInfo.GetRecordName(), methodName, methodLiteral,
85                        methodId, methodPcInfo, methodInfo);
86                }
87            }
88        }
89        CompileLastModuleThenDestroyIfNeeded();
90        StoreConstantPoolInfo();
91    }
92
93    void FetchPGOMismatchResult();
94
95    uint32_t GetCompilerMethodCount() const
96    {
97        return compiledMethodCnt_;
98    }
99protected:
100    // add maxMethodsInModule_ functions in a module and when a module is
101    // full(maxMethodsInModule_ functions have been put into) or the module is the last module,
102    // compile it and the destroy it.
103    Module *GetModule();
104
105    void IncCompiledMethod();
106
107    bool IsCurModuleFull() const;
108
109    void CompileModuleThenDestroyIfNeeded(bool isJit = false);
110
111    void CompileLastModuleThenDestroyIfNeeded();
112
113    std::vector<std::string> SplitString(const std::string &str, const char ch) const;
114
115    void SetCurrentCompilationFile() const;
116
117    void StoreConstantPoolInfo() const;
118
119    CompilationEnv *compilationEnv_ {nullptr};
120    const JSPandaFile *jsPandaFile_ {nullptr};
121    PGOProfilerDecoder &pfDecoder_;
122    BytecodeInfoCollector* collector_;
123    BCInfo &bytecodeInfo_;
124    uint32_t compiledMethodCnt_ {0};
125    AOTFileGenerator *fileGenerator_ {nullptr};
126    std::string fileName_ {};
127    std::string triple_ {};
128    LOptions *lOptions_ {nullptr};
129    CompilerLog *log_ {nullptr};
130    bool outputAsm_ {false};
131    size_t maxMethodsInModule_ {0};
132};
133
134class JitCompilationDriver : public CompilationDriver {
135public:
136    JitCompilationDriver(PGOProfilerDecoder &profilerDecoder,
137                         BytecodeInfoCollector* collector,
138                         AOTFileGenerator *fileGenerator,
139                         const std::string &fileName,
140                         const std::string &triple,
141                         LOptions *lOptions,
142                         CompilerLog *log,
143                         bool outputAsm,
144                         size_t maxMethodsInModule)
145        : CompilationDriver(profilerDecoder, collector, fileGenerator, fileName, triple, lOptions,
146                            log, outputAsm, maxMethodsInModule) { };
147    ~JitCompilationDriver() = default;
148    bool RunCg();
149    Module *GetModule();
150
151    template <class Callback>
152    bool CompileMethod(const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral,
153                       JSHandle<ProfileTypeInfo> &profileTypeInfo, const uint8_t *pcStart,
154                       const panda_file::File::Header *header, ApEntityId abcId, const Callback &cb)
155    {
156        SetCurrentCompilationFile();
157        if (methodLiteral == nullptr) {
158            return false;
159        }
160        const std::string methodName(MethodLiteral::GetMethodName(jsPandaFile, methodLiteral->GetMethodId()));
161
162        auto &methodList = bytecodeInfo_.GetMethodList();
163        const auto &methodPcInfos = bytecodeInfo_.GetMethodPcInfos();
164        auto &methodInfo = methodList.at(methodLiteral->GetMethodId().GetOffset());
165
166        auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
167        auto methodOffset = methodLiteral->GetMethodId().GetOffset();
168        bytecodeInfo_.EraseSkippedMethod(methodOffset);
169
170        Module *module = GetModule();
171        return cb(bytecodeInfo_.GetRecordNameWithIndex(0), methodName, methodLiteral, profileTypeInfo,
172            methodOffset, methodPcInfo, methodInfo, module, pcStart, header, abcId);
173    }
174};
175} // namespace panda::ecmascript::kungfu
176#endif  // ECMASCRIPT_COMPILER_COMPILATION_DRIVER_H
177