• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ecmascript/compiler/builtins/builtins_array_stub_builder.h"
16 
17 #include "ecmascript/builtins/builtins_string.h"
18 #include "ecmascript/compiler/builtins/builtins_stubs.h"
19 #include "ecmascript/compiler/call_stub_builder.h"
20 #include "ecmascript/compiler/circuit_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/base/array_helper.h"
27 
28 namespace panda::ecmascript::kungfu {
UnshiftOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)29 void BuiltinsArrayStubBuilder::UnshiftOptimised(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result,
30                                                 Label *exit, Label *slowPath)
31 {
32     auto env = GetEnvironment();
33     Label isHeapObject(env);
34     Label isJsArray(env);
35     Label isStableJsArray(env);
36     Label notOverRange(env);
37     Label numNotEqualZero(env);
38     Label numLessThanOrEqualThree(env);
39     Label grow(env);
40     Label setValue(env);
41     Label numEqual2(env);
42     Label numEqual3(env);
43     Label threeArgs(env);
44     Label final(env);
45     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
46     Bind(&isHeapObject);
47     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
48     Bind(&isJsArray);
49     BRANCH(IsStableJSArray(glue, thisValue), &isStableJsArray, slowPath);
50     Bind(&isStableJsArray);
51     BRANCH(Int64GreaterThan(numArgs, IntPtr(0)), &numNotEqualZero, slowPath);
52     Bind(&numNotEqualZero);
53     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
54     GateRef argLen = ZExtInt32ToInt64(ChangeIntPtrToInt32(numArgs));
55     GateRef newLen = Int64Add(thisLen, argLen);
56     BRANCH(Int64GreaterThan(newLen, Int64(base::MAX_SAFE_INTEGER)), slowPath, &notOverRange);
57     Bind(&notOverRange);
58     // 3 : max param num
59     BRANCH(Int64LessThanOrEqual(numArgs, IntPtr(3)), &numLessThanOrEqualThree, slowPath);
60     Bind(&numLessThanOrEqualThree);
61     GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(GetElementsArray(glue, thisValue)));
62     BRANCH(Int64GreaterThan(newLen, capacity), &grow, &setValue);
63     Bind(&grow);
64     {
65         GrowElementsCapacity(glue, thisValue, TruncInt64ToInt32(newLen));
66         Jump(&setValue);
67     }
68     Bind(&setValue);
69     {
70         Label directAdd(env);
71         Label mutantArrayEnabled(env);
72         GateRef elements = GetElementsArray(glue, thisValue);
73         GateRef arrayStart = GetDataPtrInTaggedArray(elements);
74         GateRef moveTo = PtrAdd(arrayStart, PtrMul(numArgs, IntPtr(JSTaggedValue::TaggedTypeSize())));
75         GateRef kind = GetElementsKindFromHClass(LoadHClass(glue, thisValue));
76         ArrayCopy(glue, elements, arrayStart, elements, moveTo, TruncInt64ToInt32(thisLen),
77                   NeedBarrier(kind), SameArray);
78         BRANCH_UNLIKELY(IsEnableMutantArray(glue), &mutantArrayEnabled, &directAdd);
79         Bind(&directAdd);
80         {
81             GateRef arg0 = GetCallArg0(numArgs);
82             GateRef arg1 = GetCallArg1(numArgs);
83             GateRef arg2 = GetCallArg2(numArgs);
84             DEFVARIABLE(newKind, VariableType::INT32(), kind);
85             Label migrateElementsKind(env);
86             int64_t argCount[THREE_ARGS] = {ONE_ARGS, TWO_ARGS, THREE_ARGS};
87             Label labels[THREE_ARGS] = {Label(env), Label(env), Label(env)};
88             Switch(numArgs, slowPath, argCount, labels, THREE_ARGS);
89             Bind(&labels[Index2]);
90             {
91                 newKind = Int32Or(TaggedToElementKind(glue, arg0), *newKind);
92                 newKind = Int32Or(TaggedToElementKind(glue, arg1), *newKind);
93                 newKind = Int32Or(TaggedToElementKind(glue, arg2), *newKind);
94                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(Index0), arg0);
95                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(Index1), arg1);
96                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(Index2), arg2);
97                 Jump(&migrateElementsKind);
98             }
99             Bind(&labels[Index1]);
100             {
101                 newKind = Int32Or(TaggedToElementKind(glue, arg0), *newKind);
102                 newKind = Int32Or(TaggedToElementKind(glue, arg1), *newKind);
103                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(Index0), arg0);
104                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(Index1), arg1);
105                 Jump(&migrateElementsKind);
106             }
107             Bind(&labels[Index0]);
108             {
109                 newKind = Int32Or(TaggedToElementKind(glue, arg0), *newKind);
110                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, Int32(Index0), arg0);
111                 Jump(&migrateElementsKind);
112             }
113             Bind(&migrateElementsKind);
114             {
115                 Label needTransition(env);
116                 // note: newKind is not be fixed, may be an invalid kind.
117                 // but use it as a condition for transition is ok.
118                 BRANCH_UNLIKELY(Int32NotEqual(*newKind, kind), &needTransition, &final);
119                 Bind(&needTransition);
120                 {
121                     CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
122                         RTSTUB_ID(UpdateHClassForElementsKind), { thisValue, *newKind });
123                     Jump(&final);
124                 }
125             }
126         }
127         Bind(&mutantArrayEnabled);
128         {
129             GateRef value0 = GetCallArg0(numArgs);
130             // 0 : the first Element position
131             SetValueWithElementsKind(glue, thisValue, value0, Int64(Index0), Boolean(false),
132                                      Int32(Elements::ToUint(ElementsKind::NONE)));
133             // 2 : the second param
134             BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(TWO_ARGS)), &numEqual2, &numEqual3);
135             Bind(&numEqual2);
136             {
137                 GateRef value1 = GetCallArg1(numArgs);
138                 // 1 : the second Element position
139                 SetValueWithElementsKind(glue, thisValue, value1, Int64(Index1), Boolean(false),
140                                          Int32(Elements::ToUint(ElementsKind::NONE)));
141                 Jump(&numEqual3);
142             }
143             Bind(&numEqual3);
144             {
145                 // 3 : the third param
146                 BRANCH(Int64Equal(numArgs, IntPtr(THREE_ARGS)), &threeArgs, &final);
147                 Bind(&threeArgs);
148                 GateRef value2 = GetCallArg2(numArgs);
149                 // 2 : the third Element position
150                 SetValueWithElementsKind(glue, thisValue, value2, Int64(Index2), Boolean(false),
151                                          Int32(Elements::ToUint(ElementsKind::NONE)));
152                 Jump(&final);
153             }
154             Bind(&final);
155             {
156                 SetArrayLength(glue, thisValue, newLen);
157                 result->WriteVariable(IntToTaggedPtr(newLen));
158                 Jump(exit);
159             }
160         }
161     }
162 }
163 
DoSortOptimised(GateRef glue,GateRef receiver,GateRef receiverState,Variable * result,Label * exit,Label * slowPath,GateRef hir)164 GateRef BuiltinsArrayStubBuilder::DoSortOptimised(GateRef glue, GateRef receiver, GateRef receiverState,
165                                          Variable *result, Label *exit, Label *slowPath, GateRef hir)
166 {
167     auto env = GetEnvironment();
168     Label entry(env);
169     env->SubCfgEntry(&entry);
170     GateRef len = ZExtInt32ToInt64(GetArrayLength(receiver));
171     DEFVARIABLE(i, VariableType::INT64(), Int64(1));
172     DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined());
173     DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined());
174     DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined());
175     Label loopHead(env);
176     Label loopEnd(env);
177     Label next(env);
178     Label loopExit(env);
179     Jump(&loopHead);
180     LoopBegin(&loopHead);
181     {
182         BRANCH(Int64LessThan(*i, len), &next, &loopExit);
183         Bind(&next);
184         DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0));
185         DEFVARIABLE(endIndex, VariableType::INT64(), *i);
186         Label presentValueIsHole(env);
187         Label afterGettingpresentValue(env);
188         Label presentValueHasProperty(env);
189         Label presentValueHasException0(env);
190         presentValue = GetTaggedValueWithElementsKind(glue, receiver, *i);
191         BRANCH(TaggedIsHole(*presentValue), &presentValueIsHole, &afterGettingpresentValue);
192         Bind(&presentValueIsHole);
193         {
194 #if ENABLE_NEXT_OPTIMIZATION
195             GateRef presentValueHasProp = HasProperty(glue, receiver, IntToTaggedPtr(*i), hir);
196 #else
197             GateRef presentValueHasProp = CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
198                 RTSTUB_ID(HasProperty), {receiver, IntToTaggedInt(*i)});
199 #endif
200             BRANCH(TaggedIsTrue(presentValueHasProp), &presentValueHasProperty, &afterGettingpresentValue);
201             Bind(&presentValueHasProperty);
202             {
203                 presentValue = FastGetPropertyByIndex(glue, receiver, TruncInt64ToInt32(*i), ProfileOperation(), hir);
204                 BRANCH(HasPendingException(glue), &presentValueHasException0, &afterGettingpresentValue);
205                 Bind(&presentValueHasException0);
206                 {
207                     result->WriteVariable(Exception());
208                     Jump(exit);
209                 }
210             }
211         }
212         Bind(&afterGettingpresentValue);
213         {
214             Label loopHead1(env);
215             Label loopEnd1(env);
216             Label next1(env);
217             Label loopExit1(env);
218             Jump(&loopHead1);
219             LoopBegin(&loopHead1);
220             {
221                 Label middleValueIsHole(env);
222                 Label afterGettingmiddleValue(env);
223                 Label middleValueHasProperty(env);
224                 Label middleValueHasException0(env);
225                 BRANCH(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1);
226                 Bind(&next1);
227                 GateRef sum = Int64Add(*beginIndex, *endIndex);
228                 GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half
229                 middleValue = GetTaggedValueWithElementsKind(glue, receiver, middleIndex);
230                 BRANCH(TaggedIsHole(*middleValue), &middleValueIsHole, &afterGettingmiddleValue);
231                 Bind(&middleValueIsHole);
232                 {
233 #if ENABLE_NEXT_OPTIMIZATION
234                     GateRef middleValueHasProp = HasProperty(glue, receiver, IntToTaggedPtr(middleIndex), hir);
235 #else
236                     GateRef middleValueHasProp = CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
237                         RTSTUB_ID(HasProperty), {receiver, IntToTaggedInt(middleIndex)});
238 #endif
239                     BRANCH(TaggedIsTrue(middleValueHasProp), &middleValueHasProperty, &afterGettingmiddleValue);
240                     Bind(&middleValueHasProperty);
241                     {
242                         middleValue = FastGetPropertyByIndex(glue, receiver,
243                                                              TruncInt64ToInt32(middleIndex), ProfileOperation(), hir);
244                         BRANCH(HasPendingException(glue), &middleValueHasException0, &afterGettingmiddleValue);
245                         Bind(&middleValueHasException0);
246                         {
247                             result->WriteVariable(Exception());
248                             Jump(exit);
249                         }
250                     }
251                 }
252                 Bind(&afterGettingmiddleValue);
253                 {
254                     Label isInt(env);
255                     Label notInt(env);
256                     Label isDouble(env);
257                     Label notDouble(env);
258                     Label exchangeIndex(env);
259                     GateRef middleVal = *middleValue;
260                     GateRef presentVal = *presentValue;
261                     DEFVARIABLE(compareResult, VariableType::INT32(), Int32(0));
262                     GateRef intCheck = LogicAndBuilder(env)
263                                        .And(TaggedIsInt(middleVal))
264                                        .And(TaggedIsInt(presentVal))
265                                        .Done();
266                     BRANCH(intCheck, &isInt, &notInt);
267                     Bind(&isInt);
268                     {
269                         compareResult =
270                             CallNGCRuntime(glue, RTSTUB_ID(IntLexicographicCompare), {*middleValue, *presentValue});
271                         Jump(&exchangeIndex);
272                     }
273                     Bind(&notInt);
274                     {
275                         GateRef doubleCheck = LogicAndBuilder(env)
276                                               .And(TaggedIsDouble(middleVal))
277                                               .And(TaggedIsDouble(presentVal))
278                                               .Done();
279                         BRANCH(doubleCheck, &isDouble, &notDouble);
280                         Bind(&isDouble);
281                         {
282                             compareResult = CallNGCRuntime(glue,
283                                 RTSTUB_ID(DoubleLexicographicCompare), {*middleValue, *presentValue});
284                             Jump(&exchangeIndex);
285                         }
286                         Bind(&notDouble);
287                         Label isString(env);
288                         GateRef strBool = LogicAndBuilder(env)
289                                           .And(TaggedIsString(glue, middleVal))
290                                           .And(TaggedIsString(glue, presentVal))
291                                           .Done();
292                         BRANCH(strBool, &isString, slowPath);
293                         Bind(&isString);
294                         {
295                             compareResult = StringCompare(glue, *middleValue, *presentValue);
296                             Jump(&exchangeIndex);
297                         }
298                     }
299                     Bind(&exchangeIndex);
300                     {
301                         Label less0(env);
302                         Label greater0(env);
303                         BRANCH(Int32LessThanOrEqual(*compareResult, Int32(0)), &less0, &greater0);
304                         Bind(&greater0);
305                         {
306                             endIndex = middleIndex;
307                             Jump(&loopEnd1);
308                         }
309                         Bind(&less0);
310                         {
311                             beginIndex = middleIndex;
312                             beginIndex = Int64Add(*beginIndex, Int64(1));
313                             Jump(&loopEnd1);
314                         }
315                     }
316                 }
317             }
318             Bind(&loopEnd1);
319             LoopEnd(&loopHead1);
320             Bind(&loopExit1);
321 
322             Label shouldCopy(env);
323             GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0));
324             GateRef lessI = Int64LessThan(*endIndex, *i);
325             BRANCH(BitAnd(isGreater0, lessI), &shouldCopy, &loopEnd);
326             Bind(&shouldCopy);
327             {
328                 DEFVARIABLE(j, VariableType::INT64(), *i);
329                 Label loopHead2(env);
330                 Label loopEnd2(env);
331                 Label next2(env);
332                 Label loopExit2(env);
333                 Label receiverIsNew(env);
334                 Label receiverIsOrigin(env);
335                 Label receiverIsNew2(env);
336                 Label receiverIsOrigin2(env);
337                 Jump(&loopHead2);
338                 LoopBegin(&loopHead2);
339                 {
340                     Label previousValueIsHole(env);
341                     Label afterGettingpreviousValue(env);
342                     Label previousValueHasProperty(env);
343                     Label previousValueHasException0(env);
344                     BRANCH(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2);
345                     Bind(&next2);
346                     previousValue = GetTaggedValueWithElementsKind(glue, receiver, Int64Sub(*j, Int64(1)));
347                     BRANCH(TaggedIsHole(*previousValue), &previousValueIsHole, &afterGettingpreviousValue);
348                     Bind(&previousValueIsHole);
349                     {
350 #if ENABLE_NEXT_OPTIMIZATION
351                         GateRef previousValueHasProp =
352                             HasProperty(glue, receiver, IntToTaggedPtr(Int64Sub(*j, Int64(1))), hir);
353 #else
354                         GateRef previousValueHasProp = CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
355                             RTSTUB_ID(HasProperty), {receiver, IntToTaggedInt(Int64Sub(*j, Int64(1)))});
356 #endif
357                         BRANCH(TaggedIsTrue(previousValueHasProp),
358                                &previousValueHasProperty, &afterGettingpreviousValue);
359                         Bind(&previousValueHasProperty);
360                         {
361                             previousValue = FastGetPropertyByIndex(glue, receiver,
362                                                                    TruncInt64ToInt32(Int64Sub(*j, Int64(1))),
363                                                                    ProfileOperation(), hir);
364                             BRANCH(HasPendingException(glue), &previousValueHasException0, &afterGettingpreviousValue);
365                             Bind(&previousValueHasException0);
366                             {
367                                 result->WriteVariable(Exception());
368                                 Jump(exit);
369                             }
370                         }
371                     }
372                     Bind(&afterGettingpreviousValue);
373                     {
374                         BRANCH(receiverState, &receiverIsNew, &receiverIsOrigin);
375                         Bind(&receiverIsNew);
376                         SetValueWithElementsKind(glue, receiver, *previousValue, *j, Boolean(true),
377                                                  Int32(Elements::ToUint(ElementsKind::NONE)));
378                         Jump(&loopEnd2);
379                         Bind(&receiverIsOrigin);
380                         SetValueWithElementsKind(glue, receiver, *previousValue, *j, Boolean(false),
381                                                  Int32(Elements::ToUint(ElementsKind::NONE)));
382                         Jump(&loopEnd2);
383                     }
384                 }
385                 Bind(&loopEnd2);
386                 j = Int64Sub(*j, Int64(1));
387                 LoopEnd(&loopHead2);
388                 Bind(&loopExit2);
389                 BRANCH(receiverState, &receiverIsNew2, &receiverIsOrigin2);
390                 Bind(&receiverIsNew2);
391                 {
392                     SetValueWithElementsKind(glue, receiver, *presentValue, *endIndex, Boolean(true),
393                                              Int32(Elements::ToUint(ElementsKind::NONE)));
394                     Jump(&loopEnd);
395                 }
396                 Bind(&receiverIsOrigin2);
397                 {
398                     SetValueWithElementsKind(glue, receiver, *presentValue, *endIndex, Boolean(false),
399                                              Int32(Elements::ToUint(ElementsKind::NONE)));
400                     Jump(&loopEnd);
401                 }
402             }
403         }
404     }
405     Bind(&loopEnd);
406     i = Int64Add(*i, Int64(1));
407     LoopEnd(&loopHead);
408     Bind(&loopExit);
409     env->SubCfgExit();
410     return receiver;
411 }
412 
DoSortOptimisedFast(GateRef glue,GateRef receiver,Variable * result,Label * exit,Label * slowPath,GateRef hir)413 GateRef BuiltinsArrayStubBuilder::DoSortOptimisedFast(GateRef glue, GateRef receiver,
414     [[maybe_unused]] Variable *result, [[maybe_unused]] Label *exit,
415     Label *slowPath, [[maybe_unused]] GateRef hir)
416 {
417     auto env = GetEnvironment();
418     Label entry(env);
419     env->SubCfgEntry(&entry);
420     GateRef len = ZExtInt32ToInt64(GetArrayLength(receiver));
421     DEFVARIABLE(i, VariableType::INT64(), Int64(1));
422     DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined());
423     DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined());
424     DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined());
425     GateRef elements = GetElementsArray(glue, receiver);
426     Label loopHead(env);
427     Label loopEnd(env);
428     Label next(env);
429     Label loopExit(env);
430     Jump(&loopHead);
431     LoopBegin(&loopHead);
432     {
433         BRANCH(Int64LessThan(*i, len), &next, &loopExit);
434         Bind(&next);
435         DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0));
436         DEFVARIABLE(endIndex, VariableType::INT64(), *i);
437         Label afterGettingpresentValue(env);
438         presentValue = GetValueFromTaggedArray(glue, elements, TruncInt64ToInt32(*i));
439         Jump(&afterGettingpresentValue);
440         Bind(&afterGettingpresentValue);
441         {
442             Label loopHead1(env);
443             Label loopEnd1(env);
444             Label next1(env);
445             Label loopExit1(env);
446             Jump(&loopHead1);
447             LoopBegin(&loopHead1);
448             {
449                 Label afterGettingmiddleValue(env);
450                 BRANCH(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1);
451                 Bind(&next1);
452                 GateRef sum = Int64Add(*beginIndex, *endIndex);
453                 GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half
454                 middleValue = GetValueFromTaggedArray(glue, elements, TruncInt64ToInt32(middleIndex));
455                 Jump(&afterGettingmiddleValue);
456                 Bind(&afterGettingmiddleValue);
457                 {
458                     Label intOrDouble(env);
459                     Label notIntAndDouble(env);
460                     Label exchangeIndex(env);
461                     DEFVARIABLE(compareResult, VariableType::INT32(), Int32(0));
462 
463                     Label middleIsHole(env);
464                     Label presentIsHole(env);
465                     Label middleNotHole(env);
466                     Label presentNotHole(env);
467                     Label notHole(env);
468                     Label middleIsUndefined(env);
469                     Label presentIsUndefined(env);
470                     Label middleNotUndefined(env);
471                     Label presentNotUndefined(env);
472                     Label notUndefined(env);
473                     BRANCH(TaggedIsHole(*middleValue), &middleIsHole, &middleNotHole);
474                     Bind(&middleIsHole);
475                     {
476                         Label presentNotHole0(env);
477                         BRANCH(TaggedIsHole(*presentValue), &exchangeIndex, &presentNotHole0);
478                         Bind(&presentNotHole0);
479                         compareResult = Int32(1);
480                         Jump(&exchangeIndex);
481                     }
482                     Bind(&middleNotHole);
483                     BRANCH(TaggedIsHole(*presentValue), &presentIsHole, &presentNotHole);
484                     Bind(&presentIsHole);
485                     {
486                         compareResult = Int32(-1);
487                         Jump(&exchangeIndex);
488                     }
489                     Bind(&presentNotHole);
490                     BRANCH(TaggedIsUndefined(*middleValue), &middleIsUndefined, &middleNotUndefined);
491                     Bind(&middleIsUndefined);
492                     {
493                         Label presentNotUndefined0(env);
494                         BRANCH(TaggedIsUndefined(*presentValue), &exchangeIndex, &presentNotUndefined0);
495                         Bind(&presentNotUndefined0);
496                         compareResult = Int32(1);
497                         Jump(&exchangeIndex);
498                     }
499                     Bind(&middleNotUndefined);
500                     BRANCH(TaggedIsUndefined(*presentValue), &presentIsUndefined, &presentNotUndefined);
501                     Bind(&presentIsUndefined);
502                     {
503                         compareResult = Int32(-1);
504                         Jump(&exchangeIndex);
505                     }
506                     Bind(&presentNotUndefined);
507                     Label isInt(env);
508                     Label notInt(env);
509                     Label isDouble(env);
510                     Label notDouble(env);
511                     GateRef middleVal = *middleValue;
512                     GateRef presentVal = *presentValue;
513                     GateRef intCheck = LogicAndBuilder(env)
514                                        .And(TaggedIsInt(middleVal))
515                                        .And(TaggedIsInt(presentVal))
516                                        .Done();
517                     BRANCH(intCheck, &isInt, &notInt);
518                     Bind(&isInt);
519                     {
520                         compareResult =
521                             CallNGCRuntime(glue, RTSTUB_ID(IntLexicographicCompare), {*middleValue, *presentValue});
522                         Jump(&exchangeIndex);
523                     }
524                     Bind(&notInt);
525                     GateRef doubleCheck = LogicAndBuilder(env)
526                                           .And(TaggedIsDouble(middleVal))
527                                           .And(TaggedIsDouble(presentVal))
528                                           .Done();
529                     BRANCH(doubleCheck, &isDouble, &notDouble);
530                     Bind(&isDouble);
531                     {
532                         compareResult = CallNGCRuntime(glue,
533                             RTSTUB_ID(DoubleLexicographicCompare), {*middleValue, *presentValue});
534                         Jump(&exchangeIndex);
535                     }
536                     Bind(&notDouble);
537                     Label isString(env);
538                     GateRef stringCheck = BitAnd(TaggedIsString(glue, *middleValue),
539                                                  TaggedIsString(glue, *presentValue));
540                     BRANCH(stringCheck, &isString, slowPath);
541                     Bind(&isString);
542                     {
543                         compareResult = StringCompare(glue, *middleValue, *presentValue);
544                         Jump(&exchangeIndex);
545                     }
546                     Bind(&exchangeIndex);
547                     {
548                         Label less0(env);
549                         Label greater0(env);
550                         BRANCH(Int32LessThanOrEqual(*compareResult, Int32(0)), &less0, &greater0);
551                         Bind(&greater0);
552                         {
553                             endIndex = middleIndex;
554                             Jump(&loopEnd1);
555                         }
556                         Bind(&less0);
557                         {
558                             beginIndex = middleIndex;
559                             beginIndex = Int64Add(*beginIndex, Int64(1));
560                             Jump(&loopEnd1);
561                         }
562                     }
563                 }
564             }
565             Bind(&loopEnd1);
566             LoopEnd(&loopHead1);
567             Bind(&loopExit1);
568             Label shouldCopy(env);
569             GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0));
570             GateRef lessI = Int64LessThan(*endIndex, *i);
571             BRANCH(BitAnd(isGreater0, lessI), &shouldCopy, &loopEnd);
572             Bind(&shouldCopy);
573             {
574                 DEFVARIABLE(j, VariableType::INT64(), *i);
575                 Label loopHead2(env);
576                 Label loopEnd2(env);
577                 Label next2(env);
578                 Label loopExit2(env);
579                 Label receiverIsNew(env);
580                 Label receiverIsOrigin(env);
581                 Label receiverIsNew2(env);
582                 Label receiverIsOrigin2(env);
583                 Jump(&loopHead2);
584                 LoopBegin(&loopHead2);
585                 {
586                     BRANCH(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2);
587                     Bind(&next2);
588                     previousValue = GetValueFromTaggedArray(glue, elements, TruncInt64ToInt32(Int64Sub(*j, Int64(1))));
589                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, TruncInt64ToInt32(*j),
590                                           *previousValue);
591                     Jump(&loopEnd2);
592                 }
593                 Bind(&loopEnd2);
594                 j = Int64Sub(*j, Int64(1));
595                 LoopEnd(&loopHead2);
596                 Bind(&loopExit2);
597                 SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, TruncInt64ToInt32(*endIndex),
598                                       *presentValue);
599                 Jump(&loopEnd);
600             }
601         }
602     }
603     Bind(&loopEnd);
604     i = Int64Add(*i, Int64(1));
605     LoopEnd(&loopHead);
606     Bind(&loopExit);
607     env->SubCfgExit();
608     return receiver;
609 }
610 
CopyWithinOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)611 void BuiltinsArrayStubBuilder::CopyWithinOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
612     Variable *result, Label *exit, Label *slowPath)
613 {
614     auto env = GetEnvironment();
615     Label thisExists(env);
616     Label isHeapObject(env);
617     Label isJsArray(env);
618     Label defaultConstr(env);
619     Label isStability(env);
620     Label isGeneric(env);
621     Label notCOWArray(env);
622     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
623     Bind(&thisExists);
624     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
625     Bind(&isHeapObject);
626     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
627     Bind(&isJsArray);
628     BRANCH(HasConstructor(glue, thisValue), slowPath, &defaultConstr);
629     Bind(&defaultConstr);
630     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
631     Bind(&isStability);
632     Label isJsCOWArray(env);
633     Label getElements(env);
634     BRANCH(IsJsCOWArray(glue, thisValue), &isJsCOWArray, &getElements);
635     Bind(&isJsCOWArray);
636     {
637         NewObjectStubBuilder newBuilder(this);
638         GateRef elements = GetElementsArray(glue, thisValue);
639         GateRef capacity = GetLengthOfTaggedArray(elements);
640         GateRef newElements = newBuilder.CopyArray(glue, elements, capacity, capacity);
641         SetElementsArray(VariableType::JS_POINTER(), glue, thisValue, newElements);
642         Jump(&getElements);
643     }
644     Bind(&getElements);
645     DEFVARIABLE(startPos, VariableType::INT64(), Int64(0));
646     DEFVARIABLE(endPos, VariableType::INT64(), Int64(0));
647     Label targetTagExists(env);
648     Label targetTagIsInt(env);
649     Label startTagExists(env);
650     Label startTagIsInt(env);
651     Label afterCallArg1(env);
652     Label endTagExists(env);
653     Label endTagIsInt(env);
654     Label afterCallArg2(env);
655     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
656     BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &targetTagExists);
657     Bind(&targetTagExists);
658     GateRef targetTag = GetCallArg0(numArgs);
659     BRANCH(TaggedIsInt(targetTag), &targetTagIsInt, slowPath);
660     Bind(&targetTagIsInt);
661     GateRef argTarget = SExtInt32ToInt64(TaggedGetInt(targetTag));
662     BRANCH(Int64GreaterThanOrEqual(IntPtr(ONE_ARGS), numArgs), &afterCallArg1, &startTagExists);
663     Bind(&startTagExists);
664     {
665         GateRef startTag = GetCallArg1(numArgs);
666         BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath);
667         Bind(&startTagIsInt);
668         startPos = SExtInt32ToInt64(TaggedGetInt(startTag));
669         Jump(&afterCallArg1);
670     }
671     Bind(&afterCallArg1);
672     {
673         endPos = thisLen;
674         BRANCH(Int64GreaterThanOrEqual(IntPtr(TWO_ARGS), numArgs), &afterCallArg2, &endTagExists);
675         Bind(&endTagExists);
676         {
677             GateRef endTag = GetCallArg2(numArgs);
678             BRANCH(TaggedIsInt(endTag), &endTagIsInt, slowPath);
679             Bind(&endTagIsInt);
680             {
681                 endPos = SExtInt32ToInt64(TaggedGetInt(endTag));
682                 Jump(&afterCallArg2);
683             }
684         }
685     }
686     Bind(&afterCallArg2);
687     {
688         DEFVARIABLE(copyTo, VariableType::INT64(), Int64(0));
689         DEFVARIABLE(copyFrom, VariableType::INT64(), Int64(0));
690         DEFVARIABLE(copyEnd, VariableType::INT64(), Int64(0));
691         DEFVARIABLE(count, VariableType::INT64(), Int64(0));
692         DEFVARIABLE(direction, VariableType::INT64(), Int64(0));
693         Label calculateCountBranch1(env);
694         Label calculateCountBranch2(env);
695         Label afterCalculateCount(env);
696         Label needToAdjustParam(env);
697         Label afterAdjustParam(env);
698         copyTo = CalculatePositionWithLength(argTarget, thisLen);
699         copyFrom = CalculatePositionWithLength(*startPos, thisLen);
700         copyEnd = CalculatePositionWithLength(*endPos, thisLen);
701         BRANCH(Int64LessThan(Int64Sub(*copyEnd, *copyFrom), Int64Sub(thisLen, *copyTo)),
702                &calculateCountBranch1, &calculateCountBranch2);
703         Bind(&calculateCountBranch1);
704         {
705             count = Int64Sub(*copyEnd, *copyFrom);
706             Jump(&afterCalculateCount);
707         }
708         Bind(&calculateCountBranch2);
709         {
710             count = Int64Sub(thisLen, *copyTo);
711             Jump(&afterCalculateCount);
712         }
713         Bind(&afterCalculateCount);
714         Label countGreaterZero(env);
715         Label countLessOrEqualZero(env);
716         BRANCH(Int64GreaterThan(*count, Int64(0)), &countGreaterZero, &countLessOrEqualZero);
717         Bind(&countLessOrEqualZero);
718         {
719             result->WriteVariable(thisValue);
720             Jump(exit);
721         }
722         Bind(&countGreaterZero);
723         Label enableMutantArray(env);
724         Label disableMutantArray(env);
725         GateRef isEnable = IsEnableMutantArray(glue);
726         BRANCH(isEnable, &enableMutantArray, &disableMutantArray);
727         Bind(&enableMutantArray);
728         {
729             direction = Int64(1);
730             GateRef copyFromVal = *copyFrom;
731             GateRef copyToVal = *copyTo;
732             GateRef countVal = *count;
733             BRANCH(LogicAndBuilder(env).And(Int64LessThan(copyFromVal, copyToVal))
734                 .And(Int64LessThan(copyToVal, Int64Add(copyFromVal, countVal))).Done(),
735                 &needToAdjustParam, &afterAdjustParam);
736             Bind(&needToAdjustParam);
737             {
738                 direction = Int64(-1);
739                 copyFrom = Int64Sub(Int64Add(*copyFrom, *count), Int64(1));
740                 copyTo = Int64Sub(Int64Add(*copyTo, *count), Int64(1));
741                 Jump(&afterAdjustParam);
742             }
743             Bind(&afterAdjustParam);
744             {
745                 DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
746                 Label loopHead(env);
747                 Label loopEnd(env);
748                 Label next(env);
749                 Label loopExit(env);
750                 Jump(&loopHead);
751                 LoopBegin(&loopHead);
752                 {
753                     Label kValueIsHole(env);
754                     Label setValue(env);
755                     Label hasProperty(env);
756                     Label setHole(env);
757                     Label hasException0(env);
758                     Label notHasException0(env);
759                     BRANCH(Int64GreaterThan(*count, Int64(0)), &next, &loopExit);
760                     Bind(&next);
761                     kValue = GetTaggedValueWithElementsKind(glue, thisValue, *copyFrom);
762                     BRANCH(TaggedIsHole(*kValue), &setHole, &setValue);
763                     Bind(&setHole);
764                     {
765                         SetValueWithElementsKind(glue, thisValue, Hole(), *copyTo,
766                             Boolean(true), Int32(Elements::ToUint(ElementsKind::GENERIC)));
767                         Jump(&loopEnd);
768                     }
769                     Bind(&setValue);
770                     {
771                         SetValueWithElementsKind(glue, thisValue, *kValue, *copyTo,
772                             Boolean(true), Int32(Elements::ToUint(ElementsKind::NONE)));
773                         Jump(&loopEnd);
774                     }
775                 }
776                 Bind(&loopEnd);
777                 copyFrom = Int64Add(*copyFrom, *direction);
778                 copyTo = Int64Add(*copyTo, *direction);
779                 count = Int64Sub(*count, Int64(1));
780                 LoopEnd(&loopHead);
781                 Bind(&loopExit);
782                 result->WriteVariable(thisValue);
783                 Jump(exit);
784             }
785         }
786         Bind(&disableMutantArray);
787         {
788             GateRef elements = GetElementsArray(glue, thisValue);
789             GateRef elementsPtr = GetDataPtrInTaggedArray(elements);
790             GateRef kind = GetElementsKindFromHClass(LoadHClass(glue, thisValue));
791             GateRef src = PtrAdd(elementsPtr, PtrMul(*copyFrom, IntPtr(JSTaggedValue::TaggedTypeSize())));
792             GateRef dest = PtrAdd(elementsPtr, PtrMul(*copyTo, IntPtr(JSTaggedValue::TaggedTypeSize())));
793             ArrayCopy(glue, elements, src, elements, dest,
794                       TruncInt64ToInt32(*count), NeedBarrier(kind), SameArray);
795             result->WriteVariable(thisValue);
796             Jump(exit);
797         }
798     }
799 }
800 
ToReversedOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)801 void BuiltinsArrayStubBuilder::ToReversedOptimised(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
802                                           Variable *result, Label *exit, Label *slowPath)
803 {
804     auto env = GetEnvironment();
805     Label isHeapObject(env);
806     Label isJsArray(env);
807     Label isStability(env);
808     Label notCOWArray(env);
809     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
810     Bind(&isHeapObject);
811     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
812     Bind(&isJsArray);
813     // don't check constructor, "ToReversed" always use ArrayCreate to create array.
814     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
815     Bind(&isStability);
816     BRANCH(IsJsCOWArray(glue, thisValue), slowPath, &notCOWArray);
817     Bind(&notCOWArray);
818     Label next(env);
819     DEFVARIABLE(receiver, VariableType::JS_ANY(), Hole());
820     GateRef kind = GetElementsKindFromHClass(LoadHClass(glue, thisValue));
821     GateRef thisArrLen = GetArrayLength(thisValue);
822     Label newArrayIsTagged(env);
823     Label reuseOldHClass(env);
824     BRANCH_NO_WEIGHT(ElementsKindHasHole(kind), &newArrayIsTagged, &reuseOldHClass);
825     Bind(&newArrayIsTagged);
826     {
827         // If the kind has hole, we know it must be transited to TAGGED kind;
828         // There will be no hole in the new array because hole will be converted to undefined.
829         GateRef globalEnv = GetCurrentGlobalEnv();
830         GateRef newHClass = GetGlobalEnvValue(VariableType::JS_ANY(), glue, globalEnv,
831                                               static_cast<size_t>(GlobalEnvField::ELEMENT_TAGGED_HCLASS_INDEX));
832         receiver = NewArrayWithHClass(glue, newHClass, thisArrLen);
833         Jump(&next);
834     }
835     Bind(&reuseOldHClass);
836     {
837         receiver = NewArrayWithHClass(glue, LoadHClass(glue, thisValue), thisArrLen);
838         Jump(&next);
839     }
840     Bind(&next);
841     Label afterReverse(env);
842     Label isIntOrNumber(env);
843     Label notIntOrNumber(env);
844     Label isTagged(env);
845     Label isHoleOrIntOrNumber(env);
846     GateRef intOrNumber = LogicOrBuilder(env)
847                           .Or(Int32Equal(kind, Int32(Elements::ToUint(ElementsKind::INT))))
848                           .Or(Int32Equal(kind, Int32(Elements::ToUint(ElementsKind::NUMBER))))
849                           .Done();
850     BRANCH_NO_WEIGHT(intOrNumber, &isIntOrNumber, &notIntOrNumber);
851     Bind(&notIntOrNumber);
852     {
853         GateRef holeOrIntOrNumber = LogicOrBuilder(env)
854                                     .Or(Int32Equal(kind, Int32(Elements::ToUint(ElementsKind::HOLE_INT))))
855                                     .Or(Int32Equal(kind, Int32(Elements::ToUint(ElementsKind::HOLE_NUMBER))))
856                                     .Done();
857         BRANCH_NO_WEIGHT(holeOrIntOrNumber, &isHoleOrIntOrNumber, &isTagged);
858     }
859     Bind(&isTagged);
860     {
861         // The old array and new array are both TaggedArray, so load and store the element directly.
862         // And barrier is needed.
863         DoReverse(glue, thisValue, *receiver, true, false, MemoryAttribute::Default());
864         Jump(&afterReverse);
865     }
866     Bind(&isIntOrNumber);
867     {
868         // The old array and new array are both MutantTaggedArray, so load and store the element directly.
869         // And barrier is not needed.
870         DoReverse(glue, thisValue, *receiver, false, false, MemoryAttribute::NoBarrier());
871         Jump(&afterReverse);
872     }
873     Bind(&isHoleOrIntOrNumber);
874     {
875         // The old array is mutant, but new array is TaggedArray, so load the value from old array with
876         // elements kind. And set it to new array directly, And barrier is not needed.
877         DoReverse(glue, thisValue, *receiver, true, true, MemoryAttribute::NoBarrier());
878         Jump(&afterReverse);
879     }
880     Bind(&afterReverse);
881     result->WriteVariable(*receiver);
882     Jump(exit);
883 }
884 
DoReverse(GateRef glue,GateRef fromArray,GateRef toArray,bool holeToUndefined,bool getWithKind,MemoryAttribute mAttr)885 void BuiltinsArrayStubBuilder::DoReverse(GateRef glue, GateRef fromArray, GateRef toArray, bool holeToUndefined,
886                                          bool getWithKind, MemoryAttribute mAttr)
887 {
888     auto env = GetEnvironment();
889     Label entry(env);
890     env->SubCfgEntry(&entry);
891     Label loopExit(env);
892     Label begin(env);
893     Label body(env);
894     Label endLoop(env);
895 
896     GateRef fromElements = GetElementsArray(glue, fromArray);
897     GateRef toElements = GetElementsArray(glue, toArray);
898     GateRef thisArrLen = GetArrayLength(fromArray);
899     DEFVARIABLE(index, VariableType::INT32(), Int32(0));
900     GateRef endIndex = Int32Sub(thisArrLen, Int32(1));
901     Jump(&begin);
902     LoopBegin(&begin);
903     {
904         BRANCH_LIKELY(Int32UnsignedLessThan(*index, thisArrLen), &body, &loopExit);
905         Bind(&body);
906         {
907             GateRef toIndex = Int32Sub(endIndex, *index);
908             // The old array and new array are both TaggedArray, so load and store the element directly.
909             // And barrier is needed.
910             GateRef value = getWithKind
911                                 ? GetTaggedValueWithElementsKind(glue, fromArray, *index)
912                                 : GetValueFromTaggedArray(glue, fromElements, *index);
913             if (holeToUndefined) {
914                 Label isHole(env);
915                 Label isNotHole(env);
916                 BRANCH_UNLIKELY(TaggedIsHole(value), &isHole, &isNotHole);
917                 Bind(&isHole);
918                 {
919                     // The return value of toReversed() is never sparse.
920                     // Empty slots become undefined in the returned array.
921                     SetValueToTaggedArray(VariableType::JS_ANY(), glue, toElements, toIndex, Undefined(),
922                                           MemoryAttribute::NoBarrier());
923                     Jump(&endLoop);
924                 }
925                 Bind(&isNotHole);
926             }
927             SetValueToTaggedArray(VariableType::JS_ANY(), glue, toElements, toIndex, value, mAttr);
928             Jump(&endLoop);
929         }
930     }
931     Bind(&endLoop);
932     index = Int32Add(*index, Int32(1));
933     LoopEnd(&begin);
934     Bind(&loopExit);
935     env->SubCfgExit();
936 }
937 
938 
939 // new an array, with specific hclass and length.
NewArrayWithHClass(GateRef glue,GateRef hclass,GateRef newArrayLen)940 GateRef BuiltinsArrayStubBuilder::NewArrayWithHClass(GateRef glue, GateRef hclass, GateRef newArrayLen)
941 {
942 #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC
943     GateRef globalEnv = GetCurrentGlobalEnv();
944     hclass = GetGlobalEnvValue(VariableType::JS_ANY(), glue, globalEnv,
945                                GlobalEnvField::ELEMENT_HOLE_TAGGED_HCLASS_INDEX);
946 #endif
947     // New an array with length.
948     auto env = GetEnvironment();
949     Label entry(env);
950     env->SubCfgEntry(&entry);
951     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
952     Label exit(env);
953     Label setProperties(env);
954     NewObjectStubBuilder newBuilder(this);
955     newBuilder.SetParameters(glue, Int32(0));
956     result = newBuilder.NewJSArrayWithHClass(hclass, newArrayLen);
957     BRANCH(TaggedIsException(*result), &exit, &setProperties);
958     Bind(&setProperties);
959     {
960         InitializeArray(glue, newArrayLen, &result);
961         Jump(&exit);
962     }
963     Bind(&exit);
964     auto res = *result;
965     env->SubCfgExit();
966     return res;
967 }
968 
FastToSpliced(GateRef glue,GateRef thisValue,GateRef newArray,GateRef actualStart,GateRef actualDeleteCount,GateRef insertCount,GateRef insertValue)969 void BuiltinsArrayStubBuilder::FastToSpliced(GateRef glue, GateRef thisValue, GateRef newArray, GateRef actualStart,
970                                              GateRef actualDeleteCount, GateRef insertCount, GateRef insertValue)
971 {
972     auto env = GetEnvironment();
973     Label entry(env);
974     env->SubCfgEntry(&entry);
975     Label copyBefore(env);
976     Label copyAfter(env);
977     Label insertArg(env);
978     Label exit(env);
979     GateRef srcElements = GetElementsArray(glue, thisValue);
980     GateRef dstElements = GetElementsArray(glue, newArray);
981     GateRef thisLength = GetLengthOfJSArray(thisValue);
982     BRANCH(Int32GreaterThan(actualStart, Int32(0)), &copyBefore, &insertArg);
983     Bind(&copyBefore);
984     {
985         GateRef srcStart = GetDataPtrInTaggedArray(srcElements);
986         GateRef dstStart = GetDataPtrInTaggedArray(dstElements);
987         ArrayCopyAndHoleToUndefined(glue, srcElements, srcStart, dstElements, dstStart, actualStart, Boolean(true));
988         Jump(&insertArg);
989     }
990     Bind(&insertArg);
991     {
992         Label insert(env);
993         BRANCH(Int32GreaterThan(insertCount, Int32(0)), &insert, &copyAfter);
994         Bind(&insert);
995         {
996             SetValueToTaggedArray(VariableType::JS_ANY(), glue, dstElements, actualStart, insertValue);
997             Jump(&copyAfter);
998         }
999     }
1000     Bind(&copyAfter);
1001     {
1002         Label canCopyAfter(env);
1003         Label setLength(env);
1004         GateRef oldIndex = Int32Add(actualStart, actualDeleteCount);
1005         GateRef newIndex = Int32Add(actualStart, insertCount);
1006         BRANCH(Int32LessThan(oldIndex, thisLength), &canCopyAfter, &setLength);
1007         Bind(&canCopyAfter);
1008         {
1009             GateRef srcStart = GetDataPtrInTaggedArray(srcElements, oldIndex);
1010             GateRef dstStart = GetDataPtrInTaggedArray(dstElements, newIndex);
1011             GateRef afterLength = Int32Sub(thisLength, oldIndex);
1012             ArrayCopyAndHoleToUndefined(glue, srcElements, srcStart, dstElements, dstStart, afterLength, Boolean(true));
1013             newIndex = Int32Add(newIndex, afterLength);
1014             Jump(&setLength);
1015         }
1016         Bind(&setLength);
1017         {
1018             SetArrayLength(glue, newArray, newIndex);
1019             Jump(&exit);
1020         }
1021     }
1022     Bind(&exit);
1023     env->SubCfgExit();
1024 }
1025 
ToSplicedOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1026 void BuiltinsArrayStubBuilder::ToSplicedOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1027                                          Variable *result, Label *exit, Label *slowPath)
1028 {
1029     auto env = GetEnvironment();
1030     Label isHeapObject(env);
1031     Label isJsArray(env);
1032     Label isStability(env);
1033     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1034     Bind(&isHeapObject);
1035     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1036     Bind(&isJsArray);
1037     // don't check constructor, "ToSpliced" always use ArrayCreate to create array.
1038     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1039     Bind(&isStability);
1040     Label notCOWArray(env);
1041     BRANCH(IsJsCOWArray(glue, thisValue), slowPath, &notCOWArray);
1042     Bind(&notCOWArray);
1043     GateRef thisLen = GetArrayLength(thisValue);
1044     Label lessThreeArg(env);
1045     DEFVARIABLE(actualStart, VariableType::INT32(), Int32(0));
1046     DEFVARIABLE(actualDeleteCount, VariableType::INT32(), Int32(0));
1047     DEFVARIABLE(newLen, VariableType::INT32(), Int32(0));
1048     DEFVARIABLE(insertCount, VariableType::INT32(), Int32(0));
1049     GateRef argc = ChangeIntPtrToInt32(numArgs);
1050     // 3: max arg count
1051     BRANCH(Int32LessThanOrEqual(argc, Int32(3)), &lessThreeArg, slowPath);
1052     Bind(&lessThreeArg);
1053     {
1054         Label checkOverFlow(env);
1055         Label greaterZero(env);
1056         Label greaterOne(env);
1057         Label checkGreaterOne(env);
1058         Label notOverFlow(env);
1059         Label copyAfter(env);
1060         // 0: judge the first arg exists
1061         BRANCH(Int32GreaterThan(argc, Int32(0)), &greaterZero, &checkGreaterOne);
1062         Bind(&greaterZero);
1063         {
1064             GateRef taggedStart = GetCallArg0(numArgs);
1065             Label taggedStartInt(env);
1066             BRANCH(TaggedIsInt(taggedStart), &taggedStartInt, slowPath);
1067             Bind(&taggedStartInt);
1068             {
1069                 GateRef intStart = GetInt32OfTInt(taggedStart);
1070                 actualStart = CalArrayRelativePos(intStart, thisLen);
1071                 actualDeleteCount = Int32Sub(thisLen, *actualStart);
1072                 Jump(&checkGreaterOne);
1073             }
1074         }
1075         Bind(&checkGreaterOne);
1076         {
1077             // 1: judge the second arg exists
1078             BRANCH(Int32GreaterThan(argc, Int32(1)), &greaterOne, &checkOverFlow);
1079             Bind(&greaterOne);
1080             {
1081                 // 2: arg count which is not an item
1082                 insertCount = Int32Sub(argc, Int32(2));
1083                 GateRef argDeleteCount = GetCallArg1(numArgs);
1084                 Label argDeleteCountInt(env);
1085                 BRANCH(TaggedIsInt(argDeleteCount), &argDeleteCountInt, slowPath);
1086                 Bind(&argDeleteCountInt);
1087                 {
1088                     DEFVARIABLE(deleteCount, VariableType::INT32(), TaggedGetInt(argDeleteCount));
1089                     Label deleteCountLessZero(env);
1090                     Label calActualDeleteCount(env);
1091                     BRANCH(Int32LessThan(*deleteCount, Int32(0)), &deleteCountLessZero, &calActualDeleteCount);
1092                     Bind(&deleteCountLessZero);
1093                     {
1094                         deleteCount = Int32(0);
1095                         Jump(&calActualDeleteCount);
1096                     }
1097                     Bind(&calActualDeleteCount);
1098                     {
1099                         actualDeleteCount = *deleteCount;
1100                         Label lessArrayLen(env);
1101                         BRANCH(Int32LessThan(Int32Sub(thisLen, *actualStart), *deleteCount),
1102                                &lessArrayLen, &checkOverFlow);
1103                         Bind(&lessArrayLen);
1104                         {
1105                             actualDeleteCount = Int32Sub(thisLen, *actualStart);
1106                             Jump(&checkOverFlow);
1107                         }
1108                     }
1109                 }
1110             }
1111             Bind(&checkOverFlow);
1112             {
1113                 newLen = Int32Add(Int32Sub(thisLen, *actualDeleteCount), *insertCount);
1114                 BRANCH(Int64GreaterThan(ZExtInt32ToInt64(*newLen), Int64(base::MAX_SAFE_INTEGER)),
1115                        slowPath, &notOverFlow);
1116                 Bind(&notOverFlow);
1117                 Label newLenEmpty(env);
1118                 Label newLenNotEmpty(env);
1119                 BRANCH(Int32Equal(*newLen, Int32(0)), &newLenEmpty, &newLenNotEmpty);
1120                 Bind(&newLenEmpty);
1121                 {
1122                     NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
1123                     result->WriteVariable(newBuilder.CreateEmptyArray(glue));
1124                     Jump(exit);
1125                 }
1126                 Bind(&newLenNotEmpty);
1127                 {
1128                     Label copyBefore(env);
1129                     Label insertArg(env);
1130                     Label mutantArrayToSpliced(env);
1131                     Label fastToSpliced(env);
1132                     BRANCH_UNLIKELY(IsEnableMutantArray(glue), &mutantArrayToSpliced, &fastToSpliced);
1133                     Bind(&fastToSpliced);
1134                     {
1135                         GateRef globalEnv = GetCurrentGlobalEnv();
1136                         GateRef newHClass =
1137                             GetGlobalEnvValue(VariableType::JS_ANY(), glue, globalEnv,
1138                                 static_cast<size_t>(GlobalEnvField::ELEMENT_TAGGED_HCLASS_INDEX));
1139                         GateRef newArray = NewArrayWithHClass(glue, newHClass, *newLen);
1140                         FastToSpliced(glue, thisValue, newArray, *actualStart, *actualDeleteCount, *insertCount,
1141                                       GetCallArg2(numArgs));
1142                         result->WriteVariable(newArray);
1143                         Jump(exit);
1144                     }
1145                     Bind(&mutantArrayToSpliced);
1146                     GateRef newArray = NewArray(glue, Int32(0));
1147                     GrowElementsCapacity(glue, newArray, *newLen);
1148                     DEFVARIABLE(oldIndex, VariableType::INT32(), Int32(0));
1149                     DEFVARIABLE(newIndex, VariableType::INT32(), Int32(0));
1150                     BRANCH(Int32GreaterThan(*actualStart, Int32(0)), &copyBefore, &insertArg);
1151                     Bind(&copyBefore);
1152                     {
1153                         Label loopHead(env);
1154                         Label loopEnd(env);
1155                         Label loopNext(env);
1156                         Label loopExit(env);
1157                         Label eleIsHole(env);
1158                         Label eleNotHole(env);
1159                         Jump(&loopHead);
1160                         LoopBegin(&loopHead);
1161                         {
1162                             BRANCH(Int32LessThan(*oldIndex, *actualStart), &loopNext, &loopExit);
1163                             Bind(&loopNext);
1164                             GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *oldIndex);
1165                             BRANCH(TaggedIsHole(ele), &eleIsHole, &eleNotHole);
1166                             Bind(&eleIsHole);
1167                             {
1168                                 SetValueWithElementsKind(glue, newArray, Undefined(), *newIndex, Boolean(true),
1169                                                          Int32(Elements::ToUint(ElementsKind::NONE)));
1170                                 Jump(&loopEnd);
1171                             }
1172                             Bind(&eleNotHole);
1173                             {
1174                                 SetValueWithElementsKind(glue, newArray, ele, *newIndex, Boolean(true),
1175                                                          Int32(Elements::ToUint(ElementsKind::NONE)));
1176                                 Jump(&loopEnd);
1177                             }
1178                         }
1179                         Bind(&loopEnd);
1180                         oldIndex = Int32Add(*oldIndex, Int32(1));
1181                         newIndex = Int32Add(*newIndex, Int32(1));
1182                         LoopEnd(&loopHead);
1183                         Bind(&loopExit);
1184                         Jump(&insertArg);
1185                     }
1186                     Bind(&insertArg);
1187                     {
1188                         Label insert(env);
1189                         BRANCH(Int32GreaterThan(*insertCount, Int32(0)), &insert, &copyAfter);
1190                         Bind(&insert);
1191                         {
1192                             GateRef insertNum = GetCallArg2(numArgs);
1193                             SetValueWithElementsKind(glue, newArray, insertNum, *newIndex, Boolean(true),
1194                                                      Int32(Elements::ToUint(ElementsKind::NONE)));
1195                             newIndex = Int32Add(*newIndex, Int32(1));
1196                             Jump(&copyAfter);
1197                         }
1198                     }
1199                     Bind(&copyAfter);
1200                     {
1201                         Label canCopyAfter(env);
1202                         Label setLength(env);
1203                         oldIndex = Int32Add(*actualStart, *actualDeleteCount);
1204                         BRANCH(Int32LessThan(*oldIndex, thisLen), &canCopyAfter, &setLength);
1205                         Bind(&canCopyAfter);
1206                         {
1207                             Label loopHead1(env);
1208                             Label loopNext1(env);
1209                             Label loopEnd1(env);
1210                             Label loopExit1(env);
1211                             Label ele1IsHole(env);
1212                             Label ele1NotHole(env);
1213                             Jump(&loopHead1);
1214                             LoopBegin(&loopHead1);
1215                             {
1216                                 BRANCH(Int32LessThan(*oldIndex, thisLen), &loopNext1, &loopExit1);
1217                                 Bind(&loopNext1);
1218                                 GateRef ele1 = GetTaggedValueWithElementsKind(glue, thisValue, *oldIndex);
1219                                 BRANCH(TaggedIsHole(ele1), &ele1IsHole, &ele1NotHole);
1220                                 Bind(&ele1IsHole);
1221                                 {
1222                                     SetValueWithElementsKind(glue, newArray, Undefined(), *newIndex, Boolean(true),
1223                                                              Int32(Elements::ToUint(ElementsKind::NONE)));
1224                                     Jump(&loopEnd1);
1225                                 }
1226                                 Bind(&ele1NotHole);
1227                                 {
1228                                     SetValueWithElementsKind(glue, newArray, ele1, *newIndex, Boolean(true),
1229                                                              Int32(Elements::ToUint(ElementsKind::NONE)));
1230                                     Jump(&loopEnd1);
1231                                 }
1232                             }
1233                             Bind(&loopEnd1);
1234                             oldIndex = Int32Add(*oldIndex, Int32(1));
1235                             newIndex = Int32Add(*newIndex, Int32(1));
1236                             LoopEnd(&loopHead1);
1237                             Bind(&loopExit1);
1238                             Jump(&setLength);
1239                         }
1240                         Bind(&setLength);
1241                         {
1242                             SetArrayLength(glue, newArray, *newLen);
1243                             result->WriteVariable(newArray);
1244                             Jump(exit);
1245                         }
1246                     }
1247                 }
1248             }
1249         }
1250     }
1251 }
1252 
FindOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1253 void BuiltinsArrayStubBuilder::FindOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1254                                              Variable *result, Label *exit, Label *slowPath)
1255 {
1256     auto env = GetEnvironment();
1257     Label isHeapObject(env);
1258     Label isJsArray(env);
1259     Label standardPath(env);
1260     Label compatiblePath(env);
1261     BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1262     Bind(&isHeapObject);
1263     BRANCH_LIKELY(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1264     Bind(&isJsArray);
1265     GateRef isStandard = LogicOrBuilder(env)
1266                          .Or(HasConstructor(glue, thisValue))
1267                          .Or(BoolNot(IsStableJSArray(glue, thisValue)))
1268                          .Or(IsJsCOWArray(glue, thisValue))
1269                          .Done();
1270     BRANCH_NO_WEIGHT(isStandard, &standardPath, &compatiblePath);
1271     Bind(&standardPath);
1272     {
1273         FindOrFindIndex(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodFind, Option::Standard});
1274     }
1275     Bind(&compatiblePath);
1276     {
1277         FindOrFindIndex(glue, thisValue, numArgs, result, exit, slowPath,
1278                         {Option::MethodFind, Option::Compatible5_0_0});
1279     }
1280 }
1281 
FindIndexOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1282 void BuiltinsArrayStubBuilder::FindIndexOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1283                                                   Variable *result, Label *exit, Label *slowPath)
1284 {
1285     auto env = GetEnvironment();
1286     Label isHeapObject(env);
1287     Label isJsArray(env);
1288     Label standardPath(env);
1289     Label compatiblePath(env);
1290     BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1291     Bind(&isHeapObject);
1292     BRANCH_LIKELY(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1293     Bind(&isJsArray);
1294     GateRef isStandard = LogicOrBuilder(env)
1295                          .Or(HasConstructor(glue, thisValue))
1296                          .Or(IsJsCOWArray(glue, thisValue))
1297                          .Done();
1298     BRANCH_NO_WEIGHT(isStandard, &standardPath, &compatiblePath);
1299     Bind(&standardPath);
1300     {
1301         FindOrFindIndex(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodFindIndex, Option::Standard});
1302     }
1303     Bind(&compatiblePath);
1304     {
1305         FindOrFindIndex(glue, thisValue, numArgs, result, exit, slowPath,
1306                         {Option::MethodFindIndex, Option::Compatible5_0_0});
1307     }
1308 }
1309 
FindOrFindIndex(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,const Option option)1310 void BuiltinsArrayStubBuilder::FindOrFindIndex(GateRef glue, GateRef thisValue, GateRef numArgs,
1311                                                Variable *result, Label *exit, Label *slowPath,
1312                                                const Option option)
1313 {
1314     ASSERT((option.kind == Option::MethodFind || option.kind == Option::MethodFindIndex)
1315         && "Unexpected kind in FindOrFindIndex");
1316     auto env = GetEnvironment();
1317     Label arg0HeapObject(env);
1318     Label callable(env);
1319     Label stableJSArray(env);
1320     Label notStableJSArray(env);
1321     GateRef callbackFnHandle = GetCallArg0(numArgs);
1322     BRANCH_LIKELY(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
1323     Bind(&arg0HeapObject);
1324     BRANCH_LIKELY(IsCallable(glue, callbackFnHandle), &callable, slowPath);
1325     Bind(&callable);
1326 
1327     result->WriteVariable(option.kind == Option::MethodFindIndex ? IntToTaggedPtr(Int32(-1)) : Undefined());
1328     GateRef argHandle = GetCallArg1(numArgs);
1329     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
1330     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
1331     BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &stableJSArray, &notStableJSArray);
1332     Bind(&stableJSArray);
1333     {
1334         Label loopHead(env);
1335         Label loopEnd(env);
1336         Label next(env);
1337         Label loopExit(env);
1338         Jump(&loopHead);
1339         LoopBegin(&loopHead);
1340         {
1341             DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
1342             Label useUndefined(env);
1343             Label getValue(env);
1344             Label callback(env);
1345             BRANCH_NO_WEIGHT(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
1346             Bind(&next);
1347             if (option.mode == Option::Standard) {
1348                 GateRef arrayLen = GetArrayLength(thisValue);
1349                 BRANCH_LIKELY(Int64LessThan(*i,  ZExtInt32ToInt64(arrayLen)), &getValue, &useUndefined);
1350                 Bind(&getValue);
1351             }
1352             {
1353                 kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
1354                 BRANCH_UNLIKELY(TaggedIsHole(*kValue), &useUndefined, &callback);
1355             }
1356             Bind(&useUndefined);
1357             {
1358                 kValue = Undefined();
1359                 Jump(&callback);
1360             }
1361             Bind(&callback);
1362             {
1363                 GateRef key = IntToTaggedPtr(*i);
1364                 Label hasException(env);
1365                 Label notHasException(env);
1366                 Label checkStable(env);
1367                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1368                 callArgs.callThisArg3WithReturnArgs = { argHandle, *kValue, key, thisValue };
1369                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
1370                     Circuit::NullGate(), callArgs);
1371                 GateRef retValue = callBuilder.JSCallDispatch();
1372                 BRANCH_UNLIKELY(HasPendingException(glue), &hasException, &notHasException);
1373                 Bind(&hasException);
1374                 {
1375                     result->WriteVariable(retValue);
1376                     Jump(exit);
1377                 }
1378                 Bind(&notHasException);
1379                 {
1380                     Label find(env);
1381                     BRANCH_NO_WEIGHT(TaggedIsTrue(FastToBoolean(glue, retValue)), &find, &checkStable);
1382                     Bind(&find);
1383                     {
1384                         result->WriteVariable(option.kind == Option::MethodFindIndex ? key : *kValue);
1385                         Jump(exit);
1386                     }
1387                 }
1388                 Bind(&checkStable);
1389                 i = Int64Add(*i, Int64(1));
1390                 BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
1391             }
1392         }
1393         Bind(&loopEnd);
1394         if (option.mode == Option::Compatible5_0_0) {
1395             // In version 5.0.0, the iterator length will be updated if the length of array changed
1396             // be compatible with this behaviour.
1397             thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1398         }
1399         LoopEnd(&loopHead);
1400         Bind(&loopExit);
1401         Jump(exit);
1402     }
1403     Bind(&notStableJSArray);
1404     {
1405         Label loopHead(env);
1406         Label loopEnd(env);
1407         Label next(env);
1408         Label loopExit(env);
1409         Jump(&loopHead);
1410         LoopBegin(&loopHead);
1411         {
1412             BRANCH_NO_WEIGHT(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
1413             Bind(&next);
1414             {
1415                 Label hasException0(env);
1416                 Label notHasException0(env);
1417                 GateRef kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
1418                 BRANCH_UNLIKELY(HasPendingException(glue), &hasException0, &notHasException0);
1419                 Bind(&hasException0);
1420                 {
1421                     result->WriteVariable(Exception());
1422                     Jump(exit);
1423                 }
1424                 Bind(&notHasException0);
1425                 {
1426                     GateRef key = IntToTaggedPtr(*i);
1427                     Label hasException(env);
1428                     Label notHasException(env);
1429                     JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1430                     callArgs.callThisArg3WithReturnArgs = { argHandle, kValue, key, thisValue };
1431                     CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
1432                         nullptr, Circuit::NullGate(), callArgs);
1433                     GateRef retValue = callBuilder.JSCallDispatch();
1434                     BRANCH_UNLIKELY(TaggedIsException(retValue), &hasException, &notHasException);
1435                     Bind(&hasException);
1436                     {
1437                         result->WriteVariable(retValue);
1438                         Jump(exit);
1439                     }
1440                     Bind(&notHasException);
1441                     {
1442                         Label find(env);
1443                         BRANCH_NO_WEIGHT(TaggedIsTrue(FastToBoolean(glue, retValue)), &find, &loopEnd);
1444                         Bind(&find);
1445                         {
1446                             result->WriteVariable(option.kind == Option::MethodFindIndex ? key : kValue);
1447                             Jump(exit);
1448                         }
1449                     }
1450                 }
1451             }
1452         }
1453         Bind(&loopEnd);
1454         i = Int64Add(*i, Int64(1));
1455         if (option.mode == Option::Compatible5_0_0) {
1456             // In version 5.0.0, the iterator length will be updated if the length of array changed
1457             // be compatible with this behaviour.
1458             thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1459         }
1460         LoopEnd(&loopHead);
1461         Bind(&loopExit);
1462         Jump(exit);
1463     }
1464 }
1465 
EveryOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1466 void BuiltinsArrayStubBuilder::EveryOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1467                                               Variable *result, Label *exit, Label *slowPath)
1468 {
1469     auto env = GetEnvironment();
1470     Label isHeapObject(env);
1471     Label isJsArray(env);
1472     Label standardPath(env);
1473     Label compatiblePath(env);
1474     Label thisExists(env);
1475     BRANCH_UNLIKELY(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
1476     Bind(&thisExists);
1477     BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1478     Bind(&isHeapObject);
1479     BRANCH_LIKELY(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1480     Bind(&isJsArray);
1481     result->WriteVariable(TaggedTrue());
1482     GateRef isStandard = LogicOrBuilder(env)
1483                          .Or(HasConstructor(glue, thisValue))
1484                          .Or(BoolNot(IsStableJSArray(glue, thisValue)))
1485                          .Or(IsJsCOWArray(glue, thisValue))
1486                          .Done();
1487     BRANCH_NO_WEIGHT(isStandard, &standardPath, &compatiblePath);
1488     Bind(&standardPath);
1489     {
1490         VisitAll(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodEvery, Option::Standard});
1491     }
1492     Bind(&compatiblePath);
1493     {
1494         VisitAll(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodEvery, Option::Compatible5_0_0});
1495     }
1496 };
1497 
SomeOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1498 void BuiltinsArrayStubBuilder::SomeOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1499                                              Variable *result, Label *exit, Label *slowPath)
1500 {
1501     auto env = GetEnvironment();
1502     Label isHeapObject(env);
1503     Label isJsArray(env);
1504     Label standardPath(env);
1505     Label compatiblePath(env);
1506     Label thisExists(env);
1507     BRANCH_UNLIKELY(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
1508     Bind(&thisExists);
1509     BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1510     Bind(&isHeapObject);
1511     BRANCH_LIKELY(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1512     Bind(&isJsArray);
1513     result->WriteVariable(TaggedFalse());
1514     GateRef isStandard = LogicOrBuilder(env)
1515                          .Or(HasConstructor(glue, thisValue))
1516                          .Or(BoolNot(IsStableJSArray(glue, thisValue)))
1517                          .Or(IsJsCOWArray(glue, thisValue))
1518                          .Done();
1519     BRANCH_NO_WEIGHT(isStandard, &standardPath, &compatiblePath);
1520     Bind(&standardPath);
1521     {
1522         VisitAll(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodSome, Option::Standard});
1523     }
1524     Bind(&compatiblePath);
1525     {
1526         VisitAll(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodSome, Option::Compatible5_0_0});
1527     }
1528 };
1529 
ForEachOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1530 void BuiltinsArrayStubBuilder::ForEachOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1531                                                 Variable *result, Label *exit, Label *slowPath)
1532 {
1533     auto env = GetEnvironment();
1534     Label isHeapObject(env);
1535     Label isJsArray(env);
1536     Label thisExists(env);
1537     BRANCH_UNLIKELY(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
1538     Bind(&thisExists);
1539     BRANCH_LIKELY(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1540     Bind(&isHeapObject);
1541     BRANCH_LIKELY(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1542     Bind(&isJsArray);
1543     result->WriteVariable(Undefined());
1544     VisitAll(glue, thisValue, numArgs, result, exit, slowPath, {Option::MethodForEach, Option::Standard});
1545 };
1546 
VisitAll(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,const Option option)1547 void BuiltinsArrayStubBuilder::VisitAll(GateRef glue, GateRef thisValue, GateRef numArgs,
1548                                         Variable *result, Label *exit, Label *slowPath, const Option option)
1549 {
1550     ASSERT((option.kind == Option::MethodEvery || option.kind == Option::MethodSome
1551         || option.kind == Option::MethodForEach) && "Unexpected kind in VisitAll");
1552     auto env = GetEnvironment();
1553     Label arg0HeapObject(env);
1554     Label callable(env);
1555     GateRef callbackFnHandle = GetCallArg0(numArgs);
1556     BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
1557     Bind(&arg0HeapObject);
1558     BRANCH(IsCallable(glue, callbackFnHandle), &callable, slowPath);
1559     Bind(&callable);
1560 
1561     Label returnFalse(env);
1562     Label returnTrue(env);
1563 
1564     Label thisIsStable(env);
1565     Label thisNotStable(env);
1566     GateRef argHandle = GetCallArg1(numArgs);
1567     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
1568     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
1569     BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &thisIsStable, &thisNotStable);
1570 
1571     Bind(&thisIsStable);
1572     {
1573         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
1574         Label loopHead(env);
1575         Label loopEnd(env);
1576         Label next(env);
1577         Jump(&loopHead);
1578         LoopBegin(&loopHead);
1579         {
1580             Label callDispatch(env);
1581             BRANCH_NO_WEIGHT(Int64LessThan(*i, *thisArrLen), &next, exit);
1582             Bind(&next);
1583             kValue = GetTaggedValueWithElementsKind(glue, thisValue, *i);
1584             BRANCH_UNLIKELY(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
1585             Bind(&callDispatch);
1586             {
1587                 Label hasException(env);
1588                 Label noException(env);
1589                 GateRef key = Int64ToTaggedInt(*i);
1590                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1591                 callArgs.callThisArg3WithReturnArgs = {argHandle, *kValue, key, thisValue};
1592                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
1593                                             Circuit::NullGate(), callArgs);
1594                 GateRef retValue = callBuilder.JSCallDispatch();
1595                 BRANCH_UNLIKELY(HasPendingException(glue), &hasException, &noException);
1596                 Bind(&hasException);
1597                 {
1598                     result->WriteVariable(Exception());
1599                     Jump(exit);
1600                 }
1601                 Bind(&noException);
1602                 {
1603                     Label checkLength(env);
1604                     Label checkStable(env);
1605                     if (option.kind == Option::MethodEvery) {
1606                         BRANCH_NO_WEIGHT(TaggedIsFalse(FastToBoolean(glue, retValue)), &returnFalse, &checkLength);
1607                     }
1608                     if (option.kind == Option::MethodSome) {
1609                         BRANCH_NO_WEIGHT(TaggedIsTrue(FastToBoolean(glue, retValue)), &returnTrue, &checkLength);
1610                     }
1611                     if (option.kind == Option::MethodForEach) {
1612                         Jump(&checkLength);
1613                     }
1614                     Bind(&checkLength);
1615                     {
1616                         GateRef newLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1617                         if (option.mode == Option::Compatible5_0_0) {
1618                             // In version 5.0.0, the iterator length will be updated if the length of array be shorter.
1619                             // be compatible with this behaviour.
1620                             Label changeThisLen(env);
1621                             BRANCH(Int64LessThan(newLen, *thisArrLen), &changeThisLen, &checkStable);
1622                             Bind(&changeThisLen);
1623                             {
1624                                 thisArrLen = newLen;
1625                                 Jump(&checkStable);
1626                             }
1627                         } else if (option.mode == Option::Standard) {
1628                             BRANCH_LIKELY(Int64LessThan(Int64Add(*i, Int64(1)), newLen), &checkStable, exit);
1629                         }
1630                     }
1631                     Bind(&checkStable);
1632                     {
1633                         Label changeToNotStable(env);
1634                         BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &loopEnd, &changeToNotStable);
1635                         Bind(&changeToNotStable);
1636                         {
1637                             i = Int64Add(*i, Int64(1));
1638                             Jump(&thisNotStable);
1639                         }
1640                     }
1641                 }
1642             }
1643         }
1644         Bind(&loopEnd);
1645         i = Int64Add(*i, Int64(1));
1646         LoopEnd(&loopHead);
1647     }
1648 
1649     Bind(&thisNotStable);
1650     {
1651         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
1652         Label loopHead(env);
1653         Label loopEnd(env);
1654         Label next(env);
1655         Jump(&loopHead);
1656         LoopBegin(&loopHead);
1657         {
1658             Label hasProperty(env);
1659             Label hasException0(env);
1660             Label notHasException0(env);
1661             Label callDispatch(env);
1662             Label hasException1(env);
1663             Label notHasException1(env);
1664             BRANCH_NO_WEIGHT(Int64LessThan(*i, *thisArrLen), &next, exit);
1665             Bind(&next);
1666 #if ENABLE_NEXT_OPTIMIZATION
1667             GateRef hasProp = CallCommonStub(glue, CommonStubCSigns::JSTaggedValueHasProperty,
1668                                              { glue, thisValue, IntToTaggedPtr(*i), GetCurrentGlobalEnv() });
1669 #else
1670             GateRef hasProp = CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
1671                 RTSTUB_ID(HasProperty), {thisValue, IntToTaggedInt(*i)});
1672 #endif
1673             BRANCH_LIKELY(TaggedIsTrue(hasProp), &hasProperty, &loopEnd);
1674             Bind(&hasProperty);
1675             kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
1676             BRANCH_UNLIKELY(HasPendingException(glue), &hasException0, &notHasException0);
1677             Bind(&hasException0);
1678             {
1679                 result->WriteVariable(Exception());
1680                 Jump(exit);
1681             }
1682             Bind(&notHasException0);
1683             {
1684                 BRANCH_UNLIKELY(TaggedIsHole(*kValue), &loopEnd, &callDispatch);
1685                 Bind(&callDispatch);
1686                 GateRef key = Int64ToTaggedInt(*i);
1687                 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
1688                 callArgs.callThisArg3WithReturnArgs = {argHandle, *kValue, key, thisValue};
1689                 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
1690                                             Circuit::NullGate(), callArgs);
1691                 GateRef retValue = callBuilder.JSCallDispatch();
1692                 BRANCH_UNLIKELY(HasPendingException(glue), &hasException1, &notHasException1);
1693                 Bind(&hasException1);
1694                 {
1695                     result->WriteVariable(Exception());
1696                     Jump(exit);
1697                 }
1698                 Bind(&notHasException1);
1699                 {
1700                     if (option.kind == Option::MethodEvery) {
1701                         BRANCH_NO_WEIGHT(TaggedIsFalse(FastToBoolean(glue, retValue)), &returnFalse, &loopEnd);
1702                     }
1703                     if (option.kind == Option::MethodSome) {
1704                         BRANCH_NO_WEIGHT(TaggedIsTrue(FastToBoolean(glue, retValue)), &returnTrue, &loopEnd);
1705                     }
1706                     if (option.kind == Option::MethodForEach) {
1707                         Jump(&loopEnd);
1708                     }
1709                 }
1710             }
1711         }
1712         Bind(&loopEnd);
1713         i = Int64Add(*i, Int64(1));
1714         LoopEnd(&loopHead);
1715     }
1716     if (option.kind == Option::MethodEvery) {
1717         Bind(&returnFalse);
1718         {
1719             result->WriteVariable(TaggedFalse());
1720             Jump(exit);
1721         }
1722     }
1723     if (option.kind == Option::MethodSome) {
1724         Bind(&returnTrue);
1725         {
1726             result->WriteVariable(TaggedTrue());
1727             Jump(exit);
1728         }
1729     }
1730 }
1731 
PopOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1732 void BuiltinsArrayStubBuilder::PopOptimised(GateRef glue, GateRef thisValue,
1733     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1734 {
1735     auto env = GetEnvironment();
1736     Label isHeapObject(env);
1737     Label stableJSArray(env);
1738     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1739     Bind(&isHeapObject);
1740     // don't check constructor, "Pop" won't create new array.
1741     BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
1742     Bind(&stableJSArray);
1743 
1744     Label isLengthWritable(env);
1745     BRANCH_LIKELY(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
1746     Bind(&isLengthWritable);
1747     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1748     Label notZeroLen(env);
1749     BRANCH_UNLIKELY(Int64Equal(thisLen, Int64(0)), exit, &notZeroLen);
1750     Bind(&notZeroLen);
1751     Label isJsCOWArray(env);
1752     Label getElements(env);
1753     BRANCH_NO_WEIGHT(IsJsCOWArray(glue, thisValue), &isJsCOWArray, &getElements);
1754     Bind(&isJsCOWArray);
1755     {
1756         NewObjectStubBuilder newBuilder(this);
1757         GateRef elements = GetElementsArray(glue, thisValue);
1758         GateRef capacity = GetLengthOfTaggedArray(elements);
1759         GateRef newElements = newBuilder.CopyArray(glue, elements, capacity, capacity);
1760         SetElementsArray(VariableType::JS_POINTER(), glue, thisValue, newElements);
1761         Jump(&getElements);
1762     }
1763     Bind(&getElements);
1764     GateRef elements = GetElementsArray(glue, thisValue);
1765     GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(elements));
1766     GateRef index = Int64Sub(thisLen, Int64(1));
1767 
1768     Label inRange(env);
1769     Label trimCheck(env);
1770     Label noTrimCheck(env);
1771     Label setNewLen(env);
1772 
1773     GateRef enableMutant = IsEnableMutantArray(glue);
1774     DEFVARIABLE(element, VariableType::JS_ANY(), Hole());
1775     BRANCH(Int64LessThan(index, capacity), &inRange, &trimCheck);
1776     Bind(&inRange);
1777     {
1778         Label enableMutantArray(env);
1779         Label disableMutantArray(env);
1780         BRANCH(enableMutant, &enableMutantArray, &disableMutantArray);
1781         Bind(&enableMutantArray);
1782         {
1783             element = GetTaggedValueWithElementsKind(glue, thisValue, index);
1784             Jump(&trimCheck);
1785         }
1786         Bind(&disableMutantArray);
1787         {
1788             element = GetValueFromTaggedArray(glue, elements, TruncInt64ToInt32(index));
1789             Jump(&trimCheck);
1790         }
1791     }
1792     Bind(&trimCheck);
1793     // ShouldTrim check
1794     // (oldLength - newLength > MAX_END_UNUSED)
1795     Label noTrim(env);
1796     Label needTrim(env);
1797     GateRef unused = Int64Sub(capacity, index);
1798     BRANCH_UNLIKELY(Int64GreaterThan(unused, Int64(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim);
1799     Bind(&needTrim);
1800     {
1801         CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, index});
1802         Jump(&setNewLen);
1803     }
1804     Bind(&noTrim);
1805     {
1806         Label enableMutantArray(env);
1807         Label disableMutantArray(env);
1808         BRANCH_UNLIKELY(enableMutant, &enableMutantArray, &disableMutantArray);
1809         Bind(&enableMutantArray);
1810         {
1811             SetValueWithElementsKind(glue, thisValue, Hole(), index, Boolean(false),
1812                                      Int32(Elements::ToUint(ElementsKind::NONE)));
1813             Jump(&setNewLen);
1814         }
1815         Bind(&disableMutantArray);
1816         {
1817             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements,
1818                                   TruncInt64ToInt32(index), Hole(), MemoryAttribute::NoBarrier());
1819             Jump(&setNewLen);
1820         }
1821     }
1822     Bind(&setNewLen);
1823     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
1824     Store(VariableType::INT32(), glue, thisValue, lengthOffset, TruncInt64ToInt32(index));
1825     Label isNotHole(env);
1826     BRANCH(TaggedIsHole(*element), exit, &isNotHole);
1827     Bind(&isNotHole);
1828     {
1829         result->WriteVariable(*element);
1830         Jump(exit);
1831     }
1832 }
1833 
SliceOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1834 void BuiltinsArrayStubBuilder::SliceOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
1835     Variable *result, Label *exit, Label *slowPath)
1836 {
1837     auto env = GetEnvironment();
1838     Label isHeapObject(env);
1839     Label isJsArray(env);
1840     Label noConstructor(env);
1841     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1842     Bind(&isHeapObject);
1843     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
1844     Bind(&isJsArray);
1845     // need check constructor, "Slice" should use ArraySpeciesCreate
1846     BRANCH(HasConstructor(glue, thisValue), slowPath, &noConstructor);
1847     Bind(&noConstructor);
1848 
1849     Label thisIsEmpty(env);
1850     Label thisNotEmpty(env);
1851     // Fast path if:
1852     // (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details);
1853     // (2) no arguments exist
1854     JsArrayRequirements req;
1855     req.defaultConstructor = true;
1856     BRANCH(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, &thisNotEmpty);
1857     Bind(&thisIsEmpty);
1858     {
1859         Label noArgs(env);
1860         GateRef numArgsAsInt32 = TruncPtrToInt32(numArgs);
1861         BRANCH(Int32Equal(numArgsAsInt32, Int32(0)), &noArgs, slowPath);
1862         // Creates a new empty array on fast path
1863         Bind(&noArgs);
1864         NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
1865         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
1866         Jump(exit);
1867     }
1868     Bind(&thisNotEmpty);
1869     {
1870         Label stableJSArray(env);
1871         Label arrayLenNotZero(env);
1872 
1873         GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue);
1874         BRANCH(isThisStableJSArray, &stableJSArray, slowPath);
1875         Bind(&stableJSArray);
1876 
1877         GateRef msg0 = GetCallArg0(numArgs);
1878         GateRef msg1 = GetCallArg1(numArgs);
1879         GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1880         Label msg0Int(env);
1881         BRANCH(TaggedIsInt(msg0), &msg0Int, slowPath);
1882         Bind(&msg0Int);
1883         DEFVARIABLE(start, VariableType::INT64(), Int64(0));
1884         DEFVARIABLE(end, VariableType::INT64(), thisArrLen);
1885 
1886         GateRef argStart = SExtInt32ToInt64(TaggedGetInt(msg0));
1887         Label arg0LessZero(env);
1888         Label arg0NotLessZero(env);
1889         Label startDone(env);
1890         BRANCH(Int64LessThan(argStart, Int64(0)), &arg0LessZero, &arg0NotLessZero);
1891         Bind(&arg0LessZero);
1892         {
1893             Label tempGreaterZero(env);
1894             Label tempNotGreaterZero(env);
1895             GateRef tempStart = Int64Add(argStart, thisArrLen);
1896             BRANCH(Int64GreaterThan(tempStart, Int64(0)), &tempGreaterZero, &tempNotGreaterZero);
1897             Bind(&tempGreaterZero);
1898             {
1899                 start = tempStart;
1900                 Jump(&startDone);
1901             }
1902             Bind(&tempNotGreaterZero);
1903             {
1904                 Jump(&startDone);
1905             }
1906         }
1907         Bind(&arg0NotLessZero);
1908         {
1909             Label argLessLen(env);
1910             Label argNotLessLen(env);
1911             BRANCH(Int64LessThan(argStart, thisArrLen), &argLessLen, &argNotLessLen);
1912             Bind(&argLessLen);
1913             {
1914                 start = argStart;
1915                 Jump(&startDone);
1916             }
1917             Bind(&argNotLessLen);
1918             {
1919                 start = thisArrLen;
1920                 Jump(&startDone);
1921             }
1922         }
1923         Bind(&startDone);
1924         {
1925             Label endDone(env);
1926             Label msg1Def(env);
1927             BRANCH(TaggedIsUndefined(msg1), &endDone, &msg1Def);
1928             Bind(&msg1Def);
1929             {
1930                 Label msg1Int(env);
1931                 BRANCH(TaggedIsInt(msg1), &msg1Int, slowPath);
1932                 Bind(&msg1Int);
1933                 {
1934                     GateRef argEnd = SExtInt32ToInt64(TaggedGetInt(msg1));
1935                     Label arg1LessZero(env);
1936                     Label arg1NotLessZero(env);
1937                     BRANCH(Int64LessThan(argEnd, Int64(0)), &arg1LessZero, &arg1NotLessZero);
1938                     Bind(&arg1LessZero);
1939                     {
1940                         Label tempGreaterZero(env);
1941                         Label tempNotGreaterZero(env);
1942                         GateRef tempEnd = Int64Add(argEnd, thisArrLen);
1943                         BRANCH(Int64GreaterThan(tempEnd, Int64(0)), &tempGreaterZero, &tempNotGreaterZero);
1944                         Bind(&tempGreaterZero);
1945                         {
1946                             end = tempEnd;
1947                             Jump(&endDone);
1948                         }
1949                         Bind(&tempNotGreaterZero);
1950                         {
1951                             end = Int64(0);
1952                             Jump(&endDone);
1953                         }
1954                     }
1955                     Bind(&arg1NotLessZero);
1956                     {
1957                         Label argLessLen(env);
1958                         Label argNotLessLen(env);
1959                         BRANCH(Int64LessThan(argEnd, thisArrLen), &argLessLen, &argNotLessLen);
1960                         Bind(&argLessLen);
1961                         {
1962                             end = argEnd;
1963                             Jump(&endDone);
1964                         }
1965                         Bind(&argNotLessLen);
1966                         {
1967                             end = thisArrLen;
1968                             Jump(&endDone);
1969                         }
1970                     }
1971                 }
1972             }
1973             Bind(&endDone);
1974             {
1975                 DEFVARIABLE(count, VariableType::INT64(), Int64(0));
1976                 GateRef tempCnt = Int64Sub(*end, *start);
1977                 Label tempCntGreaterOrEqualZero(env);
1978                 Label tempCntDone(env);
1979                 BRANCH(Int64LessThan(tempCnt, Int64(0)), &tempCntDone, &tempCntGreaterOrEqualZero);
1980                 Bind(&tempCntGreaterOrEqualZero);
1981                 {
1982                     count = tempCnt;
1983                     Jump(&tempCntDone);
1984                 }
1985                 Bind(&tempCntDone);
1986                 {
1987                     Label notOverFlow(env);
1988                     BRANCH(Int64GreaterThan(*count, Int64(JSObject::MAX_GAP)), slowPath, &notOverFlow);
1989                     Bind(&notOverFlow);
1990                     {
1991                         Label mutantArrayEnabled(env);
1992                         Label notMutantArrayEnabled(env);
1993                         BRANCH_NO_WEIGHT(IsEnableMutantArray(glue), &mutantArrayEnabled, &notMutantArrayEnabled);
1994                         Bind(&mutantArrayEnabled);
1995                         {
1996                             GateRef newArray = NewArray(glue, *count);
1997                             DEFVARIABLE(idx, VariableType::INT64(), Int64(0));
1998                             Label loopHead(env);
1999                             Label loopEnd(env);
2000                             Label next(env);
2001                             Label loopExit(env);
2002                             Jump(&loopHead);
2003                             LoopBegin(&loopHead);
2004                             {
2005                                 BRANCH(Int64LessThan(*idx, *count), &next, &loopExit);
2006                                 Bind(&next);
2007                                 GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, Int64Add(*idx, *start));
2008                                 SetValueWithElementsKind(glue, newArray, ele, *idx, Boolean(true),
2009                                                          Int32(Elements::ToUint(ElementsKind::NONE)));
2010                                 Jump(&loopEnd);
2011                             }
2012                             Bind(&loopEnd);
2013                             idx = Int64Add(*idx, Int64(1));
2014                             LoopEndWithCheckSafePoint(&loopHead, env, glue);
2015                             Bind(&loopExit);
2016                             result->WriteVariable(newArray);
2017                             Jump(exit);
2018                         }
2019                         Bind(&notMutantArrayEnabled);
2020                         {
2021                             GateRef kind = ComputeTaggedArrayElementKind(glue, thisValue, *start, *end);
2022                             // note: kind is not be fixed, may be an invalid kind. NeedBarrier and CreateArrayFromList
2023                             // don't need a valid kind, so use it without fix.
2024                             GateRef elements = GetElementsArray(glue, thisValue);
2025                             NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
2026                             newBuilder.SetGlue(glue);
2027                             GateRef destElements = newBuilder.NewTaggedArray(glue, TruncInt64ToInt32(*count));
2028                             GateRef sourceStart = GetDataPtrInTaggedArray(elements, *start);
2029                             GateRef dest = GetDataPtrInTaggedArray(destElements);
2030                             ArrayCopy(glue, elements, sourceStart, destElements, dest,
2031                                       TruncInt64ToInt32(*count), NeedBarrier(kind), DifferentArray);
2032                             GateRef array = newBuilder.CreateArrayFromList(glue, destElements, kind);
2033                             result->WriteVariable(array);
2034                             Jump(exit);
2035                         }
2036                     }
2037                 }
2038             }
2039         }
2040     }
2041 }
ShiftOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2042 void BuiltinsArrayStubBuilder::ShiftOptimised(GateRef glue, GateRef thisValue,
2043     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
2044 {
2045     auto env = GetEnvironment();
2046     Label isHeapObject(env);
2047     Label stableJSArray(env);
2048     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2049     Bind(&isHeapObject);
2050     // don't check constructor, "Shift" won't create new array.
2051     BRANCH(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
2052     Bind(&stableJSArray);
2053     {
2054         Label isLengthWritable(env);
2055         BRANCH(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
2056         Bind(&isLengthWritable);
2057         {
2058             GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2059             Label lengthNotZero(env);
2060             BRANCH(Int64Equal(thisLen, Int64(0)), exit, &lengthNotZero);
2061             Bind(&lengthNotZero);
2062             {
2063                 Label isJsCOWArray(env);
2064                 Label getElements(env);
2065                 BRANCH(IsJsCOWArray(glue, thisValue), &isJsCOWArray, &getElements);
2066                 Bind(&isJsCOWArray);
2067                 {
2068                     NewObjectStubBuilder newBuilder(this);
2069                     GateRef elements = GetElementsArray(glue, thisValue);
2070                     GateRef capacity = GetLengthOfTaggedArray(elements);
2071                     GateRef newElements = newBuilder.CopyArray(glue, elements, capacity, capacity);
2072                     SetElementsArray(VariableType::JS_POINTER(), glue, thisValue, newElements);
2073                     Jump(&getElements);
2074                 }
2075                 Bind(&getElements);
2076                 {
2077                     GateRef enableMutant = IsEnableMutantArray(glue);
2078                     GateRef elements = GetElementsArray(glue, thisValue);
2079                     GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(elements));
2080                     GateRef index = Int64Sub(thisLen, Int64(1));
2081                     Label enableMutantArray(env);
2082                     Label disableMutantArray(env);
2083                     Label elementExit(env);
2084                     Label copyExit(env);
2085                     DEFVARIABLE(element, VariableType::JS_ANY(), Hole());
2086                     BRANCH(enableMutant, &enableMutantArray, &disableMutantArray);
2087                     Bind(&enableMutantArray);
2088                     {
2089                         element = GetTaggedValueWithElementsKind(glue, thisValue, Int64(0));
2090                         Jump(&elementExit);
2091                     }
2092                     Bind(&disableMutantArray);
2093                     {
2094                         element = GetValueFromTaggedArray(glue, elements, Int64(0));
2095                         Jump(&elementExit);
2096                     }
2097                     Bind(&elementExit);
2098                     GateRef kind = GetElementsKindFromHClass(LoadHClass(glue, thisValue));
2099                     GateRef dest = GetDataPtrInTaggedArray(elements);
2100                     GateRef start = PtrAdd(dest, IntPtr(JSTaggedValue::TaggedTypeSize()));
2101                     ArrayCopy(glue, elements, start, elements, dest,
2102                               TruncInt64ToInt32(index), NeedBarrier(kind), SameArray);
2103                     Jump(&copyExit);
2104                     Bind(&copyExit);
2105                     {
2106                         Label noTrim(env);
2107                         Label needTrim(env);
2108                         Label setNewLen(env);
2109                         GateRef unused = Int64Sub(capacity, index);
2110                         BRANCH(Int64GreaterThan(unused, Int64(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim);
2111                         Bind(&needTrim);
2112                         {
2113                             CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, index});
2114                             Jump(&setNewLen);
2115                         }
2116                         Bind(&noTrim);
2117                         {
2118                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements,
2119                                                   TruncInt64ToInt32(index), Hole(), MemoryAttribute::NoBarrier());
2120                             Jump(&setNewLen);
2121                         }
2122                         Bind(&setNewLen);
2123                         {
2124                             GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
2125                             Store(VariableType::INT32(), glue, thisValue, lengthOffset, index);
2126                             Label isNotHole(env);
2127                             BRANCH(TaggedIsHole(*element), exit, &isNotHole);
2128                             Bind(&isNotHole);
2129                             {
2130                                 result->WriteVariable(*element);
2131                                 Jump(exit);
2132                             }
2133                         }
2134                     }
2135                 }
2136             }
2137         }
2138     }
2139 }
2140 
CalEleKindForNewArrayNoHole(GateRef glue,GateRef thisValue,GateRef thisLen,GateRef actualIndex,GateRef insertVal)2141 GateRef BuiltinsArrayStubBuilder::CalEleKindForNewArrayNoHole(GateRef glue, GateRef thisValue, GateRef thisLen,
2142                                                               GateRef actualIndex, GateRef insertVal)
2143 {
2144     auto env = GetEnvironment();
2145     Label entry(env);
2146     env->SubCfgEntry(&entry);
2147     Label exit(env);
2148 
2149     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
2150     GateRef beforePartEleKind = ComputeTaggedArrayElementKind(glue, thisValue, Int64(0), actualIndex);
2151     GateRef afterPartEleKind = ComputeTaggedArrayElementKind(glue, thisValue, Int64Add(actualIndex, Int64(1)), thisLen);
2152     result = Int32Or(beforePartEleKind, TaggedToElementKind(glue, insertVal));
2153     result = Int32Or(*result, afterPartEleKind);
2154     // don't need to fix the result elementskind, we can know if it has hole without fix.
2155     Label haveHole(env);
2156     BRANCH(ElementsKindHasHole(*result), &haveHole, &exit);
2157     Bind(&haveHole);
2158     {
2159         result = Int32(Elements::ToUint(ElementsKind::TAGGED));
2160         Jump(&exit);
2161     }
2162 
2163     Bind(&exit);
2164     auto ret = *result;
2165     env->SubCfgExit();
2166     return ret;
2167 }
2168 
FastArrayWith(GateRef glue,GateRef thisValue,GateRef newArray,GateRef actualIndex,GateRef insertValue,GateRef newArrEleKind)2169 void BuiltinsArrayStubBuilder::FastArrayWith(GateRef glue, GateRef thisValue, GateRef newArray,
2170                                              GateRef actualIndex, GateRef insertValue, GateRef newArrEleKind)
2171 {
2172     auto env = GetEnvironment();
2173     Label entry(env);
2174     env->SubCfgEntry(&entry);
2175     Label exit(env);
2176     // copy elements before actualIndex
2177     GateRef srcElements = GetElementsArray(glue, thisValue);
2178     GateRef dstElements = GetElementsArray(glue, newArray);
2179     GateRef srcStart = GetDataPtrInTaggedArray(srcElements);
2180     GateRef dstStart = GetDataPtrInTaggedArray(dstElements);
2181     ArrayCopyAndHoleToUndefined(glue, srcElements, srcStart, dstElements,
2182                                 dstStart, actualIndex, NeedBarrier(newArrEleKind));
2183     // set insertValue in new array
2184     SetValueToTaggedArray(VariableType::JS_ANY(), glue, dstElements, actualIndex, insertValue);
2185     // copy elements before actualIndex
2186     GateRef copyAfterIdx = Int32Add(actualIndex, Int32(1));
2187     srcStart = GetDataPtrInTaggedArray(srcElements, copyAfterIdx);
2188     dstStart = GetDataPtrInTaggedArray(dstElements, copyAfterIdx);
2189     GateRef thisLength = GetLengthOfJSArray(thisValue);
2190     ArrayCopyAndHoleToUndefined(glue, srcElements, srcStart, dstElements, dstStart,
2191                                 Int32Sub(thisLength, copyAfterIdx), NeedBarrier(newArrEleKind));
2192 
2193     SetArrayLength(glue, newArray, thisLength);
2194     Jump(&exit);
2195     Bind(&exit);
2196     env->SubCfgExit();
2197 }
2198 
WithOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2199 void BuiltinsArrayStubBuilder::WithOptimised(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result,
2200                                              Label *exit, Label *slowPath)
2201 {
2202     auto env = GetEnvironment();
2203     DEFVARIABLE(relativeIndex, VariableType::INT64(), Int64(0));
2204     DEFVARIABLE(actualIndex, VariableType::INT64(), Int64(0));
2205     Label isHeapObject(env);
2206     Label isJsArray(env);
2207     Label isStableArray(env);
2208     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2209     Bind(&isHeapObject);
2210     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
2211     Bind(&isJsArray);
2212     BRANCH(IsStableJSArray(glue, thisValue), &isStableArray, slowPath);
2213     Bind(&isStableArray);
2214     // don't check constructor, "with" always use ArrayCreate to create array.
2215 
2216     // don't check COW array, "With" won't modify original array.
2217 
2218     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2219     GateRef index = GetCallArg0(numArgs);
2220     Label taggedIsInt(env);
2221     BRANCH(TaggedIsInt(index), &taggedIsInt, slowPath);
2222     Bind(&taggedIsInt);
2223     {
2224         relativeIndex = GetInt64OfTInt(index);
2225         DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
2226         Label twoArg(env);
2227         Label ifOneArg(env);
2228         Label getIndex(env);
2229         // 2 : means there are two args
2230         BRANCH(Int64Equal(numArgs, IntPtr(2)), &twoArg, &ifOneArg);
2231         Bind(&twoArg);
2232         {
2233             value = GetCallArg1(numArgs);
2234             Jump(&getIndex);
2235         }
2236         Bind(&ifOneArg);
2237         {
2238             // 1 : means there are only one arg
2239             BRANCH(Int64Equal(numArgs, IntPtr(1)), &getIndex, slowPath);
2240         }
2241         Bind(&getIndex);
2242         {
2243             Label indexGreaterOrEqualZero(env);
2244             Label indexLessZero(env);
2245             Label next(env);
2246             Label notOutOfRange(env);
2247             BRANCH(Int64GreaterThanOrEqual(*relativeIndex, Int64(0)), &indexGreaterOrEqualZero, &indexLessZero);
2248             Bind(&indexGreaterOrEqualZero);
2249             {
2250                 actualIndex = *relativeIndex;
2251                 Jump(&next);
2252             }
2253             Bind(&indexLessZero);
2254             {
2255                 actualIndex = Int64Add(thisLen, *relativeIndex);
2256                 Jump(&next);
2257             }
2258             Bind(&next);
2259             {
2260                 BRANCH(BitOr(Int64GreaterThanOrEqual(*actualIndex, thisLen), Int64LessThan(*actualIndex, Int64(0))),
2261                     slowPath, &notOutOfRange);
2262                 Bind(&notOutOfRange);
2263                 {
2264                     Label enableMutantArrayWith(env);
2265                     Label fastArrayWith(env);
2266                     BRANCH_UNLIKELY(IsEnableMutantArray(glue), &enableMutantArrayWith, &fastArrayWith);
2267                     Bind(&fastArrayWith);
2268                     {
2269                         GateRef newArrayEleKind = CalEleKindForNewArrayNoHole(glue, thisValue, thisLen,
2270                                                                               *actualIndex, *value);
2271                         GateRef newHClass =  GetElementsKindHClass(glue, newArrayEleKind);
2272                         GateRef newArray = NewArrayWithHClass(glue, newHClass, TruncInt64ToInt32(thisLen));
2273                         FastArrayWith(glue, thisValue, newArray, TruncInt64ToInt32(*actualIndex),
2274                                       *value, newArrayEleKind);
2275                         result->WriteVariable(newArray);
2276                         Jump(exit);
2277                     }
2278                     Bind(&enableMutantArrayWith);
2279                     GateRef newArray = NewArray(glue, Int32(0));
2280                     GrowElementsCapacity(glue, newArray, TruncInt64ToInt32(thisLen));
2281                     DEFVARIABLE(k, VariableType::INT64(), Int64(0));
2282                     Label loopHead(env);
2283                     Label loopEnd(env);
2284                     Label loopExit(env);
2285                     Label loopNext(env);
2286                     Label replaceIndex(env);
2287                     Label notReplaceIndex(env);
2288                     Jump(&loopHead);
2289                     LoopBegin(&loopHead);
2290                     {
2291                         BRANCH(Int64LessThan(*k, thisLen), &loopNext, &loopExit);
2292                         Bind(&loopNext);
2293                         BRANCH(Int64Equal(*k, *actualIndex), &replaceIndex, &notReplaceIndex);
2294                         Bind(&replaceIndex);
2295                         {
2296                             SetValueWithElementsKind(glue, newArray, *value, *k, Boolean(true),
2297                                 Int32(Elements::ToUint(ElementsKind::NONE)));
2298                             Jump(&loopEnd);
2299                         }
2300                         Bind(&notReplaceIndex);
2301                         {
2302                             GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *k);
2303                             Label eleIsHole(env);
2304                             Label eleNotHole(env);
2305                             BRANCH(TaggedIsHole(ele), &eleIsHole, &eleNotHole);
2306                             Bind(&eleIsHole);
2307                             {
2308                                 SetValueWithElementsKind(glue, newArray, Undefined(), *k, Boolean(true),
2309                                     Int32(Elements::ToUint(ElementsKind::NONE)));
2310                                 Jump(&loopEnd);
2311                             }
2312                             Bind(&eleNotHole);
2313                             {
2314                                 SetValueWithElementsKind(glue, newArray, ele, *k, Boolean(true),
2315                                     Int32(Elements::ToUint(ElementsKind::NONE)));
2316                                 Jump(&loopEnd);
2317                             }
2318                         }
2319                     }
2320                     Bind(&loopEnd);
2321                     k = Int64Add(*k, Int64(1));
2322                     LoopEnd(&loopHead);
2323                     Bind(&loopExit);
2324                     SetArrayLength(glue, newArray, thisLen);
2325                     result->WriteVariable(newArray);
2326                     Jump(exit);
2327                 }
2328             }
2329         }
2330     }
2331 }
2332 
ConcatOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2333 void BuiltinsArrayStubBuilder::ConcatOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
2334                                                Variable *result, Label *exit, Label *slowPath)
2335 {
2336     auto env = GetEnvironment();
2337     Label isHeapObject(env);
2338     Label isJsArray(env);
2339     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2340     Bind(&isHeapObject);
2341     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
2342     Bind(&isJsArray);
2343     {
2344         Label isExtensible(env);
2345         // need check constructor, "Concat" should use ArraySpeciesCreate
2346         BRANCH(HasConstructor(glue, thisValue), slowPath, &isExtensible);
2347         Bind(&isExtensible);
2348         {
2349             Label numArgsOne(env);
2350             BRANCH(Int64Equal(numArgs, IntPtr(1)), &numArgsOne, slowPath);
2351             Bind(&numArgsOne);
2352             {
2353                 GateRef arg0 = GetCallArg0(numArgs);
2354                 Label allStableJsArray(env);
2355                 GateRef isAllStableJsArray = LogicAndBuilder(env).And(IsStableJSArray(glue, thisValue))
2356                     .And(IsStableJSArray(glue, arg0)).Done();
2357                 BRANCH(isAllStableJsArray, &allStableJsArray, slowPath);
2358                 Bind(&allStableJsArray);
2359                 {
2360                     GateRef maxArrayIndex = Int64(TaggedArray::MAX_ARRAY_INDEX);
2361                     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
2362                     GateRef argLen = ZExtInt32ToInt64(GetArrayLength(arg0));
2363                     GateRef sumArrayLen = Int64Add(argLen, thisLen);
2364                     Label isEmptyArray(env);
2365                     Label notEmptyArray(env);
2366                     BRANCH(Int64Equal(sumArrayLen, Int64(0)), &isEmptyArray, &notEmptyArray);
2367                     Bind(&isEmptyArray);
2368                     {
2369                         NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
2370                         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
2371                         Jump(exit);
2372                     }
2373                     Bind(&notEmptyArray);
2374                     Label notOverFlow(env);
2375                     BRANCH(Int64GreaterThan(sumArrayLen, maxArrayIndex), slowPath, &notOverFlow);
2376                     Bind(&notOverFlow);
2377                     {
2378                         Label spreadable(env);
2379                         GateRef isAllConcatSpreadable = LogicAndBuilder(env).And(IsConcatSpreadable(glue, thisValue))
2380                             .And(IsConcatSpreadable(glue, arg0)).Done();
2381                         BRANCH(isAllConcatSpreadable, &spreadable, slowPath);
2382                         Bind(&spreadable);
2383                         {
2384                             Label enabledMutantArray(env);
2385                             Label disableMutantArray(env);
2386                             BRANCH(IsEnableMutantArray(glue), &enabledMutantArray, &disableMutantArray);
2387                             Bind(&enabledMutantArray);
2388                             {
2389                                 DoConcat(glue, thisValue, arg0, result, exit, thisLen, argLen, sumArrayLen);
2390                             }
2391                             Bind(&disableMutantArray);
2392                             {
2393                                 GateRef kind1 = GetElementsKindFromHClass(LoadHClass(glue, thisValue));
2394                                 GateRef kind2 = GetElementsKindFromHClass(LoadHClass(glue, arg0));
2395                                 GateRef newKind = Int32Or(kind1, kind2);
2396                                 // note: kind is not be fixed, may be an invalid kind. CreateArrayFromList
2397                                 // don't need a valid kind, so use it without fix.
2398                                 GateRef thisElements = GetElementsArray(glue, thisValue);
2399                                 GateRef argElements = GetElementsArray(glue, arg0);
2400                                 NewObjectStubBuilder newBuilder(this, GetCurrentGlobalEnv());
2401                                 GateRef newElements = newBuilder.NewTaggedArray(glue, TruncInt64ToInt32(sumArrayLen));
2402                                 GateRef dst1 = GetDataPtrInTaggedArray(newElements);
2403                                 GateRef dst2 = PtrAdd(dst1, PtrMul(thisLen, IntPtr(JSTaggedValue::TaggedTypeSize())));
2404                                 ArrayCopy(glue, thisElements, GetDataPtrInTaggedArray(thisElements),
2405                                           newElements, dst1, TruncInt64ToInt32(thisLen), NeedBarrier(kind1),
2406                                           DifferentArray);
2407                                 ArrayCopy(glue, argElements, GetDataPtrInTaggedArray(argElements),
2408                                           newElements, dst2, TruncInt64ToInt32(argLen), NeedBarrier(kind2),
2409                                           DifferentArray);
2410                                 GateRef array = newBuilder.CreateArrayFromList(glue, newElements, newKind);
2411                                 result->WriteVariable(array);
2412                                 Jump(exit);
2413                             }
2414                         }
2415                     }
2416                 }
2417             }
2418         }
2419     }
2420 }
2421 
DoConcat(GateRef glue,GateRef thisValue,GateRef arg0,Variable * result,Label * exit,GateRef thisLen,GateRef argLen,GateRef sumArrayLen)2422 void BuiltinsArrayStubBuilder::DoConcat(GateRef glue, GateRef thisValue, GateRef arg0, Variable *result, Label *exit,
2423                                         GateRef thisLen, GateRef argLen, GateRef sumArrayLen)
2424 {
2425     auto env = GetEnvironment();
2426     Label setProperties(env);
2427     GateRef globalEnv = GetCurrentGlobalEnv();
2428     auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glue, globalEnv,
2429         GlobalEnv::ARRAY_FUNCTION_INDEX);
2430     GateRef intialHClass = Load(VariableType::JS_ANY(), glue, arrayFunc,
2431         IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
2432     NewObjectStubBuilder newBuilder(this, globalEnv);
2433     newBuilder.SetParameters(glue, 0);
2434     GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, sumArrayLen);
2435     BRANCH(TaggedIsException(newArray), exit, &setProperties);
2436     Bind(&setProperties);
2437     {
2438         GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
2439         Store(VariableType::INT32(), glue, newArray, lengthOffset,
2440             TruncInt64ToInt32(sumArrayLen));
2441         GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
2442             ConstantIndex::ARRAY_LENGTH_ACCESSOR);
2443         SetPropertyInlinedProps(glue, newArray, intialHClass, accessor,
2444             Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
2445         SetExtensibleToBitfield(glue, newArray, true);
2446         DEFVARIABLE(i, VariableType::INT64(), Int64(0));
2447         DEFVARIABLE(j, VariableType::INT64(), Int64(0));
2448         DEFVARIABLE(k, VariableType::INT64(), Int64(0));
2449         Label loopHead(env);
2450         Label loopEnd(env);
2451         Label next(env);
2452         Label loopExit(env);
2453         Jump(&loopHead);
2454         LoopBegin(&loopHead);
2455         {
2456             BRANCH(Int64LessThan(*i, thisLen), &next, &loopExit);
2457             Bind(&next);
2458             GateRef ele = GetTaggedValueWithElementsKind(glue, thisValue, *i);
2459             #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC
2460             SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
2461                 Int32(Elements::ToUint(ElementsKind::GENERIC)));
2462             #else
2463             SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
2464                 Int32(Elements::ToUint(ElementsKind::NONE)));
2465             #endif
2466             Jump(&loopEnd);
2467         }
2468         Bind(&loopEnd);
2469         i = Int64Add(*i, Int64(1));
2470         j = Int64Add(*j, Int64(1));
2471         LoopEndWithCheckSafePoint(&loopHead, env, glue);
2472         Bind(&loopExit);
2473         Label loopHead1(env);
2474         Label loopEnd1(env);
2475         Label next1(env);
2476         Label loopExit1(env);
2477         Jump(&loopHead1);
2478         LoopBegin(&loopHead1);
2479         {
2480             BRANCH(Int64LessThan(*k, argLen), &next1, &loopExit1);
2481             Bind(&next1);
2482             GateRef ele = GetTaggedValueWithElementsKind(glue, arg0, *k);
2483             #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC
2484             SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
2485                                      Int32(Elements::ToUint(ElementsKind::GENERIC)));
2486             #else
2487             SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
2488                                      Int32(Elements::ToUint(ElementsKind::NONE)));
2489             #endif
2490             Jump(&loopEnd1);
2491         }
2492         Bind(&loopEnd1);
2493         k = Int64Add(*k, Int64(1));
2494         j = Int64Add(*j, Int64(1));
2495         LoopEnd(&loopHead1);
2496         Bind(&loopExit1);
2497         result->WriteVariable(newArray);
2498         Jump(exit);
2499     }
2500 }
2501 
FillOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)2502 void BuiltinsArrayStubBuilder::FillOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
2503                                              Variable *result, Label *exit, Label *slowPath)
2504 {
2505     auto env = GetEnvironment();
2506     Label isHeapObject(env);
2507     Label isJsArray(env);
2508     Label isStability(env);
2509     BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
2510     Bind(&isHeapObject);
2511     BRANCH(IsJsArray(glue, thisValue), &isJsArray, slowPath);
2512     Bind(&isJsArray);
2513     BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath);
2514     Bind(&isStability);
2515     Label notCOWArray(env);
2516     BRANCH(IsJsCOWArray(glue, thisValue), slowPath, &notCOWArray);
2517     Bind(&notCOWArray);
2518     GateRef arrayCls = LoadHClass(glue, thisValue);
2519     // 1. Let O be ToObject(this value).
2520     // 2 ReturnIfAbrupt(O).
2521     Label hasException(env);
2522     Label proNotCOWArray(env);
2523     GateRef prop = GetPropertiesFromJSObject(glue, thisValue);
2524     BRANCH(IsCOWArray(glue, prop), slowPath, &proNotCOWArray);
2525     Bind(&proNotCOWArray);
2526     // 3. Let len be ToLength(Get(O,"length")).
2527     GateRef value = GetCallArg0(numArgs);
2528     GateRef thisArrLen = ZExtInt32ToInt64(GetLengthOfJSArray(thisValue));
2529     Label startArgIsInt(env);
2530     // 5. let relativeStart be ToInteger(start).
2531     GateRef startArg = GetCallArg1(numArgs);
2532     // 6 ReturnIfAbrupt(relativeStart).
2533     BRANCH(TaggedIsInt(startArg), &startArgIsInt, slowPath);
2534     // ToInteger may be side effect for array, so fast path only handle startArg is int.
2535     Bind(&startArgIsInt);
2536     GateRef argStart = SExtInt32ToInt64(GetInt32OfTInt(startArg));
2537     Label notHasException3(env);
2538     BRANCH(HasPendingException(glue), &hasException, &notHasException3);
2539     Bind(&notHasException3);
2540     // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
2541     DEFVARIABLE(start, VariableType::INT64(), Int64(0));
2542     Label maxStart(env);
2543     Label minStart(env);
2544     Label startExit(env);
2545     BRANCH(Int64LessThan(argStart, Int64(0)), &maxStart, &minStart);
2546     Bind(&maxStart);
2547     {
2548         GateRef tempStart = Int64Add(argStart, thisArrLen);
2549         Label bind1(env);
2550         BRANCH(Int64GreaterThan(tempStart, Int64(0)), &bind1, &startExit);
2551         Bind(&bind1);
2552         {
2553             start = tempStart;
2554             Jump(&startExit);
2555         }
2556     }
2557     Bind(&minStart);
2558     {
2559         Label bind1(env);
2560         Label bind2(env);
2561         BRANCH(Int64LessThan(argStart, thisArrLen), &bind1, &bind2);
2562         Bind(&bind1);
2563         {
2564             start = argStart;
2565             Jump(&startExit);
2566         }
2567         Bind(&bind2);
2568         {
2569             start = thisArrLen;
2570             Jump(&startExit);
2571         }
2572     }
2573     Bind(&startExit);
2574     Label endArgIsInt(env);
2575     // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
2576     GateRef endArg = GetCallArg2(numArgs);
2577     BRANCH(TaggedIsInt(endArg), &endArgIsInt, slowPath);
2578     Bind(&endArgIsInt);
2579     DEFVARIABLE(argEnd, VariableType::INT64(), Int64(0));
2580     Label endArgIsUndefined(env);
2581     Label endArgNotUndefined(env);
2582     Label next1(env);
2583     BRANCH(TaggedIsUndefined(endArg), &endArgIsUndefined, &endArgNotUndefined);
2584     Bind(&endArgIsUndefined);
2585     {
2586         argEnd = thisArrLen;
2587         Jump(&next1);
2588     }
2589     Bind(&endArgNotUndefined);
2590     {
2591         argEnd = SExtInt32ToInt64(GetInt32OfTInt(endArg));
2592         // 9. ReturnIfAbrupt(relativeEnd).
2593         BRANCH(HasPendingException(glue), &hasException, &next1);
2594     }
2595     Bind(&next1);
2596 
2597     // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
2598     DEFVARIABLE(end, VariableType::INT64(), Int64(0));
2599     Label maxEnd(env);
2600     Label minEnd(env);
2601     Label endExit(env);
2602     BRANCH(Int64LessThan(*argEnd, Int64(0)), &maxEnd, &minEnd);
2603     Bind(&maxEnd);
2604     {
2605         GateRef tempEnd = Int64Add(*argEnd, thisArrLen);
2606         Label bind1(env);
2607         BRANCH(Int64GreaterThan(tempEnd, Int64(0)), &bind1, &endExit);
2608         Bind(&bind1);
2609         {
2610             end = tempEnd;
2611             Jump(&endExit);
2612         }
2613     }
2614     Bind(&minEnd);
2615     {
2616         Label bind1(env);
2617         Label bind2(env);
2618         BRANCH(Int64LessThan(*argEnd, thisArrLen), &bind1, &bind2);
2619         Bind(&bind1);
2620         {
2621             end = *argEnd;
2622             Jump(&endExit);
2623         }
2624         Bind(&bind2);
2625         {
2626             end = thisArrLen;
2627             Jump(&endExit);
2628         }
2629     }
2630     Bind(&endExit);
2631     {
2632         Label defaultElements(env);
2633         Label startFill(env);
2634         Label fatal(env);
2635         Label fillAllTransit(env);
2636         Label transitKind(env);
2637         Label doFill(env);
2638         DEFVARIABLE(elementKind, VariableType::INT32(), GetElementsKindFromHClass(arrayCls));
2639         BRANCH_NO_WEIGHT(BitAnd(Int64Equal(*start, Int64(0)), Int64Equal(*end, thisArrLen)), &fillAllTransit,
2640                          &transitKind);
2641         Bind(&fillAllTransit);
2642         {
2643             Label updateKind(env);
2644             BRANCH_NO_WEIGHT(Int32Equal(*elementKind, Int32(Elements::ToUint(ElementsKind::GENERIC))), &doFill,
2645                              &updateKind);
2646             Bind(&updateKind);
2647             {
2648                 elementKind = TaggedToElementKind(glue, value);
2649                 CallRuntimeWithGlobalEnv(glue, GetCurrentGlobalEnv(),
2650                     RTSTUB_ID(UpdateHClassForElementsKind), {thisValue, *elementKind});
2651                 Jump(&doFill);
2652             }
2653         }
2654         Bind(&transitKind);
2655         {
2656             TransitToElementsKind(glue, thisValue, value, *elementKind);
2657             Jump(&doFill);
2658         }
2659         Bind(&doFill);
2660         DEFVARIABLE(migratedValue, VariableType::JS_ANY(), value);
2661         DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(glue, thisValue));
2662         GateRef mutant = IsMutantTaggedArray(glue, *elements);
2663         GateRef elementLen = ZExtInt32ToInt64(GetLengthOfTaggedArray(*elements));
2664         BRANCH(Int64GreaterThanOrEqual(elementLen, *end), &defaultElements, &fatal);
2665         Bind(&defaultElements);
2666         {
2667             Label isMutant(env);
2668             BRANCH(mutant, &isMutant, &startFill);
2669             Bind(&isMutant);
2670             {
2671                 migratedValue = ConvertTaggedValueWithElementsKind(glue, value, *elementKind);
2672                 Jump(&startFill);
2673             }
2674         }
2675         Bind(&fatal);
2676         {
2677             FatalPrint(glue, {Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable))});
2678             Jump(exit);
2679         }
2680         Bind(&startFill);
2681         Label noBarrier(env);
2682         Label needBarrier(env);
2683         Label needRevise(env);
2684         Label noRevise(env);
2685         Label startLessEnd(env);
2686         Label barrierExit(env);
2687         BRANCH(Int64LessThan(*start, *end), &startLessEnd, &noRevise);
2688         Bind(&startLessEnd);
2689         {
2690             GateRef count = Int64Sub(*end, *start);
2691             BRANCH(mutant, &noBarrier, &needBarrier);
2692             Bind(&noBarrier);
2693             {
2694                 FastFill(glue, *elements, TruncInt64ToInt32(*start), TruncInt64ToInt32(count), *migratedValue, false);
2695                 Jump(&barrierExit);
2696             }
2697             Bind(&needBarrier);
2698             {
2699                 FastFill(glue, *elements, TruncInt64ToInt32(*start), TruncInt64ToInt32(count), *migratedValue, true);
2700                 Jump(&barrierExit);
2701             }
2702             Bind(&barrierExit);
2703             SetElementsArray(VariableType::JS_POINTER(), glue, thisValue, *elements);
2704             GateRef arrLen = ZExtInt32ToInt64(GetLengthOfJSArray(thisValue));
2705             BRANCH(Int64LessThan(arrLen, *end), &needRevise, &noRevise);
2706             Bind(&needRevise);
2707             {
2708                 SetArrayLength(glue, thisValue, TruncInt64ToInt32(*end));
2709                 Jump(&noRevise);
2710             }
2711         }
2712         Bind(&noRevise);
2713         result->WriteVariable(thisValue);
2714         Jump(exit);
2715     }
2716     Bind(&hasException);
2717     {
2718         result->WriteVariable(Exception());
2719         Jump(exit);
2720     }
2721 }
2722 
FastFill(GateRef glue,GateRef element,GateRef start,GateRef count,GateRef value,bool needBarrier)2723 void BuiltinsArrayStubBuilder::FastFill(GateRef glue, GateRef element, GateRef start, GateRef count,
2724                                         GateRef value, bool needBarrier)
2725 {
2726     auto env = GetEnvironment();
2727     Label entry(env);
2728     env->SubCfgEntry(&entry);
2729     Label exit(env);
2730     GateRef dstAddr = GetDataPtrInTaggedArray(element, start);
2731     CallNGCRuntime(glue, RTSTUB_ID(FillObject), {TaggedCastToIntPtr(dstAddr), value, count});
2732     if (needBarrier) {
2733         CallCommonStub(glue, CommonStubCSigns::BatchBarrier,
2734             {glue, TaggedCastToIntPtr(element), TaggedCastToIntPtr(dstAddr), count});
2735     }
2736     Jump(&exit);
2737     Bind(&exit);
2738     env->SubCfgExit();
2739 }
2740 
ReverseOptimised(GateRef glue,GateRef thisValue,GateRef thisLen,Variable * result,Label * exit)2741 void BuiltinsArrayStubBuilder::ReverseOptimised(GateRef glue, GateRef thisValue, GateRef thisLen,
2742     Variable *result, Label *exit)
2743 {
2744     auto env = GetEnvironment();
2745     GateRef hclass = LoadHClass(glue, thisValue);
2746     GateRef kind = GetElementsKindFromHClass(hclass);
2747     Label shouldBarrier(env);
2748     Label noBarrier(env);
2749     Label afterReverse(env);
2750     GateRef element = GetElementsArray(glue, thisValue);
2751     GateRef dstAddr = GetDataPtrInTaggedArray(element);
2752     CallNGCRuntime(glue, RTSTUB_ID(ReverseArray), {glue, TaggedCastToIntPtr(dstAddr), thisLen});
2753     BRANCH(NeedBarrier(kind), &shouldBarrier, &afterReverse);
2754     Bind(&shouldBarrier);
2755     {
2756         CallCommonStub(glue, CommonStubCSigns::ReverseBarrier,
2757             {glue, TaggedCastToIntPtr(element), TaggedCastToIntPtr(dstAddr), thisLen});
2758         Jump(&afterReverse);
2759     }
2760     Bind(&afterReverse);
2761     result->WriteVariable(thisValue);
2762     Jump(exit);
2763 }
2764 
IndexOfOptimised(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,IndexOfOptions options)2765 void BuiltinsArrayStubBuilder::IndexOfOptimised(GateRef glue, GateRef thisValue, GateRef numArgs,
2766     Variable *result, Label *exit, Label *slowPath, IndexOfOptions options)
2767 {
2768     auto env = GetEnvironment();
2769     Label isStable(env);
2770     Label thisLengthNotZero(env);
2771     Label targetNotByDefault(env);
2772     Label hasFromIndex(env);
2773     Label fromIndexDone(env);
2774     Label beginDispatching(env);
2775     Label notFound(env);
2776 
2777     GateRef thisLen = GetArrayLength(thisValue);
2778     GateRef defaultFromIndex = options.reversedOrder ? Int64Sub(ZExtInt32ToInt64(thisLen), Int64(1)) : Int64(0);
2779     DEFVARIABLE(fromIndex, VariableType::INT64(), defaultFromIndex);
2780     DEFVARIABLE(target, VariableType::JS_ANY(), Undefined());
2781 
2782     BRANCH_LIKELY(IsStableJSArray(glue, thisValue), &isStable, slowPath);
2783     // thisValue is constrained to stable array
2784     Bind(&isStable);
2785     BRANCH_UNLIKELY(Int32Equal(thisLen, Int32(0)), &notFound, &thisLengthNotZero);
2786     Bind(&thisLengthNotZero);
2787     BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(2)), &hasFromIndex, &fromIndexDone); // 2: 2 parameters
2788     Bind(&hasFromIndex);
2789     {
2790         Label fromIndexIsNumber(env);
2791         GateRef fromIndexTemp = GetCallArg1(numArgs);
2792         BRANCH_LIKELY(TaggedIsNumber(fromIndexTemp), &fromIndexIsNumber, slowPath);
2793         Bind(&fromIndexIsNumber);
2794         fromIndex.WriteVariable(MakeFromIndex(fromIndexTemp, thisLen, options.reversedOrder));
2795         if (options.reversedOrder) {
2796             BRANCH(Int64LessThan(*fromIndex, Int64(0)), &notFound, &fromIndexDone);
2797         } else {
2798             BRANCH(Int64GreaterThanOrEqual(*fromIndex, ZExtInt32ToInt64(thisLen)), &notFound, &fromIndexDone);
2799         }
2800     }
2801     // Search range [startIndex, endIndex) is ensured to be non-empty
2802     Bind(&fromIndexDone);
2803     BRANCH_LIKELY(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &targetNotByDefault, &beginDispatching);
2804     Bind(&targetNotByDefault); // Otherwise, let searchElement be undefined
2805     target.WriteVariable(GetCallArg0(numArgs));
2806     Jump(&beginDispatching);
2807 
2808     Bind(&beginDispatching);
2809     GateRef elements = GetElementsArray(glue, thisValue);
2810     GateRef elementsKind = GetElementsKindFromHClass(LoadHClass(glue, thisValue));
2811 
2812     // todo: optimization for mutant arrays (by extracting raw int32 or raw double directly)
2813     Label targetNotMutant(env);
2814     BRANCH_UNLIKELY(IsEnableMutantArray(glue), slowPath, &targetNotMutant);
2815 
2816     Bind(&targetNotMutant);
2817     // Special-judges Undefined() first to make sure that Hole() is matched in includes().
2818     Label undefinedBranch(env);
2819     Label targetNotUndefined(env);
2820     BRANCH_UNLIKELY(TaggedIsUndefined(*target), &undefinedBranch, &targetNotUndefined);
2821     Bind(&undefinedBranch);
2822     *result = IndexOfTaggedUndefined(glue, elements, *fromIndex, thisLen, options);
2823     Jump(exit);
2824 
2825     Bind(&targetNotUndefined);
2826     Label intBranch(env);
2827     Label doubleBranch(env);
2828     Label stringBranch(env);
2829     Label stringOrHoleBranch(env);
2830     Label bigIntOrObjectBranch(env);
2831     Label genericBranch(env);
2832 
2833     constexpr int64_t caseKeys[] = {
2834         Elements::ToUint(ElementsKind::INT),
2835         Elements::ToUint(ElementsKind::HOLE_INT),
2836         Elements::ToUint(ElementsKind::NUMBER),
2837         Elements::ToUint(ElementsKind::HOLE_NUMBER),
2838         Elements::ToUint(ElementsKind::STRING),
2839         Elements::ToUint(ElementsKind::HOLE_STRING),
2840         Elements::ToUint(ElementsKind::OBJECT),
2841         Elements::ToUint(ElementsKind::HOLE_OBJECT),
2842     };
2843     Label *caseLabels[] = {
2844         &intBranch,
2845         &intBranch,
2846         &doubleBranch,
2847         &doubleBranch,
2848         &stringBranch,
2849         &stringOrHoleBranch,
2850         &bigIntOrObjectBranch,
2851         &bigIntOrObjectBranch,
2852     };
2853     static_assert(std::size(caseKeys) == std::size(caseLabels), "Size mismatch!");
2854     Switch(elementsKind, &genericBranch, caseKeys, caseLabels, std::size(caseKeys));
2855 
2856     Bind(&intBranch);
2857     *result = IndexOfTaggedIntElements(glue, elements, *target, *fromIndex, thisLen, options);
2858     Jump(exit);
2859     Bind(&doubleBranch);
2860     *result = IndexOfTaggedNumber(glue, elements, *target, *fromIndex, thisLen, options, false);
2861     Jump(exit);
2862     Bind(&stringBranch);
2863     *result = IndexOfStringElements(
2864         glue, elements, *target, *fromIndex, thisLen, options, StringElementsCondition::MUST_BE_STRING);
2865     Jump(exit);
2866     Bind(&stringOrHoleBranch);
2867     *result = IndexOfStringElements(
2868         glue, elements, *target, *fromIndex, thisLen, options, StringElementsCondition::MAY_BE_HOLE);
2869     Jump(exit);
2870     Bind(&bigIntOrObjectBranch);
2871     *result = IndexOfBigIntOrObjectElements(glue, elements, *target, *fromIndex, thisLen, options);
2872     Jump(exit);
2873     Bind(&genericBranch);
2874     *result = IndexOfGeneric(glue, elements, *target, *fromIndex, thisLen, options);
2875     Jump(exit);
2876 
2877     Bind(&notFound);
2878     if (options.returnType == IndexOfReturnType::TAGGED_FOUND_INDEX) {
2879         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
2880     } else {
2881         ASSERT_PRINT(options.returnType == IndexOfReturnType::TAGGED_FOUND_OR_NOT, "Tagged return type only!");
2882         result->WriteVariable(TaggedFalse());
2883     }
2884     Jump(exit);
2885 }
2886 } // namespace panda::ecmascript::kungfu
2887