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