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