• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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