• 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       collector_(collector),
37       bytecodeInfo_(collector->GetBytecodeInfo()),
38       fileGenerator_(fileGenerator),
39       fileName_(fileName),
40       triple_(triple),
41       lOptions_(lOptions),
42       log_(log),
43       outputAsm_(outputAsm),
44       maxMethodsInModule_(maxMethodsInModule)
45 {
46     vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->SetCompilationDriver(this);
47 
48     if (!optionSelectMethods.empty() && !optionSkipMethods.empty()) {
49         LOG_COMPILER(FATAL) <<
50             "--compiler-select-methods and --compiler-skip-methods should not be set at the same time";
51     }
52 
53     if (!optionSelectMethods.empty()) {
54         ParseOption(optionSelectMethods, optionSelectMethods_);
55     }
56 
57     if (!optionSkipMethods.empty()) {
58         ParseOption(optionSkipMethods, optionSkipMethods_);
59     }
60 }
61 
~CompilationDriver()62 CompilationDriver::~CompilationDriver()
63 {
64     vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->SetCompilationDriver(nullptr);
65 }
66 
GetModule()67 Module *CompilationDriver::GetModule()
68 {
69     return IsCurModuleFull() ? fileGenerator_->AddModule(fileName_, triple_, *lOptions_, outputAsm_)
70                                 : fileGenerator_->GetLatestModule();
71 }
72 
IncCompiledMethod()73 void CompilationDriver::IncCompiledMethod()
74 {
75     compiledMethodCnt_++;
76 }
77 
IsCurModuleFull() const78 bool CompilationDriver::IsCurModuleFull() const
79 {
80     return (compiledMethodCnt_ % maxMethodsInModule_ == 0);
81 }
82 
CompileModuleThenDestroyIfNeeded()83 void CompilationDriver::CompileModuleThenDestroyIfNeeded()
84 {
85     if (IsCurModuleFull()) {
86         fileGenerator_->CompileLatestModuleThenDestroy();
87     }
88 }
89 
CompileLastModuleThenDestroyIfNeeded()90 void CompilationDriver::CompileLastModuleThenDestroyIfNeeded()
91 {
92     if (!IsCurModuleFull()) {
93         fileGenerator_->CompileLatestModuleThenDestroy();
94     }
95 }
96 
TopologicalSortForRecords()97 void CompilationDriver::TopologicalSortForRecords()
98 {
99     const auto &importRecordsInfos = bytecodeInfo_.GetImportRecordsInfos();
100     std::queue<CString> recordList;
101     std::unordered_map<CString, uint32_t> recordInDegree;
102     std::unordered_map<CString, std::vector<CString>> exportRecords;
103     std::vector<CString> &tpOrder = bytecodeInfo_.GetRecordNames();
104     for (auto &record : tpOrder) {
105         auto iter = importRecordsInfos.find(record);
106         if (iter == importRecordsInfos.end()) {
107             recordInDegree.emplace(record, 0);
108             recordList.emplace(record);
109         } else {
110             recordInDegree.emplace(record, iter->second.GetImportRecordSize());
111         }
112     }
113     tpOrder.clear();
114 
115     for (auto iter = importRecordsInfos.begin(); iter != importRecordsInfos.end(); iter++) {
116         const auto &importRecords = iter->second.GetImportRecords();
117         for (const auto &import : importRecords) {
118             if (exportRecords.find(import) != exportRecords.end()) {
119                 exportRecords[import].emplace_back(iter->first);
120             } else {
121                 exportRecords.emplace(import, std::vector<CString>{iter->first});
122             }
123         }
124     }
125 
126     while (!recordList.empty()) {
127         auto curRecord = recordList.front();
128         tpOrder.emplace_back(curRecord);
129         recordList.pop();
130         auto iter = exportRecords.find(curRecord);
131         if (iter != exportRecords.end()) {
132             for (const auto &ele : iter->second) {
133                 if (recordInDegree[ele] > 0 && --recordInDegree[ele] == 0) {
134                     recordList.emplace(ele);
135                 }
136             }
137         }
138     }
139 
140     if (UNLIKELY(tpOrder.size() != recordInDegree.size())) {
141         LOG_COMPILER(INFO) << "There are circular references in records";
142         for (auto &it : recordInDegree) {
143             if (it.second != 0) {
144                 tpOrder.emplace_back(it.first);
145             }
146         }
147         ASSERT(tpOrder.size() == recordInDegree.size());
148     }
149     auto &mainMethods = bytecodeInfo_.GetMainMethodIndexes();
150     auto sortId = 0;
151     for (auto &it : tpOrder) {
152         mainMethods.emplace_back(jsPandaFile_->GetMainMethodIndex(it));
153         sortedRecords_.emplace(it, sortId++);
154     }
155     ASSERT(tpOrder.size() == mainMethods.size());
156 }
157 
FetchPGOMismatchResult()158 void CompilationDriver::FetchPGOMismatchResult()
159 {
160     ASSERT(log_ != nullptr);
161     uint32_t totalMethodCount = 0;
162     uint32_t mismatchMethodCount = 0;
163     std::set<std::pair<std::string, CString>> mismatchMethodSet {};
164     pfDecoder_.GetMismatchResult(jsPandaFile_, totalMethodCount, mismatchMethodCount, mismatchMethodSet);
165     log_->SetPGOMismatchResult(totalMethodCount, mismatchMethodCount, mismatchMethodSet);
166 }
167 
UpdatePGO()168 void CompilationDriver::UpdatePGO()
169 {
170     std::unordered_set<EntityId> newMethodIds;
171     auto dfs = [this, &newMethodIds] (const CString &recordName,
172         const std::unordered_set<EntityId> &oldIds) -> std::unordered_set<EntityId> & {
173             newMethodIds.clear();
174             if (!jsPandaFile_->HasTSTypes(recordName)) {
175                 return newMethodIds;
176             }
177             uint32_t mainMethodOffset = jsPandaFile_->GetMainMethodIndex(recordName);
178             SearchForCompilation(recordName, oldIds, newMethodIds, mainMethodOffset, false);
179             return newMethodIds;
180         };
181     pfDecoder_.Update(jsPandaFile_, dfs);
182     FetchPGOMismatchResult();
183 }
184 
InitializeCompileQueue()185 void CompilationDriver::InitializeCompileQueue()
186 {
187     TopologicalSortForRecords();
188     auto &mainMethodIndexes = bytecodeInfo_.GetMainMethodIndexes();
189     for (auto mainMethodIndex : mainMethodIndexes) {
190         compileQueue_.push_back(mainMethodIndex);
191     }
192 }
193 
FilterMethod(const CString & recordName,const MethodLiteral * methodLiteral,const MethodPcInfo & methodPCInfo,const std::string & methodName) const194 bool CompilationDriver::FilterMethod(const CString &recordName, const MethodLiteral *methodLiteral,
195                                      const MethodPcInfo &methodPCInfo, const std::string &methodName) const
196 {
197     if (methodPCInfo.methodsSize > bytecodeInfo_.GetMaxMethodSize() ||
198         !pfDecoder_.Match(jsPandaFile_, recordName, methodLiteral->GetMethodId())) {
199         return true;
200     }
201 
202     if (!optionSelectMethods_.empty()) {
203         return !FilterOption(optionSelectMethods_, ConvertToStdString(recordName), methodName);
204     } else if (!optionSkipMethods_.empty()) {
205         return FilterOption(optionSkipMethods_, ConvertToStdString(recordName), methodName);
206     }
207 
208     return false;
209 }
210 
SplitString(const std::string & str,const char ch) const211 std::vector<std::string> CompilationDriver::SplitString(const std::string &str, const char ch) const
212 {
213     std::vector<std::string> vec {};
214     std::istringstream sstr(str.c_str());
215     std::string split;
216     while (getline(sstr, split, ch)) {
217         vec.emplace_back(split);
218     }
219     return vec;
220 }
221 
ParseOption(const std::string & option,std::map<std::string,std::vector<std::string>> & optionMap) const222 void CompilationDriver::ParseOption(const std::string &option,
223                                     std::map<std::string, std::vector<std::string>> &optionMap) const
224 {
225     const char colon = ':';
226     const char comma = ',';
227     std::string str = option;
228     size_t posColon = 0;
229     size_t posComma = 0;
230     do {
231         posColon = str.find_last_of(colon);
232         std::string methodNameList = str.substr(posColon + 1, str.size());
233         std::vector<std::string> methodNameVec = SplitString(methodNameList, comma);
234         str = str.substr(0, posColon);
235         posComma = str.find_last_of(comma);
236         std::string recordName = str.substr(posComma + 1, str.size());
237         str = str.substr(0, posComma);
238         optionMap[recordName] = methodNameVec;
239     } while (posComma != std::string::npos);
240 }
241 
FilterOption(const std::map<std::string,std::vector<std::string>> & optionMap,const std::string & recordName,const std::string & methodName) const242 bool CompilationDriver::FilterOption(const std::map<std::string, std::vector<std::string>> &optionMap,
243                                      const std::string &recordName, const std::string &methodName) const
244 {
245     if (optionMap.empty()) {
246         return false;
247     }
248 
249     auto it = optionMap.find(recordName);
250     if (it == optionMap.end()) {
251         return false;
252     }
253 
254     std::vector<std::string> vec = it->second;
255     return find(vec.begin(), vec.end(), methodName) != vec.end();
256 }
257 
SetCurrentConstantPool(uint32_t methodOffset) const258 void CompilationDriver::SetCurrentConstantPool(uint32_t methodOffset) const
259 {
260     PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager();
261     ptManager->SetCurConstantPool(jsPandaFile_, methodOffset);
262 }
263 
StoreConstantPoolInfo() const264 void CompilationDriver::StoreConstantPoolInfo() const
265 {
266     auto &methodList = bytecodeInfo_.GetMethodList();
267     for (auto &x : methodList) {
268         if (!bytecodeInfo_.FindMethodOffsetToRecordName(x.first)) {
269             bytecodeInfo_.AddSkippedMethod(x.first);
270         }
271     }
272     PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager();
273     ptManager->GetAOTSnapshot().StoreConstantPoolInfo(collector_);
274 }
275 
RunCg()276 bool JitCompilationDriver::RunCg()
277 {
278     IncCompiledMethod();
279     CompileModuleThenDestroyIfNeeded();
280     return true;
281 }
282 
GetModule()283 Module *JitCompilationDriver::GetModule()
284 {
285     return IsCurModuleFull() ? fileGenerator_->AddModule(fileName_, triple_, *lOptions_, outputAsm_, true) :
286         fileGenerator_->GetLatestModule();
287 }
288 } // namespace panda::ecmascript::kungfu
289