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