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