• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/compiler/compilation_driver.h"
17 #include "ecmascript/compiler/file_generators.h"
18 #include "ecmascript/jspandafile/method_literal.h"
19 #include "ecmascript/ts_types/ts_manager.h"
20 
21 namespace panda::ecmascript::kungfu {
CompilationDriver(PGOProfilerDecoder & profilerDecoder,BytecodeInfoCollector * collector,const std::string & optionSelectMethods,const std::string & optionSkipMethods,AOTFileGenerator * fileGenerator,const std::string & fileName,const std::string & triple,LOptions * lOptions,CompilerLog * log,bool outputAsm,size_t maxMethodsInModule)22 CompilationDriver::CompilationDriver(PGOProfilerDecoder &profilerDecoder,
23                                      BytecodeInfoCollector *collector,
24                                      const std::string &optionSelectMethods,
25                                      const std::string &optionSkipMethods,
26                                      AOTFileGenerator *fileGenerator,
27                                      const std::string &fileName,
28                                      const std::string &triple,
29                                      LOptions *lOptions,
30                                      CompilerLog *log,
31                                      bool outputAsm,
32                                      size_t maxMethodsInModule)
33     : vm_(collector->GetVM()),
34       jsPandaFile_(collector->GetJSPandaFile()),
35       pfDecoder_(profilerDecoder),
36       bytecodeInfo_(collector->GetBytecodeInfo()),
37       fileGenerator_(fileGenerator),
38       fileName_(fileName),
39       triple_(triple),
40       lOptions_(lOptions),
41       log_(log),
42       outputAsm_(outputAsm),
43       maxMethodsInModule_(maxMethodsInModule)
44 {
45     vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->SetCompilationDriver(this);
46 
47     if (!optionSelectMethods.empty() && !optionSkipMethods.empty()) {
48         LOG_COMPILER(FATAL) <<
49             "--compiler-select-methods and --compiler-skip-methods should not be set at the same time";
50     }
51 
52     if (!optionSelectMethods.empty()) {
53         ParseOption(optionSelectMethods, optionSelectMethods_);
54     }
55 
56     if (!optionSkipMethods.empty()) {
57         ParseOption(optionSkipMethods, optionSkipMethods_);
58     }
59 }
60 
~CompilationDriver()61 CompilationDriver::~CompilationDriver()
62 {
63     vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->SetCompilationDriver(nullptr);
64 }
65 
GetModule()66 Module *CompilationDriver::GetModule()
67 {
68     return IsCurModuleFull() ? fileGenerator_->AddModule(fileName_, triple_, *lOptions_, outputAsm_)
69                                 : fileGenerator_->GetLatestModule();
70 }
71 
IncCompiledMethod()72 void CompilationDriver::IncCompiledMethod()
73 {
74     compiledMethodCnt_++;
75 }
76 
IsCurModuleFull() const77 bool CompilationDriver::IsCurModuleFull() const
78 {
79     return (compiledMethodCnt_ % maxMethodsInModule_ == 0);
80 }
81 
CompileModuleThenDestroyIfNeeded()82 void CompilationDriver::CompileModuleThenDestroyIfNeeded()
83 {
84     if (IsCurModuleFull()) {
85         fileGenerator_->CompileLatestModuleThenDestroy();
86     }
87 }
88 
CompileLastModuleThenDestroyIfNeeded()89 void CompilationDriver::CompileLastModuleThenDestroyIfNeeded()
90 {
91     if (!IsCurModuleFull()) {
92         fileGenerator_->CompileLatestModuleThenDestroy();
93     }
94 }
95 
TopologicalSortForRecords()96 void CompilationDriver::TopologicalSortForRecords()
97 {
98     const auto &importRecordsInfos = bytecodeInfo_.GetImportRecordsInfos();
99     std::queue<CString> recordList;
100     std::unordered_map<CString, uint32_t> recordInDegree;
101     std::unordered_map<CString, std::vector<CString>> exportRecords;
102     std::vector<CString> &tpOrder = bytecodeInfo_.GetRecordNames();
103     for (auto &record : tpOrder) {
104         auto iter = importRecordsInfos.find(record);
105         if (iter == importRecordsInfos.end()) {
106             recordInDegree.emplace(record, 0);
107             recordList.emplace(record);
108         } else {
109             recordInDegree.emplace(record, iter->second.GetImportRecordSize());
110         }
111     }
112     tpOrder.clear();
113 
114     for (auto iter = importRecordsInfos.begin(); iter != importRecordsInfos.end(); iter++) {
115         const auto &importRecords = iter->second.GetImportRecords();
116         for (const auto &import : importRecords) {
117             if (exportRecords.find(import) != exportRecords.end()) {
118                 exportRecords[import].emplace_back(iter->first);
119             } else {
120                 exportRecords.emplace(import, std::vector<CString>{iter->first});
121             }
122         }
123     }
124 
125     while (!recordList.empty()) {
126         auto curRecord = recordList.front();
127         tpOrder.emplace_back(curRecord);
128         recordList.pop();
129         auto iter = exportRecords.find(curRecord);
130         if (iter != exportRecords.end()) {
131             for (const auto &ele : iter->second) {
132                 if (recordInDegree[ele] > 0 && --recordInDegree[ele] == 0) {
133                     recordList.emplace(ele);
134                 }
135             }
136         }
137     }
138 
139     if (UNLIKELY(tpOrder.size() != recordInDegree.size())) {
140         LOG_COMPILER(INFO) << "There are circular references in records";
141         for (auto &it : recordInDegree) {
142             if (it.second != 0) {
143                 tpOrder.emplace_back(it.first);
144             }
145         }
146         ASSERT(tpOrder.size() == recordInDegree.size());
147     }
148     auto &mainMethods = bytecodeInfo_.GetMainMethodIndexes();
149     auto sortId = 0;
150     for (auto &it : tpOrder) {
151         mainMethods.emplace_back(jsPandaFile_->GetMainMethodIndex(it));
152         sortedRecords_.emplace(it, sortId++);
153     }
154     ASSERT(tpOrder.size() == mainMethods.size());
155 }
156 
FetchPGOMismatchResult()157 void CompilationDriver::FetchPGOMismatchResult()
158 {
159     ASSERT(log_ != nullptr);
160     uint32_t totalMethodCount = 0;
161     uint32_t mismatchMethodCount = 0;
162     std::set<std::pair<std::string, CString>> mismatchMethodSet {};
163     pfDecoder_.GetMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet);
164     log_->SetPGOMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet);
165 }
166 
UpdatePGO()167 void CompilationDriver::UpdatePGO()
168 {
169     std::unordered_set<EntityId> newMethodIds;
170     auto dfs = [this, &newMethodIds] (const CString &recordName,
171         const std::unordered_set<EntityId> &oldIds) -> std::unordered_set<EntityId> & {
172             newMethodIds.clear();
173             if (!jsPandaFile_->HasTSTypes(recordName)) {
174                 return newMethodIds;
175             }
176             uint32_t mainMethodOffset = jsPandaFile_->GetMainMethodIndex(recordName);
177             SearchForCompilation(recordName, oldIds, newMethodIds, mainMethodOffset, false);
178             return newMethodIds;
179         };
180     pfDecoder_.Update(dfs);
181     FetchPGOMismatchResult();
182 }
183 
InitializeCompileQueue()184 void CompilationDriver::InitializeCompileQueue()
185 {
186     TopologicalSortForRecords();
187     auto &mainMethodIndexes = bytecodeInfo_.GetMainMethodIndexes();
188     for (auto mainMethodIndex : mainMethodIndexes) {
189         compileQueue_.push_back(mainMethodIndex);
190     }
191 }
192 
FilterMethod(const CString & recordName,const MethodLiteral * methodLiteral,const MethodPcInfo & methodPCInfo,const std::string & methodName) const193 bool CompilationDriver::FilterMethod(const CString &recordName, const MethodLiteral *methodLiteral,
194                                      const MethodPcInfo &methodPCInfo, const std::string &methodName) const
195 {
196     if (methodPCInfo.methodsSize > bytecodeInfo_.GetMaxMethodSize() ||
197         !pfDecoder_.Match(recordName, methodLiteral->GetMethodId())) {
198         return true;
199     }
200 
201     if (!optionSelectMethods_.empty()) {
202         return !FilterOption(optionSelectMethods_, ConvertToStdString(recordName), methodName);
203     } else if (!optionSkipMethods_.empty()) {
204         return FilterOption(optionSkipMethods_, ConvertToStdString(recordName), methodName);
205     }
206 
207     return false;
208 }
209 
SplitString(const std::string & str,const char ch) const210 std::vector<std::string> CompilationDriver::SplitString(const std::string &str, const char ch) const
211 {
212     std::vector<std::string> vec {};
213     std::istringstream sstr(str.c_str());
214     std::string split;
215     while (getline(sstr, split, ch)) {
216         vec.emplace_back(split);
217     }
218     return vec;
219 }
220 
ParseOption(const std::string & option,std::map<std::string,std::vector<std::string>> & optionMap) const221 void CompilationDriver::ParseOption(const std::string &option,
222                                     std::map<std::string, std::vector<std::string>> &optionMap) const
223 {
224     const char colon = ':';
225     const char comma = ',';
226     std::string str = option;
227     size_t posColon = 0;
228     size_t posComma = 0;
229     do {
230         posColon = str.find_last_of(colon);
231         std::string methodNameList = str.substr(posColon + 1, str.size());
232         std::vector<std::string> methodNameVec = SplitString(methodNameList, comma);
233         str = str.substr(0, posColon);
234         posComma = str.find_last_of(comma);
235         std::string recordName = str.substr(posComma + 1, str.size());
236         str = str.substr(0, posComma);
237         optionMap[recordName] = methodNameVec;
238     } while (posComma != std::string::npos);
239 }
240 
FilterOption(const std::map<std::string,std::vector<std::string>> & optionMap,const std::string & recordName,const std::string & methodName) const241 bool CompilationDriver::FilterOption(const std::map<std::string, std::vector<std::string>> &optionMap,
242                                      const std::string &recordName, const std::string &methodName) const
243 {
244     if (optionMap.empty()) {
245         return false;
246     }
247 
248     auto it = optionMap.find(recordName);
249     if (it == optionMap.end()) {
250         return false;
251     }
252 
253     std::vector<std::string> vec = it->second;
254     return find(vec.begin(), vec.end(), methodName) != vec.end();
255 }
256 } // namespace panda::ecmascript::kungfu
257