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