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_ {}; BytecodeRegionBytecodeRegion170 BytecodeRegion(Chunk* chunk) : preds(chunk), succs(chunk), 171 trys(chunk), catches(chunk), loopBacks(chunk), expandedPreds(chunk) 172 { 173 } 174 GetBytecodeIteratorBytecodeRegion175 BytecodeIterator &GetBytecodeIterator() 176 { 177 return bytecodeIterator_; 178 } 179 180 bool operator <(const BytecodeRegion &target) const 181 { 182 return id < target.id; 183 } 184 SortCatchesBytecodeRegion185 void SortCatches() 186 { 187 if (catches.size() > 1) { 188 std::sort(catches.begin(), catches.end(), [](BytecodeRegion *first, BytecodeRegion *second) { 189 return first->start < second->start; 190 }); 191 } 192 } 193 EraseThisBlockBytecodeRegion194 void EraseThisBlock(ChunkVector<BytecodeRegion *> &blocks) 195 { 196 auto it = std::find(blocks.begin(), blocks.end(), this); 197 if (it != blocks.end()) { 198 blocks.erase(it); 199 } 200 } 201 IsEmptryBlockBytecodeRegion202 bool IsEmptryBlock() const 203 { 204 return end == static_cast<uint32_t>(BytecodeIterator::INVALID_INDEX); 205 } 206 IsLoopBackBytecodeRegion207 bool IsLoopBack(const BytecodeRegion &bb) const 208 { 209 return loopBacks.find(bb.id) != loopBacks.end(); 210 } 211 }; 212 213 using BytecodeGraph = ChunkVector<BytecodeRegion*>; 214 215 class BytecodeCircuitBuilder { 216 public: 217 BytecodeCircuitBuilder(const JSPandaFile *jsPandaFile, 218 const MethodLiteral *methodLiteral, 219 const MethodPcInfo &methodPCInfo, 220 Circuit *circuit, 221 Bytecodes *bytecodes, 222 bool enableLog, 223 bool enableTypeLowering, 224 std::string name, 225 const CString &recordName, 226 PGOProfilerDecoder *decoder, 227 bool isInline, 228 JITProfiler* jitProfiler = nullptr) circuit_(circuit)229 : circuit_(circuit), graph_(circuit->chunk()), file_(jsPandaFile), 230 method_(methodLiteral), gateAcc_(circuit), argAcc_(circuit, method_), 231 pgoTypeRecorder_(*decoder, jsPandaFile, method_->GetMethodId().GetOffset()), 232 enableLog_(enableLog), enableTypeLowering_(enableTypeLowering), 233 pcOffsets_(methodPCInfo.pcOffsets), 234 frameStateBuilder_(this, circuit, methodLiteral), 235 methodName_(name), recordName_(recordName), 236 bytecodes_(bytecodes), 237 loopHeaderGates_(circuit->chunk()), 238 preFrameState_(circuit_->GetRoot()), 239 preFrameArgs_(circuit_->GetRoot()), 240 isInline_(isInline), 241 methodId_(method_->GetMethodId().GetOffset()) 242 { 243 if (jitProfiler != nullptr) { 244 pgoTypeRecorder_.InitMap(jitProfiler); 245 } 246 } 247 ~BytecodeCircuitBuilder() = default; 248 NO_COPY_SEMANTIC(BytecodeCircuitBuilder); 249 NO_MOVE_SEMANTIC(BytecodeCircuitBuilder); 250 void PUBLIC_API BytecodeToCircuit(); 251 void CollectRegionInfo(uint32_t bcIndex); 252 GetCircuit()253 [[nodiscard]] Circuit* GetCircuit() const 254 { 255 return circuit_; 256 } 257 GetGateByBcIndex(uint32_t bcIndex)258 GateRef GetGateByBcIndex(uint32_t bcIndex) const 259 { 260 ASSERT(bcIndex < byteCodeToJSGates_.size()); 261 if (byteCodeToJSGates_[bcIndex].size() > 0) { 262 ASSERT(byteCodeToJSGates_[bcIndex].size() == 1); 263 return byteCodeToJSGates_[bcIndex].at(0); 264 } 265 return Circuit::NullGate(); 266 } 267 GetGatesByBcIndex(uint32_t bcIndex)268 const std::vector<GateRef>& GetGatesByBcIndex(uint32_t bcIndex) const 269 { 270 ASSERT(bcIndex < byteCodeToJSGates_.size()); 271 return byteCodeToJSGates_[bcIndex]; 272 } 273 GetBcIndexByGate(GateRef gate)274 uint32_t GetBcIndexByGate(GateRef gate) const 275 { 276 return jsGatesToByteCode_.at(gate); 277 } 278 IsBcIndexByGate(GateRef gate)279 bool IsBcIndexByGate(GateRef gate) const 280 { 281 if (jsGatesToByteCode_.find(gate) == jsGatesToByteCode_.end()) { 282 return false; 283 } 284 return true; 285 } 286 SetOsrOffset(int32_t offset)287 void SetOsrOffset(int32_t offset) 288 { 289 osrOffset_ = offset; 290 } 291 NeedCheckSafePointAndStackOver()292 bool NeedCheckSafePointAndStackOver() const 293 { 294 return !isInline_ && !method_->IsNoGC(); 295 } 296 UpdateBcIndexGate(GateRef gate,uint32_t bcIndex)297 void UpdateBcIndexGate(GateRef gate, uint32_t bcIndex) 298 { 299 ASSERT(gateAcc_.GetOpCode(gate) == OpCode::JS_BYTECODE); 300 ASSERT(bcIndex < byteCodeToJSGates_.size()); 301 byteCodeToJSGates_[bcIndex].emplace_back(gate); 302 jsGatesToByteCode_[gate] = bcIndex; 303 } 304 GetMethod()305 [[nodiscard]] const MethodLiteral* GetMethod() const 306 { 307 return method_; 308 } 309 GetJSPandaFile()310 [[nodiscard]] const JSPandaFile *GetJSPandaFile() const 311 { 312 return file_; 313 } 314 GetMethodName()315 const std::string& GetMethodName() const 316 { 317 return methodName_; 318 } 319 IsLogEnabled()320 bool IsLogEnabled() const 321 { 322 return enableLog_; 323 } 324 IsTypeLoweringEnabled()325 bool IsTypeLoweringEnabled() const 326 { 327 return enableTypeLowering_; 328 } 329 GetAsyncRelatedGates()330 [[nodiscard]] const std::vector<GateRef>& GetAsyncRelatedGates() const 331 { 332 return suspendAndResumeGates_; 333 } 334 UpdateAsyncRelatedGate(GateRef gate)335 void UpdateAsyncRelatedGate(GateRef gate) 336 { 337 suspendAndResumeGates_.emplace_back(gate); 338 }; 339 340 template <class Callback> EnumerateBlock(BytecodeRegion & bb,const Callback & cb)341 void EnumerateBlock(BytecodeRegion &bb, const Callback &cb) 342 { 343 auto &iterator = bb.GetBytecodeIterator(); 344 iterator.GotoStart(); 345 while (!iterator.Done()) { 346 auto &bytecodeInfo = iterator.GetBytecodeInfo(); 347 bool ret = cb(bytecodeInfo); 348 if (!ret) { 349 break; 350 } 351 ++iterator; 352 } 353 } 354 GetBasicBlockById(size_t id)355 BytecodeRegion &GetBasicBlockById(size_t id) 356 { 357 ASSERT(id < graph_.size()); 358 return RegionAt(id); 359 } 360 AddBasicBlock(BytecodeRegion * region)361 void AddBasicBlock(BytecodeRegion* region) 362 { 363 graph_.emplace_back(region); 364 } 365 GetBasicBlockCount()366 size_t GetBasicBlockCount() const 367 { 368 return graph_.size(); 369 } 370 GetPcOffset(const uint8_t * pc)371 size_t GetPcOffset(const uint8_t *pc) const 372 { 373 return static_cast<size_t>(pc - method_->GetBytecodeArray()); 374 } 375 GetPcOffset(uint32_t bcIndex)376 size_t GetPcOffset(uint32_t bcIndex) const 377 { 378 const uint8_t* pc = GetPCByIndex(bcIndex); 379 return GetPcOffset(pc); 380 } 381 GetPcOffsetByGate(GateRef gate)382 size_t GetPcOffsetByGate(GateRef gate) const 383 { 384 return GetPcOffset(jsGatesToByteCode_.at(gate)); 385 } 386 GetElementsKindsForUser(GateRef gate)387 std::vector<ElementsKind> GetElementsKindsForUser(GateRef gate) const 388 { 389 return pgoTypeRecorder_.GetElementsKindsForUser(GetPcOffsetByGate(gate)); 390 } 391 GetTransitionElementsKindsForUser(GateRef gate)392 PUBLIC_API std::vector<ElementsKind> GetTransitionElementsKindsForUser(GateRef gate) const 393 { 394 return pgoTypeRecorder_.GetTransitionElementsKindsForUser(GetPcOffsetByGate(gate)); 395 } 396 GetElementsKindForCreater(GateRef gate)397 ElementsKind GetElementsKindForCreater(GateRef gate) const 398 { 399 return pgoTypeRecorder_.GetElementsKindForCreater(gateAcc_.TryGetPcOffset(gate)); 400 } 401 GetArrayElementsLength(GateRef gate)402 uint32_t GetArrayElementsLength(GateRef gate) const 403 { 404 return pgoTypeRecorder_.GetElementsLength(gateAcc_.TryGetPcOffset(gate)); 405 } 406 GetRegionSpaceFlag(GateRef gate)407 RegionSpaceFlag GetRegionSpaceFlag(GateRef gate) const 408 { 409 return pgoTypeRecorder_.GetRegionSpaceFlag(gateAcc_.TryGetPcOffset(gate)); 410 } 411 ShouldPGOTypeInfer(GateRef gate)412 bool ShouldPGOTypeInfer(GateRef gate) const 413 { 414 return jsGatesToByteCode_.find(gate) != jsGatesToByteCode_.end(); 415 } 416 GetNumberVRegs()417 size_t GetNumberVRegs() const 418 { 419 return static_cast<size_t>(method_->GetNumberVRegs()); 420 } 421 GetNumberVRegsWithEnv()422 size_t GetNumberVRegsWithEnv() const 423 { 424 return GetNumberVRegs() + 1; // 1: env variable 425 } 426 GetEnvVregIdx()427 size_t GetEnvVregIdx() const 428 { 429 return GetNumberVRegs(); 430 } 431 GetBytecodes()432 Bytecodes *GetBytecodes() const 433 { 434 return bytecodes_; 435 } 436 GetLastBcIndex()437 uint32_t GetLastBcIndex() const 438 { 439 ASSERT(pcOffsets_.size() > 0); 440 return static_cast<uint32_t>(pcOffsets_.size() - 1); 441 } 442 GetPCByIndex(uint32_t index)443 const uint8_t *GetPCByIndex(uint32_t index) const 444 { 445 ASSERT(index <= GetLastBcIndex()); 446 return pcOffsets_[index]; 447 } 448 GetFirstPC()449 const uint8_t *GetFirstPC() const 450 { 451 return GetPCByIndex(0); 452 } 453 GetLastPC()454 const uint8_t *GetLastPC() const 455 { 456 return GetPCByIndex(GetLastBcIndex()); 457 } 458 FindBcIndexByPc(const uint8_t * pc)459 uint32_t FindBcIndexByPc(const uint8_t *pc) const 460 { 461 auto begin = pcOffsets_.begin(); 462 auto end = pcOffsets_.end(); 463 auto it = std::lower_bound(begin, end, pc); 464 ASSERT(it != end); 465 ASSERT(*it == pc); 466 return std::distance(begin, it); 467 } 468 GetBytecodeInfo(uint32_t index)469 const BytecodeInfo &GetBytecodeInfo(uint32_t index) const 470 { 471 return infoData_[index]; 472 } 473 HasTryCatch()474 bool HasTryCatch() const 475 { 476 return hasTryCatch_; 477 } 478 EnableLoopOptimization()479 bool EnableLoopOptimization() const 480 { 481 return (!HasTryCatch()) && frameStateBuilder_.HasLoop(); 482 } 483 484 void RemoveUnreachableRegion(); 485 486 void RemoveInsufficientProfileRegion(); 487 488 void RemoveIsolatedRegion(); 489 GetFrameArgs()490 GateRef GetFrameArgs() const 491 { 492 return argAcc_.GetFrameArgs(); 493 } 494 GetPreFrameState()495 GateRef GetPreFrameState() const 496 { 497 return preFrameState_; 498 } 499 SetPreFrameState(GateRef gate)500 void SetPreFrameState(GateRef gate) 501 { 502 preFrameState_ = gate; 503 } 504 GetPreFrameArgs()505 GateRef GetPreFrameArgs() const 506 { 507 return preFrameArgs_; 508 } 509 SetPreFrameArgs(GateRef gate)510 void SetPreFrameArgs(GateRef gate) 511 { 512 preFrameArgs_ = gate; 513 } 514 IsEntryBlock(const size_t bbId)515 inline bool IsEntryBlock(const size_t bbId) const 516 { 517 return bbId == 0; 518 } 519 IsFirstBasicBlock(const size_t bbId)520 inline bool IsFirstBasicBlock(const size_t bbId) const 521 { 522 return bbId == 1; 523 } 524 GetPGOTypeRecorder()525 const PGOTypeRecorder *GetPGOTypeRecorder() const 526 { 527 return &pgoTypeRecorder_; 528 } 529 GetArgGate(const size_t currentVreg)530 GateRef GetArgGate(const size_t currentVreg) const 531 { 532 return argAcc_.GetArgGate(currentVreg); 533 } 534 ArgGateNotExisted(const size_t currentVreg)535 GateRef ArgGateNotExisted(const size_t currentVreg) 536 { 537 return argAcc_.ArgGateNotExisted(currentVreg); 538 } 539 GetLoopHeaderGates()540 ChunkVector<GateRef>& GetLoopHeaderGates() 541 { 542 return loopHeaderGates_; 543 } 544 NumberOfLiveBlock()545 size_t NumberOfLiveBlock() const 546 { 547 return numOfLiveBB_; 548 } 549 GetCurrentConstpoolId()550 int32_t GetCurrentConstpoolId() const 551 { 552 panda_file::IndexAccessor indexAccessor(*file_->GetPandaFile(), panda_file::File::EntityId(methodId_)); 553 return static_cast<int32_t>(indexAccessor.GetHeaderIndex()); 554 } 555 GetCurrentConstpool(GateRef jsFunc,GateRef & sharedConstPool,GateRef & unSharedConstPool)556 void GetCurrentConstpool(GateRef jsFunc, GateRef &sharedConstPool, GateRef &unSharedConstPool) 557 { 558 int32_t constpoolId = GetCurrentConstpoolId(); 559 if (gateAcc_.GetOpCode(preFrameArgs_) == OpCode::CIRCUIT_ROOT) { 560 sharedConstPool = circuit_->NewGate(circuit_->GetSharedConstPool(constpoolId), MachineType::I64, {jsFunc}, 561 GateType::AnyType()); 562 unSharedConstPool = circuit_->NewGate(circuit_->GetUnsharedConstPool(), MachineType::I64, 563 {sharedConstPool}, GateType::AnyType()); 564 } 565 GateRef frameArgs = preFrameArgs_; 566 GateRef preSharedConstPool = Circuit::NullGate(); 567 GateRef preUnsharedConstPool = Circuit::NullGate(); 568 int32_t preConstpoolId = 0; 569 while (gateAcc_.GetOpCode(frameArgs) != OpCode::CIRCUIT_ROOT) { 570 preSharedConstPool = gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::SHARED_CONST_POOL)); 571 preUnsharedConstPool = 572 gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::UNSHARED_CONST_POOL)); 573 preConstpoolId = static_cast<int32_t>(gateAcc_.GetConstpoolId(preSharedConstPool)); 574 if (preConstpoolId == constpoolId) { 575 sharedConstPool = preSharedConstPool; 576 unSharedConstPool = preUnsharedConstPool; 577 break; 578 } 579 frameArgs = gateAcc_.GetFrameState(frameArgs); 580 } 581 } 582 SetIrreducibleLoop()583 void SetIrreducibleLoop() 584 { 585 isIrreducible_ = true; 586 } 587 HasIrreducibleLoop()588 bool HasIrreducibleLoop() const 589 { 590 return isIrreducible_; 591 } 592 SetJitCompile()593 void SetJitCompile() 594 { 595 isJitCompile_ = true; 596 } 597 IsJitCompile()598 bool IsJitCompile() const 599 { 600 return isJitCompile_; 601 } 602 SetPreAnalysis()603 void SetPreAnalysis() 604 { 605 preAnalysis_ = true; 606 } 607 IsPreAnalysis()608 bool IsPreAnalysis() const 609 { 610 return preAnalysis_; 611 } 612 NeedIrreducibleLoopCheck()613 bool NeedIrreducibleLoopCheck() const 614 { 615 return IsPreAnalysis() || IsJitCompile(); 616 } 617 TerminateAnalysis()618 bool TerminateAnalysis() const 619 { 620 return IsPreAnalysis() || HasIrreducibleLoop(); 621 } 622 IsOSR()623 bool IsOSR() const 624 { 625 return osrOffset_ != MachineCode::INVALID_OSR_OFFSET; 626 } 627 IsCacheBBOfOSRLoop(const BytecodeRegion & bb)628 bool IsCacheBBOfOSRLoop(const BytecodeRegion &bb) const 629 { 630 return catchBBOfOSRLoop_.find(&bb) != catchBBOfOSRLoop_.end(); 631 } 632 633 void ComputeNumOfLoopBack(); 634 635 enum class MarkState : uint8_t { 636 UNVISITED = 0, 637 ON_STACK, 638 PENDING, 639 VISITED, 640 VISITED1, 641 UNVISITED1 = VISITED 642 }; 643 644 struct VisitedInfo { 645 size_t needVisitIndex; 646 bool isVisitedCatchBlock = false; 647 }; 648 bool IsAncestor(size_t nodeA, size_t nodeB); 649 650 private: 651 void CollectTryCatchBlockInfo(ExceptionInfo &Exception); 652 void BuildCatchBlocks(const ExceptionInfo &Exception); 653 void BuildEntryBlock(); 654 void BuildBasicBlock(); 655 void BuildRegions(const ExceptionInfo &Exception); 656 // build circuit 657 void BuildCircuitArgs(); 658 void BuildOSRArgs(); 659 std::vector<GateRef> CreateGateInList(const BytecodeInfo &info, const GateMetaData *meta); 660 GateRef NewDeopt(BytecodeRegion &bb); 661 GateRef NewConst(const BytecodeInfo &info); 662 void NewJSGate(BytecodeRegion &bb); 663 void NewJump(BytecodeRegion &bbd); 664 GateRef NewReturn(BytecodeRegion &bb); 665 void NewByteCode(BytecodeRegion &bb); 666 void MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex); 667 void MergeExceptionGete(BytecodeRegion &bb, const BytecodeInfo& bytecodeInfo, uint32_t bcIndex); 668 void BuildSubCircuit(); 669 bool FindOsrLoopHeadBB(); 670 void GenDeoptAndReturnForOsrLoopExit(BytecodeRegion& osrLoopExitBB); 671 void CollectCacheBBforOSRLoop(BytecodeRegion *bb); 672 void HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB); 673 void BuildOsrCircuit(); 674 675 void UpdateCFG(); 676 void CollectTryPredsInfo(); 677 void ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList, bool skipInsufficientProfile = false); 678 void RemoveUnusedPredsInfo(BytecodeRegion& bb, bool skipInsufficientProfile); 679 void BuildCircuit(); 680 void PrintGraph(); 681 void PrintBBInfo(); 682 void PrintGraph(const char* title); 683 void PrintBytecodeInfo(BytecodeRegion& region); 684 void PrintDefsitesInfo(const std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo); 685 void BuildRegionInfo(); 686 void BuildFrameArgs(); 687 void RemoveIfInRpoList(BytecodeRegion *bb); 688 void PerformDFS(const std::vector<size_t> &immDom, size_t listSize); 689 void ReducibilityCheck(); 690 void ComputeImmediateDominators(const std::vector<size_t> &basicBlockList, 691 std::unordered_map<size_t, size_t> &dfsFatherIdx, std::vector<size_t> &immDom, 692 std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx); 693 void ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom, 694 std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx); 695 RegionAt(size_t i)696 BytecodeRegion &RegionAt(size_t i) 697 { 698 return *graph_[i]; 699 } 700 701 Circuit *circuit_; 702 std::vector<std::vector<GateRef>> byteCodeToJSGates_; 703 std::unordered_map<GateRef, size_t> jsGatesToByteCode_; 704 BytecodeGraph graph_; 705 const JSPandaFile *file_ {nullptr}; 706 const MethodLiteral *method_ {nullptr}; 707 GateAccessor gateAcc_; 708 ArgumentAccessor argAcc_; 709 PGOTypeRecorder pgoTypeRecorder_; 710 int32_t osrOffset_ {MachineCode::INVALID_OSR_OFFSET}; 711 bool enableLog_ {false}; 712 bool enableTypeLowering_ {false}; 713 std::vector<GateRef> suspendAndResumeGates_ {}; 714 std::vector<const uint8_t*> pcOffsets_; 715 FrameStateBuilder frameStateBuilder_; 716 std::string methodName_; 717 const CString &recordName_; 718 Bytecodes *bytecodes_; 719 RegionsInfo regionsInfo_{}; 720 std::vector<BytecodeInfo> infoData_ {}; 721 bool hasTryCatch_ {false}; 722 ChunkVector<GateRef> loopHeaderGates_; 723 GateRef preFrameState_ {Circuit::NullGate()}; 724 GateRef preFrameArgs_ {Circuit::NullGate()}; 725 size_t numOfLiveBB_ {0}; 726 bool isInline_ {false}; 727 uint32_t methodId_ {0}; 728 bool preAnalysis_ {false}; 729 std::set<const BytecodeRegion *> catchBBOfOSRLoop_{}; 730 bool isIrreducible_ {false}; 731 bool isJitCompile_ {false}; 732 CVector<size_t> timeIn_ {}; 733 CVector<size_t> timeOut_ {}; 734 std::unordered_map<size_t, size_t> bbIdToDfsTimestamp_ {}; 735 }; 736 } // namespace panda::ecmascript::kungfu 737 #endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H 738