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