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