• 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 #include "ecmascript/compiler/call_stub_builder.h"
20 
21 namespace panda::ecmascript::kungfu {
22 // common IR for containers apis that use function call
ContainersCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)23 void 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 
QueueCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)145 void 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 
DequeCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)254 void 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 
ContainersLightWeightCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)366 void 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 
ContainersHashCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)476 void 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 
ContainersLinkedListCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)613 void 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