1 /*
2 * Copyright (c) 2023 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 "ecmascript/compiler/lexical_env_specialization_pass.h"
17
18 namespace panda::ecmascript::kungfu {
Initialize()19 void LexicalEnvSpecializationPass::Initialize()
20 {
21 dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
22 GateRef entry = acc_.GetDependRoot();
23 VisitDependEntry(entry);
24 }
25
VisitDependEntry(GateRef gate)26 GateRef LexicalEnvSpecializationPass::VisitDependEntry(GateRef gate)
27 {
28 auto empty = new (chunk_) DependChains(chunk_);
29 return UpdateDependChain(gate, empty);
30 }
31
VisitGate(GateRef gate)32 GateRef LexicalEnvSpecializationPass::VisitGate(GateRef gate)
33 {
34 auto opcode = acc_.GetOpCode(gate);
35 switch (opcode) {
36 case OpCode::JS_BYTECODE: {
37 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
38 if (Bytecodes::IsLdLexVarOp(ecmaOpcode)) {
39 return TrySpecializeLdLexVar(gate);
40 }
41 return VisitOther(gate);
42 }
43 case OpCode::DEPEND_SELECTOR:
44 return VisitDependSelector(gate);
45 default:
46 if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
47 return VisitOther(gate);
48 }
49 }
50 return Circuit::NullGate();
51 }
52
VisitOther(GateRef gate)53 GateRef LexicalEnvSpecializationPass::VisitOther(GateRef gate)
54 {
55 ASSERT(acc_.GetDependCount(gate) >= 1);
56 auto depIn = acc_.GetDep(gate);
57 auto dependChain = GetDependChain(depIn);
58 if (dependChain == nullptr) {
59 return Circuit::NullGate();
60 }
61 dependChain = dependChain->UpdateNode(gate);
62 return UpdateDependChain(gate, dependChain);
63 }
64
VisitDependSelector(GateRef gate)65 GateRef LexicalEnvSpecializationPass::VisitDependSelector(GateRef gate)
66 {
67 auto state = acc_.GetState(gate);
68 if (acc_.IsLoopHead(state)) {
69 // use loop head as depend chain
70 return VisitOther(gate);
71 }
72
73 auto dependCount = acc_.GetDependCount(gate);
74 for (size_t i = 0; i < dependCount; ++i) {
75 auto depend = acc_.GetDep(gate, i);
76 auto dependChain = GetDependChain(depend);
77 if (dependChain == nullptr) {
78 return Circuit::NullGate();
79 }
80 }
81
82 // all depend done.
83 auto depend = acc_.GetDep(gate);
84 auto dependChain = GetDependChain(depend);
85 DependChains* copy = new (chunk_) DependChains(chunk_);
86 copy->CopyFrom(dependChain);
87 for (size_t i = 1; i < dependCount; ++i) { // 1: second in
88 auto dependIn = acc_.GetDep(gate, i);
89 auto tempChain = GetDependChain(dependIn);
90 copy->Merge(tempChain);
91 }
92 HasNotdomStLexVarOrCall(gate, copy->GetHeadGate());
93 return UpdateDependChain(gate, copy);
94 }
95
UpdateDependChain(GateRef gate,DependChains * dependChain)96 GateRef LexicalEnvSpecializationPass::UpdateDependChain(GateRef gate, DependChains* dependChain)
97 {
98 ASSERT(dependChain != nullptr);
99 auto oldDependChain = GetDependChain(gate);
100 if (dependChain->Equals(oldDependChain)) {
101 return Circuit::NullGate();
102 }
103 dependChains_[acc_.GetId(gate)] = dependChain;
104 return gate;
105 }
106
TrySpecializeLdLexVar(GateRef gate)107 GateRef LexicalEnvSpecializationPass::TrySpecializeLdLexVar(GateRef gate)
108 {
109 ASSERT(acc_.GetDependCount(gate) == 1);
110 auto depIn = acc_.GetDep(gate);
111 auto dependChain = GetDependChain(depIn);
112 // dependChain is null
113 if (dependChain == nullptr) {
114 return Circuit::NullGate();
115 }
116 auto stlexvarGate = LookupStLexvarNode(dependChain, gate);
117 if (stlexvarGate != Circuit::NullGate()) {
118 return acc_.GetValueIn(stlexvarGate, 3); // 3: stlexvar value in
119 }
120
121 // update gate, for others elimination
122 dependChain = dependChain->UpdateNode(gate);
123 return UpdateDependChain(gate, dependChain);
124 }
125
SearchStLexVar(GateRef gate,GateRef ldLexVar,GateRef & result)126 bool LexicalEnvSpecializationPass::SearchStLexVar(GateRef gate, GateRef ldLexVar, GateRef &result)
127 {
128 if (HasNotDomIllegalOp(gate)) {
129 result = ldLexVar;
130 return false;
131 }
132
133 if (acc_.GetOpCode(gate) != OpCode::JS_BYTECODE) {
134 return false;
135 }
136
137 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
138 if (Bytecodes::IsStLexVarOp(ecmaOpcode)) {
139 if (CheckStLexVar(gate, ldLexVar)) {
140 result = gate;
141 specializeId_.emplace_back(acc_.GetId(ldLexVar));
142 return true;
143 }
144 return false;
145 }
146
147 if (Bytecodes::IsCallOrAccessorOp(ecmaOpcode)) {
148 result = ldLexVar;
149 return false;
150 }
151
152 return false;
153 }
154
CheckStLexVar(GateRef gate,GateRef ldldLexVar)155 bool LexicalEnvSpecializationPass::CheckStLexVar(GateRef gate, GateRef ldldLexVar)
156 {
157 int32_t ldLevel = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(ldldLexVar, 0)));
158 int32_t ldSlot = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(ldldLexVar, 1))); // 1: slot
159
160 int32_t stLevel = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(gate, 0)));
161 int32_t stSlot = static_cast<int32_t>(acc_.TryGetValue(acc_.GetValueIn(gate, 1))); // 1: slot
162 if (stSlot != ldSlot) {
163 return false;
164 }
165 int32_t depth = 0;
166 GateRef ldEnv = acc_.GetValueIn(ldldLexVar, 2);
167 GateRef stEnv = acc_.GetValueIn(gate, 2);
168 if (caclulateDistanceToTarget(ldEnv, stEnv, depth)) {
169 return (ldLevel == stLevel + depth);
170 }
171
172 depth = 0;
173 if (caclulateDistanceToTarget(stEnv, ldEnv, depth)) {
174 return (ldLevel + depth == stLevel);
175 }
176 return false;
177 }
178
caclulateDistanceToTarget(GateRef startEnv,GateRef targetEnv,int32_t & dis)179 bool LexicalEnvSpecializationPass::caclulateDistanceToTarget(GateRef startEnv, GateRef targetEnv, int32_t &dis)
180 {
181 GateRef curEnv = startEnv;
182 while (true) {
183 if (curEnv == targetEnv) {
184 return true;
185 }
186 if (acc_.GetOpCode(curEnv) == OpCode::GET_ENV) {
187 return false;
188 }
189 if (acc_.GetOpCode(curEnv) != OpCode::JS_BYTECODE) {
190 return false;
191 }
192 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(curEnv);
193 if (ecmaOpcode != EcmaOpcode::POPLEXENV) {
194 ++dis;
195 } else {
196 --dis;
197 }
198 ASSERT(acc_.GetNumValueIn(curEnv) > 0);
199 curEnv = acc_.GetValueIn(curEnv, acc_.GetNumValueIn(curEnv) - 1); // 1: env value in
200 }
201 return false;
202 }
203
HasNotdomStLexVarOrCall(GateRef gate,GateRef next)204 void LexicalEnvSpecializationPass::HasNotdomStLexVarOrCall(GateRef gate, GateRef next)
205 {
206 ASSERT(acc_.GetOpCode(gate) == OpCode::DEPEND_SELECTOR);
207 ChunkVector<GateRef> vec(chunk_);
208 ChunkVector<GateRef> visited(chunk_);
209 vec.emplace_back(gate);
210 while (!vec.empty()) {
211 GateRef current = vec.back();
212 visited.emplace_back(current);
213 vec.pop_back();
214 if (current != next) {
215 if (acc_.GetOpCode(current) == OpCode::JS_BYTECODE) {
216 LookUpNotDomStLexVarOrCall(current, next);
217 }
218 for (size_t i = 0; i < acc_.GetDependCount(current); i++) {
219 GateRef dependIn = acc_.GetDep(current, i);
220 if (!std::count(visited.begin(), visited.end(), dependIn)) {
221 vec.emplace_back(dependIn);
222 }
223 }
224 }
225 }
226 }
227
LookUpNotDomStLexVarOrCall(GateRef current,GateRef next)228 void LexicalEnvSpecializationPass::LookUpNotDomStLexVarOrCall(GateRef current, GateRef next)
229 {
230 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(current);
231 if (Bytecodes::IsStLexVarOp(ecmaOpcode)) {
232 if (current != next) {
233 auto iter = notdomStlexvar_.find(next);
234 if (iter == notdomStlexvar_.end()) {
235 notdomStlexvar_[next] = current;
236 }
237 }
238 }
239
240 if (Bytecodes::IsCallOrAccessorOp(ecmaOpcode)) {
241 if (current != next) {
242 auto iter = notDomCall_.find(next);
243 if (iter == notDomCall_.end()) {
244 notDomCall_[next] = current;
245 }
246 }
247 }
248 }
249
HasNotDomIllegalOp(GateRef gate)250 bool LexicalEnvSpecializationPass::HasNotDomIllegalOp(GateRef gate)
251 {
252 if (HasNotDomStLexvar(gate)) {
253 return true;
254 }
255
256 if (HasNotDomCall(gate)) {
257 return true;
258 }
259
260 return false;
261 }
262
HasNotDomStLexvar(GateRef gate)263 bool LexicalEnvSpecializationPass::HasNotDomStLexvar(GateRef gate)
264 {
265 auto iter = notdomStlexvar_.find(gate);
266 if (iter != notdomStlexvar_.end()) {
267 return true;
268 }
269 return false;
270 }
271
HasNotDomCall(GateRef gate)272 bool LexicalEnvSpecializationPass::HasNotDomCall(GateRef gate)
273 {
274 auto iter = notDomCall_.find(gate);
275 if (iter != notDomCall_.end()) {
276 return true;
277 }
278 return false;
279 }
280
LookupStLexvarNode(DependChains * dependChain,GateRef gate)281 GateRef LexicalEnvSpecializationPass::LookupStLexvarNode(DependChains* dependChain, GateRef gate)
282 {
283 GateRef result = Circuit::NullGate();
284 for (auto iter = dependChain->begin(); iter != dependChain->end(); ++iter) {
285 GateRef curGate = iter.GetCurrentGate();
286 if (SearchStLexVar(curGate, gate, result)) {
287 return curGate;
288 } else {
289 if (result == gate) {
290 return Circuit::NullGate();
291 }
292 }
293 }
294 return Circuit::NullGate();
295 }
296
PrintSpecializeId()297 void LexicalEnvSpecializationPass::PrintSpecializeId()
298 {
299 if (enableLog_) {
300 LOG_COMPILER(INFO) << "\033[34m" << "================="
301 << " specialize ldlexvar gate id "
302 << "=================" << "\033[0m";
303 for (auto id : specializeId_) {
304 LOG_COMPILER(INFO) << "ldlexvar id: " << id;
305 }
306 LOG_COMPILER(INFO) << "\033[34m" << "===========================================================" << "\033[0m";
307 }
308 }
309
VisitGate(GateRef gate)310 GateRef GetEnvSpecializationPass::VisitGate(GateRef gate)
311 {
312 auto opcode = acc_.GetOpCode(gate);
313 if (opcode == OpCode::GET_ENV && acc_.GetOpCode(acc_.GetValueIn(gate, 0)) != OpCode::ARG) {
314 GateRef func = acc_.GetValueIn(gate, 0);
315 if (acc_.GetOpCode(func) == OpCode::JS_BYTECODE) {
316 return TryGetReplaceEnv(func);
317 }
318 }
319 return Circuit::NullGate();
320 }
321
322
TryGetReplaceEnv(GateRef func)323 GateRef GetEnvSpecializationPass::TryGetReplaceEnv(GateRef func)
324 {
325 ASSERT(acc_.GetNumValueIn(func) >= 1);
326 EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(func);
327 switch (ecmaOpcode) {
328 case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
329 case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
330 case EcmaOpcode::DEFINEMETHOD_IMM8_ID16_IMM8:
331 case EcmaOpcode::DEFINEMETHOD_IMM16_ID16_IMM8: {
332 GateRef replacement = acc_.GetValueIn(func, acc_.GetNumValueIn(func) - 1); // 1: last value in
333 return replacement;
334 }
335 default:
336 return Circuit::NullGate();
337 }
338 return Circuit::NullGate();
339 }
340 }