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