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