• 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 #ifndef ECMASCRIPT_COMPILER_BYTECODE_INFO_COLLECTOR_H
17 #define ECMASCRIPT_COMPILER_BYTECODE_INFO_COLLECTOR_H
18 
19 #include "ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.h"
20 #include "ecmascript/compiler/pgo_bc_info.h"
21 #include "ecmascript/jspandafile/js_pandafile.h"
22 #include "ecmascript/jspandafile/method_literal.h"
23 #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
24 #include "libpandafile/bytecode_instruction-inl.h"
25 
26 namespace panda::ecmascript::kungfu {
27 /*    ts source code
28  *    let a:number = 1;
29  *    function f() {
30  *        let b:number = 1;
31  *        function g() {
32  *            return a + b;
33  *        }
34  *        return g();
35  *    }
36  *
37  *                                     The structure of Lexical Environment
38  *
39  *                                               Lexical Environment             Lexical Environment
40  *               Global Environment                 of function f                   of function g
41  *              +-------------------+ <----+    +-------------------+ <----+    +-------------------+
42  *    null <----|  Outer Reference  |      +----|  Outer Reference  |      +----|  Outer Reference  |
43  *              +-------------------+           +-------------------+           +-------------------+
44  *              |Environment Recoder|           |Environment Recoder|           |Environment Recoder|
45  *              +-------------------+           +-------------------+           +-------------------+
46  *
47  *    We only record the type of the variable in Environment Recoder.
48  *    In the design of the Ark bytecode, if a method does not have any
49  *    lex-env variable in its Lexical Environment, then there will be
50  *    no EcmaOpcode::NEWLEXENV in it which leads to ARK runtime will
51  *    not create a Lexical Environment when the method is executed.
52  *    In order to simulate the state of the runtime as much as possible,
53  *    a field named 'status' will be added into the class LexEnv to
54  *    measure this state. Take the above code as an example, although in
55  *    static analysis, we will create LexEnv for each method, only Lexenvs
56  *    of global and function f will be created when methods are executed.
57  */
58 
59 using PGOProfilerDecoder = pgo::PGOProfilerDecoder;
60 
61 enum class LexicalEnvStatus : uint8_t {
62     VIRTUAL_LEXENV,
63     REALITY_LEXENV
64 };
65 
66 class LexEnv {
67 public:
68     LexEnv() = default;
69     ~LexEnv() = default;
70 
71     static constexpr uint32_t DEFAULT_ROOT = std::numeric_limits<uint32_t>::max();
72 
Inilialize(uint32_t outMethodId,uint32_t numOfLexVars,LexicalEnvStatus status)73     inline void Inilialize(uint32_t outMethodId, uint32_t numOfLexVars, LexicalEnvStatus status)
74     {
75         outerMethodId_ = outMethodId;
76         lexVarTypes_.resize(numOfLexVars, GateType::AnyType());
77         status_ = status;
78     }
79 
GetOutMethodId()80     inline uint32_t GetOutMethodId() const
81     {
82         return outerMethodId_;
83     }
84 
GetLexEnvStatus()85     inline LexicalEnvStatus GetLexEnvStatus() const
86     {
87         return status_;
88     }
89 
GetLexVarType(uint32_t slot)90     inline GateType GetLexVarType(uint32_t slot) const
91     {
92         if (slot < lexVarTypes_.size()) {
93             return lexVarTypes_[slot];
94         }
95         return GateType::AnyType();
96     }
97 
SetLexVarType(uint32_t slot,const GateType & type)98     inline void SetLexVarType(uint32_t slot, const GateType &type)
99     {
100         if (slot < lexVarTypes_.size()) {
101             lexVarTypes_[slot] = type;
102         }
103     }
104 
105 private:
106     uint32_t outerMethodId_ { DEFAULT_ROOT };
107     std::vector<GateType> lexVarTypes_ {};
108     LexicalEnvStatus status_ { LexicalEnvStatus::VIRTUAL_LEXENV };
109 };
110 
111 // each method in the abc file corresponds to one MethodInfo and
112 // methods with the same instructions share one common MethodPcInfo
113 struct MethodPcInfo {
114     std::vector<const uint8_t*> pcOffsets {};
115     uint32_t methodsSize {0};
116 };
117 
118 // importRecord : ldExternalModuleVar {importIndex} --> {exportRecordName} : stmoduleVar {exportIndex}
119 class ImportRecordInfo {
120 public:
121     ImportRecordInfo() = default;
122     ~ImportRecordInfo() = default;
123 
AddImportIdAndRecord(uint32_t importId,uint32_t bindingId,const CString & importRecord)124     void AddImportIdAndRecord(uint32_t importId, uint32_t bindingId, const CString &importRecord)
125     {
126         records_.insert(importRecord);
127         if (idToRecord_.find(importId) == idToRecord_.end()) {
128             idToRecord_.emplace(importId, std::make_pair(importRecord, bindingId));
129         }
130     }
131 
GetImportRecords()132     const std::set<CString> &GetImportRecords() const
133     {
134         return records_;
135     }
136 
GetImportRecordSize()137     uint32_t GetImportRecordSize() const
138     {
139         return records_.size();
140     }
141 
GetImportIdToExportRecord()142     const std::unordered_map<uint32_t, std::pair<CString, uint32_t>> &GetImportIdToExportRecord() const
143     {
144         return idToRecord_;
145     }
146 
147 private:
148     std::set<CString> records_ {};
149     std::unordered_map<uint32_t, std::pair<CString, uint32_t>> idToRecord_ {};
150 };
151 
152 // exportIndex_ {exportIndex1...}: collect bytecode export index whose type has not been recorded.
153 // starExportRecord_ {recordName A...}: collect recordName when there is Forwarding syntax in this record,
154 // like "export * from record A, export * from record B"
155 class ExportRecordInfo {
156 public:
157     ExportRecordInfo() = default;
ExportRecordInfo(uint32_t index)158     explicit ExportRecordInfo(uint32_t index) : exportIndex_({index}) {}
ExportRecordInfo(const CString & starRecord)159     explicit ExportRecordInfo(const CString &starRecord) : starExportRecord_({starRecord}) {}
160 
161     ~ExportRecordInfo() = default;
162 
HasExportIndex(uint32_t index)163     bool HasExportIndex(uint32_t index) const
164     {
165         return exportIndex_.find(index) != exportIndex_.end();
166     }
167 
HasStarExport()168     bool HasStarExport() const
169     {
170         return !starExportRecord_.empty();
171     }
172 
AddExportIndex(uint32_t index)173     void AddExportIndex(uint32_t index)
174     {
175         exportIndex_.insert(index);
176     }
177 
AddStarExport(const CString & starExportRecord)178     void AddStarExport(const CString &starExportRecord)
179     {
180         starExportRecord_.insert(starExportRecord);
181     }
182 
GetstarExportRecord()183     const std::unordered_set<CString> &GetstarExportRecord() const
184     {
185         return starExportRecord_;
186     }
187 
188 private:
189     std::unordered_set<uint32_t> exportIndex_ {};
190     std::unordered_set<CString> starExportRecord_ {};
191 };
192 
193 class MethodInfo {
194 public:
195     MethodInfo(uint32_t methodInfoIndex, uint32_t methodPcInfoIndex, uint32_t outMethodIdx,
196                uint32_t outMethodOffset = MethodInfo::DEFAULT_OUTMETHOD_OFFSET, uint32_t num = 0,
197                LexicalEnvStatus lexEnvStatus = LexicalEnvStatus::VIRTUAL_LEXENV, bool isNamespace = false)
methodInfoIndex_(methodInfoIndex)198         : methodInfoIndex_(methodInfoIndex), methodPcInfoIndex_(methodPcInfoIndex), outerMethodId_(outMethodIdx),
199           outerMethodOffset_(outMethodOffset), numOfLexVars_(num), status_(lexEnvStatus), isNamespace_(isNamespace)
200     {
201     }
202 
203     ~MethodInfo() = default;
204 
205     static constexpr uint32_t DEFAULT_OUTMETHOD_OFFSET = 0;
206 
GetOutMethodId()207     inline uint32_t GetOutMethodId() const
208     {
209         return outerMethodId_;
210     }
211 
SetOutMethodId(uint32_t outMethodId)212     inline void SetOutMethodId(uint32_t outMethodId)
213     {
214         outerMethodId_ = outMethodId;
215     }
216 
GetOutMethodOffset()217     inline uint32_t GetOutMethodOffset() const
218     {
219         return outerMethodOffset_;
220     }
221 
SetOutMethodOffset(uint32_t outMethodOffset)222     inline void SetOutMethodOffset(uint32_t outMethodOffset)
223     {
224         outerMethodOffset_ = outMethodOffset;
225     }
226 
GetNumOfLexVars()227     inline uint32_t GetNumOfLexVars() const
228     {
229         return numOfLexVars_;
230     }
231 
SetNumOfLexVars(uint32_t numOfLexVars)232     inline void SetNumOfLexVars(uint32_t numOfLexVars)
233     {
234         if (numOfLexVars > numOfLexVars_) {
235             numOfLexVars_ = numOfLexVars;
236         }
237     }
238 
GetLexEnvStatus()239     inline LexicalEnvStatus GetLexEnvStatus() const
240     {
241         return status_;
242     }
243 
SetLexEnvStatus(LexicalEnvStatus status)244     inline void SetLexEnvStatus(LexicalEnvStatus status)
245     {
246         status_ = status;
247     }
248 
GetMethodPcInfoIndex()249     inline uint32_t GetMethodPcInfoIndex() const
250     {
251         return methodPcInfoIndex_;
252     }
253 
SetMethodPcInfoIndex(uint32_t methodPcInfoIndex)254     inline void SetMethodPcInfoIndex(uint32_t methodPcInfoIndex)
255     {
256         methodPcInfoIndex_ = methodPcInfoIndex;
257     }
258 
GetMethodInfoIndex()259     inline uint32_t GetMethodInfoIndex() const
260     {
261         return methodInfoIndex_;
262     }
263 
SetMethodInfoIndex(uint32_t methodInfoIndex)264     inline void SetMethodInfoIndex(uint32_t methodInfoIndex)
265     {
266         methodInfoIndex_ = methodInfoIndex;
267     }
268 
AddInnerMethod(uint32_t offset,bool isConstructor)269     inline void AddInnerMethod(uint32_t offset, bool isConstructor)
270     {
271         if (isConstructor) {
272             constructorMethods_.emplace_back(offset);
273         } else {
274             innerMethods_.emplace_back(offset);
275         }
276     }
277 
RearrangeInnerMethods()278     inline void RearrangeInnerMethods()
279     {
280         innerMethods_.insert(innerMethods_.begin(), constructorMethods_.begin(), constructorMethods_.end());
281     }
282 
AddBcToTypeId(int32_t bcIndex,uint32_t innerFuncTypeId)283     inline void AddBcToTypeId(int32_t bcIndex, uint32_t innerFuncTypeId)
284     {
285         bcToFuncTypeId_.emplace(bcIndex, innerFuncTypeId);
286     }
287 
GetBCAndTypes()288     inline const std::unordered_map<int32_t, uint32_t> &GetBCAndTypes() const
289     {
290         return bcToFuncTypeId_;
291     }
292 
MarkMethodNamespace()293     inline void MarkMethodNamespace()
294     {
295         isNamespace_ = true;
296     }
297 
IsNamespace()298     inline bool IsNamespace() const
299     {
300         return isNamespace_;
301     }
302 
GetInnerMethods()303     inline const std::vector<uint32_t> &GetInnerMethods() const
304     {
305         return innerMethods_;
306     }
307 
AddImportIndex(uint32_t index)308     inline void AddImportIndex(uint32_t index)
309     {
310         importIndex_.insert(index);
311     }
312 
GetImportIndexes()313     inline const std::set<uint32_t> &GetImportIndexes() const
314     {
315         return importIndex_;
316     }
317 
CopyImportIndex(const std::set<uint32_t> & indexSet)318     inline void CopyImportIndex(const std::set<uint32_t> &indexSet)
319     {
320         importIndex_ = indexSet;
321     }
322 
IsPGO()323     bool IsPGO() const
324     {
325         return CompileStateBit::PGOBit::Decode(compileState_.value_);
326     }
327 
SetIsPGO(bool pgoMark)328     void SetIsPGO(bool pgoMark)
329     {
330         CompileStateBit::PGOBit::Set<uint8_t>(pgoMark, &compileState_.value_);
331     }
332 
IsCompiled()333     bool IsCompiled() const
334     {
335         return CompileStateBit::CompiledBit::Decode(compileState_.value_);
336     }
337 
SetIsCompiled(bool isCompiled)338     void SetIsCompiled(bool isCompiled)
339     {
340         CompileStateBit::CompiledBit::Set<uint8_t>(isCompiled, &compileState_.value_);
341     }
342 
IsTypeInferAbort()343     bool IsTypeInferAbort() const
344     {
345         return CompileStateBit::TypeInferAbortBit::Decode(compileState_.value_);
346     }
347 
SetTypeInferAbort(bool halfCompiled)348     void SetTypeInferAbort(bool halfCompiled)
349     {
350         CompileStateBit::TypeInferAbortBit::Set<uint8_t>(halfCompiled, &compileState_.value_);
351     }
352 
IsResolvedMethod()353     bool IsResolvedMethod() const
354     {
355         return CompileStateBit::ResolvedMethodBit::Decode(compileState_.value_);
356     }
357 
SetResolvedMethod(bool isDeoptResolveNeed)358     void SetResolvedMethod(bool isDeoptResolveNeed)
359     {
360         CompileStateBit::ResolvedMethodBit::Set<uint8_t>(isDeoptResolveNeed, &compileState_.value_);
361     }
362 
363 private:
364     class CompileStateBit {
365     public:
CompileStateBit(uint8_t value)366         explicit CompileStateBit(uint8_t value) : value_(value) {}
367         CompileStateBit() = default;
368         ~CompileStateBit() = default;
369         DEFAULT_COPY_SEMANTIC(CompileStateBit);
370         DEFAULT_MOVE_SEMANTIC(CompileStateBit);
371 
372         static constexpr size_t BOOL_FLAG_BIT_LENGTH = 1;
373         using PGOBit = panda::BitField<bool, 0, BOOL_FLAG_BIT_LENGTH>;
374         using CompiledBit = PGOBit::NextField<bool, BOOL_FLAG_BIT_LENGTH>;
375         using TypeInferAbortBit = CompiledBit::NextField<bool, BOOL_FLAG_BIT_LENGTH>;
376         using ResolvedMethodBit = TypeInferAbortBit::NextField<bool, BOOL_FLAG_BIT_LENGTH>;
377 
378     private:
379         uint8_t value_ {0};
380         friend class MethodInfo;
381     };
382     // used to record the index of the current MethodInfo to speed up the lookup of lexEnv
383     uint32_t methodInfoIndex_ { 0 };
384     // used to obtain MethodPcInfo from the vector methodPcInfos of struct BCInfo
385     uint32_t methodPcInfoIndex_ { 0 };
386     std::vector<uint32_t> innerMethods_ {};
387     std::vector<uint32_t> constructorMethods_ {};
388     std::unordered_map<int32_t, uint32_t> bcToFuncTypeId_ {};
389     uint32_t outerMethodId_ { LexEnv::DEFAULT_ROOT };
390     uint32_t outerMethodOffset_ { MethodInfo::DEFAULT_OUTMETHOD_OFFSET };
391     uint32_t numOfLexVars_ { 0 };
392     LexicalEnvStatus status_ { LexicalEnvStatus::VIRTUAL_LEXENV };
393     std::set<uint32_t> importIndex_ {};
394     CompileStateBit compileState_ { 0 };
395     bool isNamespace_ {false};
396 };
397 
398 struct FastCallInfo {
399     bool canFastCall_ {false};
400     bool isNoGC_ {false};
401 };
402 
403 class BCInfo {
404 public:
BCInfo(size_t maxAotMethodSize)405     explicit BCInfo(size_t maxAotMethodSize)
406         : maxMethodSize_(maxAotMethodSize)
407     {
408     }
409 
GetMainMethodIndexes()410     std::vector<uint32_t>& GetMainMethodIndexes()
411     {
412         return mainMethodIndexes_;
413     }
414 
GetRecordNames()415     std::vector<CString>& GetRecordNames()
416     {
417         return recordNames_;
418     }
419 
GetMethodPcInfos()420     std::vector<MethodPcInfo>& GetMethodPcInfos()
421     {
422         return methodPcInfos_;
423     }
424 
GetMethodList()425     std::unordered_map<uint32_t, MethodInfo>& GetMethodList()
426     {
427         return methodList_;
428     }
429 
GetMaxMethodSize()430     size_t GetMaxMethodSize() const
431     {
432         return maxMethodSize_;
433     }
434 
IsSkippedMethod(uint32_t methodOffset)435     bool IsSkippedMethod(uint32_t methodOffset) const
436     {
437         if (skippedMethods_.find(methodOffset) == skippedMethods_.end()) {
438             return false;
439         }
440         return true;
441     }
442 
GetSkippedMethodSet()443     const std::set<uint32_t>& GetSkippedMethodSet() const
444     {
445         return skippedMethods_;
446     }
447 
AddSkippedMethod(uint32_t methodOffset)448     void AddSkippedMethod(uint32_t methodOffset)
449     {
450         skippedMethods_.insert(methodOffset);
451     }
452 
EraseSkippedMethod(uint32_t methodOffset)453     void EraseSkippedMethod(uint32_t methodOffset)
454     {
455         if (skippedMethods_.find(methodOffset) != skippedMethods_.end()) {
456             skippedMethods_.erase(methodOffset);
457         }
458     }
459 
460     // for deopt resolve, when we add new resolve method to compile queue, the recordName vector also need to update
461     // for seek, its recordName also need to be set correspondingly
AddRecordName(const CString & recordName)462     void AddRecordName(const CString &recordName)
463     {
464         recordNames_.emplace_back(recordName);
465     }
466 
GetRecordName(uint32_t index)467     CString GetRecordName(uint32_t index) const
468     {
469         return recordNames_[index];
470     }
471 
FindMethodOffsetToRecordName(uint32_t methodOffset)472     bool FindMethodOffsetToRecordName(uint32_t methodOffset)
473     {
474         return methodOffsetToRecordName_.find(methodOffset) != methodOffsetToRecordName_.end();
475     }
476 
AddMethodOffsetToRecordName(uint32_t methodOffset,CString recordName)477     void AddMethodOffsetToRecordName(uint32_t methodOffset, CString recordName)
478     {
479         methodOffsetToRecordName_.emplace(methodOffset, recordName);
480     }
481 
GetSkippedMethodSize()482     size_t GetSkippedMethodSize() const
483     {
484         return skippedMethods_.size();
485     }
486 
GetDefineMethod(const uint32_t classLiteralOffset)487     uint32_t GetDefineMethod(const uint32_t classLiteralOffset) const
488     {
489         return classTypeLOffsetToDefMethod_.at(classLiteralOffset);
490     }
491 
HasClassDefMethod(const uint32_t classLiteralOffset)492     bool HasClassDefMethod(const uint32_t classLiteralOffset) const
493     {
494         return classTypeLOffsetToDefMethod_.find(classLiteralOffset) != classTypeLOffsetToDefMethod_.end();
495     }
496 
SetClassTypeOffsetAndDefMethod(uint32_t classLiteralOffset,uint32_t methodOffset)497     void SetClassTypeOffsetAndDefMethod(uint32_t classLiteralOffset, uint32_t methodOffset)
498     {
499         if (classTypeLOffsetToDefMethod_.find(classLiteralOffset) == classTypeLOffsetToDefMethod_.end()) {
500             classTypeLOffsetToDefMethod_.emplace(classLiteralOffset, methodOffset);
501         }
502     }
503 
IterateFunctionTypeIDAndMethodOffset(uint32_t functionTypeId)504     uint32_t IterateFunctionTypeIDAndMethodOffset(uint32_t functionTypeId)
505     {
506         auto iter = functionTypeIdToMethodOffset_.find(functionTypeId);
507         if (iter != functionTypeIdToMethodOffset_.end()) {
508             return iter->second;
509         }
510         return 0;
511     }
512 
SetFunctionTypeIDAndMethodOffset(uint32_t functionTypeId,uint32_t methodOffset)513     void SetFunctionTypeIDAndMethodOffset(uint32_t functionTypeId, uint32_t methodOffset)
514     {
515         if (functionTypeIdToMethodOffset_.find(functionTypeId) == functionTypeIdToMethodOffset_.end()) {
516             functionTypeIdToMethodOffset_.emplace(functionTypeId, methodOffset);
517         }
518     }
HasExportIndexToRecord(const CString & recordName,uint32_t index)519     bool HasExportIndexToRecord(const CString &recordName, uint32_t index) const
520     {
521         auto iter = recordNameToExportInfo_.find(recordName);
522         if (iter != recordNameToExportInfo_.end()) {
523             return iter->second.HasExportIndex(index);
524         }
525         return false;
526     }
527 
HasStarExportToRecord(const CString & recordName)528     bool HasStarExportToRecord(const CString &recordName) const
529     {
530         auto iter = recordNameToExportInfo_.find(recordName);
531         if (iter != recordNameToExportInfo_.end()) {
532             return iter->second.HasStarExport();
533         }
534         return false;
535     }
536 
AddExportIndexToRecord(const CString & recordName,uint32_t index)537     void AddExportIndexToRecord(const CString &recordName, uint32_t index)
538     {
539         auto iter = recordNameToExportInfo_.find(recordName);
540         if (iter != recordNameToExportInfo_.end()) {
541             iter->second.AddExportIndex(index);
542         } else {
543             ExportRecordInfo info(index);
544             recordNameToExportInfo_.emplace(recordName, std::move(info));
545         }
546     }
547 
AddStarExportToRecord(const CString & recordName,const CString & starRecord)548     void AddStarExportToRecord(const CString &recordName, const CString &starRecord)
549     {
550         auto iter = recordNameToExportInfo_.find(recordName);
551         if (iter != recordNameToExportInfo_.end()) {
552             iter->second.AddStarExport(starRecord);
553         } else {
554             ExportRecordInfo info(starRecord);
555             recordNameToExportInfo_.emplace(recordName, std::move(info));
556         }
557     }
558 
GetstarExportToRecord(const CString & recordName)559     const std::unordered_set<CString> &GetstarExportToRecord(const CString &recordName) const
560     {
561         return recordNameToExportInfo_.at(recordName).GetstarExportRecord();
562     }
563 
AddImportRecordInfoToRecord(const CString & recordName,const CString & importRecord,uint32_t importIndex,uint32_t bindingIndex)564     void AddImportRecordInfoToRecord(const CString &recordName, const CString &importRecord,
565                                      uint32_t importIndex, uint32_t bindingIndex)
566     {
567         auto iter = recordToImportRecordsInfo_.find(recordName);
568         if (iter == recordToImportRecordsInfo_.end()) {
569             ImportRecordInfo info;
570             info.AddImportIdAndRecord(importIndex, bindingIndex, importRecord);
571             recordToImportRecordsInfo_.emplace(recordName, std::move(info));
572         } else {
573             iter->second.AddImportIdAndRecord(importIndex, bindingIndex, importRecord);
574         }
575     }
576 
GetImportRecordsInfos()577     const std::unordered_map<CString, ImportRecordInfo> &GetImportRecordsInfos() const
578     {
579         return recordToImportRecordsInfo_;
580     }
581 
IterateMethodOffsetToFastCallInfo(uint32_t methodOffset,bool * isValid)582     FastCallInfo IterateMethodOffsetToFastCallInfo(uint32_t methodOffset, bool *isValid)
583     {
584         auto iter = methodOffsetToFastCallInfos_.find(methodOffset);
585         if (iter != methodOffsetToFastCallInfos_.end()) {
586             *isValid = true;
587             return iter->second;
588         }
589         *isValid = false;
590         return FastCallInfo();
591     }
592 
SetMethodOffsetToFastCallInfo(uint32_t methodOffset,bool canFastCall,bool noGC)593     void SetMethodOffsetToFastCallInfo(uint32_t methodOffset, bool canFastCall, bool noGC)
594     {
595         if (methodOffsetToFastCallInfos_.find(methodOffset) == methodOffsetToFastCallInfos_.end()) {
596             methodOffsetToFastCallInfos_.emplace(methodOffset, FastCallInfo { canFastCall, noGC });
597         }
598     }
599 
ModifyMethodOffsetToCanFastCall(uint32_t methodOffset,bool canFastCall)600     void ModifyMethodOffsetToCanFastCall(uint32_t methodOffset, bool canFastCall)
601     {
602         auto iter = methodOffsetToFastCallInfos_.find(methodOffset);
603         bool isNoGC = false;
604         if (iter != methodOffsetToFastCallInfos_.end()) {
605             isNoGC = iter->second.isNoGC_;
606         }
607         methodOffsetToFastCallInfos_.erase(methodOffset);
608         if (methodOffsetToFastCallInfos_.find(methodOffset) == methodOffsetToFastCallInfos_.end()) {
609             methodOffsetToFastCallInfos_.emplace(methodOffset, FastCallInfo { canFastCall, isNoGC });
610         }
611     }
612 private:
613     std::vector<uint32_t> mainMethodIndexes_ {};
614     std::vector<CString> recordNames_ {};
615     std::vector<MethodPcInfo> methodPcInfos_ {};
616     std::unordered_map<uint32_t, MethodInfo> methodList_ {};
617     std::unordered_map<uint32_t, CString> methodOffsetToRecordName_ {};
618     std::set<uint32_t> skippedMethods_ {};
619     size_t maxMethodSize_;
620     std::unordered_map<uint32_t, uint32_t> classTypeLOffsetToDefMethod_ {};
621     std::unordered_map<uint32_t, uint32_t> functionTypeIdToMethodOffset_ {};
622     std::unordered_map<CString, ExportRecordInfo> recordNameToExportInfo_ {};
623     std::unordered_map<CString, ImportRecordInfo> recordToImportRecordsInfo_ {};
624     std::unordered_map<uint32_t, FastCallInfo> methodOffsetToFastCallInfos_ {};
625 };
626 
627 class LexEnvManager {
628 public:
629     explicit LexEnvManager(BCInfo &bcInfo);
630     ~LexEnvManager() = default;
631     NO_COPY_SEMANTIC(LexEnvManager);
632     NO_MOVE_SEMANTIC(LexEnvManager);
633 
634     void SetLexEnvElementType(uint32_t methodId, uint32_t level, uint32_t slot, const GateType &type);
635     GateType GetLexEnvElementType(uint32_t methodId, uint32_t level, uint32_t slot) const;
636 
637 private:
638     uint32_t GetTargetLexEnv(uint32_t methodId, uint32_t level) const;
639 
GetOutMethodId(uint32_t methodId)640     inline uint32_t GetOutMethodId(uint32_t methodId) const
641     {
642         return lexEnvs_[methodId].GetOutMethodId();
643     }
644 
GetLexEnvStatus(uint32_t methodId)645     inline LexicalEnvStatus GetLexEnvStatus(uint32_t methodId) const
646     {
647         return lexEnvs_[methodId].GetLexEnvStatus();
648     }
649 
HasDefaultRoot(uint32_t methodId)650     inline bool HasDefaultRoot(uint32_t methodId) const
651     {
652         return GetOutMethodId(methodId) == LexEnv::DEFAULT_ROOT;
653     }
654 
655     std::vector<LexEnv> lexEnvs_ {};
656 };
657 
658 class BytecodeInfoCollector {
659 public:
660     BytecodeInfoCollector(EcmaVM *vm, JSPandaFile *jsPandaFile, PGOProfilerDecoder &pfDecoder,
661                           size_t maxAotMethodSize, bool enableCollectLiteralInfo);
662 
663     BytecodeInfoCollector(EcmaVM *vm, JSPandaFile *jsPandaFile, JSHandle<JSFunction> &jsFunction,
664                           PGOProfilerDecoder &pfDecoder, bool enableCollectLiteralInfo);
665 
666     ~BytecodeInfoCollector();
667     NO_COPY_SEMANTIC(BytecodeInfoCollector);
668     NO_MOVE_SEMANTIC(BytecodeInfoCollector);
669 
EnableCollectLiteralInfo()670     bool EnableCollectLiteralInfo() const
671     {
672         return enableCollectLiteralInfo_;
673     }
674 
GetByteCodes()675     Bytecodes* GetByteCodes()
676     {
677         return &bytecodes_;
678     }
679 
GetBytecodeInfo()680     BCInfo& GetBytecodeInfo()
681     {
682         return bytecodeInfo_;
683     }
684 
GetBytecodeInfoPtr()685     BCInfo* GetBytecodeInfoPtr()
686     {
687         return &bytecodeInfo_;
688     }
689 
GetPGOBCInfo()690     const PGOBCInfo* GetPGOBCInfo() const
691     {
692         return &pgoBCInfo_;
693     }
694 
StoreDataToGlobalData(SnapshotGlobalData & snapshotData)695     void StoreDataToGlobalData(SnapshotGlobalData &snapshotData)
696     {
697         snapshotCPData_.StoreDataToGlobalData(snapshotData, GetSkippedMethodSet());
698     }
699 
GetSkippedMethodSet()700     const std::set<uint32_t>& GetSkippedMethodSet() const
701     {
702         return bytecodeInfo_.GetSkippedMethodSet();
703     }
704 
IsSkippedMethod(uint32_t methodOffset)705     bool IsSkippedMethod(uint32_t methodOffset) const
706     {
707         return bytecodeInfo_.IsSkippedMethod(methodOffset);
708     }
709 
FilterMethod(const MethodLiteral * methodLiteral,const MethodPcInfo & methodPCInfo)710     bool FilterMethod(const MethodLiteral *methodLiteral, const MethodPcInfo &methodPCInfo) const
711     {
712         auto recordName = MethodLiteral::GetRecordName(jsPandaFile_, methodLiteral->GetMethodId());
713         bool methodSizeIsIllegal = methodPCInfo.methodsSize > bytecodeInfo_.GetMaxMethodSize();
714         bool methodFilteredByPGO = !pfDecoder_.Match(jsPandaFile_, recordName, methodLiteral->GetMethodId());
715         if (methodSizeIsIllegal || methodFilteredByPGO) {
716             return true;
717         }
718         return false;
719     }
720 
GetJSPandaFile()721     const JSPandaFile *GetJSPandaFile() const
722     {
723         return jsPandaFile_;
724     }
725 
GetVM()726     EcmaVM *GetVM() const
727     {
728         return vm_;
729     }
730 
GetEnvManager()731     LexEnvManager* GetEnvManager() const
732     {
733         return envManager_;
734     }
735 
736     template <class Callback>
IterateAllMethods(const Callback & cb)737     void IterateAllMethods(const Callback &cb)
738     {
739         auto &methodList = bytecodeInfo_.GetMethodList();
740         for (const auto &method : methodList) {
741             uint32_t methodOffset = method.first;
742             cb(methodOffset);
743         }
744     }
745 
746 private:
747     void ProcessEnvs();
748 
GetMethodInfoID()749     inline size_t GetMethodInfoID()
750     {
751         return methodInfoIndex_++;
752     }
753 
GetClassName(const EntityId entityId)754     inline std::string GetClassName(const EntityId entityId)
755     {
756         std::string className(MethodLiteral::GetMethodName(jsPandaFile_, entityId));
757         if (LIKELY(className.find('#') != std::string::npos)) {
758             size_t poiIndex = className.find_last_of('#');
759             className = className.substr(poiIndex + 1);
760         }
761         return className;
762     }
763 
764     const CString GetEntryFunName(const std::string_view &entryPoint) const;
765     void ProcessClasses();
766     void ProcessMethod(JSHandle<JSFunction> &jsFunction);
767     void RearrangeInnerMethods();
768     void CollectMethodPcsFromBC(const uint32_t insSz, const uint8_t *insArr,
769         MethodLiteral *method, std::vector<std::string> &classNameVec, const CString &recordName,
770         uint32_t methodOffset, std::vector<panda_file::File::EntityId> &classConstructIndexes);
771     void SetMethodPcInfoIndex(uint32_t methodOffset, const std::pair<size_t, uint32_t> &processedMethodInfo);
772     void CollectInnerMethods(const MethodLiteral *method, uint32_t innerMethodOffset, bool isConstructor = false);
773     void CollectInnerMethods(uint32_t methodId, uint32_t innerMethodOffset, bool isConstructor = false);
774     void CollectInnerMethodsFromLiteral(const MethodLiteral *method, uint64_t index);
775     void CollectInnerFuncType(const MethodLiteral *method, uint32_t innerMethodOffset, int32_t bcIndex);
776     void NewLexEnvWithSize(const MethodLiteral *method, uint64_t numOfLexVars);
777     void CollectInnerMethodsFromNewLiteral(const MethodLiteral *method, panda_file::File::EntityId literalId);
778     void CollectMethodInfoFromBC(const BytecodeInstruction &bcIns, const MethodLiteral *method,
779                                  std::vector<std::string> &classNameVec, int32_t bcIndex,
780                                  std::vector<panda_file::File::EntityId> &classConstructIndexes,
781                                  bool *canFastCall);
782     void CollectModuleInfoFromBC(const BytecodeInstruction &bcIns, const MethodLiteral *method,
783                                  const CString &recordName);
784     void IterateLiteral(const MethodLiteral *method, std::vector<uint32_t> &classOffsetVector);
785     void StoreClassTypeOffset(const uint32_t typeOffset, std::vector<uint32_t> &classOffsetVector);
786     void CollectClassLiteralInfo(const MethodLiteral *method, const std::vector<std::string> &classNameVec);
787     void CollectFunctionTypeId(panda_file::File::EntityId fieldId);
788     void CollectImportIndexs(uint32_t methodOffset, uint32_t index);
789     void CollectExportIndexs(const CString &recordName, uint32_t index);
790     bool CheckExportNameAndClassType(const CString &recordName, const JSHandle<EcmaString> &exportStr);
791     void CollectRecordReferenceREL();
792     void CollectRecordImportInfo(const CString &recordName);
793     void CollectRecordExportInfo(const CString &recordName);
794     void MarkMethodNamespace(const uint32_t methodOffset);
795 
796     EcmaVM *vm_;
797     JSPandaFile *jsPandaFile_ {nullptr};
798     BCInfo bytecodeInfo_;
799     PGOProfilerDecoder &pfDecoder_;
800     PGOBCInfo pgoBCInfo_ {};
801     SnapshotConstantPoolData snapshotCPData_;
802     size_t methodInfoIndex_ {0};
803     bool enableCollectLiteralInfo_ {false};
804     std::set<int32_t> classDefBCIndexes_ {};
805     LexEnvManager* envManager_ {nullptr};
806     Bytecodes bytecodes_;
807 };
808 }  // namespace panda::ecmascript::kungfu
809 #endif  // ECMASCRIPT_COMPILER_BYTECODE_INFO_COLLECTOR_H
810