• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/builtins/builtins_array_stub_builder.h"
17 
18 #include "ecmascript/compiler/builtins/builtins_stubs.h"
19 #include "ecmascript/compiler/new_object_stub_builder.h"
20 #include "ecmascript/builtins/builtins_string.h"
21 #include "ecmascript/compiler/profiler_operation.h"
22 #include "ecmascript/compiler/rt_call_signature.h"
23 #include "ecmascript/runtime_call_id.h"
24 #include "ecmascript/js_iterator.h"
25 #include "ecmascript/compiler/access_object_stub_builder.h"
26 #include "ecmascript/base/array_helper.h"
27 
28 namespace panda::ecmascript::kungfu {
Concat(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)29 void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef numArgs,
30     Variable *result, Label *exit, Label *slowPath)
31 {
32     auto env = GetEnvironment();
33     Label isHeapObject(env);
34     Label isJsArray(env);
35     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
36     Bind(&isHeapObject);
37     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
38     Bind(&isJsArray);
39     {
40         Label isExtensible(env);
41         Branch(HasConstructor(thisValue), slowPath, &isExtensible);
42         Bind(&isExtensible);
43         {
44             Label numArgsOne(env);
45             Branch(Int64Equal(numArgs, IntPtr(1)), &numArgsOne, slowPath);
46             Bind(&numArgsOne);
47             {
48                 GateRef arg0 = GetCallArg0(numArgs);
49                 Label allEcmaObject(env);
50                 Label allStableJsArray(env);
51                 GateRef isThisEcmaObject = IsEcmaObject(thisValue);
52                 GateRef isArgEcmaObject = IsEcmaObject(arg0);
53                 Branch(BoolAnd(isThisEcmaObject, isArgEcmaObject), &allEcmaObject, slowPath);
54                 Bind(&allEcmaObject);
55                 {
56                     GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue);
57                     GateRef isArgStableJSArray = IsStableJSArray(glue, arg0);
58                     Branch(BoolAnd(isThisStableJSArray, isArgStableJSArray), &allStableJsArray, slowPath);
59                     Bind(&allStableJsArray);
60                     {
61                         GateRef maxArrayIndex = Int64(TaggedArray::MAX_ARRAY_INDEX);
62                         GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
63                         GateRef argLen = ZExtInt32ToInt64(GetArrayLength(arg0));
64                         GateRef sumArrayLen = Int64Add(argLen, thisLen);
65                         Label isEmptyArray(env);
66                         Label notEmptyArray(env);
67                         Branch(Int64Equal(sumArrayLen, Int64(0)), &isEmptyArray, &notEmptyArray);
68                         Bind(&isEmptyArray);
69                         {
70                             NewObjectStubBuilder newBuilder(this);
71                             result->WriteVariable(newBuilder.CreateEmptyArray(glue));
72                             Jump(exit);
73                         }
74                         Bind(&notEmptyArray);
75                         Label notOverFlow(env);
76                         Branch(Int64GreaterThan(sumArrayLen, maxArrayIndex), slowPath, &notOverFlow);
77                         Bind(&notOverFlow);
78                         {
79                             Label spreadable(env);
80                             GateRef isSpreadable = IsConcatSpreadable(glue, thisValue);
81                             GateRef argisSpreadable = IsConcatSpreadable(glue, arg0);
82                             Branch(BoolAnd(isSpreadable, argisSpreadable), &spreadable, slowPath);
83                             Bind(&spreadable);
84                             {
85                                 Label setProperties(env);
86                                 GateRef glueGlobalEnvOffset =
87                                     IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
88                                 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
89                                 auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
90                                     GlobalEnv::ARRAY_FUNCTION_INDEX);
91                                 GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc,
92                                     IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
93                                 NewObjectStubBuilder newBuilder(this);
94                                 newBuilder.SetParameters(glue, 0);
95                                 GateRef newArray = newBuilder.NewJSArrayWithSize(intialHClass, sumArrayLen);
96                                 Branch(TaggedIsException(newArray), exit, &setProperties);
97                                 Bind(&setProperties);
98                                 {
99                                     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
100                                     Store(VariableType::INT32(), glue, newArray, lengthOffset,
101                                         TruncInt64ToInt32(sumArrayLen));
102                                     GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
103                                         ConstantIndex::ARRAY_LENGTH_ACCESSOR);
104                                     SetPropertyInlinedProps(glue, newArray, intialHClass, accessor,
105                                         Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
106                                     SetExtensibleToBitfield(glue, newArray, true);
107                                     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
108                                     DEFVARIABLE(j, VariableType::INT64(), Int64(0));
109                                     DEFVARIABLE(k, VariableType::INT64(), Int64(0));
110                                     Label loopHead(env);
111                                     Label loopEnd(env);
112                                     Label next(env);
113                                     Label loopExit(env);
114                                     Jump(&loopHead);
115                                     LoopBegin(&loopHead);
116                                     {
117                                         Branch(Int64LessThan(*i, thisLen), &next, &loopExit);
118                                         Bind(&next);
119                                         GateRef ele = GetTaggedValueWithElementsKind(thisValue, *i);
120                                         SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
121                                                                  Int32(static_cast<uint32_t>(ElementsKind::NONE)));
122                                         Jump(&loopEnd);
123                                     }
124                                     Bind(&loopEnd);
125                                     i = Int64Add(*i, Int64(1));
126                                     j = Int64Add(*j, Int64(1));
127                                     LoopEnd(&loopHead);
128                                     Bind(&loopExit);
129                                     Label loopHead1(env);
130                                     Label loopEnd1(env);
131                                     Label next1(env);
132                                     Label loopExit1(env);
133                                     Jump(&loopHead1);
134                                     LoopBegin(&loopHead1);
135                                     {
136                                         Branch(Int64LessThan(*k, argLen), &next1, &loopExit1);
137                                         Bind(&next1);
138                                         GateRef ele = GetTaggedValueWithElementsKind(arg0, *k);
139                                         SetValueWithElementsKind(glue, newArray, ele, *j, Boolean(true),
140                                                                  Int32(static_cast<uint32_t>(ElementsKind::NONE)));
141                                         Jump(&loopEnd1);
142                                     }
143                                     Bind(&loopEnd1);
144                                     k = Int64Add(*k, Int64(1));
145                                     j = Int64Add(*j, Int64(1));
146                                     LoopEnd(&loopHead1);
147                                     Bind(&loopExit1);
148                                     result->WriteVariable(newArray);
149                                     Jump(exit);
150                                 }
151                             }
152                         }
153                     }
154                 }
155             }
156         }
157     }
158 }
159 
Filter(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)160 void BuiltinsArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef numArgs,
161     Variable *result, Label *exit, Label *slowPath)
162 {
163     auto env = GetEnvironment();
164     Label isHeapObject(env);
165     Label isJsArray(env);
166     Label defaultConstr(env);
167     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
168     Bind(&isHeapObject);
169     GateRef thisValueIsJSArray = IsJsArray(thisValue);
170     GateRef protoIsJsArray = IsJsArray(StubBuilder::GetPrototype(glue, thisValue));
171     Branch(BoolAnd(thisValueIsJSArray, protoIsJsArray), &isJsArray, slowPath);
172     Bind(&isJsArray);
173     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
174     Bind(&defaultConstr);
175 
176     GateRef callbackFnHandle = GetCallArg0(numArgs);
177     Label argOHeapObject(env);
178     Label callable(env);
179     Label notOverFlow(env);
180     Branch(TaggedIsHeapObject(callbackFnHandle), &argOHeapObject, slowPath);
181     Bind(&argOHeapObject);
182     Branch(IsCallable(callbackFnHandle), &callable, slowPath);
183     Bind(&callable);
184     GateRef len = ZExtInt32ToInt64(GetArrayLength(thisValue));
185     Label isEmptyArray(env);
186     Label notEmptyArray(env);
187     Branch(Int64Equal(len, Int64(0)), &isEmptyArray, &notEmptyArray);
188     Bind(&isEmptyArray);
189     {
190         NewObjectStubBuilder newBuilder(this);
191         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
192         Jump(exit);
193     }
194     Bind(&notEmptyArray);
195     Branch(Int64GreaterThan(len, Int64(JSObject::MAX_GAP)), slowPath, &notOverFlow);
196     Bind(&notOverFlow);
197 
198     GateRef argHandle = GetCallArg1(numArgs);
199     GateRef newArray = NewArray(glue, len);
200     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
201     GateRef newArrayEles = GetElementsArray(newArray);
202     Label stableJSArray(env);
203     Label notStableJSArray(env);
204     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
205     DEFVARIABLE(toIndex, VariableType::INT64(), Int64(0));
206     Branch(IsStableJSArray(glue, thisValue), &stableJSArray, slowPath);
207     Bind(&stableJSArray);
208     {
209         DEFVARIABLE(thisArrLenVar, VariableType::INT64(), len);
210         DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole());
211         Label loopHead(env);
212         Label loopEnd(env);
213         Label next(env);
214         Label loopExit(env);
215         Jump(&loopHead);
216         LoopBegin(&loopHead);
217         {
218             Branch(Int64LessThan(*i, *thisArrLenVar), &next, &loopExit);
219             Bind(&next);
220             kValue = GetTaggedValueWithElementsKind(thisValue, *i);
221             Label kValueIsHole(env);
222             Label kValueNotHole(env);
223             Label arrayValueIsHole(env);
224             Label arrayValueNotHole(env);
225             Label hasProperty(env);
226             Branch(TaggedIsHole(*kValue), &arrayValueIsHole, &arrayValueNotHole);
227             Bind(&arrayValueIsHole);
228             {
229                 GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) });
230                 Branch(TaggedIsTrue(hasProp), &hasProperty, &arrayValueNotHole);
231                 Bind(&hasProperty);
232                 Label hasException0(env);
233                 Label notHasException0(env);
234                 kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
235                 Branch(HasPendingException(glue), &hasException0, &notHasException0);
236                 Bind(&hasException0);
237                 {
238                     result->WriteVariable(Exception());
239                     Jump(exit);
240                 }
241                 Bind(&notHasException0);
242                 {
243                     Jump(&arrayValueNotHole);
244                 }
245             }
246             Bind(&arrayValueNotHole);
247             Branch(TaggedIsHole(*kValue), &kValueIsHole, &kValueNotHole);
248             Bind(&kValueNotHole);
249             {
250                 GateRef key = Int64ToTaggedInt(*i);
251                 Label checkArray(env);
252                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
253                                                   Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
254                                                   { argHandle, *kValue, key, thisValue });
255                 Label find(env);
256                 Label hasException1(env);
257                 Label notHasException1(env);
258                 Branch(HasPendingException(glue), &hasException1, &notHasException1);
259                 Bind(&hasException1);
260                 {
261                     result->WriteVariable(Exception());
262                     Jump(exit);
263                 }
264                 Bind(&notHasException1);
265                 Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &checkArray);
266                 Bind(&find);
267                 {
268                     SetValueWithElementsKind(glue, newArray, *kValue, *toIndex, Boolean(true),
269                                              Int32(static_cast<uint32_t>(ElementsKind::NONE)));
270                     toIndex = Int64Add(*toIndex, Int64(1));
271                     Jump(&checkArray);
272                 }
273                 Bind(&checkArray);
274                 {
275                     Label lenChange(env);
276                     GateRef tmpArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
277                     Branch(Int64LessThan(tmpArrLen, *thisArrLenVar), &lenChange, &kValueIsHole);
278                     Bind(&lenChange);
279                     {
280                         thisArrLenVar = tmpArrLen;
281                         Jump(&kValueIsHole);
282                     }
283                 }
284             }
285             Bind(&kValueIsHole);
286             i = Int64Add(*i, Int64(1));
287             Branch(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
288         }
289         Bind(&loopEnd);
290         LoopEnd(&loopHead);
291         Bind(&loopExit);
292         Jump(&notStableJSArray);
293     }
294     Bind(&notStableJSArray);
295     {
296         Label finish(env);
297         Label callRT(env);
298         Branch(Int32LessThan(*i, len), &callRT, &finish);
299         Bind(&callRT);
300         {
301             CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, newArrayEles, *toIndex});
302             Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(*toIndex));
303             GateRef ret = CallRuntime(glue, RTSTUB_ID(JSArrayFilterUnStable), { argHandle, thisValue,
304                 IntToTaggedInt(*i), IntToTaggedInt(len), IntToTaggedInt(*toIndex), newArray, callbackFnHandle });
305             result->WriteVariable(ret);
306             Jump(exit);
307         }
308         Bind(&finish);
309         {
310             result->WriteVariable(newArray);
311             Label needTrim(env);
312             Branch(Int64LessThan(*toIndex, len), &needTrim, exit);
313             Bind(&needTrim);
314             CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, newArrayEles, *toIndex});
315             Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(*toIndex));
316             Jump(exit);
317         }
318     }
319 }
320 
321 // Note: unused arguments are reserved for further development
ForEach(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)322 void BuiltinsArrayStubBuilder::ForEach([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
323     [[maybe_unused]] Variable *result, Label *exit, Label *slowPath)
324 {
325     auto env = GetEnvironment();
326     Label thisIsEmpty(env);
327     Label isHeapObject(env);
328     // Fast path if all the conditions below are satisfied:
329     // (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details);
330     // (2) callbackFn is callable (otherwise a TypeError shall be thrown in the slow path)
331     JsArrayRequirements req;
332     req.defaultConstructor = true;
333     Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath);
334     Bind(&thisIsEmpty);
335     // Do nothing on fast path
336     Branch(TaggedIsHeapObject(GetCallArg0(numArgs)), &isHeapObject, slowPath);
337     Bind(&isHeapObject);
338     Branch(IsCallable(GetCallArg0(numArgs)), exit, slowPath);
339 }
340 
341 // Note: unused arguments are reserved for further development
IndexOf(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)342 void BuiltinsArrayStubBuilder::IndexOf([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
343     Variable *result, Label *exit, Label *slowPath)
344 {
345     auto env = GetEnvironment();
346     Label thisIsEmpty(env);
347     // Fast path if: (1) this is an empty array; (2) fromIndex is missing
348     JsArrayRequirements req;
349     Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath);
350     Bind(&thisIsEmpty);
351     {
352         Label atMostOneArg(env);
353         Branch(Int32LessThanOrEqual(TruncPtrToInt32(numArgs), Int32(1)), &atMostOneArg, slowPath);
354         // Returns -1 on fast path
355         Bind(&atMostOneArg);
356         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
357         Jump(exit);
358     }
359 }
360 
361 // Note: unused arguments are reserved for further development
LastIndexOf(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)362 void BuiltinsArrayStubBuilder::LastIndexOf([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
363     Variable *result, Label *exit, Label *slowPath)
364 {
365     auto env = GetEnvironment();
366     Label thisIsEmpty(env);
367     // Fast path if: (1) this is an empty array; (2) fromIndex is missing
368     JsArrayRequirements req;
369     Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, slowPath);
370     Bind(&thisIsEmpty);
371     {
372         Label atMostOneArg(env);
373         Branch(Int32LessThanOrEqual(TruncPtrToInt32(numArgs), Int32(1)), &atMostOneArg, slowPath);
374         // Returns -1 on fast path
375         Bind(&atMostOneArg);
376         result->WriteVariable(IntToTaggedPtr(Int32(-1)));
377         Jump(exit);
378     }
379 }
380 
Pop(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)381 void BuiltinsArrayStubBuilder::Pop(GateRef glue, GateRef thisValue,
382     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
383 {
384     auto env = GetEnvironment();
385     Label isHeapObject(env);
386     Label stableJSArray(env);
387     Label isDeufaltConstructor(env);
388     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
389     Bind(&isHeapObject);
390     Branch(HasConstructor(thisValue), slowPath, &isDeufaltConstructor);
391     Bind(&isDeufaltConstructor);
392     GateRef isThisEcmaObject = IsEcmaObject(thisValue);
393     GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue);
394     Branch(BoolAnd(isThisEcmaObject, isThisStableJSArray), &stableJSArray, slowPath);
395     Bind(&stableJSArray);
396 
397     Label isLengthWritable(env);
398     Branch(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath);
399     Bind(&isLengthWritable);
400     GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
401 
402     Label notZeroLen(env);
403     Branch(Int64Equal(thisLen, Int64(0)), exit, &notZeroLen);
404     Bind(&notZeroLen);
405     Label isJsCOWArray(env);
406     Label getElements(env);
407     Branch(IsJsCOWArray(thisValue), &isJsCOWArray, &getElements);
408     Bind(&isJsCOWArray);
409     {
410         CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), { thisValue });
411         Jump(&getElements);
412     }
413     Bind(&getElements);
414     GateRef elements = GetElementsArray(thisValue);
415     GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(elements));
416     GateRef index = Int64Sub(thisLen, Int64(1));
417 
418     Label inRange(env);
419     Label trimCheck(env);
420     Label noTrimCheck(env);
421     Label setNewLen(env);
422     Label isHole(env);
423     DEFVARIABLE(element, VariableType::JS_ANY(), Hole());
424     Branch(Int64LessThan(index, capacity), &inRange, &trimCheck);
425     Bind(&inRange);
426     {
427         element = GetTaggedValueWithElementsKind(thisValue, index);
428         Jump(&isHole);
429     }
430     Bind(&isHole);
431     Branch(TaggedIsHole(*element), &noTrimCheck, &trimCheck);
432     Bind(&noTrimCheck);
433     {
434         Label hasException0(env);
435         Label notHasException0(env);
436         element = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(index), ProfileOperation());
437         Branch(HasPendingException(glue), &hasException0, &notHasException0);
438         Bind(&hasException0);
439         {
440             result->WriteVariable(Exception());
441             Jump(exit);
442         }
443         Bind(&notHasException0);
444         {
445             Jump(&setNewLen);
446         }
447     }
448     Bind(&trimCheck);
449     // ShouldTrim check
450     // (oldLength - newLength > MAX_END_UNUSED)
451     Label noTrim(env);
452     Label needTrim(env);
453     GateRef unused = Int64Sub(capacity, index);
454     Branch(Int64GreaterThan(unused, Int64(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim);
455     Bind(&needTrim);
456     {
457         CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, index});
458         Jump(&setNewLen);
459     }
460     Bind(&noTrim);
461     {
462         SetValueWithElementsKind(glue, thisValue, Hole(), index, Boolean(false),
463                                  Int32(static_cast<uint32_t>(ElementsKind::NONE)));
464         Jump(&setNewLen);
465     }
466     Bind(&setNewLen);
467     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
468     Store(VariableType::INT32(), glue, thisValue, lengthOffset, TruncInt64ToInt32(index));
469 
470     Label isNotHole(env);
471     Branch(TaggedIsHole(*element), exit, &isNotHole);
472     Bind(&isNotHole);
473     {
474         result->WriteVariable(*element);
475         Jump(exit);
476     }
477 }
478 
Slice(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)479 void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef numArgs,
480     Variable *result, Label *exit, Label *slowPath)
481 {
482     auto env = GetEnvironment();
483     Label isHeapObject(env);
484     Label isJsArray(env);
485     Label noConstructor(env);
486     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
487     Bind(&isHeapObject);
488     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
489     Bind(&isJsArray);
490     Branch(HasConstructor(thisValue), slowPath, &noConstructor);
491     Bind(&noConstructor);
492 
493     Label thisIsEmpty(env);
494     Label thisNotEmpty(env);
495     // Fast path if:
496     // (1) this is an empty array with constructor not reset (see ArraySpeciesCreate for details);
497     // (2) no arguments exist
498     JsArrayRequirements req;
499     req.defaultConstructor = true;
500     Branch(IsJsArrayWithLengthLimit(glue, thisValue, MAX_LENGTH_ZERO, req), &thisIsEmpty, &thisNotEmpty);
501     Bind(&thisIsEmpty);
502     {
503         Label noArgs(env);
504         GateRef numArgsAsInt32 = TruncPtrToInt32(numArgs);
505         Branch(Int32Equal(numArgsAsInt32, Int32(0)), &noArgs, slowPath);
506         // Creates a new empty array on fast path
507         Bind(&noArgs);
508         NewObjectStubBuilder newBuilder(this);
509         result->WriteVariable(newBuilder.CreateEmptyArray(glue));
510         Jump(exit);
511     }
512     Bind(&thisNotEmpty);
513     {
514         Label stableJSArray(env);
515         Label arrayLenNotZero(env);
516 
517         GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue);
518         Branch(isThisStableJSArray, &stableJSArray, slowPath);
519         Bind(&stableJSArray);
520 
521         GateRef msg0 = GetCallArg0(numArgs);
522         GateRef msg1 = GetCallArg1(numArgs);
523         GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
524         Label msg0Int(env);
525         Branch(TaggedIsInt(msg0), &msg0Int, slowPath);
526         Bind(&msg0Int);
527         DEFVARIABLE(start, VariableType::INT64(), Int64(0));
528         DEFVARIABLE(end, VariableType::INT64(), thisArrLen);
529 
530         GateRef argStart = SExtInt32ToInt64(TaggedGetInt(msg0));
531         Label arg0LessZero(env);
532         Label arg0NotLessZero(env);
533         Label startDone(env);
534         Branch(Int64LessThan(argStart, Int64(0)), &arg0LessZero, &arg0NotLessZero);
535         Bind(&arg0LessZero);
536         {
537             Label tempGreaterZero(env);
538             Label tempNotGreaterZero(env);
539             GateRef tempStart = Int64Add(argStart, thisArrLen);
540             Branch(Int64GreaterThan(tempStart, Int64(0)), &tempGreaterZero, &tempNotGreaterZero);
541             Bind(&tempGreaterZero);
542             {
543                 start = tempStart;
544                 Jump(&startDone);
545             }
546             Bind(&tempNotGreaterZero);
547             {
548                 Jump(&startDone);
549             }
550         }
551         Bind(&arg0NotLessZero);
552         {
553             Label argLessLen(env);
554             Label argNotLessLen(env);
555             Branch(Int64LessThan(argStart, thisArrLen), &argLessLen, &argNotLessLen);
556             Bind(&argLessLen);
557             {
558                 start = argStart;
559                 Jump(&startDone);
560             }
561             Bind(&argNotLessLen);
562             {
563                 start = thisArrLen;
564                 Jump(&startDone);
565             }
566         }
567         Bind(&startDone);
568         {
569             Label endDone(env);
570             Label msg1Def(env);
571             Branch(TaggedIsUndefined(msg1), &endDone, &msg1Def);
572             Bind(&msg1Def);
573             {
574             Label msg1Int(env);
575             Branch(TaggedIsInt(msg1), &msg1Int, slowPath);
576             Bind(&msg1Int);
577             {
578                 GateRef argEnd = SExtInt32ToInt64(TaggedGetInt(msg1));
579                 Label arg1LessZero(env);
580                 Label arg1NotLessZero(env);
581                 Branch(Int64LessThan(argEnd, Int64(0)), &arg1LessZero, &arg1NotLessZero);
582                 Bind(&arg1LessZero);
583                 {
584                     Label tempGreaterZero(env);
585                     Label tempNotGreaterZero(env);
586                     GateRef tempEnd = Int64Add(argEnd, thisArrLen);
587                     Branch(Int64GreaterThan(tempEnd, Int64(0)), &tempGreaterZero, &tempNotGreaterZero);
588                     Bind(&tempGreaterZero);
589                     {
590                         end = tempEnd;
591                         Jump(&endDone);
592                     }
593                     Bind(&tempNotGreaterZero);
594                     {
595                         end = Int64(0);
596                         Jump(&endDone);
597                     }
598                 }
599                 Bind(&arg1NotLessZero);
600                 {
601                     Label argLessLen(env);
602                     Label argNotLessLen(env);
603                     Branch(Int64LessThan(argEnd, thisArrLen), &argLessLen, &argNotLessLen);
604                     Bind(&argLessLen);
605                     {
606                         end = argEnd;
607                         Jump(&endDone);
608                     }
609                     Bind(&argNotLessLen);
610                     {
611                         end = thisArrLen;
612                         Jump(&endDone);
613                     }
614                 }
615             }
616         }
617             Bind(&endDone);
618             {
619                 DEFVARIABLE(count, VariableType::INT64(), Int64(0));
620                 GateRef tempCnt = Int64Sub(*end, *start);
621                 Label tempCntGreaterOrEqualZero(env);
622                 Label tempCntDone(env);
623                 Branch(Int64LessThan(tempCnt, Int64(0)), &tempCntDone, &tempCntGreaterOrEqualZero);
624                 Bind(&tempCntGreaterOrEqualZero);
625                 {
626                     count = tempCnt;
627                     Jump(&tempCntDone);
628                 }
629                 Bind(&tempCntDone);
630                 {
631                     Label notOverFlow(env);
632                     Branch(Int64GreaterThan(*count, Int64(JSObject::MAX_GAP)), slowPath, &notOverFlow);
633                     Bind(&notOverFlow);
634                     {
635             GateRef newArray = NewArray(glue, *count);
636             GateRef thisEles = GetElementsArray(thisValue);
637             GateRef thisElesLen = ZExtInt32ToInt64(GetLengthOfTaggedArray(thisEles));
638 
639             Label inThisEles(env);
640             Label outThisEles(env);
641             Branch(Int64GreaterThan(thisElesLen, Int64Add(*start, *count)), &inThisEles, &outThisEles);
642             Bind(&inThisEles);
643             {
644                 DEFVARIABLE(idx, VariableType::INT64(), Int64(0));
645                 Label loopHead(env);
646                 Label loopEnd(env);
647                 Label next(env);
648                 Label loopExit(env);
649                 Jump(&loopHead);
650                 LoopBegin(&loopHead);
651                 {
652                     Branch(Int64LessThan(*idx, *count), &next, &loopExit);
653                     Bind(&next);
654 
655                     GateRef ele = GetTaggedValueWithElementsKind(thisValue, Int64Add(*idx, *start));
656                     SetValueWithElementsKind(glue, newArray, ele, *idx, Boolean(true),
657                                              Int32(static_cast<uint32_t>(ElementsKind::NONE)));
658                     Jump(&loopEnd);
659                 }
660                 Bind(&loopEnd);
661                 idx = Int64Add(*idx, Int64(1));
662                 LoopEnd(&loopHead);
663                 Bind(&loopExit);
664                 result->WriteVariable(newArray);
665                 Jump(exit);
666             }
667             Bind(&outThisEles);
668             {
669                 DEFVARIABLE(idx, VariableType::INT64(), Int64(0));
670                 Label loopHead(env);
671                 Label loopEnd(env);
672                 Label next(env);
673                 Label loopExit(env);
674                 Jump(&loopHead);
675                 LoopBegin(&loopHead);
676                 {
677                     Branch(Int64LessThan(*idx, *count), &next, &loopExit);
678                     Bind(&next);
679                     GateRef index = Int64Add(*idx, *start);
680                     DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
681 
682                     Label indexOutRange(env);
683                     Label indexInRange(env);
684                     Label setEle(env);
685                     Branch(Int64GreaterThan(thisElesLen, index), &indexInRange, &indexOutRange);
686                     Bind(&indexInRange);
687                     {
688                         ele = GetTaggedValueWithElementsKind(thisValue, index);
689                         Jump(&setEle);
690                     }
691                     Bind(&indexOutRange);
692                     {
693                         ele = Hole();
694                         Jump(&setEle);
695                     }
696                     Bind(&setEle);
697                     SetValueWithElementsKind(glue, newArray, *ele, *idx, Boolean(true),
698                                              Int32(static_cast<uint32_t>(ElementsKind::NONE)));
699                     Jump(&loopEnd);
700                 }
701                 Bind(&loopEnd);
702                 idx = Int64Add(*idx, Int64(1));
703                 LoopEnd(&loopHead);
704                 Bind(&loopExit);
705                 result->WriteVariable(newArray);
706                 Jump(exit);
707             }
708         }
709                 }
710             }
711         }
712     }
713 }
714 
Sort(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)715 void BuiltinsArrayStubBuilder::Sort(GateRef glue, GateRef thisValue,
716     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
717 {
718     auto env = GetEnvironment();
719     Label isHeapObject(env);
720     Label isJsArray(env);
721     Label isStability(env);
722     Label defaultConstr(env);
723     Label notCOWArray(env);
724     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
725     Bind(&isHeapObject);
726     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
727     Bind(&isJsArray);
728     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
729     Bind(&defaultConstr);
730     Branch(IsStableJSArray(glue, thisValue), &isStability, slowPath);
731     Bind(&isStability);
732     Branch(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
733     Bind(&notCOWArray);
734 
735     Label argUndefined(env);
736     GateRef callbackFnHandle = GetCallArg0(numArgs);
737     GateRef isUndefined = TaggedIsUndefined(callbackFnHandle);
738     Branch(isUndefined, &argUndefined, slowPath);
739     Bind(&argUndefined);
740     {
741         Label isStableJSArray(env);
742         GateRef stableArray = IsStableJSArray(glue, thisValue);
743         Branch(BoolAnd(stableArray, isUndefined), &isStableJSArray, slowPath);
744         Bind(&isStableJSArray);
745         {
746             GateRef len = ZExtInt32ToInt64(GetArrayLength(thisValue));
747             DEFVARIABLE(i, VariableType::INT64(), Int64(1));
748             DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined());
749             DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined());
750             DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined());
751             Label loopHead(env);
752             Label loopEnd(env);
753             Label next(env);
754             Label loopExit(env);
755             Jump(&loopHead);
756             LoopBegin(&loopHead);
757             {
758                 Branch(Int64LessThan(*i, len), &next, &loopExit);
759                 Bind(&next);
760                 DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0));
761                 DEFVARIABLE(endIndex, VariableType::INT64(), *i);
762                 presentValue = GetTaggedValueWithElementsKind(thisValue, *i);
763                 Label loopHead1(env);
764                 Label loopEnd1(env);
765                 Label next1(env);
766                 Label loopExit1(env);
767                 Jump(&loopHead1);
768                 LoopBegin(&loopHead1);
769                 {
770                     Branch(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1);
771                     Bind(&next1);
772                     GateRef sum = Int64Add(*beginIndex, *endIndex);
773                     GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half
774                     middleValue = GetTaggedValueWithElementsKind(thisValue, middleIndex);
775                     Label isInt(env);
776                     Branch(BoolAnd(TaggedIsInt(*middleValue), TaggedIsInt(*presentValue)), &isInt, slowPath);
777                     Bind(&isInt);
778                     {
779                         GateRef compareResult =
780                             CallNGCRuntime(glue, RTSTUB_ID(FastArraySort), {*middleValue, *presentValue});
781                         Label less0(env);
782                         Label greater0(env);
783                         Branch(Int32LessThanOrEqual(compareResult, Int32(0)), &less0, &greater0);
784                         Bind(&greater0);
785                         {
786                             endIndex = middleIndex;
787                             Jump(&loopEnd1);
788                         }
789                         Bind(&less0);
790                         {
791                             beginIndex = middleIndex;
792                             beginIndex = Int64Add(*beginIndex, Int64(1));
793                             Jump(&loopEnd1);
794                         }
795                     }
796                 }
797                 Bind(&loopEnd1);
798                 LoopEnd(&loopHead1);
799                 Bind(&loopExit1);
800 
801                 Label shouldCopy(env);
802                 GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0));
803                 GateRef lessI = Int64LessThan(*endIndex, *i);
804                 Branch(BoolAnd(isGreater0, lessI), &shouldCopy, &loopEnd);
805                 Bind(&shouldCopy);{
806                     DEFVARIABLE(j, VariableType::INT64(), *i);
807                     Label loopHead2(env);
808                     Label loopEnd2(env);
809                     Label next2(env);
810                     Label loopExit2(env);
811                     Jump(&loopHead2);
812                     LoopBegin(&loopHead2);
813                     {
814                         Branch(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2);
815                         Bind(&next2);
816                         previousValue = GetTaggedValueWithElementsKind(thisValue, Int64Sub(*j, Int64(1)));
817                         SetValueWithElementsKind(glue, thisValue, *previousValue, *j, Boolean(false),
818                                                  Int32(static_cast<uint32_t>(ElementsKind::NONE)));
819                         Jump(&loopEnd2);
820                         }
821                     Bind(&loopEnd2);
822                     j = Int64Sub(*j, Int64(1));
823                     LoopEnd(&loopHead2);
824                     Bind(&loopExit2);
825                     SetValueWithElementsKind(glue, thisValue, *presentValue, *endIndex, Boolean(false),
826                                              Int32(static_cast<uint32_t>(ElementsKind::NONE)));
827                     Jump(&loopEnd);
828                 }
829             }
830             Bind(&loopEnd);
831             i = Int64Add(*i, Int64(1));
832             LoopEnd(&loopHead);
833             Bind(&loopExit);
834             result->WriteVariable(thisValue);
835             Jump(exit);
836         }
837     }
838 }
839 
Reduce(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)840 void BuiltinsArrayStubBuilder::Reduce(GateRef glue, GateRef thisValue, GateRef numArgs,
841     Variable *result, Label *exit, Label *slowPath)
842 {
843     auto env = GetEnvironment();
844     DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0));
845     Label isHeapObject(env);
846     Label isJsArray(env);
847     Label defaultConstr(env);
848     Label atLeastOneArg(env);
849     Label callbackFnHandleHeapObject(env);
850     Label callbackFnHandleCallable(env);
851     Label noTypeError(env);
852 
853     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
854     Bind(&isHeapObject);
855     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
856     Bind(&isJsArray);
857     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
858     Bind(&defaultConstr);
859     thisLen = GetArrayLength(thisValue);
860     Branch(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
861     Bind(&atLeastOneArg);
862     GateRef callbackFnHandle = GetCallArg0(numArgs);
863     Branch(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath);
864     Bind(&callbackFnHandleHeapObject);
865     Branch(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath);
866     Bind(&callbackFnHandleCallable);
867     GateRef thisLenIsZero = Int32Equal(*thisLen, Int32(0));
868     GateRef numArgsLessThanTwo = Int64LessThan(numArgs, IntPtr(2));
869     Branch(BoolAnd(thisLenIsZero, numArgsLessThanTwo), slowPath, &noTypeError);
870     Bind(&noTypeError);
871     {
872         DEFVARIABLE(accumulator, VariableType::JS_ANY(), Undefined());
873         DEFVARIABLE(k, VariableType::INT32(), Int32(0));
874 
875         Label updateAccumulator(env);
876         Label checkForStableJSArray(env);
877 
878         Branch(Int64Equal(numArgs, IntPtr(2)), &updateAccumulator, slowPath); // 2: provide initialValue param
879         Bind(&updateAccumulator);
880         {
881             accumulator = GetCallArg1(numArgs);
882             Jump(&checkForStableJSArray);
883         }
884         Bind(&checkForStableJSArray);
885         {
886             Label isStableJSArray(env);
887             Label notStableJSArray(env);
888             Branch(IsStableJSArray(glue, thisValue), &isStableJSArray, &notStableJSArray);
889             Bind(&isStableJSArray);
890             {
891                 GateRef argsLength = Int32(4); // 4: «accumulator, kValue, k, thisValue»
892                 NewObjectStubBuilder newBuilder(this);
893                 GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
894                 Label loopHead(env);
895                 Label next(env);
896                 Label loopEnd(env);
897                 Label loopExit(env);
898                 Jump(&loopHead);
899                 LoopBegin(&loopHead);
900                 {
901                     Branch(Int32LessThan(*k, *thisLen), &next, &loopExit);
902                     Bind(&next);
903                     {
904                         Label updateK(env);
905                         Label notHole(env);
906                         Label changeThisLen(env);
907                         Label updateCallResult(env);
908                         GateRef elements = GetElementsArray(thisValue);
909                         GateRef kValue = GetTaggedValueWithElementsKind(thisValue, *k);
910                         Branch(TaggedIsHole(kValue), &loopEnd, &notHole);
911                         Bind(&notHole);
912                         {
913                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
914                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), kValue);
915                             // 2 : parameter location
916                             SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
917                             // 3 : parameter location
918                             SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
919                             GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
920                             GateRef callResult = JSCallDispatch(glue, callbackFnHandle, argsLength, 0,
921                                 Circuit::NullGate(), JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
922                                 {argsLength, argv, Undefined()});
923                             Label hasException1(env);
924                             Label notHasException1(env);
925                             Branch(HasPendingException(glue), &hasException1, &notHasException1);
926                             Bind(&hasException1);
927                             {
928                                 result->WriteVariable(Exception());
929                                 Jump(exit);
930                             }
931                             Bind(&notHasException1);
932                             GateRef newLen = GetLengthOfTaggedArray(elements);
933                             Branch(Int32LessThan(newLen, *thisLen), &changeThisLen, &updateCallResult);
934                             Bind(&changeThisLen);
935                             {
936                                 thisLen = newLen;
937                                 Jump(&updateCallResult);
938                             }
939                             Bind(&updateCallResult);
940                             {
941                                 accumulator = callResult;
942                                 Jump(&loopEnd);
943                             }
944                         }
945                     }
946                 }
947                 Bind(&loopEnd);
948                 {
949                     k = Int32Add(*k, Int32(1));
950 
951                     Label isStableJSArray1(env);
952                     Label notStableJSArray1(env);
953                     Branch(IsStableJSArray(glue, thisValue), &isStableJSArray1, &notStableJSArray1);
954                     Bind(&notStableJSArray1);
955                     {
956                         Jump(&loopExit);
957                     }
958                     Bind(&isStableJSArray1);
959                     LoopEnd(&loopHead);
960                 }
961                 Bind(&loopExit);
962                 Jump(&notStableJSArray);
963             }
964             Bind(&notStableJSArray);
965             {
966                 Label finish(env);
967                 Label callRT(env);
968                 Branch(Int32LessThan(*k, *thisLen), &callRT, &finish);
969                 Bind(&callRT);
970                 {
971                     accumulator = CallRuntime(glue, RTSTUB_ID(JSArrayReduceUnStable), { thisValue, thisValue,
972                         IntToTaggedInt(*k), IntToTaggedInt(*thisLen), *accumulator, callbackFnHandle });
973                     Jump(&finish);
974                 }
975                 Bind(&finish);
976                 {
977                     result->WriteVariable(*accumulator);
978                     Jump(exit);
979                 }
980             }
981         }
982     }
983 }
984 
985 // Note: unused arguments are reserved for further development
Reverse(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)986 void BuiltinsArrayStubBuilder::Reverse(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
987     Variable *result, Label *exit, Label *slowPath)
988 {
989     auto env = GetEnvironment();
990     Label isHeapObject(env);
991     Label isJsArray(env);
992     Label isStability(env);
993     Label defaultConstr(env);
994     Label notCOWArray(env);
995     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
996     Bind(&isHeapObject);
997     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
998     Bind(&isJsArray);
999     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
1000     Bind(&defaultConstr);
1001     Branch(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1002     Bind(&isStability);
1003     Branch(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
1004     Bind(&notCOWArray);
1005 
1006     GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1007     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
1008     DEFVARIABLE(j, VariableType::INT64(),  Int64Sub(thisArrLen, Int64(1)));
1009 
1010     Label loopHead(env);
1011     Label loopEnd(env);
1012     Label next(env);
1013     Label loopExit(env);
1014     Jump(&loopHead);
1015     LoopBegin(&loopHead);
1016     {
1017         Label arrayValue(env);
1018         Label valueEqual(env);
1019         Branch(Int64LessThan(*i, *j), &next, &loopExit);
1020         Bind(&next);
1021         {
1022             GateRef lower = GetTaggedValueWithElementsKind(thisValue, *i);
1023             GateRef upper = GetTaggedValueWithElementsKind(thisValue, *j);
1024             SetValueWithElementsKind(glue, thisValue, upper, *i, Boolean(false),
1025                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1026             SetValueWithElementsKind(glue, thisValue, lower, *j, Boolean(false),
1027                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1028             Jump(&loopEnd);
1029         }
1030     }
1031     Bind(&loopEnd);
1032     i = Int64Add(*i, Int64(1));
1033     j = Int64Sub(*j, Int64(1));
1034     LoopEnd(&loopHead);
1035     Bind(&loopExit);
1036     result->WriteVariable(thisValue);
1037     Jump(exit);
1038 }
1039 
IsJsArrayWithLengthLimit(GateRef glue,GateRef object,uint32_t maxLength,JsArrayRequirements requirements)1040 GateRef BuiltinsArrayStubBuilder::IsJsArrayWithLengthLimit(GateRef glue, GateRef object,
1041     uint32_t maxLength, JsArrayRequirements requirements)
1042 {
1043     auto env = GetEnvironment();
1044     Label entry(env);
1045     env->SubCfgEntry(&entry);
1046     Label isHeapObject(env);
1047     Label isJsArray(env);
1048     Label stabilityCheckPassed(env);
1049     Label defaultConstructorCheckPassed(env);
1050     Label exit(env);
1051     DEFVARIABLE(result, VariableType::BOOL(), False());
1052 
1053     Branch(TaggedIsHeapObject(object), &isHeapObject, &exit);
1054     Bind(&isHeapObject);
1055     Branch(IsJsArray(object), &isJsArray, &exit);
1056     Bind(&isJsArray);
1057     if (requirements.stable) {
1058         Branch(IsStableJSArray(glue, object), &stabilityCheckPassed, &exit);
1059     } else {
1060         Jump(&stabilityCheckPassed);
1061     }
1062     Bind(&stabilityCheckPassed);
1063     if (requirements.defaultConstructor) {
1064         // If HasConstructor bit is set to 1, then the constructor has been modified.
1065         Branch(HasConstructor(object), &exit, &defaultConstructorCheckPassed);
1066     } else {
1067         Jump(&defaultConstructorCheckPassed);
1068     }
1069     Bind(&defaultConstructorCheckPassed);
1070     result.WriteVariable(Int32UnsignedLessThanOrEqual(GetArrayLength(object), Int32(maxLength)));
1071     Jump(&exit);
1072     Bind(&exit);
1073     GateRef ret = *result;
1074     env->SubCfgExit();
1075     return ret;
1076 }
1077 
Values(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1078 void BuiltinsArrayStubBuilder::Values(GateRef glue, GateRef thisValue,
1079     [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1080 {
1081     auto env = GetEnvironment();
1082     Label isHeapObject(env);
1083     Label isJsArray(env);
1084     Label defaultConstr(env);
1085     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1086     Bind(&isHeapObject);
1087     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
1088     Bind(&isJsArray);
1089     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
1090     Bind(&defaultConstr);
1091     ConstantIndex iterClassIdx = ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX;
1092     GateRef iteratorHClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, iterClassIdx);
1093     NewObjectStubBuilder newBuilder(this);
1094     newBuilder.SetParameters(glue, 0);
1095     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1096     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1097     GateRef prototype = GetGlobalEnvValue(VariableType::JS_POINTER(), glueGlobalEnv,
1098                                           GlobalEnv::ARRAY_ITERATOR_PROTOTYPE_INDEX);
1099     SetPrototypeToHClass(VariableType::JS_POINTER(), glue, iteratorHClass, prototype);
1100     GateRef iter = newBuilder.NewJSObject(glue, iteratorHClass);
1101     SetIteratedArrayOfArrayIterator(glue, iter, thisValue);
1102     SetNextIndexOfArrayIterator(glue, iter, Int32(0));
1103     GateRef kind = Int32(static_cast<int32_t>(IterationKind::VALUE));
1104     SetBitFieldOfArrayIterator(glue, iter, kind);
1105     result->WriteVariable(iter);
1106     Jump(exit);
1107 }
1108 
Find(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1109 void BuiltinsArrayStubBuilder::Find(GateRef glue, GateRef thisValue, GateRef numArgs,
1110     Variable *result, Label *exit, Label *slowPath)
1111 {
1112     auto env = GetEnvironment();
1113     Label isHeapObject(env);
1114     Label isJsArray(env);
1115     Label isStability(env);
1116     Label defaultConstr(env);
1117     Label notCOWArray(env);
1118     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1119     Bind(&isHeapObject);
1120     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
1121     Bind(&isJsArray);
1122     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
1123     Bind(&defaultConstr);
1124     Branch(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1125     Bind(&isStability);
1126     Branch(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
1127     Bind(&notCOWArray);
1128 
1129     GateRef callbackFnHandle = GetCallArg0(numArgs);
1130     Label arg0HeapObject(env);
1131     Branch(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
1132     Bind(&arg0HeapObject);
1133     Label callable(env);
1134     Branch(IsCallable(callbackFnHandle), &callable, slowPath);
1135     Bind(&callable);
1136     GateRef argHandle = GetCallArg1(numArgs);
1137     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
1138     DEFVARIABLE(i, VariableType::INT64(), Int64(0));
1139     Label loopHead(env);
1140     Label loopEnd(env);
1141     Label next(env);
1142     Label loopExit(env);
1143     Jump(&loopHead);
1144     LoopBegin(&loopHead);
1145     {
1146         Label hasException0(env);
1147         Label notHasException0(env);
1148         Branch(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
1149         Bind(&next);
1150         GateRef kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
1151         Branch(HasPendingException(glue), &hasException0, &notHasException0);
1152         Bind(&hasException0);
1153         {
1154             result->WriteVariable(Exception());
1155             Jump(exit);
1156         }
1157         Bind(&notHasException0);
1158         {
1159             GateRef key = Int64ToTaggedInt(*i);
1160             Label hasException(env);
1161             Label notHasException(env);
1162             GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
1163                 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { argHandle, kValue, key, thisValue });
1164             Branch(HasPendingException(glue), &hasException, &notHasException);
1165             Bind(&hasException);
1166             {
1167                 result->WriteVariable(retValue);
1168                 Jump(exit);
1169             }
1170             Bind(&notHasException);
1171             {
1172                 Label find(env);
1173                 Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
1174                 Bind(&find);
1175                 {
1176                     result->WriteVariable(kValue);
1177                     Jump(exit);
1178                 }
1179             }
1180         }
1181     }
1182     Bind(&loopEnd);
1183     thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1184     i = Int64Add(*i, Int64(1));
1185     LoopEnd(&loopHead);
1186     Bind(&loopExit);
1187     Jump(exit);
1188 }
1189 
FindIndex(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1190 void BuiltinsArrayStubBuilder::FindIndex(GateRef glue, GateRef thisValue, GateRef numArgs,
1191     Variable *result, Label *exit, Label *slowPath)
1192 {
1193     auto env = GetEnvironment();
1194     Label isHeapObject(env);
1195     Label isJsArray(env);
1196     Label defaultConstr(env);
1197     Label notCOWArray(env);
1198     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1199     Bind(&isHeapObject);
1200     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
1201     Bind(&isJsArray);
1202     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
1203     Bind(&defaultConstr);
1204     Branch(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
1205     Bind(&notCOWArray);
1206 
1207     Label arg0HeapObject(env);
1208     Label callable(env);
1209     Label stableJSArray(env);
1210     Label notStableJSArray(env);
1211     GateRef callbackFnHandle = GetCallArg0(numArgs);
1212     Branch(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath);
1213     Bind(&arg0HeapObject);
1214     Branch(IsCallable(callbackFnHandle), &callable, slowPath);
1215     Bind(&callable);
1216     result->WriteVariable(IntToTaggedPtr(Int32(-1)));
1217     GateRef argHandle = GetCallArg1(numArgs);
1218     DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue)));
1219     Branch(IsStableJSArray(glue, thisValue), &stableJSArray, &notStableJSArray);
1220     Bind(&stableJSArray);
1221     {
1222         DEFVARIABLE(i, VariableType::INT64(), Int64(0));
1223         DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
1224         Label loopHead(env);
1225         Label loopEnd(env);
1226         Label next(env);
1227         Label loopExit(env);
1228         Jump(&loopHead);
1229         LoopBegin(&loopHead);
1230         {
1231             Branch(Int64LessThan(*i, *thisArrLen), &next, &loopExit);
1232             Bind(&next);
1233             kValue = GetTaggedValueWithElementsKind(thisValue, *i);
1234             Label isHole(env);
1235             Label notHole(env);
1236             Branch(TaggedIsHole(*kValue), &isHole, &notHole);
1237             Bind(&isHole);
1238             {
1239                 Label hasException0(env);
1240                 Label notHasException0(env);
1241                 GateRef res = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation());
1242                 Branch(HasPendingException(glue), &hasException0, &notHasException0);
1243                 Bind(&hasException0);
1244                 {
1245                     result->WriteVariable(Exception());
1246                     Jump(exit);
1247                 }
1248                 Bind(&notHasException0);
1249                 {
1250                     Label resIsHole(env);
1251                     Label resNotHole(env);
1252                     Branch(TaggedIsHole(res), &resIsHole, &resNotHole);
1253                     Bind(&resIsHole);
1254                     {
1255                         kValue = Undefined();
1256                         Jump(&notHole);
1257                     }
1258                     Bind(&resNotHole);{
1259                         kValue = res;
1260                         Jump(&notHole);
1261                     }
1262                 }
1263             }
1264             Bind(&notHole);
1265             {
1266                 GateRef key = IntToTaggedPtr(*i);
1267                 Label hasException(env);
1268                 Label notHasException(env);
1269                 Label checkStable(env);
1270                 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
1271                     Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
1272                     { argHandle, *kValue, key, thisValue });
1273                 Branch(TaggedIsException(retValue), &hasException, &notHasException);
1274                 Bind(&hasException);
1275                 {
1276                     result->WriteVariable(retValue);
1277                     Jump(exit);
1278                 }
1279                 Bind(&notHasException);
1280                 {
1281                     Label find(env);
1282                     Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &checkStable);
1283                     Bind(&find);
1284                     {
1285                         result->WriteVariable(key);
1286                         Jump(exit);
1287                     }
1288                 }
1289                 Bind(&checkStable);
1290                 i = Int64Add(*i, Int64(1));
1291                 Branch(IsStableJSArray(glue, thisValue), &loopEnd, &notStableJSArray);
1292             }
1293         }
1294         Bind(&loopEnd);
1295         thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1296         LoopEnd(&loopHead);
1297         Bind(&loopExit);
1298         Jump(exit);
1299     }
1300     Bind(&notStableJSArray);
1301     {
1302         DEFVARIABLE(j, VariableType::INT64(), Int64(0));
1303         Label loopHead(env);
1304         Label loopEnd(env);
1305         Label next(env);
1306         Label loopExit(env);
1307         Jump(&loopHead);
1308         LoopBegin(&loopHead);
1309         {
1310             thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1311             Branch(Int64LessThan(*j, *thisArrLen), &next, &loopExit);
1312             Bind(&next);
1313             {
1314                 Label hasException0(env);
1315                 Label notHasException0(env);
1316                 GateRef kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*j), ProfileOperation());
1317                 Branch(HasPendingException(glue), &hasException0, &notHasException0);
1318                 Bind(&hasException0);
1319                 {
1320                     result->WriteVariable(Exception());
1321                     Jump(exit);
1322                 }
1323                 Bind(&notHasException0);
1324                 {
1325                     GateRef key = IntToTaggedPtr(*j);
1326                     Label hasException(env);
1327                     Label notHasException(env);
1328                     GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS),
1329                         0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
1330                         { argHandle, kValue, key, thisValue });
1331                     Branch(TaggedIsException(retValue), &hasException, &notHasException);
1332                     Bind(&hasException);
1333                     {
1334                         result->WriteVariable(retValue);
1335                         Jump(exit);
1336                     }
1337                     Bind(&notHasException);
1338                     {
1339                         Label find(env);
1340                         Branch(TaggedIsTrue(FastToBoolean(retValue)), &find, &loopEnd);
1341                         Bind(&find);
1342                         {
1343                             result->WriteVariable(key);
1344                             Jump(exit);
1345                         }
1346                     }
1347                 }
1348             }
1349         }
1350         Bind(&loopEnd);
1351         thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue));
1352         j = Int64Add(*j, Int64(1));
1353         LoopEnd(&loopHead);
1354         Bind(&loopExit);
1355         Jump(exit);
1356     }
1357 }
1358 
Push(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1359 void BuiltinsArrayStubBuilder::Push(GateRef glue, GateRef thisValue,
1360     GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
1361 {
1362     auto env = GetEnvironment();
1363     Label isHeapObject(env);
1364     Label isJsArray(env);
1365     Label isStability(env);
1366     Label setLength(env);
1367     Label smallArgs(env);
1368     Label checkSmallArgs(env);
1369 
1370     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1371     Bind(&isHeapObject);
1372     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
1373     Bind(&isJsArray);
1374 
1375     Branch(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1376     Bind(&isStability);
1377 
1378     GateRef oldLength = GetArrayLength(thisValue);
1379     *result = IntToTaggedPtr(oldLength);
1380 
1381     Branch(Int32Equal(ChangeIntPtrToInt32(numArgs), Int32(0)), exit, &checkSmallArgs);
1382     Bind(&checkSmallArgs);
1383     // now unsupport more than 2 args
1384     Branch(Int32LessThanOrEqual(ChangeIntPtrToInt32(numArgs), Int32(2)), &smallArgs, slowPath);
1385     Bind(&smallArgs);
1386     GateRef newLength = Int32Add(oldLength, ChangeIntPtrToInt32(numArgs));
1387 
1388     DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(thisValue));
1389     GateRef capacity = GetLengthOfTaggedArray(*elements);
1390     Label grow(env);
1391     Label setValue(env);
1392     Branch(Int32GreaterThan(newLength, capacity), &grow, &setValue);
1393     Bind(&grow);
1394     {
1395         elements =
1396             CallRuntime(glue, RTSTUB_ID(JSObjectGrowElementsCapacity), { thisValue, IntToTaggedInt(newLength) });
1397         Jump(&setValue);
1398     }
1399     Bind(&setValue);
1400     {
1401         Label oneArg(env);
1402         Label twoArg(env);
1403         DEFVARIABLE(index, VariableType::INT32(), Int32(0));
1404         DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
1405         Branch(Int64Equal(numArgs, IntPtr(1)), &oneArg, &twoArg);  // 1 one arg
1406         Bind(&oneArg);
1407         {
1408             value = GetCallArg0(numArgs);
1409             index = Int32Add(oldLength, Int32(0));  // 0 slot index
1410             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
1411                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1412             Jump(&setLength);
1413         }
1414         Bind(&twoArg);
1415         {
1416             value = GetCallArg0(numArgs);
1417             index = Int32Add(oldLength, Int32(0));  // 0 slot index
1418             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
1419                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1420             value = GetCallArg1(numArgs);
1421             index = Int32Add(oldLength, Int32(1));  // 1 slot index
1422             SetValueWithElementsKind(glue, thisValue, *value, *index, Boolean(true),
1423                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1424             Jump(&setLength);
1425         }
1426     }
1427     Bind(&setLength);
1428     SetArrayLength(glue, thisValue, newLength);
1429     result->WriteVariable(IntToTaggedPtr(newLength));
1430     Jump(exit);
1431 }
1432 
IsConcatSpreadable(GateRef glue,GateRef obj)1433 GateRef BuiltinsArrayStubBuilder::IsConcatSpreadable(GateRef glue, GateRef obj)
1434 {
1435     auto env = GetEnvironment();
1436     Label entry(env);
1437     env->SubCfgEntry(&entry);
1438     DEFVARIABLE(result, VariableType::BOOL(), False());
1439     Label exit(env);
1440     Label isEcmaObj(env);
1441     Branch(IsEcmaObject(obj), &isEcmaObj, &exit);
1442     Bind(&isEcmaObj);
1443     {
1444         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1445         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1446         GateRef isConcatsprKey =
1447             GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ISCONCAT_SYMBOL_INDEX);
1448         AccessObjectStubBuilder builder(this);
1449         GateRef spreadable =
1450             builder.LoadObjByValue(glue, obj, isConcatsprKey, Undefined(), Int32(0), ProfileOperation());
1451         Label isDefined(env);
1452         Label isUnDefined(env);
1453         Branch(TaggedIsUndefined(spreadable), &isUnDefined, &isDefined);
1454         Bind(&isUnDefined);
1455         {
1456             Label IsArray(env);
1457             Branch(IsJsArray(obj), &IsArray, &exit);
1458             Bind(&IsArray);
1459             result = True();
1460             Jump(&exit);
1461         }
1462         Bind(&isDefined);
1463         {
1464             result = TaggedIsTrue(spreadable);
1465             Jump(&exit);
1466         }
1467     }
1468     Bind(&exit);
1469     auto res = *result;
1470     env->SubCfgExit();
1471     return res;
1472 }
1473 
NewArray(GateRef glue,GateRef count)1474 GateRef BuiltinsArrayStubBuilder::NewArray(GateRef glue, GateRef count)
1475 {
1476     auto env = GetEnvironment();
1477     Label entry(env);
1478     env->SubCfgEntry(&entry);
1479     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1480     Label exit(env);
1481     Label setProperties(env);
1482     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1483     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1484     auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
1485     GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
1486     NewObjectStubBuilder newBuilder(this);
1487     newBuilder.SetParameters(glue, 0);
1488     result = newBuilder.NewJSArrayWithSize(intialHClass, count);
1489     Branch(TaggedIsException(*result), &exit, &setProperties);
1490     Bind(&setProperties);
1491     {
1492         GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
1493         Store(VariableType::INT32(), glue, *result, lengthOffset, TruncInt64ToInt32(count));
1494         GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
1495         SetPropertyInlinedProps(glue, *result, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
1496         SetExtensibleToBitfield(glue, *result, true);
1497         Jump(&exit);
1498     }
1499     Bind(&exit);
1500     auto res = *result;
1501     env->SubCfgExit();
1502     return res;
1503 }
1504 
Includes(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1505 void BuiltinsArrayStubBuilder::Includes(GateRef glue, GateRef thisValue, GateRef numArgs,
1506     Variable *result, Label *exit, Label *slowPath)
1507 {
1508     auto env = GetEnvironment();
1509     Label isDictMode(env);
1510     Label isHeapObject(env);
1511     Label isJsArray(env);
1512     Label notFound(env);
1513     Label thisLenNotZero(env);
1514     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1515     Bind(&isHeapObject);
1516     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
1517     Bind(&isJsArray);
1518     Branch(IsDictionaryMode(thisValue), &isDictMode, slowPath);
1519     Bind(&isDictMode);
1520     GateRef thisLen = GetArrayLength(thisValue);
1521     Branch(Int32Equal(thisLen, Int32(0)), &notFound, &thisLenNotZero);
1522     Bind(&thisLenNotZero);
1523     {
1524         DEFVARIABLE(fromIndex, VariableType::INT32(), Int32(0));
1525         Label getArgTwo(env);
1526         Label nextProcess(env);
1527         Branch(Int64Equal(numArgs, IntPtr(2)), &getArgTwo, &nextProcess); // 2: 2 parameters
1528         Bind(&getArgTwo);
1529         {
1530             Label secondArgIsInt(env);
1531             GateRef fromIndexTemp = GetCallArg1(numArgs);
1532             Branch(TaggedIsInt(fromIndexTemp), &secondArgIsInt, slowPath);
1533             Bind(&secondArgIsInt);
1534             fromIndex = GetInt32OfTInt(fromIndexTemp);
1535             Jump(&nextProcess);
1536         }
1537         Bind(&nextProcess);
1538         {
1539             Label atLeastOneArg(env);
1540             Label setBackZero(env);
1541             Label calculateFrom(env);
1542             Label nextCheck(env);
1543             Branch(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
1544             Bind(&atLeastOneArg);
1545             Branch(Int32GreaterThanOrEqual(*fromIndex, thisLen), &notFound, &nextCheck);
1546             Bind(&nextCheck);
1547             {
1548                 GateRef negThisLen = Int32Sub(Int32(0), thisLen);
1549                 Branch(Int32LessThan(*fromIndex, negThisLen), &setBackZero, &calculateFrom);
1550                 Bind(&setBackZero);
1551                 {
1552                     fromIndex = Int32(0);
1553                     Jump(&calculateFrom);
1554                 }
1555                 Bind(&calculateFrom);
1556                 {
1557                     DEFVARIABLE(from, VariableType::INT32(), Int32(0));
1558                     Label fromIndexGreaterOrEqualZero(env);
1559                     Label fromIndexLessThanZero(env);
1560                     Label startLoop(env);
1561                     Branch(Int32GreaterThanOrEqual(*fromIndex, Int32(0)),
1562                         &fromIndexGreaterOrEqualZero, &fromIndexLessThanZero);
1563                     Bind(&fromIndexGreaterOrEqualZero);
1564                     {
1565                         from = *fromIndex;
1566                         Jump(&startLoop);
1567                     }
1568                     Bind(&fromIndexLessThanZero);
1569                     {
1570                         Label isLenFromIndex(env);
1571                         GateRef lenFromIndexSum = Int32Add(thisLen, *fromIndex);
1572                         Branch(Int32GreaterThanOrEqual(lenFromIndexSum, Int32(0)), &isLenFromIndex, &startLoop);
1573                         Bind(&isLenFromIndex);
1574                         {
1575                             from = lenFromIndexSum;
1576                             Jump(&startLoop);
1577                         }
1578                     }
1579                     Bind(&startLoop);
1580                     {
1581                         GateRef searchElement = GetCallArg0(numArgs);
1582                         Label loopHead(env);
1583                         Label loopEnd(env);
1584                         Label next(env);
1585                         Label loopExit(env);
1586                         Jump(&loopHead);
1587                         LoopBegin(&loopHead);
1588                         {
1589                             Branch(Int32LessThan(*from, thisLen), &next, &loopExit);
1590                             Bind(&next);
1591                             {
1592                                 Label notHoleOrUndefValue(env);
1593                                 Label valueFound(env);
1594                                 GateRef value = GetTaggedValueWithElementsKind(thisValue, *from);
1595                                 GateRef isHole = TaggedIsHole(value);
1596                                 GateRef isUndef = TaggedIsUndefined(value);
1597                                 Branch(BoolOr(isHole, isUndef), slowPath, &notHoleOrUndefValue);
1598                                 Bind(&notHoleOrUndefValue);
1599                                 GateRef valueEqual = StubBuilder::SameValueZero(glue, searchElement, value);
1600                                 Branch(valueEqual, &valueFound, &loopEnd);
1601                                 Bind(&valueFound);
1602                                 {
1603                                     result->WriteVariable(TaggedTrue());
1604                                     Jump(exit);
1605                                 }
1606                             }
1607                         }
1608                         Bind(&loopEnd);
1609                         from = Int32Add(*from, Int32(1));
1610                         LoopEnd(&loopHead);
1611                         Bind(&loopExit);
1612                         Jump(&notFound);
1613                     }
1614                 }
1615             }
1616         }
1617     }
1618     Bind(&notFound);
1619     {
1620         result->WriteVariable(TaggedFalse());
1621         Jump(exit);
1622     }
1623 }
1624 
From(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1625 void BuiltinsArrayStubBuilder::From(GateRef glue, [[maybe_unused]] GateRef thisValue, GateRef numArgs,
1626     Variable *result, Label *exit, Label *slowPath)
1627 {
1628     auto env = GetEnvironment();
1629     GateRef item = GetCallArg0(numArgs);
1630     Label stringItem(env);
1631     Branch(TaggedIsString(item), &stringItem, slowPath);
1632     Bind(&stringItem);
1633     Label undefFn(env);
1634     GateRef fn = GetCallArg1(numArgs);
1635     Branch(TaggedIsUndefined(fn), &undefFn, slowPath);
1636     Bind(&undefFn);
1637     GateRef strLen = GetLengthFromString(item);
1638     Label lessStrLen(env);
1639     Branch(Int32LessThan(strLen, Int32(builtins::StringToListResultCache::MAX_STRING_LENGTH)), &lessStrLen, slowPath);
1640     Bind(&lessStrLen);
1641     GateRef cacheArray = CallNGCRuntime(glue, RTSTUB_ID(GetStringToListCacheArray), { glue });
1642 
1643     Label cacheDef(env);
1644     Branch(TaggedIsUndefined(cacheArray), slowPath, &cacheDef);
1645     Bind(&cacheDef);
1646     {
1647         GateRef hash = GetHashcodeFromString(glue, item);
1648         GateRef entry = Int32And(hash, Int32Sub(Int32(builtins::StringToListResultCache::CACHE_SIZE), Int32(1)));
1649         GateRef index = Int32Mul(entry, Int32(builtins::StringToListResultCache::ENTRY_SIZE));
1650         GateRef cacheStr = GetValueFromTaggedArray(cacheArray,
1651             Int32Add(index, Int32(builtins::StringToListResultCache::STRING_INDEX)));
1652         Label cacheStrDef(env);
1653         Branch(TaggedIsUndefined(cacheStr), slowPath, &cacheStrDef);
1654         Bind(&cacheStrDef);
1655         Label strEqual(env);
1656         Label strSlowEqual(env);
1657         // cache str is intern
1658         Branch(Equal(cacheStr, item), &strEqual, &strSlowEqual);
1659         Bind(&strSlowEqual);
1660         Branch(FastStringEqual(glue, cacheStr, item), &strEqual, slowPath);
1661         Bind(&strEqual);
1662 
1663         GateRef cacheResArray = GetValueFromTaggedArray(cacheArray,
1664             Int32Add(index, Int32(builtins::StringToListResultCache::ARRAY_INDEX)));
1665         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1666         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1667         auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
1668         GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
1669         NewObjectStubBuilder newBuilder(this);
1670         newBuilder.SetParameters(glue, 0);
1671         GateRef newArray = newBuilder.NewJSObject(glue, intialHClass);
1672         Store(VariableType::INT32(), glue, newArray, IntPtr(JSArray::LENGTH_OFFSET), strLen);
1673         GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
1674         SetPropertyInlinedProps(glue, newArray, intialHClass, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
1675         SetExtensibleToBitfield(glue, newArray, true);
1676 
1677         SetElementsArray(VariableType::JS_ANY(), glue, newArray, cacheResArray);
1678         *result = newArray;
1679         Jump(exit);
1680     }
1681 }
1682 
CreateSpliceDeletedArray(GateRef glue,GateRef thisValue,GateRef actualDeleteCount,GateRef arrayCls,GateRef start)1683 GateRef BuiltinsArrayStubBuilder::CreateSpliceDeletedArray(GateRef glue, GateRef thisValue, GateRef actualDeleteCount,
1684     GateRef arrayCls, GateRef start)
1685 {
1686     auto env = GetEnvironment();
1687     Label subentry(env);
1688     Label exit(env);
1689     env->SubCfgEntry(&subentry);
1690     DEFVARIABLE(result, VariableType::BOOL(), False());
1691 
1692     // new delete array
1693     DEFVARIABLE(srcElements, VariableType::JS_ANY(), GetElementsArray(thisValue));
1694     NewObjectStubBuilder newBuilder(this);
1695     newBuilder.SetParameters(glue, 0);
1696     GateRef newArray = newBuilder.NewJSArrayWithSize(arrayCls, actualDeleteCount);
1697     GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
1698     Store(VariableType::INT32(), glue, newArray, lengthOffset, TruncInt64ToInt32(actualDeleteCount));
1699     GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
1700     SetPropertyInlinedProps(glue, newArray, arrayCls, accessor, Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
1701     SetExtensibleToBitfield(glue, newArray, true);
1702     result = newArray;
1703 
1704     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1705     Label loopHead(env);
1706     Label loopEnd(env);
1707     Label next(env);
1708     Label loopExit(env);
1709     Jump(&loopHead);
1710     LoopBegin(&loopHead);
1711     {
1712         Branch(Int32LessThan(*i, actualDeleteCount), &next, &loopExit);
1713         Bind(&next);
1714         Label setHole(env);
1715         Label setSrc(env);
1716         Branch(Int32GreaterThanOrEqual(Int32Add(*i, start),
1717             GetLengthOfTaggedArray(*srcElements)), &setHole, &setSrc);
1718         Bind(&setHole);
1719         {
1720             SetValueWithElementsKind(glue, newArray, Hole(), *i, Boolean(true),
1721                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1722             Jump(&loopEnd);
1723         }
1724         Bind(&setSrc);
1725         {
1726             GateRef val = GetTaggedValueWithElementsKind(thisValue, Int32Add(start, *i));
1727             SetValueWithElementsKind(glue, newArray, val, *i, Boolean(true),
1728                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1729             Jump(&loopEnd);
1730         }
1731     }
1732     Bind(&loopEnd);
1733     i = Int32Add(*i, Int32(1));
1734     LoopEnd(&loopHead);
1735     Bind(&loopExit);
1736     Jump(&exit);
1737 
1738     Bind(&exit);
1739     auto res = *result;
1740     env->SubCfgExit();
1741     return res;
1742 }
1743 
Splice(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath)1744 void BuiltinsArrayStubBuilder::Splice(GateRef glue, GateRef thisValue, GateRef numArgs,
1745     Variable *result, Label *exit, Label *slowPath)
1746 {
1747     auto env = GetEnvironment();
1748     Label isHeapObject(env);
1749     Label isJsArray(env);
1750     Label isStability(env);
1751     Label defaultConstr(env);
1752     Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
1753     Bind(&isHeapObject);
1754     Branch(IsJsArray(thisValue), &isJsArray, slowPath);
1755     Bind(&isJsArray);
1756     Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
1757     Bind(&defaultConstr);
1758     Branch(IsStableJSArray(glue, thisValue), &isStability, slowPath);
1759     Bind(&isStability);
1760     Label notCOWArray(env);
1761     Branch(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
1762     Bind(&notCOWArray);
1763 
1764     GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
1765     GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
1766     auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
1767     GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
1768     Label equalCls(env);
1769     GateRef arrayCls = LoadHClass(thisValue);
1770     Branch(Equal(intialHClass, arrayCls), &equalCls, slowPath);
1771     Bind(&equalCls);
1772 
1773     GateRef arrayLen = GetArrayLength(thisValue);
1774     Label lessThreeArg(env);
1775 
1776     DEFVARIABLE(start, VariableType::INT32(), Int32(0));
1777     DEFVARIABLE(insertCount, VariableType::INT32(), Int32(0));
1778     DEFVARIABLE(actualDeleteCount, VariableType::INT32(), Int32(0));
1779     GateRef argc = ChangeIntPtrToInt32(numArgs);
1780     Branch(Int32LessThanOrEqual(argc, Int32(3)), &lessThreeArg, slowPath); // 3 : three arg
1781     Bind(&lessThreeArg);
1782     {
1783         Label checkOverflow(env);
1784         Label greaterZero(env);
1785         Label greaterOne(env);
1786         Label checkGreaterOne(env);
1787         Label notOverflow(env);
1788         Branch(Int32GreaterThan(argc, Int32(0)), &greaterZero, &checkGreaterOne);
1789         Bind(&greaterZero);
1790         GateRef taggedStart = GetCallArg0(numArgs);
1791         Label taggedStartInt(env);
1792         Branch(TaggedIsInt(taggedStart), &taggedStartInt, slowPath);
1793         Bind(&taggedStartInt);
1794         {
1795             GateRef intStart = GetInt32OfTInt(taggedStart);
1796             start = CalArrayRelativePos(intStart, arrayLen);
1797         }
1798         actualDeleteCount = Int32Sub(arrayLen, *start);
1799         Jump(&checkGreaterOne);
1800         Bind(&checkGreaterOne);
1801         Branch(Int32GreaterThan(argc, Int32(1)), &greaterOne, &checkOverflow);
1802         Bind(&greaterOne);
1803         insertCount = Int32Sub(argc, Int32(2)); // 2 :  two args
1804         GateRef argDeleteCount = GetCallArg1(numArgs);
1805         Label argDeleteCountInt(env);
1806         Branch(TaggedIsInt(argDeleteCount), &argDeleteCountInt, slowPath);
1807         Bind(&argDeleteCountInt);
1808         DEFVARIABLE(deleteCount, VariableType::INT32(), TaggedGetInt(argDeleteCount));
1809         Label deleteCountLessZero(env);
1810         Label calActualDeleteCount(env);
1811         Branch(Int32LessThan(*deleteCount, Int32(0)), &deleteCountLessZero, &calActualDeleteCount);
1812         Bind(&deleteCountLessZero);
1813         deleteCount = Int32(0);
1814         Jump(&calActualDeleteCount);
1815         Bind(&calActualDeleteCount);
1816         actualDeleteCount = *deleteCount;
1817         Label lessArrayLen(env);
1818         Branch(Int32LessThan(Int32Sub(arrayLen, *start), *deleteCount), &lessArrayLen, &checkOverflow);
1819         Bind(&lessArrayLen);
1820         actualDeleteCount = Int32Sub(arrayLen, *start);
1821         Jump(&checkOverflow);
1822         Bind(&checkOverflow);
1823         Branch(Int64GreaterThan(Int64Sub(Int64Add(ZExtInt32ToInt64(arrayLen), ZExtInt32ToInt64(*insertCount)),
1824             ZExtInt32ToInt64(*actualDeleteCount)), Int64(base::MAX_SAFE_INTEGER)), slowPath, &notOverflow);
1825         Bind(&notOverflow);
1826 
1827         *result = CreateSpliceDeletedArray(glue, thisValue, *actualDeleteCount, intialHClass, *start);
1828 
1829         // insert Val
1830         DEFVARIABLE(srcElements, VariableType::JS_ANY(), GetElementsArray(thisValue));
1831         GateRef oldCapacity = GetLengthOfTaggedArray(*srcElements);
1832         GateRef newCapacity = Int32Add(Int32Sub(arrayLen, *actualDeleteCount), *insertCount);
1833         Label grow(env);
1834         Label copy(env);
1835         Branch(Int32GreaterThan(newCapacity, oldCapacity), &grow, &copy);
1836         Bind(&grow);
1837         {
1838             srcElements =
1839                 CallRuntime(glue, RTSTUB_ID(JSObjectGrowElementsCapacity), { thisValue, IntToTaggedInt(newCapacity) });
1840             Jump(&copy);
1841         }
1842         Bind(&copy);
1843         GateRef srcElementsLen = GetLengthOfTaggedArray(*srcElements);
1844         Label insertLessDelete(env);
1845         Label insertGreaterDelete(env);
1846         Label insertCountVal(env);
1847         Label setArrayLen(env);
1848         Label trimCheck(env);
1849         Branch(Int32LessThan(*insertCount, *actualDeleteCount), &insertLessDelete, &insertGreaterDelete);
1850         Bind(&insertLessDelete);
1851         {
1852             {
1853                 DEFVARIABLE(i, VariableType::INT32(), *start);
1854                 DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
1855 
1856                 Label loopHead(env);
1857                 Label loopEnd(env);
1858                 Label next(env);
1859                 Label loopExit(env);
1860                 Jump(&loopHead);
1861                 LoopBegin(&loopHead);
1862                 {
1863                     Branch(Int32LessThan(*i, Int32Sub(arrayLen, *actualDeleteCount)), &next, &loopExit);
1864                     Bind(&next);
1865                     ele = Hole();
1866                     Label getSrcEle(env);
1867                     Label setEle(env);
1868                     Branch(Int32LessThan(Int32Add(*i, *actualDeleteCount), srcElementsLen), &getSrcEle, &setEle);
1869                     Bind(&getSrcEle);
1870                     {
1871                         ele = GetTaggedValueWithElementsKind(thisValue, Int32Add(*i, *actualDeleteCount));
1872                         Jump(&setEle);
1873                     }
1874                     Bind(&setEle);
1875                     {
1876                         Label setIndexLessLen(env);
1877                         Branch(Int32LessThan(Int32Add(*i, *insertCount), srcElementsLen), &setIndexLessLen, &loopEnd);
1878                         Bind(&setIndexLessLen);
1879                         {
1880                             SetValueWithElementsKind(glue, thisValue, *ele, Int32Add(*i, *insertCount), Boolean(true),
1881                                                      Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1882                             Jump(&loopEnd);
1883                         }
1884                     }
1885                 }
1886                 Bind(&loopEnd);
1887                 i = Int32Add(*i, Int32(1));
1888                 LoopEnd(&loopHead);
1889                 Bind(&loopExit);
1890                 Jump(&trimCheck);
1891             }
1892 
1893             Label trim(env);
1894             Label noTrim(env);
1895             Bind(&trimCheck);
1896             Branch(BoolAnd(Int32GreaterThan(oldCapacity, newCapacity),
1897                 Int32GreaterThan(Int32Sub(newCapacity, oldCapacity),
1898                 Int32(TaggedArray::MAX_END_UNUSED))), &trim, &noTrim);
1899             Bind(&trim);
1900             {
1901                 CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, *srcElements, ZExtInt32ToInt64(newCapacity)});
1902                 Jump(&insertCountVal);
1903             }
1904             Bind(&noTrim);
1905             {
1906                 DEFVARIABLE(idx, VariableType::INT32(), newCapacity);
1907                 Label loopHead1(env);
1908                 Label loopEnd1(env);
1909                 Label next1(env);
1910                 Label loopExit1(env);
1911                 Jump(&loopHead1);
1912                 LoopBegin(&loopHead1);
1913                 {
1914                     Branch(Int32LessThan(*idx, arrayLen), &next1, &loopExit1);
1915                     Bind(&next1);
1916 
1917                     Label setHole(env);
1918                     Branch(Int32LessThan(*idx, srcElementsLen), &setHole, &loopEnd1);
1919                     Bind(&setHole);
1920                     {
1921                         SetValueWithElementsKind(glue, thisValue, Hole(), *idx, Boolean(true),
1922                                                  Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1923                         Jump(&loopEnd1);
1924                     }
1925                 }
1926                 Bind(&loopEnd1);
1927                 idx = Int32Add(*idx, Int32(1));
1928                 LoopEnd(&loopHead1);
1929                 Bind(&loopExit1);
1930                 Jump(&insertCountVal);
1931             }
1932             Bind(&insertGreaterDelete);
1933             {
1934                 DEFVARIABLE(j, VariableType::INT32(), Int32Sub(arrayLen, *actualDeleteCount));
1935                 DEFVARIABLE(ele, VariableType::JS_ANY(), Hole());
1936                 Label loopHead(env);
1937                 Label loopEnd(env);
1938                 Label next(env);
1939                 Label loopExit(env);
1940                 Jump(&loopHead);
1941                 LoopBegin(&loopHead);
1942                 {
1943                     Branch(Int32GreaterThan(*j, *start), &next, &loopExit);
1944                     Bind(&next);
1945                     ele = GetTaggedValueWithElementsKind(thisValue, Int32Sub(Int32Add(*j, *actualDeleteCount),
1946                                                                              Int32(1)));
1947                     Label setEle(env);
1948                     Label isHole(env);
1949                     Branch(TaggedIsHole(*ele), &isHole, &setEle);
1950                     Bind(&isHole);
1951                     {
1952                         ele = Undefined();
1953                         Jump(&setEle);
1954                     }
1955                     Bind(&setEle);
1956                     SetValueWithElementsKind(glue, thisValue, *ele, Int32Sub(Int32Add(*j, *insertCount), Int32(1)),
1957                                              Boolean(true), Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1958                     Jump(&loopEnd);
1959                 }
1960                 Bind(&loopEnd);
1961                 j = Int32Sub(*j, Int32(1));
1962                 LoopEnd(&loopHead);
1963                 Bind(&loopExit);
1964                 Jump(&insertCountVal);
1965             }
1966             Bind(&insertCountVal);
1967             {
1968                 Label threeArgs(env);
1969                 Branch(Int32Equal(ChangeIntPtrToInt32(numArgs), Int32(3)), &threeArgs, &setArrayLen); // 3 : three arg
1970                 Bind(&threeArgs);
1971                 {
1972                     GateRef e = GetCallArg2(numArgs);
1973                     SetValueWithElementsKind(glue, thisValue, e, *start, Boolean(true),
1974                                              Int32(static_cast<uint32_t>(ElementsKind::NONE)));
1975                     Jump(&setArrayLen);
1976                 }
1977             }
1978             Bind(&setArrayLen);
1979             SetArrayLength(glue, thisValue, newCapacity);
1980             Jump(exit);
1981         }
1982     }
1983 }
1984 }  // namespace panda::ecmascript::kungfu
1985