1 /* 2 * Copyright (c) 2021-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_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H 17 #define ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H 18 19 #include <algorithm> 20 #include <tuple> 21 #include <utility> 22 #include <vector> 23 24 #include "ecmascript/compiler/argument_accessor.h" 25 #include "ecmascript/compiler/bytecode_info_collector.h" 26 #include "ecmascript/compiler/bytecodes.h" 27 #include "ecmascript/compiler/circuit.h" 28 #include "ecmascript/compiler/ecma_opcode_des.h" 29 #include "ecmascript/compiler/frame_states.h" 30 #include "ecmascript/compiler/pgo_type/pgo_type_recorder.h" 31 #include "ecmascript/jit/jit_profiler.h" 32 #include "ecmascript/jspandafile/js_pandafile.h" 33 #include "ecmascript/jspandafile/method_literal.h" 34 #include "libpandafile/index_accessor.h" 35 36 namespace panda::ecmascript::kungfu { 37 struct ExceptionItem { 38 uint8_t* startPc; 39 uint8_t* endPc; 40 std::vector<uint8_t*> catches; 41 ExceptionItemExceptionItem42 ExceptionItem(uint8_t* startPc, uint8_t* endPc, std::vector<uint8_t*> catches) 43 : startPc(startPc), endPc(endPc), catches(catches) {} 44 }; 45 46 using ExceptionInfo = std::vector<ExceptionItem>; 47 48 class RegionItem { 49 public: 50 static constexpr uint32_t INVALID_BC_INDEX = static_cast<uint32_t>(-1); 51 bool operator<(const RegionItem &rhs) const 52 { 53 return this->startBcIndex_ < rhs.startBcIndex_; 54 } 55 56 bool operator>(const RegionItem &rhs) const 57 { 58 return this->startBcIndex_ > rhs.startBcIndex_; 59 } 60 61 bool operator==(const RegionItem &rhs) const 62 { 63 return this->startBcIndex_ == rhs.startBcIndex_; 64 } 65 RegionItem(uint32_t startBcIndex,bool isHeadBlock)66 RegionItem(uint32_t startBcIndex, bool isHeadBlock) 67 : startBcIndex_(startBcIndex), isHeadBlock_(isHeadBlock) {} 68 GetStartBcIndex()69 uint32_t GetStartBcIndex() const 70 { 71 return startBcIndex_; 72 } 73 IsHeadBlock()74 uint32_t IsHeadBlock() const 75 { 76 return isHeadBlock_; 77 } 78 private: 79 uint32_t startBcIndex_ { INVALID_BC_INDEX }; 80 bool isHeadBlock_ { false }; 81 friend class RegionsInfo; 82 }; 83 84 struct BytecodeSplitItem { BytecodeSplitItemBytecodeSplitItem85 BytecodeSplitItem(uint32_t start, uint32_t pred) 86 : startBcIndex(start), predBcIndex(pred) {} 87 uint32_t startBcIndex { RegionItem::INVALID_BC_INDEX }; 88 uint32_t predBcIndex { RegionItem::INVALID_BC_INDEX }; 89 }; 90 91 class RegionsInfo { 92 public: InsertJump(uint32_t bcIndex,uint32_t predBcIndex,bool isJumpImm)93 void InsertJump(uint32_t bcIndex, uint32_t predBcIndex, bool isJumpImm) 94 { 95 InsertBlockItem(bcIndex, false); 96 auto fallThrogth = bcIndex - 1; // 1: fall through 97 // isJumpImm will not generate fall through 98 if (isJumpImm || fallThrogth != predBcIndex) { 99 InsertSplitItem(bcIndex, predBcIndex); 100 } 101 } 102 InsertHead(uint32_t bcIndex)103 void InsertHead(uint32_t bcIndex) 104 { 105 InsertBlockItem(bcIndex, true); 106 } 107 InsertSplit(uint32_t bcIndex)108 void InsertSplit(uint32_t bcIndex) 109 { 110 InsertBlockItem(bcIndex, false); 111 } 112 FindBBIndexByBcIndex(uint32_t bcIndex)113 size_t FindBBIndexByBcIndex(uint32_t bcIndex) const 114 { 115 auto findFunc = [] (uint32_t value, const RegionItem &item) { 116 return value < item.startBcIndex_; 117 }; 118 const auto &it = std::upper_bound(blockItems_.begin(), 119 blockItems_.end(), bcIndex, findFunc); 120 if (it == blockItems_.end()) { 121 return blockItems_.size(); 122 } 123 // blockItems_[0]'s value is 0, bcIndex must be: bcIndex > blockItems_.begin() 124 return std::distance(blockItems_.begin(), it); 125 } 126 GetSplitItems()127 const std::vector<BytecodeSplitItem> &GetSplitItems() const 128 { 129 return splitItems_; 130 } 131 GetBlockItems()132 const std::set<RegionItem> &GetBlockItems() const 133 { 134 return blockItems_; 135 } 136 private: InsertBlockItem(uint32_t bcIndex,bool isHeadBlock)137 void InsertBlockItem(uint32_t bcIndex, bool isHeadBlock) 138 { 139 auto result = blockItems_.insert(RegionItem { bcIndex, isHeadBlock }); 140 if (!result.second && isHeadBlock) { 141 blockItems_.erase(result.first); 142 blockItems_.insert(RegionItem { bcIndex, isHeadBlock }); 143 } 144 } 145 InsertSplitItem(uint32_t bcIndex,uint32_t predBcIndex)146 void InsertSplitItem(uint32_t bcIndex, uint32_t predBcIndex) 147 { 148 splitItems_.emplace_back(BytecodeSplitItem { bcIndex, predBcIndex }); 149 } 150 std::set<RegionItem> blockItems_ {}; 151 std::vector<BytecodeSplitItem> splitItems_ {}; 152 }; 153 154 struct BytecodeRegion { 155 size_t id {0}; 156 uint32_t start {0}; 157 uint32_t end {0}; 158 ChunkVector<BytecodeRegion *> preds; // List of predessesor blocks 159 ChunkVector<BytecodeRegion *> succs; // List of successors blocks 160 ChunkVector<BytecodeRegion *> trys; // List of trys blocks 161 ChunkVector<BytecodeRegion *> catches; // List of catches blocks 162 ChunkSet<size_t> loopBacks; 163 size_t numOfLoopBack {0}; 164 size_t numOfStatePreds {0}; 165 size_t loopNumber {0}; 166 size_t loopIndex {0}; 167 ChunkVector<std::tuple<size_t, size_t, bool>> expandedPreds; 168 GateRef dependCache {Circuit::NullGate()}; 169 BytecodeIterator bytecodeIterator_ {}; 170 bool IsEmptyCatchBB {false}; // For empty catch BB BytecodeRegionBytecodeRegion171 BytecodeRegion(Chunk* chunk) : preds(chunk), succs(chunk), 172 trys(chunk), catches(chunk), loopBacks(chunk), expandedPreds(chunk) 173 { 174 } 175 GetBytecodeIteratorBytecodeRegion176 BytecodeIterator &GetBytecodeIterator() 177 { 178 return bytecodeIterator_; 179 } 180 181 bool operator <(const BytecodeRegion &target) const 182 { 183 return id < target.id; 184 } 185 SortCatchesBytecodeRegion186 void SortCatches() 187 { 188 if (catches.size() > 1) { 189 std::sort(catches.begin(), catches.end(), [](BytecodeRegion *first, BytecodeRegion *second) { 190 return first->start < second->start; 191 }); 192 } 193 } 194 EraseThisBlockBytecodeRegion195 void EraseThisBlock(ChunkVector<BytecodeRegion *> &blocks) 196 { 197 auto it = std::find(blocks.begin(), blocks.end(), this); 198 if (it != blocks.end()) { 199 blocks.erase(it); 200 } 201 } 202 IsEmptryBlockBytecodeRegion203 bool IsEmptryBlock() const 204 { 205 return end == static_cast<uint32_t>(BytecodeIterator::INVALID_INDEX); 206 } 207 IsLoopBackBytecodeRegion208 bool IsLoopBack(const BytecodeRegion &bb) const 209 { 210 return loopBacks.find(bb.id) != loopBacks.end(); 211 } 212 }; 213 214 using BytecodeGraph = ChunkVector<BytecodeRegion*>; 215 216 class BytecodeCircuitBuilder { 217 public: 218 BytecodeCircuitBuilder(const JSPandaFile *jsPandaFile, 219 const MethodLiteral *methodLiteral, 220 const MethodPcInfo &methodPCInfo, 221 Circuit *circuit, 222 Bytecodes *bytecodes, 223 bool enableLog, 224 bool enableTypeLowering, 225 std::string name, 226 const CString &recordName, 227 PGOProfilerDecoder *decoder, 228 bool isInline, 229 JITProfiler* jitProfiler = nullptr) circuit_(circuit)230 : circuit_(circuit), graph_(circuit->chunk()), file_(jsPandaFile), 231 method_(methodLiteral), gateAcc_(circuit), argAcc_(circuit, method_), 232 pgoTypeRecorder_(*decoder, jsPandaFile, method_->GetMethodId().GetOffset()), 233 enableLog_(enableLog), enableTypeLowering_(enableTypeLowering), 234 pcOffsets_(methodPCInfo.pcOffsets), 235 frameStateBuilder_(this, circuit, methodLiteral), 236 methodName_(name), recordName_(recordName), 237 bytecodes_(bytecodes), 238 loopHeaderGates_(circuit->chunk()), 239 preFrameState_(circuit_->GetRoot()), 240 preFrameArgs_(circuit_->GetRoot()), 241 isInline_(isInline), 242 methodId_(method_->GetMethodId().GetOffset()) 243 { 244 if (jitProfiler != nullptr) { 245 pgoTypeRecorder_.InitMap(jitProfiler); 246 } 247 } 248 ~BytecodeCircuitBuilder() = default; 249 NO_COPY_SEMANTIC(BytecodeCircuitBuilder); 250 NO_MOVE_SEMANTIC(BytecodeCircuitBuilder); 251 void PUBLIC_API BytecodeToCircuit(); 252 void CollectRegionInfo(uint32_t bcIndex); 253 GetCircuit()254 [[nodiscard]] Circuit* GetCircuit() const 255 { 256 return circuit_; 257 } 258 GetGateByBcIndex(uint32_t bcIndex)259 GateRef GetGateByBcIndex(uint32_t bcIndex) const 260 { 261 ASSERT(bcIndex < byteCodeToJSGates_.size()); 262 if (byteCodeToJSGates_[bcIndex].size() > 0) { 263 ASSERT(byteCodeToJSGates_[bcIndex].size() == 1); 264 return byteCodeToJSGates_[bcIndex].at(0); 265 } 266 return Circuit::NullGate(); 267 } 268 GetGatesByBcIndex(uint32_t bcIndex)269 const std::vector<GateRef>& GetGatesByBcIndex(uint32_t bcIndex) const 270 { 271 ASSERT(bcIndex < byteCodeToJSGates_.size()); 272 return byteCodeToJSGates_[bcIndex]; 273 } 274 GetBcIndexByGate(GateRef gate)275 uint32_t GetBcIndexByGate(GateRef gate) const 276 { 277 return jsGatesToByteCode_.at(gate); 278 } 279 IsBcIndexByGate(GateRef gate)280 bool IsBcIndexByGate(GateRef gate) const 281 { 282 if (jsGatesToByteCode_.find(gate) == jsGatesToByteCode_.end()) { 283 return false; 284 } 285 return true; 286 } 287 SetOsrOffset(int32_t offset)288 void SetOsrOffset(int32_t offset) 289 { 290 osrOffset_ = offset; 291 } 292 NeedCheckSafePointAndStackOver()293 bool NeedCheckSafePointAndStackOver() const 294 { 295 return !isInline_ && !method_->IsNoGC(); 296 } 297 UpdateBcIndexGate(GateRef gate,uint32_t bcIndex)298 void UpdateBcIndexGate(GateRef gate, uint32_t bcIndex) 299 { 300 ASSERT(gateAcc_.GetOpCode(gate) == OpCode::JS_BYTECODE); 301 ASSERT(bcIndex < byteCodeToJSGates_.size()); 302 byteCodeToJSGates_[bcIndex].emplace_back(gate); 303 jsGatesToByteCode_[gate] = bcIndex; 304 } 305 GetMethod()306 [[nodiscard]] const MethodLiteral* GetMethod() const 307 { 308 return method_; 309 } 310 GetJSPandaFile()311 [[nodiscard]] const JSPandaFile *GetJSPandaFile() const 312 { 313 return file_; 314 } 315 GetMethodName()316 const std::string& GetMethodName() const 317 { 318 return methodName_; 319 } 320 IsLogEnabled()321 bool IsLogEnabled() const 322 { 323 return enableLog_; 324 } 325 IsTypeLoweringEnabled()326 bool IsTypeLoweringEnabled() const 327 { 328 return enableTypeLowering_; 329 } 330 GetAsyncRelatedGates()331 [[nodiscard]] const std::vector<GateRef>& GetAsyncRelatedGates() const 332 { 333 return suspendAndResumeGates_; 334 } 335 UpdateAsyncRelatedGate(GateRef gate)336 void UpdateAsyncRelatedGate(GateRef gate) 337 { 338 suspendAndResumeGates_.emplace_back(gate); 339 }; 340 341 template <class Callback> EnumerateBlock(BytecodeRegion & bb,const Callback & cb)342 void EnumerateBlock(BytecodeRegion &bb, const Callback &cb) 343 { 344 auto &iterator = bb.GetBytecodeIterator(); 345 iterator.GotoStart(); 346 while (!iterator.Done()) { 347 auto &bytecodeInfo = iterator.GetBytecodeInfo(); 348 bool ret = cb(bytecodeInfo); 349 if (!ret) { 350 break; 351 } 352 ++iterator; 353 } 354 } 355 GetBasicBlockById(size_t id)356 BytecodeRegion &GetBasicBlockById(size_t id) 357 { 358 ASSERT(id < graph_.size()); 359 return RegionAt(id); 360 } 361 AddBasicBlock(BytecodeRegion * region)362 void AddBasicBlock(BytecodeRegion* region) 363 { 364 graph_.emplace_back(region); 365 } 366 GetBasicBlockCount()367 size_t GetBasicBlockCount() const 368 { 369 return graph_.size(); 370 } 371 GetPcOffset(const uint8_t * pc)372 size_t GetPcOffset(const uint8_t *pc) const 373 { 374 return static_cast<size_t>(pc - method_->GetBytecodeArray()); 375 } 376 GetPcOffset(uint32_t bcIndex)377 size_t GetPcOffset(uint32_t bcIndex) const 378 { 379 const uint8_t* pc = GetPCByIndex(bcIndex); 380 return GetPcOffset(pc); 381 } 382 GetPcOffsetByGate(GateRef gate)383 size_t GetPcOffsetByGate(GateRef gate) const 384 { 385 return GetPcOffset(jsGatesToByteCode_.at(gate)); 386 } 387 GetElementsKindsForUser(GateRef gate)388 std::vector<ElementsKind> GetElementsKindsForUser(GateRef gate) const 389 { 390 return pgoTypeRecorder_.GetElementsKindsForUser(GetPcOffsetByGate(gate)); 391 } 392 GetTransitionElementsKindsForUser(GateRef gate)393 PUBLIC_API std::vector<ElementsKind> GetTransitionElementsKindsForUser(GateRef gate) const 394 { 395 return pgoTypeRecorder_.GetTransitionElementsKindsForUser(GetPcOffsetByGate(gate)); 396 } 397 GetElementsKindForCreater(GateRef gate)398 ElementsKind GetElementsKindForCreater(GateRef gate) const 399 { 400 return pgoTypeRecorder_.GetElementsKindForCreater(gateAcc_.TryGetPcOffset(gate)); 401 } 402 GetArrayElementsLength(GateRef gate)403 uint32_t GetArrayElementsLength(GateRef gate) const 404 { 405 return pgoTypeRecorder_.GetElementsLength(gateAcc_.TryGetPcOffset(gate)); 406 } 407 ShouldPGOTypeInfer(GateRef gate)408 bool ShouldPGOTypeInfer(GateRef gate) const 409 { 410 return jsGatesToByteCode_.find(gate) != jsGatesToByteCode_.end(); 411 } 412 GetNumberVRegs()413 size_t GetNumberVRegs() const 414 { 415 return static_cast<size_t>(method_->GetNumberVRegs()); 416 } 417 GetNumberVRegsWithEnv()418 size_t GetNumberVRegsWithEnv() const 419 { 420 return GetNumberVRegs() + 1; // 1: env variable 421 } 422 GetEnvVregIdx()423 size_t GetEnvVregIdx() const 424 { 425 return GetNumberVRegs(); 426 } 427 GetBytecodes()428 Bytecodes *GetBytecodes() const 429 { 430 return bytecodes_; 431 } 432 GetLastBcIndex()433 uint32_t GetLastBcIndex() const 434 { 435 ASSERT(pcOffsets_.size() > 0); 436 return static_cast<uint32_t>(pcOffsets_.size() - 1); 437 } 438 GetPCByIndex(uint32_t index)439 const uint8_t *GetPCByIndex(uint32_t index) const 440 { 441 ASSERT(index <= GetLastBcIndex()); 442 return pcOffsets_[index]; 443 } 444 GetFirstPC()445 const uint8_t *GetFirstPC() const 446 { 447 return GetPCByIndex(0); 448 } 449 GetLastPC()450 const uint8_t *GetLastPC() const 451 { 452 return GetPCByIndex(GetLastBcIndex()); 453 } 454 FindBcIndexByPc(const uint8_t * pc)455 uint32_t FindBcIndexByPc(const uint8_t *pc) const 456 { 457 auto begin = pcOffsets_.begin(); 458 auto end = pcOffsets_.end(); 459 auto it = std::lower_bound(begin, end, pc); 460 ASSERT(it != end); 461 ASSERT(*it == pc); 462 return std::distance(begin, it); 463 } 464 GetBytecodeInfo(uint32_t index)465 const BytecodeInfo &GetBytecodeInfo(uint32_t index) const 466 { 467 return infoData_[index]; 468 } 469 HasTryCatch()470 bool HasTryCatch() const 471 { 472 return hasTryCatch_; 473 } 474 EnableLoopOptimization()475 bool EnableLoopOptimization() const 476 { 477 return (!HasTryCatch()) && frameStateBuilder_.HasLoop(); 478 } 479 480 void RemoveUnreachableRegion(); 481 GetFrameArgs()482 GateRef GetFrameArgs() const 483 { 484 return argAcc_.GetFrameArgs(); 485 } 486 GetPreFrameState()487 GateRef GetPreFrameState() const 488 { 489 return preFrameState_; 490 } 491 SetPreFrameState(GateRef gate)492 void SetPreFrameState(GateRef gate) 493 { 494 preFrameState_ = gate; 495 } 496 GetPreFrameArgs()497 GateRef GetPreFrameArgs() const 498 { 499 return preFrameArgs_; 500 } 501 SetPreFrameArgs(GateRef gate)502 void SetPreFrameArgs(GateRef gate) 503 { 504 preFrameArgs_ = gate; 505 } 506 IsEntryBlock(const size_t bbId)507 inline bool IsEntryBlock(const size_t bbId) const 508 { 509 return bbId == 0; 510 } 511 IsFirstBasicBlock(const size_t bbId)512 inline bool IsFirstBasicBlock(const size_t bbId) const 513 { 514 return bbId == 1; 515 } 516 GetPGOTypeRecorder()517 const PGOTypeRecorder *GetPGOTypeRecorder() const 518 { 519 return &pgoTypeRecorder_; 520 } 521 GetArgGate(const size_t currentVreg)522 GateRef GetArgGate(const size_t currentVreg) const 523 { 524 return argAcc_.GetArgGate(currentVreg); 525 } 526 ArgGateNotExisted(const size_t currentVreg)527 GateRef ArgGateNotExisted(const size_t currentVreg) 528 { 529 return argAcc_.ArgGateNotExisted(currentVreg); 530 } 531 GetLoopHeaderGates()532 ChunkVector<GateRef>& GetLoopHeaderGates() 533 { 534 return loopHeaderGates_; 535 } 536 NumberOfLiveBlock()537 size_t NumberOfLiveBlock() const 538 { 539 return numOfLiveBB_; 540 } 541 GetCurrentConstpoolId()542 int32_t GetCurrentConstpoolId() const 543 { 544 panda_file::IndexAccessor indexAccessor(*file_->GetPandaFile(), panda_file::File::EntityId(methodId_)); 545 return static_cast<int32_t>(indexAccessor.GetHeaderIndex()); 546 } 547 GetCurrentConstpool(GateRef jsFunc,GateRef & sharedConstPool,GateRef & unSharedConstPool)548 void GetCurrentConstpool(GateRef jsFunc, GateRef &sharedConstPool, GateRef &unSharedConstPool) 549 { 550 int32_t constpoolId = GetCurrentConstpoolId(); 551 if (gateAcc_.GetOpCode(preFrameArgs_) == OpCode::CIRCUIT_ROOT) { 552 sharedConstPool = circuit_->NewGate(circuit_->GetSharedConstPool(constpoolId), MachineType::I64, {jsFunc}, 553 GateType::AnyType()); 554 unSharedConstPool = circuit_->NewGate(circuit_->GetUnsharedConstPool(), MachineType::I64, 555 {sharedConstPool}, GateType::AnyType()); 556 } 557 GateRef frameArgs = preFrameArgs_; 558 GateRef preSharedConstPool = Circuit::NullGate(); 559 GateRef preUnsharedConstPool = Circuit::NullGate(); 560 int32_t preConstpoolId = 0; 561 while (gateAcc_.GetOpCode(frameArgs) != OpCode::CIRCUIT_ROOT) { 562 preSharedConstPool = gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::SHARED_CONST_POOL)); 563 preUnsharedConstPool = 564 gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::UNSHARED_CONST_POOL)); 565 preConstpoolId = static_cast<int32_t>(gateAcc_.GetConstpoolId(preSharedConstPool)); 566 if (preConstpoolId == constpoolId) { 567 sharedConstPool = preSharedConstPool; 568 unSharedConstPool = preUnsharedConstPool; 569 break; 570 } 571 frameArgs = gateAcc_.GetFrameState(frameArgs); 572 } 573 } 574 SetIrreducibleLoop()575 void SetIrreducibleLoop() 576 { 577 isIrreducible_ = true; 578 } 579 HasIrreducibleLoop()580 bool HasIrreducibleLoop() const 581 { 582 return isIrreducible_; 583 } 584 SetJitCompile()585 void SetJitCompile() 586 { 587 isJitCompile_ = true; 588 } 589 IsJitCompile()590 bool IsJitCompile() const 591 { 592 return isJitCompile_; 593 } 594 SetPreAnalysis()595 void SetPreAnalysis() 596 { 597 preAnalysis_ = true; 598 } 599 IsPreAnalysis()600 bool IsPreAnalysis() const 601 { 602 return preAnalysis_; 603 } 604 HasEmptyCatchBB()605 bool HasEmptyCatchBB() const 606 { 607 return hasEmptyCatchBB_; 608 } 609 NeedIrreducibleLoopCheck()610 bool NeedIrreducibleLoopCheck() const 611 { 612 return IsPreAnalysis() || IsJitCompile(); 613 } 614 TerminateAnalysis()615 bool TerminateAnalysis() const 616 { 617 return IsPreAnalysis() || HasIrreducibleLoop(); 618 } 619 IsOSR()620 bool IsOSR() const 621 { 622 return osrOffset_ != MachineCode::INVALID_OSR_OFFSET; 623 } 624 IsCacheBBOfOSRLoop(const BytecodeRegion & bb)625 bool IsCacheBBOfOSRLoop(const BytecodeRegion &bb) const 626 { 627 return catchBBOfOSRLoop_.find(&bb) != catchBBOfOSRLoop_.end(); 628 } 629 630 enum class MarkState : uint8_t { 631 UNVISITED = 0, 632 ON_STACK, 633 PENDING, 634 VISITED, 635 VISITED1, 636 UNVISITED1 = VISITED 637 }; 638 639 struct VisitedInfo { 640 size_t needVisitIndex; 641 bool isVisitedCatchBlock = false; 642 }; 643 bool IsAncestor(size_t nodeA, size_t nodeB); 644 void ComputeNumOfLoopBack(); 645 646 private: 647 void CollectTryCatchBlockInfo(ExceptionInfo &Exception); 648 void BuildCatchBlocks(const ExceptionInfo &Exception); 649 void BuildEntryBlock(); 650 void BuildBasicBlock(); 651 void BuildRegions(const ExceptionInfo &Exception); 652 // build circuit 653 void BuildCircuitArgs(); 654 void BuildOSRArgs(); 655 std::vector<GateRef> CreateGateInList(const BytecodeInfo &info, const GateMetaData *meta); 656 GateRef NewConst(const BytecodeInfo &info); 657 void NewJSGate(BytecodeRegion &bb); 658 void NewJump(BytecodeRegion &bbd); 659 GateRef NewReturn(BytecodeRegion &bb); 660 void NewByteCode(BytecodeRegion &bb); 661 void MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex); 662 void MergeExceptionGete(BytecodeRegion &bb, const BytecodeInfo& bytecodeInfo, uint32_t bcIndex); 663 void BuildSubCircuit(); 664 bool FindOsrLoopHeadBB(); 665 void GenDeoptAndReturnForOsrLoopExit(BytecodeRegion& osrLoopExitBB); 666 void CollectCacheBBforOSRLoop(BytecodeRegion *bb); 667 void HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB); 668 void BuildOsrCircuit(); 669 670 void UpdateEmptyCatchBB(); 671 void UpdateCFG(); 672 void CollectTryPredsInfo(); 673 void ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList); 674 void RemoveUnusedPredsInfo(BytecodeRegion& bb); 675 void BuildCircuit(); 676 void PrintGraph(); 677 void PrintBBInfo(); 678 void PrintGraph(const char* title); 679 void PrintBytecodeInfo(BytecodeRegion& region); 680 void PrintDefsitesInfo(const std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo); 681 void BuildRegionInfo(); 682 void BuildFrameArgs(); 683 void RemoveIfInRpoList(BytecodeRegion *bb); 684 void PerformDFS(const std::vector<size_t> &immDom, size_t listSize); 685 void ReducibilityCheck(); 686 void ComputeImmediateDominators(const std::vector<size_t> &basicBlockList, 687 std::unordered_map<size_t, size_t> &dfsFatherIdx, std::vector<size_t> &immDom, 688 std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx); 689 void ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom, 690 std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx); 691 RegionAt(size_t i)692 BytecodeRegion &RegionAt(size_t i) 693 { 694 return *graph_[i]; 695 } 696 697 Circuit *circuit_; 698 std::vector<std::vector<GateRef>> byteCodeToJSGates_; 699 std::unordered_map<GateRef, size_t> jsGatesToByteCode_; 700 BytecodeGraph graph_; 701 const JSPandaFile *file_ {nullptr}; 702 const MethodLiteral *method_ {nullptr}; 703 GateAccessor gateAcc_; 704 ArgumentAccessor argAcc_; 705 PGOTypeRecorder pgoTypeRecorder_; 706 int32_t osrOffset_ {MachineCode::INVALID_OSR_OFFSET}; 707 bool enableLog_ {false}; 708 bool enableTypeLowering_ {false}; 709 std::vector<GateRef> suspendAndResumeGates_ {}; 710 std::vector<const uint8_t*> pcOffsets_; 711 FrameStateBuilder frameStateBuilder_; 712 std::string methodName_; 713 const CString &recordName_; 714 Bytecodes *bytecodes_; 715 RegionsInfo regionsInfo_{}; 716 std::vector<BytecodeInfo> infoData_ {}; 717 bool hasTryCatch_ {false}; 718 ChunkVector<GateRef> loopHeaderGates_; 719 GateRef preFrameState_ {Circuit::NullGate()}; 720 GateRef preFrameArgs_ {Circuit::NullGate()}; 721 size_t numOfLiveBB_ {0}; 722 bool isInline_ {false}; 723 uint32_t methodId_ {0}; 724 bool preAnalysis_ {false}; 725 std::set<const BytecodeRegion *> catchBBOfOSRLoop_{}; 726 std::map<uint32_t, bool> candidateEmptyCatch_ {}; 727 bool hasEmptyCatchBB_ {false}; 728 bool isIrreducible_ {false}; 729 bool isJitCompile_ {false}; 730 CVector<size_t> timeIn_ {}; 731 CVector<size_t> timeOut_ {}; 732 std::unordered_map<size_t, size_t> bbIdToDfsTimestamp_ {}; 733 }; 734 } // namespace panda::ecmascript::kungfu 735 #endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H 736