• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include <queue>
17 #include <stack>
18 
19 #include "ecmascript/compiler/check_elimination.h"
20 
21 namespace panda::ecmascript::kungfu {
Run()22 void CheckElimination::Run()
23 {
24     RemovePassedCheck();
25     RemoveTypeTrustedCheck();
26 
27     if (IsLogEnabled()) {
28         LOG_COMPILER(INFO) << "";
29         LOG_COMPILER(INFO) << "\033[34m"
30                            << "===================="
31                            << " After check eliminating "
32                            << "[" << GetMethodName() << "]"
33                            << "===================="
34                            << "\033[0m";
35         circuit_->PrintAllGatesWithBytecode();
36         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
37     }
38 }
39 
IsPrimitiveTypeCheck(GateRef gate) const40 bool CheckElimination::IsPrimitiveTypeCheck(GateRef gate) const {
41     auto op = acc_.GetOpCode(gate);
42     return op == OpCode::PRIMITIVE_TYPE_CHECK;
43 }
44 
IsTrustedType(GateRef gate) const45 bool CheckElimination::IsTrustedType(GateRef gate) const
46 {
47     if (acc_.IsConstant(gate)) {
48         return true;
49     }
50     if (acc_.IsTypedOperator(gate)) {
51         if (acc_.GetOpCode(gate) == OpCode::TYPED_BINARY_OP) {
52             return !acc_.GetGateType(gate).IsIntType();
53         } else {
54             return true;
55         }
56     }
57     return false;
58 }
59 
TrustedTypePropagate(std::queue<GateRef> & workList,const std::vector<GateRef> & checkList)60 void CheckElimination::TrustedTypePropagate(std::queue<GateRef>& workList, const std::vector<GateRef>& checkList)
61 {
62     std::unordered_map<GateRef, size_t> trustedInCount;
63     while (!workList.empty()) {
64         auto gate = workList.front();
65         workList.pop();
66         auto uses = acc_.Uses(gate);
67         for (auto i = uses.begin(); i != uses.end(); i++) {
68             GateRef phi = *i;
69             if ((acc_.GetOpCode(phi) != OpCode::VALUE_SELECTOR) ||
70                 (acc_.GetGateType(phi) != acc_.GetGateType(gate))) {
71                 continue;
72             }
73             trustedInCount[phi]++;
74             if (trustedInCount.at(phi) == acc_.GetNumValueIn(phi)) {
75                 workList.push(phi);
76             }
77         }
78     }
79     for (auto check : checkList) {
80         ASSERT(acc_.GetOpCode(check) == OpCode::PRIMITIVE_TYPE_CHECK);
81         auto value = acc_.GetValueIn(check, 0);
82         ASSERT(acc_.GetGateType(value) == acc_.GetParamGateType(check));
83         if (IsTrustedType(value)) {
84             RemoveCheck(check);
85             continue;
86         }
87         if ((trustedInCount.count(value) != 0) &&
88             (trustedInCount.at(value) == acc_.GetNumValueIn(value))) {
89             RemoveCheck(check);
90             continue;
91         }
92         // remove check
93     }
94 }
95 
RemoveCheck(GateRef gate)96 void CheckElimination::RemoveCheck(GateRef gate) {
97     auto state = acc_.GetState(gate);
98     auto depend = acc_.GetDep(gate);
99     auto uses = acc_.Uses(gate);
100     for (auto i = uses.begin(); i != uses.end();) {
101         if (acc_.IsStateIn(i)) {
102             i = acc_.ReplaceIn(i, state);
103         } else if (acc_.IsDependIn(i)) {
104             i = acc_.ReplaceIn(i, depend);
105         } else if (acc_.IsValueIn(i)) {
106             i = acc_.ReplaceIn(i, depend);
107         }
108     }
109     acc_.DeleteGate(gate);
110 }
111 
RemovePassedCheck()112 void CheckElimination::RemovePassedCheck()
113 {
114     std::queue<GateRef> workList;
115     std::vector<GateRef> passedCheck;
116     std::vector<GateRef> outs;
117     workList.push(acc_.GetStateRoot());
118     std::unordered_set<GateRef> mergeVisit;
119     std::set<std::tuple<OpCode, BitField, GateRef>> CheckSetForOne;
120     std::set<std::tuple<OpCode, BitField, GateRef, GateRef>> CheckSetForTwo;
121     while (!workList.empty()) {
122         auto gate = workList.front();
123         workList.pop();
124         if (acc_.GetOpCode(gate) == OpCode::MERGE) {
125             if (!mergeVisit.count(gate)) {
126                 mergeVisit.insert(gate);
127             } else {
128                 continue;
129             }
130         }
131         CheckSetForOne.clear();
132         CheckSetForTwo.clear();
133         while (true) {
134             if (!acc_.IsNotWrite(gate)) {
135                 CheckSetForOne.clear();
136                 CheckSetForTwo.clear();
137             }
138             if (acc_.IsCheckWithOneIn(gate)) {
139                 auto op = OpCode(acc_.GetOpCode(gate));
140                 auto bit = acc_.TryGetValue(gate);
141                 auto v0 = acc_.GetValueIn(gate, 0);
142                 auto tp = std::make_tuple(op, bit, v0);
143                 if (CheckSetForOne.count(tp)) {
144                     passedCheck.emplace_back(gate);
145                 } else {
146                     CheckSetForOne.insert(tp);
147                 }
148             }
149             if (acc_.IsCheckWithTwoIns(gate)) {
150                 auto op = OpCode(acc_.GetOpCode(gate));
151                 auto bit = acc_.TryGetValue(gate);
152                 auto v0 = acc_.GetValueIn(gate, 0);
153                 auto v1 = acc_.GetValueIn(gate, 1);
154                 auto tp = std::make_tuple(op, bit, v0, v1);
155                 if (CheckSetForTwo.count(tp)) {
156                     passedCheck.emplace_back(gate);
157                 } else {
158                     CheckSetForTwo.insert(tp);
159                 }
160             }
161 
162             outs.clear();
163             acc_.GetStateUses(gate, outs);
164 
165             if (outs.size() == 1) {
166                 gate = outs[0];
167                 auto op = acc_.GetOpCode(gate);
168                 if (op == OpCode::LOOP_BACK || op == OpCode::LOOP_BEGIN || op == OpCode::MERGE) {
169                     break;
170                 }
171                 continue;
172             }
173             if ((outs.size() == 2) && (acc_.GetOpCode(gate) == OpCode::JS_BYTECODE)) {
174                 if(acc_.GetOpCode(outs[0]) == OpCode::IF_SUCCESS) {
175                     gate = outs[0];
176                     continue;
177                 }
178                 if(acc_.GetOpCode(outs[1]) == OpCode::IF_SUCCESS) {
179                     gate = outs[1];
180                     continue;
181                 }
182             }
183             break;
184         }
185         for (auto out : outs) {
186             if (acc_.GetOpCode(out) != OpCode::LOOP_BACK) {
187                 workList.push(out);
188             }
189         }
190     }
191     for (auto check : passedCheck) {
192         RemoveCheck(check);
193     }
194 }
195 
RemoveTypeTrustedCheck()196 void CheckElimination::RemoveTypeTrustedCheck() {
197     // eliminate type check for type trusted gate (for primitive type check)
198     std::vector<GateRef> allGates;
199     acc_.GetAllGates(allGates);
200     std::queue<GateRef> workList;
201     std::vector<GateRef> checkList;
202     for (auto gate : allGates) {
203         if (IsTrustedType(gate)) {
204             workList.push(gate);
205         }
206         if (IsPrimitiveTypeCheck(gate)) {
207             checkList.emplace_back(gate);
208         }
209     }
210     TrustedTypePropagate(workList, checkList);
211 }
212 }  // namespace panda::ecmascript::kungfu