1 /* 2 * Copyright (c) 2022-2024 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/bytecodes.h" 21 #include "ecmascript/compiler/pgo_bc_info.h" 22 #include "ecmascript/jspandafile/js_pandafile.h" 23 #include "ecmascript/jspandafile/method_literal.h" 24 #include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" 25 #include "ecmascript/compiler/compilation_env.h" 26 #include "libpandafile/bytecode_instruction-inl.h" 27 28 namespace panda::ecmascript::kungfu { 29 using PGOProfilerDecoder = pgo::PGOProfilerDecoder; 30 31 // each method in the abc file corresponds to one MethodInfo and 32 // methods with the same instructions share one common MethodPcInfo 33 struct MethodPcInfo { 34 std::vector<const uint8_t*> pcOffsets {}; 35 uint32_t methodsSize {0}; 36 }; 37 38 class MethodInfo { 39 public: MethodInfo(uint32_t methodInfoIndex, uint32_t methodPcInfoIndex, std::shared_ptr<CString> recordNamePtr)40 MethodInfo(uint32_t methodInfoIndex, uint32_t methodPcInfoIndex, std::shared_ptr<CString> recordNamePtr) 41 : methodInfoIndex_(methodInfoIndex), methodPcInfoIndex_(methodPcInfoIndex), recordNamePtr_(recordNamePtr) {} 42 43 ~MethodInfo() = default; 44 45 static constexpr uint32_t DEFAULT_OUTMETHOD_OFFSET = 0; 46 static constexpr uint32_t DEFAULT_ROOT = std::numeric_limits<uint32_t>::max(); 47 GetMethodPcInfoIndex() const48 inline uint32_t GetMethodPcInfoIndex() const 49 { 50 return methodPcInfoIndex_; 51 } 52 SetMethodPcInfoIndex(uint32_t methodPcInfoIndex)53 inline void SetMethodPcInfoIndex(uint32_t methodPcInfoIndex) 54 { 55 methodPcInfoIndex_ = methodPcInfoIndex; 56 } 57 GetMethodInfoIndex() const58 inline uint32_t GetMethodInfoIndex() const 59 { 60 return methodInfoIndex_; 61 } 62 SetMethodInfoIndex(uint32_t methodInfoIndex)63 inline void SetMethodInfoIndex(uint32_t methodInfoIndex) 64 { 65 methodInfoIndex_ = methodInfoIndex; 66 } 67 SetRecordNamePtr(const std::shared_ptr<CString> recordNamePtr)68 inline void SetRecordNamePtr(const std::shared_ptr<CString> recordNamePtr) 69 { 70 recordNamePtr_ = recordNamePtr; 71 } 72 GetRecordNamePtr() const73 inline const std::shared_ptr<CString> GetRecordNamePtr() const 74 { 75 return recordNamePtr_; 76 } 77 GetRecordName() const78 inline const CString &GetRecordName() const 79 { 80 return *recordNamePtr_; 81 } 82 IsPGO() const83 bool IsPGO() const 84 { 85 return CompileStateBit::PGOBit::Decode(compileState_.value_); 86 } 87 SetIsPGO(bool pgoMark)88 void SetIsPGO(bool pgoMark) 89 { 90 CompileStateBit::PGOBit::Set<uint8_t>(pgoMark, &compileState_.value_); 91 } 92 IsCompiled() const93 bool IsCompiled() const 94 { 95 return CompileStateBit::CompiledBit::Decode(compileState_.value_); 96 } 97 SetIsCompiled(bool isCompiled)98 void SetIsCompiled(bool isCompiled) 99 { 100 CompileStateBit::CompiledBit::Set<uint8_t>(isCompiled, &compileState_.value_); 101 } 102 103 private: 104 class CompileStateBit { 105 public: CompileStateBit(uint8_t value)106 explicit CompileStateBit(uint8_t value) : value_(value) {} 107 CompileStateBit() = default; 108 ~CompileStateBit() = default; 109 DEFAULT_COPY_SEMANTIC(CompileStateBit); 110 DEFAULT_MOVE_SEMANTIC(CompileStateBit); 111 112 static constexpr size_t BOOL_FLAG_BIT_LENGTH = 1; 113 using PGOBit = panda::BitField<bool, 0, BOOL_FLAG_BIT_LENGTH>; 114 using CompiledBit = PGOBit::NextField<bool, BOOL_FLAG_BIT_LENGTH>; 115 116 private: 117 uint8_t value_ {0}; 118 friend class MethodInfo; 119 }; 120 // used to record the index of the current MethodInfo to speed up the lookup of lexEnv 121 uint32_t methodInfoIndex_ { 0 }; 122 // used to obtain MethodPcInfo from the vector methodPcInfos of struct BCInfo 123 uint32_t methodPcInfoIndex_ { 0 }; 124 std::shared_ptr<CString> recordNamePtr_ {nullptr}; 125 CompileStateBit compileState_ { 0 }; 126 }; 127 128 struct FastCallInfo { 129 bool canFastCall_ {false}; 130 bool isNoGC_ {false}; 131 }; 132 133 class BCInfo { 134 public: BCInfo(size_t maxAotMethodSize)135 explicit BCInfo(size_t maxAotMethodSize) 136 : maxMethodSize_(maxAotMethodSize) 137 { 138 } 139 GetMainMethodIndexes()140 std::vector<uint32_t>& GetMainMethodIndexes() 141 { 142 return mainMethodIndexes_; 143 } 144 GetRecordNamePtrs()145 std::vector<std::shared_ptr<CString>>& GetRecordNamePtrs() 146 { 147 return recordNamePtrs_; 148 } 149 GetRecordNameWithIndex(uint32_t index) const150 const CString &GetRecordNameWithIndex(uint32_t index) const 151 { 152 return *recordNamePtrs_[index]; 153 } 154 GetMethodPcInfos()155 std::vector<MethodPcInfo>& GetMethodPcInfos() 156 { 157 return methodPcInfos_; 158 } 159 GetMethodList()160 std::unordered_map<uint32_t, MethodInfo>& GetMethodList() 161 { 162 return methodList_; 163 } 164 GetMaxMethodSize() const165 size_t GetMaxMethodSize() const 166 { 167 return maxMethodSize_; 168 } 169 IsSkippedMethod(uint32_t methodOffset) const170 bool IsSkippedMethod(uint32_t methodOffset) const 171 { 172 if (skippedMethods_.find(methodOffset) == skippedMethods_.end()) { 173 return false; 174 } 175 return true; 176 } 177 GetSkippedMethodSet() const178 const std::set<uint32_t>& GetSkippedMethodSet() const 179 { 180 return skippedMethods_; 181 } 182 AddSkippedMethod(uint32_t methodOffset)183 void AddSkippedMethod(uint32_t methodOffset) 184 { 185 skippedMethods_.insert(methodOffset); 186 } 187 EraseSkippedMethod(uint32_t methodOffset)188 void EraseSkippedMethod(uint32_t methodOffset) 189 { 190 if (skippedMethods_.find(methodOffset) != skippedMethods_.end()) { 191 skippedMethods_.erase(methodOffset); 192 } 193 } 194 FindMethodOffsetToRecordName(uint32_t methodOffset)195 bool FindMethodOffsetToRecordName(uint32_t methodOffset) 196 { 197 return methodOffsetToRecordName_.find(methodOffset) != methodOffsetToRecordName_.end(); 198 } 199 AddMethodOffsetToRecordName(uint32_t methodOffset, CString recordName)200 void AddMethodOffsetToRecordName(uint32_t methodOffset, CString recordName) 201 { 202 methodOffsetToRecordName_.emplace(methodOffset, recordName); 203 } 204 GetSkippedMethodSize() const205 size_t GetSkippedMethodSize() const 206 { 207 return skippedMethods_.size(); 208 } 209 GetDefineMethod(const uint32_t classLiteralOffset) const210 uint32_t GetDefineMethod(const uint32_t classLiteralOffset) const 211 { 212 return classTypeLOffsetToDefMethod_.at(classLiteralOffset); 213 } 214 HasClassDefMethod(const uint32_t classLiteralOffset) const215 bool HasClassDefMethod(const uint32_t classLiteralOffset) const 216 { 217 return classTypeLOffsetToDefMethod_.find(classLiteralOffset) != classTypeLOffsetToDefMethod_.end(); 218 } 219 SetClassTypeOffsetAndDefMethod(uint32_t classLiteralOffset, uint32_t methodOffset)220 void SetClassTypeOffsetAndDefMethod(uint32_t classLiteralOffset, uint32_t methodOffset) 221 { 222 if (classTypeLOffsetToDefMethod_.find(classLiteralOffset) == classTypeLOffsetToDefMethod_.end()) { 223 classTypeLOffsetToDefMethod_.emplace(classLiteralOffset, methodOffset); 224 } 225 } 226 IterateFunctionTypeIDAndMethodOffset(uint32_t functionTypeId)227 uint32_t IterateFunctionTypeIDAndMethodOffset(uint32_t functionTypeId) 228 { 229 auto iter = functionTypeIdToMethodOffset_.find(functionTypeId); 230 if (iter != functionTypeIdToMethodOffset_.end()) { 231 return iter->second; 232 } 233 return 0; 234 } 235 SetFunctionTypeIDAndMethodOffset(uint32_t functionTypeId, uint32_t methodOffset)236 void SetFunctionTypeIDAndMethodOffset(uint32_t functionTypeId, uint32_t methodOffset) 237 { 238 if (functionTypeIdToMethodOffset_.find(functionTypeId) == functionTypeIdToMethodOffset_.end()) { 239 functionTypeIdToMethodOffset_.emplace(functionTypeId, methodOffset); 240 } 241 } 242 IterateMethodOffsetToFastCallInfo(uint32_t methodOffset, bool *isValid)243 FastCallInfo IterateMethodOffsetToFastCallInfo(uint32_t methodOffset, bool *isValid) 244 { 245 auto iter = methodOffsetToFastCallInfos_.find(methodOffset); 246 if (iter != methodOffsetToFastCallInfos_.end()) { 247 *isValid = true; 248 return iter->second; 249 } 250 *isValid = false; 251 return FastCallInfo(); 252 } 253 SetMethodOffsetToFastCallInfo(uint32_t methodOffset, bool canFastCall, bool noGC)254 void SetMethodOffsetToFastCallInfo(uint32_t methodOffset, bool canFastCall, bool noGC) 255 { 256 if (methodOffsetToFastCallInfos_.find(methodOffset) == methodOffsetToFastCallInfos_.end()) { 257 methodOffsetToFastCallInfos_.emplace(methodOffset, FastCallInfo { canFastCall, noGC }); 258 } 259 } 260 ModifyMethodOffsetToCanFastCall(uint32_t methodOffset, bool canFastCall)261 void ModifyMethodOffsetToCanFastCall(uint32_t methodOffset, bool canFastCall) 262 { 263 auto iter = methodOffsetToFastCallInfos_.find(methodOffset); 264 bool isNoGC = false; 265 if (iter != methodOffsetToFastCallInfos_.end()) { 266 isNoGC = iter->second.isNoGC_; 267 } 268 methodOffsetToFastCallInfos_.erase(methodOffset); 269 if (methodOffsetToFastCallInfos_.find(methodOffset) == methodOffsetToFastCallInfos_.end()) { 270 methodOffsetToFastCallInfos_.emplace(methodOffset, FastCallInfo { canFastCall, isNoGC }); 271 } 272 } 273 private: 274 std::vector<uint32_t> mainMethodIndexes_ {}; 275 std::vector<std::shared_ptr<CString>> recordNamePtrs_ {}; 276 std::vector<MethodPcInfo> methodPcInfos_ {}; 277 std::unordered_map<uint32_t, MethodInfo> methodList_ {}; 278 std::unordered_map<uint32_t, CString> methodOffsetToRecordName_ {}; 279 std::set<uint32_t> skippedMethods_ {}; 280 size_t maxMethodSize_; 281 std::unordered_map<uint32_t, uint32_t> classTypeLOffsetToDefMethod_ {}; 282 std::unordered_map<uint32_t, uint32_t> functionTypeIdToMethodOffset_ {}; 283 std::unordered_map<uint32_t, FastCallInfo> methodOffsetToFastCallInfos_ {}; 284 }; 285 286 class BytecodeInfoCollector { 287 public: 288 BytecodeInfoCollector(CompilationEnv *env, JSPandaFile *jsPandaFile, PGOProfilerDecoder &pfDecoder, 289 size_t maxAotMethodSize); 290 291 BytecodeInfoCollector(CompilationEnv *env, JSPandaFile *jsPandaFile, 292 PGOProfilerDecoder &pfDecoder); 293 294 ~BytecodeInfoCollector() = default; 295 NO_COPY_SEMANTIC(BytecodeInfoCollector); 296 NO_MOVE_SEMANTIC(BytecodeInfoCollector); 297 GetByteCodes()298 Bytecodes* GetByteCodes() 299 { 300 return &bytecodes_; 301 } 302 GetBytecodeInfo()303 BCInfo& GetBytecodeInfo() 304 { 305 return bytecodeInfo_; 306 } 307 GetBytecodeInfoPtr()308 BCInfo* GetBytecodeInfoPtr() 309 { 310 return &bytecodeInfo_; 311 } 312 GetPGOBCInfo() const313 const PGOBCInfo* GetPGOBCInfo() const 314 { 315 return &pgoBCInfo_; 316 } 317 StoreDataToGlobalData(SnapshotGlobalData &snapshotData)318 void StoreDataToGlobalData(SnapshotGlobalData &snapshotData) 319 { 320 snapshotCPData_->StoreDataToGlobalData(snapshotData, GetSkippedMethodSet()); 321 } 322 GetSkippedMethodSet() const323 const std::set<uint32_t>& GetSkippedMethodSet() const 324 { 325 return bytecodeInfo_.GetSkippedMethodSet(); 326 } 327 IsSkippedMethod(uint32_t methodOffset) const328 bool IsSkippedMethod(uint32_t methodOffset) const 329 { 330 return bytecodeInfo_.IsSkippedMethod(methodOffset); 331 } 332 FilterMethod(const MethodLiteral *methodLiteral, const MethodPcInfo &methodPCInfo) const333 bool FilterMethod(const MethodLiteral *methodLiteral, const MethodPcInfo &methodPCInfo) const 334 { 335 auto recordName = MethodLiteral::GetRecordName(jsPandaFile_, methodLiteral->GetMethodId()); 336 bool methodSizeIsIllegal = methodPCInfo.methodsSize > bytecodeInfo_.GetMaxMethodSize(); 337 bool methodFilteredByPGO = !pfDecoder_.Match(jsPandaFile_, recordName, methodLiteral->GetMethodId()); 338 if (methodSizeIsIllegal || methodFilteredByPGO) { 339 return true; 340 } 341 return false; 342 } 343 GetJSPandaFile() const344 const JSPandaFile *GetJSPandaFile() const 345 { 346 return jsPandaFile_; 347 } 348 GetCompilationEnv() const349 CompilationEnv *GetCompilationEnv() const 350 { 351 return compilationEnv_; 352 } 353 354 template <class Callback> IterateAllMethods(const Callback &cb)355 void IterateAllMethods(const Callback &cb) 356 { 357 auto &methodList = bytecodeInfo_.GetMethodList(); 358 for (const auto &method : methodList) { 359 uint32_t methodOffset = method.first; 360 cb(methodOffset); 361 } 362 } 363 364 void ProcessMethod(MethodLiteral *methodLiteral); 365 private: GetNewMethodInfoID()366 inline size_t GetNewMethodInfoID() 367 { 368 return methodInfoCounts_++; 369 } 370 371 void ProcessClasses(); 372 void ProcessCurrMethod(); 373 void CollectMethodPcsFromBC(const uint32_t insSz, const uint8_t *insArr, MethodLiteral *method, 374 uint32_t methodOffset, const std::shared_ptr<CString> recordNamePtr); 375 static bool IsVRegUsed(const BytecodeInstruction &inst, const BytecodeMetaData &metaData, uint32_t idx); 376 void SetMethodPcInfoIndex(uint32_t methodOffset, const std::pair<size_t, uint32_t> &processedMethodInfo, 377 const std::shared_ptr<CString> recordNamePtr); 378 void CollectMethods(const MethodLiteral *method, const std::shared_ptr<CString> recordNamePtr); 379 void CollectMethods(uint32_t methodId, const std::shared_ptr<CString> recordNamePtr); 380 void CollectInnerMethodsFromLiteral(uint64_t index, const std::shared_ptr<CString> recordNamePtr); 381 void CollectInnerMethodsFromNewLiteral(panda_file::File::EntityId literalId, 382 const std::shared_ptr<CString> recordNamePtr); 383 void CollectMethodInfoFromBC(const BytecodeInstruction &bcIns, const MethodLiteral *method, int32_t bcIndex, 384 const std::shared_ptr<CString> recordNamePtr, bool *canFastCall, 385 bool *canTypedCall); 386 void IterateLiteral(const MethodLiteral *method, std::vector<uint32_t> &classOffsetVector); 387 void StoreClassTypeOffset(const uint32_t typeOffset, std::vector<uint32_t> &classOffsetVector); 388 void CollectClassLiteralInfo(const MethodLiteral *method, const std::vector<std::string> &classNameVec); 389 390 CompilationEnv *compilationEnv_ {nullptr}; 391 JSPandaFile *jsPandaFile_ {nullptr}; 392 BCInfo bytecodeInfo_; 393 PGOProfilerDecoder &pfDecoder_; 394 PGOBCInfo pgoBCInfo_ {}; 395 std::unique_ptr<SnapshotConstantPoolData> snapshotCPData_; 396 size_t methodInfoCounts_ {0}; 397 std::set<int32_t> classDefBCIndexes_ {}; 398 Bytecodes bytecodes_; 399 std::set<uint32_t> processedMethod_; 400 }; 401 } // namespace panda::ecmascript::kungfu 402 #endif // ECMASCRIPT_COMPILER_BYTECODE_INFO_COLLECTOR_H 403