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