• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ecmascript/base/config.h"
16 #include "ecmascript/compiler/builtins/builtins_array_stub_builder.h"
17 
18 #include "ecmascript/builtins/builtins_string.h"
19 #include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h"
20 #include "ecmascript/compiler/call_stub_builder.h"
21 #include "ecmascript/compiler/new_object_stub_builder.h"
22 #include "ecmascript/js_array_iterator.h"
23 #include "ecmascript/js_iterator.h"
24 #include "ecmascript/compiler/access_object_stub_builder.h"
25 
26 namespace panda::ecmascript::kungfu {
27 
ElementsKindHclassCompare(GateRef glue,GateRef arrayCls,Label * matchCls,Label * slowPath)28 void BuiltinsArrayStubBuilder::ElementsKindHclassCompare(GateRef glue, GateRef arrayCls,
29     Label *matchCls, Label *slowPath)
30 {
31     auto env = GetEnvironment();
32     Label isGeneric(env);
33     GateRef elementsKind = GetElementsKindFromHClass(arrayCls);
34     GateRef notGeneric = NotEqual(elementsKind, Int32(Elements::ToUint(ElementsKind::GENERIC)));
35     BRANCH(notGeneric, matchCls, &isGeneric);
36     Bind(&isGeneric);
37     {
38         GateRef intialHClass = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
39                                                       ConstantIndex::ELEMENT_HOLE_TAGGED_HCLASS_INDEX);
40         BRANCH(Equal(intialHClass, arrayCls), matchCls, slowPath);
41     }
42 }
43 
With(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)44 void BuiltinsArrayStubBuilder::With(GateRef glue, GateRef thisValue, GateRef numArgs,
45     Variable *result, Label *exit, Label *slowPath)
46 {
47 #if ENABLE_NEXT_OPTIMIZATION
48     WithOptimised(glue, thisValue, numArgs, result, exit, slowPath);
49 #else
50     auto env = GetEnvironment();
51     DEFVARIABLE(relativeIndex, VariableType::INT64(), Int64(0));
52     DEFVARIABLE(actualIndex, VariableType::INT64(), Int64(0));
53     Label isHeapObject(env);
54     Label isJsArray(env);
55     Label isStableArray(env);
56     Label notCOWArray(env);
57     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
58     Bind(&isHeapObject);
59     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
60     Bind(&isJsArray);
61     // don't check constructor, "with" always use ArrayCreate to create array.
62     BRANCH(IsStableJSArray(glue, thisValue), &isStableArray, slowPath);
63     Bind(&isStableArray);
64     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
65     Bind(&notCOWArray);
66 
67     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
68     GateRef index = GetCallArg0(numArgs);
69     Label taggedIsInt(env);
70     BRANCH(TaggedIsInt(index), &taggedIsInt, slowPath);
71     Bind(&taggedIsInt);
72     {
73         relativeIndex = GetInt64OfTInt(index);
74         DEFVARIABLE(value, VariableType::JS_ANY(), Hole());
75         Label twoArg(env);
76         Label ifOneArg(env);
77         Label getIndex(env);
78         // 2 : means there are two args
79         BRANCH(Int64Equal(numArgs, IntPtr(2)), &twoArg, &ifOneArg);
80         Bind(&twoArg);
81         {
82             value = GetCallArg1(numArgs);
83             Jump(&getIndex);
84         }
85         Bind(&ifOneArg);
86         {
87             // 1 : means there are only one arg
88             BRANCH(Int64Equal(numArgs, IntPtr(1)), &getIndex, slowPath);
89         }
90         Bind(&getIndex);
91         {
92             Label indexGreaterOrEqualZero(env);
93             Label indexLessZero(env);
94             Label next(env);
95             Label notOutOfRange(env);
96             BRANCH(Int64GreaterThanOrEqual(*relativeIndex, Int64(0)), &indexGreaterOrEqualZero, &indexLessZero);
97             Bind(&indexGreaterOrEqualZero);
98             {
99                 actualIndex = *relativeIndex;
100                 Jump(&next);
101             }
102             Bind(&indexLessZero);
103             {
104                 actualIndex = Int64Add(thisLen, *relativeIndex);
105                 Jump(&next);
106             }
107             Bind(&next);
108             {
109                 BRANCH(BitOr(Int64GreaterThanOrEqual(*actualIndex, thisLen), Int64LessThan(*actualIndex, Int64(0))),
110                     slowPath, &notOutOfRange);
111                 Bind(&notOutOfRange);
112                 {
113                     GateRef newArray = NewArray(glue, Int32(0));
114                     GrowElementsCapacity(glue, newArray, TruncInt64ToInt32(thisLen));
115                     DEFVARIABLE(k, VariableType::INT64(), Int64(0));
116                     Label loopHead(env);
117                     Label loopEnd(env);
118                     Label loopExit(env);
119                     Label loopNext(env);
120                     Label replaceIndex(env);
121                     Label notReplaceIndex(env);
122                     Jump(&loopHead);
123                     LoopBegin(&loopHead);
124                     {
125                         BRANCH(Int64LessThan(*k, thisLen), &loopNext, &loopExit);
126                         Bind(&loopNext);
127                         BRANCH(Int64Equal(*k, *actualIndex), &replaceIndex, &notReplaceIndex);
128                         Bind(&replaceIndex);
129                         {
130                             SetValueWithElementsKind(glue, newArray, *value, *k, Boolean(true),
131                                 Int32(Elements::ToUint(ElementsKind::NONE)));
132                             Jump(&loopEnd);
133                         }
134                         Bind(&notReplaceIndex);
135                         {
136                             GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *k);
137                             Label eleIsHole(env);
138                             Label eleNotHole(env);
139                             BRANCH(TaggedIsHole(ele), &eleIsHole, &eleNotHole);
140                             Bind(&eleIsHole);
141                             {
142                                 SetValueWithElementsKind(glue, newArray, Undefined(), *k, Boolean(true),
143                                     Int32(Elements::ToUint(ElementsKind::NONE)));
144                                 Jump(&loopEnd);
145                             }
146                             Bind(&eleNotHole);
147                             {
148                                 SetValueWithElementsKind(glue, newArray, ele, *k, Boolean(true),
149                                     Int32(Elements::ToUint(ElementsKind::NONE)));
150                                 Jump(&loopEnd);
151                             }
152                         }
153                     }
154                     Bind(&loopEnd);
155                     k = Int64Add(*k, Int64(1));
156                     LoopEnd(&loopHead);
157                     Bind(&loopExit);
158                     SetArrayLength(glue, newArray, thisLen);
159                     result->WriteVariable(newArray);
160                     Jump(exit);
161                 }
162             }
163         }
164     }
165 #endif
166 }
167 
Unshift(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)168 void BuiltinsArrayStubBuilder::Unshift(GateRef glue, GateRef thisValue, GateRef numArgs,
169     Variable *result, Label *exit, Label *slowPath)
170 {
171 #if ENABLE_NEXT_OPTIMIZATION
172     UnshiftOptimised(glue, thisValue, numArgs, result, exit, slowPath);
173 #else
174     auto env = GetEnvironment();
175     Label isHeapObject(env);
176     Label isJsArray(env);
177     Label isStableJsArray(env);
178     Label notOverRange(env);
179     Label numNotEqualZero(env);
180     Label numLessThanOrEqualThree(env);
181     Label loopHead(env);
182     Label next(env);
183     Label loopEnd(env);
184     Label loopExit(env);
185     Label grow(env);
186     Label setValue(env);
187     Label numEqual2(env);
188     Label numEqual3(env);
189     Label threeArgs(env);
190     Label final(env);
191     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
192     Bind(&isHeapObject);
193     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
194     Bind(&isJsArray);
195     BRANCH(IsStableJSArray(glue, thisValue), &isStableJsArray, slowPath);
196     Bind(&isStableJsArray);
197     BRANCH(Int64GreaterThan(numArgs, IntPtr(0)), &numNotEqualZero, slowPath);
198     Bind(&numNotEqualZero);
199     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
200     GateRef argLen = ZExtInt32ToInt64(ChangeIntPtrToInt32(numArgs));
201     GateRef newLen = Int64Add(thisLen, argLen);
202     BRANCH(Int64GreaterThan(newLen, Int64(base::MAX_SAFE_INTEGER)), slowPath, &notOverRange);
203     Bind(&notOverRange);
204     // 3 : max param num
205     BRANCH(Int64LessThanOrEqual(numArgs, IntPtr(3)), &numLessThanOrEqualThree, slowPath);
206     Bind(&numLessThanOrEqualThree);
207     {
208         DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(thisValue));
209         GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(*elements));
210         BRANCH(Int64GreaterThan(newLen, capacity), &grow, &setValue);
211         Bind(&grow);
212         {
213             elements = CallRuntime(glue, RTSTUB_ID(JSObjectGrowElementsCapacity), {thisValue, IntToTaggedInt(newLen)});
214             Jump(&setValue);
215         }
216         Bind(&setValue);
217         {
218             DEFVARIABLE(fromKey, VariableType::INT64(), Int64Sub(thisLen, Int64(1)));
219             DEFVARIABLE(toKey, VariableType::INT64(), Int64Sub(newLen, Int64(1)));
220             DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
221             Label eleIsHole(env);
222             Label hasProperty(env);
223             Label notHasProperty(env);
224             Label hasException0(env);
225             Label notHasException0(env);
226             Jump(&loopHead);
227             LoopBegin(&loopHead);
228             {
229                 BRANCH(Int64GreaterThanOrEqual(*fromKey, Int64(0)), &next, &loopExit);
230                 Bind(&next);
231                 {
232                     ele = GetTaggedValueWithElementsKind(glue, thisValue, *fromKey);
233                     BRANCH(TaggedIsHole(*ele), &eleIsHole, &notHasException0);
234                     Bind(&eleIsHole);
235                     {
236                         GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty),
237                             { thisValue, IntToTaggedInt(*fromKey) });
238                         BRANCH(TaggedIsTrue(hasProp), &hasProperty, &notHasProperty);
239                         Bind(&hasProperty);
240                         {
241                             ele = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*fromKey),
242                                 ProfileOperation());
243                             BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
244                             Bind(&hasException0);
245                             {
246                                 result->WriteVariable(Exception());
247                                 Jump(exit);
248                             }
249                         }
250                         Bind(&notHasProperty);
251                         {
252                             SetValueWithElementsKind(glue, thisValue, Hole(), *toKey, Boolean(false),
253                                 Int32(Elements::ToUint(ElementsKind::NONE)));
254                             Jump(&loopEnd);
255                         }
256                     }
257                     Bind(&notHasException0);
258                     {
259                         SetValueWithElementsKind(glue, thisValue, *ele, *toKey, Boolean(false),
260                             Int32(Elements::ToUint(ElementsKind::NONE)));
261                         Jump(&loopEnd);
262                     }
263                 }
264             }
265             Bind(&loopEnd);
266             fromKey = Int64Sub(*fromKey, Int64(1));
267             toKey = Int64Sub(*toKey, Int64(1));
268             LoopEnd(&loopHead);
269             Bind(&loopExit);
270             {
271                 GateRef value0 = GetCallArg0(numArgs);
272                 // 0 : the first Element position
273                 SetValueWithElementsKind(glue, thisValue, value0, Int64(0), Boolean(false),
274                     Int32(Elements::ToUint(ElementsKind::NONE)));
275                 // 2 : the second param
276                 BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(2)), &numEqual2, &numEqual3);
277                 Bind(&numEqual2);
278                 {
279                     GateRef value1 = GetCallArg1(numArgs);
280                     // 1 : the second Element position
281                     SetValueWithElementsKind(glue, thisValue, value1, Int64(1), Boolean(false),
282                         Int32(Elements::ToUint(ElementsKind::NONE)));
283                     Jump(&numEqual3);
284                 }
285                 Bind(&numEqual3);
286                 {
287                     // 3 : the third param
288                     BRANCH(Int64Equal(numArgs, IntPtr(3)), &threeArgs, &final);
289                     Bind(&threeArgs);
290                     GateRef value2 = GetCallArg2(numArgs);
291                     // 2 : the third Element position
292                     SetValueWithElementsKind(glue, thisValue, value2, Int64(2), Boolean(false),
293                         Int32(Elements::ToUint(ElementsKind::NONE)));
294                     Jump(&final);
295                 }
296                 Bind(&final);
297                 {
298                     SetArrayLength(glue, thisValue, newLen);
299                     result->WriteVariable(IntToTaggedPtr(newLen));
300                     Jump(exit);
301                 }
302             }
303         }
304     }
305 #endif
306 }
307 
Shift(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)308 void BuiltinsArrayStubBuilder::Shift(GateRef glue, GateRef thisValue,
309     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
310 {
311 #if ENABLE_NEXT_OPTIMIZATION
312     ShiftOptimised(glue, thisValue, numArgs, result, exit, slowPath);
313 #else
314     auto env = GetEnvironment();
315     Label isHeapObject(env);
316     Label stableJSArray(env);
317     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
318     Bind(&isHeapObject);
319     // don't check constructor, "Shift" won't create new array.
320     BRANCH(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
321     Bind(&stableJSArray);
322     {
323         Label isLengthWritable(env);
324         BRANCH(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
325         Bind(&isLengthWritable);
326         {
327             GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
328             Label lengthNotZero(env);
329             BRANCH(Int64Equal(thisLen, Int64(0)), exit, &lengthNotZero);
330             Bind(&lengthNotZero);
331             {
332                 Label isJsCOWArray(env);
333                 Label getElements(env);
334                 BRANCH(IsJsCOWArray(thisValue), &isJsCOWArray, &getElements);
335                 Bind(&isJsCOWArray);
336                 {
337                     CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), { thisValue });
338                     Jump(&getElements);
339                 }
340                 Bind(&getElements);
341                 {
342                     GateRef elements = GetElementsArray(thisValue);
343                     GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(elements));
344                     GateRef index = Int64Sub(thisLen, Int64(1));
345                     DEFVARIABLE(element, VariableType::JS_ANY(), Hole());
346                     element = GetTaggedValueWithElementsKind(glue, thisValue, Int64(0));
347                     Label hasException0(env);
348                     Label taggedHole(env);
349                     Label copyArray(env);
350                     BRANCH(TaggedIsHole(*element), &taggedHole, &copyArray);
351                     Bind(&taggedHole);
352                     {
353                         element = FastGetPropertyByIndex(glue, thisValue, Int32(0), ProfileOperation());
354                         BRANCH(HasPendingException(glue), &hasException0, &copyArray);
355                         Bind(&hasException0);
356                         {
357                             result->WriteVariable(Exception());
358                             Jump(exit);
359                         }
360                     }
361                     Bind(&copyArray);
362                     {
363                         DEFVARIABLE(fromKey, VariableType::INT64(), Int64(1));
364                         DEFVARIABLE(toKey, VariableType::INT64(), Int64Sub(*fromKey, Int64(1)));
365                         Label loopHead(env);
366                         Label loopNext(env);
367                         Label loopEnd(env);
368                         Label loopExit(env);
369                         Jump(&loopHead);
370                         LoopBegin(&loopHead);
371                         {
372                             BRANCH(Int64LessThan(*fromKey, thisLen), &loopNext, &loopExit);
373                             Bind(&loopNext);
374                             {
375                                 GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *fromKey);
376                                 SetValueWithElementsKind(glue, thisValue, ele, *toKey, Boolean(false),
377                                     Int32(Elements::ToUint(ElementsKind::NONE)));
378                                 Jump(&loopEnd);
379                             }
380                         }
381                         Bind(&loopEnd);
382                         fromKey = Int64Add(*fromKey, Int64(1));
383                         toKey = Int64Add(*toKey, Int64(1));
384                         LoopEnd(&loopHead);
385                         Bind(&loopExit);
386                         {
387                             Label noTrim(env);
388                             Label needTrim(env);
389                             Label setNewLen(env);
390                             GateRef unused = Int64Sub(capacity, index);
391                             BRANCH(Int64GreaterThan(unused, Int64(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim);
392                             Bind(&needTrim);
393                             {
394                                 CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, index});
395                                 Jump(&setNewLen);
396                             }
397                             Bind(&noTrim);
398                             {
399                                 SetValueWithElementsKind(glue, thisValue, Hole(), index, Boolean(false),
400                                     Int32(Elements::ToUint(ElementsKind::NONE)));
401                                 Jump(&setNewLen);
402                             }
403                             Bind(&setNewLen);
404                             {
405                                 GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
406                                 Store(VariableType::INT32(), glue, thisValue, lengthOffset, index);
407 
408                                 Label isNotHole(env);
409                                 BRANCH(TaggedIsHole(*element), exit, &isNotHole);
410                                 Bind(&isNotHole);
411                                 {
412                                     result->WriteVariable(*element);
413                                     Jump(exit);
414                                 }
415                             }
416                         }
417                     }
418                 }
419             }
420         }
421     }
422 #endif
423 }
424 
Concat(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)425 void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef numArgs,
426     Variable *result, Label *exit, Label *slowPath)
427 {
428 #if ENABLE_NEXT_OPTIMIZATION
429     ConcatOptimised(glue, thisValue, numArgs, result, exit, slowPath);
430 #else
431     auto env = GetEnvironment();
432     Label isHeapObject(env);
433     Label isJsArray(env);
434     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
435     Bind(&isHeapObject);
436     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
437     Bind(&isJsArray);
438     {
439         Label isExtensible(env);
440         // need check constructor, "Concat" should use ArraySpeciesCreate
441         BRANCH(HasConstructor(thisValue), slowPath, &isExtensible);
442         Bind(&isExtensible);
443         {
444             Label numArgsOne(env);
445             BRANCH(Int64Equal(numArgs, IntPtr(1)), &numArgsOne, slowPath);
446             Bind(&numArgsOne);
447             {
448                 GateRef arg0 = GetCallArg0(numArgs);
449                 Label allStableJsArray(env);
450                 GateRef isAllStableJsArray = LogicAndBuilder(env).And(IsStableJSArray(glue, thisValue))
451                     .And(IsStableJSArray(glue, arg0)).Done();
452                 BRANCH(isAllStableJsArray, &allStableJsArray, slowPath);
453                 Bind(&allStableJsArray);
454                 {
455                     GateRef maxArrayIndex = Int64(TaggedArray::MAX_ARRAY_INDEX);
456                     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
457                     GateRef argLen = ZExtInt32ToInt64(GetArrayLength(arg0));
458                     GateRef sumArrayLen = Int64Add(argLen, thisLen);
459                     Label isEmptyArray(env);
460                     Label notEmptyArray(env);
461                     BRANCH(Int64Equal(sumArrayLen, Int64(0)), &isEmptyArray, &notEmptyArray);
462                     Bind(&isEmptyArray);
463                     {
464                         NewObjectStubBuilder newBuilder(this);
465                         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
466                         Jump(exit);
467                     }
468                     Bind(&notEmptyArray);
469                     Label notOverFlow(env);
470                     BRANCH(Int64GreaterThan(sumArrayLen, maxArrayIndex), slowPath, &notOverFlow);
471                     Bind(&notOverFlow);
472                     {
473                         Label spreadable(env);
474                         GateRef isAllConcatSpreadable = LogicAndBuilder(env).And(IsConcatSpreadable(glue, thisValue))
475                             .And(IsConcatSpreadable(glue, arg0)).Done();
476                         BRANCH(isAllConcatSpreadable, &spreadable, slowPath);
477                         Bind(&spreadable);
478                         {
479                             Label setProperties(env);
480                             GateRef glueGlobalEnvOffset =
481                                 IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
482                             GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
483                             auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
484                                 GlobalEnv::ARRAY_FUNCTION_INDEX);
485                             GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc,
486                                 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
487                             NewObjectStubBuilder newBuilder(this);
488                             newBuilder.SetParameters(glue, 0);
489                             GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, sumArrayLen);
490                             BRANCH(TaggedIsException(newArray), exit, &setProperties);
491                             Bind(&setProperties);
492                             {
493                                 GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
494                                 Store(VariableType::INT32(), glue, newArray, lengthOffset,
495                                     TruncInt64ToInt32(sumArrayLen));
496                                 GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
497                                     ConstantIndex::ARRAY_LENGTH_ACCESSOR);
498                                 Store(VariableType::JS_ANY(), glue, newArray,
499                                       IntPtr(JSArray::GetInlinedPropertyOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX)),
500                                       accessor);
501                                 SetExtensibleToBitfield(glue, newArray, true);
502                                 DEFVARIABLE(i, VariableType::INT64(), Int64(0));
503                                 DEFVARIABLE(j, VariableType::INT64(), Int64(0));
504                                 DEFVARIABLE(k, VariableType::INT64(), Int64(0));
505                                 Label loopHead(env);
506                                 Label loopEnd(env);
507                                 Label next(env);
508                                 Label loopExit(env);
509                                 Jump(&loopHead);
510                                 LoopBegin(&loopHead);
511                                 {
512                                     BRANCH(Int64LessThan(*i, thisLen), &next, &loopExit);
513                                     Bind(&next);
514                                     GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *i);
515                                     #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC
516                                     SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
517                                         Int32(Elements::ToUint(ElementsKind::GENERIC)));
518                                     #else
519                                     SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
520                                         Int32(Elements::ToUint(ElementsKind::NONE)));
521                                     #endif
522                                     Jump(&loopEnd);
523                                 }
524                                 Bind(&loopEnd);
525                                 i = Int64Add(*i, Int64(1));
526                                 j = Int64Add(*j, Int64(1));
527                                 LoopEnd(&loopHead, env, glue);
528                                 Bind(&loopExit);
529                                 Label loopHead1(env);
530                                 Label loopEnd1(env);
531                                 Label next1(env);
532                                 Label loopExit1(env);
533                                 Jump(&loopHead1);
534                                 LoopBegin(&loopHead1);
535                                 {
536                                     BRANCH(Int64LessThan(*k, argLen), &next1, &loopExit1);
537                                     Bind(&next1);
538                                     GateRef ele = GetTaggedValueWithElementsKind(glue, arg0, *k);
539                                     #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC
540                                     SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
541                                                              Int32(Elements::ToUint(ElementsKind::GENERIC)));
542                                     #else
543                                     SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
544                                                              Int32(Elements::ToUint(ElementsKind::NONE)));
545                                     #endif
546                                     Jump(&loopEnd1);
547                                 }
548                                 Bind(&loopEnd1);
549                                 k = Int64Add(*k, Int64(1));
550                                 j = Int64Add(*j, Int64(1));
551                                 LoopEnd(&loopHead1);
552                                 Bind(&loopExit1);
553                                 result->WriteVariable(newArray);
554                                 Jump(exit);
555                             }
556                         }
557                     }
558                 }
559             }
560         }
561     }
562 #endif
563 }
564 
Filter(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)565 void BuiltinsArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef numArgs,
566     Variable *result, Label *exit, Label *slowPath)
567 {
568     auto env = GetEnvironment();
569     Label isHeapObject(env);
570     Label isJsArray(env);
571     Label isprototypeJsArray(env);
572     Label defaultConstr(env);
573     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
574     Bind(&isHeapObject);
575     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
576     Bind(&isJsArray);
577     GateRef prototype = StubBuilder::GetPrototype(glue, thisValue);
578     GateRef protoIsJSArray = LogicAndBuilder(env).And(TaggedIsHeapObject(prototype)).And(IsJsArray(prototype)).Done();
579     BRANCH(protoIsJSArray, &isprototypeJsArray, slowPath);
580     Bind(&isprototypeJsArray);
581     // need check constructor, "Filter" should use ArraySpeciesCreate
582     BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr);
583     Bind(&defaultConstr);
584 
585     GateRef callbackFnHandle = GetCallArg0(numArgs);
586     Label argOHeapObject(env);
587     Label callable(env);
588     Label notOverFlow(env);
589     BRANCH(TaggedIsHeapObject(callbackFnHandle), &argOHeapObject, slowPath);
590     Bind(&argOHeapObject);
591     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
592     Bind(&callable);
593     GateRef len = ZExtInt32ToInt64(GetArrayLength(thisValue));
594     Label isEmptyArray(env);
595     Label notEmptyArray(env);
596     BRANCH(Int64Equal(len, Int64(0)), &isEmptyArray, &notEmptyArray);
597     Bind(&isEmptyArray);
598     {
599         NewObjectStubBuilder newBuilder(this);
600         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
601         Jump(exit);
602     }
603     Bind(&notEmptyArray);
604     BRANCH(Int64GreaterThan(len, Int64(JSObject::MAX_GAP)), slowPath, &notOverFlow);
605     Bind(&notOverFlow);
606 
607     GateRef argHandle = GetCallArg1(numArgs);
608     GateRef kind = GetElementsKindFromHClass(LoadHClass(thisValue));
609     GateRef newHClass =  GetElementsKindHClass(glue, kind);
610     GateRef newArray = NewArrayWithHClass(glue, newHClass, TruncInt64ToInt32(len));
611     GateRef newArrayEles = GetElementsArray(newArray);
612     Label stableJSArray(env);
613     Label notStableJSArray(env);
614     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
615     DEFVARIABLE(toIndex, VariableType::INT64(), Int64(0));
616     BRANCH(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
617     Bind(&stableJSArray);
618     {
619         DEFVARIABLE(thisArrLenVar, VariableType::INT64(), len);
620         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
621         Label enabledMutantArray(env);
622         Label disabledMutantArray(env);
623         BRANCH(IsEnableMutantArray(glue), &enabledMutantArray, &disabledMutantArray);
624         Bind(&enabledMutantArray);
625         {
626             Label kValueIsHole(env);
627             Label kValueNotHole(env);
628             Label loopHead(env);
629             Label loopEnd(env);
630             Label next(env);
631             Label loopExit(env);
632             Jump(&loopHead);
633             LoopBegin(&loopHead);
634             {
635                 BRANCH(Int64LessThan(*i, *thisArrLenVar), &next, &loopExit);
636                 Bind(&next);
637                 kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
638                 BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &kValueNotHole);
639                 Bind(&kValueNotHole);
640                 {
641                     GateRef key = Int64ToTaggedInt(*i);
642                     Label checkArray(env);
643                     JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
644                     callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
645                     CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS),
646                         0, nullptr, Circuit::NullGate(), callArgs);
647                     GateRef retValue = callBuilder.JSCallDispatch();
648                     Label find(env);
649                     Label hasException1(env);
650                     Label notHasException1(env);
651                     BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
652                     Bind(&hasException1);
653                     {
654                         result->WriteVariable(Exception());
655                         Jump(exit);
656                     }
657                     Bind(&notHasException1);
658                     BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &checkArray);
659                     Bind(&find);
660                     {
661                         SetValueWithElementsKind(glue, newArray, *kValue, *toIndex, Boolean(true),
662                                                  Int32(Elements::ToUint(ElementsKind::NONE)));
663                         toIndex = Int64Add(*toIndex, Int64(1));
664                         Jump(&checkArray);
665                     }
666                     Bind(&checkArray);
667                     {
668                         Label lenChange(env);
669                         GateRef tmpArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
670                         BRANCH(Int64LessThan(tmpArrLen, *thisArrLenVar), &lenChange, &kValueIsHole);
671                         Bind(&lenChange);
672                         {
673                             thisArrLenVar = tmpArrLen;
674                             Jump(&kValueIsHole);
675                         }
676                     }
677                 }
678                 Bind(&kValueIsHole);
679                 i = Int64Add(*i, Int64(1));
680                 BRANCH(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
681             }
682             Bind(&loopEnd);
683             LoopEnd(&loopHead);
684             Bind(&loopExit);
685             Jump(&notStableJSArray);
686         }
687         Bind(&disabledMutantArray);
688         {
689             Label kValueIsHole(env);
690             Label kValueNotHole(env);
691             Label loopHead(env);
692             Label loopEnd(env);
693             Label next(env);
694             Label loopExit(env);
695             Jump(&loopHead);
696             LoopBegin(&loopHead);
697             {
698                 BRANCH(Int64LessThan(*i, *thisArrLenVar), &next, &loopExit);
699                 Bind(&next);
700                 GateRef elements = GetElementsArray(thisValue);
701                 kValue = GetValueFromTaggedArray(elements, *i);
702                 BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &kValueNotHole);
703                 Bind(&kValueNotHole);
704                 {
705                     GateRef key = Int64ToTaggedInt(*i);
706                     Label checkArray(env);
707                     JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
708                     callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
709                     CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
710                         nullptr, Circuit::NullGate(), callArgs);
711                     GateRef retValue = callBuilder.JSCallDispatch();
712                     Label find(env);
713                     Label hasException1(env);
714                     Label notHasException1(env);
715                     BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
716                     Bind(&hasException1);
717                     {
718                         result->WriteVariable(Exception());
719                         Jump(exit);
720                     }
721                     Bind(&notHasException1);
722                     BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &checkArray);
723                     Bind(&find);
724                     {
725                         SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayEles, *toIndex, *kValue);
726                         toIndex = Int64Add(*toIndex, Int64(1));
727                         Jump(&checkArray);
728                     }
729                     Bind(&checkArray);
730                     {
731                         Label lenChange(env);
732                         GateRef tmpArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
733                         BRANCH(Int64LessThan(tmpArrLen, *thisArrLenVar), &lenChange, &kValueIsHole);
734                         Bind(&lenChange);
735                         {
736                             thisArrLenVar = tmpArrLen;
737                             Jump(&kValueIsHole);
738                         }
739                     }
740                 }
741                 Bind(&kValueIsHole);
742                 i = Int64Add(*i, Int64(1));
743                 BRANCH(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
744             }
745             Bind(&loopEnd);
746             LoopEnd(&loopHead);
747             Bind(&loopExit);
748             Jump(&notStableJSArray);
749         }
750     }
751     Bind(&notStableJSArray);
752     {
753         Label finish(env);
754         Label callRT(env);
755         BRANCH(Int64LessThan(*i, len), &callRT, &finish);
756         Bind(&callRT);
757         {
758             CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, newArrayEles, *toIndex});
759             Store(VariableType::INT32(), glue, newArray, IntPtr(JSArray::LENGTH_OFFSET), TruncInt64ToInt32(*toIndex));
760             GateRef ret = CallRuntime(glue, RTSTUB_ID(JSArrayFilterUnStable), { argHandle, thisValue,
761                 IntToTaggedInt(*i), IntToTaggedInt(len), IntToTaggedInt(*toIndex), newArray, callbackFnHandle });
762             result->WriteVariable(ret);
763             Jump(exit);
764         }
765         Bind(&finish);
766         {
767             result->WriteVariable(newArray);
768             Label needTrim(env);
769             BRANCH(Int64LessThan(*toIndex, len), &needTrim, exit);
770             Bind(&needTrim);
771             CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, newArrayEles, *toIndex});
772             Store(VariableType::INT32(), glue, newArray, IntPtr(JSArray::LENGTH_OFFSET), TruncInt64ToInt32(*toIndex));
773             Jump(exit);
774         }
775     }
776 }
777 
Map(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)778 void BuiltinsArrayStubBuilder::Map(GateRef glue, GateRef thisValue, GateRef numArgs,
779     Variable *result, Label *exit, Label *slowPath)
780 {
781     auto env = GetEnvironment();
782     Label isHeapObject(env);
783     Label isJsArray(env);
784     Label isprototypeJsArray(env);
785     Label defaultConstr(env);
786     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
787     Bind(&isHeapObject);
788     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
789     Bind(&isJsArray);
790     GateRef prototype = StubBuilder::GetPrototype(glue, thisValue);
791     GateRef protoIsJSArray = LogicAndBuilder(env).And(TaggedIsHeapObject(prototype)).And(IsJsArray(prototype)).Done();
792     BRANCH(protoIsJSArray, &isprototypeJsArray, slowPath);
793     Bind(&isprototypeJsArray);
794     // need check constructor, "Map" should use ArraySpeciesCreate
795     BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr);
796     Bind(&defaultConstr);
797 
798     GateRef callbackFnHandle = GetCallArg0(numArgs);
799     Label argOHeapObject(env);
800     Label callable(env);
801     Label notOverFlow(env);
802     BRANCH(TaggedIsHeapObject(callbackFnHandle), &argOHeapObject, slowPath);
803     Bind(&argOHeapObject);
804     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
805     Bind(&callable);
806     GateRef len = ZExtInt32ToInt64(GetArrayLength(thisValue));
807     Label isEmptyArray(env);
808     Label notEmptyArray(env);
809     BRANCH(Int64Equal(len, Int64(0)), &isEmptyArray, &notEmptyArray);
810     Bind(&isEmptyArray);
811     {
812         NewObjectStubBuilder newBuilder(this);
813         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
814         Jump(exit);
815     }
816     Bind(&notEmptyArray);
817     BRANCH(Int64GreaterThan(len, Int64(JSObject::MAX_GAP)), slowPath, &notOverFlow);
818     Bind(&notOverFlow);
819 
820     GateRef argHandle = GetCallArg1(numArgs);
821     GateRef newArray = NewArray(glue, len);
822     Label stableJSArray(env);
823     Label notStableJSArray(env);
824     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
825     BRANCH(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
826     Bind(&stableJSArray);
827     {
828         DEFVARIABLE(thisArrLenVar, VariableType::INT64(), len);
829         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
830         Label loopHead(env);
831         Label loopEnd(env);
832         Label next(env);
833         Label loopExit(env);
834         Jump(&loopHead);
835         LoopBegin(&loopHead);
836         {
837             BRANCH(Int64LessThan(*i, *thisArrLenVar), &next, &loopExit);
838             Bind(&next);
839             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
840             Label kValueIsHole(env);
841             Label kValueNotHole(env);
842             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &kValueNotHole);
843             Bind(&kValueNotHole);
844             {
845                 GateRef key = Int64ToTaggedInt(*i);
846                 Label checkArray(env);
847                 JSCallArgs callArgs = (JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
848                 callArgs.callThisArg3WithReturnArgs = {argHandle, *kValue, key, thisValue};
849                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
850                     Circuit::NullGate(), callArgs);
851                 GateRef retValue = callBuilder.JSCallDispatch();
852                 Label hasException1(env);
853                 Label notHasException1(env);
854                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
855                 Bind(&hasException1);
856                 {
857                     result->WriteVariable(Exception());
858                     Jump(exit);
859                 }
860                 Bind(&notHasException1);
861                 SetValueWithElementsKind(glue, newArray, retValue, *i, Boolean(true),
862                                          Int32(Elements::ToUint(ElementsKind::NONE)));
863                 Label lenChange(env);
864                 GateRef tmpArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
865                 BRANCH(Int64LessThan(tmpArrLen, *thisArrLenVar), &lenChange, &kValueIsHole);
866                 Bind(&lenChange);
867                 {
868                     thisArrLenVar = tmpArrLen;
869                     Jump(&kValueIsHole);
870                 }
871             }
872             Bind(&kValueIsHole);
873             i = Int64Add(*i, Int64(1));
874             BRANCH(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
875         }
876         Bind(&loopEnd);
877         LoopEnd(&loopHead);
878         Bind(&loopExit);
879         Jump(&notStableJSArray);
880     }
881     Bind(&notStableJSArray);
882     {
883         GateRef ret = CallRuntime(glue, RTSTUB_ID(JSArrayMapUnStable), { argHandle, thisValue,
884             IntToTaggedInt(*i), IntToTaggedInt(len), newArray, callbackFnHandle });
885         result->WriteVariable(ret);
886         Jump(exit);
887     }
888 }
889 
890 // Note: unused arguments are reserved for further development
ForEach(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)891 void BuiltinsArrayStubBuilder::ForEach([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
892     [[maybe_unused]] Variable *result, Label *exit, Label *slowPath)
893 {
894 #if ENABLE_NEXT_OPTIMIZATION
895     ForEachOptimised(glue, thisValue, numArgs, result, exit, slowPath);
896 #else
897     auto env = GetEnvironment();
898     Label thisExists(env);
899     Label isHeapObject(env);
900     Label isJsArray(env);
901     Label isStability(env);
902     Label notCOWArray(env);
903     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
904     Bind(&thisExists);
905     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
906     Bind(&isHeapObject);
907     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
908     Bind(&isJsArray);
909     // don't check constructor, "ForEach" won't create new array.
910     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
911     Bind(&isStability);
912     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
913     Bind(&notCOWArray);
914     Label arg0HeapObject(env);
915     Label callable(env);
916     Label thisIsStable(env);
917     Label thisNotStable(env);
918     GateRef callbackFnHandle = GetCallArg0(numArgs);
919     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
920     Bind(&arg0HeapObject);
921     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
922     Bind(&callable);
923     GateRef argHandle = GetCallArg1(numArgs);
924 
925     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
926     DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0));
927     thisLen = GetArrayLength(thisValue);
928     Jump(&thisIsStable);
929 
930     Bind(&thisIsStable);
931     {
932         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
933         Label loopHead(env);
934         Label loopEnd(env);
935         Label next(env);
936         Label loopExit(env);
937         Jump(&loopHead);
938         LoopBegin(&loopHead);
939         {
940             Label nextStep(env);
941             Label kValueIsHole(env);
942             Label callDispatch(env);
943             Label hasProperty(env);
944             Label hasException0(env);
945             Label hasException1(env);
946             GateRef newLen = GetArrayLength(thisValue);
947             BRANCH(BitAnd(IsStableJSArray(glue, thisValue), Int32Equal(*thisLen, newLen)),
948                 &nextStep, &thisNotStable);
949             Bind(&nextStep);
950             BRANCH(Int64GreaterThanOrEqual(*i, ZExtInt32ToInt64(*thisLen)), &loopExit, &next);
951             Bind(&next);
952             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
953             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
954             Bind(&kValueIsHole);
955             {
956                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
957                 BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
958                 Bind(&hasProperty);
959                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
960                 BRANCH(HasPendingException(glue), &hasException0, &callDispatch);
961                 Bind(&hasException0);
962                 {
963                     result->WriteVariable(Exception());
964                     Jump(exit);
965                 }
966             }
967             Bind(&callDispatch);
968             {
969                 GateRef key = Int64ToTaggedInt(*i);
970                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
971                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
972                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
973                     Circuit::NullGate(), callArgs);
974                 callBuilder.JSCallDispatch();
975                 BRANCH(HasPendingException(glue), &hasException1, &loopEnd);
976                 Bind(&hasException1);
977                 {
978                     result->WriteVariable(Exception());
979                     Jump(exit);
980                 }
981             }
982         }
983         Bind(&loopEnd);
984         i = Int64Add(*i, Int64(1));
985         LoopEnd(&loopHead);
986         Bind(&loopExit);
987         Jump(exit);
988     }
989 
990     Bind(&thisNotStable);
991     {
992         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
993         Label loopHead(env);
994         Label loopEnd(env);
995         Label next(env);
996         Label loopExit(env);
997         Jump(&loopHead);
998         LoopBegin(&loopHead);
999         {
1000             Label hasProperty(env);
1001             Label hasException0(env);
1002             Label notHasException0(env);
1003             Label hasException1(env);
1004             BRANCH(Int64GreaterThanOrEqual(*i, ZExtInt32ToInt64(*thisLen)), &loopExit, &next);
1005             Bind(&next);
1006             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
1007             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
1008             Bind(&hasProperty);
1009             kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
1010             BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
1011             Bind(&hasException0);
1012             {
1013                 result->WriteVariable(Exception());
1014                 Jump(exit);
1015             }
1016             Bind(&notHasException0);
1017             {
1018                 GateRef key = Int64ToTaggedInt(*i);
1019                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1020                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
1021                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
1022                     Circuit::NullGate(), callArgs);
1023                 callBuilder.JSCallDispatch();
1024                 BRANCH(HasPendingException(glue), &hasException1, &loopEnd);
1025                 Bind(&hasException1);
1026                 {
1027                     result->WriteVariable(Exception());
1028                     Jump(exit);
1029                 }
1030             }
1031         }
1032         Bind(&loopEnd);
1033         i = Int64Add(*i, Int64(1));
1034         LoopEnd(&loopHead);
1035         Bind(&loopExit);
1036         Jump(exit);
1037     }
1038 #endif
1039 }
1040 
ArrayIteratorNext(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1041 void BuiltinsArrayStubBuilder::ArrayIteratorNext(GateRef glue, GateRef thisValue,
1042     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1043 {
1044     auto env = GetEnvironment();
1045     DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
1046     DEFVARIABLE(iterValue, VariableType::JS_ANY(), Undefined());
1047 
1048     Label thisIsArrayIterator(env);
1049     Label arrayNotUndefined(env);
1050     Label isStableJsArray(env);
1051     Label NotStableJsArray(env);
1052     Label isTypedArray(env);
1053     Label isArrayLikeObject(env);
1054     Label throwException(env);
1055     Label checkNeedCreateEntry(env);
1056     Label iterDone(env);
1057     Label createIterResult(env);
1058 
1059     GateRef array = Circuit::NullGate();
1060     GateRef index = Circuit::NullGate();
1061 
1062     BRANCH(TaggedIsArrayIterator(thisValue), &thisIsArrayIterator, slowPath);
1063     Bind(&thisIsArrayIterator);
1064     {
1065         array = Load(VariableType::JS_POINTER(), thisValue, IntPtr(JSArrayIterator::ITERATED_ARRAY_OFFSET));
1066         BRANCH(TaggedIsUndefined(array), &iterDone, &arrayNotUndefined);
1067     }
1068     Bind(&arrayNotUndefined);
1069     {
1070         index = Load(VariableType::INT32(), thisValue, IntPtr(JSArrayIterator::NEXT_INDEX_OFFSET));
1071         BRANCH(IsStableJSArray(glue, array), &isStableJsArray, &NotStableJsArray);
1072     }
1073     Bind(&isStableJsArray);
1074     {
1075         Label indexIsValid(env);
1076         Label kindIsNotKey(env);
1077         Label eleIsHole(env);
1078         Label hasProperty(env);
1079         GateRef length = GetArrayLength(array);
1080         BRANCH(Int32UnsignedLessThan(index, length), &indexIsValid, &iterDone);
1081         Bind(&indexIsValid);
1082         {
1083             IncreaseArrayIteratorIndex(glue, thisValue, index);
1084             iterValue = IntToTaggedPtr(index);
1085             BRANCH(Int32Equal(GetArrayIterationKind(thisValue), Int32(static_cast<int32_t>(IterationKind::KEY))),
1086                    &createIterResult, &kindIsNotKey);
1087             Bind(&kindIsNotKey);
1088             {
1089                 iterValue = GetTaggedValueWithElementsKind(glue, array, index);
1090                 Jump(&checkNeedCreateEntry);
1091             }
1092         }
1093     }
1094     Bind(&NotStableJsArray);
1095     BRANCH(IsTypedArray(array), &isTypedArray, &isArrayLikeObject);
1096     Bind(&isTypedArray);
1097     {
1098         Label indexIsValid(env);
1099         Label kindIsNotKey(env);
1100         BuiltinsTypedArrayStubBuilder typedArrayBuilder(this);
1101         GateRef length = typedArrayBuilder.GetArrayLength(array);
1102         BRANCH(Int32UnsignedLessThan(index, length), &indexIsValid, &iterDone);
1103         Bind(&indexIsValid);
1104         {
1105             IncreaseArrayIteratorIndex(glue, thisValue, index);
1106             iterValue = IntToTaggedPtr(index);
1107             BRANCH(Int32Equal(GetArrayIterationKind(thisValue), Int32(static_cast<int32_t>(IterationKind::KEY))),
1108                    &createIterResult, &kindIsNotKey);
1109             Bind(&kindIsNotKey);
1110             {
1111                 iterValue = typedArrayBuilder.FastGetPropertyByIndex(glue, array, index,
1112                                                                      GetObjectType(LoadHClass(array)));
1113                 BRANCH(HasPendingException(glue), &throwException, &checkNeedCreateEntry);
1114             }
1115         }
1116     }
1117     Bind(&isArrayLikeObject);
1118     {
1119         Label indexIsValid(env);
1120         Label kindIsNotKey(env);
1121         Label propertyToLength(env);
1122         Label noPendingException(env);
1123         GateRef rawLength = Circuit::NullGate();
1124         GateRef lengthString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
1125                                                       ConstantIndex::LENGTH_STRING_INDEX);
1126         GateRef value = FastGetPropertyByName(glue, array, lengthString, ProfileOperation());
1127         BRANCH(HasPendingException(glue), &throwException, &propertyToLength);
1128         Bind(&propertyToLength);
1129         {
1130             rawLength = ToLength(glue, value);
1131             BRANCH(HasPendingException(glue), &throwException, &noPendingException);
1132         }
1133         Bind(&noPendingException);
1134         {
1135             GateRef length = GetInt32OfTNumber(rawLength);
1136             BRANCH(Int32UnsignedLessThan(index, length), &indexIsValid, &iterDone);
1137             Bind(&indexIsValid);
1138             {
1139                 IncreaseArrayIteratorIndex(glue, thisValue, index);
1140                 iterValue = IntToTaggedPtr(index);
1141                 BRANCH(Int32Equal(GetArrayIterationKind(thisValue), Int32(static_cast<int32_t>(IterationKind::KEY))),
1142                        &createIterResult, &kindIsNotKey);
1143                 Bind(&kindIsNotKey);
1144                 {
1145                     iterValue = FastGetPropertyByIndex(glue, array, index, ProfileOperation());
1146                     BRANCH(HasPendingException(glue), &throwException, &checkNeedCreateEntry);
1147                 }
1148             }
1149         }
1150     }
1151     Bind(&throwException);
1152     {
1153         result->WriteVariable(Exception());
1154         Jump(exit);
1155     }
1156     Bind(&checkNeedCreateEntry);
1157     {
1158         Label kindIsEntry(env);
1159         BRANCH(Int32Equal(GetArrayIterationKind(thisValue), Int32(static_cast<int32_t>(IterationKind::KEY_AND_VALUE))),
1160                &kindIsEntry, &createIterResult);
1161         Bind(&kindIsEntry);
1162         {
1163             Label afterCreate(env);
1164             NewObjectStubBuilder newBuilder(this);
1165             GateRef elements = newBuilder.NewTaggedArray(glue, Int32(2)); // 2: length of array
1166             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(0), IntToTaggedPtr(index)); // 0: key
1167             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(1), *iterValue); // 1: value
1168             iterValue = newBuilder.CreateArrayFromList(glue, elements,
1169                 Int32(Elements::ToUint(ElementsKind::TAGGED)));
1170             Jump(&createIterResult);
1171         }
1172     }
1173     Bind(&createIterResult);
1174     {
1175         Label afterCreate(env);
1176         NewObjectStubBuilder newBuilder(this);
1177         newBuilder.CreateJSIteratorResult(glue, &res, *iterValue, TaggedFalse(), &afterCreate);
1178         Bind(&afterCreate);
1179         result->WriteVariable(*res);
1180         Jump(exit);
1181     }
1182     Bind(&iterDone);
1183     {
1184         SetIteratedArrayOfArrayIterator(glue, thisValue, Undefined());
1185         Label afterCreate(env);
1186         NewObjectStubBuilder newBuilder(this);
1187         newBuilder.CreateJSIteratorResult(glue, &res, Undefined(), TaggedTrue(), &afterCreate);
1188         Bind(&afterCreate);
1189         result->WriteVariable(*res);
1190         Jump(exit);
1191     }
1192 }
1193 
1194 // Note: unused arguments are reserved for further development
IndexOf(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1195 void BuiltinsArrayStubBuilder::IndexOf([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
1196     Variable *result, Label *exit, Label *slowPath)
1197 {
1198 #if ENABLE_NEXT_OPTIMIZATION
1199     IndexOfOptions options;
1200     options.compType = ComparisonType::STRICT_EQUAL;
1201     options.returnType = IndexOfReturnType::TAGGED_FOUND_INDEX;
1202     options.holeAsUndefined = false;
1203     options.reversedOrder = false;
1204     return IndexOfOptimised(glue, thisValue, numArgs, result, exit, slowPath, options);
1205 #else
1206     auto env = GetEnvironment();
1207     Label thisIsEmpty(env);
1208     // Fast path if: (1) this is an empty array; (2) fromIndex is missing
1209     JsArrayRequirements req;
1210     BRANCH(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath);
1211     Bind(&thisIsEmpty);
1212     {
1213         Label atMostOneArg(env);
1214         BRANCH(Int32LessThanOrEqual(TruncPtrToInt32(numArgs), Int32(1)), &atMostOneArg, slowPath);
1215         // Returns -1 on fast path
1216         Bind(&atMostOneArg);
1217         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
1218         Jump(exit);
1219     }
1220 #endif
1221 }
1222 
1223 // Note: unused arguments are reserved for further development
LastIndexOf(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1224 void BuiltinsArrayStubBuilder::LastIndexOf([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
1225     Variable *result, Label *exit, Label *slowPath)
1226 {
1227 #if ENABLE_NEXT_OPTIMIZATION
1228     IndexOfOptions options;
1229     options.compType = ComparisonType::STRICT_EQUAL;
1230     options.returnType = IndexOfReturnType::TAGGED_FOUND_INDEX;
1231     options.holeAsUndefined = false;
1232     options.reversedOrder = true;
1233     return IndexOfOptimised(glue, thisValue, numArgs, result, exit, slowPath, options);
1234 #else
1235     auto env = GetEnvironment();
1236     Label thisIsEmpty(env);
1237     // Fast path if: (1) this is an empty array; (2) fromIndex is missing
1238     JsArrayRequirements req;
1239     BRANCH(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath);
1240     Bind(&thisIsEmpty);
1241     {
1242         Label atMostOneArg(env);
1243         BRANCH(Int32LessThanOrEqual(TruncPtrToInt32(numArgs), Int32(1)), &atMostOneArg, slowPath);
1244         // Returns -1 on fast path
1245         Bind(&atMostOneArg);
1246         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
1247         Jump(exit);
1248     }
1249 #endif
1250 }
1251 
Pop(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1252 void BuiltinsArrayStubBuilder::Pop(GateRef glue, GateRef thisValue,
1253     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1254 {
1255 #if ENABLE_NEXT_OPTIMIZATION
1256     PopOptimised(glue, thisValue, numArgs, result, exit, slowPath);
1257 #else
1258     auto env = GetEnvironment();
1259     Label isHeapObject(env);
1260     Label stableJSArray(env);
1261     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1262     Bind(&isHeapObject);
1263     // don't check constructor, "Pop" won't create new array.
1264     BRANCH(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
1265     Bind(&stableJSArray);
1266 
1267     Label isLengthWritable(env);
1268     BRANCH(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
1269     Bind(&isLengthWritable);
1270     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1271 
1272     Label notZeroLen(env);
1273     BRANCH(Int64Equal(thisLen, Int64(0)), exit, &notZeroLen);
1274     Bind(&notZeroLen);
1275     Label isJsCOWArray(env);
1276     Label getElements(env);
1277     BRANCH(IsJsCOWArray(thisValue), &isJsCOWArray, &getElements);
1278     Bind(&isJsCOWArray);
1279     {
1280         CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), { thisValue });
1281         Jump(&getElements);
1282     }
1283     Bind(&getElements);
1284     GateRef elements = GetElementsArray(thisValue);
1285     GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(elements));
1286     GateRef index = Int64Sub(thisLen, Int64(1));
1287 
1288     Label inRange(env);
1289     Label trimCheck(env);
1290     Label noTrimCheck(env);
1291     Label setNewLen(env);
1292     Label isHole(env);
1293     DEFVARIABLE(element, VariableType::JS_ANY(), Hole());
1294     BRANCH(Int64LessThan(index, capacity), &inRange, &trimCheck);
1295     Bind(&inRange);
1296     {
1297         element = GetTaggedValueWithElementsKind(glue, thisValue, index);
1298         Jump(&isHole);
1299     }
1300     Bind(&isHole);
1301     BRANCH(TaggedIsHole(*element), &noTrimCheck, &trimCheck);
1302     Bind(&noTrimCheck);
1303     {
1304         Label hasException0(env);
1305         Label notHasException0(env);
1306         element = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(index), ProfileOperation());
1307         BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
1308         Bind(&hasException0);
1309         {
1310             result->WriteVariable(Exception());
1311             Jump(exit);
1312         }
1313         Bind(&notHasException0);
1314         {
1315             Jump(&setNewLen);
1316         }
1317     }
1318     Bind(&trimCheck);
1319     // ShouldTrim check
1320     // (oldLength - newLength > MAX_END_UNUSED)
1321     Label noTrim(env);
1322     Label needTrim(env);
1323     GateRef unused = Int64Sub(capacity, index);
1324     BRANCH(Int64GreaterThan(unused, Int64(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim);
1325     Bind(&needTrim);
1326     {
1327         CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, index});
1328         Jump(&setNewLen);
1329     }
1330     Bind(&noTrim);
1331     {
1332         SetValueWithElementsKind(glue, thisValue, Hole(), index, Boolean(false),
1333                                  Int32(Elements::ToUint(ElementsKind::NONE)));
1334         Jump(&setNewLen);
1335     }
1336     Bind(&setNewLen);
1337     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
1338     Store(VariableType::INT32(), glue, thisValue, lengthOffset, TruncInt64ToInt32(index));
1339 
1340     Label isNotHole(env);
1341     BRANCH(TaggedIsHole(*element), exit, &isNotHole);
1342     Bind(&isNotHole);
1343     {
1344         result->WriteVariable(*element);
1345         Jump(exit);
1346     }
1347 #endif
1348 }
1349 
Slice(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1350 void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef numArgs,
1351     Variable *result, Label *exit, Label *slowPath)
1352 {
1353 #if ENABLE_NEXT_OPTIMIZATION
1354     SliceOptimised(glue, thisValue, numArgs, result, exit, slowPath);
1355 #else
1356     auto env = GetEnvironment();
1357     Label isHeapObject(env);
1358     Label isJsArray(env);
1359     Label noConstructor(env);
1360     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1361     Bind(&isHeapObject);
1362     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
1363     Bind(&isJsArray);
1364     // need check constructor, "Slice" should use ArraySpeciesCreate
1365     BRANCH(HasConstructor(thisValue), slowPath, &noConstructor);
1366     Bind(&noConstructor);
1367 
1368     Label thisIsEmpty(env);
1369     Label thisNotEmpty(env);
1370     // Fast path if:
1371     // (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details);
1372     // (2) no arguments exist
1373     JsArrayRequirements req;
1374     req.defaultConstructor = true;
1375     BRANCH(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, &thisNotEmpty);
1376     Bind(&thisIsEmpty);
1377     {
1378         Label noArgs(env);
1379         GateRef numArgsAsInt32 = TruncPtrToInt32(numArgs);
1380         BRANCH(Int32Equal(numArgsAsInt32, Int32(0)), &noArgs, slowPath);
1381         // Creates a new empty array on fast path
1382         Bind(&noArgs);
1383         NewObjectStubBuilder newBuilder(this);
1384         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
1385         Jump(exit);
1386     }
1387     Bind(&thisNotEmpty);
1388     {
1389         Label stableJSArray(env);
1390         Label arrayLenNotZero(env);
1391 
1392         GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue);
1393         BRANCH(isThisStableJSArray, &stableJSArray, slowPath);
1394         Bind(&stableJSArray);
1395 
1396         GateRef msg0 = GetCallArg0(numArgs);
1397         GateRef msg1 = GetCallArg1(numArgs);
1398         GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1399         Label msg0Int(env);
1400         BRANCH(TaggedIsInt(msg0), &msg0Int, slowPath);
1401         Bind(&msg0Int);
1402         DEFVARIABLE(start, VariableType::INT64(), Int64(0));
1403         DEFVARIABLE(end, VariableType::INT64(), thisArrLen);
1404 
1405         GateRef argStart = SExtInt32ToInt64(TaggedGetInt(msg0));
1406         Label arg0LessZero(env);
1407         Label arg0NotLessZero(env);
1408         Label startDone(env);
1409         BRANCH(Int64LessThan(argStart, Int64(0)), &arg0LessZero, &arg0NotLessZero);
1410         Bind(&arg0LessZero);
1411         {
1412             Label tempGreaterZero(env);
1413             Label tempNotGreaterZero(env);
1414             GateRef tempStart = Int64Add(argStart, thisArrLen);
1415             BRANCH(Int64GreaterThan(tempStart, Int64(0)), &tempGreaterZero, &tempNotGreaterZero);
1416             Bind(&tempGreaterZero);
1417             {
1418                 start = tempStart;
1419                 Jump(&startDone);
1420             }
1421             Bind(&tempNotGreaterZero);
1422             {
1423                 Jump(&startDone);
1424             }
1425         }
1426         Bind(&arg0NotLessZero);
1427         {
1428             Label argLessLen(env);
1429             Label argNotLessLen(env);
1430             BRANCH(Int64LessThan(argStart, thisArrLen), &argLessLen, &argNotLessLen);
1431             Bind(&argLessLen);
1432             {
1433                 start = argStart;
1434                 Jump(&startDone);
1435             }
1436             Bind(&argNotLessLen);
1437             {
1438                 start = thisArrLen;
1439                 Jump(&startDone);
1440             }
1441         }
1442         Bind(&startDone);
1443         {
1444             Label endDone(env);
1445             Label msg1Def(env);
1446             BRANCH(TaggedIsUndefined(msg1), &endDone, &msg1Def);
1447             Bind(&msg1Def);
1448             {
1449                 Label msg1Int(env);
1450                 BRANCH(TaggedIsInt(msg1), &msg1Int, slowPath);
1451                 Bind(&msg1Int);
1452                 {
1453                     GateRef argEnd = SExtInt32ToInt64(TaggedGetInt(msg1));
1454                     Label arg1LessZero(env);
1455                     Label arg1NotLessZero(env);
1456                     BRANCH(Int64LessThan(argEnd, Int64(0)), &arg1LessZero, &arg1NotLessZero);
1457                     Bind(&arg1LessZero);
1458                     {
1459                         Label tempGreaterZero(env);
1460                         Label tempNotGreaterZero(env);
1461                         GateRef tempEnd = Int64Add(argEnd, thisArrLen);
1462                         BRANCH(Int64GreaterThan(tempEnd, Int64(0)), &tempGreaterZero, &tempNotGreaterZero);
1463                         Bind(&tempGreaterZero);
1464                         {
1465                             end = tempEnd;
1466                             Jump(&endDone);
1467                         }
1468                         Bind(&tempNotGreaterZero);
1469                         {
1470                             end = Int64(0);
1471                             Jump(&endDone);
1472                         }
1473                     }
1474                     Bind(&arg1NotLessZero);
1475                     {
1476                         Label argLessLen(env);
1477                         Label argNotLessLen(env);
1478                         BRANCH(Int64LessThan(argEnd, thisArrLen), &argLessLen, &argNotLessLen);
1479                         Bind(&argLessLen);
1480                         {
1481                             end = argEnd;
1482                             Jump(&endDone);
1483                         }
1484                         Bind(&argNotLessLen);
1485                         {
1486                             end = thisArrLen;
1487                             Jump(&endDone);
1488                         }
1489                     }
1490                 }
1491             }
1492             Bind(&endDone);
1493             {
1494                 DEFVARIABLE(count, VariableType::INT64(), Int64(0));
1495                 GateRef tempCnt = Int64Sub(*end, *start);
1496                 Label tempCntGreaterOrEqualZero(env);
1497                 Label tempCntDone(env);
1498                 BRANCH(Int64LessThan(tempCnt, Int64(0)), &tempCntDone, &tempCntGreaterOrEqualZero);
1499                 Bind(&tempCntGreaterOrEqualZero);
1500                 {
1501                     count = tempCnt;
1502                     Jump(&tempCntDone);
1503                 }
1504                 Bind(&tempCntDone);
1505                 {
1506                     Label notOverFlow(env);
1507                     BRANCH(Int64GreaterThan(*count, Int64(JSObject::MAX_GAP)), slowPath, &notOverFlow);
1508                     Bind(&notOverFlow);
1509                     {
1510                         GateRef newArray = NewArray(glue, *count);
1511                         GateRef thisEles = GetElementsArray(thisValue);
1512                         GateRef thisElesLen = ZExtInt32ToInt64(GetLengthOfTaggedArray(thisEles));
1513 
1514                         Label inThisEles(env);
1515                         Label outThisEles(env);
1516                         BRANCH(Int64GreaterThan(thisElesLen, Int64Add(*start, *count)), &inThisEles, &outThisEles);
1517                         Bind(&inThisEles);
1518                         {
1519                             DEFVARIABLE(idx, VariableType::INT64(), Int64(0));
1520                             Label loopHead(env);
1521                             Label loopEnd(env);
1522                             Label next(env);
1523                             Label loopExit(env);
1524                             Jump(&loopHead);
1525                             LoopBegin(&loopHead);
1526                             {
1527                                 BRANCH(Int64LessThan(*idx, *count), &next, &loopExit);
1528                                 Bind(&next);
1529 
1530                                 GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, Int64Add(*idx, *start));
1531                                 SetValueWithElementsKind(glue, newArray, ele, *idx, Boolean(true),
1532                                                          Int32(Elements::ToUint(ElementsKind::NONE)));
1533                                 Jump(&loopEnd);
1534                             }
1535                             Bind(&loopEnd);
1536                             idx = Int64Add(*idx, Int64(1));
1537                             LoopEnd(&loopHead, env, glue);
1538                             Bind(&loopExit);
1539                             result->WriteVariable(newArray);
1540                             Jump(exit);
1541                         }
1542                         Bind(&outThisEles);
1543                         {
1544                             DEFVARIABLE(idx, VariableType::INT64(), Int64(0));
1545                             Label loopHead(env);
1546                             Label loopEnd(env);
1547                             Label next(env);
1548                             Label loopExit(env);
1549                             Jump(&loopHead);
1550                             LoopBegin(&loopHead);
1551                             {
1552                                 BRANCH(Int64LessThan(*idx, *count), &next, &loopExit);
1553                                 Bind(&next);
1554                                 GateRef index = Int64Add(*idx, *start);
1555                                 DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
1556 
1557                                 Label indexOutRange(env);
1558                                 Label indexInRange(env);
1559                                 Label setEle(env);
1560                                 BRANCH(Int64GreaterThan(thisElesLen, index), &indexInRange, &indexOutRange);
1561                                 Bind(&indexInRange);
1562                                 {
1563                                     ele = GetTaggedValueWithElementsKind(glue, thisValue, index);
1564                                     Jump(&setEle);
1565                                 }
1566                                 Bind(&indexOutRange);
1567                                 {
1568                                     ele = Hole();
1569                                     Jump(&setEle);
1570                                 }
1571                                 Bind(&setEle);
1572                                 SetValueWithElementsKind(glue, newArray, *ele, *idx, Boolean(true),
1573                                                          Int32(Elements::ToUint(ElementsKind::NONE)));
1574                                 Jump(&loopEnd);
1575                             }
1576                             Bind(&loopEnd);
1577                             idx = Int64Add(*idx, Int64(1));
1578                             LoopEnd(&loopHead, env, glue);
1579                             Bind(&loopExit);
1580                             result->WriteVariable(newArray);
1581                             Jump(exit);
1582                         }
1583                     }
1584                 }
1585             }
1586         }
1587     }
1588 #endif
1589 }
1590 
Sort(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1591 void BuiltinsArrayStubBuilder::Sort(GateRef glue, GateRef thisValue,
1592     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1593 {
1594     GateRef callbackFnHandle = GetCallArg0(numArgs);
1595     SortAfterArgs(glue, thisValue, callbackFnHandle, result, exit, slowPath);
1596 }
1597 
SortAfterArgs(GateRef glue,GateRef thisValue,GateRef callbackFnHandle,Variable * result,Label * exit,Label * slowPath,GateRef hir)1598 void BuiltinsArrayStubBuilder::SortAfterArgs(GateRef glue, GateRef thisValue,
1599     GateRef callbackFnHandle, Variable *result, Label *exit, Label *slowPath, GateRef hir)
1600 {
1601     auto env = GetEnvironment();
1602     Label isHeapObject(env);
1603     Label isJsArray(env);
1604     Label isStability(env);
1605     Label notCOWArray(env);
1606     Label argUndefined(env);
1607     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1608     Bind(&isHeapObject);
1609     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
1610     Bind(&isJsArray);
1611     // don't check constructor, "Sort" won't create new array.
1612     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1613     Bind(&isStability);
1614     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
1615     Bind(&notCOWArray);
1616     BRANCH(TaggedIsUndefined(callbackFnHandle), &argUndefined, slowPath);
1617     Bind(&argUndefined);
1618     result->WriteVariable(DoSort(glue, thisValue, false, result, exit, slowPath, hir));
1619     Jump(exit);
1620 }
1621 
ToSorted(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1622 void BuiltinsArrayStubBuilder::ToSorted(GateRef glue, GateRef thisValue,
1623     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1624 {
1625     auto env = GetEnvironment();
1626     Label isHeapObject(env);
1627     Label isJsArray(env);
1628     Label isStability(env);
1629     Label notCOWArray(env);
1630     Label argUndefined(env);
1631     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1632     Bind(&isHeapObject);
1633     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
1634     Bind(&isJsArray);
1635     // don't check constructor, "Sort" always use ArrayCreate to create array.
1636     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1637     Bind(&isStability);
1638     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
1639     Bind(&notCOWArray);
1640     GateRef callbackFnHandle = GetCallArg0(numArgs);
1641     BRANCH(TaggedIsUndefined(callbackFnHandle), &argUndefined, slowPath);
1642     Bind(&argUndefined);
1643 
1644     GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1645     GateRef receiver = NewArray(glue, thisArrLen);
1646     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
1647     Label loopHead(env);
1648     Label loopEnd(env);
1649     Label next(env);
1650     Label loopExit(env);
1651     Jump(&loopHead);
1652     LoopBegin(&loopHead);
1653     {
1654         BRANCH(Int64LessThan(*i, thisArrLen), &next, &loopExit);
1655         Bind(&next);
1656         {
1657             GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *i);
1658             SetValueWithElementsKind(glue, receiver, ele, *i, Boolean(true),
1659                 Int32(Elements::ToUint(ElementsKind::NONE)));
1660             Jump(&loopEnd);
1661         }
1662     }
1663     Bind(&loopEnd);
1664     i = Int64Add(*i, Int64(1));
1665     LoopEnd(&loopHead);
1666     Bind(&loopExit);
1667     result->WriteVariable(DoSort(glue, receiver, true, result, exit, slowPath));
1668     Jump(exit);
1669 }
1670 
DoSort(GateRef glue,GateRef receiver,bool isToSorted,Variable * result,Label * exit,Label * slowPath,GateRef hir)1671 GateRef BuiltinsArrayStubBuilder::DoSort(GateRef glue, GateRef receiver, bool isToSorted,
1672     Variable *result, Label *exit, Label *slowPath, GateRef hir)
1673 {
1674 #if ENABLE_NEXT_OPTIMIZATION
1675     auto env = GetEnvironment();
1676     Label entry(env);
1677     env->SubCfgEntry(&entry);
1678     Label exit1(env);
1679     Label fastPath(env);
1680     Label slowPath1(env);
1681     DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
1682     if (isToSorted) {
1683         res = DoSortOptimised(glue, receiver, Boolean(true), result, exit, slowPath, hir);
1684         Jump(&exit1);
1685     } else {
1686         BRANCH(IsEnableMutantArray(glue), &slowPath1, &fastPath);
1687         Bind(&slowPath1);
1688         {
1689             res = DoSortOptimised(glue, receiver, Boolean(false), result, exit, slowPath, hir);
1690             Jump(&exit1);
1691         }
1692         Bind(&fastPath);
1693         {
1694             res = DoSortOptimisedFast(glue, receiver, result, exit, slowPath, hir);
1695             Jump(&exit1);
1696         }
1697     }
1698     Bind(&exit1);
1699     auto ret = *res;
1700     env->SubCfgExit();
1701     return ret;
1702 #else
1703     auto env = GetEnvironment();
1704     Label entry(env);
1705     env->SubCfgEntry(&entry);
1706     GateRef len = ZExtInt32ToInt64(GetArrayLength(receiver));
1707     DEFVARIABLE(i, VariableType::INT64(), Int64(1));
1708     DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined());
1709     DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined());
1710     DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined());
1711     Label loopHead(env);
1712     Label loopEnd(env);
1713     Label next(env);
1714     Label loopExit(env);
1715     Jump(&loopHead);
1716     LoopBegin(&loopHead);
1717     {
1718         BRANCH(Int64LessThan(*i, len), &next, &loopExit);
1719         Bind(&next);
1720         DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0));
1721         DEFVARIABLE(endIndex, VariableType::INT64(), *i);
1722         Label presentValueIsHole(env);
1723         Label afterGettingpresentValue(env);
1724         Label presentValueHasProperty(env);
1725         Label presentValueHasException0(env);
1726         presentValue = GetTaggedValueWithElementsKind(glue, receiver, *i);
1727         BRANCH(TaggedIsHole(*presentValue), &presentValueIsHole, &afterGettingpresentValue);
1728         Bind(&presentValueIsHole);
1729         {
1730             GateRef presentValueHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { receiver, IntToTaggedInt(*i) });
1731             BRANCH(TaggedIsTrue(presentValueHasProp), &presentValueHasProperty, &afterGettingpresentValue);
1732             Bind(&presentValueHasProperty);
1733             {
1734                 presentValue = FastGetPropertyByIndex(glue, receiver, TruncInt64ToInt32(*i), ProfileOperation(), hir);
1735                 BRANCH(HasPendingException(glue), &presentValueHasException0, &afterGettingpresentValue);
1736                 Bind(&presentValueHasException0);
1737                 {
1738                     result->WriteVariable(Exception());
1739                     Jump(exit);
1740                 }
1741             }
1742         }
1743         Bind(&afterGettingpresentValue);
1744         {
1745             Label loopHead1(env);
1746             Label loopEnd1(env);
1747             Label next1(env);
1748             Label loopExit1(env);
1749             Jump(&loopHead1);
1750             LoopBegin(&loopHead1);
1751             {
1752                 Label middleValueIsHole(env);
1753                 Label afterGettingmiddleValue(env);
1754                 Label middleValueHasProperty(env);
1755                 Label middleValueHasException0(env);
1756                 BRANCH(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1);
1757                 Bind(&next1);
1758                 GateRef sum = Int64Add(*beginIndex, *endIndex);
1759                 GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half
1760                 middleValue = GetTaggedValueWithElementsKind(glue, receiver, middleIndex);
1761                 BRANCH(TaggedIsHole(*middleValue), &middleValueIsHole, &afterGettingmiddleValue);
1762                 Bind(&middleValueIsHole);
1763                 {
1764                     GateRef middleValueHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty),
1765                         { receiver, IntToTaggedInt(middleIndex) });
1766                     BRANCH(TaggedIsTrue(middleValueHasProp), &middleValueHasProperty, &afterGettingmiddleValue);
1767                     Bind(&middleValueHasProperty);
1768                     {
1769                         middleValue = FastGetPropertyByIndex(glue, receiver,
1770                             TruncInt64ToInt32(middleIndex), ProfileOperation(), hir);
1771                         BRANCH(HasPendingException(glue), &middleValueHasException0, &afterGettingmiddleValue);
1772                         Bind(&middleValueHasException0);
1773                         {
1774                             result->WriteVariable(Exception());
1775                             Jump(exit);
1776                         }
1777                     }
1778                 }
1779                 Bind(&afterGettingmiddleValue);
1780                 {
1781                     Label isInt(env);
1782                     GateRef middleVal = *middleValue;
1783                     GateRef presentVal = *presentValue;
1784                     BRANCH(LogicAndBuilder(env).And(TaggedIsInt(middleVal)).And(TaggedIsInt(presentVal)).Done(),
1785                         &isInt, slowPath);
1786                     Bind(&isInt);
1787                     {
1788                         GateRef compareResult =
1789                             CallNGCRuntime(glue, RTSTUB_ID(IntLexicographicCompare), {*middleValue, *presentValue});
1790                         Label less0(env);
1791                         Label greater0(env);
1792                         BRANCH(Int32LessThanOrEqual(compareResult, Int32(0)), &less0, &greater0);
1793                         Bind(&greater0);
1794                         {
1795                             endIndex = middleIndex;
1796                             Jump(&loopEnd1);
1797                         }
1798                         Bind(&less0);
1799                         {
1800                             beginIndex = middleIndex;
1801                             beginIndex = Int64Add(*beginIndex, Int64(1));
1802                             Jump(&loopEnd1);
1803                         }
1804                     }
1805                 }
1806             }
1807             Bind(&loopEnd1);
1808             LoopEnd(&loopHead1);
1809             Bind(&loopExit1);
1810 
1811             Label shouldCopy(env);
1812             GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0));
1813             GateRef lessI = Int64LessThan(*endIndex, *i);
1814             BRANCH(BitAnd(isGreater0, lessI), &shouldCopy, &loopEnd);
1815             Bind(&shouldCopy);
1816             {
1817                 DEFVARIABLE(j, VariableType::INT64(), *i);
1818                 Label loopHead2(env);
1819                 Label loopEnd2(env);
1820                 Label next2(env);
1821                 Label loopExit2(env);
1822                 Jump(&loopHead2);
1823                 LoopBegin(&loopHead2);
1824                 {
1825                     Label previousValueIsHole(env);
1826                     Label afterGettingpreviousValue(env);
1827                     Label previousValueHasProperty(env);
1828                     Label previousValueHasException0(env);
1829                     BRANCH(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2);
1830                     Bind(&next2);
1831                     previousValue = GetTaggedValueWithElementsKind(glue, receiver, Int64Sub(*j, Int64(1)));
1832                     BRANCH(TaggedIsHole(*previousValue), &previousValueIsHole, &afterGettingpreviousValue);
1833                     Bind(&previousValueIsHole);
1834                     {
1835                         GateRef previousValueHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty),
1836                             { receiver, IntToTaggedInt(Int64Sub(*j, Int64(1))) });
1837                         BRANCH(TaggedIsTrue(previousValueHasProp),
1838                             &previousValueHasProperty, &afterGettingpreviousValue);
1839                         Bind(&previousValueHasProperty);
1840                         {
1841                             previousValue = FastGetPropertyByIndex(glue, receiver,
1842                                 TruncInt64ToInt32(Int64Sub(*j, Int64(1))), ProfileOperation(), hir);
1843                             BRANCH(HasPendingException(glue), &previousValueHasException0, &afterGettingpreviousValue);
1844                             Bind(&previousValueHasException0);
1845                             {
1846                                 result->WriteVariable(Exception());
1847                                 Jump(exit);
1848                             }
1849                         }
1850                     }
1851                     Bind(&afterGettingpreviousValue);
1852                     {
1853                         SetValueWithElementsKind(glue, receiver, *previousValue, *j, Boolean(isToSorted),
1854                             Int32(Elements::ToUint(ElementsKind::NONE)));
1855                         Jump(&loopEnd2);
1856                     }
1857                 }
1858                 Bind(&loopEnd2);
1859                 j = Int64Sub(*j, Int64(1));
1860                 LoopEnd(&loopHead2);
1861                 Bind(&loopExit2);
1862                 SetValueWithElementsKind(glue, receiver, *presentValue, *endIndex, Boolean(isToSorted),
1863                     Int32(Elements::ToUint(ElementsKind::NONE)));
1864                 Jump(&loopEnd);
1865             }
1866         }
1867     }
1868     Bind(&loopEnd);
1869     i = Int64Add(*i, Int64(1));
1870     LoopEnd(&loopHead);
1871     Bind(&loopExit);
1872     env->SubCfgExit();
1873     return receiver;
1874 #endif
1875 }
1876 
Reduce(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1877 void BuiltinsArrayStubBuilder::Reduce(GateRef glue, GateRef thisValue, GateRef numArgs,
1878     Variable *result, Label *exit, Label *slowPath)
1879 {
1880     auto env = GetEnvironment();
1881     DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0));
1882     Label isHeapObject(env);
1883     Label isJsArray(env);
1884     Label atLeastOneArg(env);
1885     Label callbackFnHandleHeapObject(env);
1886     Label callbackFnHandleCallable(env);
1887     Label noTypeError(env);
1888 
1889     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1890     Bind(&isHeapObject);
1891     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
1892     Bind(&isJsArray);
1893     // don't check constructor, "Reduce" won't create new array.
1894     thisLen = GetArrayLength(thisValue);
1895     BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
1896     Bind(&atLeastOneArg);
1897     GateRef callbackFnHandle = GetCallArg0(numArgs);
1898     BRANCH(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath);
1899     Bind(&callbackFnHandleHeapObject);
1900     BRANCH(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath);
1901     Bind(&callbackFnHandleCallable);
1902     GateRef thisLenIsZero = Int32Equal(*thisLen, Int32(0));
1903     GateRef numArgsLessThanTwo = Int64LessThan(numArgs, IntPtr(2));
1904     BRANCH(BitAnd(thisLenIsZero, numArgsLessThanTwo), slowPath, &noTypeError);
1905     Bind(&noTypeError);
1906     {
1907         DEFVARIABLE(accumulator, VariableType::JS_ANY(), Undefined());
1908         DEFVARIABLE(k, VariableType::INT32(), Int32(0));
1909 
1910         Label updateAccumulator(env);
1911         Label checkForStableJSArray(env);
1912 
1913         BRANCH(Int64Equal(numArgs, IntPtr(2)), &updateAccumulator, slowPath); // 2: provide initialValue param
1914         Bind(&updateAccumulator);
1915         {
1916             accumulator = GetCallArg1(numArgs);
1917             Jump(&checkForStableJSArray);
1918         }
1919         Bind(&checkForStableJSArray);
1920         {
1921             Label isStableJSArray(env);
1922             Label notStableJSArray(env);
1923             BRANCH(IsStableJSArray(glue, thisValue), &isStableJSArray, &notStableJSArray);
1924             Bind(&isStableJSArray);
1925             {
1926                 GateRef argsLength = Int32(4); // 4: «accumulator, kValue, k, thisValue»
1927                 NewObjectStubBuilder newBuilder(this);
1928                 GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
1929                 Label loopHead(env);
1930                 Label next(env);
1931                 Label loopEnd(env);
1932                 Label loopExit(env);
1933                 Jump(&loopHead);
1934                 LoopBegin(&loopHead);
1935                 {
1936                     BRANCH(Int32LessThan(*k, *thisLen), &next, &loopExit);
1937                     Bind(&next);
1938                     {
1939                         Label updateK(env);
1940                         Label notHole(env);
1941                         Label changeThisLen(env);
1942                         Label updateCallResult(env);
1943                         GateRef elements = GetElementsArray(thisValue);
1944                         GateRef kValue = GetTaggedValueWithElementsKind(glue, thisValue, *k);
1945                         BRANCH(TaggedIsHole(kValue), &loopEnd, &notHole);
1946                         Bind(&notHole);
1947                         {
1948                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
1949                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), kValue);
1950                             // 2 : parameter location
1951                             SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
1952                             // 3 : parameter location
1953                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
1954                             GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
1955                             JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
1956                             callArgs.callThisArgvWithReturnArgs = { argsLength, argv, Undefined() };
1957                             CallStubBuilder callBuilder(this, glue, callbackFnHandle, argsLength, 0, nullptr,
1958                                 Circuit::NullGate(), callArgs);
1959                             GateRef callResult = callBuilder.JSCallDispatch();
1960                             Label hasException1(env);
1961                             Label notHasException1(env);
1962                             BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
1963                             Bind(&hasException1);
1964                             {
1965                                 result->WriteVariable(Exception());
1966                                 Jump(exit);
1967                             }
1968                             Bind(&notHasException1);
1969                             GateRef newLen = GetLengthOfTaggedArray(elements);
1970                             BRANCH(Int32LessThan(newLen, *thisLen), &changeThisLen, &updateCallResult);
1971                             Bind(&changeThisLen);
1972                             {
1973                                 thisLen = newLen;
1974                                 Jump(&updateCallResult);
1975                             }
1976                             Bind(&updateCallResult);
1977                             {
1978                                 accumulator = callResult;
1979                                 Jump(&loopEnd);
1980                             }
1981                         }
1982                     }
1983                 }
1984                 Bind(&loopEnd);
1985                 {
1986                     k = Int32Add(*k, Int32(1));
1987 
1988                     Label isStableJSArray1(env);
1989                     Label notStableJSArray1(env);
1990                     BRANCH(IsStableJSArray(glue, thisValue), &isStableJSArray1, &notStableJSArray1);
1991                     Bind(&notStableJSArray1);
1992                     {
1993                         Jump(&loopExit);
1994                     }
1995                     Bind(&isStableJSArray1);
1996                     LoopEnd(&loopHead, env, glue);
1997                 }
1998                 Bind(&loopExit);
1999                 Jump(&notStableJSArray);
2000             }
2001             Bind(&notStableJSArray);
2002             {
2003                 Label finish(env);
2004                 Label callRT(env);
2005                 BRANCH(Int32LessThan(*k, *thisLen), &callRT, &finish);
2006                 Bind(&callRT);
2007                 {
2008                     accumulator = CallRuntime(glue, RTSTUB_ID(JSArrayReduceUnStable), { thisValue, thisValue,
2009                         IntToTaggedInt(*k), IntToTaggedInt(*thisLen), *accumulator, callbackFnHandle });
2010                     Jump(&finish);
2011                 }
2012                 Bind(&finish);
2013                 {
2014                     result->WriteVariable(*accumulator);
2015                     Jump(exit);
2016                 }
2017             }
2018         }
2019     }
2020 }
2021 
Reverse(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2022 void BuiltinsArrayStubBuilder::Reverse(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2023     Variable *result, Label *exit, Label *slowPath)
2024 {
2025     auto env = GetEnvironment();
2026     Label isHeapObject(env);
2027     Label isJsArray(env);
2028     Label isStability(env);
2029     Label notCOWArray(env);
2030     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2031     Bind(&isHeapObject);
2032     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2033     Bind(&isJsArray);
2034     // don't check constructor, "Reverse" won't create new array.
2035     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
2036     Bind(&isStability);
2037     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
2038     Bind(&notCOWArray);
2039     GateRef thisLen = GetArrayLength(thisValue);
2040     GateRef thisArrLen = ZExtInt32ToInt64(thisLen);
2041 #if ENABLE_NEXT_OPTIMIZATION
2042     Label useReversBarrier(env);
2043     Label noReverseBarrier(env);
2044     // 10 : length < 10 reverse item by item
2045     BRANCH(Int32LessThan(thisLen, Int32(10)), &noReverseBarrier, &useReversBarrier);
2046     Bind(&useReversBarrier);
2047     ReverseOptimised(glue, thisValue, thisLen, result, exit);
2048     Bind(&noReverseBarrier);
2049 #endif
2050     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
2051     DEFVARIABLE(j, VariableType::INT64(),  Int64Sub(thisArrLen, Int64(1)));
2052 
2053     GateRef hclass = LoadHClass(thisValue);
2054     GateRef kind = GetElementsKindFromHClass(hclass);
2055     Label isInt(env);
2056     Label isNotInt(env);
2057     Label notFastKind(env);
2058     GateRef isMutantArrayEnabled = IsEnableMutantArray(glue);
2059     GateRef checkIntKind = LogicAndBuilder(env)
2060         .And(isMutantArrayEnabled)
2061         .And(Int32GreaterThanOrEqual(kind, Int32(Elements::ToUint(ElementsKind::INT))))
2062         .And(Int32LessThanOrEqual(kind, Int32(Elements::ToUint(ElementsKind::HOLE_INT))))
2063         .Done();
2064     BRANCH(checkIntKind, &isInt, &isNotInt);
2065     Bind(&isInt);
2066     {
2067         FastReverse(glue, thisValue, thisArrLen, ElementsKind::INT, result, exit);
2068     }
2069     Bind(&isNotInt);
2070     {
2071         Label isNumber(env);
2072         Label isNotNumber(env);
2073         GateRef checkNumberKind = LogicAndBuilder(env)
2074             .And(isMutantArrayEnabled)
2075             .And(Int32GreaterThanOrEqual(kind, Int32(Elements::ToUint(ElementsKind::NUMBER))))
2076             .And(Int32LessThanOrEqual(kind, Int32(Elements::ToUint(ElementsKind::HOLE_NUMBER))))
2077             .Done();
2078         BRANCH(checkNumberKind, &isNumber, &isNotNumber);
2079         Bind(&isNumber);
2080         {
2081             FastReverse(glue, thisValue, thisArrLen, ElementsKind::NUMBER, result, exit);
2082         }
2083         Bind(&isNotNumber);
2084         {
2085             FastReverse(glue, thisValue, thisArrLen, ElementsKind::TAGGED, result, exit);
2086         }
2087     }
2088 }
2089 
FastReverse(GateRef glue,GateRef thisValue,GateRef len,ElementsKind kind,Variable * result,Label * exit)2090 void BuiltinsArrayStubBuilder::FastReverse(GateRef glue, GateRef thisValue, GateRef len,
2091     ElementsKind kind, Variable *result, Label *exit)
2092 {
2093     auto env = GetEnvironment();
2094     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
2095     DEFVARIABLE(j, VariableType::INT64(),  Int64Sub(len, Int64(1)));
2096     GateRef elements = GetElementsArray(thisValue);
2097     Label loopHead(env);
2098     Label loopEnd(env);
2099     Label next(env);
2100     Label loopExit(env);
2101     Jump(&loopHead);
2102     LoopBegin(&loopHead);
2103     {
2104         Label arrayValue(env);
2105         Label valueEqual(env);
2106         BRANCH(Int64LessThan(*i, *j), &next, &loopExit);
2107         Bind(&next);
2108         {
2109             if (kind == ElementsKind::INT || kind == ElementsKind::NUMBER) {
2110                 GateRef lower = GetValueFromMutantTaggedArray(elements, *i);
2111                 GateRef upper = GetValueFromMutantTaggedArray(elements, *j);
2112                 FastSetValueWithElementsKind(glue, thisValue, elements, upper, *i, kind);
2113                 FastSetValueWithElementsKind(glue, thisValue, elements, lower, *j, kind);
2114                 Jump(&loopEnd);
2115             } else {
2116                 GateRef lower = GetValueFromTaggedArray(elements, *i);
2117                 GateRef upper = GetValueFromTaggedArray(elements, *j);
2118                 FastSetValueWithElementsKind(glue, thisValue, elements, upper, *i, kind);
2119                 FastSetValueWithElementsKind(glue, thisValue, elements, lower, *j, kind);
2120                 Jump(&loopEnd);
2121             }
2122         }
2123     }
2124     Bind(&loopEnd);
2125     i = Int64Add(*i, Int64(1));
2126     j = Int64Sub(*j, Int64(1));
2127     LoopEnd(&loopHead, env, glue);
2128     Bind(&loopExit);
2129     result->WriteVariable(thisValue);
2130     Jump(exit);
2131 }
2132 
ToReversed(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2133 void BuiltinsArrayStubBuilder::ToReversed(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2134                                           Variable* result, Label* exit, Label* slowPath)
2135 {
2136 #if ENABLE_NEXT_OPTIMIZATION
2137     ToReversedOptimised(glue, thisValue, numArgs, result, exit, slowPath);
2138 #else
2139     auto env = GetEnvironment();
2140     Label isHeapObject(env);
2141     Label isJsArray(env);
2142     Label isStability(env);
2143     Label notCOWArray(env);
2144     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2145     Bind(&isHeapObject);
2146     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2147     Bind(&isJsArray);
2148     // don't check constructor, "ToReversed" always use ArrayCreate to create array.
2149     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
2150     Bind(&isStability);
2151     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
2152     Bind(&notCOWArray);
2153 
2154     GateRef thisArrLen = GetArrayLength(thisValue);
2155     GateRef receiver = NewArray(glue, Int32(0));
2156     GrowElementsCapacity(glue, receiver, thisArrLen);
2157     SetArrayLength(glue, receiver, thisArrLen);
2158     result->WriteVariable(DoReverse(glue, thisValue, receiver, Boolean(true), result, exit));
2159     Jump(exit);
2160 #endif
2161 }
2162 
DoReverse(GateRef glue,GateRef thisValue,GateRef receiver,GateRef receiverState,Variable * result,Label * exit)2163 GateRef BuiltinsArrayStubBuilder::DoReverse(GateRef glue, GateRef thisValue, GateRef receiver,
2164     GateRef receiverState, Variable *result, Label *exit)
2165 {
2166     auto env = GetEnvironment();
2167     Label entry(env);
2168     env->SubCfgEntry(&entry);
2169     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
2170     DEFVARIABLE(j, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(GetArrayLength(thisValue)), Int64(1)));
2171     Label loopHead(env);
2172     Label loopEnd(env);
2173     Label next(env);
2174     Label loopExit(env);
2175 
2176     Jump(&loopHead);
2177     LoopBegin(&loopHead);
2178     {
2179         DEFVARIABLE(lower, VariableType::JS_ANY(), Hole());
2180         DEFVARIABLE(upper, VariableType::JS_ANY(), Hole());
2181         Label lowerValueIsHole(env);
2182         Label afterGettingLower(env);
2183         Label lowerHasProperty(env);
2184         Label lowerHasException0(env);
2185         Label upperValueIsHole(env);
2186         Label afterGettingUpper(env);
2187         Label upperHasProperty(env);
2188         Label upperHasException0(env);
2189         Label receiverIsNew(env);
2190         Label receiverIsOrigin(env);
2191         Label lowerIsHole(env);
2192         Label lowerIsNotHole(env);
2193         Label dealWithUpper(env);
2194         Label upperIsHole(env);
2195         Label upperIsNotHole(env);
2196         BRANCH(Int64LessThanOrEqual(*i, *j), &next, &loopExit);
2197         Bind(&next);
2198         {
2199             lower = GetTaggedValueWithElementsKind(glue, thisValue, *i);
2200             BRANCH(TaggedIsHole(*lower), &lowerValueIsHole, &afterGettingLower);
2201             Bind(&lowerValueIsHole);
2202             {
2203                 GateRef lowerHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
2204                 BRANCH(TaggedIsTrue(lowerHasProp), &lowerHasProperty, &afterGettingLower);
2205                 Bind(&lowerHasProperty);
2206                 {
2207                     lower = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
2208                     BRANCH(HasPendingException(glue), &lowerHasException0, &afterGettingLower);
2209                     Bind(&lowerHasException0);
2210                     {
2211                         result->WriteVariable(Exception());
2212                         Jump(exit);
2213                     }
2214                 }
2215             }
2216             Bind(&afterGettingLower);
2217             {
2218                 upper = GetTaggedValueWithElementsKind(glue, thisValue, *j);
2219                 BRANCH(TaggedIsHole(*upper), &upperValueIsHole, &afterGettingUpper);
2220                 Bind(&upperValueIsHole);
2221                 {
2222                     GateRef upperHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*j) });
2223                     BRANCH(TaggedIsTrue(upperHasProp), &upperHasProperty, &afterGettingUpper);
2224                     Bind(&upperHasProperty);
2225                     {
2226                         upper = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*j), ProfileOperation());
2227                         BRANCH(HasPendingException(glue), &upperHasException0, &afterGettingUpper);
2228                     }
2229                     Bind(&upperHasException0);
2230                     {
2231                         result->WriteVariable(Exception());
2232                         Jump(exit);
2233                     }
2234                 }
2235                 Bind(&afterGettingUpper);
2236                 {
2237                     BRANCH(receiverState, &receiverIsNew, &receiverIsOrigin);
2238                     Bind(&receiverIsNew);
2239                     {
2240                         BRANCH(TaggedIsHole(*lower), &lowerIsHole, &lowerIsNotHole);
2241                         Bind(&lowerIsHole);
2242                         {
2243                             SetValueWithElementsKind(glue, receiver, Undefined(), *j, Boolean(true),
2244                                 Int32(Elements::ToUint(ElementsKind::NONE)));
2245                             Jump(&dealWithUpper);
2246                         }
2247                         Bind(&lowerIsNotHole);
2248                         {
2249                             SetValueWithElementsKind(glue, receiver, *lower, *j, Boolean(true),
2250                                 Int32(Elements::ToUint(ElementsKind::NONE)));
2251                             Jump(&dealWithUpper);
2252                         }
2253                         Bind(&dealWithUpper);
2254                         {
2255                             BRANCH(TaggedIsHole(*upper), &upperIsHole, &upperIsNotHole);
2256                             Bind(&upperIsHole);
2257                             {
2258                                 SetValueWithElementsKind(glue, receiver, Undefined(), *i, Boolean(true),
2259                                     Int32(Elements::ToUint(ElementsKind::NONE)));
2260                                 Jump(&loopEnd);
2261                             }
2262                             Bind(&upperIsNotHole);
2263                             {
2264                                 SetValueWithElementsKind(glue, receiver, *upper, *i, Boolean(true),
2265                                     Int32(Elements::ToUint(ElementsKind::NONE)));
2266                                 Jump(&loopEnd);
2267                             }
2268                         }
2269                     }
2270                     Bind(&receiverIsOrigin);
2271                     {
2272                         SetValueWithElementsKind(glue, receiver, *upper, *i, Boolean(false),
2273                             Int32(Elements::ToUint(ElementsKind::NONE)));
2274                         SetValueWithElementsKind(glue, receiver, *lower, *j, Boolean(false),
2275                             Int32(Elements::ToUint(ElementsKind::NONE)));
2276                         Jump(&loopEnd);
2277                     }
2278                 }
2279             }
2280         }
2281     }
2282     Bind(&loopEnd);
2283     i = Int64Add(*i, Int64(1));
2284     j = Int64Sub(*j, Int64(1));
2285     LoopEnd(&loopHead);
2286     Bind(&loopExit);
2287     env->SubCfgExit();
2288     return receiver;
2289 }
2290 
IsJsArrayWithLengthLimit(GateRef glue,GateRef object,uint32_t maxLength,JsArrayRequirements requirements)2291 GateRef BuiltinsArrayStubBuilder::IsJsArrayWithLengthLimit(GateRef glue, GateRef object,
2292     uint32_t maxLength, JsArrayRequirements requirements)
2293 {
2294     auto env = GetEnvironment();
2295     Label entry(env);
2296     env->SubCfgEntry(&entry);
2297     Label isHeapObject(env);
2298     Label isJsArray(env);
2299     Label stabilityCheckPassed(env);
2300     Label defaultConstructorCheckPassed(env);
2301     Label exit(env);
2302     DEFVARIABLE(result, VariableType::BOOL(), False());
2303 
2304     BRANCH(TaggedIsHeapObject(object), &isHeapObject, &exit);
2305     Bind(&isHeapObject);
2306     BRANCH(IsJsArray(object), &isJsArray, &exit);
2307     Bind(&isJsArray);
2308     if (requirements.stable) {
2309         BRANCH(IsStableJSArray(glue, object), &stabilityCheckPassed, &exit);
2310     } else {
2311         Jump(&stabilityCheckPassed);
2312     }
2313     Bind(&stabilityCheckPassed);
2314     if (requirements.defaultConstructor) {
2315         // If HasConstructor bit is set to 1, then the constructor has been modified.
2316         BRANCH(HasConstructor(object), &exit, &defaultConstructorCheckPassed);
2317     } else {
2318         Jump(&defaultConstructorCheckPassed);
2319     }
2320     Bind(&defaultConstructorCheckPassed);
2321     result.WriteVariable(Int32UnsignedLessThanOrEqual(GetArrayLength(object), Int32(maxLength)));
2322     Jump(&exit);
2323     Bind(&exit);
2324     GateRef ret = *result;
2325     env->SubCfgExit();
2326     return ret;
2327 }
2328 
Values(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2329 void BuiltinsArrayStubBuilder::Values(GateRef glue, GateRef thisValue,
2330     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
2331 {
2332     auto env = GetEnvironment();
2333     Label isHeapObject(env);
2334     Label isJsArray(env);
2335     Label defaultConstr(env);
2336     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2337     Bind(&isHeapObject);
2338     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2339     Bind(&isJsArray);
2340     // don't check constructor, "Values" won't create new array.
2341     ConstantIndex iterClassIdx = ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX;
2342     GateRef iteratorHClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, iterClassIdx);
2343     NewObjectStubBuilder newBuilder(this);
2344     newBuilder.SetParameters(glue, 0);
2345     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
2346     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
2347     GateRef prototype = GetGlobalEnvValue(VariableType::JS_POINTER(), glueGlobalEnv,
2348                                           GlobalEnv::ARRAY_ITERATOR_PROTOTYPE_INDEX);
2349     SetPrototypeToHClass(VariableType::JS_POINTER(), glue, iteratorHClass, prototype);
2350     GateRef iter = newBuilder.NewJSObject(glue, iteratorHClass);
2351     SetIteratedArrayOfArrayIterator(glue, iter, thisValue);
2352     SetNextIndexOfArrayIterator(glue, iter, Int32(0));
2353     GateRef kind = Int32(static_cast<int32_t>(IterationKind::VALUE));
2354     SetBitFieldOfArrayIterator(glue, iter, kind);
2355     result->WriteVariable(iter);
2356     Jump(exit);
2357 }
2358 
Find(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2359 void BuiltinsArrayStubBuilder::Find(GateRef glue, GateRef thisValue, GateRef numArgs,
2360     Variable *result, Label *exit, Label *slowPath)
2361 {
2362 #if ENABLE_NEXT_OPTIMIZATION
2363     FindOptimised(glue, thisValue, numArgs, result, exit, slowPath);
2364 #else
2365     auto env = GetEnvironment();
2366     Label isHeapObject(env);
2367     Label isJsArray(env);
2368     Label isStability(env);
2369     Label notCOWArray(env);
2370     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2371     Bind(&isHeapObject);
2372     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2373     Bind(&isJsArray);
2374     // don't check constructor, "Find" won't create new array.
2375     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
2376     Bind(&isStability);
2377     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
2378     Bind(&notCOWArray);
2379 
2380     GateRef callbackFnHandle = GetCallArg0(numArgs);
2381     Label arg0HeapObject(env);
2382     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
2383     Bind(&arg0HeapObject);
2384     Label callable(env);
2385     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
2386     Bind(&callable);
2387     GateRef argHandle = GetCallArg1(numArgs);
2388     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
2389     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
2390     Label loopHead(env);
2391     Label loopEnd(env);
2392     Label next(env);
2393     Label loopExit(env);
2394     Jump(&loopHead);
2395     LoopBegin(&loopHead);
2396     {
2397         Label hasException0(env);
2398         Label notHasException0(env);
2399         BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
2400         Bind(&next);
2401         GateRef kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
2402         BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
2403         Bind(&hasException0);
2404         {
2405             result->WriteVariable(Exception());
2406             Jump(exit);
2407         }
2408         Bind(&notHasException0);
2409         {
2410             GateRef key = Int64ToTaggedInt(*i);
2411             Label hasException(env);
2412             Label notHasException(env);
2413             JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
2414             callArgs.callThisArg3WithReturnArgs = { argHandle, kValue, key, thisValue };
2415             CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
2416                 Circuit::NullGate(), callArgs);
2417             GateRef retValue = callBuilder.JSCallDispatch();
2418             BRANCH(HasPendingException(glue), &hasException, &notHasException);
2419             Bind(&hasException);
2420             {
2421                 result->WriteVariable(retValue);
2422                 Jump(exit);
2423             }
2424             Bind(&notHasException);
2425             {
2426                 Label find(env);
2427                 BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
2428                 Bind(&find);
2429                 {
2430                     result->WriteVariable(kValue);
2431                     Jump(exit);
2432                 }
2433             }
2434         }
2435     }
2436     Bind(&loopEnd);
2437     thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2438     i = Int64Add(*i, Int64(1));
2439     LoopEnd(&loopHead, env, glue);
2440     Bind(&loopExit);
2441     Jump(exit);
2442 #endif
2443 }
2444 
FindIndex(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2445 void BuiltinsArrayStubBuilder::FindIndex(GateRef glue, GateRef thisValue, GateRef numArgs,
2446     Variable *result, Label *exit, Label *slowPath)
2447 {
2448 #if ENABLE_NEXT_OPTIMIZATION
2449     FindIndexOptimised(glue, thisValue, numArgs, result, exit, slowPath);
2450 #else
2451     auto env = GetEnvironment();
2452     Label isHeapObject(env);
2453     Label isJsArray(env);
2454     Label notCOWArray(env);
2455     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2456     Bind(&isHeapObject);
2457     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2458     Bind(&isJsArray);
2459     // don't check constructor, "Shift" won't create new array.
2460     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
2461     Bind(&notCOWArray);
2462 
2463     Label arg0HeapObject(env);
2464     Label callable(env);
2465     Label stableJSArray(env);
2466     Label notStableJSArray(env);
2467     GateRef callbackFnHandle = GetCallArg0(numArgs);
2468     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
2469     Bind(&arg0HeapObject);
2470     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
2471     Bind(&callable);
2472     result->WriteVariable(IntToTaggedPtr(Int32(-1)));
2473     GateRef argHandle = GetCallArg1(numArgs);
2474     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
2475     BRANCH(IsStableJSArray(glue, thisValue), &stableJSArray, &notStableJSArray);
2476     Bind(&stableJSArray);
2477     {
2478         DEFVARIABLE(i, VariableType::INT64(), Int64(0));
2479         DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
2480         Label loopHead(env);
2481         Label loopEnd(env);
2482         Label next(env);
2483         Label loopExit(env);
2484         Jump(&loopHead);
2485         LoopBegin(&loopHead);
2486         {
2487             BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
2488             Bind(&next);
2489             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
2490             Label isHole(env);
2491             Label notHole(env);
2492             BRANCH(TaggedIsHole(*kValue), &isHole, &notHole);
2493             Bind(&isHole);
2494             {
2495                 Label hasException0(env);
2496                 Label notHasException0(env);
2497                 GateRef res = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
2498                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
2499                 Bind(&hasException0);
2500                 {
2501                     result->WriteVariable(Exception());
2502                     Jump(exit);
2503                 }
2504                 Bind(&notHasException0);
2505                 {
2506                     Label resIsHole(env);
2507                     Label resNotHole(env);
2508                     BRANCH(TaggedIsHole(res), &resIsHole, &resNotHole);
2509                     Bind(&resIsHole);
2510                     {
2511                         kValue = Undefined();
2512                         Jump(&notHole);
2513                     }
2514                     Bind(&resNotHole);{
2515                         kValue = res;
2516                         Jump(&notHole);
2517                     }
2518                 }
2519             }
2520             Bind(&notHole);
2521             {
2522                 GateRef key = IntToTaggedPtr(*i);
2523                 Label hasException(env);
2524                 Label notHasException(env);
2525                 Label checkStable(env);
2526                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
2527                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
2528                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
2529                     Circuit::NullGate(), callArgs);
2530                 GateRef retValue = callBuilder.JSCallDispatch();
2531                 BRANCH(HasPendingException(glue), &hasException, &notHasException);
2532                 Bind(&hasException);
2533                 {
2534                     result->WriteVariable(retValue);
2535                     Jump(exit);
2536                 }
2537                 Bind(&notHasException);
2538                 {
2539                     Label find(env);
2540                     BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &checkStable);
2541                     Bind(&find);
2542                     {
2543                         result->WriteVariable(key);
2544                         Jump(exit);
2545                     }
2546                 }
2547                 Bind(&checkStable);
2548                 i = Int64Add(*i, Int64(1));
2549                 BRANCH(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
2550             }
2551         }
2552         Bind(&loopEnd);
2553         thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2554         LoopEnd(&loopHead, env, glue);
2555         Bind(&loopExit);
2556         Jump(exit);
2557     }
2558     Bind(&notStableJSArray);
2559     {
2560         DEFVARIABLE(j, VariableType::INT64(), Int64(0));
2561         Label loopHead(env);
2562         Label loopEnd(env);
2563         Label next(env);
2564         Label loopExit(env);
2565         Jump(&loopHead);
2566         LoopBegin(&loopHead);
2567         {
2568             thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2569             BRANCH(Int64LessThan(*j, *thisArrLen), &next, &loopExit);
2570             Bind(&next);
2571             {
2572                 Label hasException0(env);
2573                 Label notHasException0(env);
2574                 GateRef kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*j), ProfileOperation());
2575                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
2576                 Bind(&hasException0);
2577                 {
2578                     result->WriteVariable(Exception());
2579                     Jump(exit);
2580                 }
2581                 Bind(&notHasException0);
2582                 {
2583                     GateRef key = IntToTaggedPtr(*j);
2584                     Label hasException(env);
2585                     Label notHasException(env);
2586                     JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
2587                     callArgs.callThisArg3WithReturnArgs = { argHandle, kValue, key, thisValue };
2588                     CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
2589                         nullptr, Circuit::NullGate(), callArgs);
2590                     GateRef retValue = callBuilder.JSCallDispatch();
2591                     BRANCH(TaggedIsException(retValue), &hasException, &notHasException);
2592                     Bind(&hasException);
2593                     {
2594                         result->WriteVariable(retValue);
2595                         Jump(exit);
2596                     }
2597                     Bind(&notHasException);
2598                     {
2599                         Label find(env);
2600                         BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
2601                         Bind(&find);
2602                         {
2603                             result->WriteVariable(key);
2604                             Jump(exit);
2605                         }
2606                     }
2607                 }
2608             }
2609         }
2610         Bind(&loopEnd);
2611         thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2612         j = Int64Add(*j, Int64(1));
2613         LoopEnd(&loopHead, env, glue);
2614         Bind(&loopExit);
2615         Jump(exit);
2616     }
2617 #endif
2618 }
2619 
2620 #if ENABLE_NEXT_OPTIMIZATION
Push(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2621 void BuiltinsArrayStubBuilder::Push(GateRef glue, GateRef thisValue,
2622     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
2623 {
2624     auto env = GetEnvironment();
2625     Label isStability(env);
2626     Label setLength(env);
2627     Label smallArgs(env);
2628     Label checkSmallArgs(env);
2629     Label isLengthWritable(env);
2630 
2631     BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &isStability, slowPath);
2632     Bind(&isStability);
2633     BRANCH_LIKELY(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
2634     Bind(&isLengthWritable);
2635     GateRef oldLength = GetArrayLength(thisValue);
2636     *result = IntToTaggedPtr(oldLength);
2637     BRANCH_UNLIKELY(Int32Equal(ChangeIntPtrToInt32(numArgs), Int32(0)), exit, &checkSmallArgs);
2638     Bind(&checkSmallArgs);
2639     // now unsupport more than 2 args
2640     BRANCH_LIKELY(Int32LessThanOrEqual(ChangeIntPtrToInt32(numArgs), Int32(2)), &smallArgs, slowPath);
2641     Bind(&smallArgs);
2642 
2643     GateRef newLength = Int32Add(oldLength, ChangeIntPtrToInt32(numArgs));
2644 
2645     DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(thisValue));
2646     GateRef capacity = GetLengthOfTaggedArray(*elements);
2647     Label grow(env);
2648     Label setValue(env);
2649     BRANCH_UNLIKELY(Int32GreaterThan(newLength, capacity), &grow, &setValue);
2650     Bind(&grow);
2651     {
2652         elements = CallCommonStub(glue, CommonStubCSigns::GrowElementsCapacity, {glue, thisValue, newLength});
2653         Jump(&setValue);
2654     }
2655     Bind(&setValue);
2656     {
2657         Label oneArg(env);
2658         Label twoArg(env);
2659         DEFVARIABLE(index, VariableType::INT32(), Int32(0));
2660         DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
2661         BRANCH_LIKELY(Int64Equal(numArgs, IntPtr(1)), &oneArg, &twoArg); // 1 one arg
2662         Bind(&oneArg);
2663         {
2664             value = GetCallArg0(numArgs);
2665             index = Int32Add(oldLength, Int32(0)); // 0 slot index
2666             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
2667                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2668             Jump(&setLength);
2669         }
2670         Bind(&twoArg);
2671         {
2672             DEFVARIABLE(index2, VariableType::INT32(), Int32(0));
2673             DEFVARIABLE(value2, VariableType::JS_ANY(), Undefined());
2674             value = GetCallArg0(numArgs);
2675             index = Int32Add(oldLength, Int32(0)); // 0 slot index
2676             value2 = GetCallArg1(numArgs);
2677             index2 = Int32Add(oldLength, Int32(1)); // 1 slot index
2678             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
2679                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2680             SetValueWithElementsKind(glue, thisValue, *value2, *index2, Boolean(true),
2681                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2682             Jump(&setLength);
2683         }
2684     }
2685     Bind(&setLength);
2686     SetArrayLength(glue, thisValue, newLength);
2687     result->WriteVariable(IntToTaggedPtr(newLength));
2688     Jump(exit);
2689 }
2690 #else
Push(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2691 void BuiltinsArrayStubBuilder::Push(GateRef glue, GateRef thisValue,
2692     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
2693 {
2694     auto env = GetEnvironment();
2695     Label isHeapObject(env);
2696     Label isJsArray(env);
2697     Label isStability(env);
2698     Label setLength(env);
2699     Label smallArgs(env);
2700     Label checkSmallArgs(env);
2701 
2702     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2703     Bind(&isHeapObject);
2704     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2705     Bind(&isJsArray);
2706     Label isLengthWritable(env);
2707     BRANCH(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
2708     Bind(&isLengthWritable);
2709 
2710     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
2711     Bind(&isStability);
2712 
2713     GateRef oldLength = GetArrayLength(thisValue);
2714     *result = IntToTaggedPtr(oldLength);
2715 
2716     BRANCH(Int32Equal(ChangeIntPtrToInt32(numArgs), Int32(0)), exit, &checkSmallArgs);
2717     Bind(&checkSmallArgs);
2718     // now unsupport more than 2 args
2719     BRANCH(Int32LessThanOrEqual(ChangeIntPtrToInt32(numArgs), Int32(2)), &smallArgs, slowPath);
2720     Bind(&smallArgs);
2721     GateRef newLength = Int32Add(oldLength, ChangeIntPtrToInt32(numArgs));
2722 
2723     DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(thisValue));
2724     GateRef capacity = GetLengthOfTaggedArray(*elements);
2725     Label grow(env);
2726     Label setValue(env);
2727     BRANCH(Int32GreaterThan(newLength, capacity), &grow, &setValue);
2728     Bind(&grow);
2729     {
2730         elements = GrowElementsCapacity(glue, thisValue, newLength);
2731         Jump(&setValue);
2732     }
2733     Bind(&setValue);
2734     {
2735         Label oneArg(env);
2736         Label twoArg(env);
2737         DEFVARIABLE(index, VariableType::INT32(), Int32(0));
2738         DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
2739         BRANCH(Int64Equal(numArgs, IntPtr(1)), &oneArg, &twoArg);  // 1 one arg
2740         Bind(&oneArg);
2741         {
2742             value = GetCallArg0(numArgs);
2743             index = Int32Add(oldLength, Int32(0));  // 0 slot index
2744             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
2745                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2746             Jump(&setLength);
2747         }
2748         Bind(&twoArg);
2749         {
2750             value = GetCallArg0(numArgs);
2751             index = Int32Add(oldLength, Int32(0));  // 0 slot index
2752             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
2753                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2754             value = GetCallArg1(numArgs);
2755             index = Int32Add(oldLength, Int32(1));  // 1 slot index
2756             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
2757                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2758             Jump(&setLength);
2759         }
2760     }
2761     Bind(&setLength);
2762     SetArrayLength(glue, thisValue, newLength);
2763     result->WriteVariable(IntToTaggedPtr(newLength));
2764     Jump(exit);
2765 }
2766 #endif
2767 
IsConcatSpreadable(GateRef glue,GateRef obj)2768 GateRef BuiltinsArrayStubBuilder::IsConcatSpreadable(GateRef glue, GateRef obj)
2769 {
2770     auto env = GetEnvironment();
2771     Label entry(env);
2772     env->SubCfgEntry(&entry);
2773     DEFVARIABLE(result, VariableType::BOOL(), False());
2774     Label exit(env);
2775     Label isEcmaObj(env);
2776     BRANCH(IsEcmaObject(obj), &isEcmaObj, &exit);
2777     Bind(&isEcmaObj);
2778     {
2779         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
2780         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
2781         GateRef isConcatsprKey =
2782             GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ISCONCAT_SYMBOL_INDEX);
2783         AccessObjectStubBuilder builder(this);
2784         GateRef spreadable =
2785             builder.LoadObjByValue(glue, obj, isConcatsprKey, Undefined(), Int32(0), ProfileOperation());
2786         Label isDefined(env);
2787         Label isUnDefined(env);
2788         BRANCH(TaggedIsUndefined(spreadable), &isUnDefined, &isDefined);
2789         Bind(&isUnDefined);
2790         {
2791             Label IsArray(env);
2792             BRANCH(IsJsArray(obj), &IsArray, &exit);
2793             Bind(&IsArray);
2794             result = True();
2795             Jump(&exit);
2796         }
2797         Bind(&isDefined);
2798         {
2799             result = TaggedIsTrue(spreadable);
2800             Jump(&exit);
2801         }
2802     }
2803     Bind(&exit);
2804     auto res = *result;
2805     env->SubCfgExit();
2806     return res;
2807 }
2808 
InitializeArray(GateRef glue,GateRef count,Variable * result)2809 void BuiltinsArrayStubBuilder::InitializeArray(GateRef glue, GateRef count, Variable* result)
2810 {
2811     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
2812     Store(VariableType::INT32(), glue, result->ReadVariable(), lengthOffset, TruncInt64ToInt32(count));
2813     GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
2814     Store(VariableType::JS_ANY(), glue, result->ReadVariable(),
2815           IntPtr(JSArray::GetInlinedPropertyOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX)), accessor);
2816     SetExtensibleToBitfield(glue, result->ReadVariable(), true);
2817 }
2818 
NewArray(GateRef glue,GateRef count)2819 GateRef BuiltinsArrayStubBuilder::NewArray(GateRef glue, GateRef count)
2820 {
2821     auto env = GetEnvironment();
2822     Label entry(env);
2823     env->SubCfgEntry(&entry);
2824     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2825     Label exit(env);
2826     Label setProperties(env);
2827     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
2828     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
2829     auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
2830     GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
2831     NewObjectStubBuilder newBuilder(this);
2832     newBuilder.SetParameters(glue, 0);
2833     result = newBuilder.NewJSArrayWithSize(intialHClass, count);
2834     BRANCH(TaggedIsException(*result), &exit, &setProperties);
2835     Bind(&setProperties);
2836     {
2837         InitializeArray(glue, count, &result);
2838         Jump(&exit);
2839     }
2840     Bind(&exit);
2841     auto res = *result;
2842     env->SubCfgExit();
2843     return res;
2844 }
2845 
Includes(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2846 void BuiltinsArrayStubBuilder::Includes(GateRef glue, GateRef thisValue, GateRef numArgs,
2847     Variable *result, Label *exit, Label *slowPath)
2848 {
2849 #if ENABLE_NEXT_OPTIMIZATION
2850     IndexOfOptions options;
2851     options.compType = ComparisonType::SAME_VALUE_ZERO;
2852     options.returnType = IndexOfReturnType::TAGGED_FOUND_OR_NOT;
2853     options.holeAsUndefined = true;
2854     options.reversedOrder = false;
2855 
2856     IndexOfOptimised(glue, thisValue, numArgs, result, exit, slowPath, options);
2857 #else
2858     auto env = GetEnvironment();
2859     Label isDictMode(env);
2860     Label isHeapObject(env);
2861     Label isJsArray(env);
2862     Label isStableJsArray(env);
2863     Label notFound(env);
2864     Label thisLenNotZero(env);
2865     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2866     Bind(&isHeapObject);
2867     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
2868     Bind(&isJsArray);
2869     BRANCH(IsStableJSArray(glue, thisValue), &isStableJsArray, slowPath);
2870     Bind(&isStableJsArray);
2871     GateRef thisLen = GetArrayLength(thisValue);
2872     BRANCH(Int32Equal(thisLen, Int32(0)), &notFound, &thisLenNotZero);
2873     Bind(&thisLenNotZero);
2874     {
2875         DEFVARIABLE(fromIndex, VariableType::INT32(), Int32(0));
2876         Label getArgTwo(env);
2877         Label nextProcess(env);
2878         BRANCH(Int64Equal(numArgs, IntPtr(2)), &getArgTwo, &nextProcess); // 2: 2 parameters
2879         Bind(&getArgTwo);
2880         {
2881             Label secondArgIsInt(env);
2882             GateRef fromIndexTemp = GetCallArg1(numArgs);
2883             BRANCH(TaggedIsInt(fromIndexTemp), &secondArgIsInt, slowPath);
2884             Bind(&secondArgIsInt);
2885             fromIndex = GetInt32OfTInt(fromIndexTemp);
2886             Jump(&nextProcess);
2887         }
2888         Bind(&nextProcess);
2889         {
2890             Label atLeastOneArg(env);
2891             Label setBackZero(env);
2892             Label calculateFrom(env);
2893             Label nextCheck(env);
2894             BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
2895             Bind(&atLeastOneArg);
2896             BRANCH(Int32GreaterThanOrEqual(*fromIndex, thisLen), &notFound, &nextCheck);
2897             Bind(&nextCheck);
2898             {
2899                 GateRef negThisLen = Int32Sub(Int32(0), thisLen);
2900                 BRANCH(Int32LessThan(*fromIndex, negThisLen), &setBackZero, &calculateFrom);
2901                 Bind(&setBackZero);
2902                 {
2903                     fromIndex = Int32(0);
2904                     Jump(&calculateFrom);
2905                 }
2906                 Bind(&calculateFrom);
2907                 {
2908                     DEFVARIABLE(from, VariableType::INT32(), Int32(0));
2909                     Label fromIndexGreaterOrEqualZero(env);
2910                     Label fromIndexLessThanZero(env);
2911                     Label startLoop(env);
2912                     BRANCH(Int32GreaterThanOrEqual(*fromIndex, Int32(0)),
2913                         &fromIndexGreaterOrEqualZero, &fromIndexLessThanZero);
2914                     Bind(&fromIndexGreaterOrEqualZero);
2915                     {
2916                         from = *fromIndex;
2917                         Jump(&startLoop);
2918                     }
2919                     Bind(&fromIndexLessThanZero);
2920                     {
2921                         Label isLenFromIndex(env);
2922                         GateRef lenFromIndexSum = Int32Add(thisLen, *fromIndex);
2923                         BRANCH(Int32GreaterThanOrEqual(lenFromIndexSum, Int32(0)), &isLenFromIndex, &startLoop);
2924                         Bind(&isLenFromIndex);
2925                         {
2926                             from = lenFromIndexSum;
2927                             Jump(&startLoop);
2928                         }
2929                     }
2930                     Bind(&startLoop);
2931                     {
2932                         GateRef searchElement = GetCallArg0(numArgs);
2933                         Label loopHead(env);
2934                         Label loopEnd(env);
2935                         Label next(env);
2936                         Label loopExit(env);
2937                         Jump(&loopHead);
2938                         LoopBegin(&loopHead);
2939                         {
2940                             BRANCH(Int32LessThan(*from, thisLen), &next, &loopExit);
2941                             Bind(&next);
2942                             {
2943                                 Label notHoleOrUndefValue(env);
2944                                 Label valueFound(env);
2945                                 GateRef value = GetTaggedValueWithElementsKind(glue, thisValue, *from);
2946                                 GateRef isHole = TaggedIsHole(value);
2947                                 GateRef isUndef = TaggedIsUndefined(value);
2948                                 BRANCH(BitOr(isHole, isUndef), slowPath, &notHoleOrUndefValue);
2949                                 Bind(&notHoleOrUndefValue);
2950                                 GateRef valueEqual = StubBuilder::SameValueZero(glue, searchElement, value);
2951                                 BRANCH(valueEqual, &valueFound, &loopEnd);
2952                                 Bind(&valueFound);
2953                                 {
2954                                     result->WriteVariable(TaggedTrue());
2955                                     Jump(exit);
2956                                 }
2957                             }
2958                         }
2959                         Bind(&loopEnd);
2960                         from = Int32Add(*from, Int32(1));
2961                         LoopEnd(&loopHead, env, glue);
2962                         Bind(&loopExit);
2963                         Jump(&notFound);
2964                     }
2965                 }
2966             }
2967         }
2968     }
2969     Bind(&notFound);
2970     {
2971         result->WriteVariable(TaggedFalse());
2972         Jump(exit);
2973     }
2974 #endif
2975 }
2976 
From(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2977 void BuiltinsArrayStubBuilder::From(GateRef glue, [[maybe_unused]] GateRef thisValue, GateRef numArgs,
2978     Variable *result, Label *exit, Label *slowPath)
2979 {
2980     auto env = GetEnvironment();
2981     GateRef item = GetCallArg0(numArgs);
2982     Label stringItem(env);
2983     BRANCH(TaggedIsString(item), &stringItem, slowPath);
2984     Bind(&stringItem);
2985     Label undefFn(env);
2986     GateRef fn = GetCallArg1(numArgs);
2987     BRANCH(TaggedIsUndefined(fn), &undefFn, slowPath);
2988     Bind(&undefFn);
2989     GateRef strLen = GetLengthFromString(item);
2990     Label lessStrLen(env);
2991     BRANCH(Int32LessThan(strLen, Int32(builtins::StringToListResultCache::MAX_STRING_LENGTH)), &lessStrLen, slowPath);
2992     Bind(&lessStrLen);
2993     GateRef cacheArray = CallNGCRuntime(glue, RTSTUB_ID(GetStringToListCacheArray), { glue });
2994 
2995     Label cacheDef(env);
2996     BRANCH(TaggedIsUndefined(cacheArray), slowPath, &cacheDef);
2997     Bind(&cacheDef);
2998     {
2999         GateRef hash = GetHashcodeFromString(glue, item);
3000         GateRef entry = Int32And(hash, Int32Sub(Int32(builtins::StringToListResultCache::CACHE_SIZE), Int32(1)));
3001         GateRef index = Int32Mul(entry, Int32(builtins::StringToListResultCache::ENTRY_SIZE));
3002         GateRef cacheStr = GetValueFromTaggedArray(cacheArray,
3003             Int32Add(index, Int32(builtins::StringToListResultCache::STRING_INDEX)));
3004         Label cacheStrDef(env);
3005         BRANCH(TaggedIsUndefined(cacheStr), slowPath, &cacheStrDef);
3006         Bind(&cacheStrDef);
3007         Label strEqual(env);
3008         Label strSlowEqual(env);
3009         // cache str is intern
3010         BRANCH(Equal(cacheStr, item), &strEqual, &strSlowEqual);
3011         Bind(&strSlowEqual);
3012         BRANCH(FastStringEqual(glue, cacheStr, item), &strEqual, slowPath);
3013         Bind(&strEqual);
3014 
3015         GateRef cacheResArray = GetValueFromTaggedArray(cacheArray,
3016             Int32Add(index, Int32(builtins::StringToListResultCache::ARRAY_INDEX)));
3017         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
3018         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
3019         auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
3020         GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
3021         NewObjectStubBuilder newBuilder(this);
3022         newBuilder.SetParameters(glue, 0);
3023         GateRef newArray = newBuilder.NewJSObject(glue, intialHClass);
3024         Store(VariableType::INT32(), glue, newArray, IntPtr(JSArray::LENGTH_OFFSET), strLen);
3025         GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
3026         Store(VariableType::JS_ANY(), glue, newArray,
3027               IntPtr(JSArray::GetInlinedPropertyOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX)), accessor);
3028         SetExtensibleToBitfield(glue, newArray, true);
3029 
3030         SetElementsArray(VariableType::JS_ANY(), glue, newArray, cacheResArray);
3031         *result = newArray;
3032         Jump(exit);
3033     }
3034 }
3035 
CreateSpliceDeletedArray(GateRef glue,GateRef thisValue,GateRef actualDeleteCount,GateRef start)3036 GateRef BuiltinsArrayStubBuilder::CreateSpliceDeletedArray(GateRef glue, GateRef thisValue, GateRef actualDeleteCount,
3037                                                            GateRef start)
3038 {
3039     auto env = GetEnvironment();
3040     Label subentry(env);
3041     Label exit(env);
3042     env->SubCfgEntry(&subentry);
3043     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
3044 
3045     // new delete array
3046     DEFVARIABLE(srcElements, VariableType::JS_ANY(), GetElementsArray(thisValue));
3047     GateRef newArray = NewArray(glue, actualDeleteCount);
3048     result = newArray;
3049 
3050     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
3051     Label loopHead(env);
3052     Label loopEnd(env);
3053     Label next(env);
3054     Label loopExit(env);
3055     Jump(&loopHead);
3056     LoopBegin(&loopHead);
3057     {
3058         BRANCH(Int32LessThan(*i, actualDeleteCount), &next, &loopExit);
3059         Bind(&next);
3060         Label setHole(env);
3061         Label setSrc(env);
3062         BRANCH(Int32GreaterThanOrEqual(Int32Add(*i, start),
3063             GetLengthOfTaggedArray(*srcElements)), &setHole, &setSrc);
3064         Bind(&setHole);
3065         {
3066             SetValueWithElementsKind(glue, newArray, Hole(), *i, Boolean(true),
3067                                      Int32(Elements::ToUint(ElementsKind::NONE)));
3068             Jump(&loopEnd);
3069         }
3070         Bind(&setSrc);
3071         {
3072             GateRef val = GetTaggedValueWithElementsKind(glue, thisValue, Int32Add(start, *i));
3073             SetValueWithElementsKind(glue, newArray, val, *i, Boolean(true),
3074                                      Int32(Elements::ToUint(ElementsKind::NONE)));
3075             Jump(&loopEnd);
3076         }
3077     }
3078     Bind(&loopEnd);
3079     i = Int32Add(*i, Int32(1));
3080     LoopEnd(&loopHead, env, glue);
3081     Bind(&loopExit);
3082     Jump(&exit);
3083 
3084     Bind(&exit);
3085     auto res = *result;
3086     env->SubCfgExit();
3087     return res;
3088 }
3089 
Fill(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)3090 void BuiltinsArrayStubBuilder::Fill(GateRef glue, GateRef thisValue, GateRef numArgs,
3091     Variable *result, Label *exit, Label *slowPath)
3092 {
3093 #if ENABLE_NEXT_OPTIMIZATION
3094     FillOptimised(glue, thisValue, numArgs, result, exit, slowPath);
3095 #else
3096     auto env = GetEnvironment();
3097     Label isHeapObject(env);
3098     Label isJsArray(env);
3099     Label isStability(env);
3100     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
3101     Bind(&isHeapObject);
3102     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
3103     Bind(&isJsArray);
3104     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
3105     Bind(&isStability);
3106     Label notCOWArray(env);
3107     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
3108     Bind(&notCOWArray);
3109     GateRef arrayCls = LoadHClass(thisValue);
3110     // 1. Let O be ToObject(this value).
3111     // 2 ReturnIfAbrupt(O).
3112     Label hasException(env);
3113     Label proNotCOWArray(env);
3114     GateRef prop = GetPropertiesFromJSObject(thisValue);
3115     BRANCH(IsCOWArray(prop), slowPath, &proNotCOWArray);
3116     Bind(&proNotCOWArray);
3117     // 3. Let len be ToLength(Get(O,"length")).
3118     GateRef value = GetCallArg0(numArgs);
3119     GateRef thisArrLen = GetLengthOfJSArray(thisValue);
3120     Label isDict(env);
3121     Label notDict(env);
3122     BRANCH(IsDictionaryElement(arrayCls), &isDict, &notDict);
3123     Bind(&isDict);
3124     {
3125         GateRef size = GetNumberOfElements(glue, thisValue);
3126         BRANCH(Int32GreaterThan(Int32Sub(thisArrLen, size),
3127             TruncInt64ToInt32(IntPtr(JSObject::MAX_GAP))), slowPath, &notDict);
3128     }
3129     Bind(&notDict);
3130     // 5. let relativeStart be ToInteger(start).
3131     GateRef startArg = GetCallArg1(numArgs);
3132     // 6 ReturnIfAbrupt(relativeStart).
3133     GateRef argStart = NumberGetInt(glue, ToNumber(glue, startArg));
3134     Label notHasException3(env);
3135     BRANCH(HasPendingException(glue), &hasException, &notHasException3);
3136     Bind(&notHasException3);
3137     // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
3138     DEFVARIABLE(start, VariableType::INT32(), Int32(0));
3139     Label maxStart(env);
3140     Label minStart(env);
3141     Label startExit(env);
3142     BRANCH(Int32LessThan(argStart, Int32(0)), &maxStart, &minStart);
3143     Bind(&maxStart);
3144     {
3145         GateRef tempStart = Int32Add(argStart, thisArrLen);
3146         Label bind1(env);
3147         BRANCH(Int32GreaterThan(tempStart, Int32(0)), &bind1, &startExit);
3148         Bind(&bind1);
3149         {
3150             start = tempStart;
3151             Jump(&startExit);
3152         }
3153     }
3154     Bind(&minStart);
3155     {
3156         Label bind1(env);
3157         Label bind2(env);
3158         BRANCH(Int32LessThan(argStart, thisArrLen), &bind1, &bind2);
3159         Bind(&bind1);
3160         {
3161             start = argStart;
3162             Jump(&startExit);
3163         }
3164         Bind(&bind2);
3165         {
3166             start = thisArrLen;
3167             Jump(&startExit);
3168         }
3169     }
3170     Bind(&startExit);
3171     // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
3172     GateRef endArg = GetCallArg2(numArgs);
3173     DEFVARIABLE(argEnd, VariableType::INT32(), Int32(0));
3174     Label endArgIsUndefined(env);
3175     Label endArgNotUndefined(env);
3176     Label next1(env);
3177     BRANCH(TaggedIsUndefined(endArg), &endArgIsUndefined, &endArgNotUndefined);
3178     Bind(&endArgIsUndefined);
3179     {
3180         argEnd = thisArrLen;
3181         Jump(&next1);
3182     }
3183     Bind(&endArgNotUndefined);
3184     {
3185         argEnd = NumberGetInt(glue, ToNumber(glue, endArg));
3186         // 9. ReturnIfAbrupt(relativeEnd).
3187         BRANCH(HasPendingException(glue), &hasException, &next1);
3188     }
3189     Bind(&next1);
3190 
3191     // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
3192     DEFVARIABLE(end, VariableType::INT32(), Int32(0));
3193     Label maxEnd(env);
3194     Label minEnd(env);
3195     Label endExit(env);
3196     BRANCH(Int32LessThan(*argEnd, Int32(0)), &maxEnd, &minEnd);
3197     Bind(&maxEnd);
3198     {
3199         GateRef tempEnd = Int32Add(*argEnd, thisArrLen);
3200         Label bind1(env);
3201         Label bind2(env);
3202         BRANCH(Int32GreaterThan(tempEnd, Int32(0)), &bind1, &endExit);
3203         Bind(&bind1);
3204         {
3205             end = tempEnd;
3206             Jump(&endExit);
3207         }
3208     }
3209     Bind(&minEnd);
3210     {
3211         Label bind1(env);
3212         Label bind2(env);
3213         BRANCH(Int32LessThan(*argEnd, thisArrLen), &bind1, &bind2);
3214         Bind(&bind1);
3215         {
3216             end = *argEnd;
3217             Jump(&endExit);
3218         }
3219         Bind(&bind2);
3220         {
3221             end = thisArrLen;
3222             Jump(&endExit);
3223         }
3224     }
3225     Bind(&endExit);
3226     {
3227         Label newElements(env);
3228         Label defaultElements(env);
3229         Label startFill(env);
3230         GateRef elementKind = GetElementsKindFromHClass(arrayCls);
3231         TransitToElementsKind(glue, thisValue, value, elementKind);
3232         DEFVARIABLE(migratedValue, VariableType::JS_ANY(), value);
3233         DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(thisValue));
3234         GateRef mutant = IsMutantTaggedArray(*elements);
3235         GateRef elementLen = GetLengthOfTaggedArray(*elements);
3236         BRANCH(Int32GreaterThanOrEqual(elementLen, *end), &defaultElements, &newElements);
3237         Bind(&defaultElements);
3238         {
3239             Label isMutant(env);
3240             BRANCH(mutant, &isMutant, &startFill);
3241             Bind(&isMutant);
3242             {
3243                 migratedValue = ConvertTaggedValueWithElementsKind(glue, value, elementKind);
3244                 Jump(&startFill);
3245             }
3246         }
3247         Bind(&newElements);
3248         {
3249             Label isMutant(env);
3250             Label notMutant(env);
3251             NewObjectStubBuilder newBuilder(this);
3252             BRANCH(mutant, &isMutant, &notMutant);
3253             Bind(&isMutant);
3254             {
3255                 elements = newBuilder.NewMutantTaggedArray(glue, elementLen);
3256                 migratedValue = ConvertTaggedValueWithElementsKind(glue, value, elementKind);
3257                 Jump(&startFill);
3258             }
3259             Bind(&notMutant);
3260             {
3261                 elements = newBuilder.NewTaggedArray(glue, elementLen);
3262                 Jump(&startFill);
3263             }
3264         }
3265         Bind(&startFill);
3266         Label noBarrier(env);
3267         Label needBarrier(env);
3268         Label needRevise(env);
3269         Label noRevise(env);
3270         Label barrierExit(env);
3271         BRANCH(mutant, &noBarrier, &needBarrier);
3272         Bind(&noBarrier);
3273         {
3274             DEFVARIABLE(idx, VariableType::INT32(), *start);
3275             Label loopHead(env);
3276             Label loopEnd(env);
3277             Label next(env);
3278             Label loopExit(env);
3279             Jump(&loopHead);
3280             LoopBegin(&loopHead);
3281             {
3282                 BRANCH(Int32LessThan(*idx, *end), &next, &loopExit);
3283                 Bind(&next);
3284                 SetValueToTaggedArray(VariableType::JS_ANY(), glue,
3285                     *elements, *idx, *migratedValue, MemoryAttribute::NoBarrier());
3286                 Jump(&loopEnd);
3287             }
3288             Bind(&loopEnd);
3289             idx = Int32Add(*idx, Int32(1));
3290             LoopEnd(&loopHead);
3291             Bind(&loopExit);
3292             Jump(&barrierExit);
3293         }
3294         Bind(&needBarrier);
3295         {
3296             DEFVARIABLE(idx, VariableType::INT32(), *start);
3297             Label loopHead(env);
3298             Label loopEnd(env);
3299             Label next(env);
3300             Label loopExit(env);
3301             Jump(&loopHead);
3302             LoopBegin(&loopHead);
3303             {
3304                 BRANCH(Int32LessThan(*idx, *end), &next, &loopExit);
3305                 Bind(&next);
3306                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, *elements, *idx, *migratedValue);
3307                 Jump(&loopEnd);
3308             }
3309             Bind(&loopEnd);
3310             idx = Int32Add(*idx, Int32(1));
3311             LoopEnd(&loopHead);
3312             Bind(&loopExit);
3313             Jump(&barrierExit);
3314         }
3315         Bind(&barrierExit);
3316         SetElementsArray(VariableType::JS_POINTER(), glue, thisValue, *elements);
3317         GateRef arrLen = GetLengthOfJSArray(thisValue);
3318         BRANCH(Int32LessThan(arrLen, *end), &needRevise, &noRevise);
3319         Bind(&needRevise);
3320         {
3321             SetArrayLength(glue, thisValue, *end);
3322             Jump(&noRevise);
3323         }
3324         Bind(&noRevise);
3325         result->WriteVariable(thisValue);
3326         Jump(exit);
3327     }
3328     Bind(&hasException);
3329     {
3330         result->WriteVariable(Exception());
3331         Jump(exit);
3332     }
3333 #endif
3334 }
3335 
Splice(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)3336 void BuiltinsArrayStubBuilder::Splice(GateRef glue, GateRef thisValue, GateRef numArgs,
3337     Variable *result, Label *exit, Label *slowPath)
3338 {
3339     auto env = GetEnvironment();
3340     Label isHeapObject(env);
3341     Label isJsArray(env);
3342     Label isStability(env);
3343     Label defaultConstr(env);
3344     Label isGeneric(env);
3345     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
3346     Bind(&isHeapObject);
3347     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
3348     Bind(&isJsArray);
3349     // need check constructor, "Splice" should use ArraySpeciesCreate
3350     BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr);
3351     Bind(&defaultConstr);
3352     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
3353     Bind(&isStability);
3354     Label notCOWArray(env);
3355     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
3356     Bind(&notCOWArray);
3357     GateRef arrayLen = GetArrayLength(thisValue);
3358     Label lessThreeArg(env);
3359 
3360     DEFVARIABLE(start, VariableType::INT32(), Int32(0));
3361     DEFVARIABLE(insertCount, VariableType::INT32(), Int32(0));
3362     DEFVARIABLE(actualDeleteCount, VariableType::INT32(), Int32(0));
3363     GateRef argc = ChangeIntPtrToInt32(numArgs);
3364     BRANCH(Int32LessThanOrEqual(argc, Int32(3)), &lessThreeArg, slowPath); // 3 : three arg
3365     Bind(&lessThreeArg);
3366     {
3367         Label checkOverflow(env);
3368         Label greaterZero(env);
3369         Label greaterOne(env);
3370         Label checkGreaterOne(env);
3371         Label notOverflow(env);
3372         BRANCH(Int32GreaterThan(argc, Int32(0)), &greaterZero, &checkGreaterOne);
3373         Bind(&greaterZero);
3374         GateRef taggedStart = GetCallArg0(numArgs);
3375         Label taggedStartInt(env);
3376         BRANCH(TaggedIsInt(taggedStart), &taggedStartInt, slowPath);
3377         Bind(&taggedStartInt);
3378         {
3379             GateRef intStart = GetInt32OfTInt(taggedStart);
3380             start = CalArrayRelativePos(intStart, arrayLen);
3381         }
3382         actualDeleteCount = Int32Sub(arrayLen, *start);
3383         Jump(&checkGreaterOne);
3384         Bind(&checkGreaterOne);
3385         BRANCH(Int32GreaterThan(argc, Int32(1)), &greaterOne, &checkOverflow);
3386         Bind(&greaterOne);
3387         insertCount = Int32Sub(argc, Int32(2)); // 2 :  two args
3388         GateRef argDeleteCount = GetCallArg1(numArgs);
3389         Label argDeleteCountInt(env);
3390         BRANCH(TaggedIsInt(argDeleteCount), &argDeleteCountInt, slowPath);
3391         Bind(&argDeleteCountInt);
3392         DEFVARIABLE(deleteCount, VariableType::INT32(), TaggedGetInt(argDeleteCount));
3393         Label deleteCountLessZero(env);
3394         Label calActualDeleteCount(env);
3395         BRANCH(Int32LessThan(*deleteCount, Int32(0)), &deleteCountLessZero, &calActualDeleteCount);
3396         Bind(&deleteCountLessZero);
3397         deleteCount = Int32(0);
3398         Jump(&calActualDeleteCount);
3399         Bind(&calActualDeleteCount);
3400         actualDeleteCount = *deleteCount;
3401         Label lessArrayLen(env);
3402         BRANCH(Int32LessThan(Int32Sub(arrayLen, *start), *deleteCount), &lessArrayLen, &checkOverflow);
3403         Bind(&lessArrayLen);
3404         actualDeleteCount = Int32Sub(arrayLen, *start);
3405         Jump(&checkOverflow);
3406         Bind(&checkOverflow);
3407         BRANCH(Int64GreaterThan(Int64Sub(Int64Add(ZExtInt32ToInt64(arrayLen), ZExtInt32ToInt64(*insertCount)),
3408             ZExtInt32ToInt64(*actualDeleteCount)), Int64(base::MAX_SAFE_INTEGER)), slowPath, &notOverflow);
3409         Bind(&notOverflow);
3410         *result = CreateSpliceDeletedArray(glue, thisValue, *actualDeleteCount, *start);
3411         // insert Val
3412         DEFVARIABLE(srcElements, VariableType::JS_ANY(), GetElementsArray(thisValue));
3413         GateRef oldCapacity = GetLengthOfTaggedArray(*srcElements);
3414         GateRef newCapacity = Int32Add(Int32Sub(arrayLen, *actualDeleteCount), *insertCount);
3415         Label grow(env);
3416         Label copy(env);
3417         BRANCH(Int32GreaterThan(newCapacity, oldCapacity), &grow, &copy);
3418         Bind(&grow);
3419         {
3420             srcElements = GrowElementsCapacity(glue, thisValue, newCapacity);
3421             Jump(&copy);
3422         }
3423         Bind(&copy);
3424         GateRef srcElementsLen = GetLengthOfTaggedArray(*srcElements);
3425         Label insertLessDelete(env);
3426         Label insertGreaterDelete(env);
3427         Label insertCountVal(env);
3428         Label setArrayLen(env);
3429         Label trimCheck(env);
3430         BRANCH(Int32LessThan(*insertCount, *actualDeleteCount), &insertLessDelete, &insertGreaterDelete);
3431         Bind(&insertLessDelete);
3432         {
3433             {
3434                 DEFVARIABLE(i, VariableType::INT32(), *start);
3435                 DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
3436 
3437                 Label loopHead(env);
3438                 Label loopEnd(env);
3439                 Label next(env);
3440                 Label loopExit(env);
3441                 Jump(&loopHead);
3442                 LoopBegin(&loopHead);
3443                 {
3444                     BRANCH(Int32LessThan(*i, Int32Sub(arrayLen, *actualDeleteCount)), &next, &loopExit);
3445                     Bind(&next);
3446                     ele = Hole();
3447                     Label getSrcEle(env);
3448                     Label setEle(env);
3449                     BRANCH(Int32LessThan(Int32Add(*i, *actualDeleteCount), srcElementsLen), &getSrcEle, &setEle);
3450                     Bind(&getSrcEle);
3451                     {
3452                         ele = GetTaggedValueWithElementsKind(glue, thisValue, Int32Add(*i, *actualDeleteCount));
3453                         Jump(&setEle);
3454                     }
3455                     Bind(&setEle);
3456                     {
3457                         Label setIndexLessLen(env);
3458                         BRANCH(Int32LessThan(Int32Add(*i, *insertCount), srcElementsLen), &setIndexLessLen, &loopEnd);
3459                         Bind(&setIndexLessLen);
3460                         {
3461                             SetValueWithElementsKind(glue, thisValue, *ele, Int32Add(*i, *insertCount), Boolean(true),
3462                                                      Int32(Elements::ToUint(ElementsKind::NONE)));
3463                             Jump(&loopEnd);
3464                         }
3465                     }
3466                 }
3467                 Bind(&loopEnd);
3468                 i = Int32Add(*i, Int32(1));
3469                 LoopEnd(&loopHead, env, glue);
3470                 Bind(&loopExit);
3471                 Jump(&trimCheck);
3472             }
3473 
3474             Label trim(env);
3475             Label noTrim(env);
3476             Bind(&trimCheck);
3477             GateRef needTrim = LogicAndBuilder(env)
3478                 .And(Int32GreaterThan(oldCapacity, newCapacity))
3479                 .And(Int32GreaterThan(Int32Sub(oldCapacity, newCapacity), Int32(TaggedArray::MAX_END_UNUSED)))
3480                 .Done();
3481             BRANCH(needTrim, &trim, &noTrim);
3482             Bind(&trim);
3483             {
3484                 CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, *srcElements, ZExtInt32ToInt64(newCapacity)});
3485                 Jump(&insertCountVal);
3486             }
3487             Bind(&noTrim);
3488             {
3489                 DEFVARIABLE(idx, VariableType::INT32(), newCapacity);
3490                 Label loopHead1(env);
3491                 Label loopEnd1(env);
3492                 Label next1(env);
3493                 Label loopExit1(env);
3494                 Jump(&loopHead1);
3495                 LoopBegin(&loopHead1);
3496                 {
3497                     BRANCH(Int32LessThan(*idx, arrayLen), &next1, &loopExit1);
3498                     Bind(&next1);
3499 
3500                     Label setHole(env);
3501                     BRANCH(Int32LessThan(*idx, srcElementsLen), &setHole, &loopEnd1);
3502                     Bind(&setHole);
3503                     {
3504                         SetValueWithElementsKind(glue, thisValue, Hole(), *idx, Boolean(true),
3505                                                  Int32(Elements::ToUint(ElementsKind::NONE)));
3506                         Jump(&loopEnd1);
3507                     }
3508                 }
3509                 Bind(&loopEnd1);
3510                 idx = Int32Add(*idx, Int32(1));
3511                 LoopEnd(&loopHead1);
3512                 Bind(&loopExit1);
3513                 Jump(&insertCountVal);
3514             }
3515             Bind(&insertGreaterDelete);
3516             {
3517                 DEFVARIABLE(j, VariableType::INT32(), Int32Sub(arrayLen, *actualDeleteCount));
3518                 DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
3519                 Label loopHead(env);
3520                 Label loopEnd(env);
3521                 Label next(env);
3522                 Label loopExit(env);
3523                 Jump(&loopHead);
3524                 LoopBegin(&loopHead);
3525                 {
3526                     BRANCH(Int32GreaterThan(*j, *start), &next, &loopExit);
3527                     Bind(&next);
3528                     ele = GetTaggedValueWithElementsKind(glue, thisValue, Int32Sub(Int32Add(*j, *actualDeleteCount),
3529                                                                                    Int32(1)));
3530                     SetValueWithElementsKind(glue, thisValue, *ele, Int32Sub(Int32Add(*j, *insertCount), Int32(1)),
3531                                              Boolean(true), Int32(Elements::ToUint(ElementsKind::NONE)));
3532                     Jump(&loopEnd);
3533                 }
3534                 Bind(&loopEnd);
3535                 j = Int32Sub(*j, Int32(1));
3536                 LoopEnd(&loopHead, env, glue);
3537                 Bind(&loopExit);
3538                 Jump(&insertCountVal);
3539             }
3540             Bind(&insertCountVal);
3541             {
3542                 Label threeArgs(env);
3543                 BRANCH(Int32Equal(ChangeIntPtrToInt32(numArgs), Int32(3)), &threeArgs, &setArrayLen); // 3 : three arg
3544                 Bind(&threeArgs);
3545                 {
3546                     GateRef e = GetCallArg2(numArgs);
3547                     SetValueWithElementsKind(glue, thisValue, e, *start, Boolean(true),
3548                                              Int32(Elements::ToUint(ElementsKind::NONE)));
3549                     Jump(&setArrayLen);
3550                 }
3551             }
3552             Bind(&setArrayLen);
3553             SetArrayLength(glue, thisValue, newCapacity);
3554             Jump(exit);
3555         }
3556     }
3557 }
3558 
ToSpliced(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)3559 void BuiltinsArrayStubBuilder::ToSpliced(GateRef glue, GateRef thisValue, GateRef numArgs,
3560     Variable *result, Label *exit, Label *slowPath)
3561 {
3562 #if ENABLE_NEXT_OPTIMIZATION
3563     ToSplicedOptimised(glue, thisValue, numArgs, result, exit, slowPath);
3564 #else
3565     auto env = GetEnvironment();
3566     Label isHeapObject(env);
3567     Label isJsArray(env);
3568     Label isStability(env);
3569     Label isGeneric(env);
3570     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
3571     Bind(&isHeapObject);
3572     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
3573     Bind(&isJsArray);
3574     // don't check constructor, "ToSpliced" always use ArrayCreate to create array.
3575     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
3576     Bind(&isStability);
3577     Label notCOWArray(env);
3578     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
3579     Bind(&notCOWArray);
3580     GateRef thisLen = GetArrayLength(thisValue);
3581     Label lessThreeArg(env);
3582     DEFVARIABLE(actualStart, VariableType::INT32(), Int32(0));
3583     DEFVARIABLE(actualDeleteCount, VariableType::INT32(), Int32(0));
3584     DEFVARIABLE(newLen, VariableType::INT32(), Int32(0));
3585     DEFVARIABLE(insertCount, VariableType::INT32(), Int32(0));
3586     GateRef argc = ChangeIntPtrToInt32(numArgs);
3587     // 3: max arg count
3588     BRANCH(Int32LessThanOrEqual(argc, Int32(3)), &lessThreeArg, slowPath);
3589     Bind(&lessThreeArg);
3590     {
3591         Label checkOverFlow(env);
3592         Label greaterZero(env);
3593         Label greaterOne(env);
3594         Label checkGreaterOne(env);
3595         Label notOverFlow(env);
3596         Label copyAfter(env);
3597         // 0: judge the first arg exists
3598         BRANCH(Int32GreaterThan(argc, Int32(0)), &greaterZero, &checkGreaterOne);
3599         Bind(&greaterZero);
3600         {
3601             GateRef taggedStart = GetCallArg0(numArgs);
3602             Label taggedStartInt(env);
3603             BRANCH(TaggedIsInt(taggedStart), &taggedStartInt, slowPath);
3604             Bind(&taggedStartInt);
3605             {
3606                 GateRef intStart = GetInt32OfTInt(taggedStart);
3607                 actualStart = CalArrayRelativePos(intStart, thisLen);
3608                 actualDeleteCount = Int32Sub(thisLen, *actualStart);
3609                 Jump(&checkGreaterOne);
3610             }
3611         }
3612         Bind(&checkGreaterOne);
3613         {
3614             // 1: judge the second arg exists
3615             BRANCH(Int32GreaterThan(argc, Int32(1)), &greaterOne, &checkOverFlow);
3616             Bind(&greaterOne);
3617             {
3618                 // 2: arg count which is not an item
3619                 insertCount = Int32Sub(argc, Int32(2));
3620                 GateRef argDeleteCount = GetCallArg1(numArgs);
3621                 Label argDeleteCountInt(env);
3622                 BRANCH(TaggedIsInt(argDeleteCount), &argDeleteCountInt, slowPath);
3623                 Bind(&argDeleteCountInt);
3624                 {
3625                     DEFVARIABLE(deleteCount, VariableType::INT32(), TaggedGetInt(argDeleteCount));
3626                     Label deleteCountLessZero(env);
3627                     Label calActualDeleteCount(env);
3628                     BRANCH(Int32LessThan(*deleteCount, Int32(0)), &deleteCountLessZero, &calActualDeleteCount);
3629                     Bind(&deleteCountLessZero);
3630                     {
3631                         deleteCount = Int32(0);
3632                         Jump(&calActualDeleteCount);
3633                     }
3634                     Bind(&calActualDeleteCount);
3635                     {
3636                         actualDeleteCount = *deleteCount;
3637                         Label lessArrayLen(env);
3638                         BRANCH(Int32LessThan(Int32Sub(thisLen, *actualStart), *deleteCount),
3639                             &lessArrayLen, &checkOverFlow);
3640                         Bind(&lessArrayLen);
3641                         {
3642                             actualDeleteCount = Int32Sub(thisLen, *actualStart);
3643                             Jump(&checkOverFlow);
3644                         }
3645                     }
3646                 }
3647             }
3648             Bind(&checkOverFlow);
3649             {
3650                 newLen = Int32Add(Int32Sub(thisLen, *actualDeleteCount), *insertCount);
3651                 BRANCH(Int64GreaterThan(ZExtInt32ToInt64(*newLen), Int64(base::MAX_SAFE_INTEGER)),
3652                     slowPath, &notOverFlow);
3653                 Bind(&notOverFlow);
3654                 Label newLenEmpty(env);
3655                 Label newLenNotEmpty(env);
3656                 BRANCH(Int32Equal(*newLen, Int32(0)), &newLenEmpty, &newLenNotEmpty);
3657                 Bind(&newLenEmpty);
3658                 {
3659                     NewObjectStubBuilder newBuilder(this);
3660                     result->WriteVariable(newBuilder.CreateEmptyArray(glue));
3661                     Jump(exit);
3662                 }
3663                 Bind(&newLenNotEmpty);
3664                 {
3665                     Label copyBefore(env);
3666                     Label insertArg(env);
3667                     GateRef newArray = NewArray(glue, Int32(0));
3668                     GrowElementsCapacity(glue, newArray, *newLen);
3669                     DEFVARIABLE(oldIndex, VariableType::INT32(), Int32(0));
3670                     DEFVARIABLE(newIndex, VariableType::INT32(), Int32(0));
3671                     BRANCH(Int32GreaterThan(*actualStart, Int32(0)), &copyBefore, &insertArg);
3672                     Bind(&copyBefore);
3673                     {
3674                         Label loopHead(env);
3675                         Label loopEnd(env);
3676                         Label loopNext(env);
3677                         Label loopExit(env);
3678                         Label eleIsHole(env);
3679                         Label eleNotHole(env);
3680                         Jump(&loopHead);
3681                         LoopBegin(&loopHead);
3682                         {
3683                             BRANCH(Int32LessThan(*oldIndex, *actualStart), &loopNext, &loopExit);
3684                             Bind(&loopNext);
3685                             GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *oldIndex);
3686                             BRANCH(TaggedIsHole(ele), &eleIsHole, &eleNotHole);
3687                             Bind(&eleIsHole);
3688                             {
3689                                 SetValueWithElementsKind(glue, newArray, Undefined(), *newIndex, Boolean(true),
3690                                     Int32(Elements::ToUint(ElementsKind::NONE)));
3691                                 Jump(&loopEnd);
3692                             }
3693                             Bind(&eleNotHole);
3694                             {
3695                                 SetValueWithElementsKind(glue, newArray, ele, *newIndex, Boolean(true),
3696                                     Int32(Elements::ToUint(ElementsKind::NONE)));
3697                                 Jump(&loopEnd);
3698                             }
3699                         }
3700                         Bind(&loopEnd);
3701                         oldIndex = Int32Add(*oldIndex, Int32(1));
3702                         newIndex = Int32Add(*newIndex, Int32(1));
3703                         LoopEnd(&loopHead);
3704                         Bind(&loopExit);
3705                         Jump(&insertArg);
3706                     }
3707                     Bind(&insertArg);
3708                     {
3709                         Label insert(env);
3710                         BRANCH(Int32GreaterThan(*insertCount, Int32(0)), &insert, &copyAfter);
3711                         Bind(&insert);
3712                         {
3713                             GateRef insertNum = GetCallArg2(numArgs);
3714                             SetValueWithElementsKind(glue, newArray, insertNum, *newIndex, Boolean(true),
3715                                 Int32(Elements::ToUint(ElementsKind::NONE)));
3716                             newIndex = Int32Add(*newIndex, Int32(1));
3717                             Jump(&copyAfter);
3718                         }
3719                     }
3720                     Bind(&copyAfter);
3721                     {
3722                         Label canCopyAfter(env);
3723                         Label setLength(env);
3724                         oldIndex = Int32Add(*actualStart, *actualDeleteCount);
3725                         BRANCH(Int32LessThan(*oldIndex, thisLen), &canCopyAfter, &setLength);
3726                         Bind(&canCopyAfter);
3727                         {
3728                             Label loopHead1(env);
3729                             Label loopNext1(env);
3730                             Label loopEnd1(env);
3731                             Label loopExit1(env);
3732                             Label ele1IsHole(env);
3733                             Label ele1NotHole(env);
3734                             Jump(&loopHead1);
3735                             LoopBegin(&loopHead1);
3736                             {
3737                                 BRANCH(Int32LessThan(*oldIndex, thisLen), &loopNext1, &loopExit1);
3738                                 Bind(&loopNext1);
3739                                 GateRef ele1 = GetTaggedValueWithElementsKind(glue, thisValue, *oldIndex);
3740                                 BRANCH(TaggedIsHole(ele1), &ele1IsHole, &ele1NotHole);
3741                                 Bind(&ele1IsHole);
3742                                 {
3743                                     SetValueWithElementsKind(glue, newArray, Undefined(), *newIndex, Boolean(true),
3744                                         Int32(Elements::ToUint(ElementsKind::NONE)));
3745                                     Jump(&loopEnd1);
3746                                 }
3747                                 Bind(&ele1NotHole);
3748                                 {
3749                                     SetValueWithElementsKind(glue, newArray, ele1, *newIndex, Boolean(true),
3750                                         Int32(Elements::ToUint(ElementsKind::NONE)));
3751                                     Jump(&loopEnd1);
3752                                 }
3753                             }
3754                             Bind(&loopEnd1);
3755                             oldIndex = Int32Add(*oldIndex, Int32(1));
3756                             newIndex = Int32Add(*newIndex, Int32(1));
3757                             LoopEnd(&loopHead1);
3758                             Bind(&loopExit1);
3759                             Jump(&setLength);
3760                         }
3761                         Bind(&setLength);
3762                         {
3763                             SetArrayLength(glue, newArray, *newLen);
3764                             result->WriteVariable(newArray);
3765                             Jump(exit);
3766                         }
3767                     }
3768                 }
3769             }
3770         }
3771     }
3772 #endif
3773 }
3774 
CopyWithin(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)3775 void BuiltinsArrayStubBuilder::CopyWithin(GateRef glue, GateRef thisValue, GateRef numArgs,
3776     Variable *result, Label *exit, Label *slowPath)
3777 {
3778 #if ENABLE_NEXT_OPTIMIZATION
3779     CopyWithinOptimised(glue, thisValue, numArgs, result, exit, slowPath);
3780 #else
3781     auto env = GetEnvironment();
3782     Label thisExists(env);
3783     Label isHeapObject(env);
3784     Label isJsArray(env);
3785     Label isStability(env);
3786     Label notCOWArray(env);
3787     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
3788     Bind(&thisExists);
3789     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
3790     Bind(&isHeapObject);
3791     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
3792     Bind(&isJsArray);
3793     // don't check constructor, "CopyWithin" won't create new array.
3794     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
3795     Bind(&isStability);
3796     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
3797     Bind(&notCOWArray);
3798     DEFVARIABLE(startPos, VariableType::INT64(), Int64(0));
3799     DEFVARIABLE(endPos, VariableType::INT64(), Int64(0));
3800     Label targetTagExists(env);
3801     Label targetTagIsInt(env);
3802     Label startTagExists(env);
3803     Label startTagIsInt(env);
3804     Label afterCallArg1(env);
3805     Label endTagExists(env);
3806     Label endTagIsInt(env);
3807     Label afterCallArg2(env);
3808     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
3809     BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &targetTagExists);
3810     Bind(&targetTagExists);
3811     GateRef targetTag = GetCallArg0(numArgs);
3812     BRANCH(TaggedIsInt(targetTag), &targetTagIsInt, slowPath);
3813     Bind(&targetTagIsInt);
3814     GateRef argTarget = SExtInt32ToInt64(TaggedGetInt(targetTag));
3815     BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &afterCallArg1, &startTagExists);
3816     Bind(&startTagExists);
3817     {
3818         GateRef startTag = GetCallArg1(numArgs);
3819         BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath);
3820         Bind(&startTagIsInt);
3821         startPos = SExtInt32ToInt64(TaggedGetInt(startTag));
3822         Jump(&afterCallArg1);
3823     }
3824     Bind(&afterCallArg1);
3825     {
3826         endPos = thisLen;
3827         BRANCH(Int64GreaterThanOrEqual(IntPtr(2), numArgs), &afterCallArg2, &endTagExists); //2: 2 parameters
3828         Bind(&endTagExists);
3829         {
3830             GateRef endTag = GetCallArg2(numArgs);
3831             BRANCH(TaggedIsInt(endTag), &endTagIsInt, slowPath);
3832             Bind(&endTagIsInt);
3833             {
3834                 endPos = SExtInt32ToInt64(TaggedGetInt(endTag));
3835                 Jump(&afterCallArg2);
3836             }
3837         }
3838     }
3839     Bind(&afterCallArg2);
3840     {
3841         DEFVARIABLE(copyTo, VariableType::INT64(), Int64(0));
3842         DEFVARIABLE(copyFrom, VariableType::INT64(), Int64(0));
3843         DEFVARIABLE(copyEnd, VariableType::INT64(), Int64(0));
3844         DEFVARIABLE(count, VariableType::INT64(), Int64(0));
3845         DEFVARIABLE(direction, VariableType::INT64(), Int64(0));
3846         Label calculateCountBranch1(env);
3847         Label calculateCountBranch2(env);
3848         Label afterCalculateCount(env);
3849         Label needToAdjustParam(env);
3850         Label afterAdjustParam(env);
3851         copyTo = CalculatePositionWithLength(argTarget, thisLen);
3852         copyFrom = CalculatePositionWithLength(*startPos, thisLen);
3853         copyEnd = CalculatePositionWithLength(*endPos, thisLen);
3854         BRANCH(Int64LessThan(Int64Sub(*copyEnd, *copyFrom), Int64Sub(thisLen, *copyTo)),
3855             &calculateCountBranch1, &calculateCountBranch2);
3856         Bind(&calculateCountBranch1);
3857         {
3858             count = Int64Sub(*copyEnd, *copyFrom);
3859             Jump(&afterCalculateCount);
3860         }
3861         Bind(&calculateCountBranch2);
3862         {
3863             count = Int64Sub(thisLen, *copyTo);
3864             Jump(&afterCalculateCount);
3865         }
3866 
3867         Bind(&afterCalculateCount);
3868         {
3869             direction = Int64(1);
3870             GateRef copyFromVal = *copyFrom;
3871             GateRef copyToVal = *copyTo;
3872             GateRef countVal = *count;
3873             BRANCH(LogicAndBuilder(env).And(Int64LessThan(copyFromVal, copyToVal))
3874                 .And(Int64LessThan(copyToVal, Int64Add(copyFromVal, countVal))).Done(),
3875                 &needToAdjustParam, &afterAdjustParam);
3876             Bind(&needToAdjustParam);
3877             {
3878                 direction = Int64(-1);
3879                 copyFrom = Int64Sub(Int64Add(*copyFrom, *count), Int64(1));
3880                 copyTo = Int64Sub(Int64Add(*copyTo, *count), Int64(1));
3881                 Jump(&afterAdjustParam);
3882             }
3883 
3884             Bind(&afterAdjustParam);
3885             {
3886                 DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
3887                 Label loopHead(env);
3888                 Label loopEnd(env);
3889                 Label next(env);
3890                 Label loopExit(env);
3891                 Jump(&loopHead);
3892                 LoopBegin(&loopHead);
3893                 {
3894                     Label kValueIsHole(env);
3895                     Label setValue(env);
3896                     Label hasProperty(env);
3897                     Label setHole(env);
3898                     Label hasException0(env);
3899                     Label notHasException0(env);
3900                     BRANCH(Int64GreaterThan(*count, Int64(0)), &next, &loopExit);
3901                     Bind(&next);
3902                     kValue = GetTaggedValueWithElementsKind(glue, thisValue, *copyFrom);
3903                     BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &setValue);
3904                     Bind(&kValueIsHole);
3905                     GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty),
3906                         { thisValue, IntToTaggedInt(*copyFrom) });
3907                     BRANCH(TaggedIsTrue(hasProp), &hasProperty, &setHole);
3908 
3909                     Bind(&hasProperty);
3910                     kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*copyFrom), ProfileOperation());
3911                     BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
3912                     Bind(&hasException0);
3913                     {
3914                         result->WriteVariable(Exception());
3915                         Jump(exit);
3916                     }
3917                     Bind(&notHasException0);
3918                     BRANCH(TaggedIsHole(*kValue), &setHole, &setValue);
3919                     Bind(&setHole);
3920                     {
3921                         SetValueWithElementsKind(glue, thisValue, Hole(), *copyTo,
3922                             Boolean(true), Int32(Elements::ToUint(ElementsKind::DICTIONARY)));
3923                         Jump(&loopEnd);
3924                     }
3925                     Bind(&setValue);
3926                     {
3927                         SetValueWithElementsKind(glue, thisValue, *kValue, *copyTo,
3928                             Boolean(true), Int32(Elements::ToUint(ElementsKind::NONE)));
3929                         Jump(&loopEnd);
3930                     }
3931                 }
3932                 Bind(&loopEnd);
3933                 copyFrom = Int64Add(*copyFrom, *direction);
3934                 copyTo = Int64Add(*copyTo, *direction);
3935                 count = Int64Sub(*count, Int64(1));
3936                 LoopEnd(&loopHead);
3937                 Bind(&loopExit);
3938                 result->WriteVariable(thisValue);
3939                 Jump(exit);
3940             }
3941         }
3942     }
3943 #endif
3944 }
3945 
CalculatePositionWithLength(GateRef position,GateRef length)3946 GateRef BuiltinsArrayStubBuilder::CalculatePositionWithLength(GateRef position, GateRef length)
3947 {
3948     auto env = GetEnvironment();
3949     Label entry(env);
3950     env->SubCfgEntry(&entry);
3951     DEFVARIABLE(result, VariableType::INT64(), Int64(0));
3952     Label positionLessThanZero(env);
3953     Label positionNotLessThanZero(env);
3954     Label resultNotGreaterThanZero(env);
3955     Label positionLessThanLength(env);
3956     Label positionNotLessThanLength(env);
3957     Label afterCalculatePosition(env);
3958 
3959     BRANCH(Int64LessThan(position, Int64(0)), &positionLessThanZero, &positionNotLessThanZero);
3960     Bind(&positionLessThanZero);
3961     {
3962         result = Int64Add(position, length);
3963         BRANCH(Int64GreaterThan(*result, Int64(0)), &afterCalculatePosition, &resultNotGreaterThanZero);
3964         Bind(&resultNotGreaterThanZero);
3965         result = Int64(0);
3966         Jump(&afterCalculatePosition);
3967     }
3968     Bind(&positionNotLessThanZero);
3969     {
3970         BRANCH(Int64LessThan(position, length), &positionLessThanLength, &positionNotLessThanLength);
3971         Bind(&positionLessThanLength);
3972         {
3973             result = position;
3974             Jump(&afterCalculatePosition);
3975         }
3976         Bind(&positionNotLessThanLength);
3977         {
3978             result = length;
3979             Jump(&afterCalculatePosition);
3980         }
3981     }
3982     Bind(&afterCalculatePosition);
3983     auto ret = *result;
3984     env->SubCfgExit();
3985     return ret;
3986 }
3987 
Some(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)3988 void BuiltinsArrayStubBuilder::Some(GateRef glue, GateRef thisValue, GateRef numArgs,
3989     Variable *result, Label *exit, Label *slowPath)
3990 {
3991 #if ENABLE_NEXT_OPTIMIZATION
3992     SomeOptimised(glue, thisValue, numArgs, result, exit, slowPath);
3993 #else
3994     auto env = GetEnvironment();
3995     Label thisExists(env);
3996     Label isHeapObject(env);
3997     Label isJsArray(env);
3998     Label defaultConstr(env);
3999     Label isStability(env);
4000     Label notCOWArray(env);
4001     Label equalCls(env);
4002     Label isGeneric(env);
4003     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
4004     Bind(&thisExists);
4005     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
4006     Bind(&isHeapObject);
4007     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
4008     Bind(&isJsArray);
4009     // don't check constructor, "Some" won't create new array.
4010     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
4011     Bind(&isStability);
4012     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
4013     Bind(&notCOWArray);
4014     Label arg0HeapObject(env);
4015     Label callable(env);
4016     Label thisIsStable(env);
4017     Label thisNotStable(env);
4018     GateRef callbackFnHandle = GetCallArg0(numArgs);
4019     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
4020     Bind(&arg0HeapObject);
4021     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
4022     Bind(&callable);
4023     GateRef argHandle = GetCallArg1(numArgs);
4024 
4025     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
4026     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
4027     Jump(&thisIsStable);
4028 
4029     Bind(&thisIsStable);
4030     {
4031         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4032         Label loopHead(env);
4033         Label loopEnd(env);
4034         Label next(env);
4035         Label loopExit(env);
4036         Jump(&loopHead);
4037         LoopBegin(&loopHead);
4038         {
4039             Label nextStep(env);
4040             Label kValueIsHole(env);
4041             Label callDispatch(env);
4042             Label hasProperty(env);
4043             Label hasException0(env);
4044             Label notHasException0(env);
4045             Label hasException1(env);
4046             Label notHasException1(env);
4047             BRANCH(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable);
4048             Bind(&nextStep);
4049             BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
4050             Bind(&next);
4051             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
4052             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
4053             Bind(&kValueIsHole);
4054             {
4055                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
4056                 BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
4057                 Bind(&hasProperty);
4058                 {
4059                     kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4060                     BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4061                     Bind(&hasException0);
4062                     {
4063                         result->WriteVariable(Exception());
4064                         Jump(exit);
4065                     }
4066                     Bind(&notHasException0);
4067                     {
4068                         BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
4069                     }
4070                 }
4071             }
4072             Bind(&callDispatch);
4073             {
4074                 GateRef key = Int64ToTaggedInt(*i);
4075                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4076                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4077                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
4078                     Circuit::NullGate(), callArgs);
4079                 GateRef retValue = callBuilder.JSCallDispatch();
4080                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4081                 Bind(&hasException1);
4082                 {
4083                     result->WriteVariable(Exception());
4084                     Jump(exit);
4085                 }
4086                 Bind(&notHasException1);
4087                 {
4088                     DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
4089                     Label changeThisLen(env);
4090                     Label afterChangeLen(env);
4091                     Label retValueIsTrue(env);
4092                     BRANCH(Int64LessThan(*newLen, *thisArrLen), &changeThisLen, &afterChangeLen);
4093                     Bind(&changeThisLen);
4094                     {
4095                         thisArrLen = *newLen;
4096                         Jump(&afterChangeLen);
4097                     }
4098                     Bind(&afterChangeLen);
4099                     {
4100                         BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &retValueIsTrue, &loopEnd);
4101                         Bind(&retValueIsTrue);
4102                         {
4103                             result->WriteVariable(TaggedTrue());
4104                             Jump(exit);
4105                         }
4106                     }
4107                 }
4108             }
4109         }
4110         Bind(&loopEnd);
4111         i = Int64Add(*i, Int64(1));
4112         LoopEnd(&loopHead);
4113         Bind(&loopExit);
4114         result->WriteVariable(TaggedFalse());
4115         Jump(exit);
4116     }
4117 
4118     Bind(&thisNotStable);
4119     {
4120         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4121         Label loopHead(env);
4122         Label loopEnd(env);
4123         Label next(env);
4124         Label loopExit(env);
4125         Jump(&loopHead);
4126         LoopBegin(&loopHead);
4127         {
4128             Label hasProperty(env);
4129             Label hasException0(env);
4130             Label notHasException0(env);
4131             Label callDispatch(env);
4132             Label hasException1(env);
4133             Label notHasException1(env);
4134             BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
4135             Bind(&next);
4136             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
4137             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
4138             Bind(&hasProperty);
4139             {
4140                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4141                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4142                 Bind(&hasException0);
4143                 {
4144                     result->WriteVariable(Exception());
4145                     Jump(exit);
4146                 }
4147                 Bind(&notHasException0);
4148                 {
4149                     BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
4150                     Bind(&callDispatch);
4151                     {
4152                         GateRef key = Int64ToTaggedInt(*i);
4153                         JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4154                         callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4155                         CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
4156                             nullptr, Circuit::NullGate(), callArgs);
4157                         GateRef retValue = callBuilder.JSCallDispatch();
4158                         BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4159                         Bind(&hasException1);
4160                         {
4161                             result->WriteVariable(Exception());
4162                             Jump(exit);
4163                         }
4164                         Bind(&notHasException1);
4165                         {
4166                             Label retValueIsTrue(env);
4167                             BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &retValueIsTrue, &loopEnd);
4168                             Bind(&retValueIsTrue);
4169                             {
4170                                 result->WriteVariable(TaggedTrue());
4171                                 Jump(exit);
4172                             }
4173                         }
4174                     }
4175                 }
4176             }
4177         }
4178         Bind(&loopEnd);
4179         i = Int64Add(*i, Int64(1));
4180         LoopEnd(&loopHead);
4181         Bind(&loopExit);
4182         result->WriteVariable(TaggedFalse());
4183         Jump(exit);
4184     }
4185 #endif
4186 }
4187 
Every(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)4188 void BuiltinsArrayStubBuilder::Every(GateRef glue, GateRef thisValue, GateRef numArgs,
4189     Variable *result, Label *exit, Label *slowPath)
4190 {
4191 #if ENABLE_NEXT_OPTIMIZATION
4192     EveryOptimised(glue, thisValue, numArgs, result, exit, slowPath);
4193 #else
4194     auto env = GetEnvironment();
4195     Label thisExists(env);
4196     Label isHeapObject(env);
4197     Label isJsArray(env);
4198     Label isStability(env);
4199     Label notCOWArray(env);
4200     Label arg0HeapObject(env);
4201     Label callable(env);
4202     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
4203     Bind(&thisExists);
4204     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
4205     Bind(&isHeapObject);
4206     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
4207     Bind(&isJsArray);
4208     // don't check constructor, "Every" won't create new array.
4209     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
4210     Bind(&isStability);
4211     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
4212     Bind(&notCOWArray);
4213     GateRef callbackFnHandle = GetCallArg0(numArgs);
4214     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
4215     Bind(&arg0HeapObject);
4216     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
4217     Bind(&callable);
4218 
4219     Label thisIsStable(env);
4220     Label thisNotStable(env);
4221     GateRef argHandle = GetCallArg1(numArgs);
4222     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
4223     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
4224     Jump(&thisIsStable);
4225 
4226     Bind(&thisIsStable);
4227     {
4228         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4229         Label loopHead(env);
4230         Label loopEnd(env);
4231         Label next(env);
4232         Label loopExit(env);
4233         Jump(&loopHead);
4234         LoopBegin(&loopHead);
4235         {
4236             Label nextStep(env);
4237             Label kValueIsHole(env);
4238             Label callDispatch(env);
4239             Label hasProperty(env);
4240             Label hasException0(env);
4241             Label notHasException0(env);
4242             Label hasException1(env);
4243             Label notHasException1(env);
4244             BRANCH(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable);
4245             Bind(&nextStep);
4246             BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
4247             Bind(&next);
4248             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
4249             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
4250             Bind(&kValueIsHole);
4251             {
4252                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
4253                 BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
4254                 Bind(&hasProperty);
4255                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4256                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4257                 Bind(&hasException0);
4258                 {
4259                     result->WriteVariable(Exception());
4260                     Jump(exit);
4261                 }
4262                 Bind(&notHasException0);
4263                 BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
4264             }
4265             Bind(&callDispatch);
4266             {
4267                 GateRef key = Int64ToTaggedInt(*i);
4268                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4269                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4270                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
4271                     Circuit::NullGate(), callArgs);
4272                 GateRef retValue = callBuilder.JSCallDispatch();
4273                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4274                 Bind(&hasException1);
4275                 {
4276                     result->WriteVariable(Exception());
4277                     Jump(exit);
4278                 }
4279                 Bind(&notHasException1);
4280                 {
4281                     DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
4282                     Label changeThisLen(env);
4283                     Label afterChangeLen(env);
4284                     Label retValueIsFalse(env);
4285                     BRANCH(Int64LessThan(*newLen, *thisArrLen), &changeThisLen, &afterChangeLen);
4286                     Bind(&changeThisLen);
4287                     {
4288                         thisArrLen = *newLen;
4289                         Jump(&afterChangeLen);
4290                     }
4291                     Bind(&afterChangeLen);
4292                     {
4293                         BRANCH(TaggedIsFalse(FastToBoolean(retValue)), &retValueIsFalse, &loopEnd);
4294                         Bind(&retValueIsFalse);
4295                         result->WriteVariable(TaggedFalse());
4296                         Jump(exit);
4297                     }
4298                 }
4299             }
4300         }
4301         Bind(&loopEnd);
4302         i = Int64Add(*i, Int64(1));
4303         LoopEnd(&loopHead);
4304         Bind(&loopExit);
4305         result->WriteVariable(TaggedTrue());
4306         Jump(exit);
4307     }
4308 
4309     Bind(&thisNotStable);
4310     {
4311         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4312         Label loopHead(env);
4313         Label loopEnd(env);
4314         Label next(env);
4315         Label loopExit(env);
4316         Jump(&loopHead);
4317         LoopBegin(&loopHead);
4318         {
4319             Label hasProperty(env);
4320             Label hasException0(env);
4321             Label notHasException0(env);
4322             Label callDispatch(env);
4323             Label hasException1(env);
4324             Label notHasException1(env);
4325             BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
4326             Bind(&next);
4327             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
4328             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
4329             Bind(&hasProperty);
4330             kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4331             BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4332             Bind(&hasException0);
4333             {
4334                 result->WriteVariable(Exception());
4335                 Jump(exit);
4336             }
4337             Bind(&notHasException0);
4338             {
4339                 BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
4340                 Bind(&callDispatch);
4341                 GateRef key = Int64ToTaggedInt(*i);
4342                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4343                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4344                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
4345                     Circuit::NullGate(), callArgs);
4346                 GateRef retValue = callBuilder.JSCallDispatch();
4347                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4348                 Bind(&hasException1);
4349                 {
4350                     result->WriteVariable(Exception());
4351                     Jump(exit);
4352                 }
4353                 Bind(&notHasException1);
4354                 {
4355                     Label retValueIsFalse(env);
4356                     BRANCH(TaggedIsFalse(FastToBoolean(retValue)), &retValueIsFalse, &loopEnd);
4357                     Bind(&retValueIsFalse);
4358                     result->WriteVariable(TaggedFalse());
4359                     Jump(exit);
4360                 }
4361             }
4362         }
4363         Bind(&loopEnd);
4364         i = Int64Add(*i, Int64(1));
4365         LoopEnd(&loopHead);
4366         Bind(&loopExit);
4367         result->WriteVariable(TaggedTrue());
4368         Jump(exit);
4369     }
4370 #endif
4371 }
4372 
ReduceRight(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)4373 void BuiltinsArrayStubBuilder::ReduceRight(GateRef glue, GateRef thisValue, GateRef numArgs,
4374     Variable *result, Label *exit, Label *slowPath)
4375 {
4376     auto env = GetEnvironment();
4377     Label thisExists(env);
4378     Label isHeapObject(env);
4379     Label isJsArray(env);
4380     Label notCOWArray(env);
4381     Label equalCls(env);
4382     Label isGeneric(env);
4383     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
4384     Bind(&thisExists);
4385     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
4386     Bind(&isHeapObject);
4387     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
4388     // don't check constructor, "ReduceRight" won't create new array.
4389     Bind(&isJsArray);
4390     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
4391     Bind(&notCOWArray);
4392     DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0));
4393     DEFVARIABLE(accumulator, VariableType::JS_ANY(), Undefined());
4394     DEFVARIABLE(k, VariableType::INT32(), Int32(0));
4395     Label atLeastOneArg(env);
4396     Label callbackFnHandleHeapObject(env);
4397     Label callbackFnHandleCallable(env);
4398     Label updateAccumulator(env);
4399     Label thisIsStable(env);
4400     Label thisNotStable(env);
4401     thisLen = GetArrayLength(thisValue);
4402     BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
4403     Bind(&atLeastOneArg);
4404     GateRef callbackFnHandle = GetCallArg0(numArgs);
4405     BRANCH(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath);
4406     Bind(&callbackFnHandleHeapObject);
4407     BRANCH(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath);
4408     Bind(&callbackFnHandleCallable);
4409     GateRef numArgsLessThanTwo = Int64LessThan(numArgs, IntPtr(2));                 // 2: callbackFn initialValue
4410     k = Int32Sub(*thisLen, Int32(1));
4411     BRANCH(numArgsLessThanTwo, slowPath, &updateAccumulator);           // 2: callbackFn initialValue
4412     Bind(&updateAccumulator);
4413     accumulator = GetCallArg1(numArgs);
4414     BRANCH(IsStableJSArray(glue, thisValue), &thisIsStable, &thisNotStable);
4415 
4416     Bind(&thisIsStable);
4417     {
4418         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4419         GateRef argsLength = Int32(4);
4420         NewObjectStubBuilder newBuilder(this);
4421         GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
4422         Label loopHead(env);
4423         Label next(env);
4424         Label loopEnd(env);
4425         Label loopExit(env);
4426         Jump(&loopHead);
4427         LoopBegin(&loopHead);
4428         {
4429             Label nextStep(env);
4430             Label kValueIsHole(env);
4431             Label callDispatch(env);
4432             Label hasProperty(env);
4433             Label hasException0(env);
4434             Label notHasException0(env);
4435             Label hasException1(env);
4436             Label notHasException1(env);
4437             GateRef thisLenVal = *thisLen;
4438             BRANCH(LogicAndBuilder(env).And(IsStableJSArray(glue, thisValue))
4439                 .And(Int32Equal(thisLenVal, GetArrayLength(thisValue))).Done(),
4440                 &nextStep, &thisNotStable);
4441             Bind(&nextStep);
4442             BRANCH(Int32GreaterThanOrEqual(*k, Int32(0)), &next, &loopExit);
4443             Bind(&next);
4444             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *k);
4445             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
4446             Bind(&kValueIsHole);
4447             {
4448 #if ENABLE_NEXT_OPTIMIZATION
4449                 GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
4450                                                  { glue, thisValue, IntToTaggedPtr(*k) });
4451 #else
4452                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*k)});
4453 #endif
4454                 BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
4455                 Bind(&hasProperty);
4456                 kValue = FastGetPropertyByIndex(glue, thisValue, *k, ProfileOperation());
4457                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4458                 Bind(&hasException0);
4459                 result->WriteVariable(Exception());
4460                 Jump(exit);
4461                 Bind(&notHasException0);
4462                 BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
4463             }
4464             Bind(&callDispatch);
4465             {
4466                 // callback param 0: accumulator
4467                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
4468                 // callback param 1: currentValue
4469                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), *kValue);
4470                 // callback param 2: index
4471                 SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
4472                 // callback param 3: array
4473                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
4474                 GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
4475                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
4476                 callArgs.callThisArgvWithReturnArgs = { argsLength, argv, Undefined() };
4477                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, argsLength, 0, nullptr, Circuit::NullGate(),
4478                     callArgs);
4479                 GateRef callResult = callBuilder.JSCallDispatch();
4480                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4481                 Bind(&hasException1);
4482                 {
4483                     result->WriteVariable(Exception());
4484                     Jump(exit);
4485                 }
4486 
4487                 Bind(&notHasException1);
4488                 {
4489                     accumulator = callResult;
4490                     Jump(&loopEnd);
4491                 }
4492             }
4493         }
4494         Bind(&loopEnd);
4495         k = Int32Sub(*k, Int32(1));
4496         LoopEnd(&loopHead);
4497         Bind(&loopExit);
4498         result->WriteVariable(*accumulator);
4499         Jump(exit);
4500     }
4501 
4502     Bind(&thisNotStable);
4503     {
4504         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4505         GateRef argsLength = Int32(4);
4506         NewObjectStubBuilder newBuilder(this);
4507         GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
4508         Label loopHead(env);
4509         Label next(env);
4510         Label loopEnd(env);
4511         Label loopExit(env);
4512         Jump(&loopHead);
4513         LoopBegin(&loopHead);
4514         {
4515             Label hasProperty(env);
4516             Label hasException0(env);
4517             Label notHasException0(env);
4518             Label callDispatch(env);
4519             Label hasException1(env);
4520             Label notHasException1(env);
4521             BRANCH(Int32GreaterThanOrEqual(*k, Int32(0)), &next, &loopExit);
4522             Bind(&next);
4523 #if ENABLE_NEXT_OPTIMIZATION
4524             GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
4525                                              { glue, thisValue, IntToTaggedPtr(*k) });
4526 #else
4527             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*k)});
4528 #endif
4529             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
4530             Bind(&hasProperty);
4531             kValue = FastGetPropertyByIndex(glue, thisValue, *k, ProfileOperation());
4532             BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4533             Bind(&hasException0);
4534             result->WriteVariable(Exception());
4535             Jump(exit);
4536             Bind(&notHasException0);
4537             BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
4538             Bind(&callDispatch);
4539             {
4540                 // callback param 0: accumulator
4541                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
4542                 // callback param 1: currentValue
4543                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), *kValue);
4544                 // callback param 2: index
4545                 SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
4546                 // callback param 3: array
4547                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
4548                 GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
4549                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARGV_WITH_RETURN);
4550                 callArgs.callThisArgvWithReturnArgs = { argsLength, argv, Undefined() };
4551                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, argsLength, 0, nullptr, Circuit::NullGate(),
4552                     callArgs);
4553                 GateRef callResult = callBuilder.JSCallDispatch();
4554                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4555                 Bind(&hasException1);
4556                 {
4557                     result->WriteVariable(Exception());
4558                     Jump(exit);
4559                 }
4560 
4561                 Bind(&notHasException1);
4562                 {
4563                     accumulator = callResult;
4564                     Jump(&loopEnd);
4565                 }
4566             }
4567         }
4568         Bind(&loopEnd);
4569         k = Int32Sub(*k, Int32(1));
4570         LoopEnd(&loopHead);
4571         Bind(&loopExit);
4572         result->WriteVariable(*accumulator);
4573         Jump(exit);
4574     }
4575 }
4576 
FindLastIndex(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)4577 void BuiltinsArrayStubBuilder::FindLastIndex(GateRef glue, GateRef thisValue, GateRef numArgs,
4578     Variable *result, Label *exit, Label *slowPath)
4579 {
4580     auto env = GetEnvironment();
4581     Label thisExists(env);
4582     Label isHeapObject(env);
4583     Label isJsArray(env);
4584     Label notCOWArray(env);
4585     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
4586     Bind(&thisExists);
4587     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
4588     Bind(&isHeapObject);
4589     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
4590     // don't check constructor, "FindLastIndex" won't create new array.
4591     Bind(&isJsArray);
4592     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
4593     Bind(&notCOWArray);
4594     Label arg0HeapObject(env);
4595     Label callable(env);
4596     Label thisIsStable(env);
4597     Label thisNotStable(env);
4598     GateRef callbackFnHandle = GetCallArg0(numArgs);
4599     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
4600     Bind(&arg0HeapObject);
4601     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
4602     Bind(&callable);
4603     GateRef argHandle = GetCallArg1(numArgs);
4604 
4605     DEFVARIABLE(i, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(GetArrayLength(thisValue)), Int64(1)));
4606     BRANCH(IsStableJSArray(glue, thisValue), &thisIsStable, &thisNotStable);
4607 
4608     Bind(&thisIsStable);
4609     {
4610         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4611         Label loopHead(env);
4612         Label loopEnd(env);
4613         Label next(env);
4614         Label loopExit(env);
4615         Jump(&loopHead);
4616         LoopBegin(&loopHead);
4617         {
4618             Label nextStep(env);
4619             Label kValueIsHole(env);
4620             Label callDispatch(env);
4621             Label hasProperty(env);
4622             Label hasException0(env);
4623             Label notHasException0(env);
4624             Label useUndefined(env);
4625             Label hasException1(env);
4626             Label notHasException1(env);
4627             BRANCH(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable);
4628             Bind(&nextStep);
4629             BRANCH(Int64LessThan(*i, Int64(0)), &loopExit, &next);
4630             Bind(&next);
4631             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
4632             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
4633             Bind(&kValueIsHole);
4634             {
4635 #if ENABLE_NEXT_OPTIMIZATION
4636                 GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
4637                                                  { glue, thisValue, IntToTaggedPtr(*i) });
4638 #else
4639                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*i)});
4640 #endif
4641                 BRANCH(TaggedIsTrue(hasProp), &hasProperty, &useUndefined);
4642                 Bind(&hasProperty);
4643                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4644                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4645                 Bind(&hasException0);
4646                 {
4647                     result->WriteVariable(Exception());
4648                     Jump(exit);
4649                 }
4650                 Bind(&notHasException0);
4651                 {
4652                     BRANCH(TaggedIsHole(*kValue), &useUndefined, &callDispatch);
4653                     Bind(&useUndefined);
4654                     kValue = Undefined();
4655                     Jump(&callDispatch);
4656                 }
4657             }
4658             Bind(&callDispatch);
4659             {
4660                 GateRef key = Int64ToTaggedInt(*i);
4661                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4662                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4663                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
4664                     Circuit::NullGate(), callArgs);
4665                 GateRef retValue = callBuilder.JSCallDispatch();
4666                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4667                 Bind(&hasException1);
4668                 {
4669                     result->WriteVariable(Exception());
4670                     Jump(exit);
4671                 }
4672 
4673                 Bind(&notHasException1);
4674                 {
4675                     DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
4676                     Label checkRetValue(env);
4677                     Label find(env);
4678                     BRANCH(Int64LessThan(*newLen, Int64Add(*i, Int64(1))), &thisNotStable, &checkRetValue);
4679                     Bind(&checkRetValue);
4680                     BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
4681                     Bind(&find);
4682                     result->WriteVariable(IntToTaggedPtr(*i));
4683                     Jump(exit);
4684                 }
4685             }
4686         }
4687         Bind(&loopEnd);
4688         i = Int64Sub(*i, Int64(1));
4689         LoopEnd(&loopHead);
4690         Bind(&loopExit);
4691         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
4692         Jump(exit);
4693     }
4694 
4695     Bind(&thisNotStable);
4696     {
4697         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4698         Label loopHead(env);
4699         Label loopEnd(env);
4700         Label next(env);
4701         Label loopExit(env);
4702         Jump(&loopHead);
4703         LoopBegin(&loopHead);
4704         {
4705             Label hasProperty(env);
4706             Label hasException0(env);
4707             Label notHasException0(env);
4708             Label useUndefined(env);
4709             Label callDispatch(env);
4710             Label hasException1(env);
4711             Label notHasException1(env);
4712             BRANCH(Int64LessThan(*i, Int64(0)), &loopExit, &next);
4713             Bind(&next);
4714 #if ENABLE_NEXT_OPTIMIZATION
4715             GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
4716                                              { glue, thisValue, IntToTaggedPtr(*i) });
4717 #else
4718             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*i)});
4719 #endif
4720             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &useUndefined);
4721             Bind(&hasProperty);
4722             kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4723             BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4724             Bind(&hasException0);
4725             {
4726                 result->WriteVariable(Exception());
4727                 Jump(exit);
4728             }
4729             Bind(&notHasException0);
4730             {
4731                 BRANCH(TaggedIsHole(*kValue), &useUndefined, &callDispatch);
4732                 Bind(&useUndefined);
4733                 kValue = Undefined();
4734                 Jump(&callDispatch);
4735                 Bind(&callDispatch);
4736                 GateRef key = Int64ToTaggedInt(*i);
4737                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4738                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4739                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
4740                     Circuit::NullGate(), callArgs);
4741                 GateRef retValue = callBuilder.JSCallDispatch();
4742                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4743                 Bind(&hasException1);
4744                 {
4745                     result->WriteVariable(Exception());
4746                     Jump(exit);
4747                 }
4748 
4749                 Bind(&notHasException1);
4750                 {
4751                     Label find(env);
4752                     BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
4753                     Bind(&find);
4754                     result->WriteVariable(IntToTaggedPtr(*i));
4755                     Jump(exit);
4756                 }
4757             }
4758         }
4759         Bind(&loopEnd);
4760         i = Int64Sub(*i, Int64(1));
4761         LoopEnd(&loopHead);
4762         Bind(&loopExit);
4763         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
4764         Jump(exit);
4765     }
4766 }
4767 
FindLast(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)4768 void BuiltinsArrayStubBuilder::FindLast(GateRef glue, GateRef thisValue, GateRef numArgs,
4769     Variable *result, Label *exit, Label *slowPath)
4770 {
4771     auto env = GetEnvironment();
4772     Label thisExists(env);
4773     Label isHeapObject(env);
4774     Label isJsArray(env);
4775     Label notCOWArray(env);
4776     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
4777     Bind(&thisExists);
4778     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
4779     Bind(&isHeapObject);
4780     BRANCH(IsJsArray(thisValue), &isJsArray, slowPath);
4781     Bind(&isJsArray);
4782     // don't check constructor, "FindLast" won't create new array.
4783     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
4784     Bind(&notCOWArray);
4785     Label arg0HeapObject(env);
4786     Label callable(env);
4787     Label thisIsStable(env);
4788     Label thisNotStable(env);
4789     GateRef callbackFnHandle = GetCallArg0(numArgs);
4790     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
4791     Bind(&arg0HeapObject);
4792     BRANCH(IsCallable(callbackFnHandle), &callable, slowPath);
4793     Bind(&callable);
4794     GateRef argHandle = GetCallArg1(numArgs);
4795 
4796     DEFVARIABLE(i, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(GetArrayLength(thisValue)), Int64(1)));
4797     BRANCH(IsStableJSArray(glue, thisValue), &thisIsStable, &thisNotStable);
4798 
4799     Bind(&thisIsStable);
4800     {
4801         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4802         Label loopHead(env);
4803         Label loopEnd(env);
4804         Label next(env);
4805         Label loopExit(env);
4806         Jump(&loopHead);
4807         LoopBegin(&loopHead);
4808         {
4809             Label nextStep(env);
4810             Label kValueIsHole(env);
4811             Label callDispatch(env);
4812             Label hasProperty(env);
4813             Label hasException0(env);
4814             Label notHasException0(env);
4815             Label useUndefined(env);
4816             Label hasException1(env);
4817             Label notHasException1(env);
4818             BRANCH(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable);
4819             Bind(&nextStep);
4820             BRANCH(Int64LessThan(*i, Int64(0)), &loopExit, &next);
4821             Bind(&next);
4822             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
4823             BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
4824             Bind(&kValueIsHole);
4825             {
4826 #if ENABLE_NEXT_OPTIMIZATION
4827                 GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
4828                                                  { glue, thisValue, IntToTaggedPtr(*i) });
4829 #else
4830                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*i)});
4831 #endif
4832                 BRANCH(TaggedIsTrue(hasProp), &hasProperty, &useUndefined);
4833                 Bind(&hasProperty);
4834                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4835                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4836                 Bind(&hasException0);
4837                 {
4838                     result->WriteVariable(Exception());
4839                     Jump(exit);
4840                 }
4841                 Bind(&notHasException0);
4842                 {
4843                     BRANCH(TaggedIsHole(*kValue), &useUndefined, &callDispatch);
4844                     Bind(&useUndefined);
4845                     kValue = Undefined();
4846                     Jump(&callDispatch);
4847                 }
4848             }
4849             Bind(&callDispatch);
4850             {
4851                 GateRef key = Int64ToTaggedInt(*i);
4852                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4853                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4854                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
4855                     Circuit::NullGate(), callArgs);
4856                 GateRef retValue = callBuilder.JSCallDispatch();
4857                 BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4858                 Bind(&hasException1);
4859                 {
4860                     result->WriteVariable(Exception());
4861                     Jump(exit);
4862                 }
4863 
4864                 Bind(&notHasException1);
4865                 {
4866                     DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
4867                     Label checkRetValue(env);
4868                     Label find(env);
4869                     BRANCH(Int64LessThan(*newLen, Int64Add(*i, Int64(1))), &thisNotStable, &checkRetValue);
4870                     Bind(&checkRetValue);
4871                     BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
4872                     Bind(&find);
4873                     result->WriteVariable(*kValue);
4874                     Jump(exit);
4875                 }
4876             }
4877         }
4878         Bind(&loopEnd);
4879         i = Int64Sub(*i, Int64(1));
4880         LoopEnd(&loopHead);
4881         Bind(&loopExit);
4882         Jump(exit);
4883     }
4884 
4885     Bind(&thisNotStable);
4886     {
4887         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
4888         Label loopHead(env);
4889         Label loopEnd(env);
4890         Label next(env);
4891         Label loopExit(env);
4892         Jump(&loopHead);
4893         LoopBegin(&loopHead);
4894         {
4895             Label hasProperty(env);
4896             Label hasException0(env);
4897             Label notHasException0(env);
4898             Label useUndefined(env);
4899             Label callDispatch(env);
4900             Label hasException1(env);
4901             Label notHasException1(env);
4902             BRANCH(Int64LessThan(*i, Int64(0)), &loopExit, &next);
4903             Bind(&next);
4904 #if ENABLE_NEXT_OPTIMIZATION
4905             GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
4906                                              { glue, thisValue, IntToTaggedPtr(*i) });
4907 #else
4908             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*i)});
4909 #endif
4910             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &useUndefined);
4911             Bind(&hasProperty);
4912             kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
4913             BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
4914             Bind(&hasException0);
4915             {
4916                 result->WriteVariable(Exception());
4917                 Jump(exit);
4918             }
4919             Bind(&notHasException0);
4920             {
4921                 BRANCH(TaggedIsHole(*kValue), &useUndefined, &callDispatch);
4922                 Bind(&useUndefined);
4923                 {
4924                     kValue = Undefined();
4925                     Jump(&callDispatch);
4926                 }
4927                 Bind(&callDispatch);
4928                 {
4929                     GateRef key = Int64ToTaggedInt(*i);
4930                     JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
4931                     callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
4932                     CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
4933                         nullptr, Circuit::NullGate(), callArgs);
4934                     GateRef retValue = callBuilder.JSCallDispatch();
4935                     BRANCH(HasPendingException(glue), &hasException1, &notHasException1);
4936                     Bind(&hasException1);
4937                     {
4938                         result->WriteVariable(Exception());
4939                         Jump(exit);
4940                     }
4941 
4942                     Bind(&notHasException1);
4943                     {
4944                         Label find(env);
4945                         BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
4946                         Bind(&find);
4947                         result->WriteVariable(*kValue);
4948                         Jump(exit);
4949                     }
4950                 }
4951             }
4952         }
4953         Bind(&loopEnd);
4954         i = Int64Sub(*i, Int64(1));
4955         LoopEnd(&loopHead);
4956         Bind(&loopExit);
4957         Jump(exit);
4958     }
4959 }
4960 
FastCreateArrayWithArgv(GateRef glue,Variable * res,GateRef argc,GateRef hclass,Label * exit)4961 void BuiltinsArrayStubBuilder::FastCreateArrayWithArgv(GateRef glue, Variable *res, GateRef argc,
4962                                                        GateRef hclass, Label *exit)
4963 {
4964     auto env = GetEnvironment();
4965     NewObjectStubBuilder newBuilder(this);
4966     newBuilder.SetParameters(glue, 0);
4967 
4968     // create elements from argv
4969     GateRef len = TruncInt64ToInt32(argc);
4970     GateRef elements = newBuilder.NewTaggedArray(glue, len);
4971 
4972     // set value
4973     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
4974     DEFVARIABLE(newHClass, VariableType::JS_ANY(), hclass);
4975     DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
4976 #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC
4977     DEFVARIABLE(elementKind, VariableType::INT32(), Int32(Elements::ToUint(ElementsKind::NONE)));
4978 #else
4979     DEFVARIABLE(elementKind, VariableType::INT32(), Int32(Elements::ToUint(ElementsKind::NONE)));
4980 #endif
4981     Label loopHead(env);
4982     Label loopEnd(env);
4983     Label setValue(env);
4984     Label loopExit(env);
4985     Jump(&loopHead);
4986     LoopBegin(&loopHead);
4987     {
4988         BRANCH(Int64LessThan(*i, argc), &setValue, &loopExit);
4989         Bind(&setValue);
4990         Label isHole(env);
4991         Label notHole(env);
4992         value = GetArgFromArgv(*i);
4993         BRANCH(TaggedIsHole(*value), &isHole, &notHole);
4994         Bind(&isHole);
4995         value = TaggedUndefined();
4996         Jump(&notHole);
4997         Bind(&notHole);
4998         elementKind = Int32Or(TaggedToElementKind(*value), *elementKind);
4999         SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, *i, *value);
5000         i = Int64Add(*i, Int64(1));
5001         Jump(&loopEnd);
5002     }
5003     Bind(&loopEnd);
5004     LoopEnd(&loopHead);
5005     Bind(&loopExit);
5006     GateRef noneHClass = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ELEMENT_NONE_HCLASS_INDEX);
5007     Label useElementsKindHClass(env);
5008     Label createArray(env);
5009     GateRef newHClassVal = *newHClass;
5010     // if the newHClass is not noneHClass, means the elementskind is not enable or "Array" is modified, then do not use
5011     // specific hclass for elementskind.
5012     BRANCH_LIKELY(Equal(newHClassVal, noneHClass), &useElementsKindHClass, &createArray);
5013     Bind(&useElementsKindHClass);
5014     {
5015         // elementKind may be an invalid kind, but use it to index the hclass is supported.
5016         newHClass = GetElementsKindHClass(glue, *elementKind);
5017         Jump(&createArray);
5018     }
5019     Bind(&createArray);
5020     // create array object
5021     GateRef arr = newBuilder.NewJSObject(glue, *newHClass);
5022     res->WriteVariable(arr);
5023     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
5024     Store(VariableType::INT32(), glue, arr, lengthOffset, len);
5025     GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
5026     Store(VariableType::JS_ANY(), glue, arr,
5027           IntPtr(JSArray::GetInlinedPropertyOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX)), accessor);
5028     SetExtensibleToBitfield(glue, arr, true);
5029     SetElementsArray(VariableType::JS_POINTER(), glue, arr, elements);
5030     Jump(exit);
5031 }
5032 
GenArrayConstructor(GateRef glue,GateRef nativeCode,GateRef func,GateRef newTarget,GateRef thisValue,GateRef numArgs)5033 void BuiltinsArrayStubBuilder::GenArrayConstructor(GateRef glue, GateRef nativeCode,
5034     GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs)
5035 {
5036     auto env = GetEnvironment();
5037     DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
5038 
5039     Label newTargetIsHeapObject(env);
5040     Label newTargetIsJSFunction(env);
5041     Label slowPath(env);
5042     Label slowPath1(env);
5043     Label exit(env);
5044 
5045     BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath);
5046     Bind(&newTargetIsHeapObject);
5047     BRANCH(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath);
5048     Bind(&newTargetIsJSFunction);
5049     {
5050         Label fastGetHclass(env);
5051         Label intialHClassIsHClass(env);
5052         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
5053         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
5054         auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
5055         BRANCH(Equal(arrayFunc, newTarget), &fastGetHclass, &slowPath1);
5056         Bind(&fastGetHclass);
5057         GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
5058         DEFVARIABLE(arrayLength, VariableType::INT64(), Int64(0));
5059         BRANCH(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath1);
5060         Bind(&intialHClassIsHClass);
5061         {
5062             Label noArg(env);
5063             Label hasArg(env);
5064             Label arrayCreate(env);
5065             BRANCH(Int64Equal(numArgs, IntPtr(0)), &noArg, &hasArg);
5066             Bind(&noArg);
5067             {
5068                 Jump(&arrayCreate);
5069             }
5070             Bind(&hasArg);
5071             {
5072                 Label hasOneArg(env);
5073                 Label multiArg(env);
5074                 BRANCH(Int64Equal(numArgs, IntPtr(1)), &hasOneArg, &multiArg);
5075                 Bind(&hasOneArg);
5076                 {
5077                     Label argIsNumber(env);
5078                     GateRef arg0 = GetArgFromArgv(IntPtr(0), numArgs, true);
5079                     BRANCH(TaggedIsNumber(arg0), &argIsNumber, &slowPath);
5080                     Bind(&argIsNumber);
5081                     {
5082                         Label argIsInt(env);
5083                         Label argIsDouble(env);
5084                         BRANCH(TaggedIsInt(arg0), &argIsInt, &argIsDouble);
5085                         Bind(&argIsInt);
5086                         {
5087                             Label validIntLength(env);
5088                             GateRef intLen = GetInt64OfTInt(arg0);
5089                             GateRef isGEZero = Int64GreaterThanOrEqual(intLen, Int64(0));
5090                             GateRef isLEMaxLen = Int64LessThanOrEqual(intLen, Int64(JSArray::MAX_ARRAY_INDEX));
5091                             BRANCH(BitAnd(isGEZero, isLEMaxLen), &validIntLength, &slowPath);
5092                             Bind(&validIntLength);
5093                             {
5094                                 arrayLength = intLen;
5095                                 Jump(&arrayCreate);
5096                             }
5097                         }
5098                         Bind(&argIsDouble);
5099                         {
5100                             Label validDoubleLength(env);
5101                             GateRef doubleLength = GetDoubleOfTDouble(arg0);
5102                             GateRef doubleToInt = DoubleToInt(glue, doubleLength);
5103                             GateRef intToDouble = CastInt64ToFloat64(SExtInt32ToInt64(doubleToInt));
5104                             GateRef doubleEqual = DoubleEqual(doubleLength, intToDouble);
5105                             GateRef doubleLEMaxLen =
5106                                 DoubleLessThanOrEqual(doubleLength, Double(JSArray::MAX_ARRAY_INDEX));
5107                             BRANCH(BitAnd(doubleEqual, doubleLEMaxLen), &validDoubleLength, &slowPath);
5108                             Bind(&validDoubleLength);
5109                             {
5110                                 arrayLength = SExtInt32ToInt64(doubleToInt);
5111                                 Jump(&arrayCreate);
5112                             }
5113                         }
5114                     }
5115                 }
5116                 Bind(&multiArg);
5117                 {
5118                     Label lengthValid(env);
5119                     BRANCH(Int64LessThan(numArgs, IntPtr(JSObject::MAX_GAP)), &lengthValid, &slowPath);
5120                     Bind(&lengthValid);
5121                     {
5122                         FastCreateArrayWithArgv(glue, &res, numArgs, intialHClass, &exit);
5123                     }
5124                 }
5125             }
5126             Bind(&arrayCreate);
5127             {
5128                 Label lengthValid(env);
5129                 BRANCH(Int64GreaterThan(*arrayLength, Int64(JSObject::MAX_GAP)), &slowPath, &lengthValid);
5130                 Bind(&lengthValid);
5131                 {
5132                     NewObjectStubBuilder newBuilder(this);
5133                     newBuilder.SetParameters(glue, 0);
5134                     res = newBuilder.NewJSArrayWithSize(intialHClass, *arrayLength);
5135                     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
5136                     Store(VariableType::INT32(), glue, *res, lengthOffset, TruncInt64ToInt32(*arrayLength));
5137                     GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
5138                                                               ConstantIndex::ARRAY_LENGTH_ACCESSOR);
5139                     Store(VariableType::JS_ANY(), glue, *res,
5140                           IntPtr(JSArray::GetInlinedPropertyOffset(JSArray::LENGTH_INLINE_PROPERTY_INDEX)), accessor);
5141                     SetExtensibleToBitfield(glue, *res, true);
5142                     Jump(&exit);
5143                 }
5144             }
5145         }
5146         Bind(&slowPath1);
5147         {
5148             GateRef argv = GetArgv();
5149             res = CallBuiltinRuntimeWithNewTarget(glue,
5150                 { glue, nativeCode, func, thisValue, numArgs, argv, newTarget });
5151             Jump(&exit);
5152         }
5153     }
5154     Bind(&slowPath);
5155     {
5156         GateRef argv = GetArgv();
5157         res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true);
5158         Jump(&exit);
5159     }
5160 
5161     Bind(&exit);
5162     Return(*res);
5163 }
5164 
FlatMap(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)5165 void BuiltinsArrayStubBuilder::FlatMap(GateRef glue, GateRef thisValue, GateRef numArgs,
5166     Variable *result, Label *exit, Label *slowPath)
5167 {
5168     auto env = GetEnvironment();
5169     Label isHeapObject(env);
5170     Label isJsArray(env);
5171     Label defaultConstr(env);
5172     Label isStability(env);
5173     Label notCOWArray(env);
5174     Label equalCls(env);
5175     Label isGeneric(env);
5176     BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
5177     Bind(&isHeapObject);
5178     BRANCH_LIKELY(IsJsArray(thisValue), &isJsArray, slowPath);
5179     Bind(&isJsArray);
5180     // need check constructor, "FlatMap" should use ArraySpeciesCreate
5181     BRANCH_UNLIKELY(HasConstructor(thisValue), slowPath, &defaultConstr);
5182     Bind(&defaultConstr);
5183     BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &isStability, slowPath);
5184     Bind(&isStability);
5185     BRANCH(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
5186     Bind(&notCOWArray);
5187     Label arg0HeapObject(env);
5188     Label callable(env);
5189     Label thisNotStable(env);
5190     Label doFlat(env);
5191     GateRef callbackFnHandle = GetCallArg0(numArgs);
5192     BRANCH_LIKELY(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
5193     Bind(&arg0HeapObject);
5194     BRANCH_LIKELY(IsCallable(callbackFnHandle), &callable, slowPath);
5195     Bind(&callable);
5196     GateRef argHandle = GetCallArg1(numArgs);
5197 
5198     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
5199     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
5200     DEFVARIABLE(newArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
5201     GateRef mappedArray = NewArray(glue, *thisArrLen);
5202     GateRef mappedElements = GetElementsArray(mappedArray);
5203     // fast path for stable array
5204     {
5205         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
5206         Label loopHead(env);
5207         Label loopEnd(env);
5208         Label next(env);
5209         Label loopExit(env);
5210         Jump(&loopHead);
5211         LoopBegin(&loopHead);
5212         {
5213             Label nextStep(env);
5214             Label kValueIsHole(env);
5215             Label callDispatch(env);
5216             Label hasProperty(env);
5217             Label changeNewArrLen(env);
5218             Label hasException0(env);
5219             Label notHasException0(env);
5220             Label hasException1(env);
5221             Label notHasException1(env);
5222             BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable);
5223             Bind(&nextStep);
5224             BRANCH_LIKELY(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
5225             Bind(&next);
5226             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
5227             BRANCH_UNLIKELY(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch);
5228             Bind(&kValueIsHole);
5229             {
5230                 newArrLen = Int64Sub(*newArrLen, Int64(1));
5231                 Jump(&loopEnd);
5232             }
5233             Bind(&callDispatch);
5234             {
5235                 GateRef key = Int64ToTaggedInt(*i);
5236                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
5237                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
5238                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
5239                     Circuit::NullGate(), callArgs, ProfileOperation(), false);
5240                 GateRef retValue = callBuilder.JSCallDispatch();
5241                 BRANCH_UNLIKELY(HasPendingException(glue), &hasException1, &notHasException1);
5242                 Bind(&hasException1);
5243                 {
5244                     result->WriteVariable(Exception());
5245                     Jump(exit);
5246                 }
5247                 Bind(&notHasException1);
5248                 {
5249                     DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
5250                     Label changeThisLen(env);
5251                     Label afterChangeLen(env);
5252                     Label retValueIsHeapObject(env);
5253                     Label retValueIsJsArray(env);
5254                     BRANCH_UNLIKELY(Int64LessThan(*newLen, *thisArrLen), &changeThisLen, &afterChangeLen);
5255                     Bind(&changeThisLen);
5256                     {
5257                         newArrLen = Int64Sub(*newArrLen, Int64Sub(*thisArrLen, *newLen));
5258                         thisArrLen = *newLen;
5259                         Jump(&afterChangeLen);
5260                     }
5261                     Bind(&afterChangeLen);
5262                     {
5263                         SetValueToTaggedArray(VariableType::JS_ANY(), glue, mappedElements, *i, retValue);
5264                         BRANCH(TaggedIsHeapObject(retValue), &retValueIsHeapObject, &loopEnd);
5265                         Bind(&retValueIsHeapObject);
5266                         {
5267                             BRANCH_NO_WEIGHT(IsJsArray(retValue), &retValueIsJsArray, &loopEnd);
5268                         }
5269                         Bind(&retValueIsJsArray);
5270                         {
5271                             // newArray only contains non-hole elements
5272                             // but elementsLength is bigger than number of non-hole elements
5273                             // so should trim after flat
5274                             GateRef retElements = GetElementsArray(retValue);
5275                             GateRef elementsLength = GetLengthOfTaggedArray(retElements);
5276                             newArrLen = Int64Sub(Int64Add(*newArrLen, elementsLength), Int64(1));
5277                             Jump(&loopEnd);
5278                         }
5279                     }
5280                 }
5281             }
5282         }
5283         Bind(&loopEnd);
5284         i = Int64Add(*i, Int64(1));
5285         LoopEnd(&loopHead);
5286         Bind(&loopExit);
5287         Jump(&doFlat);
5288     }
5289 
5290     Bind(&thisNotStable);
5291     {
5292         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
5293         Label loopHead(env);
5294         Label loopEnd(env);
5295         Label next(env);
5296         Label loopExit(env);
5297         Jump(&loopHead);
5298         LoopBegin(&loopHead);
5299         {
5300             Label hasProperty(env);
5301             Label changeNewArrLen(env);
5302             Label hasException0(env);
5303             Label notHasException0(env);
5304             Label callDispatch(env);
5305             Label hasException1(env);
5306             Label notHasException1(env);
5307             BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
5308             Bind(&next);
5309             GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
5310             BRANCH(TaggedIsTrue(hasProp), &hasProperty, &changeNewArrLen);
5311             Bind(&hasProperty);
5312             {
5313                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
5314                 BRANCH(HasPendingException(glue), &hasException0, &notHasException0);
5315                 Bind(&hasException0);
5316                 {
5317                     result->WriteVariable(Exception());
5318                     Jump(exit);
5319                 }
5320                 Bind(&notHasException0);
5321                 {
5322                     BRANCH(TaggedIsHole(*kValue), &changeNewArrLen, &callDispatch);
5323                 }
5324             }
5325             Bind(&changeNewArrLen);
5326             {
5327                 newArrLen = Int64Sub(*newArrLen, Int64(1));
5328                 Jump(&loopEnd);
5329             }
5330             Bind(&callDispatch);
5331             {
5332                 GateRef key = Int64ToTaggedInt(*i);
5333                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
5334                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
5335                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
5336                     Circuit::NullGate(), callArgs);
5337                 GateRef retValue = callBuilder.JSCallDispatch();
5338                 BRANCH_UNLIKELY(HasPendingException(glue), &hasException1, &notHasException1);
5339                 Bind(&hasException1);
5340                 {
5341                     result->WriteVariable(Exception());
5342                     Jump(exit);
5343                 }
5344                 Bind(&notHasException1);
5345                 {
5346                     Label retValueIsHeapObject(env);
5347                     Label retValueIsJsArray(env);
5348                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, mappedElements, *i, retValue);
5349                     BRANCH(TaggedIsHeapObject(retValue), &retValueIsHeapObject, &loopEnd);
5350                     Bind(&retValueIsHeapObject);
5351                     {
5352                         BRANCH(IsJsArray(retValue), &retValueIsJsArray, &loopEnd);
5353                     }
5354                     Bind(&retValueIsJsArray);
5355                     {
5356                         // newArray only contains non-hole elements
5357                         // but elementsLength is bigger than number of non-hole elements
5358                         // so should trim after flat
5359                         GateRef retElements = GetElementsArray(retValue);
5360                         GateRef elementsLength = GetLengthOfTaggedArray(retElements);
5361                         newArrLen = Int64Sub(Int64Add(*newArrLen, elementsLength), Int64(1));
5362                         Jump(&loopEnd);
5363                     }
5364                 }
5365             }
5366         }
5367         Bind(&loopEnd);
5368         i = Int64Add(*i, Int64(1));
5369         LoopEnd(&loopHead);
5370         Bind(&loopExit);
5371         Jump(&doFlat);
5372     }
5373 
5374     Bind(&doFlat);
5375     {
5376         i = Int64(0);
5377         DEFVARIABLE(j, VariableType::INT64(), Int64(0));
5378         DEFVARIABLE(retValueItem, VariableType::JS_ANY(), Hole());
5379         GateRef newArray = NewArray(glue, *newArrLen);
5380         Label loopHead2(env);
5381         Label loopEnd2(env);
5382         Label next2(env);
5383         Label loopExit2(env);
5384         Jump(&loopHead2);
5385         LoopBegin(&loopHead2);
5386         {
5387             Label nextStep(env);
5388             Label retValueIsHeapObject(env);
5389             Label retValueIsJsArray(env);
5390             Label retValueIsNotJsArray(env);
5391             BRANCH_LIKELY(Int64LessThan(*i, *thisArrLen), &next2, &loopExit2);
5392             Bind(&next2);
5393             GateRef retValue = GetValueFromTaggedArray(mappedElements, *i);
5394             BRANCH(TaggedIsHole(retValue), &loopEnd2, &nextStep);
5395             Bind(&nextStep);
5396             BRANCH_NO_WEIGHT(TaggedIsHeapObject(retValue), &retValueIsHeapObject, &retValueIsNotJsArray);
5397             Bind(&retValueIsHeapObject);
5398             {
5399                 BRANCH_NO_WEIGHT(IsJsArray(retValue), &retValueIsJsArray, &retValueIsNotJsArray);
5400                 Bind(&retValueIsJsArray);
5401                 {
5402                     Label retValueIsStableArray(env);
5403                     Label retValueNotStableArray(env);
5404                     GateRef retValueIsStable = IsStableJSArray(glue, retValue);
5405                     GateRef arrLen = ZExtInt32ToInt64(GetArrayLength(retValue));
5406                     DEFVARIABLE(k, VariableType::INT64(), Int64(0));
5407                     Label loopHead3(env);
5408                     Label loopEnd3(env);
5409                     Label next3(env);
5410                     Label loopExit3(env);
5411                     Label setValue(env);
5412                     Label itemExist(env);
5413                     Jump(&loopHead3);
5414                     LoopBegin(&loopHead3);
5415                     {
5416                         BRANCH_LIKELY(Int64LessThan(*k, arrLen), &next3, &loopExit3);
5417                         Bind(&next3);
5418                         BRANCH_LIKELY(retValueIsStable, &retValueIsStableArray, &retValueNotStableArray);
5419                         Bind(&retValueIsStableArray);
5420                         retValueItem = GetTaggedValueWithElementsKind(glue, retValue, *k);
5421                         BRANCH_NO_WEIGHT(TaggedIsHole(*retValueItem), &loopEnd3, &setValue);
5422                         Bind(&retValueNotStableArray);
5423                         GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { retValue, IntToTaggedInt(*k) });
5424                         BRANCH_NO_WEIGHT(TaggedIsTrue(hasProp), &itemExist, &loopEnd3);
5425                         Bind(&itemExist);
5426                         retValueItem =
5427                             FastGetPropertyByIndex(glue, retValue, TruncInt64ToInt32(*k), ProfileOperation());
5428                         Jump(&setValue);
5429                         Bind(&setValue);
5430                         SetValueWithElementsKind(glue, newArray, *retValueItem, *j, Boolean(true),
5431                             Int32(Elements::ToUint(ElementsKind::NONE)));
5432                         j = Int64Add(*j, Int64(1));
5433                         Jump(&loopEnd3);
5434                     }
5435                     Bind(&loopEnd3);
5436                     k = Int64Add(*k, Int64(1));
5437                     LoopEnd(&loopHead3);
5438                     Bind(&loopExit3);
5439                     Jump(&loopEnd2);
5440                 }
5441             }
5442             Bind(&retValueIsNotJsArray);
5443             {
5444                 SetValueWithElementsKind(glue, newArray, retValue, *j, Boolean(true),
5445                     Int32(Elements::ToUint(ElementsKind::NONE)));
5446                 j = Int64Add(*j, Int64(1));
5447                 Jump(&loopEnd2);
5448             }
5449         }
5450         Bind(&loopEnd2);
5451         i = Int64Add(*i, Int64(1));
5452         LoopEnd(&loopHead2);
5453         Bind(&loopExit2);
5454         Label trim(env);
5455         Label noTrim(env);
5456         BRANCH(Int32GreaterThan(*newArrLen, *j), &trim, &noTrim);
5457         Bind(&trim);
5458         {
5459             GateRef elements = GetElementsArray(newArray);
5460             CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, *j});
5461             SetArrayLength(glue, newArray, TruncInt64ToInt32(*j));
5462             result->WriteVariable(newArray);
5463             Jump(exit);
5464         }
5465         Bind(&noTrim);
5466         result->WriteVariable(newArray);
5467         Jump(exit);
5468     }
5469 }
5470 
IsArray(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)5471 void BuiltinsArrayStubBuilder::IsArray([[maybe_unused]] GateRef glue, [[maybe_unused]] GateRef thisValue,
5472     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
5473 {
5474     auto env = GetEnvironment();
5475     GateRef obj = GetCallArg0(numArgs);
5476     Label isHeapObj(env);
5477     Label notHeapObj(env);
5478     BRANCH(TaggedIsHeapObject(obj), &isHeapObj, &notHeapObj);
5479     Bind(&isHeapObj);
5480     {
5481         Label isJSArray(env);
5482         Label notJSArray(env);
5483         GateRef objectType = GetObjectType(LoadHClass(obj));
5484         BRANCH(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_ARRAY))), &isJSArray, &notJSArray);
5485         Bind(&isJSArray);
5486         {
5487             result->WriteVariable(TaggedTrue());
5488             Jump(exit);
5489         }
5490         Bind(&notJSArray);
5491         BRANCH(Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::JS_PROXY))), slowPath, &notHeapObj);
5492     }
5493     Bind(&notHeapObj);
5494     {
5495         result->WriteVariable(TaggedFalse());
5496         Jump(exit);
5497     }
5498 }
5499 }  // namespace panda::ecmascript::kungfu
5500