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