• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/builtins/containers_stub_builder.h"
17 #include "ecmascript/compiler/builtins/containers_vector_stub_builder.h"
18 
19 namespace panda::ecmascript::kungfu {
20 // common IR for containers apis that use function call
ContainersCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)21 void ContainersStubBuilder::ContainersCommonFuncCall(GateRef glue, GateRef thisValue,
22     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
23 {
24     auto env = GetEnvironment();
25     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
26     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
27     DEFVARIABLE(key, VariableType::INT64(), Int64(0));
28     DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
29     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
30     DEFVARIABLE(k, VariableType::INT32(), Int32(0));
31     Label valueIsJSAPIVector(env);
32     Label valueNotJSAPIVector(env);
33     Label objIsJSProxy(env);
34     Label objNotJSProxy(env);
35     Label objIsJSAPIVector(env);
36     Label thisArgUndefined(env);
37     Label thisArgNotUndefined(env);
38     Label callbackUndefined(env);
39     Label callbackNotUndefined(env);
40     Label nextCount(env);
41     Label loopHead(env);
42     Label loopEnd(env);
43     Label next(env);
44     Label afterLoop(env);
45     GateRef callbackFnHandle;
46     Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
47     Bind(&valueNotJSAPIVector);
48     {
49         Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
50         Bind(&objIsJSProxy);
51         {
52             GateRef tempObj = GetTarget(*thisObj);
53             Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath);
54             Bind(&objIsJSAPIVector);
55             {
56                 thisObj = tempObj;
57                 Jump(&valueIsJSAPIVector);
58             }
59         }
60         Bind(&objNotJSProxy);
61         Jump(slowPath);
62     }
63     Bind(&valueIsJSAPIVector);
64     {
65         Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
66         Bind(&callbackUndefined);
67         Jump(slowPath);
68         Bind(&callbackNotUndefined);
69         {
70             Label isCall(env);
71             Label notCall(env);
72             Label isHeapObj(env);
73             callbackFnHandle = GetCallArg0(numArgs);
74             Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
75             Bind(&isHeapObj);
76             Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
77             Bind(&notCall);
78             Jump(slowPath);
79             Bind(&isCall);
80             {
81                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
82                 Bind(&thisArgUndefined);
83                 Jump(&nextCount);
84                 Bind(&thisArgNotUndefined);
85                 thisArg = GetCallArg1(numArgs);
86                 Jump(&nextCount);
87             }
88         }
89     }
90     Bind(&nextCount);
91     {
92         length = ContainerGetSize(*thisObj, type);
93         Jump(&loopHead);
94         LoopBegin(&loopHead);
95         {
96             Label lenChange(env);
97             Label hasException(env);
98             Label notHasException(env);
99             Label setValue(env);
100             Branch(Int32LessThan(*k, *length), &next, &afterLoop);
101             Bind(&next);
102             {
103                 kValue = ContainerGetValue(*thisObj, *k, type);
104                 if (IsPlainArray(type)) {
105                     key = PlainArrayGetKey(*thisObj, *k);
106                 } else {
107                     key = IntToTaggedInt(*k);
108                 }
109                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
110                     Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj });
111                 Branch(HasPendingException(glue), &hasException, &notHasException);
112                 Bind(&hasException);
113                 {
114                     result->WriteVariable(retValue);
115                     Jump(exit);
116                 }
117                 Bind(&notHasException);
118                 GateRef tempLen = ContainerGetSize(*thisObj, type);
119                 Branch(Int32NotEqual(tempLen, *length), &lenChange, &setValue);
120                 Bind(&lenChange);
121                 length = tempLen;
122                 Branch(Int32GreaterThanOrEqual(*k, *length), &afterLoop, &setValue);
123                 Bind(&setValue);
124                 if (IsReplaceAllElements(type)) {
125                     ContainerSet(glue, *thisObj, *k, retValue, type);
126                 }
127                 Jump(&loopEnd);
128             }
129         }
130         Bind(&loopEnd);
131         k = Int32Add(*k, Int32(1));
132         LoopEnd(&loopHead);
133     }
134     Bind(&afterLoop);
135     Jump(exit);
136 }
137 
QueueCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)138 void ContainersStubBuilder::QueueCommonFuncCall(GateRef glue, GateRef thisValue,
139     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
140 {
141     auto env = GetEnvironment();
142     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
143     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
144     DEFVARIABLE(key, VariableType::INT64(), Int64(0));
145     DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
146     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
147     DEFVARIABLE(k, VariableType::INT32(), Int32(0));
148     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
149     Label valueIsJSAPIVector(env);
150     Label valueNotJSAPIVector(env);
151     Label objIsJSProxy(env);
152     Label objNotJSProxy(env);
153     Label objIsJSAPIVector(env);
154     Label thisArgUndefined(env);
155     Label thisArgNotUndefined(env);
156     Label callbackUndefined(env);
157     Label callbackNotUndefined(env);
158     Label nextCount(env);
159     Label loopHead(env);
160     Label loopEnd(env);
161     Label next(env);
162     Label afterLoop(env);
163     GateRef callbackFnHandle;
164     Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
165     Bind(&valueNotJSAPIVector);
166     {
167         Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
168         Bind(&objIsJSProxy);
169         {
170             GateRef tempObj = GetTarget(*thisObj);
171             Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath);
172             Bind(&objIsJSAPIVector);
173             {
174                 thisObj = tempObj;
175                 Jump(&valueIsJSAPIVector);
176             }
177         }
178         Bind(&objNotJSProxy);
179         Jump(slowPath);
180     }
181     Bind(&valueIsJSAPIVector);
182     {
183         Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
184         Bind(&callbackUndefined);
185         Jump(slowPath);
186         Bind(&callbackNotUndefined);
187         {
188             Label isCall(env);
189             Label notCall(env);
190             Label isHeapObj(env);
191             callbackFnHandle = GetCallArg0(numArgs);
192             Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
193             Bind(&isHeapObj);
194             Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
195             Bind(&notCall);
196             Jump(slowPath);
197             Bind(&isCall);
198             {
199                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
200                 Bind(&thisArgUndefined);
201                 Jump(&nextCount);
202                 Bind(&thisArgNotUndefined);
203                 thisArg = GetCallArg1(numArgs);
204                 Jump(&nextCount);
205             }
206         }
207     }
208     Bind(&nextCount);
209     {
210         length = ContainerGetSize(*thisObj, type);
211         Jump(&loopHead);
212         LoopBegin(&loopHead);
213         {
214             Label lenChange(env);
215             Label hasException(env);
216             Label notHasException(env);
217             Label setValue(env);
218             Branch(Int32LessThan(*k, *length), &next, &afterLoop);
219             Bind(&next);
220             {
221                 kValue = ContainerGetValue(*thisObj, *index, type);
222                 index = QueueGetNextPosition(*thisObj, *index);
223                 key = IntToTaggedInt(*k);
224                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
225                     Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj });
226                 Branch(HasPendingException(glue), &hasException, &notHasException);
227                 Bind(&hasException);
228                 {
229                     result->WriteVariable(retValue);
230                     Jump(exit);
231                 }
232                 Bind(&notHasException);
233                 Jump(&loopEnd);
234             }
235         }
236         Bind(&loopEnd);
237         k = Int32Add(*k, Int32(1));
238         LoopEnd(&loopHead);
239     }
240     Bind(&afterLoop);
241     Jump(exit);
242 }
243 
DequeCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)244 void ContainersStubBuilder::DequeCommonFuncCall(GateRef glue, GateRef thisValue,
245     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
246 {
247     auto env = GetEnvironment();
248     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
249     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
250     DEFVARIABLE(key, VariableType::INT64(), Int64(0));
251     DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
252     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
253     DEFVARIABLE(first, VariableType::INT32(), Int32(0));
254     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
255     Label valueIsJSAPIVector(env);
256     Label valueNotJSAPIVector(env);
257     Label objIsJSProxy(env);
258     Label objNotJSProxy(env);
259     Label objIsJSAPIVector(env);
260     Label thisArgUndefined(env);
261     Label thisArgNotUndefined(env);
262     Label callbackUndefined(env);
263     Label callbackNotUndefined(env);
264     Label nextCount(env);
265     Label loopHead(env);
266     Label loopEnd(env);
267     Label next(env);
268     Label afterLoop(env);
269     GateRef callbackFnHandle;
270     Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
271     Bind(&valueNotJSAPIVector);
272     {
273         Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
274         Bind(&objIsJSProxy);
275         {
276             GateRef tempObj = GetTarget(*thisObj);
277             Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath);
278             Bind(&objIsJSAPIVector);
279             {
280                 thisObj = tempObj;
281                 Jump(&valueIsJSAPIVector);
282             }
283         }
284         Bind(&objNotJSProxy);
285         Jump(slowPath);
286     }
287     Bind(&valueIsJSAPIVector);
288     {
289         Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
290         Bind(&callbackUndefined);
291         Jump(slowPath);
292         Bind(&callbackNotUndefined);
293         {
294             Label isCall(env);
295             Label notCall(env);
296             Label isHeapObj(env);
297             callbackFnHandle = GetCallArg0(numArgs);
298             Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
299             Bind(&isHeapObj);
300             Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
301             Bind(&notCall);
302             Jump(slowPath);
303             Bind(&isCall);
304             {
305                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
306                 Bind(&thisArgUndefined);
307                 Jump(&nextCount);
308                 Bind(&thisArgNotUndefined);
309                 thisArg = GetCallArg1(numArgs);
310                 Jump(&nextCount);
311             }
312         }
313     }
314     Bind(&nextCount);
315     {
316         ContainersDequeStubBuilder dequeBuilder(this);
317         first = dequeBuilder.GetFirst(*thisObj);
318         GateRef last = dequeBuilder.GetLast(*thisObj);
319         GateRef capacity = dequeBuilder.GetElementsLength(*thisObj);
320         Jump(&loopHead);
321         LoopBegin(&loopHead);
322         {
323             Label lenChange(env);
324             Label hasException(env);
325             Label notHasException(env);
326             Label setValue(env);
327             Branch(Int32NotEqual(*first, last), &next, &afterLoop);
328             Bind(&next);
329             {
330                 kValue = ContainerGetValue(*thisObj, *index, type);
331                 key = IntToTaggedInt(*index);
332                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
333                     Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj });
334                 Branch(HasPendingException(glue), &hasException, &notHasException);
335                 Bind(&hasException);
336                 {
337                     result->WriteVariable(retValue);
338                     Jump(exit);
339                 }
340                 Bind(&notHasException);
341                 Jump(&loopEnd);
342             }
343         }
344         Bind(&loopEnd);
345         first = Int32Mod(Int32Add(*first, Int32(1)), capacity);
346         index = Int32Add(*index, Int32(1));
347         LoopEnd(&loopHead);
348     }
349     Bind(&afterLoop);
350     Jump(exit);
351 }
352 
ContainersLightWeightCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)353 void ContainersStubBuilder::ContainersLightWeightCall(GateRef glue, GateRef thisValue,
354     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
355 {
356     auto env = GetEnvironment();
357     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
358     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
359     DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
360     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
361     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
362     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
363     Label valueIsJSAPILightWeight(env);
364     Label valueNotJSAPILightWeight(env);
365     Label objIsJSProxy(env);
366     Label objNotJSProxy(env);
367     Label objIsJSAPILightWeight(env);
368     Label thisArgUndefined(env);
369     Label thisArgNotUndefined(env);
370     Label callbackUndefined(env);
371     Label callbackNotUndefined(env);
372     Label nextCount(env);
373     Label loopHead(env);
374     Label loopEnd(env);
375     Label next(env);
376     Label afterLoop(env);
377     GateRef callbackFnHandle;
378     Branch(IsContainer(*thisObj, type), &valueIsJSAPILightWeight, &valueNotJSAPILightWeight);
379     Bind(&valueNotJSAPILightWeight);
380     {
381         Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
382         Bind(&objIsJSProxy);
383         {
384             GateRef tempObj = GetTarget(*thisObj);
385             Branch(IsContainer(tempObj, type), &objIsJSAPILightWeight, slowPath);
386             Bind(&objIsJSAPILightWeight);
387             {
388                 thisObj = tempObj;
389                 Jump(&valueIsJSAPILightWeight);
390             }
391         }
392         Bind(&objNotJSProxy);
393         Jump(slowPath);
394     }
395     Bind(&valueIsJSAPILightWeight);
396     {
397         Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
398         Bind(&callbackUndefined);
399         Jump(slowPath);
400         Bind(&callbackNotUndefined);
401         {
402             Label isCall(env);
403             Label notCall(env);
404             Label isHeapObj(env);
405             callbackFnHandle = GetCallArg0(numArgs);
406             Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
407             Bind(&isHeapObj);
408             Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
409             Bind(&notCall);
410             Jump(slowPath);
411             Bind(&isCall);
412             {
413                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
414                 Bind(&thisArgUndefined);
415                 Jump(&nextCount);
416                 Bind(&thisArgNotUndefined);
417                 thisArg = GetCallArg1(numArgs);
418                 Jump(&nextCount);
419             }
420         }
421     }
422     Bind(&nextCount);
423     {
424         length = ContainerGetSize(*thisObj, type);
425         Jump(&loopHead);
426         LoopBegin(&loopHead);
427         {
428             Label lenChange(env);
429             Label hasException(env);
430             Label notHasException(env);
431             Branch(Int32LessThan(*index, *length), &next, &afterLoop);
432             Bind(&next);
433             {
434                 value = ContainerGetValue(*thisObj, *index, type);
435                 key = ContainerGetKey(*thisObj, *index, type);
436                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
437                     Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj });
438                 Branch(HasPendingException(glue), &hasException, &notHasException);
439                 Bind(&hasException);
440                 {
441                     result->WriteVariable(retValue);
442                     Jump(exit);
443                 }
444                 Bind(&notHasException);
445                 GateRef currentLen = ContainerGetSize(*thisObj, type);
446                 Branch(Int32NotEqual(currentLen, *length), &lenChange, &loopEnd);
447                 Bind(&lenChange);
448                 length = currentLen;
449                 Jump(&loopEnd);
450             }
451         }
452         Bind(&loopEnd);
453         index = Int32Add(*index, Int32(1));
454         LoopEnd(&loopHead);
455     }
456     Bind(&afterLoop);
457     Jump(exit);
458 }
459 
ContainersHashCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)460 void ContainersStubBuilder::ContainersHashCall(GateRef glue, GateRef thisValue,
461     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
462 {
463     auto env = GetEnvironment();
464     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
465     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
466     DEFVARIABLE(node, VariableType::JS_ANY(), Undefined());
467     DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
468     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
469     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
470     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
471     Label valueIsJSAPIHash(env);
472     Label valueNotJSAPIHash(env);
473     Label objIsJSProxy(env);
474     Label objNotJSProxy(env);
475     Label objIsJSAPIHash(env);
476     Label thisArgUndefined(env);
477     Label thisArgNotUndefined(env);
478     Label callbackUndefined(env);
479     Label callbackNotUndefined(env);
480     Label nextCount(env);
481     Label nodeNotHole(env);
482     Label nodeIsLinked(env);
483     Label nodeIsRBTree(env);
484     Label loopLinked(env);
485     Label loopHead(env);
486     Label loopEnd(env);
487     Label next(env);
488     Label afterLoop(env);
489     GateRef callbackFnHandle;
490     Branch(IsContainer(*thisObj, type), &valueIsJSAPIHash, &valueNotJSAPIHash);
491     Bind(&valueNotJSAPIHash);
492     {
493         Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
494         Bind(&objIsJSProxy);
495         {
496             GateRef tempObj = GetTarget(*thisObj);
497             Branch(IsContainer(tempObj, type), &objIsJSAPIHash, slowPath);
498             Bind(&objIsJSAPIHash);
499             {
500                 thisObj = tempObj;
501                 Jump(&valueIsJSAPIHash);
502             }
503         }
504         Bind(&objNotJSProxy);
505         Jump(slowPath);
506     }
507     Bind(&valueIsJSAPIHash);
508     {
509         Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
510         Bind(&callbackUndefined);
511         Jump(slowPath);
512         Bind(&callbackNotUndefined);
513         {
514             Label isCall(env);
515             Label notCall(env);
516             Label isHeapObj(env);
517             callbackFnHandle = GetCallArg0(numArgs);
518             Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, &notCall);
519             Bind(&isHeapObj);
520             Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
521             Bind(&notCall);
522             Jump(slowPath);
523             Bind(&isCall);
524             {
525                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
526                 Bind(&thisArgUndefined);
527                 Jump(&nextCount);
528                 Bind(&thisArgNotUndefined);
529                 thisArg = GetCallArg1(numArgs);
530                 Jump(&nextCount);
531             }
532         }
533     }
534     Bind(&nextCount);
535     {
536         length = ContainerGetSize(*thisObj, type);
537         Jump(&loopHead);
538         LoopBegin(&loopHead);
539         {
540             Label hasExceptionLinked(env);
541             Label notHasExceptionLinked(env);
542             Label hasExceptionRBTree(env);
543             Label notHasExceptionRBTree(env);
544             Branch(Int32LessThan(*index, *length), &next, &afterLoop);
545             Bind(&next);
546             {
547                 node = ContainerGetNode(*thisObj, *index, type);
548                 Branch(TaggedIsHole(*node), &loopEnd, &nodeNotHole);
549                 Bind(&nodeNotHole);
550                 Branch(IsLinkedNode(*node), &nodeIsLinked, &nodeIsRBTree);
551                 LoopBegin(&nodeIsLinked);
552                 {
553                     value = Load(VariableType::JS_POINTER(), *node, IntPtr(
554                         type == ContainersType::HASHSET_FOREACH ? LinkedNode::KEY_OFFSET : LinkedNode::VALUE_OFFSET));
555                     key = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::KEY_OFFSET));
556                     GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
557                         Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
558                         { *thisArg, *value, *key, *thisObj });
559                     Branch(HasPendingException(glue), &hasExceptionLinked, &notHasExceptionLinked);
560                     Bind(&hasExceptionLinked);
561                     {
562                         result->WriteVariable(retValue);
563                         Jump(exit);
564                     }
565                     Bind(&notHasExceptionLinked);
566                     node = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::NEXT_OFFSET));
567                     Branch(TaggedIsHole(*node), &loopEnd, &loopLinked);
568                 }
569                 Bind(&loopLinked);
570                 LoopEnd(&nodeIsLinked);
571                 Bind(&nodeIsRBTree);
572                 {
573                     GateRef retValue = CallRuntime(glue, RTSTUB_ID(ContainerRBTreeForEach),
574                                                    { *node, callbackFnHandle, *thisArg, *thisObj,
575                                                      IntToTaggedInt(Int32(static_cast<int32_t>(type))) });
576                     Branch(HasPendingException(glue), &hasExceptionRBTree, &notHasExceptionRBTree);
577                     Bind(&hasExceptionRBTree);
578                     {
579                         result->WriteVariable(retValue);
580                         Jump(exit);
581                     }
582                     Bind(&notHasExceptionRBTree);
583                     Jump(&loopEnd);
584                 }
585             }
586         }
587         Bind(&loopEnd);
588         index = Int32Add(*index, Int32(1));
589         LoopEnd(&loopHead);
590     }
591     Bind(&afterLoop);
592     Jump(exit);
593 }
594 
ContainersLinkedListCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)595 void ContainersStubBuilder::ContainersLinkedListCall(GateRef glue, GateRef thisValue,
596     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
597 {
598     auto env = GetEnvironment();
599     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
600     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
601     DEFVARIABLE(valueNode, VariableType::INT32(), Int32(0));
602     DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
603     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
604     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
605     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
606     Label valueIsJSAPILinkedList(env);
607     Label valueNotJSAPILinkedList(env);
608     Label objIsJSProxy(env);
609     Label objNotJSProxy(env);
610     Label objIsJSAPILinkedList(env);
611     Label thisArgUndefined(env);
612     Label thisArgNotUndefined(env);
613     Label callbackUndefined(env);
614     Label callbackNotUndefined(env);
615     Label nextCount(env);
616     Label valueNotHole(env);
617     Label loopHead(env);
618     Label loopEnd(env);
619     Label next(env);
620     Label afterLoop(env);
621     GateRef callbackFnHandle;
622     Branch(IsContainer(*thisObj, type), &valueIsJSAPILinkedList, &valueNotJSAPILinkedList);
623     Bind(&valueNotJSAPILinkedList);
624     {
625         Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
626         Bind(&objIsJSProxy);
627         {
628             GateRef tempObj = GetTarget(*thisObj);
629             Branch(IsContainer(tempObj, type), &objIsJSAPILinkedList, slowPath);
630             Bind(&objIsJSAPILinkedList);
631             {
632                 thisObj = tempObj;
633                 Jump(&valueIsJSAPILinkedList);
634             }
635         }
636         Bind(&objNotJSProxy);
637         Jump(slowPath);
638     }
639     Bind(&valueIsJSAPILinkedList);
640     {
641         Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
642         Bind(&callbackUndefined);
643         Jump(slowPath);
644         Bind(&callbackNotUndefined);
645         {
646             Label isCall(env);
647             Label notCall(env);
648             Label isHeapObj(env);
649             callbackFnHandle = GetCallArg0(numArgs);
650             Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, &notCall);
651             Bind(&isHeapObj);
652             Branch(IsCallable(callbackFnHandle), &isCall, &notCall);
653             Bind(&notCall);
654             Jump(slowPath);
655             Bind(&isCall);
656             {
657                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
658                 Bind(&thisArgUndefined);
659                 Jump(&nextCount);
660                 Bind(&thisArgNotUndefined);
661                 thisArg = GetCallArg1(numArgs);
662                 Jump(&nextCount);
663             }
664         }
665     }
666     Bind(&nextCount);
667     {
668         length = ContainerGetSize(*thisObj, type);
669         valueNode = Int32(TaggedList<TaggedArray>::ELEMENTS_START_INDEX);
670         Jump(&loopHead);
671         LoopBegin(&loopHead);
672         {
673             Label hasException(env);
674             Label notHasException(env);
675             Branch(Int32LessThan(*index, *length), &next, &afterLoop);
676             Bind(&next);
677             {
678                 valueNode = TaggedGetInt(ContainerGetNode(*thisObj,
679                     Int32Add(*valueNode, Int32(TaggedList<TaggedArray>::NEXT_PTR_OFFSET)), type));
680                 value = ContainerGetNode(*thisObj, *valueNode, type);
681                 Branch(TaggedIsHole(*value), &loopEnd, &valueNotHole);
682                 Bind(&valueNotHole);
683                 key = IntToTaggedInt(*index);
684                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
685                     Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj });
686                 Branch(HasPendingException(glue), &hasException, &notHasException);
687                 Bind(&hasException);
688                 {
689                     result->WriteVariable(retValue);
690                     Jump(exit);
691                 }
692                 Bind(&notHasException);
693                 Jump(&loopEnd);
694             }
695         }
696         Bind(&loopEnd);
697         index = Int32Add(*index, Int32(1));
698         LoopEnd(&loopHead);
699     }
700     Bind(&afterLoop);
701     Jump(exit);
702 }
703 }  // namespace panda::ecmascript::kungfu
704