• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <numeric>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
24 #include "circuit.h"
25 #include "ecmascript/ecma_vm.h"
26 #include "ecmascript/interpreter/interpreter-inl.h"
27 #include "ecmascript/js_method.h"
28 
29 namespace panda::ecmascript::kungfu {
30 using VRegIDType = uint16_t;
31 
32 enum class SplitKind : uint8_t {
33     DEFAULT,
34     START,
35     END
36 };
37 
38 struct CfgInfo {
39     uint8_t *pc {nullptr};
40     SplitKind splitKind {SplitKind::DEFAULT};
41     std::vector<uint8_t *> succs {};
CfgInfoCfgInfo42     CfgInfo(uint8_t *startOrEndPc, SplitKind kind, std::vector<uint8_t *> successors)
43         : pc(startOrEndPc), splitKind(kind), succs(successors) {};
44 
45     bool operator<(const CfgInfo &rhs) const
46     {
47         if (this->pc != rhs.pc) {
48             return this->pc < rhs.pc;
49         } else {
50             return this->splitKind < rhs.splitKind;
51         }
52     }
53 
54     bool operator==(const CfgInfo &rhs) const
55     {
56         return this->pc == rhs.pc && this->splitKind == rhs.splitKind;
57     }
58 };
59 
60 struct BytecodeRegion {
61     int32_t id {-1};
62     uint8_t *start {nullptr};
63     uint8_t *end {nullptr};
64     std::vector<BytecodeRegion *> preds {}; // List of predessesor blocks
65     std::vector<BytecodeRegion *> succs {}; // List of successors blocks
66     std::vector<BytecodeRegion *> trys {}; // List of trys blocks
67     std::vector<BytecodeRegion *> catchs {}; // List of catches blocks
68     std::vector<BytecodeRegion *> immDomBlocks {}; // List of dominated blocks
69     BytecodeRegion *iDominator {nullptr}; // Block that dominates the current block
70     std::vector<BytecodeRegion *> domFrontiers {}; // List of dominace frontiers
71     bool isDead {false};
72     std::set<uint16_t> phi {}; // phi node
73     bool phiAcc {false};
74     int32_t numOfStatePreds {0};
75     int32_t statePredIndex {0};
76     std::vector<std::tuple<size_t, uint8_t *, bool>> expandedPreds {};
77     kungfu::GateRef stateStart {kungfu::Circuit::NullGate()};
78     kungfu::GateRef dependStart {kungfu::Circuit::NullGate()};
79     std::map<uint16_t, kungfu::GateRef> vregToValSelectorGate {}; // corresponding ValueSelector gates of vregs
80     kungfu::GateRef valueSelectorAccGate {kungfu::Circuit::NullGate()};
81 
82     bool operator <(const BytecodeRegion &target) const
83     {
84         return id < target.id;
85     }
86 };
87 
88 struct BytecodeInfo {
89     std::vector<VRegIDType> vregIn {}; // read register
90     std::vector<VRegIDType> vregOut {}; // write register
91     bool accIn {false}; // read acc
92     bool accOut {false}; // write acc
93     uint64_t imm {0};
94     uint8_t opcode {0};
95     uint16_t offset {0};
96 };
97 
98 struct BytecodeGraph {
99     std::vector<BytecodeRegion> graph {};
100     const JSMethod *method;
101 };
102 
103 enum BytecodeOffset {
104     ONE = 1,
105     TWO,
106     THREE,
107     FOUR,
108     FIVE,
109     SIX,
110     SEVEN,
111     EIGHT,
112     NINE,
113     TEN
114 };
115 
116 enum CommonArgIdx : uint8_t {
117     GLUE = 0,
118     FUNC,
119     NEW_TARGET,
120     THIS,
121     NUM_OF_ARGS,
122 };
123 
124 class BytecodeCircuitBuilder {
125 public:
126     explicit BytecodeCircuitBuilder() = default;
127     ~BytecodeCircuitBuilder() = default;
128     NO_COPY_SEMANTIC(BytecodeCircuitBuilder);
129     NO_MOVE_SEMANTIC(BytecodeCircuitBuilder);
130     void PUBLIC_API BytecodeToCircuit(const std::vector<uint8_t *> &pcArray, const panda_file::File &pf,
131                                       const JSMethod *method);
132 
GetCircuit()133     [[nodiscard]] kungfu::Circuit* GetCircuit()
134     {
135         return &circuit_;
136     }
137 
GetGateToBytecode()138     [[nodiscard]] const std::map<kungfu::GateRef, std::pair<size_t, uint8_t *>>& GetGateToBytecode() const
139     {
140         return jsgateToBytecode_;
141     }
142 
GetBytecodeToGate()143     [[nodiscard]] const std::map<uint8_t *, kungfu::GateRef>& GetBytecodeToGate() const
144     {
145         return byteCodeToJSGate_;
146     }
147 
GetBytecodeStr(kungfu::GateRef gate)148     [[nodiscard]] std::string GetBytecodeStr(kungfu::GateRef gate) const
149     {
150         auto pc = jsgateToBytecode_.at(gate).second;
151         return GetEcmaOpcodeStr(static_cast<EcmaOpcode>(*pc));
152     }
153 
GetJSBytecode(GateRef gate)154     [[nodiscard]] uint8_t* GetJSBytecode(GateRef gate) const
155     {
156         return jsgateToBytecode_.at(gate).second;
157     }
158 
GetCommonArgByIndex(CommonArgIdx idx)159     [[nodiscard]] GateRef GetCommonArgByIndex(CommonArgIdx idx)
160     {
161         return commonArgs_[idx];
162     }
163 
164 private:
165     void PUBLIC_API CollectBytecodeBlockInfo(uint8_t* pc, std::vector<CfgInfo> &bytecodeBlockInfos);
166 
167     std::map<std::pair<uint8_t *, uint8_t *>, std::vector<uint8_t *>> CollectTryCatchBlockInfo(
168         const panda_file::File &file, const JSMethod *method, std::map<uint8_t *, uint8_t*> &byteCodeCurPrePc,
169         std::vector<CfgInfo> &bytecodeBlockInfos);
170 
171     void CompleteBytecodeBlockInfo(std::map<uint8_t *, uint8_t*> &byteCodeCurPrePc,
172                                    std::vector<CfgInfo> &bytecodeBlockInfos);
173 
174     void BuildBasicBlocks(const JSMethod *method,
175                           std::map<std::pair<uint8_t *, uint8_t *>, std::vector<uint8_t *>> &exception,
176                           std::vector<CfgInfo> &bytecodeBlockInfo,
177                           std::map<uint8_t *, uint8_t*> &byteCodeCurPrePc);
178     void ComputeDominatorTree(BytecodeGraph &byteCodeGraph);
179     void BuildImmediateDominator(std::vector<int32_t> &immDom, BytecodeGraph &byteCodeGraph);
180     void ComputeDomFrontiers(std::vector<int32_t> &immDom, BytecodeGraph &byteCodeGraph);
181     BytecodeInfo GetBytecodeInfo(uint8_t *pc);
182     void RemoveDeadRegions(const std::map<size_t, size_t> &dfsTimestamp, BytecodeGraph &byteCodeGraph);
183     void InsertPhi(BytecodeGraph &byteCodeGraph);
184     void UpdateCFG(BytecodeGraph &byteCodeGraph);
185     void BuildCircuit(BytecodeGraph &byteCodeGraph);
186     void PrintCollectBlockInfo(std::vector<CfgInfo> &bytecodeBlockInfos);
187     void PrintGraph(std::vector<BytecodeRegion> &graph);
188     void PrintBytecodeInfo(std::vector<BytecodeRegion> &graph);
189     void PrintBBInfo(std::vector<BytecodeRegion> &graph);
190     static bool IsJump(EcmaOpcode opcode);
191     static bool IsCondJump(EcmaOpcode opcode);
192     static bool IsMov(EcmaOpcode opcode);
193     static bool IsReturn(EcmaOpcode opcode);
194     static bool IsThrow(EcmaOpcode opcode);
195     static bool IsGeneral(EcmaOpcode opcode);
196     static bool IsSetConstant(EcmaOpcode opcode);
GetActualNumArgs(size_t numArgs)197     size_t GetActualNumArgs(size_t numArgs)
198     {
199         return numArgs + CommonArgIdx::NUM_OF_ARGS;
200     }
201 
202     kungfu::Circuit circuit_;
203     std::map<kungfu::GateRef, std::pair<size_t, uint8_t *>> jsgateToBytecode_;
204     std::map<uint8_t *, kungfu::GateRef> byteCodeToJSGate_;
205     std::map<int32_t, BytecodeRegion *> bbIdToBasicBlock_;
206     std::array<GateRef, CommonArgIdx::NUM_OF_ARGS> commonArgs_ {};
207 };
208 }  // namespace panda::ecmascript::kungfu
209 #endif  // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H