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