• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 
18 #include "ecmascript/compiler/call_stub_builder.h"
19 
20 namespace panda::ecmascript::kungfu {
21 // common IR for containers apis that use function call
ContainersCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)22 void ContainersCommonStubBuilder::ContainersCommonFuncCall(GateRef glue, GateRef thisValue,
23     GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
24 {
25     auto env = GetEnvironment();
26     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
27     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
28     DEFVARIABLE(key, VariableType::INT64(), Int64(0));
29     DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
30     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
31     DEFVARIABLE(k, VariableType::INT32(), Int32(0));
32     Label valueIsJSAPIVector(env);
33     Label valueNotJSAPIVector(env);
34     Label objIsJSProxy(env);
35     Label objNotJSProxy(env);
36     Label objIsJSAPIVector(env);
37     Label thisArgUndefined(env);
38     Label thisArgNotUndefined(env);
39     Label callbackUndefined(env);
40     Label callbackNotUndefined(env);
41     Label nextCount(env);
42     Label loopHead(env);
43     Label loopEnd(env);
44     Label next(env);
45     Label afterLoop(env);
46     Label thisValueIsHeapObj(env);
47     GateRef callbackFnHandle;
48     BRANCH(TaggedIsHeapObject(thisValue), &thisValueIsHeapObj, slowPath);
49     Bind(&thisValueIsHeapObj);
50     BRANCH(IsContainer(glue, *thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
51     Bind(&valueNotJSAPIVector);
52     {
53         BRANCH(IsJsProxy(glue, *thisObj), &objIsJSProxy, &objNotJSProxy);
54         Bind(&objIsJSProxy);
55         {
56             GateRef tempObj = GetTarget(glue, *thisObj);
57             BRANCH(IsContainer(glue, tempObj, type), &objIsJSAPIVector, slowPath);
58             Bind(&objIsJSAPIVector);
59             {
60                 thisObj = tempObj;
61                 Jump(&valueIsJSAPIVector);
62             }
63         }
64         Bind(&objNotJSProxy);
65         Jump(slowPath);
66     }
67     Bind(&valueIsJSAPIVector);
68     {
69         BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
70         Bind(&callbackUndefined);
71         Jump(slowPath);
72         Bind(&callbackNotUndefined);
73         {
74             Label isCall(env);
75             Label notCall(env);
76             Label isHeapObj(env);
77             callbackFnHandle = GetCallArg0(numArgs);
78             BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
79             Bind(&isHeapObj);
80             BRANCH(IsCallable(glue, callbackFnHandle), &isCall, &notCall);
81             Bind(&notCall);
82             Jump(slowPath);
83             Bind(&isCall);
84             {
85                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
86                 Bind(&thisArgUndefined);
87                 Jump(&nextCount);
88                 Bind(&thisArgNotUndefined);
89                 thisArg = GetCallArg1(numArgs);
90                 Jump(&nextCount);
91             }
92         }
93     }
94     Bind(&nextCount);
95     {
96         length = ContainerGetSize(glue, *thisObj, type);
97         Jump(&loopHead);
98         LoopBegin(&loopHead);
99         {
100             Label lenChange(env);
101             Label hasException(env);
102             Label notHasException(env);
103             Label setValue(env);
104             BRANCH(Int32LessThan(*k, *length), &next, &afterLoop);
105             Bind(&next);
106             {
107                 kValue = ContainerGetValue(glue, *thisObj, *k, type);
108                 if (IsPlainArray(type)) {
109                     key = PlainArrayGetKey(glue, *thisObj, *k);
110                 } else {
111                     key = IntToTaggedInt(*k);
112                 }
113                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
114                 callArgs.callThisArg3WithReturnArgs = { *thisArg, *kValue, *key, *thisObj };
115                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
116                     Circuit::NullGate(), callArgs);
117                 GateRef retValue = callBuilder.JSCallDispatch();
118                 BRANCH(HasPendingException(glue), &hasException, &notHasException);
119                 Bind(&hasException);
120                 {
121                     result->WriteVariable(retValue);
122                     Jump(exit);
123                 }
124                 Bind(&notHasException);
125                 GateRef tempLen = ContainerGetSize(glue, *thisObj, type);
126                 BRANCH(Int32NotEqual(tempLen, *length), &lenChange, &setValue);
127                 Bind(&lenChange);
128                 if (!IsArrayListReplaceAllelements(type)) {
129                     length = tempLen;
130                 }
131                 BRANCH(Int32GreaterThanOrEqual(*k, *length), &afterLoop, &setValue);
132                 Bind(&setValue);
133                 if (IsReplaceAllElements(type)) {
134                     GateRef elementsOffset = IntPtr(JSObject::ELEMENTS_OFFSET);
135                     GateRef elements = Load(VariableType::JS_POINTER(), glue, *thisObj, elementsOffset);
136                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, *k, retValue);
137                 }
138                 Jump(&loopEnd);
139             }
140         }
141         Bind(&loopEnd);
142         k = Int32Add(*k, Int32(1));
143         LoopEndWithCheckSafePoint(&loopHead, env, glue);
144     }
145     Bind(&afterLoop);
146     Jump(exit);
147 }
148 
ContainersLightWeightCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)149 void ContainersCommonStubBuilder::ContainersLightWeightCall(GateRef glue, GateRef thisValue, GateRef numArgs,
150                                                             Variable* result, Label *exit, Label *slowPath,
151                                                             ContainersType type)
152 {
153     auto env = GetEnvironment();
154     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
155     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
156     DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
157     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
158     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
159     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
160     Label valueIsJSAPILightWeight(env);
161     Label valueNotJSAPILightWeight(env);
162     Label objIsJSProxy(env);
163     Label objNotJSProxy(env);
164     Label objIsJSAPILightWeight(env);
165     Label thisArgUndefined(env);
166     Label thisArgNotUndefined(env);
167     Label callbackUndefined(env);
168     Label callbackNotUndefined(env);
169     Label nextCount(env);
170     Label loopHead(env);
171     Label loopEnd(env);
172     Label next(env);
173     Label afterLoop(env);
174     Label thisValueIsHeapObj(env);
175     GateRef callbackFnHandle;
176     BRANCH(TaggedIsHeapObject(thisValue), &thisValueIsHeapObj, slowPath);
177     Bind(&thisValueIsHeapObj);
178     BRANCH(IsContainer(glue, *thisObj, type), &valueIsJSAPILightWeight, &valueNotJSAPILightWeight);
179     Bind(&valueNotJSAPILightWeight);
180     {
181         BRANCH(IsJsProxy(glue, *thisObj), &objIsJSProxy, &objNotJSProxy);
182         Bind(&objIsJSProxy);
183         {
184             GateRef tempObj = GetTarget(glue, *thisObj);
185             BRANCH(IsContainer(glue, tempObj, type), &objIsJSAPILightWeight, slowPath);
186             Bind(&objIsJSAPILightWeight);
187             {
188                 thisObj = tempObj;
189                 Jump(&valueIsJSAPILightWeight);
190             }
191         }
192         Bind(&objNotJSProxy);
193         Jump(slowPath);
194     }
195     Bind(&valueIsJSAPILightWeight);
196     {
197         BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
198         Bind(&callbackUndefined);
199         Jump(slowPath);
200         Bind(&callbackNotUndefined);
201         {
202             Label isCall(env);
203             Label notCall(env);
204             Label isHeapObj(env);
205             callbackFnHandle = GetCallArg0(numArgs);
206             BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
207             Bind(&isHeapObj);
208             BRANCH(IsCallable(glue, callbackFnHandle), &isCall, &notCall);
209             Bind(&notCall);
210             Jump(slowPath);
211             Bind(&isCall);
212             {
213                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
214                 Bind(&thisArgUndefined);
215                 Jump(&nextCount);
216                 Bind(&thisArgNotUndefined);
217                 thisArg = GetCallArg1(numArgs);
218                 Jump(&nextCount);
219             }
220         }
221     }
222     Bind(&nextCount);
223     {
224         length = ContainerGetSize(glue, *thisObj, type);
225         Jump(&loopHead);
226         LoopBegin(&loopHead);
227         {
228             Label lenChange(env);
229             Label hasException(env);
230             Label notHasException(env);
231             BRANCH(Int32LessThan(*index, *length), &next, &afterLoop);
232             Bind(&next);
233             {
234                 value = ContainerGetValue(glue, *thisObj, *index, type);
235                 key = ContainerGetKey(glue, *thisObj, *index, type);
236                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
237                 callArgs.callThisArg3WithReturnArgs = { *thisArg, *value, *key, *thisObj };
238                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
239                     Circuit::NullGate(), callArgs);
240                 GateRef retValue = callBuilder.JSCallDispatch();
241                 BRANCH(HasPendingException(glue), &hasException, &notHasException);
242                 Bind(&hasException);
243                 {
244                     result->WriteVariable(retValue);
245                     Jump(exit);
246                 }
247                 Bind(&notHasException);
248                 GateRef currentLen = ContainerGetSize(glue, *thisObj, type);
249                 BRANCH(Int32NotEqual(currentLen, *length), &lenChange, &loopEnd);
250                 Bind(&lenChange);
251                 length = currentLen;
252                 Jump(&loopEnd);
253             }
254         }
255         Bind(&loopEnd);
256         index = Int32Add(*index, Int32(1));
257         LoopEndWithCheckSafePoint(&loopHead, env, glue);
258     }
259     Bind(&afterLoop);
260     Jump(exit);
261 }
262 
ContainersHashCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)263 void ContainersCommonStubBuilder::ContainersHashCall(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* result,
264                                                      Label *exit, Label *slowPath, ContainersType type)
265 {
266     auto env = GetEnvironment();
267     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
268     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
269     DEFVARIABLE(node, VariableType::JS_ANY(), Undefined());
270     DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
271     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
272     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
273     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
274     Label valueIsJSAPIHash(env);
275     Label valueNotJSAPIHash(env);
276     Label objIsJSProxy(env);
277     Label objNotJSProxy(env);
278     Label objIsJSAPIHash(env);
279     Label thisArgUndefined(env);
280     Label thisArgNotUndefined(env);
281     Label callbackUndefined(env);
282     Label callbackNotUndefined(env);
283     Label nextCount(env);
284     Label nodeNotHole(env);
285     Label nodeIsLinked(env);
286     Label nodeIsRBTree(env);
287     Label loopLinked(env);
288     Label loopHead(env);
289     Label loopEnd(env);
290     Label next(env);
291     Label afterLoop(env);
292     Label thisValueIsHeapObj(env);
293     GateRef callbackFnHandle;
294     BRANCH(TaggedIsHeapObject(thisValue), &thisValueIsHeapObj, slowPath);
295     Bind(&thisValueIsHeapObj);
296     BRANCH(IsContainer(glue, *thisObj, type), &valueIsJSAPIHash, &valueNotJSAPIHash);
297     Bind(&valueNotJSAPIHash);
298     {
299         BRANCH(IsJsProxy(glue, *thisObj), &objIsJSProxy, &objNotJSProxy);
300         Bind(&objIsJSProxy);
301         {
302             GateRef tempObj = GetTarget(glue, *thisObj);
303             BRANCH(IsContainer(glue, tempObj, type), &objIsJSAPIHash, slowPath);
304             Bind(&objIsJSAPIHash);
305             {
306                 thisObj = tempObj;
307                 Jump(&valueIsJSAPIHash);
308             }
309         }
310         Bind(&objNotJSProxy);
311         Jump(slowPath);
312     }
313     Bind(&valueIsJSAPIHash);
314     {
315         BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
316         Bind(&callbackUndefined);
317         Jump(slowPath);
318         Bind(&callbackNotUndefined);
319         {
320             Label isCall(env);
321             Label notCall(env);
322             Label isHeapObj(env);
323             callbackFnHandle = GetCallArg0(numArgs);
324             BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, &notCall);
325             Bind(&isHeapObj);
326             BRANCH(IsCallable(glue, callbackFnHandle), &isCall, &notCall);
327             Bind(&notCall);
328             Jump(slowPath);
329             Bind(&isCall);
330             {
331                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
332                 Bind(&thisArgUndefined);
333                 Jump(&nextCount);
334                 Bind(&thisArgNotUndefined);
335                 thisArg = GetCallArg1(numArgs);
336                 Jump(&nextCount);
337             }
338         }
339     }
340     Bind(&nextCount);
341     {
342         length = ContainerGetSize(glue, *thisObj, type);
343         Jump(&loopHead);
344         LoopBegin(&loopHead);
345         {
346             Label hasExceptionLinked(env);
347             Label notHasExceptionLinked(env);
348             Label hasExceptionRBTree(env);
349             Label notHasExceptionRBTree(env);
350             BRANCH(Int32LessThan(*index, *length), &next, &afterLoop);
351             Bind(&next);
352             {
353                 node = ContainerGetNode(glue, *thisObj, *index, type);
354                 BRANCH(TaggedIsHole(*node), &loopEnd, &nodeNotHole);
355                 Bind(&nodeNotHole);
356                 BRANCH(IsLinkedNode(glue, *node), &nodeIsLinked, &nodeIsRBTree);
357                 LoopBegin(&nodeIsLinked);
358                 {
359                     value = Load(VariableType::JS_POINTER(), glue, *node, IntPtr(
360                         type == ContainersType::HASHSET_FOREACH ? LinkedNode::KEY_OFFSET : LinkedNode::VALUE_OFFSET));
361                     key = Load(VariableType::JS_POINTER(), glue, *node, IntPtr(LinkedNode::KEY_OFFSET));
362                     JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
363                     callArgs.callThisArg3WithReturnArgs = { *thisArg, *value, *key, *thisObj };
364                     CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
365                         nullptr, Circuit::NullGate(), callArgs);
366                     GateRef retValue = callBuilder.JSCallDispatch();
367                     BRANCH(HasPendingException(glue), &hasExceptionLinked, &notHasExceptionLinked);
368                     Bind(&hasExceptionLinked);
369                     {
370                         result->WriteVariable(retValue);
371                         Jump(exit);
372                     }
373                     Bind(&notHasExceptionLinked);
374                     node = Load(VariableType::JS_POINTER(), glue, *node, IntPtr(LinkedNode::NEXT_OFFSET));
375                     BRANCH(TaggedIsHole(*node), &loopEnd, &loopLinked);
376                 }
377                 Bind(&loopLinked);
378                 LoopEnd(&nodeIsLinked);
379                 Bind(&nodeIsRBTree);
380                 {
381                     GateRef retValue = CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
382                         RTSTUB_ID(ContainerRBTreeForEach), { *node, callbackFnHandle, *thisArg, *thisObj,
383                             IntToTaggedInt(Int32(static_cast<int32_t>(type))) });
384                     BRANCH(HasPendingException(glue), &hasExceptionRBTree, &notHasExceptionRBTree);
385                     Bind(&hasExceptionRBTree);
386                     {
387                         result->WriteVariable(retValue);
388                         Jump(exit);
389                     }
390                     Bind(&notHasExceptionRBTree);
391                     Jump(&loopEnd);
392                 }
393             }
394         }
395         Bind(&loopEnd);
396         index = Int32Add(*index, Int32(1));
397         LoopEndWithCheckSafePoint(&loopHead, env, glue);
398     }
399     Bind(&afterLoop);
400     Jump(exit);
401 }
402 
ContainersLinkedListCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)403 void ContainersCommonStubBuilder::ContainersLinkedListCall(GateRef glue, GateRef thisValue, GateRef numArgs,
404                                                            Variable* result, Label *exit, Label *slowPath,
405                                                            ContainersType type)
406 {
407     auto env = GetEnvironment();
408     DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
409     DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
410     DEFVARIABLE(valueNode, VariableType::INT32(), Int32(0));
411     DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
412     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
413     DEFVARIABLE(length, VariableType::INT32(), Int32(0));
414     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
415     Label valueIsJSAPILinkedList(env);
416     Label valueNotJSAPILinkedList(env);
417     Label objIsJSProxy(env);
418     Label objNotJSProxy(env);
419     Label objIsJSAPILinkedList(env);
420     Label thisArgUndefined(env);
421     Label thisArgNotUndefined(env);
422     Label callbackUndefined(env);
423     Label callbackNotUndefined(env);
424     Label nextCount(env);
425     Label valueNotHole(env);
426     Label loopHead(env);
427     Label loopEnd(env);
428     Label next(env);
429     Label afterLoop(env);
430     Label thisValueIsHeapObj(env);
431     GateRef callbackFnHandle;
432     BRANCH(TaggedIsHeapObject(thisValue), &thisValueIsHeapObj, slowPath);
433     Bind(&thisValueIsHeapObj);
434     BRANCH(IsContainer(glue, *thisObj, type), &valueIsJSAPILinkedList, &valueNotJSAPILinkedList);
435     Bind(&valueNotJSAPILinkedList);
436     {
437         BRANCH(IsJsProxy(glue, *thisObj), &objIsJSProxy, &objNotJSProxy);
438         Bind(&objIsJSProxy);
439         {
440             GateRef tempObj = GetTarget(glue, *thisObj);
441             BRANCH(IsContainer(glue, tempObj, type), &objIsJSAPILinkedList, slowPath);
442             Bind(&objIsJSAPILinkedList);
443             {
444                 thisObj = tempObj;
445                 Jump(&valueIsJSAPILinkedList);
446             }
447         }
448         Bind(&objNotJSProxy);
449         Jump(slowPath);
450     }
451     Bind(&valueIsJSAPILinkedList);
452     {
453         BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
454         Bind(&callbackUndefined);
455         Jump(slowPath);
456         Bind(&callbackNotUndefined);
457         {
458             Label isCall(env);
459             Label notCall(env);
460             Label isHeapObj(env);
461             callbackFnHandle = GetCallArg0(numArgs);
462             BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, &notCall);
463             Bind(&isHeapObj);
464             BRANCH(IsCallable(glue, callbackFnHandle), &isCall, &notCall);
465             Bind(&notCall);
466             Jump(slowPath);
467             Bind(&isCall);
468             {
469                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
470                 Bind(&thisArgUndefined);
471                 Jump(&nextCount);
472                 Bind(&thisArgNotUndefined);
473                 thisArg = GetCallArg1(numArgs);
474                 Jump(&nextCount);
475             }
476         }
477     }
478     Bind(&nextCount);
479     {
480         length = ContainerGetSize(glue, *thisObj, type);
481         valueNode = Int32(TaggedList<TaggedArray>::ELEMENTS_START_INDEX);
482         Jump(&loopHead);
483         LoopBegin(&loopHead);
484         {
485             Label hasException(env);
486             Label notHasException(env);
487             BRANCH(Int32LessThan(*index, *length), &next, &afterLoop);
488             Bind(&next);
489             {
490                 valueNode = TaggedGetInt(ContainerGetNode(glue, *thisObj,
491                     Int32Add(*valueNode, Int32(TaggedList<TaggedArray>::NEXT_PTR_OFFSET)), type));
492                 value = ContainerGetNode(glue, *thisObj, *valueNode, type);
493                 BRANCH(TaggedIsHole(*value), &loopEnd, &valueNotHole);
494                 Bind(&valueNotHole);
495                 key = IntToTaggedInt(*index);
496                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
497                 callArgs.callThisArg3WithReturnArgs = { *thisArg, *value, *key, *thisObj };
498                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
499                     Circuit::NullGate(), callArgs);
500                 GateRef retValue = callBuilder.JSCallDispatch();
501                 BRANCH(HasPendingException(glue), &hasException, &notHasException);
502                 Bind(&hasException);
503                 {
504                     result->WriteVariable(retValue);
505                     Jump(exit);
506                 }
507                 Bind(&notHasException);
508                 Jump(&loopEnd);
509             }
510         }
511         Bind(&loopEnd);
512         index = Int32Add(*index, Int32(1));
513         LoopEndWithCheckSafePoint(&loopHead, env, glue);
514     }
515     Bind(&afterLoop);
516     Jump(exit);
517 }
518 }  // namespace panda::ecmascript::kungfu
519