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