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