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