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