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