1 /** 2 * Copyright (c) 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 LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_IR_BUILDER_H 17 #define LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_IR_BUILDER_H 18 19 #include "static_core/compiler/optimizer/ir/graph.h" 20 #include "static_core/compiler/optimizer/ir/basicblock.h" 21 #include "static_core/compiler/optimizer/pass.h" 22 #include "libabckit/src/irbuilder_dynamic/pbc_iterator_dyn.h" 23 #include "libabckit/src/irbuilder_dynamic/inst_builder_dyn.h" 24 25 namespace libabckit { 26 27 /** 28 * Build IR from JS bytecode 29 */ 30 class IrBuilderDynamic : public compiler::Optimization { 31 struct Boundaries { 32 uint32_t beginPc; 33 uint32_t endPc; 34 }; 35 36 struct CatchCodeBlock { 37 uint32_t pc {}; 38 uint32_t typeId {}; 39 }; 40 41 // NOLINTBEGIN(misc-non-private-member-variables-in-classes) 42 struct TryCodeBlock { 43 Boundaries boundaries {}; // NOLINT(misc-non-private-member-variables-in-classes) 44 compiler::BasicBlock *beginBb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 45 compiler::BasicBlock *endBb {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 46 ArenaVector<CatchCodeBlock> *catches {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 47 ArenaVector<compiler::BasicBlock *> *basicBlocks { 48 nullptr}; // NOLINT(misc-non-private-member-variables-in-classes) 49 uint32_t id {compiler::INVALID_ID}; // NOLINT(misc-non-private-member-variables-in-classes) 50 bool containsThrowableInst {false}; // NOLINT(misc-non-private-member-variables-in-classes) 51 InitTryCodeBlock52 void Init(compiler::Graph *graph, uint32_t tryId) 53 { 54 id = tryId; 55 auto allocator = graph->GetLocalAllocator(); 56 catches = allocator->New<ArenaVector<CatchCodeBlock>>(allocator->Adapter()); 57 beginBb = graph->CreateEmptyBlock(boundaries.beginPc); 58 beginBb->SetTryBegin(true); 59 endBb = graph->CreateEmptyBlock(boundaries.endPc); 60 endBb->SetTryEnd(true); 61 // Order of try-blocks should be saved in the graph to restore it in the generated bytecode 62 graph->AppendTryBeginBlock(beginBb); 63 } 64 }; 65 // NOLINTEND(misc-non-private-member-variables-in-classes) 66 67 public: IrBuilderDynamic(compiler::Graph * graph)68 explicit IrBuilderDynamic(compiler::Graph *graph) : IrBuilderDynamic(graph, graph->GetMethod()) {} 69 IrBuilderDynamic(compiler::Graph * graph,AbckitRuntimeAdapterDynamic::MethodPtr method)70 IrBuilderDynamic(compiler::Graph *graph, AbckitRuntimeAdapterDynamic::MethodPtr method) 71 : Optimization(graph), 72 blocks_(graph->GetLocalAllocator()->Adapter()), 73 catchesPc_(graph->GetLocalAllocator()->Adapter()), 74 tryBlocks_(graph->GetLocalAllocator()->Adapter()), 75 openedTryBlocks_(graph->GetLocalAllocator()->Adapter()), 76 catchHandlers_(graph->GetLocalAllocator()->Adapter()), 77 instDefs_(graph->GetLocalAllocator()->Adapter()), 78 method_(method) 79 { 80 } 81 82 NO_COPY_SEMANTIC(IrBuilderDynamic); 83 NO_MOVE_SEMANTIC(IrBuilderDynamic); 84 ~IrBuilderDynamic() override = default; 85 86 bool RunImpl() override; 87 GetPassName()88 const char *GetPassName() const override 89 { 90 return "IrBuilderDynamic"; 91 } 92 GetMethod()93 auto GetMethod() const 94 { 95 return method_; 96 } 97 98 private: CreateBlock(size_t pc)99 void CreateBlock(size_t pc) 100 { 101 if (blocks_[pc] == nullptr) { 102 blocks_[pc] = GetGraph()->CreateEmptyBlock(); 103 blocks_[pc]->SetGuestPc(pc); 104 } 105 } 106 GetBlockForPc(size_t pc)107 compiler::BasicBlock *GetBlockForPc(size_t pc) 108 { 109 return blocks_[pc]; 110 } 111 GetPrevBlockForPc(size_t pc)112 compiler::BasicBlock *GetPrevBlockForPc(size_t pc) 113 { 114 do { 115 ASSERT(pc > 0); 116 pc--; 117 } while (blocks_[pc] == nullptr || blocks_[pc]->GetGraph() == nullptr); 118 return blocks_[pc]; 119 } 120 121 bool CheckMethodLimitations(const BytecodeInstructions &instructions, size_t vregsCount); 122 void BuildBasicBlocks(const BytecodeInstructions &instructions); 123 bool BuildBasicBlock(compiler::BasicBlock *bb, InstBuilder *instBuilder, const uint8_t *instructionsBuf); 124 bool BuildInstructionsForBB(compiler::BasicBlock *bb, InstBuilder *instBuilder, const uint8_t *instructionsBuf); 125 void SplitConstant(compiler::ConstantInst *constInst); 126 127 struct BlocksConnectorInfo { 128 bool fallthrough {}; 129 bool deadInstructions {}; 130 BytecodeInst prevInst {nullptr}; 131 }; 132 133 compiler::BasicBlock *AddSuccs(BlocksConnectorInfo *info, compiler::BasicBlock *currBb, 134 compiler::BasicBlock *targetBlock, size_t &pc, BytecodeInst &inst); 135 void ConnectBasicBlocks(const BytecodeInstructions &instructions); 136 void CreateTryCatchBoundariesBlocks(); 137 void ResolveTryCatchBlocks(); 138 void ConnectTryCatchBlocks(); 139 IrBuilderDynamic::TryCodeBlock *InsertTryBlockInfo(const Boundaries &tryBoundaries); 140 void TrackTryBoundaries(size_t pc); 141 compiler::BasicBlock *GetBlockToJump(BytecodeInst *inst, size_t pc); 142 compiler::BasicBlock *GetBlockForSaveStateDeoptimize(compiler::BasicBlock *block); 143 void MarkTryCatchBlocks(compiler::Marker marker); 144 template <class Callback> 145 void EnumerateTryBlocksCoveredPc(uint32_t pc, const Callback &callback); 146 void ConnectTryCodeBlock(const TryCodeBlock &tryBlock, 147 const ArenaMap<uint32_t, compiler::BasicBlock *> &catchBlocks); 148 void ProcessThrowableInstructions(InstBuilder *instBuilder, compiler::Inst *throwableInst); 149 void RestoreTryEnd(const TryCodeBlock &tryBlock); 150 151 private: 152 ArenaVector<compiler::BasicBlock *> blocks_; 153 ArenaSet<uint32_t> catchesPc_; 154 ArenaMultiMap<uint32_t, TryCodeBlock> tryBlocks_; 155 ArenaList<TryCodeBlock *> openedTryBlocks_; 156 ArenaUnorderedSet<compiler::BasicBlock *> catchHandlers_; 157 compiler::InstVector instDefs_; 158 AbckitRuntimeAdapterDynamic::MethodPtr method_ = nullptr; 159 }; 160 161 } // namespace libabckit 162 163 #endif // LIBABCKIT_SRC_IR_BUILDER_DYNAMIC_IR_BUILDER_H 164