• 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/early_elimination.h"
17 
18 namespace panda::ecmascript::kungfu {
19 
Initialize()20 void EarlyElimination::Initialize()
21 {
22     dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
23     renames_.resize(circuit_->GetMaxGateId() + 1, Circuit::NullGate()); // 1: +1 for size
24     GateRef entry = acc_.GetDependRoot();
25     VisitDependEntry(entry);
26 }
27 
GetLoopDependInfo(GateRef depend)28 DependInfoNode* EarlyElimination::GetLoopDependInfo(GateRef depend)
29 {
30     auto depIn = acc_.GetDep(depend);
31     auto dependChain = GetDependChain(depIn);
32     if (dependChain == nullptr) {
33         return nullptr;
34     }
35     auto newChain = new (chunk_) DependInfoNode(chunk_);
36     newChain->CopyFrom(dependChain);
37     ChunkSet<GateRef> visited(chunk_);
38     ChunkQueue<GateRef> workList(chunk_);
39     workList.push(depend);
40     visited.insert(acc_.GetDep(depend));
41     while (!workList.empty()) {
42         auto curDep = workList.front();
43         workList.pop();
44         if (visited.count(curDep)) {
45             continue;
46         }
47         if (!acc_.IsNotWrite(curDep)) {
48             newChain = UpdateWrite(curDep, newChain);
49         }
50         visited.insert(curDep);
51         auto depCount = acc_.GetDependCount(curDep);
52         for (size_t i = 0; i < depCount; ++i) {
53             workList.push(acc_.GetDep(curDep, i));
54         }
55     }
56     return newChain;
57 }
58 
VisitDependEntry(GateRef gate)59 GateRef EarlyElimination::VisitDependEntry(GateRef gate)
60 {
61     auto empty = new (chunk_) DependInfoNode(chunk_);
62     return UpdateDependChain(gate, empty);
63 }
64 
VisitGate(GateRef gate)65 GateRef EarlyElimination::VisitGate(GateRef gate)
66 {
67     auto opcode = acc_.GetOpCode(gate);
68     switch (opcode) {
69         case OpCode::LOAD_PROPERTY:
70         case OpCode::LOAD_ELEMENT:
71         case OpCode::LOAD_ARRAY_LENGTH:
72         case OpCode::LOAD_TYPED_ARRAY_LENGTH:
73         case OpCode::TYPED_ARRAY_CHECK:
74         case OpCode::OBJECT_TYPE_CHECK:
75         case OpCode::STABLE_ARRAY_CHECK:
76         case OpCode::INDEX_CHECK:
77         case OpCode::ELEMENTSKIND_CHECK:
78         case OpCode::TYPED_CALL_CHECK:
79         case OpCode::LOAD_CONST_OFFSET:
80         case OpCode::LOAD_HCLASS_FROM_CONSTPOOL:
81         case OpCode::TYPED_BINARY_OP:
82         case OpCode::TYPED_UNARY_OP:
83         case OpCode::JSINLINETARGET_TYPE_CHECK:
84         case OpCode::PROTOTYPE_CHECK:
85         case OpCode::LOAD_GETTER:
86         case OpCode::LOAD_SETTER:
87         case OpCode::ECMA_STRING_CHECK:
88         case OpCode::BUILTIN_PROTOTYPE_HCLASS_CHECK:
89         case OpCode::TYPE_OF_CHECK:
90         case OpCode::ARRAY_CONSTRUCTOR_CHECK:
91         case OpCode::FLOAT32_ARRAY_CONSTRUCTOR_CHECK:
92         case OpCode::OBJECT_CONSTRUCTOR_CHECK:
93         case OpCode::BOOLEAN_CONSTRUCTOR_CHECK:
94         case OpCode::PROTO_CHANGE_MARKER_CHECK:
95         case OpCode::MONO_LOAD_PROPERTY_ON_PROTO:
96         case OpCode::LOAD_BUILTIN_OBJECT:
97         case OpCode::LOOK_UP_HOLDER:
98         case OpCode::IS_CALLABLE_CHECK:
99             return TryEliminateGate(gate);
100         case OpCode::STATE_SPLIT:
101             if (enableFrameStateElimination_) {
102                 return TryEliminateFrameState(gate);
103             }
104             break;
105         case OpCode::DEPEND_SELECTOR:
106             return TryEliminateDependSelector(gate);
107         default:
108             if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
109                 return TryEliminateOther(gate);
110             }
111             break;
112     }
113     return Circuit::NullGate();
114 }
115 
TryEliminateOther(GateRef gate)116 GateRef EarlyElimination::TryEliminateOther(GateRef gate)
117 {
118     ASSERT(acc_.GetDependCount(gate) >= 1);
119     auto depIn = acc_.GetDep(gate);
120     auto dependChain = GetDependChain(depIn);
121     if (dependChain == nullptr) {
122         return Circuit::NullGate();
123     }
124 
125     if (!acc_.IsNotWrite(gate)) {
126         dependChain = UpdateWrite(gate, dependChain);
127     }
128 
129     return UpdateDependChain(gate, dependChain);
130 }
131 
TryEliminateGate(GateRef gate)132 GateRef EarlyElimination::TryEliminateGate(GateRef gate)
133 {
134     ASSERT(acc_.GetDependCount(gate) == 1);
135     auto depIn = acc_.GetDep(gate);
136     auto dependChain = GetDependChain(depIn);
137     // dependChain is null
138     if (dependChain == nullptr) {
139         return Circuit::NullGate();
140     }
141 
142     if (!acc_.IsNotWrite(gate)) {
143         dependChain = UpdateWrite(gate, dependChain);
144         return UpdateDependChain(gate, dependChain);
145     }
146 
147     auto numIns = acc_.GetNumValueIn(gate);
148     for (size_t i = 0; i < numIns; ++i) {
149         auto origin = acc_.GetValueIn(gate, i);
150         auto checkd = dependChain->LookupCheckedNode(this, origin);
151         if (origin != checkd) {
152             acc_.ReplaceValueIn(gate, checkd, i);
153         }
154     }
155 
156     // lookup gate, replace
157     auto preGate = dependChain->LookupNode(this, gate);
158     if (preGate != Circuit::NullGate()) {
159         return preGate;
160     }
161     // update gate, for others elimination
162     dependChain = dependChain->UpdateNode(gate);
163     return UpdateDependChain(gate, dependChain);
164 }
165 
TryEliminateFrameState(GateRef gate)166 GateRef EarlyElimination::TryEliminateFrameState(GateRef gate)
167 {
168     ASSERT(acc_.GetOpCode(gate) == OpCode::STATE_SPLIT);
169     auto depIn = acc_.GetDep(gate);
170     auto dependChain = GetDependChain(depIn);
171     // dependChain is null
172     if (dependChain == nullptr) {
173         return Circuit::NullGate();
174     }
175     // lookup gate, replace
176     auto preFrame = dependChain->LookupFrameState();
177     auto curFrame = acc_.GetFrameState(gate);
178     if ((preFrame != Circuit::NullGate()) && (preFrame != curFrame) &&
179         acc_.GetFrameState(preFrame) == acc_.GetFrameState(curFrame)) {
180         acc_.UpdateAllUses(curFrame, preFrame);
181         auto frameValues = acc_.GetValueIn(curFrame, 1); // 1: frameValues
182         acc_.DeleteGate(frameValues);
183         acc_.DeleteGate(curFrame);
184         return depIn;
185     } else {
186         dependChain = dependChain->UpdateFrameState(curFrame);
187     }
188     // update gate, for others elimination
189 
190     return UpdateDependChain(gate, dependChain);
191 }
192 
TryEliminateDependSelector(GateRef gate)193 GateRef EarlyElimination::TryEliminateDependSelector(GateRef gate)
194 {
195     auto state = acc_.GetState(gate);
196     if (acc_.IsLoopHead(state)) {
197         auto dependChain = GetLoopDependInfo(gate);
198         if (dependChain == nullptr) {
199             return Circuit::NullGate();
200         }
201         return UpdateDependChain(gate, dependChain);
202     }
203 
204     auto dependCount = acc_.GetDependCount(gate);
205     for (size_t i = 0; i < dependCount; ++i) {
206         auto depend = acc_.GetDep(gate, i);
207         auto dependChain = GetDependChain(depend);
208         if (dependChain == nullptr) {
209             return Circuit::NullGate();
210         }
211     }
212 
213     // all depend done.
214     auto depend = acc_.GetDep(gate);
215     auto dependChain = GetDependChain(depend);
216     DependInfoNode* copy = new (chunk_) DependInfoNode(chunk_);
217     copy->CopyFrom(dependChain);
218     for (size_t i = 1; i < dependCount; ++i) { // 1: second in
219         auto dependIn = acc_.GetDep(gate, i);
220         auto tempChain = GetDependChain(dependIn);
221         copy->Merge(this, tempChain);
222     }
223     return UpdateDependChain(gate, copy);
224 }
225 
UpdateDependChain(GateRef gate,DependInfoNode * dependChain)226 GateRef EarlyElimination::UpdateDependChain(GateRef gate, DependInfoNode* dependChain)
227 {
228     ASSERT(dependChain != nullptr);
229     auto oldDependChain = GetDependChain(gate);
230     if (dependChain->Equals(oldDependChain)) {
231         return Circuit::NullGate();
232     }
233     dependChains_[acc_.GetId(gate)] = dependChain;
234     return gate;
235 }
236 
UpdateWrite(GateRef gate,DependInfoNode * dependInfo)237 DependInfoNode* EarlyElimination::UpdateWrite(GateRef gate, DependInfoNode* dependInfo)
238 {
239     if (!enableMemoryAnalysis_) {
240         return new (chunk_) DependInfoNode(chunk_);
241     }
242     auto op = acc_.GetOpCode(gate);
243     switch (op) {
244         case OpCode::STORE_PROPERTY:
245         case OpCode::STORE_PROPERTY_NO_BARRIER:
246         case OpCode::STORE_CONST_OFFSET:
247         case OpCode::STORE_ELEMENT:
248         case OpCode::STORE_MEMORY:
249         case OpCode::MIGRATE_ARRAY_WITH_KIND:
250         case OpCode::MONO_STORE_PROPERTY_LOOK_UP_PROTO:
251         case OpCode::MONO_STORE_PROPERTY:
252             return dependInfo->UpdateStoreProperty(this, gate);
253         default:
254             return new (chunk_) DependInfoNode(chunk_);
255     }
256 }
257 
MayAccessOneMemory(GateRef lhs,GateRef rhs)258 bool EarlyElimination::MayAccessOneMemory(GateRef lhs, GateRef rhs)
259 {
260     auto rop = acc_.GetOpCode(rhs);
261     auto lop = acc_.GetOpCode(lhs);
262     switch (rop) {
263         case OpCode::STORE_MEMORY:
264             ASSERT(acc_.GetMemoryType(rhs) == MemoryType::ELEMENT_TYPE);
265             return acc_.GetOpCode(lhs) == OpCode::LOAD_ELEMENT;
266         case OpCode::MIGRATE_ARRAY_WITH_KIND: {
267             if (lop == OpCode::LOAD_ELEMENT) {
268                 GateRef lopValueIn = acc_.GetValueIn(lhs, 0); // loadelement receiver
269                 GateRef ropValueIn = acc_.GetValueIn(rhs, 0); // migrate receiver
270                 return lopValueIn == ropValueIn;
271             }
272             return false;
273         }
274         case OpCode::STORE_ELEMENT: {
275             if (lop == OpCode::LOAD_ELEMENT) {
276                 bool lopIsTypedArray = acc_.TypedOpIsTypedArray(lhs, TypedOpKind::TYPED_LOAD_OP);
277                 bool ropIsTypedArray = acc_.TypedOpIsTypedArray(rhs, TypedOpKind::TYPED_STORE_OP);
278                 return lopIsTypedArray == ropIsTypedArray;
279             }
280             return false;
281         }
282         case OpCode::STORE_PROPERTY:
283         case OpCode::STORE_PROPERTY_NO_BARRIER: {
284             if (lop == OpCode::LOAD_PROPERTY) {
285                 auto loff = acc_.GetValueIn(lhs, 1);
286                 auto roff = acc_.GetValueIn(rhs, 1);
287                 ASSERT(acc_.GetOpCode(loff) == OpCode::CONSTANT);
288                 ASSERT(acc_.GetOpCode(roff) == OpCode::CONSTANT);
289                 return loff == roff;
290             } else if (lop == OpCode::PROTOTYPE_CHECK) {
291                 auto lindex = acc_.GetHClassIndex(lhs);
292                 auto rindex = acc_.GetHClassIndex(rhs);
293                 return (lindex == 0) || (rindex == 0) || (lindex != rindex);
294             }
295             break;
296         }
297         case OpCode::STORE_CONST_OFFSET: {
298             if (lop == OpCode::LOAD_CONST_OFFSET) {
299                 auto loff = acc_.GetOffset(lhs);
300                 auto roff = acc_.GetOffset(rhs);
301                 return loff == roff;
302             }
303             break;
304         }
305         case OpCode::LOAD_PROPERTY:
306         case OpCode::MONO_LOAD_PROPERTY_ON_PROTO:
307             if (acc_.GetGateType(lhs).Value() != acc_.GetGateType(rhs).Value()) {
308                 return false;
309             }
310             break;
311         default:
312             break;
313     }
314     return false;
315 }
316 
CompareOrder(GateRef lhs,GateRef rhs)317 bool EarlyElimination::CompareOrder(GateRef lhs, GateRef rhs)
318 {
319     return visitor_->GetGateOrder(lhs) < visitor_->GetGateOrder(rhs);
320 }
321 
CheckReplacement(GateRef lhs,GateRef rhs)322 bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
323 {
324     if (!acc_.MetaDataEqu(lhs, rhs)) {
325         if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) {
326             return false;
327         }
328     }
329 
330     size_t valueCount = acc_.GetNumValueIn(lhs);
331     for (size_t i = 0; i < valueCount; i++) {
332         if (Rename(acc_.GetValueIn(lhs, i)) != Rename(acc_.GetValueIn(rhs, i))) {
333             return false;
334         }
335     }
336 
337     auto opcode = acc_.GetOpCode(lhs);
338     switch (opcode) {
339         case OpCode::LOAD_ELEMENT: {
340             if (acc_.GetTypedLoadOp(lhs) != acc_.GetTypedLoadOp(rhs)) {
341                 return false;
342             }
343             break;
344         }
345         case OpCode::TYPED_BINARY_OP: {
346             auto lhsOp = acc_.GetTypedBinaryOp(lhs);
347             auto rhsOp = acc_.GetTypedBinaryOp(rhs);
348             if (lhsOp != rhsOp) {
349                 return false;
350             }
351             break;
352         }
353         case OpCode::TYPED_UNARY_OP: {
354             auto lhsOp = acc_.GetTypedUnAccessor(lhs).GetTypedUnOp();
355             auto rhsOp = acc_.GetTypedUnAccessor(rhs).GetTypedUnOp();
356             if (lhsOp != rhsOp) {
357                 return false;
358             }
359             break;
360         }
361         case OpCode::TYPED_ARRAY_CHECK: {
362             TypedArrayMetaDataAccessor lhsAccessor = acc_.GetTypedArrayMetaDataAccessor(lhs);
363             TypedArrayMetaDataAccessor rhsAccessor = acc_.GetTypedArrayMetaDataAccessor(rhs);
364             if ((lhsAccessor.GetParamType() != rhsAccessor.GetParamType()) ||
365                 (lhsAccessor.GetOnHeapMode() != rhsAccessor.GetOnHeapMode())) {
366                 return false;
367             }
368             break;
369         }
370         case OpCode::TYPE_OF_CHECK: {
371             if (acc_.GetParamType(lhs) != acc_.GetParamType(rhs)) {
372                 return false;
373             }
374             break;
375         }
376         case OpCode::PROTOTYPE_CHECK: {
377             if (acc_.GetHClassIndex(lhs) != acc_.GetHClassIndex(rhs)) {
378                 return false;
379             }
380             break;
381         }
382         case OpCode::LOAD_CONST_OFFSET: {
383             if (acc_.GetOffset(lhs) != acc_.GetOffset(rhs)) {
384                 return false;
385             }
386             if (acc_.GetMachineType(lhs) != acc_.GetMachineType(rhs)) {
387                 return false;
388             }
389             if (acc_.GetMemoryAttribute(lhs).Value() != acc_.GetMemoryAttribute(rhs).Value()) {
390                 return false;
391             }
392             break;
393         }
394         case OpCode::LOAD_HCLASS_FROM_CONSTPOOL: {
395             if (acc_.GetIndex(lhs) != acc_.GetIndex(rhs)) {
396                 return false;
397             }
398             break;
399         }
400         case OpCode::JSINLINETARGET_TYPE_CHECK: {
401             if (acc_.GetFuncGT(lhs) != acc_.GetFuncGT(rhs)) {
402                 return false;
403             }
404             break;
405         }
406         case OpCode::ARRAY_CONSTRUCTOR_CHECK:
407         case OpCode::FLOAT32_ARRAY_CONSTRUCTOR_CHECK:
408         case OpCode::OBJECT_CONSTRUCTOR_CHECK:
409         case OpCode::BOOLEAN_CONSTRUCTOR_CHECK: {
410             if (acc_.GetValueIn(lhs) != acc_.GetValueIn(rhs)) {
411                 return false;
412             }
413             break;
414         }
415         case OpCode::LOAD_BUILTIN_OBJECT: {
416             if (acc_.GetIndex(lhs) != acc_.GetIndex(rhs)) {
417                 return false;
418             }
419             break;
420         }
421         case OpCode::STABLE_ARRAY_CHECK: {
422             ArrayMetaDataAccessor lhsAccessor = acc_.GetArrayMetaDataAccessor(lhs);
423             ArrayMetaDataAccessor rhsAccessor = acc_.GetArrayMetaDataAccessor(rhs);
424             if (lhsAccessor.GetMode() != rhsAccessor.GetMode()) {
425                 return false;
426             }
427             break;
428         }
429         default:
430             break;
431     }
432     return true;
433 }
434 
CheckRenameReplacement(GateRef lhs,GateRef rhs)435 bool EarlyElimination::CheckRenameReplacement(GateRef lhs, GateRef rhs)
436 {
437     auto opcode = acc_.GetOpCode(lhs);
438     switch (opcode) {
439         case OpCode::INDEX_CHECK: {
440             auto index = acc_.GetValueIn(lhs, 1);
441             if (Rename(index) == Rename(rhs)) {
442                 return true;
443             }
444             break;
445         }
446         default:
447             break;
448     }
449     return false;
450 }
451 
Rename(GateRef gate)452 GateRef EarlyElimination::Rename(GateRef gate)
453 {
454     ChunkStack<GateRef> gateStack(chunk_);
455     while (true) {
456         auto op = acc_.GetOpCode(gate);
457         bool renamed = false;
458         switch (op) {
459             case OpCode::INDEX_CHECK: {
460                 GateRef ans = renames_[acc_.GetId(gate)];
461                 if (ans == Circuit::NullGate()) {
462                     renamed = true;
463                     gateStack.push(gate);
464                     gate = acc_.GetValueIn(gate, 1);
465                 } else {
466                     gate = ans;
467                 }
468                 break;
469             }
470             default:
471                 break;
472         }
473         if (!renamed) {
474             break;
475         }
476     }
477     while (!gateStack.empty()) {
478         auto topGate = gateStack.top();
479         gateStack.pop();
480         renames_[acc_.GetId(topGate)] = gate;
481     }
482     return gate;
483 }
484 
Merge(EarlyElimination * elimination,DependInfoNode * that)485 void DependInfoNode::Merge(EarlyElimination* elimination, DependInfoNode* that)
486 {
487     auto siz = this->size_; // size of lhs-chain
488     auto lhs = this->head_;
489     auto rhs = that->head_;
490     ChunkStack<GateRef> gateStack(chunk_);
491     while (lhs != rhs) {
492         if (lhs == nullptr || rhs == nullptr) {
493             siz = 0;
494             lhs = nullptr;
495             break;
496         } else if (lhs->gate == rhs->gate) {
497             gateStack.push(lhs->gate);
498             siz--;
499             lhs = lhs->next;
500             rhs = rhs->next;
501         } else if (elimination->CompareOrder(lhs->gate, rhs->gate)) {
502             rhs = rhs->next;
503         } else {
504             siz--;
505             lhs = lhs->next;
506         }
507     }
508     // lhs : common suffix of lhs-chain and rhs-chain
509     this->head_ = lhs;
510     this->size_ = siz;
511     while (!gateStack.empty()) {
512         Node* node = chunk_->New<Node>(gateStack.top(), head_);
513         gateStack.pop();
514         this->size_++;
515         this->head_ = node;
516     }
517     if (this->frameState_ != that->frameState_) {
518         this->frameState_ = Circuit::NullGate();
519     }
520 }
521 
Equals(DependInfoNode * that)522 bool DependInfoNode::Equals(DependInfoNode* that)
523 {
524     if (that == nullptr) {
525         return false;
526     }
527     if (size_ != that->size_ || frameState_ != that->frameState_) {
528         return false;
529     }
530     auto lhs = this->head_;
531     auto rhs = that->head_;
532     while (lhs != rhs) {
533         if (lhs->gate != rhs->gate) {
534             return false;
535         }
536         lhs = lhs->next;
537         rhs = rhs->next;
538     }
539     return true;
540 }
541 
LookupFrameState() const542 GateRef DependInfoNode::LookupFrameState() const
543 {
544     return frameState_;
545 }
546 
LookupCheckedNode(EarlyElimination * elimination,GateRef gate)547 GateRef DependInfoNode::LookupCheckedNode(EarlyElimination* elimination, GateRef gate)
548 {
549     for (Node* node = head_; node != nullptr; node = node->next) {
550         if (elimination->CheckRenameReplacement(node->gate, gate)) {
551             return node->gate;
552         }
553     }
554     return gate;
555 }
556 
GetGates(std::vector<GateRef> & gates) const557 void DependInfoNode::GetGates(std::vector<GateRef>& gates) const
558 {
559     ChunkStack<GateRef> st(chunk_);
560     for (Node* node = head_; node != nullptr; node = node->next) {
561         st.push(node->gate);
562     }
563     while (!st.empty()) {
564         gates.emplace_back(st.top());
565         st.pop();
566     }
567 }
568 
LookupNode(EarlyElimination * elimination,GateRef gate)569 GateRef DependInfoNode::LookupNode(EarlyElimination* elimination, GateRef gate)
570 {
571     for (Node* node = head_; node != nullptr; node = node->next) {
572         if (elimination->CheckReplacement(node->gate, gate)) {
573             return node->gate;
574         }
575     }
576     return Circuit::NullGate();
577 }
578 
UpdateNode(GateRef gate)579 DependInfoNode* DependInfoNode::UpdateNode(GateRef gate)
580 {
581     // assign node->next to head
582     Node* node = chunk_->New<Node>(gate, head_);
583     DependInfoNode* that = new (chunk_) DependInfoNode(chunk_);
584     // assign head to node
585     that->head_ = node;
586     that->size_ = size_ + 1;
587     that->frameState_ = frameState_;
588     return that;
589 }
590 
UpdateFrameState(GateRef framestate)591 DependInfoNode* DependInfoNode::UpdateFrameState(GateRef framestate)
592 {
593     // assign node->next to head
594     DependInfoNode* that = new (chunk_) DependInfoNode(chunk_);
595     // assign head to node
596     that->head_ = head_;
597     that->size_ = size_;
598     that->frameState_ = framestate;
599     return that;
600 }
601 
UpdateStoreProperty(EarlyElimination * elimination,GateRef gate)602 DependInfoNode* DependInfoNode::UpdateStoreProperty(EarlyElimination* elimination, GateRef gate)
603 {
604     DependInfoNode* that = new (chunk_) DependInfoNode(chunk_);
605     ChunkStack<GateRef> gateStack(chunk_);
606     for (Node* node = head_; node != nullptr; node = node->next) {
607         if (!elimination->MayAccessOneMemory(node->gate, gate)) {
608             gateStack.push(node->gate);
609         }
610     }
611     while (!gateStack.empty()) {
612         that = that->UpdateNode(gateStack.top());
613         gateStack.pop();
614     }
615     return that;
616 }
617 }  // namespace panda::ecmascript::kungfu
618