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